Commit | Line | Data |
---|---|---|
c82f8ef0 | 1 | /* @(#)if_qe.c 7.6 (Berkeley) %G% */ |
aabe40e7 | 2 | |
5b6dfa0c | 3 | /* from @(#)if_qe.c 1.15 (ULTRIX) 4/16/86 */ |
aabe40e7 KD |
4 | |
5 | ||
6 | /**************************************************************** | |
7 | * * | |
8 | * Licensed from Digital Equipment Corporation * | |
9 | * Copyright (c) * | |
10 | * Digital Equipment Corporation * | |
11 | * Maynard, Massachusetts * | |
12 | * 1985, 1986 * | |
13 | * All rights reserved. * | |
14 | * * | |
15 | * The Information in this software is subject to change * | |
16 | * without notice and should not be construed as a commitment * | |
17 | * by Digital Equipment Corporation. Digital makes no * | |
18 | * representations about the suitability of this software for * | |
19 | * any purpose. It is supplied "As Is" without expressed or * | |
20 | * implied warranty. * | |
21 | * * | |
22 | * If the Regents of the University of California or its * | |
23 | * licensees modify the software in a manner creating * | |
5b6dfa0c MK |
24 | * derivative copyright rights, appropriate copyright * |
25 | * legends may be placed on the derivative work in addition * | |
aabe40e7 KD |
26 | * to that set forth above. * |
27 | * * | |
28 | ****************************************************************/ | |
29 | /* --------------------------------------------------------------------- | |
30 | * Modification History | |
31 | * | |
32 | * 15-Apr-86 -- afd | |
33 | * Rename "unused_multi" to "qunused_multi" for extending Generic | |
34 | * kernel to MicroVAXen. | |
35 | * | |
36 | * 18-mar-86 -- jaw br/cvec changed to NOT use registers. | |
37 | * | |
38 | * 12 March 86 -- Jeff Chase | |
39 | * Modified to handle the new MCLGET macro | |
40 | * Changed if_qe_data.c to use more receive buffers | |
41 | * Added a flag to poke with adb to log qe_restarts on console | |
42 | * | |
43 | * 19 Oct 85 -- rjl | |
44 | * Changed the watch dog timer from 30 seconds to 3. VMS is using | |
45 | * less than 1 second in their's. Also turned the printf into an | |
46 | * mprintf. | |
47 | * | |
48 | * 09/16/85 -- Larry Cohen | |
49 | * Add 43bsd alpha tape changes for subnet routing | |
50 | * | |
51 | * 1 Aug 85 -- rjl | |
52 | * Panic on a non-existent memory interrupt and the case where a packet | |
53 | * was chained. The first should never happen because non-existant | |
54 | * memory interrupts cause a bus reset. The second should never happen | |
55 | * because we hang 2k input buffers on the device. | |
56 | * | |
57 | * 1 Aug 85 -- rich | |
58 | * Fixed the broadcast loopback code to handle Clusters without | |
59 | * wedging the system. | |
60 | * | |
61 | * 27 Feb. 85 -- ejf | |
62 | * Return default hardware address on ioctl request. | |
63 | * | |
64 | * 12 Feb. 85 -- ejf | |
65 | * Added internal extended loopback capability. | |
66 | * | |
67 | * 27 Dec. 84 -- rjl | |
68 | * Fixed bug that caused every other transmit descriptor to be used | |
69 | * instead of every descriptor. | |
70 | * | |
71 | * 21 Dec. 84 -- rjl | |
72 | * Added watchdog timer to mask hardware bug that causes device lockup. | |
73 | * | |
74 | * 18 Dec. 84 -- rjl | |
75 | * Reworked driver to use q-bus mapping routines. MicroVAX-I now does | |
76 | * copying instead of m-buf shuffleing. | |
77 | * A number of deficencies in the hardware/firmware were compensated | |
78 | * for. See comments in qestart and qerint. | |
79 | * | |
80 | * 14 Nov. 84 -- jf | |
81 | * Added usage counts for multicast addresses. | |
82 | * Updated general protocol support to allow access to the Ethernet | |
83 | * header. | |
84 | * | |
85 | * 04 Oct. 84 -- jf | |
86 | * Added support for new ioctls to add and delete multicast addresses | |
87 | * and set the physical address. | |
88 | * Add support for general protocols. | |
89 | * | |
90 | * 14 Aug. 84 -- rjl | |
91 | * Integrated Shannon changes. (allow arp above 1024 and ? ) | |
92 | * | |
93 | * 13 Feb. 84 -- rjl | |
94 | * | |
95 | * Initial version of driver. derived from IL driver. | |
96 | * | |
97 | * --------------------------------------------------------------------- | |
98 | */ | |
99 | ||
100 | #include "qe.h" | |
5b6dfa0c | 101 | #if NQE > 0 |
aabe40e7 KD |
102 | /* |
103 | * Digital Q-BUS to NI Adapter | |
104 | */ | |
5b6dfa0c MK |
105 | #include "param.h" |
106 | #include "systm.h" | |
107 | #include "mbuf.h" | |
108 | #include "buf.h" | |
109 | #include "protosw.h" | |
110 | #include "socket.h" | |
111 | #include "vmmac.h" | |
112 | #include "ioctl.h" | |
113 | #include "errno.h" | |
114 | #include "syslog.h" | |
115 | #include "time.h" | |
116 | #include "kernel.h" | |
117 | ||
118 | #include "../net/if.h" | |
119 | #include "../net/netisr.h" | |
120 | #include "../net/route.h" | |
121 | ||
122 | #ifdef INET | |
123 | #include "../netinet/in.h" | |
124 | #include "../netinet/in_systm.h" | |
125 | #include "../netinet/in_var.h" | |
126 | #include "../netinet/ip.h" | |
127 | #include "../netinet/if_ether.h" | |
128 | #endif | |
129 | ||
130 | #ifdef NS | |
131 | #include "../netns/ns.h" | |
132 | #include "../netns/ns_if.h" | |
133 | #endif | |
134 | ||
0b8a7d57 | 135 | #include "../vax/pte.h" |
5b6dfa0c MK |
136 | #include "../vax/cpu.h" |
137 | #include "../vax/mtpr.h" | |
138 | #include "if_qereg.h" | |
139 | #include "if_uba.h" | |
140 | #include "../vaxuba/ubareg.h" | |
141 | #include "../vaxuba/ubavar.h" | |
142 | ||
a7f4fd96 MK |
143 | #if NQE > 1 |
144 | #define NRCV 15 /* Receive descriptors */ | |
145 | #else | |
146 | #define NRCV 20 /* Receive descriptors */ | |
147 | #endif | |
5b6dfa0c MK |
148 | #define NXMT 5 /* Transmit descriptors */ |
149 | #define NTOT (NXMT + NRCV) | |
0b8a7d57 MK |
150 | |
151 | #define QETIMEOUT 2 /* transmit timeout, must be > 1 */ | |
5b6dfa0c MK |
152 | |
153 | /* | |
154 | * This constant should really be 60 because the qna adds 4 bytes of crc. | |
155 | * However when set to 60 our packets are ignored by deuna's , 3coms are | |
156 | * okay ?????????????????????????????????????????? | |
157 | */ | |
158 | #define MINDATA 64 | |
159 | ||
160 | /* | |
161 | * Ethernet software status per interface. | |
162 | * | |
163 | * Each interface is referenced by a network interface structure, | |
0b8a7d57 | 164 | * qe_if, which the routing code uses to locate the interface. |
5b6dfa0c MK |
165 | * This structure contains the output queue for the interface, its address, ... |
166 | */ | |
167 | struct qe_softc { | |
0b8a7d57 MK |
168 | struct arpcom qe_ac; /* Ethernet common part */ |
169 | #define qe_if qe_ac.ac_if /* network-visible interface */ | |
170 | #define qe_addr qe_ac.ac_enaddr /* hardware Ethernet address */ | |
5b6dfa0c MK |
171 | struct ifubinfo qe_uba; /* Q-bus resources */ |
172 | struct ifrw qe_ifr[NRCV]; /* for receive buffers; */ | |
173 | struct ifxmt qe_ifw[NXMT]; /* for xmit buffers; */ | |
174 | int qe_flags; /* software state */ | |
175 | #define QEF_RUNNING 0x01 | |
176 | #define QEF_SETADDR 0x02 | |
177 | int setupaddr; /* mapping info for setup pkts */ | |
178 | struct qe_ring *rringaddr; /* mapping info for rings */ | |
179 | struct qe_ring *tringaddr; /* "" */ | |
180 | struct qe_ring rring[NRCV+1]; /* Receive ring descriptors */ | |
181 | struct qe_ring tring[NXMT+1]; /* Transmit ring descriptors */ | |
182 | u_char setup_pkt[16][8]; /* Setup packet */ | |
183 | int rindex; /* Receive index */ | |
184 | int tindex; /* Transmit index */ | |
185 | int otindex; /* Old transmit index */ | |
186 | int qe_intvec; /* Interrupt vector */ | |
187 | struct qedevice *addr; /* device addr */ | |
188 | int setupqueued; /* setup packet queued */ | |
189 | int nxmit; /* Transmits in progress */ | |
5b6dfa0c MK |
190 | int qe_restarts; /* timeouts */ |
191 | } qe_softc[NQE]; | |
192 | ||
193 | struct uba_device *qeinfo[NQE]; | |
aabe40e7 | 194 | |
aabe40e7 | 195 | extern struct timeval time; |
aabe40e7 | 196 | |
0b8a7d57 MK |
197 | int qeprobe(), qeattach(), qeintr(), qetimeout(); |
198 | int qeinit(), qeoutput(), qeioctl(), qereset(); | |
aabe40e7 KD |
199 | |
200 | u_short qestd[] = { 0 }; | |
201 | struct uba_driver qedriver = | |
202 | { qeprobe, 0, qeattach, 0, qestd, "qe", qeinfo }; | |
203 | ||
aabe40e7 KD |
204 | #define QE_TIMEO (15) |
205 | #define QEUNIT(x) minor(x) | |
206 | static int mask = 0x3ffff; /* address mask */ | |
aabe40e7 | 207 | /* |
5b6dfa0c | 208 | * The deqna shouldn't receive more than ETHERMTU + sizeof(struct ether_header) |
aabe40e7 KD |
209 | * but will actually take in up to 2048 bytes. To guard against the receiver |
210 | * chaining buffers (which we aren't prepared to handle) we allocate 2kb | |
211 | * size buffers. | |
212 | */ | |
213 | #define MAXPACKETSIZE 2048 /* Should really be ETHERMTU */ | |
214 | /* | |
215 | * Probe the QNA to see if it's there | |
216 | */ | |
217 | qeprobe(reg) | |
218 | caddr_t reg; | |
219 | { | |
5b6dfa0c | 220 | register int br, cvec; /* r11, r10 value-result */ |
aabe40e7 KD |
221 | register struct qedevice *addr = (struct qedevice *)reg; |
222 | register struct qe_ring *rp; | |
223 | register struct qe_ring *prp; /* physical rp */ | |
5ba846a2 | 224 | register int i, j; |
aabe40e7 KD |
225 | static int next=0; /* softc index */ |
226 | register struct qe_softc *sc = &qe_softc[next++]; | |
227 | ||
5ba846a2 MK |
228 | #ifdef lint |
229 | br = 0; cvec = br; br = cvec; | |
58bca61d | 230 | qeintr(0); |
5ba846a2 | 231 | #endif |
aabe40e7 KD |
232 | /* |
233 | * Set the address mask for the particular cpu | |
234 | */ | |
5b6dfa0c | 235 | mask = 0x3ffff; |
aabe40e7 KD |
236 | |
237 | /* | |
238 | * The QNA interrupts on i/o operations. To do an I/O operation | |
239 | * we have to setup the interface by transmitting a setup packet. | |
240 | */ | |
241 | addr->qe_csr = QE_RESET; | |
242 | addr->qe_vector = (uba_hd[numuba].uh_lastiv -= 4); | |
243 | ||
244 | /* | |
245 | * Map the communications area and the setup packet. | |
246 | */ | |
247 | sc->setupaddr = | |
58bca61d MK |
248 | uballoc(0, (caddr_t)sc->setup_pkt, sizeof(sc->setup_pkt), 0); |
249 | sc->rringaddr = (struct qe_ring *) uballoc(0, (caddr_t)sc->rring, | |
250 | sizeof(struct qe_ring) * (NTOT+2), 0); | |
aabe40e7 KD |
251 | prp = (struct qe_ring *)((int)sc->rringaddr & mask); |
252 | ||
253 | /* | |
254 | * The QNA will loop the setup packet back to the receive ring | |
255 | * for verification, therefore we initialize the first | |
256 | * receive & transmit ring descriptors and link the setup packet | |
257 | * to them. | |
258 | */ | |
58bca61d MK |
259 | qeinitdesc(sc->tring, (caddr_t)(sc->setupaddr & mask), |
260 | sizeof(sc->setup_pkt)); | |
261 | qeinitdesc(sc->rring, (caddr_t)(sc->setupaddr & mask), | |
262 | sizeof(sc->setup_pkt)); | |
aabe40e7 KD |
263 | |
264 | rp = (struct qe_ring *)sc->tring; | |
265 | rp->qe_setup = 1; | |
266 | rp->qe_eomsg = 1; | |
267 | rp->qe_flag = rp->qe_status1 = QE_NOTYET; | |
268 | rp->qe_valid = 1; | |
269 | ||
270 | rp = (struct qe_ring *)sc->rring; | |
271 | rp->qe_flag = rp->qe_status1 = QE_NOTYET; | |
272 | rp->qe_valid = 1; | |
273 | ||
274 | /* | |
275 | * Get the addr off of the interface and place it into the setup | |
276 | * packet. This code looks strange due to the fact that the address | |
277 | * is placed in the setup packet in col. major order. | |
278 | */ | |
279 | for( i = 0 ; i < 6 ; i++ ) | |
280 | sc->setup_pkt[i][1] = addr->qe_sta_addr[i]; | |
281 | ||
282 | qesetup( sc ); | |
283 | /* | |
284 | * Start the interface and wait for the packet. | |
285 | */ | |
286 | j = cvec; | |
287 | addr->qe_csr = QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT; | |
288 | addr->qe_rcvlist_lo = (short)prp; | |
289 | addr->qe_rcvlist_hi = (short)((int)prp >> 16); | |
5b6dfa0c | 290 | prp += NRCV+1; |
aabe40e7 KD |
291 | addr->qe_xmtlist_lo = (short)prp; |
292 | addr->qe_xmtlist_hi = (short)((int)prp >> 16); | |
293 | DELAY(10000); | |
294 | /* | |
5b6dfa0c | 295 | * All done with the bus resources. |
aabe40e7 | 296 | */ |
5b6dfa0c | 297 | ubarelse(0, &sc->setupaddr); |
58bca61d | 298 | ubarelse(0, (int *)&sc->rringaddr); |
aabe40e7 KD |
299 | if( cvec == j ) |
300 | return 0; /* didn't interrupt */ | |
0b8a7d57 MK |
301 | |
302 | br = 0x15; /* q-bus doesn't get level */ | |
aabe40e7 KD |
303 | return( sizeof(struct qedevice) ); |
304 | } | |
305 | ||
306 | /* | |
307 | * Interface exists: make available by filling in network interface | |
308 | * record. System will initialize the interface when it is ready | |
309 | * to accept packets. | |
310 | */ | |
311 | qeattach(ui) | |
312 | struct uba_device *ui; | |
313 | { | |
314 | register struct qe_softc *sc = &qe_softc[ui->ui_unit]; | |
0b8a7d57 | 315 | register struct ifnet *ifp = &sc->qe_if; |
aabe40e7 KD |
316 | register struct qedevice *addr = (struct qedevice *)ui->ui_addr; |
317 | register int i; | |
aabe40e7 KD |
318 | |
319 | ifp->if_unit = ui->ui_unit; | |
320 | ifp->if_name = "qe"; | |
321 | ifp->if_mtu = ETHERMTU; | |
5b6dfa0c | 322 | ifp->if_flags = IFF_BROADCAST; |
aabe40e7 KD |
323 | |
324 | /* | |
325 | * Read the address from the prom and save it. | |
326 | */ | |
327 | for( i=0 ; i<6 ; i++ ) | |
0b8a7d57 MK |
328 | sc->setup_pkt[i][1] = sc->qe_addr[i] = addr->qe_sta_addr[i] & 0xff; |
329 | printf("qe%d: hardware address %s\n", ui->ui_unit, | |
c82f8ef0 | 330 | ether_sprintf(sc->qe_addr)); |
aabe40e7 KD |
331 | |
332 | /* | |
333 | * Save the vector for initialization at reset time. | |
334 | */ | |
335 | sc->qe_intvec = addr->qe_vector; | |
336 | ||
aabe40e7 KD |
337 | ifp->if_init = qeinit; |
338 | ifp->if_output = qeoutput; | |
339 | ifp->if_ioctl = qeioctl; | |
340 | ifp->if_reset = qereset; | |
0b8a7d57 | 341 | ifp->if_watchdog = qetimeout; |
5b6dfa0c | 342 | sc->qe_uba.iff_flags = UBA_CANTWAIT; |
aabe40e7 KD |
343 | if_attach(ifp); |
344 | } | |
345 | ||
346 | /* | |
347 | * Reset of interface after UNIBUS reset. | |
348 | * If interface is on specified uba, reset its state. | |
349 | */ | |
350 | qereset(unit, uban) | |
351 | int unit, uban; | |
352 | { | |
353 | register struct uba_device *ui; | |
354 | ||
5b6dfa0c | 355 | if (unit >= NQE || (ui = qeinfo[unit]) == 0 || ui->ui_alive == 0 || |
aabe40e7 KD |
356 | ui->ui_ubanum != uban) |
357 | return; | |
358 | printf(" qe%d", unit); | |
0b8a7d57 | 359 | qe_softc[unit].qe_if.if_flags &= ~IFF_RUNNING; |
aabe40e7 KD |
360 | qeinit(unit); |
361 | } | |
362 | ||
363 | /* | |
364 | * Initialization of interface. | |
365 | */ | |
366 | qeinit(unit) | |
367 | int unit; | |
368 | { | |
369 | register struct qe_softc *sc = &qe_softc[unit]; | |
370 | register struct uba_device *ui = qeinfo[unit]; | |
371 | register struct qedevice *addr = (struct qedevice *)ui->ui_addr; | |
0b8a7d57 | 372 | register struct ifnet *ifp = &sc->qe_if; |
aabe40e7 KD |
373 | register i; |
374 | int s; | |
375 | ||
376 | /* address not known */ | |
aabe40e7 KD |
377 | if (ifp->if_addrlist == (struct ifaddr *)0) |
378 | return; | |
5b6dfa0c | 379 | if (sc->qe_flags & QEF_RUNNING) |
aabe40e7 KD |
380 | return; |
381 | ||
5b6dfa0c MK |
382 | if ((ifp->if_flags & IFF_RUNNING) == 0) { |
383 | /* | |
384 | * map the communications area onto the device | |
385 | */ | |
58bca61d MK |
386 | sc->rringaddr = (struct qe_ring *) |
387 | ((int) uballoc(0, (caddr_t)sc->rring, | |
5b6dfa0c MK |
388 | sizeof(struct qe_ring) * (NTOT+2), 0) & mask); |
389 | sc->tringaddr = sc->rringaddr + NRCV + 1; | |
58bca61d | 390 | sc->setupaddr = uballoc(0, (caddr_t)sc->setup_pkt, |
5b6dfa0c MK |
391 | sizeof(sc->setup_pkt), 0) & mask; |
392 | /* | |
393 | * init buffers and maps | |
394 | */ | |
395 | if (if_ubaminit(&sc->qe_uba, ui->ui_ubanum, | |
396 | sizeof (struct ether_header), (int)btoc(MAXPACKETSIZE), | |
397 | sc->qe_ifr, NRCV, sc->qe_ifw, NXMT) == 0) { | |
398 | printf("qe%d: can't initialize\n", unit); | |
0b8a7d57 | 399 | sc->qe_if.if_flags &= ~IFF_UP; |
5b6dfa0c MK |
400 | return; |
401 | } | |
aabe40e7 KD |
402 | } |
403 | /* | |
404 | * Init the buffer descriptors and indexes for each of the lists and | |
405 | * loop them back to form a ring. | |
406 | */ | |
5b6dfa0c | 407 | for (i = 0; i < NRCV; i++) { |
aabe40e7 | 408 | qeinitdesc( &sc->rring[i], |
58bca61d | 409 | (caddr_t)(sc->qe_ifr[i].ifrw_info & mask), MAXPACKETSIZE); |
aabe40e7 KD |
410 | sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET; |
411 | sc->rring[i].qe_valid = 1; | |
412 | } | |
58bca61d | 413 | qeinitdesc(&sc->rring[i], (caddr_t)NULL, 0); |
aabe40e7 KD |
414 | |
415 | sc->rring[i].qe_addr_lo = (short)sc->rringaddr; | |
416 | sc->rring[i].qe_addr_hi = (short)((int)sc->rringaddr >> 16); | |
417 | sc->rring[i].qe_chain = 1; | |
418 | sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET; | |
419 | sc->rring[i].qe_valid = 1; | |
420 | ||
5b6dfa0c | 421 | for( i = 0 ; i <= NXMT ; i++ ) |
58bca61d | 422 | qeinitdesc(&sc->tring[i], (caddr_t)NULL, 0); |
aabe40e7 KD |
423 | i--; |
424 | ||
425 | sc->tring[i].qe_addr_lo = (short)sc->tringaddr; | |
426 | sc->tring[i].qe_addr_hi = (short)((int)sc->tringaddr >> 16); | |
427 | sc->tring[i].qe_chain = 1; | |
428 | sc->tring[i].qe_flag = sc->tring[i].qe_status1 = QE_NOTYET; | |
429 | sc->tring[i].qe_valid = 1; | |
430 | ||
431 | sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0; | |
432 | ||
433 | /* | |
434 | * Take the interface out of reset, program the vector, | |
435 | * enable interrupts, and tell the world we are up. | |
436 | */ | |
437 | s = splimp(); | |
438 | addr->qe_vector = sc->qe_intvec; | |
439 | sc->addr = addr; | |
5b6dfa0c MK |
440 | addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | |
441 | QE_RCV_INT | QE_ILOOP; | |
aabe40e7 KD |
442 | addr->qe_rcvlist_lo = (short)sc->rringaddr; |
443 | addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16); | |
444 | ifp->if_flags |= IFF_UP | IFF_RUNNING; | |
5b6dfa0c | 445 | sc->qe_flags |= QEF_RUNNING; |
aabe40e7 KD |
446 | qesetup( sc ); |
447 | qestart( unit ); | |
aabe40e7 KD |
448 | splx( s ); |
449 | ||
450 | } | |
451 | ||
452 | /* | |
453 | * Start output on interface. | |
454 | * | |
455 | */ | |
0b8a7d57 MK |
456 | qestart(unit) |
457 | int unit; | |
aabe40e7 | 458 | { |
aabe40e7 KD |
459 | struct uba_device *ui = qeinfo[unit]; |
460 | register struct qe_softc *sc = &qe_softc[unit]; | |
461 | register struct qedevice *addr; | |
462 | register struct qe_ring *rp; | |
463 | register index; | |
5ba846a2 MK |
464 | struct mbuf *m; |
465 | int buf_addr, len, s; | |
aabe40e7 KD |
466 | |
467 | ||
468 | s = splimp(); | |
469 | addr = (struct qedevice *)ui->ui_addr; | |
470 | /* | |
471 | * The deqna doesn't look at anything but the valid bit | |
472 | * to determine if it should transmit this packet. If you have | |
473 | * a ring and fill it the device will loop indefinately on the | |
474 | * packet and continue to flood the net with packets until you | |
475 | * break the ring. For this reason we never queue more than n-1 | |
476 | * packets in the transmit ring. | |
477 | * | |
478 | * The microcoders should have obeyed their own defination of the | |
479 | * flag and status words, but instead we have to compensate. | |
480 | */ | |
481 | for( index = sc->tindex; | |
5b6dfa0c MK |
482 | sc->tring[index].qe_valid == 0 && sc->nxmit < (NXMT-1) ; |
483 | sc->tindex = index = ++index % NXMT){ | |
aabe40e7 KD |
484 | rp = &sc->tring[index]; |
485 | if( sc->setupqueued ) { | |
486 | buf_addr = sc->setupaddr; | |
487 | len = 128; | |
488 | rp->qe_setup = 1; | |
489 | sc->setupqueued = 0; | |
490 | } else { | |
0b8a7d57 | 491 | IF_DEQUEUE(&sc->qe_if.if_snd, m); |
aabe40e7 KD |
492 | if( m == 0 ){ |
493 | splx(s); | |
494 | return; | |
495 | } | |
5b6dfa0c MK |
496 | buf_addr = sc->qe_ifw[index].ifw_info; |
497 | len = if_ubaput(&sc->qe_uba, &sc->qe_ifw[index], m); | |
aabe40e7 KD |
498 | } |
499 | /* | |
500 | * Does buffer end on odd byte ? | |
501 | */ | |
502 | if( len & 1 ) { | |
503 | len++; | |
504 | rp->qe_odd_end = 1; | |
505 | } | |
506 | if( len < MINDATA ) | |
507 | len = MINDATA; | |
508 | rp->qe_buf_len = -(len/2); | |
509 | buf_addr &= mask; | |
510 | rp->qe_flag = rp->qe_status1 = QE_NOTYET; | |
511 | rp->qe_addr_lo = (short)buf_addr; | |
512 | rp->qe_addr_hi = (short)(buf_addr >> 16); | |
513 | rp->qe_eomsg = 1; | |
514 | rp->qe_flag = rp->qe_status1 = QE_NOTYET; | |
515 | rp->qe_valid = 1; | |
516 | sc->nxmit++; | |
0b8a7d57 | 517 | sc->qe_if.if_timer = QETIMEOUT; |
aabe40e7 KD |
518 | |
519 | /* | |
520 | * See if the xmit list is invalid. | |
521 | */ | |
522 | if( addr->qe_csr & QE_XL_INVALID ) { | |
523 | buf_addr = (int)(sc->tringaddr+index); | |
524 | addr->qe_xmtlist_lo = (short)buf_addr; | |
525 | addr->qe_xmtlist_hi = (short)(buf_addr >> 16); | |
526 | } | |
aabe40e7 KD |
527 | } |
528 | splx( s ); | |
529 | } | |
530 | ||
531 | /* | |
532 | * Ethernet interface interrupt processor | |
533 | */ | |
534 | qeintr(unit) | |
535 | int unit; | |
536 | { | |
537 | register struct qe_softc *sc = &qe_softc[unit]; | |
aabe40e7 KD |
538 | struct qedevice *addr = (struct qedevice *)qeinfo[unit]->ui_addr; |
539 | int s, buf_addr, csr; | |
540 | ||
541 | s = splimp(); | |
542 | csr = addr->qe_csr; | |
5b6dfa0c | 543 | addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP; |
aabe40e7 KD |
544 | if( csr & QE_RCV_INT ) |
545 | qerint( unit ); | |
546 | if( csr & QE_XMIT_INT ) | |
547 | qetint( unit ); | |
548 | if( csr & QE_NEX_MEM_INT ) | |
549 | panic("qe: Non existant memory interrupt"); | |
550 | ||
551 | if( addr->qe_csr & QE_RL_INVALID && sc->rring[sc->rindex].qe_status1 == QE_NOTYET ) { | |
552 | buf_addr = (int)&sc->rringaddr[sc->rindex]; | |
553 | addr->qe_rcvlist_lo = (short)buf_addr; | |
554 | addr->qe_rcvlist_hi = (short)(buf_addr >> 16); | |
555 | } | |
556 | splx( s ); | |
557 | } | |
558 | ||
559 | /* | |
560 | * Ethernet interface transmit interrupt. | |
561 | */ | |
562 | ||
563 | qetint(unit) | |
564 | int unit; | |
565 | { | |
566 | register struct qe_softc *sc = &qe_softc[unit]; | |
aabe40e7 | 567 | register struct qe_ring *rp; |
aabe40e7 | 568 | register struct ifxmt *ifxp; |
5ba846a2 | 569 | int status1, setupflag; |
aabe40e7 KD |
570 | short len; |
571 | ||
572 | ||
573 | while( sc->otindex != sc->tindex && sc->tring[sc->otindex].qe_status1 != QE_NOTYET && sc->nxmit > 0 ) { | |
574 | /* | |
575 | * Save the status words from the descriptor so that it can | |
576 | * be released. | |
577 | */ | |
578 | rp = &sc->tring[sc->otindex]; | |
579 | status1 = rp->qe_status1; | |
aabe40e7 KD |
580 | setupflag = rp->qe_setup; |
581 | len = (-rp->qe_buf_len) * 2; | |
582 | if( rp->qe_odd_end ) | |
583 | len++; | |
584 | /* | |
585 | * Init the buffer descriptor | |
586 | */ | |
58bca61d | 587 | bzero((caddr_t)rp, sizeof(struct qe_ring)); |
aabe40e7 | 588 | if( --sc->nxmit == 0 ) |
0b8a7d57 | 589 | sc->qe_if.if_timer = 0; |
aabe40e7 KD |
590 | if( !setupflag ) { |
591 | /* | |
592 | * Do some statistics. | |
593 | */ | |
0b8a7d57 MK |
594 | sc->qe_if.if_opackets++; |
595 | sc->qe_if.if_collisions += ( status1 & QE_CCNT ) >> 4; | |
5b6dfa0c | 596 | if (status1 & QE_ERROR) |
0b8a7d57 | 597 | sc->qe_if.if_oerrors++; |
aabe40e7 KD |
598 | /* |
599 | * If this was a broadcast packet loop it | |
5b6dfa0c MK |
600 | * back because the hardware can't hear its own |
601 | * transmits. | |
aabe40e7 | 602 | */ |
5b6dfa0c | 603 | ifxp = &sc->qe_ifw[sc->otindex]; |
805c7eea MK |
604 | if (bcmp((caddr_t)((struct ether_header *)ifxp->ifw_addr)->ether_dhost, |
605 | (caddr_t)etherbroadcastaddr, | |
606 | sizeof(etherbroadcastaddr)) == 0) | |
607 | qeread(sc, &ifxp->ifrw, | |
608 | len - sizeof(struct ether_header)); | |
5b6dfa0c MK |
609 | if (ifxp->ifw_xtofree) { |
610 | m_freem(ifxp->ifw_xtofree); | |
611 | ifxp->ifw_xtofree = 0; | |
aabe40e7 KD |
612 | } |
613 | } | |
5b6dfa0c | 614 | sc->otindex = ++sc->otindex % NXMT; |
aabe40e7 KD |
615 | } |
616 | qestart( unit ); | |
617 | } | |
618 | ||
619 | /* | |
620 | * Ethernet interface receiver interrupt. | |
621 | * If can't determine length from type, then have to drop packet. | |
622 | * Othewise decapsulate packet based on type and pass to type specific | |
623 | * higher-level input routine. | |
624 | */ | |
625 | qerint(unit) | |
626 | int unit; | |
627 | { | |
628 | register struct qe_softc *sc = &qe_softc[unit]; | |
aabe40e7 KD |
629 | register struct qe_ring *rp; |
630 | int len, status1, status2; | |
631 | int bufaddr; | |
aabe40e7 KD |
632 | |
633 | /* | |
634 | * Traverse the receive ring looking for packets to pass back. | |
635 | * The search is complete when we find a descriptor not in use. | |
636 | * | |
637 | * As in the transmit case the deqna doesn't honor it's own protocols | |
638 | * so there exists the possibility that the device can beat us around | |
639 | * the ring. The proper way to guard against this is to insure that | |
640 | * there is always at least one invalid descriptor. We chose instead | |
641 | * to make the ring large enough to minimize the problem. With a ring | |
642 | * size of 4 we haven't been able to see the problem. To be safe we | |
643 | * doubled that to 8. | |
644 | * | |
645 | */ | |
5b6dfa0c | 646 | for( ; sc->rring[sc->rindex].qe_status1 != QE_NOTYET ; sc->rindex = ++sc->rindex % NRCV ){ |
aabe40e7 KD |
647 | rp = &sc->rring[sc->rindex]; |
648 | status1 = rp->qe_status1; | |
649 | status2 = rp->qe_status2; | |
58bca61d | 650 | bzero((caddr_t)rp, sizeof(struct qe_ring)); |
aabe40e7 KD |
651 | if( (status1 & QE_MASK) == QE_MASK ) |
652 | panic("qe: chained packet"); | |
5b6dfa0c | 653 | len = ((status1 & QE_RBL_HI) | (status2 & QE_RBL_LO)) + 60; |
0b8a7d57 | 654 | sc->qe_if.if_ipackets++; |
aabe40e7 | 655 | |
805c7eea MK |
656 | if (status1 & QE_ERROR) { |
657 | if ((status1 & QE_RUNT) == 0) | |
0b8a7d57 | 658 | sc->qe_if.if_ierrors++; |
805c7eea | 659 | } else { |
5b6dfa0c MK |
660 | /* |
661 | * We don't process setup packets. | |
662 | */ | |
663 | if( !(status1 & QE_ESETUP) ) | |
664 | qeread(sc, &sc->qe_ifr[sc->rindex], | |
665 | len - sizeof(struct ether_header)); | |
aabe40e7 KD |
666 | } |
667 | /* | |
668 | * Return the buffer to the ring | |
669 | */ | |
5b6dfa0c | 670 | bufaddr = (int)sc->qe_ifr[sc->rindex].ifrw_info & mask; |
aabe40e7 KD |
671 | rp->qe_buf_len = -((MAXPACKETSIZE)/2); |
672 | rp->qe_addr_lo = (short)bufaddr; | |
673 | rp->qe_addr_hi = (short)((int)bufaddr >> 16); | |
674 | rp->qe_flag = rp->qe_status1 = QE_NOTYET; | |
675 | rp->qe_valid = 1; | |
676 | } | |
677 | } | |
678 | /* | |
679 | * Ethernet output routine. | |
680 | * Encapsulate a packet of type family for the local net. | |
681 | * Use trailer local net encapsulation if enough data in first | |
682 | * packet leaves a multiple of 512 bytes of data in remainder. | |
683 | */ | |
684 | qeoutput(ifp, m0, dst) | |
685 | struct ifnet *ifp; | |
686 | struct mbuf *m0; | |
687 | struct sockaddr *dst; | |
688 | { | |
689 | int type, s, error; | |
690 | u_char edst[6]; | |
691 | struct in_addr idst; | |
aabe40e7 KD |
692 | register struct qe_softc *is = &qe_softc[ifp->if_unit]; |
693 | register struct mbuf *m = m0; | |
694 | register struct ether_header *eh; | |
695 | register int off; | |
5b6dfa0c | 696 | int usetrailers; |
aabe40e7 | 697 | |
5b6dfa0c MK |
698 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { |
699 | error = ENETDOWN; | |
700 | goto bad; | |
701 | } | |
702 | ||
aabe40e7 KD |
703 | switch (dst->sa_family) { |
704 | ||
705 | #ifdef INET | |
706 | case AF_INET: | |
aabe40e7 | 707 | idst = ((struct sockaddr_in *)dst)->sin_addr; |
0b8a7d57 | 708 | if (!arpresolve(&is->qe_ac, m, &idst, edst, &usetrailers)) |
aabe40e7 KD |
709 | return (0); /* if not yet resolved */ |
710 | off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; | |
5b6dfa0c MK |
711 | if (usetrailers && off > 0 && (off & 0x1ff) == 0 && |
712 | m->m_off >= MMINOFF + 2 * sizeof (u_short)) { | |
aabe40e7 KD |
713 | type = ETHERTYPE_TRAIL + (off>>9); |
714 | m->m_off -= 2 * sizeof (u_short); | |
715 | m->m_len += 2 * sizeof (u_short); | |
716 | *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); | |
717 | *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); | |
5b6dfa0c | 718 | goto gottrailertype; |
aabe40e7 KD |
719 | } |
720 | type = ETHERTYPE_IP; | |
721 | off = 0; | |
722 | goto gottype; | |
723 | #endif | |
5b6dfa0c MK |
724 | #ifdef NS |
725 | case AF_NS: | |
726 | type = ETHERTYPE_NS; | |
727 | bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), | |
728 | (caddr_t)edst, sizeof (edst)); | |
729 | off = 0; | |
730 | goto gottype; | |
731 | #endif | |
732 | ||
aabe40e7 KD |
733 | |
734 | case AF_UNSPEC: | |
735 | eh = (struct ether_header *)dst->sa_data; | |
736 | bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); | |
737 | type = eh->ether_type; | |
738 | goto gottype; | |
739 | ||
740 | default: | |
5b6dfa0c MK |
741 | printf("qe%d: can't handle af%d\n", ifp->if_unit, |
742 | dst->sa_family); | |
743 | error = EAFNOSUPPORT; | |
744 | goto bad; | |
aabe40e7 KD |
745 | } |
746 | ||
5b6dfa0c | 747 | gottrailertype: |
aabe40e7 KD |
748 | /* |
749 | * Packet to be sent as trailer: move first packet | |
750 | * (control information) to end of chain. | |
751 | */ | |
752 | while (m->m_next) | |
753 | m = m->m_next; | |
754 | m->m_next = m0; | |
755 | m = m0->m_next; | |
756 | m0->m_next = 0; | |
757 | m0 = m; | |
758 | ||
759 | gottype: | |
760 | /* | |
761 | * Add local net header. If no space in first mbuf, | |
762 | * allocate another. | |
763 | */ | |
5b6dfa0c MK |
764 | if (m->m_off > MMAXOFF || |
765 | MMINOFF + sizeof (struct ether_header) > m->m_off) { | |
aabe40e7 KD |
766 | m = m_get(M_DONTWAIT, MT_HEADER); |
767 | if (m == 0) { | |
768 | error = ENOBUFS; | |
769 | goto bad; | |
770 | } | |
771 | m->m_next = m0; | |
772 | m->m_off = MMINOFF; | |
773 | m->m_len = sizeof (struct ether_header); | |
774 | } else { | |
775 | m->m_off -= sizeof (struct ether_header); | |
776 | m->m_len += sizeof (struct ether_header); | |
777 | } | |
778 | eh = mtod(m, struct ether_header *); | |
779 | eh->ether_type = htons((u_short)type); | |
780 | bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); | |
0b8a7d57 | 781 | bcopy((caddr_t)is->qe_addr, (caddr_t)eh->ether_shost, sizeof (is->qe_addr)); |
aabe40e7 KD |
782 | |
783 | /* | |
784 | * Queue message on interface, and start output if interface | |
785 | * not yet active. | |
786 | */ | |
787 | s = splimp(); | |
788 | if (IF_QFULL(&ifp->if_snd)) { | |
789 | IF_DROP(&ifp->if_snd); | |
790 | splx(s); | |
791 | m_freem(m); | |
792 | return (ENOBUFS); | |
793 | } | |
794 | IF_ENQUEUE(&ifp->if_snd, m); | |
795 | qestart(ifp->if_unit); | |
796 | splx(s); | |
797 | return (0); | |
798 | ||
799 | bad: | |
800 | m_freem(m0); | |
801 | return (error); | |
802 | } | |
803 | ||
804 | ||
805 | /* | |
806 | * Process an ioctl request. | |
807 | */ | |
808 | qeioctl(ifp, cmd, data) | |
809 | register struct ifnet *ifp; | |
810 | int cmd; | |
811 | caddr_t data; | |
812 | { | |
813 | struct qe_softc *sc = &qe_softc[ifp->if_unit]; | |
aabe40e7 | 814 | struct ifaddr *ifa = (struct ifaddr *)data; |
5ba846a2 | 815 | int s = splimp(), error = 0; |
aabe40e7 KD |
816 | |
817 | switch (cmd) { | |
818 | ||
aabe40e7 KD |
819 | case SIOCSIFADDR: |
820 | ifp->if_flags |= IFF_UP; | |
821 | qeinit(ifp->if_unit); | |
822 | switch(ifa->ifa_addr.sa_family) { | |
823 | #ifdef INET | |
824 | case AF_INET: | |
825 | ((struct arpcom *)ifp)->ac_ipaddr = | |
826 | IA_SIN(ifa)->sin_addr; | |
827 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); | |
828 | break; | |
829 | #endif | |
5b6dfa0c MK |
830 | #ifdef NS |
831 | case AF_NS: | |
832 | { | |
833 | register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); | |
834 | ||
835 | if (ns_nullhost(*ina)) | |
0b8a7d57 | 836 | ina->x_host = *(union ns_host *)(sc->qe_addr); |
5b6dfa0c MK |
837 | else |
838 | qe_setaddr(ina->x_host.c_host, ifp->if_unit); | |
aabe40e7 | 839 | break; |
5b6dfa0c MK |
840 | } |
841 | #endif | |
aabe40e7 KD |
842 | } |
843 | break; | |
5b6dfa0c MK |
844 | |
845 | case SIOCSIFFLAGS: | |
846 | if ((ifp->if_flags & IFF_UP) == 0 && | |
847 | sc->qe_flags & QEF_RUNNING) { | |
848 | ((struct qedevice *) | |
849 | (qeinfo[ifp->if_unit]->ui_addr))->qe_csr = QE_RESET; | |
850 | sc->qe_flags &= ~QEF_RUNNING; | |
a7f4fd96 MK |
851 | } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == |
852 | IFF_RUNNING && (sc->qe_flags & QEF_RUNNING) == 0) | |
58bca61d | 853 | qerestart(sc); |
5b6dfa0c MK |
854 | break; |
855 | ||
aabe40e7 KD |
856 | default: |
857 | error = EINVAL; | |
858 | ||
859 | } | |
5ba846a2 | 860 | splx(s); |
aabe40e7 KD |
861 | return (error); |
862 | } | |
863 | ||
5b6dfa0c MK |
864 | /* |
865 | * set ethernet address for unit | |
866 | */ | |
867 | qe_setaddr(physaddr, unit) | |
868 | u_char *physaddr; | |
869 | int unit; | |
870 | { | |
871 | register struct qe_softc *sc = &qe_softc[unit]; | |
5b6dfa0c MK |
872 | register int i; |
873 | ||
874 | for (i = 0; i < 6; i++) | |
0b8a7d57 | 875 | sc->setup_pkt[i][1] = sc->qe_addr[i] = physaddr[i]; |
5b6dfa0c | 876 | sc->qe_flags |= QEF_SETADDR; |
0b8a7d57 | 877 | if (sc->qe_if.if_flags & IFF_RUNNING) |
5b6dfa0c MK |
878 | qesetup(sc); |
879 | qeinit(unit); | |
880 | } | |
aabe40e7 KD |
881 | |
882 | ||
883 | /* | |
884 | * Initialize a ring descriptor with mbuf allocation side effects | |
885 | */ | |
58bca61d | 886 | qeinitdesc(rp, addr, len) |
aabe40e7 | 887 | register struct qe_ring *rp; |
58bca61d | 888 | caddr_t addr; /* mapped address */ |
aabe40e7 KD |
889 | int len; |
890 | { | |
891 | /* | |
892 | * clear the entire descriptor | |
893 | */ | |
58bca61d | 894 | bzero((caddr_t)rp, sizeof(struct qe_ring)); |
aabe40e7 KD |
895 | |
896 | if( len ) { | |
897 | rp->qe_buf_len = -(len/2); | |
5ba846a2 MK |
898 | rp->qe_addr_lo = (short)addr; |
899 | rp->qe_addr_hi = (short)((int)addr >> 16); | |
aabe40e7 KD |
900 | } |
901 | } | |
902 | /* | |
903 | * Build a setup packet - the physical address will already be present | |
904 | * in first column. | |
905 | */ | |
906 | qesetup( sc ) | |
907 | struct qe_softc *sc; | |
908 | { | |
5ba846a2 | 909 | register i, j; |
aabe40e7 KD |
910 | |
911 | /* | |
912 | * Copy the target address to the rest of the entries in this row. | |
913 | */ | |
914 | for ( j = 0; j < 6 ; j++ ) | |
915 | for ( i = 2 ; i < 8 ; i++ ) | |
916 | sc->setup_pkt[j][i] = sc->setup_pkt[j][1]; | |
917 | /* | |
918 | * Duplicate the first half. | |
919 | */ | |
58bca61d | 920 | bcopy((caddr_t)sc->setup_pkt[0], (caddr_t)sc->setup_pkt[8], 64); |
aabe40e7 KD |
921 | /* |
922 | * Fill in the broadcast address. | |
923 | */ | |
924 | for ( i = 0; i < 6 ; i++ ) | |
925 | sc->setup_pkt[i][2] = 0xff; | |
aabe40e7 KD |
926 | sc->setupqueued++; |
927 | } | |
5b6dfa0c | 928 | |
aabe40e7 KD |
929 | /* |
930 | * Pass a packet to the higher levels. | |
931 | * We deal with the trailer protocol here. | |
932 | */ | |
5b6dfa0c | 933 | qeread(sc, ifrw, len) |
aabe40e7 KD |
934 | register struct qe_softc *sc; |
935 | struct ifrw *ifrw; | |
936 | int len; | |
aabe40e7 | 937 | { |
5ba846a2 MK |
938 | struct ether_header *eh; |
939 | struct mbuf *m; | |
aabe40e7 KD |
940 | int off, resid; |
941 | struct ifqueue *inq; | |
942 | ||
943 | /* | |
944 | * Deal with trailer protocol: if type is INET trailer | |
945 | * get true type from first 16-bit word past data. | |
946 | * Remember that type was trailer by setting off. | |
947 | */ | |
948 | ||
aabe40e7 KD |
949 | eh = (struct ether_header *)ifrw->ifrw_addr; |
950 | eh->ether_type = ntohs((u_short)eh->ether_type); | |
951 | #define qedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) | |
952 | if (eh->ether_type >= ETHERTYPE_TRAIL && | |
953 | eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
954 | off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; | |
955 | if (off >= ETHERMTU) | |
956 | return; /* sanity */ | |
5b6dfa0c MK |
957 | eh->ether_type = ntohs(*qedataaddr(eh,off, u_short *)); |
958 | resid = ntohs(*(qedataaddr(eh, off+2, u_short *))); | |
959 | if (off + resid > len) | |
960 | return; /* sanity */ | |
961 | len = off + resid; | |
962 | } else | |
aabe40e7 | 963 | off = 0; |
aabe40e7 KD |
964 | if (len == 0) |
965 | return; | |
966 | ||
967 | /* | |
968 | * Pull packet off interface. Off is nonzero if packet | |
969 | * has trailing header; qeget will then force this header | |
970 | * information to be at the front, but we still have to drop | |
971 | * the type and length which are at the front of any trailer data. | |
972 | */ | |
0b8a7d57 | 973 | m = if_ubaget(&sc->qe_uba, ifrw, len, off, &sc->qe_if); |
aabe40e7 KD |
974 | |
975 | if (m == 0) | |
976 | return; | |
977 | ||
978 | if (off) { | |
5b6dfa0c MK |
979 | struct ifnet *ifp; |
980 | ||
981 | ifp = *(mtod(m, struct ifnet **)); | |
aabe40e7 KD |
982 | m->m_off += 2 * sizeof (u_short); |
983 | m->m_len -= 2 * sizeof (u_short); | |
5b6dfa0c | 984 | *(mtod(m, struct ifnet **)) = ifp; |
aabe40e7 | 985 | } |
aabe40e7 | 986 | switch (eh->ether_type) { |
5b6dfa0c | 987 | |
aabe40e7 KD |
988 | #ifdef INET |
989 | case ETHERTYPE_IP: | |
aabe40e7 KD |
990 | schednetisr(NETISR_IP); |
991 | inq = &ipintrq; | |
992 | break; | |
5b6dfa0c | 993 | |
aabe40e7 | 994 | case ETHERTYPE_ARP: |
0b8a7d57 | 995 | arpinput(&sc->qe_ac, m); |
aabe40e7 KD |
996 | return; |
997 | #endif | |
5b6dfa0c MK |
998 | #ifdef NS |
999 | case ETHERTYPE_NS: | |
1000 | schednetisr(NETISR_NS); | |
1001 | inq = &nsintrq; | |
1002 | break; | |
1003 | ||
1004 | #endif | |
1005 | ||
aabe40e7 | 1006 | default: |
5b6dfa0c MK |
1007 | m_freem(m); |
1008 | return; | |
aabe40e7 KD |
1009 | } |
1010 | ||
1011 | if (IF_QFULL(inq)) { | |
1012 | IF_DROP(inq); | |
1013 | m_freem(m); | |
1014 | return; | |
1015 | } | |
1016 | IF_ENQUEUE(inq, m); | |
1017 | } | |
5b6dfa0c | 1018 | |
aabe40e7 | 1019 | /* |
0b8a7d57 | 1020 | * Watchdog timeout routine. There is a condition in the hardware that |
aabe40e7 KD |
1021 | * causes the board to lock up under heavy load. This routine detects |
1022 | * the hang up and restarts the device. | |
1023 | */ | |
0b8a7d57 MK |
1024 | qetimeout(unit) |
1025 | int unit; | |
aabe40e7 KD |
1026 | { |
1027 | register struct qe_softc *sc; | |
0b8a7d57 MK |
1028 | |
1029 | sc = &qe_softc[unit]; | |
1030 | log(LOG_ERR, "qe%d: transmit timeout, restarted %d\n", | |
1031 | unit, ++sc->qe_restarts); | |
1032 | qerestart(sc); | |
aabe40e7 KD |
1033 | } |
1034 | /* | |
1035 | * Restart for board lockup problem. | |
1036 | */ | |
5b6dfa0c | 1037 | qerestart(sc) |
aabe40e7 KD |
1038 | register struct qe_softc *sc; |
1039 | { | |
0b8a7d57 | 1040 | register struct ifnet *ifp = &sc->qe_if; |
aabe40e7 KD |
1041 | register struct qedevice *addr = sc->addr; |
1042 | register struct qe_ring *rp; | |
1043 | register i; | |
1044 | ||
aabe40e7 | 1045 | addr->qe_csr = QE_RESET; |
aabe40e7 | 1046 | qesetup( sc ); |
5b6dfa0c | 1047 | for (i = 0, rp = sc->tring; i < NXMT; rp++, i++) { |
aabe40e7 KD |
1048 | rp->qe_flag = rp->qe_status1 = QE_NOTYET; |
1049 | rp->qe_valid = 0; | |
1050 | } | |
1051 | sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0; | |
5b6dfa0c MK |
1052 | addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | |
1053 | QE_RCV_INT | QE_ILOOP; | |
aabe40e7 KD |
1054 | addr->qe_rcvlist_lo = (short)sc->rringaddr; |
1055 | addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16); | |
5b6dfa0c MK |
1056 | sc->qe_flags |= QEF_RUNNING; |
1057 | qestart(ifp->if_unit); | |
aabe40e7 KD |
1058 | } |
1059 | #endif |