diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2002-02-22 20:15:29 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2002-02-22 20:15:29 +0000 |
commit | fba59d7e033da21befb25cc10849261322d0f017 (patch) | |
tree | f7e003877edf1ca99c6ea760f3d34f7ec106a60f | |
parent | 0080f5aa080e0cfacb5799e40e10c54235ac9ea1 (diff) |
Revert to previous (non hacked =) version now that the iommu is handled
correctly and it doesn't crash
-rw-r--r-- | sys/dev/ic/gem.c | 512 | ||||
-rw-r--r-- | sys/dev/ic/gemreg.h | 15 | ||||
-rw-r--r-- | sys/dev/ic/gemvar.h | 126 | ||||
-rw-r--r-- | sys/dev/pci/if_gem_pci.c | 19 |
4 files changed, 366 insertions, 306 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; +} diff --git a/sys/dev/ic/gemreg.h b/sys/dev/ic/gemreg.h index 00a8beee005..3d570677797 100644 --- a/sys/dev/ic/gemreg.h +++ b/sys/dev/ic/gemreg.h @@ -1,3 +1,4 @@ +/* $OpenBSD: gemreg.h,v 1.7 2002/02/22 20:15:28 jason Exp $ */ /* $NetBSD: gemreg.h,v 1.1 2001/09/16 00:11:43 eeh Exp $ */ /* @@ -81,11 +82,11 @@ #define GEM_INTR_MAC_CONTROL 0x000010000 /* MAC control interrupt */ #define GEM_INTR_MIF 0x000020000 #define GEM_INTR_BERR 0x000040000 /* Bus error interrupt */ -#define GEM_INTR_BITS "\177\020" \ - "b\0INTME\0b\1TXEMPTY\0b\2TXDONE\0" \ - "b\4RXDONE\0b\5RXNOBUF\0b\6RX_TAG_ERR\0" \ - "b\15PCS\0b\16TXMAC\0b\17RXMAC\0" \ - "b\20MAC_CONTROL\0b\21MIF\0b\22BERR\0\0" \ +#define GEM_INTR_BITS "\020" \ + "\1INTME\2TXEMPTY\3TXDONE" \ + "\5RXDONE\6RXNOBUF\7RX_TAG_ERR" \ + "\16PCS\17TXMAC\20RXMAC" \ + "\21MACCONTROL\22MIF\23BERR" @@ -531,11 +532,11 @@ struct gem_desc { #define GEM_RD_BUFSHIFT 16 #define GEM_RD_BUFLEN(x) (((x)&GEM_RD_BUFSIZE)>>GEM_RD_BUFSHIFT) -#ifndef EVL_ENCAPLEN +#ifndef EVL_ENCAPLEN /* defined if NVLAN > 0 */ #define EVL_ENCAPLEN 0 #endif #define GEM_MTU \ (ETHERMTU + EVL_ENCAPLEN + sizeof(u_int32_t) + sizeof(struct ether_header)) -#endif +#endif /* _IF_GEMREG_H */ diff --git a/sys/dev/ic/gemvar.h b/sys/dev/ic/gemvar.h index 76b10e65cb6..beba25108b5 100644 --- a/sys/dev/ic/gemvar.h +++ b/sys/dev/ic/gemvar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: gemvar.h,v 1.5 2002/01/28 01:04:02 jason Exp $ */ -/* $NetBSD: gemvar.h,v 1.4 2001/10/18 15:09:15 thorpej Exp $ */ +/* $OpenBSD: gemvar.h,v 1.6 2002/02/22 20:15:28 jason Exp $ */ +/* $NetBSD: gemvar.h,v 1.1 2001/09/16 00:11:43 eeh Exp $ */ /* * @@ -33,14 +33,9 @@ #ifndef _IF_GEMVAR_H #define _IF_GEMVAR_H - #include <sys/queue.h> #include <sys/timeout.h> -#if NRND > 0 -#include <sys/rnd.h> -#endif - /* * Misc. definitions for the Sun ``Gem'' Ethernet controller family driver. */ @@ -52,11 +47,16 @@ */ #define GEM_NTXSEGS 16 -#define GEM_TXQUEUELEN 8 +#define GEM_TXQUEUELEN 64 #define GEM_NTXDESC (GEM_TXQUEUELEN * GEM_NTXSEGS) #define GEM_NTXDESC_MASK (GEM_NTXDESC - 1) #define GEM_NEXTTX(x) ((x + 1) & GEM_NTXDESC_MASK) +struct gem_sxd { + struct mbuf *sd_mbuf; + bus_dmamap_t sd_map; +}; + /* * Receive descriptor list size. We have one Rx buffer per incoming * packet, so this logic is a little simpler. @@ -80,8 +80,6 @@ struct gem_control_data { * The receive descriptors. */ struct gem_desc gcd_rxdescs[GEM_NRXDESC]; - - u_int8_t gcd_txbufs[GEM_NTXDESC][MCLBYTES]; }; #define GEM_CDOFF(x) offsetof(struct gem_control_data, x) @@ -89,25 +87,32 @@ struct gem_control_data { #define GEM_CDRXOFF(x) GEM_CDOFF(gcd_rxdescs[(x)]) /* - * Software state for transmit jobs. + * Software state for receive jobs. */ -struct gem_txsoft { - struct mbuf *txs_mbuf; /* head of our mbuf chain */ - bus_dmamap_t txs_dmamap; /* our DMA map */ - int txs_firstdesc; /* first descriptor in packet */ - int txs_lastdesc; /* last descriptor in packet */ - int txs_ndescs; /* number of descriptors */ - SIMPLEQ_ENTRY(gem_txsoft) txs_q; +struct gem_rxsoft { + struct mbuf *rxs_mbuf; /* head of our mbuf chain */ + bus_dmamap_t rxs_dmamap; /* our DMA map */ }; -SIMPLEQ_HEAD(gem_txsq, gem_txsoft); /* - * Software state for receive jobs. + * Table which describes the transmit threshold mode. We generally + * start at index 0. Whenever we get a transmit underrun, we increment + * our index, falling back if we encounter the NULL terminator. */ -struct gem_rxsoft { - struct mbuf *rxs_mbuf; /* head of our mbuf chain */ - bus_dmamap_t rxs_dmamap; /* our DMA map */ +struct gem_txthresh_tab { + u_int32_t txth_opmode; /* OPMODE bits */ + const char *txth_name; /* name of mode */ +}; + +/* + * Some misc. statics, useful for debugging. + */ +struct gem_stats { + u_long ts_tx_uf; /* transmit underflow errors */ + u_long ts_tx_to; /* transmit jabber timeouts */ + u_long ts_tx_ec; /* excessve collision count */ + u_long ts_tx_lc; /* late collision count */ }; /* @@ -115,7 +120,7 @@ struct gem_rxsoft { */ struct gem_softc { struct device sc_dev; /* generic device information */ - struct arpcom sc_arpcom; /* ethernet common data */ + struct arpcom sc_arpcom; /* ethernet common data */ struct mii_data sc_mii; /* MII media control */ #define sc_media sc_mii.mii_media/* shorthand */ struct timeout sc_tick_ch; /* tick callout */ @@ -125,7 +130,15 @@ struct gem_softc { bus_dma_tag_t sc_dmatag; /* bus dma tag */ bus_dmamap_t sc_dmamap; /* bus dma handle */ bus_space_handle_t sc_h; /* bus space handle for all regs */ - +#if 0 + /* The following may be needed for SBus */ + bus_space_handle_t sc_seb; /* HME Global registers */ + bus_space_handle_t sc_erx; /* HME ERX registers */ + bus_space_handle_t sc_etx; /* HME ETX registers */ + bus_space_handle_t sc_mac; /* HME MAC registers */ + bus_space_handle_t sc_mif; /* HME MIF registers */ +#endif + int sc_burst; /* DVMA burst size in effect */ int sc_phys[2]; /* MII instance -> PHY map */ int sc_mif_config; /* Selected MII reg setting */ @@ -135,6 +148,8 @@ struct gem_softc { void *sc_sdhook; /* shutdown hook */ void *sc_powerhook; /* power management hook */ + struct gem_stats sc_stats; /* debugging stats */ + /* * Ring buffer DMA stuff. */ @@ -146,10 +161,10 @@ struct gem_softc { /* * Software state for transmit and receive descriptors. */ - struct gem_txsoft sc_txsoft[GEM_TXQUEUELEN]; - struct gem_rxsoft sc_rxsoft[GEM_NRXDESC]; + struct gem_sxd sc_txd[GEM_NTXDESC]; + u_int32_t sc_tx_cnt, sc_tx_prod, sc_tx_cons; - u_int32_t sc_tx_prod, sc_tx_cons, sc_tx_cnt; + struct gem_rxsoft sc_rxsoft[GEM_NRXDESC]; /* * Control data structures. @@ -158,26 +173,45 @@ struct gem_softc { #define sc_txdescs sc_control_data->gcd_txdescs #define sc_rxdescs sc_control_data->gcd_rxdescs - int sc_rxptr; /* next ready RX descriptor/descsoft */ + int sc_txfree; /* number of free Tx descriptors */ + int sc_txnext; /* next ready Tx descriptor */ + + u_int32_t sc_tdctl_ch; /* conditional desc chaining */ + u_int32_t sc_tdctl_er; /* conditional desc end-of-ring */ + + u_int32_t sc_setup_fsls; /* FS|LS on setup descriptor */ + + int sc_rxptr; /* next ready RX descriptor/descsoft */ /* ========== */ - int sc_inited; - int sc_debug; - void *sc_sh; /* shutdownhook cookie */ + int sc_inited; + int sc_debug; + void *sc_sh; /* shutdownhook cookie */ + u_int8_t sc_enaddr[ETHER_ADDR_LEN]; /* MAC address */ /* Special hardware hooks */ void (*sc_hwreset) __P((struct gem_softc *)); void (*sc_hwinit) __P((struct gem_softc *)); - -#if NRND > 0 - rndsource_element_t rnd_source; -#endif }; - #define GEM_DMA_READ(sc, v) (((sc)->sc_pci) ? letoh64(v) : betoh64(v)) #define GEM_DMA_WRITE(sc, v) (((sc)->sc_pci) ? htole64(v) : htobe64(v)) +/* + * This macro returns the current media entry for *non-MII* media. + */ +#define GEM_CURRENT_MEDIA(sc) \ + (IFM_SUBTYPE((sc)->sc_mii.mii_media.ifm_cur->ifm_media) != IFM_AUTO ? \ + (sc)->sc_mii.mii_media.ifm_cur : (sc)->sc_nway_active) + +/* + * This macro determines if a change to media-related OPMODE bits requires + * a chip reset. + */ +#define GEM_MEDIA_NEEDSRESET(sc, newbits) \ + (((sc)->sc_opmode & OPMODE_MEDIA_BITS) != \ + ((newbits) & OPMODE_MEDIA_BITS)) + #define GEM_CDTXADDR(sc, x) ((sc)->sc_cddma + GEM_CDTXOFF((x))) #define GEM_CDRXADDR(sc, x) ((sc)->sc_cddma + GEM_CDRXOFF((x))) @@ -223,16 +257,28 @@ do { \ GEM_DMA_WRITE((sc), __rxs->rxs_dmamap->dm_segs[0].ds_addr); \ __rxd->gd_flags = \ GEM_DMA_WRITE((sc), \ - (((__m->m_ext.ext_size)<<GEM_RD_BUFSHIFT) \ - & GEM_RD_BUFSIZE) | GEM_RD_OWN); \ + (((__m->m_ext.ext_size)<<GEM_RD_BUFSHIFT) \ + & GEM_RD_BUFSIZE) | GEM_RD_OWN); \ GEM_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \ } while (0) #ifdef _KERNEL -void gem_attach __P((struct gem_softc *, uint8_t *)); +void gem_attach __P((struct gem_softc *, const u_int8_t *)); +int gem_activate __P((struct device *, enum devact)); +int gem_detach __P((struct gem_softc *)); int gem_intr __P((void *)); +int gem_read_srom __P((struct gem_softc *)); +int gem_srom_crcok __P((const u_int8_t *)); +int gem_isv_srom __P((const u_int8_t *)); +int gem_isv_srom_enaddr __P((struct gem_softc *, u_int8_t *)); +int gem_parse_old_srom __P((struct gem_softc *, u_int8_t *)); +int gem_mediachange __P((struct ifnet *)); +void gem_mediastatus __P((struct ifnet *, struct ifmediareq *)); + +void gem_config __P((struct gem_softc *)); void gem_reset __P((struct gem_softc *)); +int gem_intr __P((void *)); #endif /* _KERNEL */ diff --git a/sys/dev/pci/if_gem_pci.c b/sys/dev/pci/if_gem_pci.c index 14c238e7131..135576f4c1a 100644 --- a/sys/dev/pci/if_gem_pci.c +++ b/sys/dev/pci/if_gem_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_gem_pci.c,v 1.6 2002/01/28 01:04:02 jason Exp $ */ +/* $OpenBSD: if_gem_pci.c,v 1.7 2002/02/22 20:15:28 jason Exp $ */ /* $NetBSD: if_gem_pci.c,v 1.1 2001/09/16 00:11:42 eeh Exp $ */ /* @@ -127,7 +127,6 @@ gem_attach_pci(parent, self, aux) #endif const char *intrstr; int type; - char enaddr[ETHER_ADDR_LEN]; if (pa->pa_memt) { type = PCI_MAPREG_TYPE_MEM; @@ -152,18 +151,28 @@ gem_attach_pci(parent, self, aux) sc->sc_bustag = gsc->gsc_memt; sc->sc_h = gsc->gsc_memh; +#if 0 +/* SBUS compatible stuff? */ + sc->sc_seb = gsc->gsc_memh; + sc->sc_etx = gsc->gsc_memh + 0x2000; + sc->sc_erx = gsc->gsc_memh + 0x4000; + sc->sc_mac = gsc->gsc_memh + 0x6000; + sc->sc_mif = gsc->gsc_memh + 0x7000; +#endif #ifdef __sparc__ - myetheraddr(enaddr); + myetheraddr(sc->sc_enaddr); #endif #ifdef __powerpc__ - pci_ether_hw_addr(pa->pa_pc, enaddr); + pci_ether_hw_addr(pa->pa_pc, sc->sc_enaddr); #endif + sc->sc_burst = 16; /* XXX */ + printf("\n"); /* * call the main configure */ - gem_attach(sc, enaddr); + gem_config(sc); if (pci_intr_map(pa, &intrhandle) != 0) { printf("%s: couldn't map interrupt\n", |