Commit | Line | Data |
---|---|---|
6c21119b KS |
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 | * | |
e61560e0 | 6 | * @(#)if_de.c 6.12 (Berkeley) %G% |
6c21119b | 7 | */ |
2af91c21 MK |
8 | #include "de.h" |
9 | #if NDE > 0 | |
10 | ||
11 | /* | |
12 | * DEC DEUNA interface | |
13 | * | |
14 | * Lou Salkind | |
15 | * New York University | |
16 | * | |
17 | * TODO: | |
18 | * timeout routine (get statistics) | |
2af91c21 MK |
19 | */ |
20 | #include "../machine/pte.h" | |
21 | ||
a6e960e7 JB |
22 | #include "param.h" |
23 | #include "systm.h" | |
24 | #include "mbuf.h" | |
25 | #include "buf.h" | |
26 | #include "protosw.h" | |
27 | #include "socket.h" | |
28 | #include "vmmac.h" | |
29 | #include "ioctl.h" | |
30 | #include "errno.h" | |
2af91c21 MK |
31 | |
32 | #include "../net/if.h" | |
33 | #include "../net/netisr.h" | |
34 | #include "../net/route.h" | |
6c21119b KS |
35 | |
36 | #ifdef INET | |
2af91c21 MK |
37 | #include "../netinet/in.h" |
38 | #include "../netinet/in_systm.h" | |
7f0e1e06 | 39 | #include "../netinet/in_var.h" |
2af91c21 MK |
40 | #include "../netinet/ip.h" |
41 | #include "../netinet/ip_var.h" | |
42 | #include "../netinet/if_ether.h" | |
6c21119b KS |
43 | #endif |
44 | ||
b1b3e868 | 45 | #ifdef PUP |
2af91c21 | 46 | #include "../netpup/pup.h" |
b1b3e868 | 47 | #endif |
2af91c21 | 48 | |
6c21119b KS |
49 | #ifdef NS |
50 | #include "../netns/ns.h" | |
51 | #include "../netns/ns_if.h" | |
52 | #endif | |
53 | ||
2af91c21 MK |
54 | #include "../vax/cpu.h" |
55 | #include "../vax/mtpr.h" | |
a6e960e7 JB |
56 | #include "if_dereg.h" |
57 | #include "if_uba.h" | |
2af91c21 MK |
58 | #include "../vaxuba/ubareg.h" |
59 | #include "../vaxuba/ubavar.h" | |
60 | ||
cd4baa58 KS |
61 | #define NXMT 3 /* number of transmit buffers */ |
62 | #define NRCV 7 /* number of receive buffers (must be > 1) */ | |
2af91c21 MK |
63 | #define NTOT (NXMT + NRCV) |
64 | ||
c5c241c4 | 65 | int dedebug = 0; |
d6d71290 | 66 | |
2af91c21 MK |
67 | int deprobe(), deattach(), deintr(); |
68 | struct uba_device *deinfo[NDE]; | |
69 | u_short destd[] = { 0 }; | |
70 | struct uba_driver dedriver = | |
71 | { deprobe, 0, deattach, 0, destd, "de", deinfo }; | |
2af91c21 MK |
72 | int deinit(),deoutput(),deioctl(),dereset(); |
73 | struct mbuf *deget(); | |
74 | ||
75 | ||
76 | /* | |
4843f48e MK |
77 | * The deuba structures generalizes the ifuba structure |
78 | * to an arbitrary number of receive and transmit buffers. | |
2af91c21 | 79 | */ |
4843f48e MK |
80 | struct ifxmt { |
81 | struct ifrw x_ifrw; /* mapping information */ | |
82 | struct pte x_map[IF_MAXNUBAMR]; /* output base pages */ | |
83 | short x_xswapd; /* mask of clusters swapped */ | |
84 | struct mbuf *x_xtofree; /* pages being dma'ed out */ | |
85 | }; | |
86 | ||
2af91c21 MK |
87 | struct deuba { |
88 | short ifu_uban; /* uba number */ | |
89 | short ifu_hlen; /* local net header length */ | |
90 | struct uba_regs *ifu_uba; /* uba regs, in vm */ | |
91 | struct ifrw ifu_r[NRCV]; /* receive information */ | |
4843f48e | 92 | struct ifxmt ifu_w[NXMT]; /* transmit information */ |
2af91c21 MK |
93 | short ifu_flags; /* used during uballoc's */ |
94 | }; | |
95 | ||
96 | /* | |
97 | * Ethernet software status per interface. | |
98 | * | |
99 | * Each interface is referenced by a network interface structure, | |
100 | * ds_if, which the routing code uses to locate the interface. | |
101 | * This structure contains the output queue for the interface, its address, ... | |
102 | * We also have, for each interface, a UBA interface structure, which | |
103 | * contains information about the UNIBUS resources held by the interface: | |
104 | * map registers, buffered data paths, etc. Information is cached in this | |
105 | * structure for use by the if_uba.c routines in running the interface | |
106 | * efficiently. | |
107 | */ | |
108 | struct de_softc { | |
109 | struct arpcom ds_ac; /* Ethernet common part */ | |
110 | #define ds_if ds_ac.ac_if /* network-visible interface */ | |
111 | #define ds_addr ds_ac.ac_enaddr /* hardware Ethernet address */ | |
112 | int ds_flags; | |
113 | #define DSF_LOCK 1 /* lock out destart */ | |
d6d71290 | 114 | #define DSF_RUNNING 2 |
2af91c21 MK |
115 | int ds_ubaddr; /* map info for incore structs */ |
116 | struct deuba ds_deuba; /* unibus resource structure */ | |
117 | /* the following structures are always mapped in */ | |
118 | struct de_pcbb ds_pcbb; /* port control block */ | |
119 | struct de_ring ds_xrent[NXMT]; /* transmit ring entrys */ | |
120 | struct de_ring ds_rrent[NRCV]; /* receive ring entrys */ | |
121 | struct de_udbbuf ds_udbbuf; /* UNIBUS data buffer */ | |
122 | /* end mapped area */ | |
123 | #define INCORE_BASE(p) ((char *)&(p)->ds_pcbb) | |
124 | #define RVAL_OFF(n) ((char *)&de_softc[0].n - INCORE_BASE(&de_softc[0])) | |
125 | #define LVAL_OFF(n) ((char *)de_softc[0].n - INCORE_BASE(&de_softc[0])) | |
126 | #define PCBB_OFFSET RVAL_OFF(ds_pcbb) | |
127 | #define XRENT_OFFSET LVAL_OFF(ds_xrent) | |
128 | #define RRENT_OFFSET LVAL_OFF(ds_rrent) | |
129 | #define UDBBUF_OFFSET RVAL_OFF(ds_udbbuf) | |
130 | #define INCORE_SIZE RVAL_OFF(ds_xindex) | |
131 | int ds_xindex; /* UNA index into transmit chain */ | |
132 | int ds_rindex; /* UNA index into receive chain */ | |
133 | int ds_xfree; /* index for next transmit buffer */ | |
134 | int ds_nxmit; /* # of transmits in progress */ | |
135 | } de_softc[NDE]; | |
136 | ||
137 | deprobe(reg) | |
138 | caddr_t reg; | |
139 | { | |
140 | register int br, cvec; /* r11, r10 value-result */ | |
141 | register struct dedevice *addr = (struct dedevice *)reg; | |
142 | register i; | |
143 | ||
144 | #ifdef lint | |
145 | br = 0; cvec = br; br = cvec; | |
146 | i = 0; derint(i); deintr(i); | |
147 | #endif | |
148 | ||
149 | addr->pcsr0 = PCSR0_RSET; | |
150 | while ((addr->pcsr0 & PCSR0_INTR) == 0) | |
151 | ; | |
152 | /* make board interrupt by executing a GETPCBB command */ | |
153 | addr->pcsr0 = PCSR0_INTE; | |
154 | addr->pcsr2 = 0; | |
155 | addr->pcsr3 = 0; | |
156 | addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB; | |
157 | DELAY(100000); | |
158 | return(1); | |
159 | } | |
160 | ||
161 | /* | |
162 | * Interface exists: make available by filling in network interface | |
163 | * record. System will initialize the interface when it is ready | |
164 | * to accept packets. We get the ethernet address here. | |
165 | */ | |
166 | deattach(ui) | |
167 | struct uba_device *ui; | |
168 | { | |
169 | register struct de_softc *ds = &de_softc[ui->ui_unit]; | |
170 | register struct ifnet *ifp = &ds->ds_if; | |
171 | register struct dedevice *addr = (struct dedevice *)ui->ui_addr; | |
2af91c21 MK |
172 | int csr0; |
173 | ||
174 | ifp->if_unit = ui->ui_unit; | |
175 | ifp->if_name = "de"; | |
176 | ifp->if_mtu = ETHERMTU; | |
7f0e1e06 | 177 | ifp->if_flags = IFF_BROADCAST; |
2af91c21 MK |
178 | |
179 | /* | |
180 | * Reset the board and temporarily map | |
181 | * the pcbb buffer onto the Unibus. | |
182 | */ | |
183 | addr->pcsr0 = PCSR0_RSET; | |
184 | while ((addr->pcsr0 & PCSR0_INTR) == 0) | |
185 | ; | |
186 | csr0 = addr->pcsr0; | |
187 | addr->pchigh = csr0 >> 8; | |
188 | if (csr0 & PCSR0_PCEI) | |
189 | printf("de%d: reset failed, csr0=%b csr1=%b\n", ui->ui_unit, | |
190 | csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); | |
191 | ds->ds_ubaddr = uballoc(ui->ui_ubanum, (char *)&ds->ds_pcbb, | |
192 | sizeof (struct de_pcbb), 0); | |
193 | addr->pcsr2 = ds->ds_ubaddr & 0xffff; | |
194 | addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3; | |
195 | addr->pclow = CMD_GETPCBB; | |
196 | while ((addr->pcsr0 & PCSR0_INTR) == 0) | |
197 | ; | |
198 | csr0 = addr->pcsr0; | |
199 | addr->pchigh = csr0 >> 8; | |
200 | if (csr0 & PCSR0_PCEI) | |
201 | printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit, | |
202 | csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); | |
203 | ds->ds_pcbb.pcbb0 = FC_RDPHYAD; | |
204 | addr->pclow = CMD_GETCMD; | |
205 | while ((addr->pcsr0 & PCSR0_INTR) == 0) | |
206 | ; | |
207 | csr0 = addr->pcsr0; | |
208 | addr->pchigh = csr0 >> 8; | |
209 | if (csr0 & PCSR0_PCEI) | |
210 | printf("de%d: rdphyad failed, csr0=%b csr1=%b\n", ui->ui_unit, | |
211 | csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); | |
212 | ubarelse(ui->ui_ubanum, &ds->ds_ubaddr); | |
d6d71290 MK |
213 | if (dedebug) |
214 | printf("de%d: addr=%d:%d:%d:%d:%d:%d\n", ui->ui_unit, | |
215 | ds->ds_pcbb.pcbb2&0xff, (ds->ds_pcbb.pcbb2>>8)&0xff, | |
216 | ds->ds_pcbb.pcbb4&0xff, (ds->ds_pcbb.pcbb4>>8)&0xff, | |
217 | ds->ds_pcbb.pcbb6&0xff, (ds->ds_pcbb.pcbb6>>8)&0xff); | |
7f0e1e06 | 218 | bcopy((caddr_t)&ds->ds_pcbb.pcbb2, (caddr_t)ds->ds_addr, |
2af91c21 | 219 | sizeof (ds->ds_addr)); |
2af91c21 MK |
220 | ifp->if_init = deinit; |
221 | ifp->if_output = deoutput; | |
222 | ifp->if_ioctl = deioctl; | |
223 | ifp->if_reset = dereset; | |
224 | ds->ds_deuba.ifu_flags = UBA_CANTWAIT; | |
225 | #ifdef notdef | |
226 | /* CAN WE USE BDP's ??? */ | |
227 | ds->ds_deuba.ifu_flags |= UBA_NEEDBDP; | |
228 | #endif | |
229 | if_attach(ifp); | |
230 | } | |
231 | ||
232 | /* | |
233 | * Reset of interface after UNIBUS reset. | |
234 | * If interface is on specified uba, reset its state. | |
235 | */ | |
236 | dereset(unit, uban) | |
237 | int unit, uban; | |
238 | { | |
239 | register struct uba_device *ui; | |
240 | ||
241 | if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 || | |
242 | ui->ui_ubanum != uban) | |
243 | return; | |
244 | printf(" de%d", unit); | |
7f0e1e06 | 245 | de_softc[unit].ds_if.if_flags &= ~IFF_RUNNING; |
2af91c21 MK |
246 | deinit(unit); |
247 | } | |
248 | ||
249 | /* | |
250 | * Initialization of interface; clear recorded pending | |
251 | * operations, and reinitialize UNIBUS usage. | |
252 | */ | |
253 | deinit(unit) | |
254 | int unit; | |
255 | { | |
256 | register struct de_softc *ds = &de_softc[unit]; | |
257 | register struct uba_device *ui = deinfo[unit]; | |
258 | register struct dedevice *addr; | |
259 | register struct ifrw *ifrw; | |
4843f48e MK |
260 | register struct ifxmt *ifxp; |
261 | struct ifnet *ifp = &ds->ds_if; | |
2af91c21 | 262 | int s; |
2af91c21 MK |
263 | struct de_ring *rp; |
264 | int incaddr; | |
265 | int csr0; | |
266 | ||
7f0e1e06 MK |
267 | /* not yet, if address still unknown */ |
268 | if (ifp->if_addrlist == (struct ifaddr *)0) | |
2af91c21 MK |
269 | return; |
270 | ||
271 | if (ifp->if_flags & IFF_RUNNING) | |
7f0e1e06 | 272 | return; |
2af91c21 MK |
273 | if (de_ubainit(&ds->ds_deuba, ui->ui_ubanum, |
274 | sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) { | |
275 | printf("de%d: can't initialize\n", unit); | |
276 | ds->ds_if.if_flags &= ~IFF_UP; | |
277 | return; | |
278 | } | |
279 | ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), INCORE_SIZE,0); | |
280 | addr = (struct dedevice *)ui->ui_addr; | |
281 | ||
282 | /* set the pcbb block address */ | |
283 | incaddr = ds->ds_ubaddr + PCBB_OFFSET; | |
284 | addr->pcsr2 = incaddr & 0xffff; | |
285 | addr->pcsr3 = (incaddr >> 16) & 0x3; | |
286 | addr->pclow = CMD_GETPCBB; | |
287 | while ((addr->pcsr0 & PCSR0_INTR) == 0) | |
288 | ; | |
289 | csr0 = addr->pcsr0; | |
290 | addr->pchigh = csr0 >> 8; | |
291 | if (csr0 & PCSR0_PCEI) | |
292 | printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit, | |
293 | csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); | |
294 | ||
295 | /* set the transmit and receive ring header addresses */ | |
296 | incaddr = ds->ds_ubaddr + UDBBUF_OFFSET; | |
297 | ds->ds_pcbb.pcbb0 = FC_WTRING; | |
298 | ds->ds_pcbb.pcbb2 = incaddr & 0xffff; | |
299 | ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3; | |
300 | ||
301 | incaddr = ds->ds_ubaddr + XRENT_OFFSET; | |
302 | ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff; | |
303 | ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3; | |
304 | ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short); | |
305 | ds->ds_udbbuf.b_trlen = NXMT; | |
306 | incaddr = ds->ds_ubaddr + RRENT_OFFSET; | |
307 | ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff; | |
308 | ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3; | |
309 | ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short); | |
310 | ds->ds_udbbuf.b_rrlen = NRCV; | |
311 | ||
312 | addr->pclow = CMD_GETCMD; | |
313 | while ((addr->pcsr0 & PCSR0_INTR) == 0) | |
314 | ; | |
315 | csr0 = addr->pcsr0; | |
316 | addr->pchigh = csr0 >> 8; | |
317 | if (csr0 & PCSR0_PCEI) | |
318 | printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit, | |
319 | csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); | |
320 | ||
321 | /* initialize the mode - enable hardware padding */ | |
322 | ds->ds_pcbb.pcbb0 = FC_WTMODE; | |
323 | /* let hardware do padding - set MTCH bit on broadcast */ | |
324 | ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX; | |
325 | addr->pclow = CMD_GETCMD; | |
326 | while ((addr->pcsr0 & PCSR0_INTR) == 0) | |
327 | ; | |
328 | csr0 = addr->pcsr0; | |
329 | addr->pchigh = csr0 >> 8; | |
330 | if (csr0 & PCSR0_PCEI) | |
331 | printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit, | |
332 | csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); | |
333 | ||
334 | /* set up the receive and transmit ring entries */ | |
4843f48e | 335 | ifxp = &ds->ds_deuba.ifu_w[0]; |
2af91c21 | 336 | for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) { |
4843f48e MK |
337 | rp->r_segbl = ifxp->x_ifrw.ifrw_info & 0xffff; |
338 | rp->r_segbh = (ifxp->x_ifrw.ifrw_info >> 16) & 0x3; | |
2af91c21 | 339 | rp->r_flags = 0; |
4843f48e | 340 | ifxp++; |
2af91c21 MK |
341 | } |
342 | ifrw = &ds->ds_deuba.ifu_r[0]; | |
343 | for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) { | |
344 | rp->r_slen = sizeof (struct de_buf); | |
345 | rp->r_segbl = ifrw->ifrw_info & 0xffff; | |
346 | rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3; | |
347 | rp->r_flags = RFLG_OWN; /* hang receive */ | |
348 | ifrw++; | |
349 | } | |
350 | ||
351 | /* start up the board (rah rah) */ | |
352 | s = splimp(); | |
353 | ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = 0; | |
7f0e1e06 | 354 | ds->ds_if.if_flags |= IFF_RUNNING; |
d6d71290 | 355 | destart(unit); /* queue output packets */ |
2af91c21 MK |
356 | addr->pclow = PCSR0_INTE; /* avoid interlock */ |
357 | addr->pclow = CMD_START | PCSR0_INTE; | |
d6d71290 | 358 | ds->ds_flags |= DSF_RUNNING; |
2af91c21 | 359 | splx(s); |
2af91c21 MK |
360 | } |
361 | ||
362 | /* | |
363 | * Setup output on interface. | |
364 | * Get another datagram to send off of the interface queue, | |
365 | * and map it to the interface before starting the output. | |
366 | */ | |
367 | destart(unit) | |
368 | int unit; | |
369 | { | |
370 | int len; | |
371 | struct uba_device *ui = deinfo[unit]; | |
372 | struct dedevice *addr = (struct dedevice *)ui->ui_addr; | |
373 | register struct de_softc *ds = &de_softc[unit]; | |
374 | register struct de_ring *rp; | |
375 | struct mbuf *m; | |
376 | register int nxmit; | |
377 | ||
378 | /* | |
379 | * the following test is necessary, since | |
380 | * the code is not reentrant and we have | |
381 | * multiple transmission buffers. | |
382 | */ | |
383 | if (ds->ds_flags & DSF_LOCK) | |
384 | return; | |
385 | for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) { | |
386 | IF_DEQUEUE(&ds->ds_if.if_snd, m); | |
387 | if (m == 0) | |
388 | break; | |
389 | rp = &ds->ds_xrent[ds->ds_xfree]; | |
390 | if (rp->r_flags & XFLG_OWN) | |
391 | panic("deuna xmit in progress"); | |
4843f48e | 392 | len = deput(&ds->ds_deuba, ds->ds_xfree, m); |
2af91c21 MK |
393 | if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP) |
394 | UBAPURGE(ds->ds_deuba.ifu_uba, | |
4843f48e | 395 | ds->ds_deuba.ifu_w[ds->ds_xfree].x_ifrw.ifrw_bdp); |
2af91c21 MK |
396 | rp->r_slen = len; |
397 | rp->r_tdrerr = 0; | |
398 | rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN; | |
399 | ||
400 | ds->ds_xfree++; | |
401 | if (ds->ds_xfree == NXMT) | |
402 | ds->ds_xfree = 0; | |
403 | } | |
404 | if (ds->ds_nxmit != nxmit) { | |
405 | ds->ds_nxmit = nxmit; | |
d6d71290 | 406 | if (ds->ds_flags & DSF_RUNNING) |
2af91c21 MK |
407 | addr->pclow = PCSR0_INTE|CMD_PDMD; |
408 | } | |
409 | } | |
410 | ||
411 | /* | |
412 | * Command done interrupt. | |
413 | */ | |
414 | deintr(unit) | |
415 | int unit; | |
416 | { | |
417 | struct uba_device *ui = deinfo[unit]; | |
418 | register struct dedevice *addr = (struct dedevice *)ui->ui_addr; | |
419 | register struct de_softc *ds = &de_softc[unit]; | |
420 | register struct de_ring *rp; | |
4843f48e | 421 | register struct ifxmt *ifxp; |
2af91c21 MK |
422 | short csr0; |
423 | ||
424 | /* save flags right away - clear out interrupt bits */ | |
425 | csr0 = addr->pcsr0; | |
426 | addr->pchigh = csr0 >> 8; | |
427 | ||
428 | ||
429 | ds->ds_flags |= DSF_LOCK; /* prevent entering destart */ | |
430 | /* | |
431 | * if receive, put receive buffer on mbuf | |
432 | * and hang the request again | |
433 | */ | |
434 | derecv(unit); | |
435 | ||
436 | /* | |
437 | * Poll transmit ring and check status. | |
438 | * Be careful about loopback requests. | |
439 | * Then free buffer space and check for | |
440 | * more transmit requests. | |
441 | */ | |
442 | for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) { | |
443 | rp = &ds->ds_xrent[ds->ds_xindex]; | |
444 | if (rp->r_flags & XFLG_OWN) | |
445 | break; | |
446 | ds->ds_if.if_opackets++; | |
4843f48e | 447 | ifxp = &ds->ds_deuba.ifu_w[ds->ds_xindex]; |
2af91c21 MK |
448 | /* check for unusual conditions */ |
449 | if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) { | |
450 | if (rp->r_flags & XFLG_ERRS) { | |
451 | /* output error */ | |
452 | ds->ds_if.if_oerrors++; | |
d6d71290 | 453 | if (dedebug) |
2af91c21 MK |
454 | printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n", |
455 | unit, rp->r_flags, XFLG_BITS, | |
456 | rp->r_tdrerr, XERR_BITS, rp->r_slen); | |
457 | } else if (rp->r_flags & XFLG_ONE) { | |
458 | /* one collision */ | |
459 | ds->ds_if.if_collisions++; | |
460 | } else if (rp->r_flags & XFLG_MORE) { | |
461 | /* more than one collision */ | |
462 | ds->ds_if.if_collisions += 2; /* guess */ | |
463 | } else if (rp->r_flags & XFLG_MTCH) { | |
464 | /* received our own packet */ | |
465 | ds->ds_if.if_ipackets++; | |
4843f48e | 466 | deread(ds, &ifxp->x_ifrw, |
2af91c21 MK |
467 | rp->r_slen - sizeof (struct ether_header)); |
468 | } | |
469 | } | |
4843f48e MK |
470 | if (ifxp->x_xtofree) { |
471 | m_freem(ifxp->x_xtofree); | |
472 | ifxp->x_xtofree = 0; | |
473 | } | |
2af91c21 MK |
474 | /* check if next transmit buffer also finished */ |
475 | ds->ds_xindex++; | |
476 | if (ds->ds_xindex == NXMT) | |
477 | ds->ds_xindex = 0; | |
478 | } | |
479 | ds->ds_flags &= ~DSF_LOCK; | |
480 | destart(unit); | |
481 | ||
482 | if (csr0 & PCSR0_RCBI) { | |
483 | printf("de%d: buffer unavailable\n", unit); | |
484 | addr->pclow = PCSR0_INTE|CMD_PDMD; | |
485 | } | |
486 | } | |
487 | ||
488 | /* | |
489 | * Ethernet interface receiver interface. | |
490 | * If input error just drop packet. | |
491 | * Otherwise purge input buffered data path and examine | |
492 | * packet to determine type. If can't determine length | |
493 | * from type, then have to drop packet. Othewise decapsulate | |
494 | * packet based on type and pass to type specific higher-level | |
495 | * input routine. | |
496 | */ | |
497 | derecv(unit) | |
498 | int unit; | |
499 | { | |
500 | register struct de_softc *ds = &de_softc[unit]; | |
501 | register struct de_ring *rp; | |
502 | int len; | |
503 | ||
504 | rp = &ds->ds_rrent[ds->ds_rindex]; | |
505 | while ((rp->r_flags & RFLG_OWN) == 0) { | |
506 | ds->ds_if.if_ipackets++; | |
507 | if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP) | |
508 | UBAPURGE(ds->ds_deuba.ifu_uba, | |
509 | ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_bdp); | |
510 | len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header) | |
511 | - 4; /* don't forget checksum! */ | |
512 | /* check for errors */ | |
513 | if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) || | |
514 | (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) || | |
515 | (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) || | |
516 | len < ETHERMIN || len > ETHERMTU) { | |
517 | ds->ds_if.if_ierrors++; | |
d6d71290 | 518 | if (dedebug) |
2af91c21 MK |
519 | printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n", |
520 | unit, rp->r_flags, RFLG_BITS, rp->r_lenerr, | |
521 | RERR_BITS, len); | |
522 | } else | |
523 | deread(ds, &ds->ds_deuba.ifu_r[ds->ds_rindex], len); | |
524 | ||
525 | /* hang the receive buffer again */ | |
526 | rp->r_lenerr = 0; | |
527 | rp->r_flags = RFLG_OWN; | |
528 | ||
529 | /* check next receive buffer */ | |
530 | ds->ds_rindex++; | |
531 | if (ds->ds_rindex == NRCV) | |
532 | ds->ds_rindex = 0; | |
533 | rp = &ds->ds_rrent[ds->ds_rindex]; | |
534 | } | |
535 | } | |
536 | ||
537 | /* | |
538 | * Pass a packet to the higher levels. | |
539 | * We deal with the trailer protocol here. | |
540 | */ | |
541 | deread(ds, ifrw, len) | |
542 | register struct de_softc *ds; | |
543 | struct ifrw *ifrw; | |
544 | int len; | |
545 | { | |
546 | struct ether_header *eh; | |
547 | struct mbuf *m; | |
548 | int off, resid; | |
30faddf7 | 549 | int s; |
2af91c21 MK |
550 | register struct ifqueue *inq; |
551 | ||
552 | /* | |
7f0e1e06 | 553 | * Deal with trailer protocol: if type is trailer type |
2af91c21 MK |
554 | * get true type from first 16-bit word past data. |
555 | * Remember that type was trailer by setting off. | |
556 | */ | |
557 | eh = (struct ether_header *)ifrw->ifrw_addr; | |
558 | eh->ether_type = ntohs((u_short)eh->ether_type); | |
559 | #define dedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) | |
7f0e1e06 MK |
560 | if (eh->ether_type >= ETHERTYPE_TRAIL && |
561 | eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
562 | off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; | |
2af91c21 MK |
563 | if (off >= ETHERMTU) |
564 | return; /* sanity */ | |
565 | eh->ether_type = ntohs(*dedataaddr(eh, off, u_short *)); | |
566 | resid = ntohs(*(dedataaddr(eh, off+2, u_short *))); | |
567 | if (off + resid > len) | |
568 | return; /* sanity */ | |
569 | len = off + resid; | |
570 | } else | |
571 | off = 0; | |
572 | if (len == 0) | |
573 | return; | |
574 | ||
575 | /* | |
576 | * Pull packet off interface. Off is nonzero if packet | |
577 | * has trailing header; deget will then force this header | |
578 | * information to be at the front, but we still have to drop | |
579 | * the type and length which are at the front of any trailer data. | |
580 | */ | |
581 | m = deget(&ds->ds_deuba, ifrw, len, off); | |
582 | if (m == 0) | |
583 | return; | |
584 | if (off) { | |
585 | m->m_off += 2 * sizeof (u_short); | |
586 | m->m_len -= 2 * sizeof (u_short); | |
587 | } | |
588 | switch (eh->ether_type) { | |
589 | ||
590 | #ifdef INET | |
7f0e1e06 | 591 | case ETHERTYPE_IP: |
2af91c21 MK |
592 | schednetisr(NETISR_IP); |
593 | inq = &ipintrq; | |
594 | break; | |
595 | ||
7f0e1e06 | 596 | case ETHERTYPE_ARP: |
2af91c21 MK |
597 | arpinput(&ds->ds_ac, m); |
598 | return; | |
6c21119b KS |
599 | #endif |
600 | #ifdef NS | |
601 | case ETHERTYPE_NS: | |
602 | schednetisr(NETISR_NS); | |
603 | inq = &nsintrq; | |
604 | break; | |
605 | ||
2af91c21 MK |
606 | #endif |
607 | default: | |
608 | m_freem(m); | |
609 | return; | |
610 | } | |
611 | ||
30faddf7 | 612 | s = splimp(); |
2af91c21 MK |
613 | if (IF_QFULL(inq)) { |
614 | IF_DROP(inq); | |
30faddf7 | 615 | splx(s); |
2af91c21 MK |
616 | m_freem(m); |
617 | return; | |
618 | } | |
619 | IF_ENQUEUE(inq, m); | |
30faddf7 | 620 | splx(s); |
2af91c21 MK |
621 | } |
622 | ||
623 | /* | |
624 | * Ethernet output routine. | |
625 | * Encapsulate a packet of type family for the local net. | |
626 | * Use trailer local net encapsulation if enough data in first | |
627 | * packet leaves a multiple of 512 bytes of data in remainder. | |
628 | */ | |
629 | deoutput(ifp, m0, dst) | |
630 | struct ifnet *ifp; | |
631 | struct mbuf *m0; | |
632 | struct sockaddr *dst; | |
633 | { | |
634 | int type, s, error; | |
7f0e1e06 | 635 | u_char edst[6]; |
2af91c21 MK |
636 | struct in_addr idst; |
637 | register struct de_softc *ds = &de_softc[ifp->if_unit]; | |
638 | register struct mbuf *m = m0; | |
639 | register struct ether_header *eh; | |
640 | register int off; | |
641 | ||
642 | switch (dst->sa_family) { | |
643 | ||
644 | #ifdef INET | |
645 | case AF_INET: | |
646 | idst = ((struct sockaddr_in *)dst)->sin_addr; | |
7f0e1e06 | 647 | if (!arpresolve(&ds->ds_ac, m, &idst, edst)) |
2af91c21 MK |
648 | return (0); /* if not yet resolved */ |
649 | off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; | |
650 | /* need per host negotiation */ | |
651 | if ((ifp->if_flags & IFF_NOTRAILERS) == 0) | |
652 | if (off > 0 && (off & 0x1ff) == 0 && | |
653 | m->m_off >= MMINOFF + 2 * sizeof (u_short)) { | |
7f0e1e06 | 654 | type = ETHERTYPE_TRAIL + (off>>9); |
2af91c21 MK |
655 | m->m_off -= 2 * sizeof (u_short); |
656 | m->m_len += 2 * sizeof (u_short); | |
7f0e1e06 | 657 | *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); |
2af91c21 MK |
658 | *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); |
659 | goto gottrailertype; | |
660 | } | |
7f0e1e06 | 661 | type = ETHERTYPE_IP; |
2af91c21 MK |
662 | off = 0; |
663 | goto gottype; | |
664 | #endif | |
6c21119b KS |
665 | #ifdef NS |
666 | case AF_NS: | |
667 | type = ETHERTYPE_NS; | |
668 | bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), | |
669 | (caddr_t)edst, sizeof (edst)); | |
670 | off = 0; | |
671 | goto gottype; | |
672 | #endif | |
2af91c21 MK |
673 | |
674 | case AF_UNSPEC: | |
675 | eh = (struct ether_header *)dst->sa_data; | |
7f0e1e06 | 676 | bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); |
2af91c21 MK |
677 | type = eh->ether_type; |
678 | goto gottype; | |
679 | ||
680 | default: | |
681 | printf("de%d: can't handle af%d\n", ifp->if_unit, | |
682 | dst->sa_family); | |
683 | error = EAFNOSUPPORT; | |
684 | goto bad; | |
685 | } | |
686 | ||
687 | gottrailertype: | |
688 | /* | |
689 | * Packet to be sent as trailer: move first packet | |
690 | * (control information) to end of chain. | |
691 | */ | |
692 | while (m->m_next) | |
693 | m = m->m_next; | |
694 | m->m_next = m0; | |
695 | m = m0->m_next; | |
696 | m0->m_next = 0; | |
697 | m0 = m; | |
698 | ||
699 | gottype: | |
700 | /* | |
701 | * Add local net header. If no space in first mbuf, | |
702 | * allocate another. | |
703 | */ | |
704 | if (m->m_off > MMAXOFF || | |
705 | MMINOFF + sizeof (struct ether_header) > m->m_off) { | |
706 | m = m_get(M_DONTWAIT, MT_HEADER); | |
707 | if (m == 0) { | |
708 | error = ENOBUFS; | |
709 | goto bad; | |
710 | } | |
711 | m->m_next = m0; | |
712 | m->m_off = MMINOFF; | |
713 | m->m_len = sizeof (struct ether_header); | |
714 | } else { | |
715 | m->m_off -= sizeof (struct ether_header); | |
716 | m->m_len += sizeof (struct ether_header); | |
717 | } | |
718 | eh = mtod(m, struct ether_header *); | |
719 | eh->ether_type = htons((u_short)type); | |
7f0e1e06 | 720 | bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); |
2af91c21 MK |
721 | /* DEUNA fills in source address */ |
722 | ||
723 | /* | |
724 | * Queue message on interface, and start output if interface | |
725 | * not yet active. | |
726 | */ | |
727 | s = splimp(); | |
728 | if (IF_QFULL(&ifp->if_snd)) { | |
729 | IF_DROP(&ifp->if_snd); | |
730 | splx(s); | |
731 | m_freem(m); | |
732 | return (ENOBUFS); | |
733 | } | |
734 | IF_ENQUEUE(&ifp->if_snd, m); | |
735 | destart(ifp->if_unit); | |
736 | splx(s); | |
737 | return (0); | |
738 | ||
739 | bad: | |
740 | m_freem(m0); | |
741 | return (error); | |
742 | } | |
743 | ||
744 | /* | |
745 | * Routines supporting UNIBUS network interfaces. | |
746 | */ | |
747 | ||
748 | /* | |
749 | * Init UNIBUS for interface on uban whose headers of size hlen are to | |
750 | * end on a page boundary. We allocate a UNIBUS map register for the page | |
751 | * with the header, and nmr more UNIBUS map registers for i/o on the adapter, | |
752 | * doing this for each receive and transmit buffer. We also | |
753 | * allocate page frames in the mbuffer pool for these pages. | |
754 | */ | |
755 | de_ubainit(ifu, uban, hlen, nmr) | |
756 | register struct deuba *ifu; | |
757 | int uban, hlen, nmr; | |
758 | { | |
759 | register caddr_t cp, dp; | |
760 | register struct ifrw *ifrw; | |
4843f48e MK |
761 | register struct ifxmt *ifxp; |
762 | int i, ncl; | |
2af91c21 MK |
763 | |
764 | ncl = clrnd(nmr + CLSIZE) / CLSIZE; | |
765 | if (ifu->ifu_r[0].ifrw_addr) | |
766 | /* | |
767 | * If the first read buffer has a non-zero | |
768 | * address, it means we have already allocated core | |
769 | */ | |
770 | cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen); | |
771 | else { | |
772 | cp = m_clalloc(NTOT * ncl, MPG_SPACE); | |
773 | if (cp == 0) | |
774 | return (0); | |
775 | ifu->ifu_hlen = hlen; | |
776 | ifu->ifu_uban = uban; | |
777 | ifu->ifu_uba = uba_hd[uban].uh_uba; | |
778 | dp = cp + CLBYTES - hlen; | |
779 | for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { | |
780 | ifrw->ifrw_addr = dp; | |
781 | dp += ncl * CLBYTES; | |
782 | } | |
4843f48e MK |
783 | for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) { |
784 | ifxp->x_ifrw.ifrw_addr = dp; | |
2af91c21 MK |
785 | dp += ncl * CLBYTES; |
786 | } | |
787 | } | |
788 | /* allocate for receive ring */ | |
789 | for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { | |
790 | if (de_ubaalloc(ifu, ifrw, nmr) == 0) { | |
4843f48e | 791 | struct ifrw *rw; |
2af91c21 | 792 | |
4843f48e MK |
793 | for (rw = ifu->ifu_r; rw < ifrw; rw++) |
794 | ubarelse(ifu->ifu_uban, &rw->ifrw_info); | |
2af91c21 MK |
795 | goto bad; |
796 | } | |
797 | } | |
798 | /* and now transmit ring */ | |
4843f48e MK |
799 | for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) { |
800 | ifrw = &ifxp->x_ifrw; | |
2af91c21 | 801 | if (de_ubaalloc(ifu, ifrw, nmr) == 0) { |
4843f48e | 802 | struct ifxmt *xp; |
2af91c21 | 803 | |
4843f48e MK |
804 | for (xp = ifu->ifu_w; xp < ifxp; xp++) |
805 | ubarelse(ifu->ifu_uban, &xp->x_ifrw.ifrw_info); | |
806 | for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) | |
807 | ubarelse(ifu->ifu_uban, &ifrw->ifrw_info); | |
2af91c21 MK |
808 | goto bad; |
809 | } | |
4843f48e MK |
810 | for (i = 0; i < nmr; i++) |
811 | ifxp->x_map[i] = ifrw->ifrw_mr[i]; | |
812 | ifxp->x_xswapd = 0; | |
2af91c21 MK |
813 | } |
814 | return (1); | |
815 | bad: | |
816 | m_pgfree(cp, NTOT * ncl); | |
817 | ifu->ifu_r[0].ifrw_addr = 0; | |
818 | return(0); | |
819 | } | |
820 | ||
821 | /* | |
822 | * Setup either a ifrw structure by allocating UNIBUS map registers, | |
823 | * possibly a buffered data path, and initializing the fields of | |
824 | * the ifrw structure to minimize run-time overhead. | |
825 | */ | |
826 | static | |
827 | de_ubaalloc(ifu, ifrw, nmr) | |
828 | struct deuba *ifu; | |
829 | register struct ifrw *ifrw; | |
830 | int nmr; | |
831 | { | |
832 | register int info; | |
833 | ||
834 | info = | |
835 | uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen, | |
836 | ifu->ifu_flags); | |
837 | if (info == 0) | |
838 | return (0); | |
839 | ifrw->ifrw_info = info; | |
840 | ifrw->ifrw_bdp = UBAI_BDP(info); | |
841 | ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); | |
842 | ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1]; | |
843 | return (1); | |
844 | } | |
845 | ||
846 | /* | |
847 | * Pull read data off a interface. | |
848 | * Len is length of data, with local net header stripped. | |
849 | * Off is non-zero if a trailer protocol was used, and | |
850 | * gives the offset of the trailer information. | |
851 | * We copy the trailer information and then all the normal | |
852 | * data into mbufs. When full cluster sized units are present | |
853 | * on the interface on cluster boundaries we can get them more | |
854 | * easily by remapping, and take advantage of this here. | |
855 | */ | |
856 | struct mbuf * | |
857 | deget(ifu, ifrw, totlen, off0) | |
858 | register struct deuba *ifu; | |
859 | register struct ifrw *ifrw; | |
860 | int totlen, off0; | |
861 | { | |
862 | struct mbuf *top, **mp, *m; | |
863 | int off = off0, len; | |
864 | register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen; | |
865 | ||
866 | top = 0; | |
867 | mp = ⊤ | |
868 | while (totlen > 0) { | |
869 | MGET(m, M_DONTWAIT, MT_DATA); | |
870 | if (m == 0) | |
871 | goto bad; | |
872 | if (off) { | |
873 | len = totlen - off; | |
874 | cp = ifrw->ifrw_addr + ifu->ifu_hlen + off; | |
875 | } else | |
876 | len = totlen; | |
877 | if (len >= CLBYTES) { | |
878 | struct mbuf *p; | |
879 | struct pte *cpte, *ppte; | |
880 | int x, *ip, i; | |
881 | ||
882 | MCLGET(p, 1); | |
883 | if (p == 0) | |
884 | goto nopage; | |
885 | len = m->m_len = CLBYTES; | |
886 | m->m_off = (int)p - (int)m; | |
887 | if (!claligned(cp)) | |
888 | goto copy; | |
889 | ||
890 | /* | |
891 | * Switch pages mapped to UNIBUS with new page p, | |
892 | * as quick form of copy. Remap UNIBUS and invalidate. | |
893 | */ | |
894 | cpte = &Mbmap[mtocl(cp)*CLSIZE]; | |
895 | ppte = &Mbmap[mtocl(p)*CLSIZE]; | |
896 | x = btop(cp - ifrw->ifrw_addr); | |
897 | ip = (int *)&ifrw->ifrw_mr[x]; | |
898 | for (i = 0; i < CLSIZE; i++) { | |
899 | struct pte t; | |
900 | t = *ppte; *ppte++ = *cpte; *cpte = t; | |
901 | *ip++ = | |
902 | cpte++->pg_pfnum|ifrw->ifrw_proto; | |
903 | mtpr(TBIS, cp); | |
904 | cp += NBPG; | |
905 | mtpr(TBIS, (caddr_t)p); | |
906 | p += NBPG / sizeof (*p); | |
907 | } | |
908 | goto nocopy; | |
909 | } | |
910 | nopage: | |
911 | m->m_len = MIN(MLEN, len); | |
912 | m->m_off = MMINOFF; | |
913 | copy: | |
914 | bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); | |
915 | cp += m->m_len; | |
916 | nocopy: | |
917 | *mp = m; | |
918 | mp = &m->m_next; | |
919 | if (off) { | |
920 | /* sort of an ALGOL-W style for statement... */ | |
921 | off += m->m_len; | |
922 | if (off == totlen) { | |
923 | cp = ifrw->ifrw_addr + ifu->ifu_hlen; | |
924 | off = 0; | |
925 | totlen = off0; | |
926 | } | |
927 | } else | |
928 | totlen -= m->m_len; | |
929 | } | |
930 | return (top); | |
931 | bad: | |
932 | m_freem(top); | |
933 | return (0); | |
934 | } | |
935 | ||
936 | /* | |
937 | * Map a chain of mbufs onto a network interface | |
938 | * in preparation for an i/o operation. | |
939 | * The argument chain of mbufs includes the local network | |
940 | * header which is copied to be in the mapped, aligned | |
941 | * i/o space. | |
2af91c21 | 942 | */ |
4843f48e MK |
943 | deput(ifu, n, m) |
944 | struct deuba *ifu; | |
945 | int n; | |
2af91c21 MK |
946 | register struct mbuf *m; |
947 | { | |
948 | register struct mbuf *mp; | |
949 | register caddr_t cp; | |
4843f48e MK |
950 | register struct ifxmt *ifxp; |
951 | register struct ifrw *ifrw; | |
2af91c21 | 952 | register int i; |
4843f48e MK |
953 | int xswapd = 0; |
954 | int x, cc, t; | |
955 | caddr_t dp; | |
2af91c21 | 956 | |
4843f48e MK |
957 | ifxp = &ifu->ifu_w[n]; |
958 | ifrw = &ifxp->x_ifrw; | |
2af91c21 MK |
959 | cp = ifrw->ifrw_addr; |
960 | while (m) { | |
961 | dp = mtod(m, char *); | |
962 | if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) { | |
4843f48e MK |
963 | struct pte *pte; int *ip; |
964 | pte = &Mbmap[mtocl(dp)*CLSIZE]; | |
2af91c21 MK |
965 | x = btop(cp - ifrw->ifrw_addr); |
966 | ip = (int *)&ifrw->ifrw_mr[x]; | |
4843f48e | 967 | for (i = 0; i < CLSIZE; i++) |
2af91c21 | 968 | *ip++ = |
4843f48e MK |
969 | ifrw->ifrw_proto | pte++->pg_pfnum; |
970 | xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT)); | |
971 | mp = m->m_next; | |
972 | m->m_next = ifxp->x_xtofree; | |
973 | ifxp->x_xtofree = m; | |
974 | cp += m->m_len; | |
2af91c21 MK |
975 | } else { |
976 | bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); | |
977 | cp += m->m_len; | |
4843f48e | 978 | MFREE(m, mp); |
2af91c21 | 979 | } |
2af91c21 MK |
980 | m = mp; |
981 | } | |
982 | ||
4843f48e MK |
983 | /* |
984 | * Xswapd is the set of clusters we just mapped out. Ifxp->x_xswapd | |
985 | * is the set of clusters mapped out from before. We compute | |
986 | * the number of clusters involved in this operation in x. | |
987 | * Clusters mapped out before and involved in this operation | |
988 | * should be unmapped so original pages will be accessed by the device. | |
989 | */ | |
2af91c21 | 990 | cc = cp - ifrw->ifrw_addr; |
4843f48e MK |
991 | x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT; |
992 | ifxp->x_xswapd &= ~xswapd; | |
993 | while (i = ffs(ifxp->x_xswapd)) { | |
994 | i--; | |
995 | if (i >= x) | |
996 | break; | |
997 | ifxp->x_xswapd &= ~(1<<i); | |
998 | i *= CLSIZE; | |
999 | for (t = 0; t < CLSIZE; t++) { | |
1000 | ifrw->ifrw_mr[i] = ifxp->x_map[i]; | |
1001 | i++; | |
1002 | } | |
1003 | } | |
1004 | ifxp->x_xswapd |= xswapd; | |
2af91c21 MK |
1005 | return (cc); |
1006 | } | |
2af91c21 MK |
1007 | |
1008 | /* | |
1009 | * Process an ioctl request. | |
1010 | */ | |
1011 | deioctl(ifp, cmd, data) | |
1012 | register struct ifnet *ifp; | |
1013 | int cmd; | |
1014 | caddr_t data; | |
1015 | { | |
7f0e1e06 | 1016 | register struct ifaddr *ifa = (struct ifaddr *)data; |
2af91c21 MK |
1017 | int s = splimp(), error = 0; |
1018 | ||
1019 | switch (cmd) { | |
1020 | ||
1021 | case SIOCSIFADDR: | |
7f0e1e06 | 1022 | ifp->if_flags |= IFF_UP; |
2af91c21 | 1023 | deinit(ifp->if_unit); |
7f0e1e06 MK |
1024 | |
1025 | switch (ifa->ifa_addr.sa_family) { | |
6c21119b | 1026 | #ifdef INET |
7f0e1e06 MK |
1027 | case AF_INET: |
1028 | ((struct arpcom *)ifp)->ac_ipaddr = | |
1029 | IA_SIN(ifa)->sin_addr; | |
1030 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); | |
1031 | break; | |
6c21119b KS |
1032 | #endif |
1033 | #ifdef NS | |
1034 | case AF_NS: | |
cd4baa58 KS |
1035 | { |
1036 | register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); | |
1037 | ||
1038 | if (ns_nullhost(*ina)) { | |
1039 | ina->x_host = * (union ns_host *) | |
6c21119b | 1040 | (de_softc[ifp->if_unit].ds_addr); |
cd4baa58 KS |
1041 | } else { |
1042 | de_setaddr(ina->x_host.c_host,ifp->if_unit); | |
1043 | } | |
6c21119b | 1044 | break; |
cd4baa58 | 1045 | } |
6c21119b | 1046 | #endif |
7f0e1e06 | 1047 | } |
2af91c21 MK |
1048 | break; |
1049 | ||
1050 | default: | |
1051 | error = EINVAL; | |
1052 | } | |
1053 | splx(s); | |
1054 | return (error); | |
1055 | } | |
cd4baa58 KS |
1056 | |
1057 | /* | |
1058 | * set ethernet address for unit | |
1059 | */ | |
1060 | de_setaddr(physaddr, unit) | |
1061 | u_char *physaddr; | |
1062 | int unit; | |
1063 | { | |
1064 | register struct de_softc *ds = &de_softc[unit]; | |
1065 | register struct uba_device *ui = deinfo[unit]; | |
1066 | register struct dedevice *addr= (struct dedevice *)ui->ui_addr; | |
1067 | int csr0; | |
1068 | ||
e61560e0 KS |
1069 | if (! (ds->ds_flags & DSF_RUNNING)) |
1070 | return; | |
1071 | ||
cd4baa58 KS |
1072 | bcopy(physaddr, &ds->ds_pcbb.pcbb2, 6); |
1073 | ds->ds_pcbb.pcbb0 = FC_WTPHYAD; | |
e61560e0 | 1074 | addr->pclow = PCSR0_INTE|CMD_PDMD; |
cd4baa58 KS |
1075 | csr0 = addr->pcsr0; |
1076 | addr->pchigh = csr0 >> 8; | |
1077 | if (csr0 & PCSR0_PCEI) | |
1078 | printf("de%d: wtphyad failed, csr0=%b csr1=%b\n", | |
1079 | ui->ui_unit, csr0, PCSR0_BITS, | |
1080 | addr->pcsr1, PCSR1_BITS); | |
1081 | } | |
1082 | ||
4843f48e | 1083 | #endif |
cd4baa58 | 1084 |