Commit | Line | Data |
---|---|---|
29444ed3 | 1 | /* if_uba.c 4.6 81/12/09 */ |
0468e5fa BJ |
2 | |
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
5 | #include "../h/mbuf.h" | |
6 | #include "../h/map.h" | |
7 | #include "../h/pte.h" | |
8a13b737 | 8 | #include "../h/buf.h" |
0468e5fa BJ |
9 | #include "../h/ubareg.h" |
10 | #include "../h/ubavar.h" | |
11 | #include "../h/cmap.h" | |
12 | #include "../h/mtpr.h" | |
8a13b737 BJ |
13 | #include "../h/vmmac.h" |
14 | #include "../net/in.h" | |
15 | #include "../net/in_systm.h" | |
16 | #include "../net/if.h" | |
0468e5fa BJ |
17 | #include "../net/if_uba.h" |
18 | ||
19 | /* | |
20 | * Routines supporting UNIBUS network interfaces. | |
21 | * | |
22 | * TODO: | |
23 | * Support interfaces using only one BDP statically. | |
24 | */ | |
25 | ||
26 | /* | |
27 | * Init UNIBUS for interface on uban whose headers of size hlen are to | |
28 | * end on a page boundary. We allocate a UNIBUS map register for the page | |
29 | * with the header, and nmr more UNIBUS map registers for i/o on the adapter, | |
30 | * doing this twice: once for reading and once for writing. We also | |
31 | * allocate page frames in the mbuffer pool for these pages. | |
32 | */ | |
33 | if_ubainit(ifu, uban, hlen, nmr) | |
34 | register struct ifuba *ifu; | |
35 | int uban, hlen, nmr; | |
36 | { | |
97da2a42 BJ |
37 | register caddr_t cp; |
38 | int i, ncl; | |
0468e5fa | 39 | |
8a13b737 | 40 | COUNT(IF_UBAINIT); |
97da2a42 BJ |
41 | ncl = clrnd(nmr + CLSIZE) / CLSIZE; |
42 | cp = m_clalloc(2 * ncl, MPG_SPACE); | |
0468e5fa BJ |
43 | if (cp == 0) |
44 | return (0); | |
b454c3ea | 45 | ifu->ifu_hlen = hlen; |
8a13b737 BJ |
46 | ifu->ifu_uban = uban; |
47 | ifu->ifu_uba = uba_hd[uban].uh_uba; | |
97da2a42 BJ |
48 | ifu->ifu_r.ifrw_addr = cp + CLBYTES - hlen; |
49 | ifu->ifu_w.ifrw_addr = ifu->ifu_r.ifrw_addr + ncl * CLBYTES; | |
b454c3ea | 50 | if (if_ubaalloc(ifu, &ifu->ifu_r, nmr) == 0) |
0468e5fa | 51 | goto bad; |
b454c3ea | 52 | if (if_ubaalloc(ifu, &ifu->ifu_w, nmr) == 0) |
0468e5fa | 53 | goto bad2; |
b454c3ea | 54 | for (i = 0; i < nmr; i++) |
97da2a42 | 55 | ifu->ifu_wmap[i] = ifu->ifu_w.ifrw_mr[i]; |
8a13b737 | 56 | ifu->ifu_xswapd = 0; |
0468e5fa BJ |
57 | return (1); |
58 | bad2: | |
8a13b737 | 59 | ubarelse(ifu->ifu_uban, &ifu->ifu_r.ifrw_info); |
0468e5fa | 60 | bad: |
97da2a42 | 61 | m_pgfree(cp, 2 * ncl); |
0468e5fa BJ |
62 | return (0); |
63 | } | |
64 | ||
65 | /* | |
66 | * Setup either a ifrw structure by allocating UNIBUS map registers, | |
67 | * a buffered data path, and initializing the fields of the ifrw structure | |
68 | * to minimize run-time overhead. | |
69 | */ | |
70 | static | |
b454c3ea | 71 | if_ubaalloc(ifu, ifrw, nmr) |
0468e5fa BJ |
72 | struct ifuba *ifu; |
73 | register struct ifrw *ifrw; | |
b454c3ea | 74 | int nmr; |
0468e5fa BJ |
75 | { |
76 | register int info; | |
77 | ||
8a13b737 | 78 | COUNT(IF_UBAALLOC); |
0468e5fa | 79 | info = |
b454c3ea | 80 | uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen, |
0468e5fa BJ |
81 | UBA_NEED16|UBA_NEEDBDP); |
82 | if (info == 0) | |
8a13b737 | 83 | return (0); |
0468e5fa BJ |
84 | ifrw->ifrw_info = info; |
85 | ifrw->ifrw_bdp = UBAI_BDP(info); | |
97da2a42 | 86 | ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); |
8a13b737 BJ |
87 | ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1]; |
88 | return (1); | |
0468e5fa BJ |
89 | } |
90 | ||
91 | /* | |
f1b2fa5b BJ |
92 | * Pull read data off a interface. |
93 | * Len is length of data, with local net header stripped. | |
94 | * Off is non-zero if a trailer protocol was used, and | |
95 | * gives the offset of the trailer information. | |
96 | * We copy the trailer information and then all the normal | |
97 | * data into mbufs. When full cluster sized units are present | |
98 | * on the interface on cluster boundaries we can get them more | |
99 | * easily by remapping, and take advantage of this here. | |
0468e5fa BJ |
100 | */ |
101 | struct mbuf * | |
f1b2fa5b | 102 | if_rubaget(ifu, totlen, off0) |
0468e5fa | 103 | register struct ifuba *ifu; |
f1b2fa5b | 104 | int totlen, off0; |
0468e5fa | 105 | { |
b454c3ea BJ |
106 | struct mbuf *top, **mp, *m; |
107 | int off = off0, len; | |
97da2a42 | 108 | register caddr_t cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen; |
0468e5fa | 109 | |
8a13b737 | 110 | COUNT(IF_RUBAGET); |
0468e5fa | 111 | |
f1b2fa5b BJ |
112 | top = 0; |
113 | mp = ⊤ | |
114 | while (totlen > 0) { | |
0468e5fa BJ |
115 | MGET(m, 0); |
116 | if (m == 0) | |
8a13b737 | 117 | goto bad; |
f1b2fa5b BJ |
118 | if (off) { |
119 | len = totlen - off; | |
120 | cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen + off; | |
121 | } else | |
122 | len = totlen; | |
97da2a42 | 123 | if (len >= CLBYTES) { |
b454c3ea | 124 | struct mbuf *p; |
0468e5fa | 125 | struct pte *cpte, *ppte; |
b454c3ea | 126 | int x, *ip, i; |
0468e5fa BJ |
127 | |
128 | MCLGET(p, 1); | |
129 | if (p == 0) | |
130 | goto nopage; | |
97da2a42 | 131 | len = m->m_len = CLBYTES; |
0468e5fa | 132 | m->m_off = (int)p - (int)m; |
b454c3ea | 133 | if (!claligned(cp)) |
0468e5fa BJ |
134 | goto copy; |
135 | ||
136 | /* | |
b454c3ea BJ |
137 | * Switch pages mapped to UNIBUS with new page p, |
138 | * as quick form of copy. Remap UNIBUS and invalidate. | |
0468e5fa | 139 | */ |
b454c3ea BJ |
140 | cpte = &Mbmap[mtocl(cp)*CLSIZE]; |
141 | ppte = &Mbmap[mtocl(p)*CLSIZE]; | |
8a13b737 | 142 | x = btop(cp - ifu->ifu_r.ifrw_addr); |
97da2a42 | 143 | ip = (int *)&ifu->ifu_r.ifrw_mr[x]; |
0468e5fa BJ |
144 | for (i = 0; i < CLSIZE; i++) { |
145 | struct pte t; | |
b454c3ea | 146 | t = *ppte; *ppte++ = *cpte; *cpte = t; |
0468e5fa | 147 | *ip++ = |
8a13b737 | 148 | cpte++->pg_pfnum|ifu->ifu_r.ifrw_proto; |
0468e5fa | 149 | mtpr(TBIS, cp); |
8a13b737 | 150 | cp += NBPG; |
0468e5fa | 151 | mtpr(TBIS, (caddr_t)p); |
8a13b737 | 152 | p += NBPG / sizeof (*p); |
0468e5fa BJ |
153 | } |
154 | goto nocopy; | |
155 | } | |
156 | nopage: | |
157 | m->m_len = MIN(MLEN, len); | |
158 | m->m_off = MMINOFF; | |
159 | copy: | |
160 | bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); | |
161 | cp += m->m_len; | |
162 | nocopy: | |
f1b2fa5b BJ |
163 | *mp = m; |
164 | mp = &m->m_next; | |
165 | if (off) { | |
b454c3ea | 166 | /* sort of an ALGOL-W style for statement... */ |
f1b2fa5b BJ |
167 | off += m->m_len; |
168 | if (off == totlen) { | |
169 | cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen; | |
170 | off = 0; | |
97da2a42 | 171 | totlen = off0; |
f1b2fa5b | 172 | } |
97da2a42 BJ |
173 | } else |
174 | totlen -= len; | |
0468e5fa BJ |
175 | } |
176 | return (top); | |
177 | bad: | |
178 | m_freem(top); | |
179 | return (0); | |
180 | } | |
181 | ||
182 | /* | |
183 | * Map a chain of mbufs onto a network interface | |
184 | * in preparation for an i/o operation. | |
185 | * The argument chain of mbufs includes the local network | |
186 | * header which is copied to be in the mapped, aligned | |
187 | * i/o space. | |
188 | */ | |
189 | if_wubaput(ifu, m) | |
190 | register struct ifuba *ifu; | |
191 | register struct mbuf *m; | |
192 | { | |
193 | register struct mbuf *mp; | |
194 | register caddr_t cp, dp; | |
195 | register int i; | |
b454c3ea BJ |
196 | int xswapd = 0; |
197 | int x, cc; | |
0468e5fa | 198 | |
8a13b737 | 199 | COUNT(IF_WUBAPUT); |
0468e5fa BJ |
200 | ifu->ifu_xswapd = 0; |
201 | cp = ifu->ifu_w.ifrw_addr; | |
202 | while (m) { | |
203 | dp = mtod(m, char *); | |
97da2a42 | 204 | if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) { |
0468e5fa | 205 | struct pte *pte; int *ip; |
b454c3ea | 206 | pte = &Mbmap[mtocl(dp)*CLSIZE]; |
0468e5fa | 207 | x = btop(cp - ifu->ifu_w.ifrw_addr); |
97da2a42 | 208 | ip = (int *)&ifu->ifu_w.ifrw_mr[x]; |
0468e5fa BJ |
209 | for (i = 0; i < CLSIZE; i++) |
210 | *ip++ = | |
211 | ifu->ifu_w.ifrw_proto | pte++->pg_pfnum; | |
97da2a42 | 212 | xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT)); |
b454c3ea BJ |
213 | mp = m->m_next; |
214 | m->m_next = ifu->ifu_xtofree; | |
215 | ifu->ifu_xtofree = m; | |
216 | cp += m->m_len; | |
217 | } else { | |
0468e5fa | 218 | bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); |
b454c3ea BJ |
219 | cp += m->m_len; |
220 | MFREE(m, mp); | |
221 | } | |
0468e5fa BJ |
222 | m = mp; |
223 | } | |
b454c3ea BJ |
224 | |
225 | /* | |
226 | * Xswapd is the set of clusters we just mapped out. Ifu->ifu_xswapd | |
227 | * is the set of clusters mapped out from before. We compute | |
228 | * the number of clusters involved in this operation in x. | |
229 | * Clusters mapped out before and involved in this operation | |
230 | * should be unmapped so original pages will be accessed by the device. | |
231 | */ | |
232 | cc = cp - ifu->ifu_w.ifrw_addr; | |
233 | x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT; | |
97da2a42 | 234 | ifu->ifu_xswapd &= ~xswapd; |
0468e5fa | 235 | xswapd &= ~ifu->ifu_xswapd; |
97da2a42 BJ |
236 | while (i = ffs(ifu->ifu_xswapd)) { |
237 | i--; | |
238 | if (i >= x) | |
239 | break; | |
240 | ifu->ifu_xswapd &= ~(1<<i); | |
241 | i *= CLSIZE; | |
242 | for (x = 0; x < CLSIZE; x++) { | |
243 | ifu->ifu_w.ifrw_mr[i] = ifu->ifu_wmap[i]; | |
244 | i++; | |
0468e5fa | 245 | } |
97da2a42 | 246 | } |
b454c3ea BJ |
247 | ifu->ifu_xswapd |= xswapd; |
248 | return (cc); | |
0468e5fa | 249 | } |