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