diff options
Diffstat (limited to 'sys/dev/ic/gem.c')
-rw-r--r-- | sys/dev/ic/gem.c | 512 |
1 files changed, 258 insertions, 254 deletions
diff --git a/sys/dev/ic/gem.c b/sys/dev/ic/gem.c index 3c7a7a3b4ac..52eb0d4bcb5 100644 --- a/sys/dev/ic/gem.c +++ b/sys/dev/ic/gem.c @@ -1,5 +1,5 @@ -/* $OpenBSD: gem.c,v 1.15 2002/01/28 01:04:02 jason Exp $ */ -/* $NetBSD: gem.c,v 1.11 2001/11/17 00:56:04 thorpej Exp $ */ +/* $OpenBSD: gem.c,v 1.16 2002/02/22 20:15:28 jason Exp $ */ +/* $NetBSD: gem.c,v 1.1 2001/09/16 00:11:43 eeh Exp $ */ /* * @@ -37,8 +37,6 @@ #include "bpfilter.h" #include "vlan.h" -#include <sys/cdefs.h> - #include <sys/param.h> #include <sys/systm.h> #include <sys/timeout.h> @@ -61,9 +59,6 @@ #ifdef INET #include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> #include <netinet/if_ether.h> #endif @@ -87,6 +82,10 @@ #define TRIES 10000 +struct cfdriver gem_cd = { + NULL, "gem", DV_IFNET +}; + void gem_start __P((struct ifnet *)); void gem_stop __P((struct ifnet *, int)); int gem_ioctl __P((struct ifnet *, u_long, caddr_t)); @@ -106,6 +105,7 @@ int gem_disable_tx(struct gem_softc *sc); void gem_rxdrain(struct gem_softc *sc); int gem_add_rxbuf(struct gem_softc *sc, int idx); void gem_setladrf __P((struct gem_softc *)); +int gem_encap __P((struct gem_softc *, struct mbuf *, u_int32_t *)); /* MII methods & callbacks */ static int gem_mii_readreg __P((struct device *, int, int)); @@ -120,9 +120,11 @@ int gem_put __P((struct gem_softc *, int, struct mbuf *)); void gem_read __P((struct gem_softc *, int, int)); int gem_eint __P((struct gem_softc *, u_int)); int gem_rint __P((struct gem_softc *)); -int gem_tint __P((struct gem_softc *)); +int gem_tint __P((struct gem_softc *, u_int32_t)); void gem_power __P((int, void *)); +static int ether_cmp __P((u_char *, u_char *)); + #ifdef GEM_DEBUG #define DPRINTF(sc, x) if ((sc)->sc_arpcom.ac_if.if_flags & IFF_DEBUG) \ printf x @@ -132,20 +134,21 @@ void gem_power __P((int, void *)); /* - * gem_attach: + * gem_config: * * Attach a Gem interface to the system. */ void -gem_attach(sc, enaddr) +gem_config(sc) struct gem_softc *sc; - uint8_t *enaddr; { struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct mii_data *mii = &sc->sc_mii; struct mii_softc *child; int i, error; + bcopy(sc->sc_enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); + /* Make sure the chip is stopped. */ ifp->if_softc = sc; gem_reset(sc); @@ -162,6 +165,7 @@ gem_attach(sc, enaddr) goto fail_0; } + /* XXX should map this in with correct endianness */ if ((error = bus_dmamem_map(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg, sizeof(struct gem_control_data), (caddr_t *)&sc->sc_control_data, BUS_DMA_COHERENT)) != 0) { @@ -207,9 +211,7 @@ gem_attach(sc, enaddr) /* Announce ourselves. */ printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname, - ether_sprintf(enaddr)); - - bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); + ether_sprintf(sc->sc_enaddr)); /* Initialize ifnet structure. */ strcpy(ifp->if_xname, sc->sc_dev.dv_xname); @@ -292,11 +294,6 @@ gem_attach(sc, enaddr) ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); } -#if 0 - /* claim 802.1q capability */ - sc->sc_arpcom.ac_capabilities |= ETHERCAP_VLAN_MTU; -#endif - /* Attach the interface. */ if_attach(ifp); ether_ifattach(ifp); @@ -305,23 +302,6 @@ gem_attach(sc, enaddr) if (sc->sc_sh == NULL) panic("gem_config: can't establish shutdownhook"); -#if NRND > 0 - rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname, - RND_TYPE_NET, 0); -#endif - - -#if notyet - /* - * Add a suspend hook to make sure we come back up after a - * resume. - */ - sc->sc_powerhook = powerhook_establish(gem_power, sc); - if (sc->sc_powerhook == NULL) - printf("%s: WARNING: unable to establish power hook\n", - sc->sc_dev.dv_xname); -#endif - timeout_set(&sc->sc_tick_ch, gem_tick, sc); return; @@ -353,14 +333,30 @@ gem_tick(arg) void *arg; { struct gem_softc *sc = arg; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t mac = sc->sc_h; int s; - s = splnet(); + s = splimp(); + + /* unload collisions counters */ + ifp->if_collisions += + bus_space_read_4(t, mac, GEM_MAC_NORM_COLL_CNT) + + bus_space_read_4(t, mac, GEM_MAC_FIRST_COLL_CNT) + + bus_space_read_4(t, mac, GEM_MAC_EXCESS_COLL_CNT) + + bus_space_read_4(t, mac, GEM_MAC_LATE_COLL_CNT); + + /* clear the hardware counters */ + bus_space_write_4(t, mac, GEM_MAC_NORM_COLL_CNT, 0); + bus_space_write_4(t, mac, GEM_MAC_FIRST_COLL_CNT, 0); + bus_space_write_4(t, mac, GEM_MAC_EXCESS_COLL_CNT, 0); + bus_space_write_4(t, mac, GEM_MAC_LATE_COLL_CNT, 0); + mii_tick(&sc->sc_mii); splx(s); timeout_add(&sc->sc_tick_ch, hz); - } void @@ -372,7 +368,7 @@ gem_reset(sc) int i; int s; - s = splnet(); + s = splimp(); DPRINTF(sc, ("%s: gem_reset\n", sc->sc_dev.dv_xname)); gem_reset_rx(sc); gem_reset_tx(sc); @@ -420,6 +416,8 @@ void gem_stop(struct ifnet *ifp, int disable) { struct gem_softc *sc = (struct gem_softc *)ifp->if_softc; + struct gem_sxd *sd; + u_int32_t i; DPRINTF(sc, ("%s: gem_stop\n", sc->sc_dev.dv_xname)); @@ -427,8 +425,27 @@ gem_stop(struct ifnet *ifp, int disable) mii_down(&sc->sc_mii); /* XXX - Should we reset these instead? */ - gem_reset_rx(sc); - gem_reset_tx(sc); + gem_disable_rx(sc); + gem_disable_rx(sc); + + /* + * Release any queued transmit buffers. + */ + for (i = 0; i < GEM_NTXDESC; i++) { + sd = &sc->sc_txd[i]; + if (sd->sd_map != NULL) { + bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0, + sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmatag, sd->sd_map); + bus_dmamap_destroy(sc->sc_dmatag, sd->sd_map); + sd->sd_map = NULL; + } + if (sd->sd_mbuf != NULL) { + m_freem(sd->sd_mbuf); + sd->sd_mbuf = NULL; + } + } + sc->sc_tx_cnt = sc->sc_tx_prod = sc->sc_tx_cons = 0; if (disable) { gem_rxdrain(sc); @@ -460,7 +477,7 @@ gem_reset_rx(struct gem_softc *sc) gem_disable_rx(sc); bus_space_write_4(t, h, GEM_RX_CONFIG, 0); /* Wait till it finishes */ - for (i=TRIES; i--; delay(100)) + for (i = TRIES; i--; delay(100)) if ((bus_space_read_4(t, h, GEM_RX_CONFIG) & 1) == 0) break; if ((bus_space_read_4(t, h, GEM_RX_CONFIG) & 1) != 0) @@ -473,7 +490,7 @@ gem_reset_rx(struct gem_softc *sc) /* Finally, reset the ERX */ bus_space_write_4(t, h, GEM_RESET, GEM_RESET_RX); /* Wait till it finishes */ - for (i=TRIES; i--; delay(100)) + for (i = TRIES; i--; delay(100)) if ((bus_space_read_4(t, h, GEM_RESET) & GEM_RESET_RX) == 0) break; if ((bus_space_read_4(t, h, GEM_RESET) & GEM_RESET_RX) != 0) { @@ -502,7 +519,7 @@ gem_reset_tx(struct gem_softc *sc) gem_disable_tx(sc); bus_space_write_4(t, h, GEM_TX_CONFIG, 0); /* Wait till it finishes */ - for (i=TRIES; i--; delay(100)) + for (i = TRIES; i--; delay(100)) if ((bus_space_read_4(t, h, GEM_TX_CONFIG) & 1) == 0) break; if ((bus_space_read_4(t, h, GEM_TX_CONFIG) & 1) != 0) @@ -515,7 +532,7 @@ gem_reset_tx(struct gem_softc *sc) /* Finally, reset the ETX */ bus_space_write_4(t, h, GEM_RESET, GEM_RESET_TX); /* Wait till it finishes */ - for (i=TRIES; i--; delay(100)) + for (i = TRIES; i--; delay(100)) if ((bus_space_read_4(t, h, GEM_RESET) & GEM_RESET_TX) == 0) break; if ((bus_space_read_4(t, h, GEM_RESET) & GEM_RESET_TX) != 0) { @@ -543,7 +560,7 @@ gem_disable_rx(struct gem_softc *sc) bus_space_write_4(t, h, GEM_MAC_RX_CONFIG, cfg); /* Wait for it to finish */ - for (i=TRIES; i--; delay(100)) + for (i = TRIES; i--; delay(100)) if ((bus_space_read_4(t, h, GEM_MAC_RX_CONFIG) & GEM_MAC_RX_ENABLE) == 0) return (0); @@ -567,7 +584,7 @@ gem_disable_tx(struct gem_softc *sc) bus_space_write_4(t, h, GEM_MAC_TX_CONFIG, cfg); /* Wait for it to finish */ - for (i=TRIES; i--; delay(100)) + for (i = TRIES; i--; delay(100)) if ((bus_space_read_4(t, h, GEM_MAC_TX_CONFIG) & GEM_MAC_TX_ENABLE) == 0) return (0); @@ -593,7 +610,6 @@ gem_meminit(struct gem_softc *sc) } GEM_CDTXSYNC(sc, 0, GEM_NTXDESC, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - sc->sc_tx_cons = sc->sc_tx_prod = 0; /* * Initialize the receive descriptor and receive job @@ -655,6 +671,7 @@ gem_ringsize(int sz) v = GEM_RING_SZ_8192; break; default: + v = GEM_RING_SZ_32; printf("gem: invalid Receive Descriptor ring size\n"); break; } @@ -674,7 +691,7 @@ gem_init(struct ifnet *ifp) int s; u_int32_t v; - s = splnet(); + s = splimp(); DPRINTF(sc, ("%s: gem_init: calling stop\n", sc->sc_dev.dv_xname)); /* @@ -701,18 +718,19 @@ gem_init(struct ifnet *ifp) /* step 4. TX MAC registers & counters */ gem_init_regs(sc); - bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME, - GEM_MTU | (0x2000 << 16)); + v = (GEM_MTU) | (0x2000 << 16) /* Burst size */; + bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME, v); /* step 5. RX MAC registers & counters */ gem_setladrf(sc); /* step 6 & 7. Program Descriptor Ring Base Addresses */ - /* NOTE: we use only 32-bit DMA addresses here. */ - bus_space_write_4(t, h, GEM_TX_RING_PTR_HI, 0); + bus_space_write_4(t, h, GEM_TX_RING_PTR_HI, + (((uint64_t)GEM_CDTXADDR(sc,0)) >> 32)); bus_space_write_4(t, h, GEM_TX_RING_PTR_LO, GEM_CDTXADDR(sc, 0)); - bus_space_write_4(t, h, GEM_RX_RING_PTR_HI, 0); + bus_space_write_4(t, h, GEM_RX_RING_PTR_HI, + (((uint64_t)GEM_CDRXADDR(sc,0)) >> 32)); bus_space_write_4(t, h, GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0)); /* step 8. Global Configuration & Interrupt Mask */ @@ -730,11 +748,11 @@ gem_init(struct ifnet *ifp) /* step 9. ETX Configuration: use mostly default values */ /* Enable DMA */ + bus_space_write_4(t, h, GEM_TX_KICK, 0); v = gem_ringsize(GEM_NTXDESC /*XXX*/); bus_space_write_4(t, h, GEM_TX_CONFIG, v|GEM_TX_CONFIG_TXDMA_EN| ((0x400<<10)&GEM_TX_CONFIG_TXFIFO_TH)); - bus_space_write_4(t, h, GEM_TX_KICK, 0); /* step 10. ERX Configuration */ @@ -756,9 +774,6 @@ gem_init(struct ifnet *ifp) /* step 11. Configure Media */ gem_mii_statchg(&sc->sc_dev); -/* XXXX Serial link needs a whole different setup. */ - - /* step 12. RX_MAC Configuration Register */ v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG); v |= GEM_MAC_RX_ENABLE; @@ -785,14 +800,31 @@ gem_init(struct ifnet *ifp) return (0); } +/* + * Compare two Ether/802 addresses for equality, inlined and unrolled for + * speed. + */ +static __inline__ int +ether_cmp(a, b) + u_char *a, *b; +{ + + if (a[5] != b[5] || a[4] != b[4] || a[3] != b[3] || + a[2] != b[2] || a[1] != b[1] || a[0] != b[0]) + return (0); + return (1); +} + + void gem_init_regs(struct gem_softc *sc) { - struct ifnet *ifp = &sc->sc_arpcom.ac_if; bus_space_tag_t t = sc->sc_bustag; bus_space_handle_t h = sc->sc_h; + u_int32_t v; /* These regs are not cleared on reset */ + sc->sc_inited = 0; if (!sc->sc_inited) { /* Wooo. Magic values. */ @@ -802,17 +834,15 @@ gem_init_regs(struct gem_softc *sc) bus_space_write_4(t, h, GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN); /* Max frame and max burst size */ - bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME, - (ifp->if_mtu+18) | (0x2000<<16)/* Burst size */); + v = (GEM_MTU) | (0x2000 << 16) /* Burst size */; + bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME, v); bus_space_write_4(t, h, GEM_MAC_PREAMBLE_LEN, 0x7); bus_space_write_4(t, h, GEM_MAC_JAM_SIZE, 0x4); bus_space_write_4(t, h, GEM_MAC_ATTEMPT_LIMIT, 0x10); /* Dunno.... */ bus_space_write_4(t, h, GEM_MAC_CONTROL_TYPE, 0x8088); bus_space_write_4(t, h, GEM_MAC_RANDOM_SEED, - ((sc->sc_arpcom.ac_enaddr[5] << 8) | - (sc->sc_arpcom.ac_enaddr[4]) << 0) & 0x3ff); - + ((sc->sc_enaddr[5]<<8)|sc->sc_enaddr[4])&0x3ff); /* Secondary MAC addr set to 0:0:0:0:0:0 */ bus_space_write_4(t, h, GEM_MAC_ADDR3, 0); bus_space_write_4(t, h, GEM_MAC_ADDR4, 0); @@ -847,123 +877,18 @@ gem_init_regs(struct gem_softc *sc) bus_space_write_4(t, h, GEM_MAC_RX_CODE_VIOL, 0); /* Un-pause stuff */ -#if 0 - bus_space_write_4(t, h, GEM_MAC_SEND_PAUSE_CMD, 0x1BF0); -#else bus_space_write_4(t, h, GEM_MAC_SEND_PAUSE_CMD, 0); -#endif /* * Set the station address. */ bus_space_write_4(t, h, GEM_MAC_ADDR0, - (sc->sc_arpcom.ac_enaddr[4] << 8) | sc->sc_arpcom.ac_enaddr[5]); + (sc->sc_enaddr[4]<<8) | sc->sc_enaddr[5]); bus_space_write_4(t, h, GEM_MAC_ADDR1, - (sc->sc_arpcom.ac_enaddr[2] << 8) | sc->sc_arpcom.ac_enaddr[3]); + (sc->sc_enaddr[2]<<8) | sc->sc_enaddr[3]); bus_space_write_4(t, h, GEM_MAC_ADDR2, - (sc->sc_arpcom.ac_enaddr[0] << 8) | sc->sc_arpcom.ac_enaddr[1]); -} - - - -void -gem_start(ifp) - struct ifnet *ifp; -{ - struct gem_softc *sc = (struct gem_softc *)ifp->if_softc; - struct mbuf *m0; - u_int32_t prod; - - if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) - return; - - prod = sc->sc_tx_prod; - for (;;) { - IFQ_POLL(&ifp->if_snd, m0); - if (m0 == NULL) - break; - - if (sc->sc_tx_cnt == (GEM_NTXDESC - 2)) { - ifp->if_flags |= IFF_OACTIVE; - break; - } - - IFQ_DEQUEUE(&ifp->if_snd, m0); - if (m0 == NULL) - break; - - m_copydata(m0, 0, m0->m_pkthdr.len, - &sc->sc_control_data->gcd_txbufs[prod][0]); - bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap, - offsetof(struct gem_control_data, gcd_txbufs[prod][0]), - m0->m_pkthdr.len, BUS_DMASYNC_PREWRITE); + (sc->sc_enaddr[0]<<8) | sc->sc_enaddr[1]); - sc->sc_txdescs[prod].gd_addr = - GEM_DMA_WRITE(sc, sc->sc_cddmamap->dm_segs[0].ds_addr + - offsetof(struct gem_control_data, gcd_txbufs[prod][0])); - sc->sc_txdescs[prod].gd_flags = GEM_DMA_WRITE(sc, - (m0->m_pkthdr.len & GEM_TD_BUFSIZE) | - GEM_TD_START_OF_PACKET | GEM_TD_END_OF_PACKET); - - m_freem(m0); - - GEM_CDTXSYNC(sc, prod, 1, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - - if (++prod == GEM_NTXDESC) - prod = 0; - ++sc->sc_tx_cnt; - } - if (prod != sc->sc_tx_prod) - bus_space_write_4(sc->sc_bustag, sc->sc_h, GEM_TX_KICK, prod); - sc->sc_tx_prod = prod; -} - -/* - * Transmit interrupt. - */ -int -gem_tint(sc) - struct gem_softc *sc; -{ - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - bus_space_tag_t t = sc->sc_bustag; - bus_space_handle_t mac = sc->sc_h; - u_int32_t hwcons, cons; - - /* - * Unload collision counters - */ - ifp->if_collisions += - bus_space_read_4(t, mac, GEM_MAC_NORM_COLL_CNT) + - bus_space_read_4(t, mac, GEM_MAC_FIRST_COLL_CNT) + - bus_space_read_4(t, mac, GEM_MAC_EXCESS_COLL_CNT) + - bus_space_read_4(t, mac, GEM_MAC_LATE_COLL_CNT); - - /* - * then clear the hardware counters. - */ - bus_space_write_4(t, mac, GEM_MAC_NORM_COLL_CNT, 0); - bus_space_write_4(t, mac, GEM_MAC_FIRST_COLL_CNT, 0); - bus_space_write_4(t, mac, GEM_MAC_EXCESS_COLL_CNT, 0); - bus_space_write_4(t, mac, GEM_MAC_LATE_COLL_CNT, 0); - - /* - * Go through our Tx list and free mbufs for those - * frames that have been transmitted. - */ - cons = sc->sc_tx_cons; - hwcons = bus_space_read_4(t, mac, GEM_TX_COMPLETION); - while (cons != hwcons) { - if (++cons == GEM_NTXDESC) - cons = 0; - --sc->sc_tx_cnt; - } - sc->sc_tx_cons = cons; - - ifp->if_flags &= ~IFF_OACTIVE; - - return (1); } /* @@ -982,7 +907,6 @@ gem_rint(sc) u_int64_t rxstat; int i, len; - DPRINTF(sc, ("%s: gem_rint\n", sc->sc_dev.dv_xname)); /* * XXXX Read the lastrx only once at the top for speed. */ @@ -1135,7 +1059,7 @@ gem_eint(sc, status) return (1); } - printf("%s: status=%x\n", sc->sc_dev.dv_xname, status); + printf("%s: status=%b\n", sc->sc_dev.dv_xname, status, GEM_INTR_BITS); return (1); } @@ -1149,22 +1073,16 @@ gem_intr(v) bus_space_handle_t seb = sc->sc_h; u_int32_t status; int r = 0; -#ifdef GEM_DEBUG - char bits[128]; -#endif status = bus_space_read_4(t, seb, GEM_STATUS); - DPRINTF(sc, ("%s: gem_intr: cplt %xstatus %s\n", - sc->sc_dev.dv_xname, (status>>19), - bitmask_snprintf(status, GEM_INTR_BITS, bits, sizeof(bits)))); + DPRINTF(sc, ("%s: gem_intr: cplt %xstatus %b\n", + sc->sc_dev.dv_xname, (status>>19), status, GEM_INTR_BITS)); if ((status & (GEM_INTR_RX_TAG_ERR | GEM_INTR_BERR)) != 0) r |= gem_eint(sc, status); - if ((status & - (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) - != 0) - r |= gem_tint(sc); + if ((status & (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) != 0) + r |= gem_tint(sc, status); if ((status & (GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF)) != 0) r |= gem_rint(sc); @@ -1200,7 +1118,7 @@ gem_watchdog(ifp) ++ifp->if_oerrors; /* Try to get more packets going. */ - gem_start(ifp); + gem_init(ifp); } /* @@ -1249,17 +1167,6 @@ gem_mii_readreg(self, phy, reg) printf("gem_mii_readreg: phy %d reg %d\n", phy, reg); #endif -#if 0 - /* Select the desired PHY in the MIF configuration register */ - v = bus_space_read_4(t, mif, GEM_MIF_CONFIG); - /* Clear PHY select bit */ - v &= ~GEM_MIF_CONFIG_PHY_SEL; - if (phy == GEM_PHYAD_EXTERNAL) - /* Set PHY select bit to get at external device */ - v |= GEM_MIF_CONFIG_PHY_SEL; - bus_space_write_4(t, mif, GEM_MIF_CONFIG, v); -#endif - /* Construct the frame command */ v = (reg << GEM_MIF_REG_SHIFT) | (phy << GEM_MIF_PHY_SHIFT) | GEM_MIF_FRAME_READ; @@ -1334,8 +1241,8 @@ gem_mii_statchg(dev) #ifdef GEM_DEBUG if (sc->sc_debug) - printf("gem_mii_statchg: status change: phy = %d\n", - sc->sc_phys[instance];); + printf("gem_mii_statchg: status change: phy = %d\n", + sc->sc_phys[instance]); #endif @@ -1414,39 +1321,35 @@ gem_ioctl(ifp, cmd, data) s = splimp(); - if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) { - splx(s); - return error; - } - switch (cmd) { + case SIOCSIFADDR: ifp->if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: gem_init(ifp); arp_ifinit(&sc->sc_arpcom, ifa); break; -#endif /* INET */ +#endif #ifdef NS - /* XXX - This code is probably wrong. */ case AF_NS: { struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; if (ns_nullhost(*ina)) - ina->x_host = - *(union ns_host *)(sc->sc_arpcom.ac_enaddr); - else - bcopy(ina->x_host.c_host, - sc->sc_arpcom.ac_enaddr, - sizeof(sc->sc_arpcom.ac_enaddr)); + ina->x_host = + *(union ns_host *)LLADDR(ifp->if_sadl); + else { + memcpy(LLADDR(ifp->if_sadl), + ina->x_host.c_host, sizeof(sc->sc_enaddr)); + } /* Set new address. */ gem_init(ifp); break; } -#endif /* NS */ +#endif default: gem_init(ifp); break; @@ -1463,34 +1366,37 @@ gem_ioctl(ifp, cmd, data) gem_stop(ifp, 1); ifp->if_flags &= ~IFF_RUNNING; } else if ((ifp->if_flags & IFF_UP) != 0 && - (ifp->if_flags & IFF_RUNNING) == 0) { + (ifp->if_flags & IFF_RUNNING) == 0) { /* * If interface is marked up and it is stopped, then * start it. */ gem_init(ifp); - } else { + } else if ((ifp->if_flags & IFF_UP) != 0) { /* * Reset the interface to pick up changes in any other * flags that affect hardware registers. */ - gem_stop(ifp, 0); + /*gem_stop(sc);*/ gem_init(ifp); } +#ifdef HMEDEBUG + sc->sc_debug = (ifp->if_flags & IFF_DEBUG) != 0 ? 1 : 0; +#endif break; case SIOCADDMULTI: case SIOCDELMULTI: error = (cmd == SIOCADDMULTI) ? - ether_addmulti(ifr, &sc->sc_arpcom): - ether_delmulti(ifr, &sc->sc_arpcom); + ether_addmulti(ifr, &sc->sc_arpcom) : + ether_delmulti(ifr, &sc->sc_arpcom); if (error == ENETRESET) { /* * Multicast list has changed; set the hardware filter * accordingly. */ - gem_init(ifp); + gem_setladrf(sc); error = 0; } break; @@ -1501,12 +1407,11 @@ gem_ioctl(ifp, cmd, data) break; default: + error = EINVAL; break; } - if (ifp->if_flags & IFF_UP) - gem_start(ifp); - + splx(s); return (error); } @@ -1568,7 +1473,7 @@ gem_setladrf(sc) ETHER_FIRST_MULTI(step, ac, enm); while (enm != NULL) { - if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { + if (ether_cmp(enm->enm_addrlo, enm->enm_addrhi)) { /* * We must listen to a range of multicast addresses. * For now, just accept all multicasts, rather than @@ -1632,46 +1537,145 @@ chipit: bus_space_write_4(t, h, GEM_MAC_RX_CONFIG, v); } -#if notyet +int +gem_encap(sc, mhead, bixp) + struct gem_softc *sc; + struct mbuf *mhead; + u_int32_t *bixp; +{ + u_int64_t flags; + u_int32_t cur, frag, i; + bus_dmamap_t map; + + cur = frag = *bixp; + + if (bus_dmamap_create(sc->sc_dmatag, MCLBYTES, GEM_NTXDESC, + MCLBYTES, 0, BUS_DMA_NOWAIT, &map) != 0) { + return (ENOBUFS); + } + + if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, mhead, + BUS_DMA_NOWAIT) != 0) { + bus_dmamap_destroy(sc->sc_dmatag, map); + return (ENOBUFS); + } + + if ((sc->sc_tx_cnt + map->dm_nsegs) > (GEM_NTXDESC - 2)) { + bus_dmamap_unload(sc->sc_dmatag, map); + bus_dmamap_destroy(sc->sc_dmatag, map); + return (ENOBUFS); + } + + bus_dmamap_sync(sc->sc_dmatag, map, 0, map->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + for (i = 0; i < map->dm_nsegs; i++) { + sc->sc_txdescs[frag].gd_addr = + GEM_DMA_WRITE(sc, map->dm_segs[i].ds_addr); + flags = (map->dm_segs[i].ds_len & GEM_TD_BUFSIZE) | + (i == 0 ? GEM_TD_START_OF_PACKET : 0) | + ((i == (map->dm_nsegs - 1)) ? GEM_TD_END_OF_PACKET : 0); + sc->sc_txdescs[frag].gd_flags = GEM_DMA_WRITE(sc, flags); + bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap, + GEM_CDTXOFF(frag), sizeof(struct gem_desc), + BUS_DMASYNC_PREWRITE); + cur = frag; + if (++frag == GEM_NTXDESC) + frag = 0; + } + + sc->sc_tx_cnt += map->dm_nsegs; + sc->sc_txd[cur].sd_map = map; + sc->sc_txd[cur].sd_mbuf = mhead; + + bus_space_write_4(sc->sc_bustag, sc->sc_h, GEM_TX_KICK, frag); + + *bixp = frag; + + /* sync descriptors */ + + return (0); +} /* - * gem_power: - * - * Power management (suspend/resume) hook. + * Transmit interrupt. */ -void -gem_power(why, arg) - int why; - void *arg; +int +gem_tint(sc, status) + struct gem_softc *sc; + u_int32_t status; { - struct gem_softc *sc = arg; struct ifnet *ifp = &sc->sc_arpcom.ac_if; - int s; + struct gem_sxd *sd; + u_int32_t cons, hwcons; - s = splnet(); - switch (why) { - case PWR_SUSPEND: - case PWR_STANDBY: - gem_stop(ifp, 1); - if (sc->sc_power != NULL) - (*sc->sc_power)(sc, why); - break; - case PWR_RESUME: - if (ifp->if_flags & IFF_UP) { - if (sc->sc_power != NULL) - (*sc->sc_power)(sc, why); - gem_init(ifp); + hwcons = status >> 19; + cons = sc->sc_tx_cons; + while (cons != hwcons) { + sd = &sc->sc_txd[cons]; + if (sd->sd_map != NULL) { + bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0, + sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmatag, sd->sd_map); + bus_dmamap_destroy(sc->sc_dmatag, sd->sd_map); + sd->sd_map = NULL; } - break; - case PWR_SOFTSUSPEND: - case PWR_SOFTSTANDBY: - case PWR_SOFTRESUME: - break; + if (sd->sd_mbuf != NULL) { + m_freem(sd->sd_mbuf); + sd->sd_mbuf = NULL; + } + sc->sc_tx_cnt--; + if (++cons == GEM_NTXDESC) + cons = 0; } - splx(s); + sc->sc_tx_cons = cons; + + gem_start(ifp); + + if (sc->sc_tx_cnt == 0) + ifp->if_timer = 0; + + return (1); } + +void +gem_start(ifp) + struct ifnet *ifp; +{ + struct gem_softc *sc = ifp->if_softc; + struct mbuf *m; + u_int32_t bix; + + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + + bix = sc->sc_tx_prod; + while (sc->sc_txd[bix].sd_mbuf == NULL) { + IFQ_POLL(&ifp->if_snd, m); + if (m == NULL) + break; + +#if NBPFILTER > 0 + /* + * If BPF is listening on this interface, let it see the + * packet before we commit it to the wire. + */ + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m); #endif -struct cfdriver gem_cd = { - NULL, "gem", DV_IFNET -}; + /* + * Encapsulate this packet and start it going... + * or fail... + */ + if (gem_encap(sc, m, &bix)) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + + IFQ_DEQUEUE(&ifp->if_snd, m); + ifp->if_timer = 5; + } + + sc->sc_tx_prod = bix; +} |