if_le_ebus.c revision 1.1 1 /* $NetBSD: if_le_ebus.c,v 1.1 2011/01/26 01:18:50 pooka Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code was written by Alessandro Forin and Neil Pittman
8 * at Microsoft Research and contributed to The NetBSD Foundation
9 * by Microsoft Corporation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_le_ebus.c,v 1.1 2011/01/26 01:18:50 pooka Exp $");
35
36 #include "opt_inet.h"
37
38 #include "rnd.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/mbuf.h>
43 #include <sys/syslog.h>
44 #include <sys/socket.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
47 #include <sys/ioctl.h>
48 #include <sys/errno.h>
49
50 #include <net/if.h>
51 #include <net/if_dl.h>
52 #include <net/if_ether.h>
53 #include <net/if_media.h>
54
55 #ifdef INET
56 #include <netinet/in.h>
57 #include <netinet/if_inarp.h>
58 #endif
59
60 #include <net/bpf.h>
61 #include <net/bpfdesc.h>
62
63 #if NRND > 0
64 #include <sys/rnd.h>
65 #endif
66
67 #include <emips/ebus/ebusvar.h>
68 #include <emips/emips/machdep.h>
69 #include <machine/emipsreg.h>
70
71 extern paddr_t kvtophys(vaddr_t);
72
73 struct bufmap {
74 struct mbuf *mbuf;
75 paddr_t phys;
76 };
77
78 struct enic_softc {
79 device_t sc_dev; /* base device glue */
80 struct ethercom sc_ethercom; /* Ethernet common part */
81 struct ifmedia sc_media; /* our supported media */
82
83 struct _Enic *sc_regs; /* hw registers */
84
85 int sc_havecarrier; /* carrier status */
86 void *sc_sh; /* shutdownhook cookie */
87 int inited;
88
89 int sc_no_rd;
90 int sc_n_recv;
91 int sc_recv_h;
92 /* BUGBUG really should be malloc-ed */
93 #define SC_MAX_N_RECV 64
94 struct bufmap sc_recv[SC_MAX_N_RECV];
95
96 int sc_no_td;
97 int sc_n_xmit;
98 int sc_xmit_h;
99 /* BUGBUG really should be malloc-ed */
100 #define SC_MAX_N_XMIT 16
101 struct bufmap sc_xmit[SC_MAX_N_XMIT];
102
103 #if DEBUG
104 int xhit;
105 int xmiss;
106 int tfull;
107 int tfull2;
108 int brh;
109 int rf;
110 int bxh;
111
112 int it;
113 #endif
114
115 u_int8_t sc_enaddr[ETHER_ADDR_LEN];
116 u_int8_t sc_pad[2];
117 #if NRND > 0
118 rndsource_element_t rnd_source;
119 #endif
120 };
121
122 void enic_reset(struct ifnet *);
123 int enic_init(struct ifnet *);
124 void enic_stop(struct ifnet *ifp, int suspend);
125 void enic_start(struct ifnet *ifp);
126 void enic_shutdown(void *);
127 void enic_watchdog(struct ifnet *ifp);
128 int enic_mediachange(struct ifnet *ifp);
129 void enic_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr);
130 int enic_ioctl(struct ifnet *ifp, u_long cmd, void *data);
131 int enic_intr(void *cookie, void *f);
132 void enic_rint(struct enic_softc *, uint32_t, paddr_t);
133 void enic_tint(struct enic_softc *, uint32_t, paddr_t);
134 void enic_kill_xmit(struct enic_softc *sc);
135 void enic_post_recv(struct enic_softc *sc, struct mbuf *m);
136 void enic_refill(struct enic_softc *sc);
137 static int enic_gethwinfo(struct enic_softc *sc);
138 int enic_put(struct enic_softc *sc, struct mbuf **pm);
139
140 static int enic_match(struct device *, struct cfdata *, void *);
141 static void enic_attach(struct device *, struct device *, void *);
142
143 CFATTACH_DECL_NEW(enic_emips, sizeof(struct enic_softc),
144 enic_match, enic_attach, NULL, NULL);
145
146 int
147 enic_match(struct device *parent, struct cfdata *match, void *aux)
148 {
149 struct ebus_attach_args *d = aux;
150 /* donno yet */
151 struct _Enic *et = (struct _Enic *)d->ia_vaddr;
152
153 if (strcmp("enic", d->ia_name) != 0)
154 return (0);
155 if ((et == NULL) || (et->Tag != PMTTAG_ETHERNET))
156 return 0;
157 return (1);
158 }
159
160 void
161 enic_attach(struct device *parent, struct device *self, void *aux)
162 {
163 struct enic_softc *sc = device_private(self);
164 struct ebus_attach_args *ia = aux;
165 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
166
167 sc->sc_regs = (struct _Enic *)(ia->ia_vaddr);
168 #if DEBUG
169 printf(" virt=%p ", (void*)sc->sc_regs);
170 #endif
171
172 /* Get the MAC and the depth of the FIFOs */
173 if (!enic_gethwinfo(sc)) {
174 printf(" <cannot get hw info> DISABLED.\n");
175 /*
176 * NB: caveat maintainer: make sure what we
177 * did NOT do below does not hurt the system
178 */
179 return;
180 }
181
182 sc->sc_dev = self;
183 sc->sc_no_td = 0;
184 sc->sc_havecarrier = 1; /* BUGBUG */
185 sc->sc_recv_h = 0;
186 sc->sc_xmit_h = 0;
187 /* uhmm do I need to do this? */
188 memset(sc->sc_recv,0, sizeof sc->sc_recv );
189 memset(sc->sc_xmit,0, sizeof sc->sc_xmit );
190
191 /* Initialize ifnet structure. */
192 strcpy(ifp->if_xname, device_xname(sc->sc_dev));
193 ifp->if_softc = sc;
194 ifp->if_start = enic_start;
195 ifp->if_ioctl = enic_ioctl;
196 ifp->if_watchdog = enic_watchdog;
197 ifp->if_init = enic_init;
198 ifp->if_stop = enic_stop;
199 ifp->if_flags =
200 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
201 IFQ_SET_READY(&ifp->if_snd);
202
203 /* Initialize ifmedia structures. */
204 ifmedia_init(&sc->sc_media, 0, enic_mediachange, enic_mediastatus);
205 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
206 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
207
208 /* Make sure the chip is stopped. */
209 enic_stop(ifp, 0);
210 sc->inited = 0;
211
212 /* Get the mac address and print it */
213 printf(": eNIC [%d %d], address %s\n",
214 sc->sc_n_recv, sc->sc_n_xmit, ether_sprintf(sc->sc_enaddr));
215
216 /* claim 802.1q capability */
217 // sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
218
219 /* Attach the interface. */
220 if_attach(ifp);
221 ether_ifattach(ifp, sc->sc_enaddr);
222
223 sc->sc_sh = shutdownhook_establish(enic_shutdown, ifp);
224 if (sc->sc_sh == NULL)
225 panic("enic_attach: cannot establish shutdown hook");
226
227 #if NRND > 0
228 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
229 RND_TYPE_NET, 0);
230 #endif
231
232 ebus_intr_establish(parent, (void*)ia->ia_cookie, IPL_NET,
233 enic_intr, sc);
234 }
235
236 /* Beware: does not work while the nic is running
237 */
238 static int enic_gethwinfo(struct enic_softc *sc)
239 {
240 uint8_t buffer[8];/* 64bits max */
241 PENIC_INFO hw = (PENIC_INFO)buffer;
242 paddr_t phys = kvtophys((vaddr_t)&buffer[0]), phys2;
243 int i;
244
245 /* First thing first, get the MAC address
246 */
247 memset(buffer,0,sizeof buffer);
248 buffer[0] = ENIC_CMD_GET_ADDRESS;
249 buffer[3] = ENIC_CMD_GET_ADDRESS;/* bswap bug */
250 sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD;
251 sc->sc_regs->BufferAddressHi32 = 0;
252 sc->sc_regs->BufferAddressLo32 = phys; /* go! */
253
254 for (i = 0; i < 100; i++) {
255 DELAY(100);
256 if (0 == (sc->sc_regs->Control & EC_OF_EMPTY))
257 break;
258 }
259 if (i == 100)
260 return 0;
261
262 phys2 = sc->sc_regs->BufferAddressLo32;
263 if (phys2 != phys) {
264 printf("enic uhu? %llx != %llx?\n",(long long)phys,(long long)phys2);
265 return 0;
266 }
267 memcpy(sc->sc_enaddr,buffer,ETHER_ADDR_LEN);
268
269 /* Next get the HW parameters
270 */
271 memset(buffer,0,sizeof buffer);
272 buffer[0] = ENIC_CMD_GET_INFO;
273 buffer[3] = ENIC_CMD_GET_INFO;/* bswap bug */
274 sc->sc_regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD;
275 sc->sc_regs->BufferAddressHi32 = 0;
276 sc->sc_regs->BufferAddressLo32 = phys; /* go! */
277
278 for (i = 0; i < 100; i++) {
279 DELAY(100);
280 if (0 == (sc->sc_regs->Control & EC_OF_EMPTY))
281 break;
282 }
283 if (i == 100)
284 return 0;
285
286 phys2 = sc->sc_regs->BufferAddressLo32;
287 if (phys2 != phys) {
288 printf("enic uhu2? %llx != %llx?\n",(long long)phys,(long long)phys2);
289 return 0;
290 }
291 //printf("enic: hwinfo: %x %x %x %x %x %x \n", hw->InputFifoSize, hw->OutputFifoSize, hw->CompletionFifoSize,
292 // hw->ErrorCount, hw->FramesDropped, hw->Reserved);
293
294 /* Get FIFO depths and cap them
295 */
296 sc->sc_n_recv = hw->InputFifoSize;
297 if (sc->sc_n_recv > SC_MAX_N_RECV)
298 sc->sc_n_recv = SC_MAX_N_RECV;
299 if (sc->sc_n_recv == 0) { /* sanity and compat with old hw/simulator */
300 sc->sc_n_recv = 8;
301 sc->sc_n_xmit = 4;
302 } else {
303 sc->sc_n_xmit = hw->OutputFifoSize;
304 if (sc->sc_n_xmit > SC_MAX_N_XMIT)
305 sc->sc_n_xmit = SC_MAX_N_XMIT;
306 }
307
308 return 1;
309 }
310
311 void
312 enic_reset(struct ifnet *ifp)
313 {
314 int s;
315
316 s = splnet();
317 enic_stop(ifp,0);
318 enic_init(ifp);
319 splx(s);
320 }
321
322 void
323 enic_stop(struct ifnet *ifp, int suspend)
324 {
325 struct enic_softc *sc = ifp->if_softc;
326
327 //printf("enic_stop %x\n", sc->sc_regs->Control);
328
329 /* NB: only "ifconfig down" says suspend=1 (then "up" calls init)
330 * Could simply set RXDIS in this case
331 */
332 sc->inited = 2;
333 sc->sc_regs->Control = EC_RESET;
334 sc->sc_no_rd = 0; /* they are gone */
335 sc->sc_no_td = 0; /* they are gone */
336 }
337
338 void
339 enic_shutdown(void *arg)
340 {
341 struct ifnet *ifp = arg;
342
343 enic_stop(ifp, 0);
344 }
345
346 void
347 enic_kill_xmit(struct enic_softc *sc)
348 {
349 int i;
350 struct mbuf *m;
351
352 for (i = 0; i < sc->sc_n_xmit; i++)
353 if ((m = sc->sc_xmit[i].mbuf) != NULL) {
354 sc->sc_xmit[i].mbuf = NULL;
355 sc->sc_xmit[i].phys = ~0;
356 m_freem(m);
357 }
358 sc->sc_no_td = 0;
359 sc->sc_xmit_h = 0;
360 }
361
362 void
363 enic_post_recv(struct enic_softc *sc, struct mbuf *m)
364 {
365 int i, waitmode = M_DONTWAIT;
366 paddr_t phys;
367
368 #define rpostone(_p_) \
369 sc->sc_regs->SizeAndFlags = ES_F_RECV | MCLBYTES; \
370 sc->sc_regs->BufferAddressHi32 = 0; \
371 sc->sc_regs->BufferAddressLo32 = _p_;
372 #define tpostone(_p_,_s_) \
373 sc->sc_regs->SizeAndFlags = ES_F_XMIT | (_s_); \
374 sc->sc_regs->BufferAddressHi32 = 0; \
375 sc->sc_regs->BufferAddressLo32 = _p_;
376
377 /* Operational reload? */
378 if (m != NULL) {
379 /* But is the hw ready for it */
380 if (sc->sc_regs->Control & EC_IF_FULL)
381 goto no_room;
382 /* Yes, find a spot. Include empty q case. */
383 for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++)
384 if (sc->sc_recv[i].mbuf == NULL)
385 goto found;
386 for (i = 0; i < sc->sc_recv_h; i++)
387 if (sc->sc_recv[i].mbuf == NULL)
388 goto found;
389 /* no spot, drop it (sigh) */
390 no_room:
391 #if DEBUG
392 sc->rf++;
393 #endif
394 m_freem(m);
395 return;
396 found:
397 phys = kvtophys((vaddr_t)m->m_data);
398 sc->sc_recv[i].mbuf = m;
399 sc->sc_recv[i].phys = phys;
400 rpostone(phys);
401 sc->sc_no_rd++;
402 return;
403 }
404
405 /* Repost after reset? */
406 if (sc->inited) {
407 /* order doesnt matter, might as well keep it clean */
408 int j = 0;
409 sc->sc_recv_h = 0;
410 for (i = 0; i < sc->sc_n_recv; i++)
411 if ((m = sc->sc_recv[i].mbuf) != NULL) {
412 phys = sc->sc_recv[i].phys;
413 sc->sc_recv[i].mbuf = NULL;
414 sc->sc_recv[i].phys = ~0;
415 sc->sc_recv[j].mbuf = m;
416 sc->sc_recv[j].phys = phys;
417 #if DEBUG
418 if (sc->sc_regs->Control & EC_IF_FULL)
419 printf("?uhu? postrecv full? %d\n", sc->sc_no_rd);
420 #endif
421 sc->sc_no_rd++;
422 rpostone(phys);
423 j++;
424 }
425 /* Any holes left? */
426 sc->inited = 1;
427 if (j >= sc->sc_n_recv)
428 return;/* no, we are done */
429 /* continue on with the loop below */
430 i = j; m = NULL;
431 goto fillem;
432 }
433
434 /* Initial refill, we can wait */
435 waitmode = M_WAIT;
436 sc->sc_recv_h = 0;
437 memset(sc->sc_recv, 0, sizeof(sc->sc_recv[0]) * sc->sc_n_recv);
438 i = 0;
439 fillem:
440 for (; i < sc->sc_n_recv; i++) {
441 MGETHDR(m, waitmode, MT_DATA);
442 if (m == 0)
443 break;
444 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
445 m->m_pkthdr.len = 0;
446
447 MCLGET(m, waitmode);
448 if ((m->m_flags & M_EXT) == 0)
449 break;
450
451 /* This offset aligns IP/TCP headers and helps performance
452 */
453 #if 1
454 #define ADJUST_MBUF_OFFSET(_m_) { \
455 (_m_)->m_data += 2; \
456 (_m_)->m_len -= 2; \
457 }
458 #else
459 #define ADJUST_MBUF_OFFSET(_m_)
460 #endif
461
462 m->m_len = MCLBYTES;
463
464 ADJUST_MBUF_OFFSET(m);
465 phys = kvtophys((vaddr_t)m->m_data);
466 sc->sc_recv[i].mbuf = m;
467 sc->sc_recv[i].phys = phys;
468 #if DEBUG
469 if (sc->sc_regs->Control & EC_IF_FULL)
470 printf("?uhu? postrecv2 full? %d\n", sc->sc_no_rd);
471 #endif
472 sc->sc_no_rd++;
473 rpostone(phys);
474 m = NULL;
475 }
476
477 if (m) m_freem(m);
478 sc->inited = 1;
479 }
480
481 void enic_refill(struct enic_softc *sc)
482 {
483 struct mbuf *m;
484 int waitmode = M_DONTWAIT;
485
486 MGETHDR(m, waitmode, MT_DATA);
487 if (m == 0)
488 return;
489 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
490 m->m_pkthdr.len = 0;
491
492 MCLGET(m, waitmode);
493 if ((m->m_flags & M_EXT) == 0) {
494 m_freem(m);
495 return;
496 }
497
498 m->m_len = MCLBYTES;
499 ADJUST_MBUF_OFFSET(m);
500
501 enic_post_recv(sc,m);
502 }
503
504 int
505 enic_init(struct ifnet *ifp)
506 {
507 struct enic_softc *sc = ifp->if_softc;
508 uint32_t ctl;
509
510 /* no need to init many times unless we are in reset */
511 if (sc->inited != 1) {
512
513 /* Cancel all xmit buffers */
514 enic_kill_xmit(sc);
515
516 /* Re-post all recv buffers */
517 enic_post_recv(sc,NULL);
518 }
519
520 /* Start the eNIC */
521 ifp->if_flags |= IFF_RUNNING;
522 ifp->if_flags &= ~IFF_OACTIVE;
523 ifp->if_timer = 0;
524 ctl = sc->sc_regs->Control | EC_INTEN;
525 ctl &= ~EC_RXDIS;
526 sc->sc_regs->Control = ctl;
527 //printf("enic_init <- %x\n",ctl);
528
529 enic_start(ifp);
530
531 return (0);
532 }
533
534
535 void
536 enic_watchdog(struct ifnet *ifp)
537 {
538 struct enic_softc *sc = ifp->if_softc;
539
540 //printf("enic_watch ctl=%x\n", sc->sc_regs->Control);
541 log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
542 ++ifp->if_oerrors;
543
544 enic_reset(ifp);
545 }
546
547 int
548 enic_mediachange(struct ifnet *ifp)
549 {
550 // struct enic_softc *sc = ifp->if_softc;
551 /* more code here.. */
552
553 return (0);
554 }
555
556 void
557 enic_mediastatus(
558 struct ifnet *ifp,
559 struct ifmediareq *ifmr)
560 {
561 struct enic_softc *sc = ifp->if_softc;
562
563 if ((ifp->if_flags & IFF_UP) == 0)
564 return;
565
566 ifmr->ifm_status = IFM_AVALID;
567 if (sc->sc_havecarrier)
568 ifmr->ifm_status |= IFM_ACTIVE;
569
570 /* more code here someday.. */
571 }
572
573 /*
574 * Process an ioctl request.
575 */
576 int
577 enic_ioctl(struct ifnet *ifp, u_long cmd, void *data)
578 {
579 struct enic_softc *sc = ifp->if_softc;
580 struct ifreq *ifr = (struct ifreq *)data;
581 int s, error = 0;
582
583 s = splnet();
584
585 switch (cmd) {
586 case SIOCGIFMEDIA:
587 case SIOCSIFMEDIA:
588 #if 0 /*DEBUG*/
589 {
590 extern int ei_drops[];
591 static int flip = 0;
592 if (flip++ == 2) {
593 int i;
594 flip = 0;
595 printf("enic_ioctl(%x) %qd/%qd %qd/%qd %d/%d %d:%d "
596 "%d+%d %d/%d/%d\n", ifp->if_flags,
597 ifp->if_ierrors, ifp->if_oerrors,
598 ifp->if_ipackets, ifp->if_opackets,
599 sc->sc_no_rd, sc->sc_no_td,
600 sc->xhit, sc->xmiss,
601 sc->tfull, sc->tfull2,
602 sc->brh, sc->rf, sc->bxh);
603 printf(" Ctl %x lt %x tim %d\n",
604 sc->sc_regs->Control, sc->it, ifp->if_timer);
605
606 for (i = 0; i < 64; i++)
607 if (ei_drops[i])
608 printf(" %d.%d",i,ei_drops[i]);
609 printf("\n");
610 }
611 }
612 #endif
613 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
614 break;
615
616 default:
617 error = ether_ioctl(ifp, cmd, data);
618 if (cmd == SIOCSIFADDR) {
619 /*
620 * hackattack: NFS does not turn us back
621 * on after a stop. So.
622 */
623 //printf("enic_ioctl(%lx)\n",cmd);
624 enic_init(ifp);
625 }
626 if (error != ENETRESET)
627 break;
628 error = 0;
629 if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
630 break;
631 if (ifp->if_flags & IFF_RUNNING) {
632 enic_reset(ifp);
633 }
634 break;
635 }
636 splx(s);
637
638 return (error);
639 }
640
641 int
642 enic_intr(void *cookie, void *f)
643 {
644 struct enic_softc *sc = cookie;
645 u_int32_t isr, saf, hi, lo, fl;
646
647 isr = sc->sc_regs->Control;
648
649 /* Make sure there is one and that we should take it */
650 if ((isr & (EC_INTEN|EC_DONE)) != (EC_INTEN|EC_DONE))
651 return (0);
652
653 if (isr & EC_ERROR) {
654 printf("%s: internal error\n", device_xname(sc->sc_dev));
655 enic_reset(&sc->sc_ethercom.ec_if);
656 return (1);
657 }
658
659 /* pull out all completed buffers
660 */
661 while ((isr & EC_OF_EMPTY) == 0) {
662
663 /* beware, order matters */
664 saf = sc->sc_regs->SizeAndFlags;
665 hi = sc->sc_regs->BufferAddressHi32; /* BUGBUG 64bit */
666 lo = sc->sc_regs->BufferAddressLo32; /* this pops the fifo */
667
668 fl = saf & (ES_F_MASK &~ ES_F_DONE);
669 if (fl == ES_F_RECV)
670 enic_rint(sc,saf,lo);
671 else
672 if (fl == ES_F_XMIT)
673 enic_tint(sc,saf,lo);
674 else
675 /* we do not currently expect or care for command completions? */
676 if (fl != ES_F_CMD)
677 printf("%s: invalid saf=x%x (lo=%x)\n", device_xname(sc->sc_dev), saf, lo);
678
679 isr = sc->sc_regs->Control;
680 }
681
682 #if NRND > 0
683 rnd_add_uint32(&sc->rnd_source, isr);
684 #endif
685
686 return (1);
687 }
688
689 void
690 enic_rint(struct enic_softc *sc, uint32_t saf, paddr_t phys)
691 {
692 struct mbuf *m;
693 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
694 int len = saf & ES_S_MASK, i;
695
696 /* Find what buffer it is. Should be the first. */
697 for (i = sc->sc_recv_h; i < sc->sc_n_recv; i++)
698 if (sc->sc_recv[i].phys == phys)
699 goto found;
700 for (i = 0; i < sc->sc_recv_h; i++)
701 if (sc->sc_recv[i].phys == phys)
702 goto found;
703
704 /* uhu?? */
705 printf("%s: bad recv phys %llx\n", device_xname(sc->sc_dev), (long long)phys);
706 ifp->if_ierrors++;
707 return;
708
709 /* got it, pop it */
710 found:
711 sc->sc_no_rd--;
712 m = sc->sc_recv[i].mbuf;
713 sc->sc_recv[i].mbuf = NULL;
714 sc->sc_recv[i].phys = ~0;
715 if (i == sc->sc_recv_h) { /* should be */
716 sc->sc_recv_h = (++i == sc->sc_n_recv) ? 0 : i;
717 }
718 #if DEBUG
719 else sc->brh++;
720 #endif
721
722 if (len <= sizeof(struct ether_header) ||
723 len > ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ?
724 ETHER_VLAN_ENCAP_LEN + ETHERMTU + sizeof(struct ether_header) :
725 ETHERMTU + sizeof(struct ether_header))) {
726 ifp->if_ierrors++;
727
728 /* reuse it */
729 enic_post_recv(sc,m);
730 return;
731 }
732
733 /* Adjust size */
734 m->m_pkthdr.len = len;
735 m->m_len = len; /* recheck */
736
737 ifp->if_ipackets++;
738
739 /*
740 * Check if there's a BPF listener on this interface.
741 * If so, hand off the raw packet to BPF.
742 */
743 if (ifp->if_bpf)
744 bpf_mtap(ifp, m);
745
746 /* Pass the packet up. */
747 (*ifp->if_input)(ifp, m);
748
749 /* Need to refill now */
750 enic_refill(sc);
751 }
752
753 void enic_tint(struct enic_softc *sc, uint32_t saf, paddr_t phys)
754 {
755 struct mbuf *m;
756 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
757 int i;
758
759 #if DEBUG
760 sc->it = 1;
761 #endif
762
763 /* BUGBUG should there be a per-buffer error bit in SAF? */
764
765 /* Find what buffer it is. Should be the first. */
766 for (i = sc->sc_xmit_h; i < sc->sc_n_xmit; i++)
767 if (sc->sc_xmit[i].phys == phys)
768 goto found;
769 for (i = 0; i < sc->sc_xmit_h; i++)
770 if (sc->sc_xmit[i].phys == phys)
771 goto found;
772
773 /* uhu?? */
774 printf("%s: bad xmit phys %llx\n", device_xname(sc->sc_dev), (long long)phys);
775 ifp->if_oerrors++;
776 return;
777
778 /* got it, pop it */
779 found:
780 m = sc->sc_xmit[i].mbuf;
781 sc->sc_xmit[i].mbuf = NULL;
782 sc->sc_xmit[i].phys = ~0;
783 if (i == sc->sc_xmit_h) { /* should be */
784 sc->sc_xmit_h = (++i == sc->sc_n_xmit) ? 0 : i;
785 }
786 #if DEBUG
787 else sc->bxh++;
788 #endif
789 m_freem(m);
790 ifp->if_opackets++;
791
792 if (--sc->sc_no_td == 0)
793 ifp->if_timer = 0;
794
795 ifp->if_flags &= ~IFF_OACTIVE;
796 enic_start(ifp);
797 #if DEBUG
798 sc->it = 1;
799 #endif
800 }
801
802 /*
803 * Setup output on interface.
804 * Get another datagram to send off of the interface queue, and map it to the
805 * interface before starting the output.
806 * Called only at splnet or interrupt level.
807 */
808 void
809 enic_start(struct ifnet *ifp)
810 {
811 struct enic_softc *sc = ifp->if_softc;
812 struct mbuf *m;
813 int len, ix, s;
814 paddr_t phys;
815
816 #if DEBUG
817 sc->it = 0;
818 #endif
819
820 //printf("enic_start(%x)\n", ifp->if_flags);
821
822 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
823 return;
824
825 s = splnet(); /* I know, I dont trust people.. */
826
827 ix = sc->sc_xmit_h;
828 for (;;) {
829
830 /* Anything to do? */
831 IFQ_POLL(&ifp->if_snd, m);
832 if (m == 0)
833 break;
834
835 /* find a spot, if any */
836 for (;ix < sc->sc_n_xmit; ix++)
837 if (sc->sc_xmit[ix].mbuf == NULL)
838 goto found;
839 for (ix = 0; ix < sc->sc_xmit_h; ix++)
840 if (sc->sc_xmit[ix].mbuf == NULL)
841 goto found;
842 /* oh well */
843 ifp->if_flags |= IFF_OACTIVE;
844 #if DEBUG
845 sc->tfull++;
846 #endif
847 break;
848
849 found:
850 IFQ_DEQUEUE(&ifp->if_snd, m);
851 if (m == 0)
852 break;
853
854 /*
855 * If BPF is listening on this interface, let it see the packet
856 * before we commit it to the wire.
857 */
858 if (ifp->if_bpf)
859 bpf_mtap(ifp, m);
860
861 /*
862 * Copy the mbuf chain into a contiguous transmit buffer.
863 */
864 len = enic_put(sc, &m);
865 if (len == 0)
866 break; /* sanity */
867 if (len > (ETHERMTU + sizeof(struct ether_header))) {
868 printf("enic? tlen %d > %d\n", len, ETHERMTU + sizeof(struct ether_header));
869 len = ETHERMTU + sizeof(struct ether_header);
870 }
871
872 ifp->if_timer = 5;
873
874 /*
875 * Remember and post the buffer
876 */
877 phys = kvtophys((vaddr_t)m->m_data);
878 sc->sc_xmit[ix].mbuf = m;
879 sc->sc_xmit[ix].phys = phys;
880
881 sc->sc_no_td++;
882
883 tpostone(phys,len);
884
885 if (sc->sc_regs->Control & EC_IF_FULL) {
886 ifp->if_flags |= IFF_OACTIVE;
887 #if DEBUG
888 sc->tfull2++;
889 #endif
890 break;
891 }
892
893 ix++;
894 }
895
896 splx(s);
897 }
898
899 int enic_put(struct enic_softc *sc, struct mbuf **pm)
900 {
901 struct mbuf *n, *m = *pm, *mm;
902 int len, tlen = 0, xlen = m->m_pkthdr.len;
903 uint8_t *cp;
904
905 #if 0
906 /* drop garbage */
907 tlen = xlen;
908 for (; m; m = n) {
909 len = m->m_len;
910 if (len == 0) {
911 MFREE(m, n);
912 if (m == *pm) *pm = n;
913 continue;
914 }
915 tlen -= len;
916 KASSERT(m != m->m_next);
917 n = m->m_next;
918 if (tlen <= 0) break;
919 }
920
921 /* We might be done: (a) empty chain (b) only one segment (c) bad chain */
922 if (((m = *pm) == NULL) || (tlen > 0))
923 xlen = 0;
924 #endif
925
926 if ((xlen == 0) || (xlen <= m->m_len)) {
927 #if DEBUG
928 sc->xhit++;
929 #endif
930 return xlen;
931 }
932
933 /* Nope, true chain. Copy to contig :-(( */
934 tlen = xlen;
935 MGETHDR(n, M_NOWAIT, MT_DATA);
936 if (n == 0)
937 goto Bad;
938 n->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
939 n->m_pkthdr.len = tlen;
940
941 MCLGET(n, M_NOWAIT);
942 if ((n->m_flags & M_EXT) == 0) {
943 m_freem(n);
944 goto Bad;
945 }
946
947 n->m_len = tlen;
948 cp = mtod(n, uint8_t *);
949 for (; m && tlen; m = mm) {
950
951 len = m->m_len;
952 if (len > tlen) len = tlen;
953 if (len)
954 memcpy(cp, mtod(m, void *), len);
955
956 cp += len;
957 tlen -= len;
958 MFREE(m, mm);
959
960 }
961
962 *pm = n;
963 #if DEBUG
964 sc->xmiss++;
965 #endif
966 return (xlen);
967
968 Bad:
969 printf("enic_put: no mem?\n");
970 m_freem(m);
971 return 0;
972 }
973