Annotation of sys/arch/sparc/dev/hme.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: hme.c,v 1.55 2006/06/25 21:53:44 brad Exp $ */
2:
3: /*
4: * Copyright (c) 1998 Jason L. Wright (jason@thought.net)
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: /*
30: * Driver for the Happy Meal (hme) ethernet boards
31: * Based on information gleaned from reading the
32: * S/Linux driver by David Miller
33: *
34: * Thanks go to the University of North Carolina at Greensboro, Systems
35: * and Networks Department for some of the resources used to develop
36: * this driver.
37: */
38:
39: #include "bpfilter.h"
40: #include "vlan.h"
41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/kernel.h>
45: #include <sys/errno.h>
46: #include <sys/ioctl.h>
47: #include <sys/mbuf.h>
48: #include <sys/socket.h>
49: #include <sys/syslog.h>
50: #include <sys/device.h>
51: #include <sys/malloc.h>
52:
53: #include <net/if.h>
54: #include <net/if_dl.h>
55: #include <net/if_types.h>
56: #include <net/netisr.h>
57: #include <net/if_media.h>
58:
59: #ifdef INET
60: #include <netinet/in.h>
61: #include <netinet/in_systm.h>
62: #include <netinet/in_var.h>
63: #include <netinet/ip.h>
64: #include <netinet/if_ether.h>
65: #include <netinet/tcp.h>
66: #include <netinet/udp.h>
67: #endif
68:
69: #if NBPFILTER > 0
70: #include <net/bpf.h>
71: #include <net/bpfdesc.h>
72: #endif
73:
74: #include <machine/autoconf.h>
75: #include <sparc/cpu.h>
76: #include <sparc/sparc/cpuvar.h>
77: #include <sparc/dev/sbusvar.h>
78: #include <sparc/dev/dmareg.h> /* for SBUS_BURST_* */
79: #include <dev/mii/mii.h>
80: #include <dev/mii/miivar.h>
81: #include <sparc/dev/hmereg.h>
82: #include <sparc/dev/hmevar.h>
83:
84: int hmematch(struct device *, void *, void *);
85: void hmeattach(struct device *, struct device *, void *);
86: void hmewatchdog(struct ifnet *);
87: int hmeintr(void *);
88: int hmeioctl(struct ifnet *, u_long, caddr_t);
89: void hmereset(struct hme_softc *);
90: void hmestart(struct ifnet *);
91: void hmestop(struct hme_softc *);
92: void hmeinit(struct hme_softc *);
93: void hme_meminit(struct hme_softc *);
94:
95: void hme_tcvr_bb_writeb(struct hme_softc *, int);
96: int hme_tcvr_bb_readb(struct hme_softc *, int);
97:
98: void hme_poll_stop(struct hme_softc *sc);
99:
100: int hme_rint(struct hme_softc *);
101: int hme_tint(struct hme_softc *);
102: int hme_mint(struct hme_softc *, u_int32_t);
103: int hme_eint(struct hme_softc *, u_int32_t);
104:
105: /* TCP/UDP checksum offload support */
106: void hme_rxcksum(struct mbuf *, u_int32_t);
107:
108: void hme_reset_rx(struct hme_softc *);
109: void hme_reset_tx(struct hme_softc *);
110:
111: void hme_read(struct hme_softc *, int, int, u_int32_t);
112: int hme_put(struct hme_softc *, int, struct mbuf *);
113:
114: /*
115: * ifmedia glue
116: */
117: int hme_mediachange(struct ifnet *);
118: void hme_mediastatus(struct ifnet *, struct ifmediareq *);
119:
120: /*
121: * mii glue
122: */
123: int hme_mii_read(struct device *, int, int);
124: void hme_mii_write(struct device *, int, int, int);
125: void hme_mii_statchg(struct device *);
126:
127: void hme_mcreset(struct hme_softc *);
128:
129: struct cfattach hme_ca = {
130: sizeof (struct hme_softc), hmematch, hmeattach
131: };
132:
133: struct cfdriver hme_cd = {
134: NULL, "hme", DV_IFNET
135: };
136:
137: int
138: hmematch(parent, vcf, aux)
139: struct device *parent;
140: void *vcf, *aux;
141: {
142: struct cfdata *cf = vcf;
143: struct confargs *ca = aux;
144: register struct romaux *ra = &ca->ca_ra;
145:
146: if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
147: strcmp("SUNW,hme", ra->ra_name) &&
148: strcmp("SUNW,qfe", ra->ra_name)) {
149: return (0);
150: }
151: if (!sbus_testdma((struct sbus_softc *)parent, ca))
152: return(0);
153: return (1);
154: }
155:
156: void
157: hmeattach(parent, self, aux)
158: struct device *parent, *self;
159: void *aux;
160: {
161: struct confargs *ca = aux;
162: struct hme_softc *sc = (struct hme_softc *)self;
163: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
164: int pri;
165: struct bootpath *bp;
166: /* XXX the following declaration should be elsewhere */
167: extern void myetheraddr(u_char *);
168:
169: if (ca->ca_ra.ra_nintr != 1) {
170: printf(": expected 1 interrupt, got %d\n",
171: ca->ca_ra.ra_nintr);
172: return;
173: }
174: pri = ca->ca_ra.ra_intr[0].int_pri;
175:
176: /* map registers */
177: if (ca->ca_ra.ra_nreg != 5) {
178: printf(": expected 5 registers, got %d\n", ca->ca_ra.ra_nreg);
179: return;
180: }
181: sc->sc_gr = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
182: ca->ca_ra.ra_reg[0].rr_len);
183: sc->sc_txr = mapiodev(&(ca->ca_ra.ra_reg[1]), 0,
184: ca->ca_ra.ra_reg[1].rr_len);
185: sc->sc_rxr = mapiodev(&(ca->ca_ra.ra_reg[2]), 0,
186: ca->ca_ra.ra_reg[2].rr_len);
187: sc->sc_cr = mapiodev(&(ca->ca_ra.ra_reg[3]), 0,
188: ca->ca_ra.ra_reg[3].rr_len);
189: sc->sc_tcvr = mapiodev(&(ca->ca_ra.ra_reg[4]), 0,
190: ca->ca_ra.ra_reg[4].rr_len);
191:
192: sc->sc_node = ca->ca_ra.ra_node;
193:
194: sc->sc_rev = getpropint(ca->ca_ra.ra_node, "hm-rev", -1);
195: if (sc->sc_rev == 0xff)
196: sc->sc_rev = 0xa0;
197: if (sc->sc_rev == 0x20 || sc->sc_rev == 0x21)
198: sc->sc_flags = HME_FLAG_20_21;
199: else if (sc->sc_rev != 0xa0)
200: sc->sc_flags = HME_FLAG_NOT_A0;
201:
202: sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);
203: if (sc->sc_burst == -1)
204: sc->sc_burst = ((struct sbus_softc *)parent)->sc_burst;
205:
206: /* Clamp at parent's burst sizes */
207: sc->sc_burst &= ((struct sbus_softc *)parent)->sc_burst;
208:
209: hme_meminit(sc);
210:
211: sc->sc_ih.ih_fun = hmeintr;
212: sc->sc_ih.ih_arg = sc;
213: intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_NET,
214: self->dv_xname);
215:
216: /*
217: * Get MAC address from card if 'local-mac-address' property exists.
218: * Otherwise, use the machine's builtin MAC.
219: */
220: if (getprop(ca->ca_ra.ra_node, "local-mac-address",
221: sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN) <= 0) {
222: myetheraddr(sc->sc_arpcom.ac_enaddr);
223: }
224:
225: printf(" pri %d: address %s rev %d\n", pri,
226: ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_rev);
227:
228: sc->sc_mii.mii_ifp = ifp;
229: sc->sc_mii.mii_readreg = hme_mii_read;
230: sc->sc_mii.mii_writereg = hme_mii_write;
231: sc->sc_mii.mii_statchg = hme_mii_statchg;
232: ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, hme_mediachange,
233: hme_mediastatus);
234: mii_phy_probe(self, &sc->sc_mii, 0xffffffff);
235:
236: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
237: ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE,
238: 0, NULL);
239: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
240: }
241: else
242: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
243:
244: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
245: ifp->if_softc = sc;
246: ifp->if_start = hmestart;
247: ifp->if_ioctl = hmeioctl;
248: ifp->if_watchdog = hmewatchdog;
249: ifp->if_flags =
250: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
251: sc->sc_if_flags = ifp->if_flags;
252: ifp->if_capabilities = IFCAP_VLAN_MTU;
253: IFQ_SET_MAXLEN(&ifp->if_snd, HME_TX_RING_SIZE);
254: IFQ_SET_READY(&ifp->if_snd);
255:
256: /* Attach the interface. */
257: if_attach(ifp);
258: ether_ifattach(ifp);
259:
260: bp = ca->ca_ra.ra_bp;
261: if (bp != NULL && sc->sc_dev.dv_unit == bp->val[1] &&
262: ((strcmp(bp->name, hme_cd.cd_name) == 0) ||
263: (strcmp(bp->name, "qfe") == 0) ||
264: (strcmp(bp->name, "SUNW,hme") == 0)))
265: bp->dev = &sc->sc_dev;
266: }
267:
268: /*
269: * Start output on interface.
270: * We make two assumptions here:
271: * 1) that the current priority is set to splnet _before_ this code
272: * is called *and* is returned to the appropriate priority after
273: * return
274: * 2) that the IFF_OACTIVE flag is checked before this code is called
275: * (i.e. that the output part of the interface is idle)
276: */
277: void
278: hmestart(ifp)
279: struct ifnet *ifp;
280: {
281: struct hme_softc *sc = ifp->if_softc;
282: struct mbuf *m;
283: int bix, len;
284:
285: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
286: return;
287:
288: bix = sc->sc_last_td;
289:
290: for (;;) {
291: IFQ_DEQUEUE(&ifp->if_snd, m);
292: if (m == NULL)
293: break;
294: #if NBPFILTER > 0
295: /*
296: * If BPF is listening on this interface, let it see the
297: * packet before we commit it to the wire.
298: */
299: if (ifp->if_bpf)
300: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
301: #endif
302:
303: /*
304: * Copy the mbuf chain into the transmit buffer.
305: */
306: len = hme_put(sc, bix, m);
307:
308: /*
309: * Initialize transmit registers and start transmission.
310: */
311: sc->sc_desc->hme_txd[bix].tx_flags =
312: HME_TXD_OWN | HME_TXD_SOP | HME_TXD_EOP |
313: (len & HME_TXD_SIZE);
314: sc->sc_txr->tx_pnding = TXR_TP_DMAWAKEUP;
315:
316: if (++bix == HME_TX_RING_SIZE)
317: bix = 0;
318:
319: if (++sc->sc_no_td == HME_TX_RING_SIZE) {
320: ifp->if_flags |= IFF_OACTIVE;
321: break;
322: }
323: }
324:
325: sc->sc_last_td = bix;
326: }
327:
328: #define MAX_STOP_TRIES 16
329:
330: void
331: hmestop(sc)
332: struct hme_softc *sc;
333: {
334: int tries = 0;
335:
336: sc->sc_gr->reset = GR_RESET_ALL;
337: while (sc->sc_gr->reset && (++tries != MAX_STOP_TRIES))
338: DELAY(20);
339: if (tries == MAX_STOP_TRIES)
340: printf("%s: stop failed\n", sc->sc_dev.dv_xname);
341: sc->sc_mii.mii_media_status &= ~IFM_ACTIVE;
342: }
343:
344: /*
345: * Reset interface.
346: */
347: void
348: hmereset(sc)
349: struct hme_softc *sc;
350: {
351: int s;
352:
353: s = splnet();
354: hmestop(sc);
355: hmeinit(sc);
356: splx(s);
357: }
358:
359: /*
360: * Device timeout/watchdog routine. Entered if the device neglects to generate
361: * an interrupt after a transmit has been started on it.
362: */
363: void
364: hmewatchdog(ifp)
365: struct ifnet *ifp;
366: {
367: struct hme_softc *sc = ifp->if_softc;
368:
369: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
370: ++sc->sc_arpcom.ac_if.if_oerrors;
371:
372: hmereset(sc);
373: }
374:
375: int
376: hmeioctl(ifp, cmd, data)
377: struct ifnet *ifp;
378: u_long cmd;
379: caddr_t data;
380: {
381: struct hme_softc *sc = ifp->if_softc;
382: struct ifaddr *ifa = (struct ifaddr *)data;
383: struct ifreq *ifr = (struct ifreq *)data;
384: int s, error = 0;
385:
386: s = splnet();
387:
388: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
389: splx(s);
390: return (error);
391: }
392:
393: switch (cmd) {
394: case SIOCSIFADDR:
395: switch (ifa->ifa_addr->sa_family) {
396: #ifdef INET
397: case AF_INET:
398: if (ifp->if_flags & IFF_UP)
399: hme_mcreset(sc);
400: else {
401: ifp->if_flags |= IFF_UP;
402: hmeinit(sc);
403: }
404: arp_ifinit(&sc->sc_arpcom, ifa);
405: break;
406: #endif /* INET */
407: default:
408: ifp->if_flags |= IFF_UP;
409: hmeinit(sc);
410: break;
411: }
412: break;
413:
414: case SIOCSIFFLAGS:
415: if ((ifp->if_flags & IFF_UP) == 0 &&
416: (ifp->if_flags & IFF_RUNNING) != 0) {
417: /*
418: * If interface is marked down and it is running, then
419: * stop it.
420: */
421: hmestop(sc);
422: ifp->if_flags &= ~IFF_RUNNING;
423: } else if ((ifp->if_flags & IFF_UP) != 0 &&
424: (ifp->if_flags & IFF_RUNNING) == 0) {
425: /*
426: * If interface is marked up and it is stopped, then
427: * start it.
428: */
429: hmeinit(sc);
430: } else {
431: /*
432: * If setting debug or promiscuous mode, do not reset
433: * the chip; for everything else, call hmeinit()
434: * which will trigger a reset.
435: */
436: #define RESETIGN (IFF_CANTCHANGE | IFF_DEBUG)
437: if (ifp->if_flags == sc->sc_if_flags)
438: break;
439: if ((ifp->if_flags & (~RESETIGN))
440: == (sc->sc_if_flags & (~RESETIGN)))
441: hme_mcreset(sc);
442: else
443: hmeinit(sc);
444: #undef RESETIGN
445: }
446: break;
447:
448: case SIOCADDMULTI:
449: case SIOCDELMULTI:
450: error = (cmd == SIOCADDMULTI) ?
451: ether_addmulti(ifr, &sc->sc_arpcom):
452: ether_delmulti(ifr, &sc->sc_arpcom);
453:
454: if (error == ENETRESET) {
455: /*
456: * Multicast list has changed; set the hardware filter
457: * accordingly.
458: */
459: if (ifp->if_flags & IFF_RUNNING)
460: hme_mcreset(sc);
461: error = 0;
462: }
463: break;
464: case SIOCGIFMEDIA:
465: case SIOCSIFMEDIA:
466: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
467: break;
468: default:
469: error = ENOTTY;
470: }
471:
472: sc->sc_if_flags = ifp->if_flags;
473: splx(s);
474: return (error);
475: }
476:
477: void
478: hme_meminit(sc)
479: struct hme_softc *sc;
480: {
481: struct hme_desc *desc;
482: int i;
483:
484: if (sc->sc_desc_dva == NULL)
485: sc->sc_desc_dva = (struct hme_desc *) dvma_malloc(
486: sizeof(struct hme_desc), &sc->sc_desc, M_NOWAIT);
487: if (sc->sc_bufs_dva == NULL)
488: sc->sc_bufs_dva = (struct hme_bufs *) dvma_malloc(
489: sizeof(struct hme_bufs), &sc->sc_bufs, M_NOWAIT);
490:
491: desc = sc->sc_desc;
492:
493: /*
494: * Setup TX descriptors
495: */
496: sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
497: for (i = 0; i < HME_TX_RING_SIZE; i++) {
498: desc->hme_txd[i].tx_addr =
499: (u_int32_t)sc->sc_bufs_dva->tx_buf[i];
500: desc->hme_txd[i].tx_flags = 0;
501: }
502:
503: /*
504: * Setup RX descriptors
505: */
506: sc->sc_last_rd = 0;
507: for (i = 0; i < HME_RX_RING_SIZE; i++) {
508: desc->hme_rxd[i].rx_addr =
509: (u_int32_t)sc->sc_bufs_dva->rx_buf[i];
510: desc->hme_rxd[i].rx_flags = HME_RXD_OWN |
511: ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);
512: }
513: }
514:
515: void
516: hmeinit(sc)
517: struct hme_softc *sc;
518: {
519: u_int32_t c, n;
520: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
521: struct hme_tcvr *tcvr = sc->sc_tcvr;
522: struct hme_cr *cr = sc->sc_cr;
523: struct hme_gr *gr = sc->sc_gr;
524: struct hme_txr *txr = sc->sc_txr;
525: struct hme_rxr *rxr = sc->sc_rxr;
526:
527: hme_poll_stop(sc);
528: hmestop(sc);
529:
530: hme_meminit(sc);
531:
532: tcvr->int_mask = 0xffff;
533:
534: c = tcvr->cfg;
535: if (sc->sc_flags & HME_FLAG_FENABLE)
536: tcvr->cfg = c & ~(TCVR_CFG_BENABLE);
537: else
538: tcvr->cfg = c | TCVR_CFG_BENABLE;
539:
540: hme_reset_tx(sc);
541: hme_reset_rx(sc);
542:
543: cr->rand_seed = sc->sc_arpcom.ac_enaddr[5] |
544: ((sc->sc_arpcom.ac_enaddr[4] << 8) & 0x3f00);
545: cr->mac_addr0 = (sc->sc_arpcom.ac_enaddr[0] << 8) |
546: sc->sc_arpcom.ac_enaddr[1];
547: cr->mac_addr1 = (sc->sc_arpcom.ac_enaddr[2] << 8) |
548: sc->sc_arpcom.ac_enaddr[3];
549: cr->mac_addr2 = (sc->sc_arpcom.ac_enaddr[4] << 8) |
550: sc->sc_arpcom.ac_enaddr[5];
551: cr->tx_pkt_max = cr->rx_pkt_max = ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN;
552:
553: cr->jsize = HME_DEFAULT_JSIZE;
554: cr->ipkt_gap1 = HME_DEFAULT_IPKT_GAP1;
555: cr->ipkt_gap2 = HME_DEFAULT_IPKT_GAP2;
556:
557: rxr->rx_ring = (u_int32_t)sc->sc_desc_dva->hme_rxd;
558: txr->tx_ring = (u_int32_t)sc->sc_desc_dva->hme_txd;
559:
560: if (sc->sc_burst & SBUS_BURST_64)
561: gr->cfg = GR_CFG_BURST64;
562: else if (sc->sc_burst & SBUS_BURST_32)
563: gr->cfg = GR_CFG_BURST32;
564: else if (sc->sc_burst & SBUS_BURST_16)
565: gr->cfg = GR_CFG_BURST16;
566: else {
567: printf("%s: burst size unknown\n", sc->sc_dev.dv_xname);
568: gr->cfg = 0;
569: }
570:
571: gr->imask = GR_IMASK_SENTFRAME | GR_IMASK_TXPERR |
572: GR_IMASK_GOTFRAME | GR_IMASK_RCNTEXP;
573:
574: txr->tx_rsize = (HME_TX_RING_SIZE >> TXR_RSIZE_SHIFT) - 1;
575: txr->cfg |= TXR_CFG_DMAENABLE;
576:
577: c = RXR_CFG_DMAENABLE | (HME_RX_OFFSET << 3);
578: /* RX TCP/UDP cksum offset */
579: n = (ETHER_HDR_LEN + sizeof(struct ip)) / 2;
580: n = (n << RXR_CFG_CSUM_SHIFT) & RXR_CFG_CSUMSTART;
581: c |= n;
582: #if HME_RX_RING_SIZE == 32
583: c |= RXR_CFG_RINGSIZE32;
584: #elif HME_RX_RING_SIZE == 64
585: c |= RXR_CFG_RINGSIZE64;
586: #elif HME_RX_RING_SIZE == 128
587: c |= RXR_CFG_RINGSIZE128;
588: #elif HME_RX_RING_SIZE == 256
589: c |= RXR_CFG_RINGSIZE256;
590: #else
591: #error "HME_RX_RING_SIZE must be 32, 64, 128, or 256."
592: #endif
593: rxr->cfg = c;
594: DELAY(20);
595: if (c != rxr->cfg) /* the receiver sometimes misses bits */
596: printf("%s: setting rxreg->cfg failed.\n", sc->sc_dev.dv_xname);
597:
598: cr->rx_cfg = 0;
599: hme_mcreset(sc);
600: DELAY(10);
601:
602: cr->tx_cfg |= CR_TXCFG_DGIVEUP;
603:
604: c = CR_XCFG_ODENABLE;
605: if (sc->sc_flags & HME_FLAG_LANCE)
606: c |= (HME_DEFAULT_IPKT_GAP0 << 5) | CR_XCFG_LANCE;
607: cr->xif_cfg = c;
608:
609: cr->tx_cfg |= CR_TXCFG_ENABLE; /* enable tx */
610: cr->rx_cfg |= CR_RXCFG_ENABLE; /* enable rx */
611:
612: mii_mediachg(&sc->sc_mii);
613:
614: ifp->if_flags |= IFF_RUNNING;
615: ifp->if_flags &= ~IFF_OACTIVE;
616: sc->sc_if_flags = ifp->if_flags;
617: ifp->if_timer = 0;
618: }
619:
620: void
621: hme_poll_stop(sc)
622: struct hme_softc *sc;
623: {
624: struct hme_tcvr *tcvr = sc->sc_tcvr;
625:
626: /* if not polling, or polling not enabled, we're done. */
627: if ((sc->sc_flags & (HME_FLAG_POLLENABLE | HME_FLAG_POLL)) !=
628: (HME_FLAG_POLLENABLE | HME_FLAG_POLL))
629: return;
630:
631: /* Turn off MIF interrupts, and disable polling */
632: tcvr->int_mask = 0xffff;
633: tcvr->cfg &= ~(TCVR_CFG_PENABLE);
634: sc->sc_flags &= ~(HME_FLAG_POLL);
635: DELAY(200);
636: }
637:
638: #define RESET_TRIES 32
639:
640: void
641: hme_reset_tx(sc)
642: struct hme_softc *sc;
643: {
644: int tries = RESET_TRIES;
645: struct hme_cr *cr = sc->sc_cr;
646:
647: cr->tx_swreset = 0;
648: while (--tries && (cr->tx_swreset & 1))
649: DELAY(20);
650:
651: if (!tries)
652: printf("%s: reset tx failed\n", sc->sc_dev.dv_xname);
653: }
654:
655: void
656: hme_reset_rx(sc)
657: struct hme_softc *sc;
658: {
659: int tries = RESET_TRIES;
660: struct hme_cr *cr = sc->sc_cr;
661:
662: cr->rx_swreset = 0;
663: while (--tries && (cr->rx_swreset & 1))
664: DELAY(20);
665:
666: if (!tries)
667: printf("%s: reset rx failed\n", sc->sc_dev.dv_xname);
668: }
669:
670: /*
671: * mif interrupt
672: */
673: int
674: hme_mint(sc, why)
675: struct hme_softc *sc;
676: u_int32_t why;
677: {
678: printf("%s: link status changed\n", sc->sc_dev.dv_xname);
679: hme_poll_stop(sc);
680: return (1);
681: }
682:
683: /*
684: * transmit interrupt
685: */
686: int
687: hme_tint(sc)
688: struct hme_softc *sc;
689: {
690: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
691: struct hme_cr *cr = sc->sc_cr;
692: int bix;
693: struct hme_txd txd;
694:
695: /*
696: * Get collision counters
697: */
698: ifp->if_collisions += cr->ex_ctr + cr->lt_ctr + cr->fc_ctr + cr->nc_ctr;
699: cr->ex_ctr = 0;
700: cr->lt_ctr = 0;
701: cr->fc_ctr = 0;
702: cr->nc_ctr = 0;
703:
704: bix = sc->sc_first_td;
705:
706: for (;;) {
707: if (sc->sc_no_td <= 0)
708: break;
709:
710: bcopy(&sc->sc_desc->hme_txd[bix], &txd, sizeof(txd));
711:
712: if (txd.tx_flags & HME_TXD_OWN)
713: break;
714:
715: ifp->if_flags &= ~IFF_OACTIVE;
716: ifp->if_opackets++;
717:
718: if (++bix == HME_TX_RING_SIZE)
719: bix = 0;
720:
721: --sc->sc_no_td;
722: }
723:
724: sc->sc_first_td = bix;
725:
726: hmestart(ifp);
727:
728: if (sc->sc_no_td == 0)
729: ifp->if_timer = 0;
730:
731: return (1);
732: }
733:
734: /*
735: * XXX layering violation
736: *
737: * If we can have additional csum data member in 'struct pkthdr' for
738: * these incomplete checksum offload capable hardware, things would be
739: * much simpler. That member variable will carry partial checksum
740: * data and it may be evaluated in TCP/UDP input handler after
741: * computing pseudo header checksumming.
742: */
743: void
744: hme_rxcksum(struct mbuf *m, u_int32_t flags)
745: {
746: struct ether_header *eh;
747: struct ip *ip;
748: struct udphdr *uh;
749: int32_t hlen, len, pktlen;
750: u_int16_t cksum, *opts;
751: u_int32_t temp32;
752: union pseudoh {
753: struct hdr {
754: u_int16_t len;
755: u_int8_t ttl;
756: u_int8_t proto;
757: u_int32_t src;
758: u_int32_t dst;
759: } h;
760: u_int16_t w[6];
761: } ph;
762:
763: pktlen = m->m_pkthdr.len;
764: if (pktlen < sizeof(struct ether_header))
765: return;
766: eh = mtod(m, struct ether_header *);
767: if (eh->ether_type != htons(ETHERTYPE_IP))
768: return;
769: ip = (struct ip *)(eh + 1);
770: if (ip->ip_v != IPVERSION)
771: return;
772:
773: hlen = ip->ip_hl << 2;
774: pktlen -= sizeof(struct ether_header);
775: if (hlen < sizeof(struct ip))
776: return;
777: if (ntohs(ip->ip_len) < hlen)
778: return;
779: if (ntohs(ip->ip_len) != pktlen)
780: return;
781: if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
782: return; /* can't handle fragmented packet */
783:
784: switch (ip->ip_p) {
785: case IPPROTO_TCP:
786: if (pktlen < (hlen + sizeof(struct tcphdr)))
787: return;
788: break;
789: case IPPROTO_UDP:
790: if (pktlen < (hlen + sizeof(struct udphdr)))
791: return;
792: uh = (struct udphdr *)((caddr_t)ip + hlen);
793: if (uh->uh_sum == 0)
794: return; /* no checksum */
795: break;
796: default:
797: return;
798: }
799:
800: cksum = htons(~(flags & HME_RXD_CSUM));
801: /* cksum fixup for IP options */
802: len = hlen - sizeof(struct ip);
803: if (len > 0) {
804: opts = (u_int16_t *)(ip + 1);
805: for (; len > 0; len -= sizeof(u_int16_t), opts++) {
806: temp32 = cksum - *opts;
807: temp32 = (temp32 >> 16) + (temp32 & 65535);
808: cksum = temp32 & 65535;
809: }
810: }
811: /* cksum fixup for pseudo-header, replace with in_cksum_phdr()? */
812: ph.h.len = htons(ntohs(ip->ip_len) - hlen);
813: ph.h.ttl = 0;
814: ph.h.proto = ip->ip_p;
815: ph.h.src = ip->ip_src.s_addr;
816: ph.h.dst = ip->ip_dst.s_addr;
817: temp32 = cksum;
818: opts = &ph.w[0];
819: temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
820: temp32 = (temp32 >> 16) + (temp32 & 65535);
821: temp32 += (temp32 >> 16);
822: cksum = ~temp32;
823: if (cksum == 0) {
824: m->m_pkthdr.csum_flags |=
825: M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
826: }
827: }
828:
829: int
830: hme_rint(sc)
831: struct hme_softc *sc;
832: {
833: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
834: int bix, len;
835: struct hme_rxd rxd;
836:
837: bix = sc->sc_last_rd;
838:
839: for (;;) {
840: bcopy(&sc->sc_desc->hme_rxd[bix], &rxd, sizeof(rxd));
841: len = rxd.rx_flags >> 16;
842:
843: if (rxd.rx_flags & HME_RXD_OWN)
844: break;
845:
846: if (rxd.rx_flags & HME_RXD_OVERFLOW)
847: ifp->if_ierrors++;
848: else
849: hme_read(sc, bix, len, rxd.rx_flags);
850:
851: rxd.rx_flags = HME_RXD_OWN |
852: ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);
853: bcopy(&rxd, &sc->sc_desc->hme_rxd[bix], sizeof(rxd));
854:
855: if (++bix == HME_RX_RING_SIZE)
856: bix = 0;
857: }
858:
859: sc->sc_last_rd = bix;
860:
861: return (1);
862: }
863:
864: /*
865: * error interrupt
866: */
867: int
868: hme_eint(sc, why)
869: struct hme_softc *sc;
870: u_int32_t why;
871: {
872: if (why & GR_STAT_NORXD) {
873: sc->sc_arpcom.ac_if.if_ierrors++;
874: why &= ~GR_STAT_NORXD;
875: }
876: if (why & GR_STAT_DTIMEXP) {
877: sc->sc_arpcom.ac_if.if_oerrors++;
878: why &= ~GR_STAT_DTIMEXP;
879: }
880:
881: if (why & GR_STAT_ALL_ERRORS) {
882: printf("%s: stat=%b, resetting.\n", sc->sc_dev.dv_xname,
883: why, GR_STAT_BITS);
884: hmereset(sc);
885: }
886:
887: return (1);
888: }
889:
890: /*
891: * Interrupt handler
892: */
893: int
894: hmeintr(v)
895: void *v;
896: {
897: struct hme_softc *sc = (struct hme_softc *)v;
898: struct hme_gr *gr = sc->sc_gr;
899: u_int32_t why;
900: int r = 0;
901:
902: why = gr->stat;
903:
904: if (why & GR_STAT_ALL_ERRORS)
905: r |= hme_eint(sc, why);
906:
907: if (why & GR_STAT_MIFIRQ)
908: r |= hme_mint(sc, why);
909:
910: if (why & (GR_STAT_TXALL | GR_STAT_HOSTTOTX))
911: r |= hme_tint(sc);
912:
913: if (why & GR_STAT_RXTOHOST)
914: r |= hme_rint(sc);
915:
916: return (r);
917: }
918:
919: int
920: hme_put(sc, idx, m)
921: struct hme_softc *sc;
922: int idx;
923: struct mbuf *m;
924: {
925: struct mbuf *n;
926: u_int8_t *buf = sc->sc_bufs->tx_buf[idx];
927: int len, tlen = 0;
928:
929: for (; m; m = n) {
930: len = m->m_len;
931: if (len == 0) {
932: MFREE(m, n);
933: continue;
934: }
935: bcopy(mtod(m, caddr_t), buf, len);
936: buf += len;
937: tlen += len;
938: MFREE(m, n);
939: }
940: return (tlen);
941: }
942:
943: void
944: hme_read(sc, idx, len, flags)
945: struct hme_softc *sc;
946: int idx, len;
947: u_int32_t flags;
948: {
949: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
950: struct mbuf *m;
951:
952: if (len <= sizeof(struct ether_header) ||
953: len > ETHERMTU + sizeof(struct ether_header)) {
954: printf("%s: invalid packet size %d; dropping\n",
955: ifp->if_xname, len);
956: ifp->if_ierrors++;
957: return;
958: }
959:
960: /* Pull packet off interface. */
961: m = m_devget(sc->sc_bufs->rx_buf[idx], len + HME_RX_OFFSET, 0,
962: &sc->sc_arpcom.ac_if, NULL);
963: if (m == NULL) {
964: ifp->if_ierrors++;
965: return;
966: }
967: m_adj(m, HME_RX_OFFSET);
968:
969: ifp->if_ipackets++;
970: hme_rxcksum(m, flags);
971:
972: #if NBPFILTER > 0
973: /*
974: * Check if there's a BPF listener on this interface.
975: * If so, hand off the raw packet to BPF.
976: */
977: if (ifp->if_bpf)
978: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
979: #endif
980: /* Pass the packet up. */
981: ether_input_mbuf(ifp, m);
982: }
983:
984: /*
985: * Program the multicast receive filter.
986: */
987: void
988: hme_mcreset(sc)
989: struct hme_softc *sc;
990: {
991: struct arpcom *ac = &sc->sc_arpcom;
992: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
993: struct hme_cr *cr = sc->sc_cr;
994: u_int32_t crc;
995: u_int16_t hash[4];
996: u_int8_t octet;
997: int i, j;
998: struct ether_multi *enm;
999: struct ether_multistep step;
1000:
1001: if (ifp->if_flags & IFF_PROMISC) {
1002: cr->rx_cfg |= CR_RXCFG_PMISC;
1003: return;
1004: }
1005: else
1006: cr->rx_cfg &= ~CR_RXCFG_PMISC;
1007:
1008: if (ifp->if_flags & IFF_ALLMULTI) {
1009: cr->htable3 = 0xffff;
1010: cr->htable2 = 0xffff;
1011: cr->htable1 = 0xffff;
1012: cr->htable0 = 0xffff;
1013: cr->rx_cfg |= CR_RXCFG_HENABLE;
1014: return;
1015: }
1016:
1017: hash[3] = hash[2] = hash[1] = hash[0] = 0;
1018:
1019: ETHER_FIRST_MULTI(step, ac, enm);
1020: while (enm != NULL) {
1021: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
1022: /*
1023: * We must listen to a range of multicast
1024: * addresses. For now, just accept all
1025: * multicasts, rather than trying to set only
1026: * those filter bits needed to match the range.
1027: * (At this time, the only use of address
1028: * ranges is for IP multicast routing, for
1029: * which the range is big enough to require
1030: * all bits set.)
1031: */
1032: cr->htable3 = 0xffff;
1033: cr->htable2 = 0xffff;
1034: cr->htable1 = 0xffff;
1035: cr->htable0 = 0xffff;
1036: cr->rx_cfg |= CR_RXCFG_HENABLE;
1037: ifp->if_flags |= IFF_ALLMULTI;
1038: return;
1039: }
1040:
1041: crc = 0xffffffff;
1042:
1043: for (i = 0; i < ETHER_ADDR_LEN; i++) {
1044: octet = enm->enm_addrlo[i];
1045:
1046: for (j = 0; j < 8; j++) {
1047: if ((crc & 1) ^ (octet & 1)) {
1048: crc >>= 1;
1049: crc ^= ETHER_CRC_POLY_LE;
1050: }
1051: else
1052: crc >>= 1;
1053: octet >>= 1;
1054: }
1055: }
1056:
1057: crc >>=26;
1058: hash[crc >> 4] |= 1 << (crc & 0xf);
1059: ETHER_NEXT_MULTI(step, enm);
1060: }
1061: cr->htable3 = hash[3];
1062: cr->htable2 = hash[2];
1063: cr->htable1 = hash[1];
1064: cr->htable0 = hash[0];
1065: cr->rx_cfg |= CR_RXCFG_HENABLE;
1066: ifp->if_flags &= ~IFF_ALLMULTI;
1067: }
1068:
1069: /*
1070: * Writing to the serial BitBang, is a matter of putting the bit
1071: * into the data register, then strobing the clock.
1072: */
1073: void
1074: hme_tcvr_bb_writeb(sc, b)
1075: struct hme_softc *sc;
1076: int b;
1077: {
1078: sc->sc_tcvr->bb_data = b & 0x1;
1079: sc->sc_tcvr->bb_clock = 0;
1080: sc->sc_tcvr->bb_clock = 1;
1081: }
1082:
1083: /*
1084: * Read a bit from a PHY, if the PHY is not our internal or external
1085: * phy addr, just return all zero's.
1086: */
1087: int
1088: hme_tcvr_bb_readb(sc, phy)
1089: struct hme_softc *sc;
1090: int phy;
1091: {
1092: int ret;
1093:
1094: sc->sc_tcvr->bb_clock = 0;
1095: DELAY(10);
1096:
1097: if (phy == TCVR_PHYADDR_ITX)
1098: ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO0;
1099: else if (phy == TCVR_PHYADDR_ETX)
1100: ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO1;
1101: else
1102: ret = 0;
1103:
1104: sc->sc_tcvr->bb_clock = 1;
1105:
1106: return ((ret) ? 1 : 0);
1107: }
1108:
1109: void
1110: hme_mii_write(self, phy, reg, val)
1111: struct device *self;
1112: int phy, reg, val;
1113: {
1114: struct hme_softc *sc = (struct hme_softc *)self;
1115: struct hme_tcvr *tcvr = sc->sc_tcvr;
1116: int tries = 16, i;
1117:
1118: if (sc->sc_flags & HME_FLAG_FENABLE) {
1119: tcvr->frame = (FRAME_WRITE | phy << 23) |
1120: ((reg & 0xff) << 18) | (val & 0xffff);
1121: while (!(tcvr->frame & 0x10000) && (tries != 0)) {
1122: tries--;
1123: DELAY(200);
1124: }
1125: if (!tries)
1126: printf("%s: mii_write failed\n", sc->sc_dev.dv_xname);
1127: return;
1128: }
1129:
1130: tcvr->bb_oenab = 1;
1131:
1132: for (i = 0; i < 32; i++)
1133: hme_tcvr_bb_writeb(sc, 1);
1134:
1135: hme_tcvr_bb_writeb(sc, (MII_COMMAND_START >> 1) & 1);
1136: hme_tcvr_bb_writeb(sc, MII_COMMAND_START & 1);
1137: hme_tcvr_bb_writeb(sc, (MII_COMMAND_WRITE >> 1) & 1);
1138: hme_tcvr_bb_writeb(sc, MII_COMMAND_WRITE & 1);
1139:
1140: for (i = 4; i >= 0; i--)
1141: hme_tcvr_bb_writeb(sc, (phy >> i) & 1);
1142:
1143: for (i = 4; i >= 0; i--)
1144: hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
1145:
1146: for (i = 15; i >= 0; i--)
1147: hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
1148:
1149: tcvr->bb_oenab = 0;
1150: }
1151:
1152: int
1153: hme_mii_read(self, phy, reg)
1154: struct device *self;
1155: int phy, reg;
1156: {
1157: struct hme_softc *sc = (struct hme_softc *)self;
1158: struct hme_tcvr *tcvr = sc->sc_tcvr;
1159: int tries = 16, i, ret = 0;
1160:
1161: /* Use the frame if possible */
1162: if (sc->sc_flags & HME_FLAG_FENABLE) {
1163: tcvr->frame = (FRAME_READ | phy << 23) |
1164: ((reg & 0xff) << 18);
1165: while (!(tcvr->frame & 0x10000) && (tries != 0)) {
1166: tries--;
1167: DELAY(20);
1168: }
1169: if (!tries) {
1170: printf("%s: mii_read failed\n", sc->sc_dev.dv_xname);
1171: return (0);
1172: }
1173: return (tcvr->frame & 0xffff);
1174: }
1175:
1176: tcvr->bb_oenab = 1;
1177:
1178: for (i = 0; i < 32; i++) /* make bitbang idle */
1179: hme_tcvr_bb_writeb(sc, 1);
1180:
1181: hme_tcvr_bb_writeb(sc, (MII_COMMAND_START >> 1) & 1);
1182: hme_tcvr_bb_writeb(sc, MII_COMMAND_START & 1);
1183: hme_tcvr_bb_writeb(sc, (MII_COMMAND_READ >> 1) & 1);
1184: hme_tcvr_bb_writeb(sc, MII_COMMAND_READ & 1);
1185:
1186: for (i = 4; i >= 0; i--)
1187: hme_tcvr_bb_writeb(sc, (phy >> i) & 1);
1188:
1189: for (i = 4; i >= 0; i--)
1190: hme_tcvr_bb_writeb(sc, (reg >> i) & 1);
1191:
1192: tcvr->bb_oenab = 0; /* turn off bitbang intrs */
1193:
1194: hme_tcvr_bb_readb(sc, phy); /* ignore... */
1195:
1196: for (i = 15; i >= 15; i--) /* read value */
1197: ret |= hme_tcvr_bb_readb(sc, phy) << i;
1198:
1199: hme_tcvr_bb_readb(sc, phy); /* ignore... */
1200: hme_tcvr_bb_readb(sc, phy); /* ignore... */
1201: hme_tcvr_bb_readb(sc, phy); /* ignore... */
1202:
1203: return (ret);
1204: }
1205:
1206: int
1207: hme_mediachange(ifp)
1208: struct ifnet *ifp;
1209: {
1210: if (ifp->if_flags & IFF_UP)
1211: hmeinit(ifp->if_softc);
1212: return (0);
1213: }
1214:
1215: void
1216: hme_mediastatus(ifp, ifmr)
1217: struct ifnet *ifp;
1218: struct ifmediareq *ifmr;
1219: {
1220: struct hme_softc *sc = (struct hme_softc *)ifp->if_softc;
1221:
1222: mii_pollstat(&sc->sc_mii);
1223: ifmr->ifm_active = sc->sc_mii.mii_media_active;
1224: ifmr->ifm_status = sc->sc_mii.mii_media_status;
1225: }
1226:
1227: void
1228: hme_mii_statchg(self)
1229: struct device *self;
1230: {
1231: struct hme_softc *sc = (struct hme_softc *)self;
1232: struct hme_cr *cr = sc->sc_cr;
1233:
1234: /* Apparently the hme chip is SIMPLEX if working in full duplex mode,
1235: but not otherwise. */
1236: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) {
1237: cr->tx_cfg |= CR_TXCFG_FULLDPLX;
1238: sc->sc_arpcom.ac_if.if_flags |= IFF_SIMPLEX;
1239: } else {
1240: cr->tx_cfg &= ~CR_TXCFG_FULLDPLX;
1241: sc->sc_arpcom.ac_if.if_flags &= ~IFF_SIMPLEX;
1242: }
1243: sc->sc_if_flags = sc->sc_arpcom.ac_if.if_flags;
1244: }
CVSweb