diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2010-09-04 12:47:01 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2010-09-04 12:47:01 +0000 |
commit | 5882b5104fd69b5de0d8442a9caf28aa6644954d (patch) | |
tree | 1b68c215c7e7724e794b693d7cdb41fc4afb17f6 /sys/dev | |
parent | 5f86ebb1d8d1e131e074a173957575950b506808 (diff) |
Let se(4) support SiS191, and bring a lot of bugfixes and improvements from
FreeBSD.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_se.c | 1832 | ||||
-rw-r--r-- | sys/dev/pci/if_sereg.h | 442 |
2 files changed, 1131 insertions, 1143 deletions
diff --git a/sys/dev/pci/if_se.c b/sys/dev/pci/if_se.c index 45be6a4997e..ca405513ddd 100644 --- a/sys/dev/pci/if_se.c +++ b/sys/dev/pci/if_se.c @@ -1,7 +1,8 @@ -/* $OpenBSD: if_se.c,v 1.3 2010/08/27 17:08:00 jsg Exp $ */ +/* $OpenBSD: if_se.c,v 1.4 2010/09/04 12:47:00 miod Exp $ */ /*- * Copyright (c) 2009, 2010 Christopher Zimmermann <madroach@zakweb.de> + * Copyright (c) 2008, 2009, 2010 Nikolay Denev <ndenev@gmail.com> * Copyright (c) 2007, 2008 Alexander Pohoyda <alexander.pohoyda@gmx.net> * Copyright (c) 1997, 1998, 1999 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. @@ -35,10 +36,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - /* - * SiS 190 Fast Ethernet PCI NIC driver. + * SiS 190/191 PCI Ethernet NIC driver. * * Adapted to SiS 190 NIC by Alexander Pohoyda based on the original * SiS 900 driver by Bill Paul, using SiS 190/191 Solaris driver by @@ -48,310 +47,430 @@ * * Ported to OpenBSD by Christopher Zimmermann 2009/10 * - * It should be easy to adapt this driver to SiS 191 Gigabit Ethernet - * PCI NIC. + * Adapted to SiS 191 NIC by Nikolay Denev with further ideas from the + * Linux and Solaris drivers. */ +#include "bpfilter.h" + #include <sys/param.h> #include <sys/systm.h> -#include <sys/sockio.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> #include <sys/mbuf.h> #include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/timeout.h> #include <net/if.h> #include <net/if_dl.h> #include <net/if_media.h> +#include <net/if_types.h> #include <netinet/in.h> #include <netinet/if_ether.h> +#if NBPFILTER > 0 #include <net/bpf.h> +#endif +#include <dev/mii/mii.h> #include <dev/mii/miivar.h> -#include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/pci/if_sereg.h> + +#define SE_RX_RING_CNT 256 /* [8, 1024] */ +#define SE_TX_RING_CNT 256 /* [8, 8192] */ +#define SE_RX_BUF_ALIGN sizeof(uint64_t) + +#define SE_RX_RING_SZ (SE_RX_RING_CNT * sizeof(struct se_desc)) +#define SE_TX_RING_SZ (SE_TX_RING_CNT * sizeof(struct se_desc)) + +struct se_list_data { + struct se_desc *se_rx_ring; + struct se_desc *se_tx_ring; + bus_dmamap_t se_rx_dmamap; + bus_dmamap_t se_tx_dmamap; +}; + +struct se_chain_data { + struct mbuf *se_rx_mbuf[SE_RX_RING_CNT]; + struct mbuf *se_tx_mbuf[SE_TX_RING_CNT]; + bus_dmamap_t se_rx_map[SE_RX_RING_CNT]; + bus_dmamap_t se_tx_map[SE_TX_RING_CNT]; + uint se_rx_prod; + uint se_tx_prod; + uint se_tx_cons; + uint se_tx_cnt; +}; + +struct se_softc { + struct device sc_dev; + void *sc_ih; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; + + struct mii_data sc_mii; + struct arpcom sc_ac; -#include "if_sereg.h" + struct se_list_data se_ldata; + struct se_chain_data se_cdata; + + struct timeout sc_tick_tmo; + + int sc_flags; +#define SE_FLAG_FASTETHER 0x0001 +#define SE_FLAG_RGMII 0x0010 +#define SE_FLAG_LINK 0x8000 +}; /* * Various supported device vendors/types and their names. */ const struct pci_matchid se_devices[] = { { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_190 }, - /* Gigabit variant not supported yet. */ - /*{ PCI_VENDOR_SIS, PCI_PRODUCT_SIS_191 }*/ + { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_191 } }; -int se_probe(struct device *, void *, void *); -void se_attach(struct device *, struct device *, void *); +int se_match(struct device *, void *, void *); +void se_attach(struct device *, struct device *, void *); +int se_activate(struct device *, int); -struct cfattach se_ca = { - sizeof(struct se_softc), se_probe, se_attach +const struct cfattach se_ca = { + sizeof(struct se_softc), + se_match, se_attach, NULL, se_activate }; struct cfdriver se_cd = { 0, "se", DV_IFNET }; -int se_get_mac_addr_cmos (struct se_softc *, caddr_t); -int se_get_mac_addr_eeprom (struct se_softc *, caddr_t); -int se_isabridge_match (struct pci_attach_args *); -uint16_t se_read_eeprom (struct se_softc *, int); -void miibus_cmd (struct se_softc *, u_int32_t); -int se_miibus_readreg (struct device *, int, int); -void se_miibus_writereg (struct device *, int, int, int); -void se_miibus_statchg (struct device *); - -int se_ifmedia_upd (struct ifnet *); -void se_ifmedia_sts (struct ifnet *, struct ifmediareq *); - -int se_ioctl (struct ifnet *, u_long, caddr_t); - -void se_setmulti (struct se_softc *); -uint32_t se_mchash (struct se_softc *, const uint8_t *); - -int se_newbuf (struct se_softc *, u_int32_t, - struct mbuf *); -int se_encap (struct se_softc *, - struct mbuf *, u_int32_t *); -int se_init (struct ifnet *); -int se_list_rx_init (struct se_softc *); -int se_list_rx_free (struct se_softc *); -int se_list_tx_init (struct se_softc *); -int se_list_tx_free (struct se_softc *); +uint32_t + se_miibus_cmd(struct se_softc *, uint32_t); +int se_miibus_readreg(struct device *, int, int); +void se_miibus_writereg(struct device *, int, int, int); +void se_miibus_statchg(struct device *); + +int se_newbuf(struct se_softc *, uint); +void se_discard_rxbuf(struct se_softc *, uint); +int se_encap(struct se_softc *, struct mbuf *, uint *); +void se_rxeof(struct se_softc *); +void se_txeof(struct se_softc *); +int se_intr(void *); +void se_tick(void *); +void se_start(struct ifnet *); +int se_ioctl(struct ifnet *, u_long, caddr_t); +int se_init(struct ifnet *); +void se_stop(struct se_softc *); +void se_watchdog(struct ifnet *); +int se_ifmedia_upd(struct ifnet *); +void se_ifmedia_sts(struct ifnet *, struct ifmediareq *); + +int se_pcib_match(struct pci_attach_args *); +int se_get_mac_addr_apc(struct se_softc *, uint8_t *); +int se_get_mac_addr_eeprom(struct se_softc *, uint8_t *); +uint16_t + se_read_eeprom(struct se_softc *, int); -int se_intr (void *); -void se_rxeof (struct se_softc *); -void se_txeof (struct se_softc *); +void se_iff(struct se_softc *); +void se_reset(struct se_softc *); +int se_list_rx_init(struct se_softc *); +int se_list_rx_free(struct se_softc *); +int se_list_tx_init(struct se_softc *); +int se_list_tx_free(struct se_softc *); -void se_tick (void *); -void se_watchdog (struct ifnet *); +/* + * Register space access macros. + */ -void se_start (struct ifnet *); -void se_reset (struct se_softc *); -void se_stop (struct se_softc *); -void se_shutdown (void *); +#define CSR_WRITE_4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, reg, val) +#define CSR_WRITE_2(sc, reg, val) \ + bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, reg, val) +#define CSR_WRITE_1(sc, reg, val) \ + bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, reg, val) +#define CSR_READ_4(sc, reg) \ + bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, reg) +#define CSR_READ_2(sc, reg) \ + bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, reg) +#define CSR_READ_1(sc, reg) \ + bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, reg) /* * Read a sequence of words from the EEPROM. */ uint16_t -se_read_eeprom(sc, offset) - struct se_softc *sc; - int offset; +se_read_eeprom(struct se_softc *sc, int offset) { - uint32_t ret, val, i; - int s; + uint32_t val; + int i; KASSERT(offset <= EI_OFFSET); - s = splnet(); - - val = EI_REQ | EI_OP_RD | (offset << EI_OFFSET_SHIFT); - CSR_WRITE_4(sc, ROMInterface, val); + CSR_WRITE_4(sc, ROMInterface, + EI_REQ | EI_OP_RD | (offset << EI_OFFSET_SHIFT)); DELAY(500); - - for (i = 0; ((ret = CSR_READ_4(sc, ROMInterface)) & EI_REQ) != 0; i++) { - if (i > 1000) { - /* timeout */ - printf("EEPROM read timeout %d\n", i); - splx(s); - return (0xffff); - } - DELAY(100); + for (i = 0; i < SE_TIMEOUT; i++) { + val = CSR_READ_4(sc, ROMInterface); + if ((val & EI_REQ) == 0) + break; + DELAY(100); + } + if (i == SE_TIMEOUT) { + printf("%s: EEPROM read timeout: 0x%08x\n", + sc->sc_dev.dv_xname, val); + return 0xffff; } - splx(s); - return ((ret & EI_DATA) >> EI_DATA_SHIFT); -} - -int -se_isabridge_match(struct pci_attach_args *pa) -{ - const struct pci_matchid device_ids[] = { - { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_965}, - { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_966}, - { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_968}, - }; - - return (pci_matchbyid(pa, device_ids, - sizeof(device_ids)/sizeof(device_ids[0]))); + return (val & EI_DATA) >> EI_DATA_SHIFT; } int -se_get_mac_addr_cmos(sc, dest) - struct se_softc *sc; - caddr_t dest; +se_get_mac_addr_eeprom(struct se_softc *sc, uint8_t *dest) { - struct pci_attach_args isa_bridge; - u_int32_t reg, tmp; - int i, s; + uint16_t val; + int i; - if (!pci_find_device(&isa_bridge, se_isabridge_match)) { - printf("Could not find ISA bridge to retrieve MAC address.\n"); - return -1; + val = se_read_eeprom(sc, EEPROMSignature); + if (val == 0xffff || val == 0x0000) { + printf("%s: invalid EEPROM signature : 0x%04x\n", + sc->sc_dev.dv_xname, val); + return (EINVAL); } - s = splnet(); - - /* Enable port 78h & 79h to access APC Registers. - * Taken from linux driver. */ - tmp = pci_conf_read(isa_bridge.pa_pc, isa_bridge.pa_tag, 0x48); - reg = tmp & ~0x02; - pci_conf_write(isa_bridge.pa_pc, isa_bridge.pa_tag, 0x48, reg); - delay(50); - reg = pci_conf_read(isa_bridge.pa_pc, isa_bridge.pa_tag, 0x48); - - for (i = 0; i < ETHER_ADDR_LEN; i++) { - bus_space_write_1(isa_bridge.pa_iot, 0x0, 0x78, 0x9 + i); - *(dest + i) = bus_space_read_1(isa_bridge.pa_iot, 0x0, 0x79); + for (i = 0; i < ETHER_ADDR_LEN; i += 2) { + val = se_read_eeprom(sc, EEPROMMACAddr + i / 2); + dest[i + 0] = (uint8_t)val; + dest[i + 1] = (uint8_t)(val >> 8); } - bus_space_write_1(isa_bridge.pa_iot, 0x0, 0x78, 0x12); - reg = bus_space_read_1(isa_bridge.pa_iot, 0x0, 0x79); + if ((se_read_eeprom(sc, EEPROMInfo) & 0x80) != 0) + sc->sc_flags |= SE_FLAG_RGMII; + return (0); +} - pci_conf_write(isa_bridge.pa_pc, isa_bridge.pa_tag, 0x48, tmp); +/* + * For SiS96x, APC CMOS RAM is used to store Ethernet address. + * APC CMOS RAM is accessed through ISA bridge. + */ +#if defined(__amd64__) || defined(__i386__) +int +se_pcib_match(struct pci_attach_args *pa) +{ + const struct pci_matchid apc_devices[] = { + { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_965 }, + { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_966 }, + { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_968 } + }; - /* XXX: pci_dev_put(isa_bridge) ? */ - splx(s); - return 0; + return pci_matchbyid(pa, apc_devices, nitems(apc_devices)); } +#endif int -se_get_mac_addr_eeprom(sc, dest) - struct se_softc *sc; - caddr_t dest; +se_get_mac_addr_apc(struct se_softc *sc, uint8_t *dest) { - uint16_t val, i; +#if defined(__amd64__) || defined(__i386__) + struct pci_attach_args pa; + pcireg_t reg; + bus_space_handle_t ioh; + int rc, i; + + if (pci_find_device(&pa, se_pcib_match) == 0) { + printf("\n%s: couldn't find PCI-ISA bridge\n", + sc->sc_dev.dv_xname); + return EINVAL; + } - val = se_read_eeprom(sc, EEPROMSignature); - if (val == 0xffff || val == 0x0000) - return (1); + /* Enable port 0x78 and 0x79 to access APC registers. */ + reg = pci_conf_read(pa.pa_pc, pa.pa_tag, 0x48); + pci_conf_write(pa.pa_pc, pa.pa_tag, 0x48, reg & ~0x02); + DELAY(50); + (void)pci_conf_read(pa.pa_pc, pa.pa_tag, 0x48); + + /* XXX this abuses bus_space implementation knowledge */ + rc = _bus_space_map(pa.pa_iot, 0x78, 2, 0, &ioh); + if (rc == 0) { + /* Read stored Ethernet address. */ + for (i = 0; i < ETHER_ADDR_LEN; i++) { + bus_space_write_1(pa.pa_iot, ioh, 0, 0x09 + i); + dest[i] = bus_space_read_1(pa.pa_iot, ioh, 1); + } + bus_space_write_1(pa.pa_iot, ioh, 0, 0x12); + if ((bus_space_read_1(pa.pa_iot, ioh, 1) & 0x80) != 0) + sc->sc_flags |= SE_FLAG_RGMII; + _bus_space_unmap(pa.pa_iot, ioh, 2, NULL); + } else + rc = EINVAL; - for (i = 0; i < ETHER_ADDR_LEN; i += 2) { - val = se_read_eeprom(sc, EEPROMMACAddr + i/2); - dest[i + 0] = (uint8_t) val; - dest[i + 1] = (uint8_t) (val >> 8); - } + /* Restore access to APC registers. */ + pci_conf_write(pa.pa_pc, pa.pa_tag, 0x48, reg); - return (0); + return rc; +#endif + return EINVAL; } -void -miibus_cmd(sc, ctl) - struct se_softc *sc; - u_int32_t ctl; +uint32_t +se_miibus_cmd(struct se_softc *sc, uint32_t ctrl) { - uint32_t i; - int s; + int i; + uint32_t val; - s = splnet(); - CSR_WRITE_4(sc, GMIIControl, ctl); + CSR_WRITE_4(sc, GMIIControl, ctrl); DELAY(10); - - for (i = 0; (CSR_READ_4(sc, GMIIControl) & GMI_REQ) != 0; i++) - { - if (i > 1000) { - /* timeout */ - printf("MIIBUS timeout\n"); - splx(s); - return; - } - DELAY(100); + for (i = 0; i < SE_TIMEOUT; i++) { + val = CSR_READ_4(sc, GMIIControl); + if ((val & GMI_REQ) == 0) + return val; + DELAY(10); } - splx(s); - return; + + return GMI_REQ; } int -se_miibus_readreg(self, phy, reg) - struct device *self; - int phy, reg; +se_miibus_readreg(struct device *self, int phy, int reg) { - struct se_softc *sc = (struct se_softc *)self; - miibus_cmd(sc, (phy << GMI_PHY_SHIFT) | - (reg << GMI_REG_SHIFT) | GMI_OP_RD | GMI_REQ); - return ((CSR_READ_4(sc, GMIIControl) & GMI_DATA) >> GMI_DATA_SHIFT); + struct se_softc *sc = (struct se_softc *)self; + uint32_t ctrl, val; + + ctrl = (phy << GMI_PHY_SHIFT) | (reg << GMI_REG_SHIFT) | + GMI_OP_RD | GMI_REQ; + val = se_miibus_cmd(sc, ctrl); + if ((val & GMI_REQ) != 0) { + printf("%s: PHY read timeout : %d\n", + sc->sc_dev.dv_xname, reg); + return 0; + } + return (val & GMI_DATA) >> GMI_DATA_SHIFT; } void -se_miibus_writereg(self, phy, reg, data) - struct device *self; - int phy, reg, data; +se_miibus_writereg(struct device *self, int phy, int reg, int data) { - struct se_softc *sc = (struct se_softc *)self; - miibus_cmd(sc, (((uint32_t) data) << GMI_DATA_SHIFT) | - (((uint32_t) phy) << GMI_PHY_SHIFT) | - (reg << GMI_REG_SHIFT) | GMI_OP_WR | GMI_REQ); + struct se_softc *sc = (struct se_softc *)self; + uint32_t ctrl, val; + + ctrl = (phy << GMI_PHY_SHIFT) | (reg << GMI_REG_SHIFT) | + GMI_OP_WR | (data << GMI_DATA_SHIFT) | GMI_REQ; + val = se_miibus_cmd(sc, ctrl); + if ((val & GMI_REQ) != 0) { + printf("%s: PHY write timeout : %d\n", + sc->sc_dev.dv_xname, reg); + } } void -se_miibus_statchg(self) - struct device *self; +se_miibus_statchg(struct device *self) { - struct se_softc *sc = (struct se_softc *)self; - - se_init(sc->se_ifp); -} - -u_int32_t -se_mchash(sc, addr) - struct se_softc *sc; - const uint8_t *addr; -{ - return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26); + struct se_softc *sc = (struct se_softc *)self; +#ifdef SE_DEBUG + struct ifnet *ifp = &sc->sc_ac.ac_if; +#endif + struct mii_data *mii = &sc->sc_mii; + uint32_t ctl, speed; + + speed = 0; + sc->sc_flags &= ~SE_FLAG_LINK; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: 10baseT link\n", ifp->if_xname); +#endif + sc->sc_flags |= SE_FLAG_LINK; + speed = SC_SPEED_10; + break; + case IFM_100_TX: +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: 100baseTX link\n", ifp->if_xname); +#endif + sc->sc_flags |= SE_FLAG_LINK; + speed = SC_SPEED_100; + break; + case IFM_1000_T: +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: 1000baseT link\n", ifp->if_xname); +#endif + if ((sc->sc_flags & SE_FLAG_FASTETHER) == 0) { + sc->sc_flags |= SE_FLAG_LINK; + speed = SC_SPEED_1000; + } + break; + default: + break; + } + } + if ((sc->sc_flags & SE_FLAG_LINK) == 0) { +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: no link\n", ifp->if_xname); +#endif + return; + } + /* Reprogram MAC to resolved speed/duplex/flow-control paramters. */ + ctl = CSR_READ_4(sc, StationControl); + ctl &= ~(0x0f000000 | SC_FDX | SC_SPEED_MASK); + if (speed == SC_SPEED_1000) + ctl |= 0x07000000; + else + ctl |= 0x04000000; +#ifdef notyet + if ((sc->sc_flags & SE_FLAG_GMII) != 0) + ctl |= 0x03000000; +#endif + ctl |= speed; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + ctl |= SC_FDX; + CSR_WRITE_4(sc, StationControl, ctl); + if ((sc->sc_flags & SE_FLAG_RGMII) != 0) { + CSR_WRITE_4(sc, RGMIIDelay, 0x0441); + CSR_WRITE_4(sc, RGMIIDelay, 0x0440); + } } void -se_setmulti(sc) - struct se_softc *sc; +se_iff(struct se_softc *sc) { - struct ifnet *ifp = sc->se_ifp; - struct arpcom *ac = &sc->arpcom; - struct ether_multi *enm; - struct ether_multistep step; - uint32_t hashes[2] = { 0, 0 }, rxfilt; - //struct ifmultiaddr *ifma; - - rxfilt = AcceptMyPhys | 0x0052; - - if (ifp->if_flags & IFF_PROMISC) { - rxfilt |= AcceptAllPhys; + struct arpcom *ac = &sc->sc_ac; + struct ifnet *ifp = &ac->ac_if; + struct ether_multi *enm; + struct ether_multistep step; + uint32_t crc, hashes[2]; + uint16_t rxfilt; + + rxfilt = CSR_READ_2(sc, RxMacControl); + rxfilt &= ~(AcceptBroadcast | AcceptAllPhys | AcceptMulticast); + rxfilt |= AcceptMyPhys; + if ((ifp->if_flags & IFF_BROADCAST) != 0) + rxfilt |= AcceptBroadcast; + if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { + if ((ifp->if_flags & IFF_PROMISC) != 0) + rxfilt |= AcceptAllPhys; + rxfilt |= AcceptMulticast; + hashes[0] = hashes[1] = 0xffffffff; } else { - rxfilt &= ~AcceptAllPhys; - } - - if (ifp->if_flags & IFF_BROADCAST) { - rxfilt |= AcceptBroadcast; - } else { - rxfilt &= ~AcceptBroadcast; - } - - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { -allmulti: - rxfilt |= AcceptMulticast; - CSR_WRITE_2(sc, RxMacControl, rxfilt); - CSR_WRITE_4(sc, RxHashTable, 0xFFFFFFFF); - CSR_WRITE_4(sc, RxHashTable2, 0xFFFFFFFF); - return; - } - - /* now program new ones */ - //TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - ETHER_FIRST_MULTI(step, ac, enm); - while (enm != NULL) { - if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { - ifp->if_flags |= IFF_ALLMULTI; - goto allmulti; - } - - int bit_nr = se_mchash(sc, LLADDR((struct sockaddr_dl *) - enm->enm_addrlo)); - hashes[bit_nr >> 5] |= 1 << (bit_nr & 31); - rxfilt |= AcceptMulticast; - ETHER_NEXT_MULTI(step, enm); + rxfilt |= AcceptMulticast; + /* Now program new ones. */ + ETHER_FIRST_MULTI(step, ac, enm); + hashes[0] = hashes[1] = 0; + while (enm != NULL) { + crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); + hashes[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); + ETHER_NEXT_MULTI(step, enm); + } } CSR_WRITE_2(sc, RxMacControl, rxfilt); @@ -360,22 +479,24 @@ allmulti: } void -se_reset(sc) - struct se_softc *sc; +se_reset(struct se_softc *sc) { CSR_WRITE_4(sc, IntrMask, 0); CSR_WRITE_4(sc, IntrStatus, 0xffffffff); - CSR_WRITE_4(sc, TxControl, 0x00001a00); - CSR_WRITE_4(sc, RxControl, 0x00001a1d); - + /* Soft reset. */ CSR_WRITE_4(sc, IntrControl, 0x8000); - SE_PCI_COMMIT(); + CSR_READ_4(sc, IntrControl); DELAY(100); - CSR_WRITE_4(sc, IntrControl, 0x0); + CSR_WRITE_4(sc, IntrControl, 0); + /* Stop MAC. */ + CSR_WRITE_4(sc, TX_CTL, 0x1a00); + CSR_WRITE_4(sc, RX_CTL, 0x1a00); CSR_WRITE_4(sc, IntrMask, 0); CSR_WRITE_4(sc, IntrStatus, 0xffffffff); + + CSR_WRITE_4(sc, GMIIControl, 0); } /* @@ -383,251 +504,187 @@ se_reset(sc) * IDs against our list and return a device name if we find a match. */ int -se_probe(parent, match, aux) - struct device *parent; - void *match; - void *aux; +se_match(struct device *parent, void *match, void *aux) { - return (pci_matchbyid((struct pci_attach_args *)aux, se_devices, - sizeof(se_devices)/sizeof(se_devices[0]))); + struct pci_attach_args *pa = (struct pci_attach_args *)aux; + + return pci_matchbyid(pa, se_devices, nitems(se_devices)); } /* - * Attach the interface. Allocate softc structures, do ifmedia - * setup and ethernet/BPF attach. + * Attach the interface. Do ifmedia setup and ethernet/BPF attach. */ void -se_attach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; +se_attach(struct device *parent, struct device *self, void *aux) { - const char *intrstr = NULL; - struct se_softc *sc = (struct se_softc *)self; - struct pci_attach_args *pa = aux; - pci_chipset_tag_t pc = pa->pa_pc; - pci_intr_handle_t ih; - bus_size_t size; - struct ifnet *ifp; - bus_dma_segment_t seg; - int nseg; - struct se_list_data *ld; + struct se_softc *sc = (struct se_softc *)self; + struct arpcom *ac = &sc->sc_ac; + struct ifnet *ifp = &ac->ac_if; + struct pci_attach_args *pa = (struct pci_attach_args *)aux; + uint8_t eaddr[ETHER_ADDR_LEN]; + const char *intrstr; + pci_intr_handle_t ih; + bus_size_t iosize; + bus_dma_segment_t seg; + struct se_list_data *ld; struct se_chain_data *cd; - int i, error = 0; - - ld = &sc->se_ldata; - cd = &sc->se_cdata; + int nseg; + uint i; + int rc; - /* TODO: What about power management ? */ - - /* - * Handle power management nonsense. - */ -#if 0 -/* power management registers */ -#define SIS_PCI_CAPID 0x50 /* 8 bits */ -#define SIS_PCI_NEXTPTR 0x51 /* 8 bits */ -#define SIS_PCI_PWRMGMTCAP 0x52 /* 16 bits */ -#define SIS_PCI_PWRMGMTCTRL 0x54 /* 16 bits */ - -#define SIS_PSTATE_MASK 0x0003 -#define SIS_PSTATE_D0 0x0000 -#define SIS_PSTATE_D1 0x0001 -#define SIS_PSTATE_D2 0x0002 -#define SIS_PSTATE_D3 0x0003 -#define SIS_PME_EN 0x0010 -#define SIS_PME_STATUS 0x8000 -#define SIS_PCI_INTLINE 0x3C -#define SIS_PCI_LOMEM 0x14 - command = pci_conf_read(pc, pa->pa_tag, SIS_PCI_CAPID) & 0x000000FF; - if (command == 0x01) { - - command = pci_conf_read(pc, pa->pa_tag, SIS_PCI_PWRMGMTCTRL); - if (command & SIS_PSTATE_MASK) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_conf_read(pc, pa->pa_tag, SIS_PCI_LOIO); - membase = pci_conf_read(pc, pa->pa_tag, SIS_PCI_LOMEM); - irq = pci_conf_read(pc, pa->pa_tag, SIS_PCI_INTLINE); - - /* Reset the power state. */ - printf("%s: chip is in D%d power mode -- setting to D0\n", - sc->sc_dev.dv_xname, command & SIS_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_conf_write(pc, pa->pa_tag, SIS_PCI_PWRMGMTCTRL, command); - - /* Restore PCI config data. */ - pci_conf_write(pc, pa->pa_tag, SIS_PCI_LOIO, iobase); - pci_conf_write(pc, pa->pa_tag, SIS_PCI_LOMEM, membase); - pci_conf_write(pc, pa->pa_tag, SIS_PCI_INTLINE, irq); - } - } -#endif + printf(": "); /* * Map control/status registers. */ - /* Map IO */ - if ((error = pci_mapreg_map( - pa, - SE_PCI_LOMEM, - PCI_MAPREG_TYPE_MEM, 0, - &sc->se_btag, - &sc->se_bhandle, - NULL, - &size, - 0))) - { - printf(": can't map i/o space (code %d)\n", error); - return; - } - - /* Allocate interrupt */ + rc = pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0, + &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0); + if (rc != 0) { + printf("can't map i/o space\n"); + return; + } + if (pci_intr_map(pa, &ih)) { - printf(": couldn't map interrupt\n"); - goto intfail; + printf("can't map interrupt\n"); + goto fail1; } - intrstr = pci_intr_string(pc, ih); - sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, se_intr, sc, + intrstr = pci_intr_string(pa->pa_pc, ih); + sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, se_intr, sc, self->dv_xname); if (sc->sc_ih == NULL) { - printf(": couldn't establish interrupt"); - if (intrstr != NULL) - printf(" at %s", intrstr); - printf("\n"); - goto intfail; + printf("can't establish interrupt"); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + goto fail1; } + printf("%s", intrstr); + + if (pa->pa_id == PCI_ID_CODE(PCI_VENDOR_SIS, PCI_PRODUCT_SIS_190)) + sc->sc_flags |= SE_FLAG_FASTETHER; + /* Reset the adapter. */ se_reset(sc); - /* - * Get MAC address from the EEPROM. - */ - if (se_get_mac_addr_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr) && - se_get_mac_addr_cmos(sc, (caddr_t)&sc->arpcom.ac_enaddr) - ) - goto fail; - - printf(": %s, address %s\n", intrstr, - ether_sprintf(sc->arpcom.ac_enaddr)); + /* Get MAC address from the EEPROM. */ + if ((pci_conf_read(pa->pa_pc, pa->pa_tag, 0x70) & (0x01 << 24)) != 0) + se_get_mac_addr_apc(sc, eaddr); + else + se_get_mac_addr_eeprom(sc, eaddr); + printf(", address %s\n", ether_sprintf(eaddr)); + bcopy(eaddr, ac->ac_enaddr, ETHER_ADDR_LEN); /* * Now do all the DMA mapping stuff */ - sc->se_tag = pa->pa_dmat; + sc->sc_dmat = pa->pa_dmat; + ld = &sc->se_ldata; + cd = &sc->se_cdata; /* First create TX/RX busdma maps. */ for (i = 0; i < SE_RX_RING_CNT; i++) { - error = bus_dmamap_create(sc->se_tag, MCLBYTES, 1, MCLBYTES, + rc = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, BUS_DMA_NOWAIT, &cd->se_rx_map[i]); - if (error) { - printf("cannot init the RX map array!\n"); - goto fail; - } + if (rc != 0) { + printf("%s: cannot init the RX map array\n", + self->dv_xname); + goto fail2; + } } for (i = 0; i < SE_TX_RING_CNT; i++) { - error = bus_dmamap_create(sc->se_tag, MCLBYTES, 1, MCLBYTES, + rc = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, BUS_DMA_NOWAIT, &cd->se_tx_map[i]); - if (error) { - printf("cannot init the TX map array!\n"); - goto fail; - } + if (rc != 0) { + printf("%s: cannot init the TX map array\n", + self->dv_xname); + goto fail2; + } } - /* - * Now allocate a tag for the DMA descriptor lists and a chunk - * of DMA-able memory based on the tag. Also obtain the physical - * addresses of the RX and TX ring, which we'll need later. - * All of our lists are allocated as a contiguous block - * of memory. + * Now allocate a chunk of DMA-able memory for RX and TX ring + * descriptors, as a contiguous block of memory. + * XXX fix deallocation upon error */ /* RX */ - - error = bus_dmamem_alloc(sc->se_tag, SE_RX_RING_SZ, PAGE_SIZE, 0, - &seg, 1, &nseg, BUS_DMA_NOWAIT); - if (error) { - printf("no memory for rx list buffers!\n"); - goto fail; + rc = bus_dmamem_alloc(sc->sc_dmat, SE_RX_RING_SZ, PAGE_SIZE, 0, + &seg, 1, &nseg, BUS_DMA_NOWAIT); + if (rc != 0) { + printf("%s: no memory for RX descriptors\n", self->dv_xname); + goto fail2; } - error = bus_dmamem_map(sc->se_tag, &seg, nseg, SE_RX_RING_SZ, - (caddr_t *)&ld->se_rx_ring, BUS_DMA_NOWAIT); - if (error) { - printf("can't map rx list buffers!\n"); - goto fail; + rc = bus_dmamem_map(sc->sc_dmat, &seg, nseg, SE_RX_RING_SZ, + (caddr_t *)&ld->se_rx_ring, BUS_DMA_NOWAIT); + if (rc != 0) { + printf("%s: can't map RX descriptors\n", self->dv_xname); + goto fail2; } - error = bus_dmamap_create(sc->se_tag, SE_RX_RING_SZ, 1, - SE_RX_RING_SZ, 0, BUS_DMA_NOWAIT, &ld->se_rx_dmamap); - if (error) { - printf("can't alloc rx list map!\n"); - goto fail; + rc = bus_dmamap_create(sc->sc_dmat, SE_RX_RING_SZ, 1, + SE_RX_RING_SZ, 0, BUS_DMA_NOWAIT, &ld->se_rx_dmamap); + if (rc != 0) { + printf("%s: can't alloc RX DMA map\n", self->dv_xname); + goto fail2; } - error = bus_dmamap_load(sc->se_tag, ld->se_rx_dmamap, - (caddr_t)ld->se_rx_ring, SE_RX_RING_SZ, - NULL, BUS_DMA_NOWAIT); - if (error) { - printf("can't load rx ring mapping!\n"); - bus_dmamem_unmap(sc->se_tag, + rc = bus_dmamap_load(sc->sc_dmat, ld->se_rx_dmamap, + (caddr_t)ld->se_rx_ring, SE_RX_RING_SZ, NULL, BUS_DMA_NOWAIT); + if (rc != 0) { + printf("%s: can't load RX DMA map\n", self->dv_xname); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)ld->se_rx_ring, SE_RX_RING_SZ); - bus_dmamap_destroy(sc->se_tag, ld->se_rx_dmamap); - bus_dmamem_free(sc->se_tag, &seg, nseg); - goto fail; + bus_dmamap_destroy(sc->sc_dmat, ld->se_rx_dmamap); + bus_dmamem_free(sc->sc_dmat, &seg, nseg); + goto fail2; } /* TX */ - - error = bus_dmamem_alloc(sc->se_tag, SE_TX_RING_SZ, PAGE_SIZE, 0, - &seg, 1, &nseg, BUS_DMA_NOWAIT); - if (error) { - printf("no memory for tx list buffers!\n"); - goto fail; + rc = bus_dmamem_alloc(sc->sc_dmat, SE_TX_RING_SZ, PAGE_SIZE, 0, + &seg, 1, &nseg, BUS_DMA_NOWAIT); + if (rc != 0) { + printf("%s: no memory for TX descriptors\n", self->dv_xname); + goto fail2; } - error = bus_dmamem_map(sc->se_tag, &seg, nseg, SE_TX_RING_SZ, - (caddr_t *)&ld->se_tx_ring, BUS_DMA_NOWAIT); - if (error) { - printf("can't map tx list buffers!\n"); - goto fail; + rc = bus_dmamem_map(sc->sc_dmat, &seg, nseg, SE_TX_RING_SZ, + (caddr_t *)&ld->se_tx_ring, BUS_DMA_NOWAIT); + if (rc != 0) { + printf("%s: can't map TX descriptors\n", self->dv_xname); + goto fail2; } - error = bus_dmamap_create(sc->se_tag, SE_TX_RING_SZ, 1, - SE_TX_RING_SZ, 0, BUS_DMA_NOWAIT, &ld->se_tx_dmamap); - if (error) { - printf("can't alloc tx list map!\n"); - goto fail; + rc = bus_dmamap_create(sc->sc_dmat, SE_TX_RING_SZ, 1, + SE_TX_RING_SZ, 0, BUS_DMA_NOWAIT, &ld->se_tx_dmamap); + if (rc != 0) { + printf("%s: can't alloc TX DMA map\n", self->dv_xname); + goto fail2; } - error = bus_dmamap_load(sc->se_tag, ld->se_tx_dmamap, - (caddr_t)ld->se_tx_ring, SE_TX_RING_SZ, - NULL, BUS_DMA_NOWAIT); - if (error) { - printf("can't load tx ring mapping!\n"); - bus_dmamem_unmap(sc->se_tag, + rc = bus_dmamap_load(sc->sc_dmat, ld->se_tx_dmamap, + (caddr_t)ld->se_tx_ring, SE_TX_RING_SZ, NULL, BUS_DMA_NOWAIT); + if (rc != 0) { + printf("%s: can't load TX DMA map\n", self->dv_xname); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)ld->se_tx_ring, SE_TX_RING_SZ); - bus_dmamap_destroy(sc->se_tag, ld->se_tx_dmamap); - bus_dmamem_free(sc->se_tag, &seg, nseg); - goto fail; + bus_dmamap_destroy(sc->sc_dmat, ld->se_tx_dmamap); + bus_dmamem_free(sc->sc_dmat, &seg, nseg); + goto fail2; } - timeout_set(&sc->se_timeout, se_tick, sc); + timeout_set(&sc->sc_tick_tmo, se_tick, sc); - sc->se_ifp = ifp = &sc->arpcom.ac_if; + ifp = &sc->sc_ac.ac_if; ifp->if_softc = sc; - ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = se_ioctl; ifp->if_start = se_start; ifp->if_watchdog = se_watchdog; - ifp->if_baudrate = IF_Mbps(100); IFQ_SET_MAXLEN(&ifp->if_snd, SE_TX_RING_CNT - 1); IFQ_SET_READY(&ifp->if_snd); bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); @@ -640,15 +697,18 @@ se_attach(parent, self, aux) sc->sc_mii.mii_readreg = se_miibus_readreg; sc->sc_mii.mii_writereg = se_miibus_writereg; sc->sc_mii.mii_statchg = se_miibus_statchg; - ifmedia_init(&sc->sc_mii.mii_media, 0, - se_ifmedia_upd,se_ifmedia_sts); - mii_phy_probe(self, &sc->sc_mii, 0xffffffff); + ifmedia_init(&sc->sc_mii.mii_media, 0, se_ifmedia_upd, + se_ifmedia_sts); + mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, + MII_OFFSET_ANY, 0); if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { - ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL); - ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE); + /* No PHY attached */ + ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL, + 0, NULL); + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL); } else - ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO); + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO); /* * Call MI attach routine. @@ -656,66 +716,70 @@ se_attach(parent, self, aux) if_attach(ifp); ether_ifattach(ifp); - shutdownhook_establish(se_shutdown, sc); - return; -fail: - pci_intr_disestablish(pc, sc->sc_ih); - -intfail: - bus_space_unmap(sc->se_btag, sc->se_bhandle, size); +fail2: + pci_intr_disestablish(pa->pa_pc, sc->sc_ih); +fail1: + bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); } -/* - * Stop all chip I/O so that the kernel's probe routines don't - * get confused by errant DMAs when rebooting. - */ -void -se_shutdown(v) - void *v; +int +se_activate(struct device *self, int act) { - struct se_softc *sc = (struct se_softc *)v; + struct se_softc *sc = (struct se_softc *)self; + struct ifnet *ifp = &sc->sc_ac.ac_if; + int rc = 0; + + switch (act) { + case DVACT_SUSPEND: + if (ifp->if_flags & IFF_RUNNING) + se_stop(sc); + rc = config_activate_children(self, act); + break; + case DVACT_RESUME: + rc = config_activate_children(self, act); + if (ifp->if_flags & IFF_UP) + (void)se_init(ifp); + break; + } - se_reset(sc); - se_stop(sc); + return rc; } - - /* * Initialize the TX descriptors. */ int -se_list_tx_init(sc) - struct se_softc *sc; +se_list_tx_init(struct se_softc *sc) { - struct se_list_data *ld = &sc->se_ldata; - struct se_chain_data *cd = &sc->se_cdata; + struct se_list_data *ld = &sc->se_ldata; + struct se_chain_data *cd = &sc->se_cdata; bzero(ld->se_tx_ring, SE_TX_RING_SZ); - ld->se_tx_ring[SE_TX_RING_CNT - 1].se_flags |= RING_END; - cd->se_tx_prod = cd->se_tx_cons = cd->se_tx_cnt = 0; + ld->se_tx_ring[SE_TX_RING_CNT - 1].se_flags = htole32(RING_END); + cd->se_tx_prod = 0; + cd->se_tx_cons = 0; + cd->se_tx_cnt = 0; - return (0); + return 0; } int -se_list_tx_free(sc) - struct se_softc *sc; +se_list_tx_free(struct se_softc *sc) { - struct se_chain_data *cd = &sc->se_cdata; - int i; + struct se_chain_data *cd = &sc->se_cdata; + uint i; for (i = 0; i < SE_TX_RING_CNT; i++) { - if (cd->se_tx_mbuf[i] != NULL) { - bus_dmamap_unload(sc->se_tag, cd->se_tx_map[i]); - m_free(cd->se_tx_mbuf[i]); - cd->se_tx_mbuf[i] = NULL; - } + if (cd->se_tx_mbuf[i] != NULL) { + bus_dmamap_unload(sc->sc_dmat, cd->se_tx_map[i]); + m_free(cd->se_tx_mbuf[i]); + cd->se_tx_mbuf[i] = NULL; + } } - return (0); + return 0; } /* @@ -724,101 +788,102 @@ se_list_tx_free(sc) * has RING_END flag set. */ int -se_list_rx_init(sc) - struct se_softc *sc; +se_list_rx_init(struct se_softc *sc) { - struct se_list_data *ld = &sc->se_ldata; - struct se_chain_data *cd = &sc->se_cdata; - int i; + struct se_list_data *ld = &sc->se_ldata; + struct se_chain_data *cd = &sc->se_cdata; + uint i; bzero(ld->se_rx_ring, SE_RX_RING_SZ); for (i = 0; i < SE_RX_RING_CNT; i++) { - if (se_newbuf(sc, i, NULL) == ENOBUFS) { - printf("unable to allocate MBUFs, %d\n", i); - return (ENOBUFS); - } + if (se_newbuf(sc, i) != 0) + return ENOBUFS; } - ld->se_rx_ring[SE_RX_RING_CNT - 1].se_flags |= RING_END; + ld->se_rx_ring[SE_RX_RING_CNT - 1].se_flags |= htole32(RING_END); cd->se_rx_prod = 0; - return (0); + return 0; } int -se_list_rx_free(sc) - struct se_softc *sc; +se_list_rx_free(struct se_softc *sc) { - struct se_chain_data *cd = &sc->se_cdata; - int i; + struct se_chain_data *cd = &sc->se_cdata; + uint i; for (i = 0; i < SE_RX_RING_CNT; i++) { - if (cd->se_rx_mbuf[i] != NULL) { - bus_dmamap_unload(sc->se_tag, cd->se_rx_map[i]); - m_free(cd->se_rx_mbuf[i]); - cd->se_rx_mbuf[i] = NULL; - } + if (cd->se_rx_mbuf[i] != NULL) { + bus_dmamap_unload(sc->sc_dmat, cd->se_rx_map[i]); + m_free(cd->se_rx_mbuf[i]); + cd->se_rx_mbuf[i] = NULL; + } } - return (0); + return 0; } /* * Initialize an RX descriptor and attach an MBUF cluster. */ int -se_newbuf(sc, i, m) - struct se_softc *sc; - u_int32_t i; - struct mbuf *m; +se_newbuf(struct se_softc *sc, uint i) { - struct se_list_data *ld = &sc->se_ldata; - struct se_chain_data *cd = &sc->se_cdata; - /*struct ifnet *ifp = sc->se_ifp;*/ - int error, alloc; +#ifdef SE_DEBUG + struct ifnet *ifp = &sc->sc_ac.ac_if; +#endif + struct se_list_data *ld = &sc->se_ldata; + struct se_chain_data *cd = &sc->se_cdata; + struct se_desc *desc; + struct mbuf *m; + int rc; + m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES); if (m == NULL) { - m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES); - if (m == NULL) { - printf("unable to get new MBUF\n"); - return (ENOBUFS); - } - cd->se_rx_mbuf[i] = m; - alloc = 1; - } else { - m->m_data = m->m_ext.ext_buf; - alloc = 0; +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: MCLGETI failed\n", ifp->if_xname); +#endif + return ENOBUFS; } - m->m_len = m->m_pkthdr.len = MCLBYTES; + m_adj(m, SE_RX_BUF_ALIGN); - if (alloc) { - error = bus_dmamap_load_mbuf(sc->se_tag, cd->se_rx_map[i], - m, BUS_DMA_NOWAIT); - if (error) { - printf("unable to map and load the MBUF\n"); + rc = bus_dmamap_load_mbuf(sc->sc_dmat, cd->se_rx_map[i], + m, BUS_DMA_NOWAIT); + KASSERT(cd->se_rx_map[i]->dm_nsegs == 1); + if (rc != 0) { m_freem(m); - return (ENOBUFS); - } + return ENOBUFS; } - /* This is used both to initialize the newly created RX - * descriptor as well as for re-initializing it for reuse. */ - ld->se_rx_ring[i].se_sts_size = 0; - ld->se_rx_ring[i].se_cmdsts = - htole32(OWNbit | INTbit | IPbit | TCPbit | UDPbit); - ld->se_rx_ring[i].se_ptr = - htole32(cd->se_rx_map[i]->dm_segs[0].ds_addr); - ld->se_rx_ring[i].se_flags = - htole32(cd->se_rx_map[i]->dm_segs[0].ds_len) - | (i == SE_RX_RING_CNT - 1 ? RING_END : 0); - KASSERT(cd->se_rx_map[i]->dm_nsegs == 1); + cd->se_rx_mbuf[i] = m; + desc = &ld->se_rx_ring[i]; + desc->se_sts_size = 0; + desc->se_cmdsts = htole32(RDC_OWN | RDC_INTR); + desc->se_ptr = htole32((uint32_t)cd->se_rx_map[i]->dm_segs[0].ds_addr); + desc->se_flags = htole32(cd->se_rx_map[i]->dm_segs[0].ds_len); + if (i == SE_RX_RING_CNT - 1) + desc->se_flags |= htole32(RING_END); - bus_dmamap_sync(sc->se_tag, cd->se_rx_map[i], 0, - cd->se_rx_map[i]->dm_mapsize, - BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->sc_dmat, cd->se_rx_map[i], 0, + cd->se_rx_map[i]->dm_mapsize, BUS_DMASYNC_PREREAD); - return (0); + return 0; +} + +void +se_discard_rxbuf(struct se_softc *sc, uint i) +{ + struct se_list_data *ld = &sc->se_ldata; + struct se_desc *desc; + + desc = &ld->se_rx_ring[i]; + desc->se_sts_size = 0; + desc->se_cmdsts = htole32(RDC_OWN | RDC_INTR); + desc->se_flags = htole32(MCLBYTES - SE_RX_BUF_ALIGN); + if (i == SE_RX_RING_CNT - 1) + desc->se_flags |= htole32(RING_END); } /* @@ -826,207 +891,195 @@ se_newbuf(sc, i, m) * the higher level protocols. */ void -se_rxeof(sc) - struct se_softc *sc; +se_rxeof(struct se_softc *sc) { - struct mbuf *m, *m0; - struct ifnet *ifp = sc->se_ifp; - struct se_list_data *ld = &sc->se_ldata; - struct se_chain_data *cd = &sc->se_cdata; - struct se_desc *cur_rx; - u_int32_t i, rxstat, total_len = 0; - - for (i = cd->se_rx_prod; !SE_OWNDESC(&ld->se_rx_ring[i]); - SE_INC(i, SE_RX_RING_CNT)) - { - bus_dmamap_sync(sc->se_tag, cd->se_rx_map[i], 0, - cd->se_rx_map[i]->dm_mapsize, - BUS_DMASYNC_POSTREAD); - - cur_rx = &ld->se_rx_ring[i]; - rxstat = SE_RXSTATUS(cur_rx); - total_len = SE_RXSIZE(cur_rx); - m = cd->se_rx_mbuf[i]; - - /* - * If an error occurs, update stats, clear the - * status word and leave the mbuf cluster in place: - * it should simply get re-used next time this descriptor - * comes up in the ring. - */ - if (rxstat & RX_ERR_BITS) { - printf("error_bits=%#x\n", rxstat); - ifp->if_ierrors++; - /* TODO: better error differentiation */ - se_newbuf(sc, i, m); - continue; - } - - /* No errors; receive the packet. */ - cd->se_rx_mbuf[i] = NULL; /* XXX neccessary? */ -#ifndef __STRICT_ALIGNMENT - if (se_newbuf(sc, i, NULL) == 0) { - m->m_pkthdr.len = m->m_len = total_len; - } else -#endif - { - /* ETHER_ALIGN is 2 */ - m0 = m_devget(mtod(m, char *), total_len, - 2, ifp, NULL); - se_newbuf(sc, i, m); - if (m0 == NULL) { - printf("unable to copy MBUF\n"); - ifp->if_ierrors++; - continue; + struct mbuf *m; + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct se_list_data *ld = &sc->se_ldata; + struct se_chain_data *cd = &sc->se_cdata; + struct se_desc *cur_rx; + uint32_t rxinfo, rxstat; + uint i; + + for (i = cd->se_rx_prod; ; SE_INC(i, SE_RX_RING_CNT)) { + cur_rx = &ld->se_rx_ring[i]; + rxinfo = letoh32(cur_rx->se_cmdsts); + if ((rxinfo & RDC_OWN) != 0) + break; + rxstat = letoh32(cur_rx->se_sts_size); + bus_dmamap_sync(sc->sc_dmat, cd->se_rx_map[i], 0, + cd->se_rx_map[i]->dm_mapsize, + BUS_DMASYNC_POSTREAD); + + /* + * If an error occurs, update stats, clear the + * status word and leave the mbuf cluster in place: + * it should simply get re-used next time this descriptor + * comes up in the ring. + */ + if ((rxstat & RDS_CRCOK) == 0 || SE_RX_ERROR(rxstat) != 0 || + SE_RX_NSEGS(rxstat) != 1) { + /* XXX We don't support multi-segment frames yet. */ + if (ifp->if_flags & IFF_DEBUG) + printf("%s: rx error %b\n", + ifp->if_xname, rxstat, RX_ERR_BITS); + se_discard_rxbuf(sc, i); + ifp->if_ierrors++; + continue; } - m = m0; - } - ifp->if_ipackets++; - m->m_pkthdr.rcvif = ifp; + /* No errors; receive the packet. */ + m = cd->se_rx_mbuf[i]; + if (se_newbuf(sc, i) != 0) { + se_discard_rxbuf(sc, i); + ifp->if_iqdrops++; + continue; + } + /* + * Account for 10 bytes auto padding which is used + * to align IP header on a 32bit boundary. Also note, + * CRC bytes are automatically removed by the hardware. + */ + m->m_data += SE_RX_PAD_BYTES; + m->m_pkthdr.len = m->m_len = + SE_RX_BYTES(rxstat) - SE_RX_PAD_BYTES; + + ifp->if_ipackets++; + m->m_pkthdr.rcvif = ifp; #if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); #endif - - /* pass it on. */ - ether_input_mbuf(ifp, m); + ether_input_mbuf(ifp, m); } cd->se_rx_prod = i; } - /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ void -se_txeof(sc) - struct se_softc *sc; +se_txeof(struct se_softc *sc) { - struct ifnet *ifp = sc->se_ifp; - struct se_list_data *ld = &sc->se_ldata; - struct se_chain_data *cd = &sc->se_cdata; - struct se_desc *cur_tx; - u_int32_t i, txstat; + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct se_list_data *ld = &sc->se_ldata; + struct se_chain_data *cd = &sc->se_cdata; + struct se_desc *cur_tx; + uint32_t txstat; + uint i; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ - for (i = cd->se_tx_cons; cd->se_tx_cnt > 0 && - !SE_OWNDESC(&ld->se_tx_ring[i]); - cd->se_tx_cnt--, SE_INC(i, SE_TX_RING_CNT)) - { - cur_tx = &ld->se_tx_ring[i]; - txstat = letoh32(cur_tx->se_cmdsts); - bus_dmamap_sync(sc->se_tag, cd->se_tx_map[i], 0, + for (i = cd->se_tx_cons; cd->se_tx_cnt > 0; + cd->se_tx_cnt--, SE_INC(i, SE_TX_RING_CNT)) { + cur_tx = &ld->se_tx_ring[i]; + txstat = letoh32(cur_tx->se_cmdsts); + if ((txstat & TDC_OWN) != 0) + break; + + ifp->if_flags &= ~IFF_OACTIVE; + + if (SE_TX_ERROR(txstat) != 0) { + if (ifp->if_flags & IFF_DEBUG) + printf("%s: tx error %b\n", + ifp->if_xname, txstat, TX_ERR_BITS); + ifp->if_oerrors++; + /* TODO: better error differentiation */ + } else + ifp->if_opackets++; + + if (cd->se_tx_mbuf[i] != NULL) { + bus_dmamap_sync(sc->sc_dmat, cd->se_tx_map[i], 0, cd->se_tx_map[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, cd->se_tx_map[i]); + m_free(cd->se_tx_mbuf[i]); + cd->se_tx_mbuf[i] = NULL; + } - /* current slot is transferred now */ - - if (txstat & TX_ERR_BITS) { - printf("error_bits=%#x\n", txstat); - ifp->if_oerrors++; - /* TODO: better error differentiation */ - } - - ifp->if_opackets++; - if (cd->se_tx_mbuf[i] != NULL) { - bus_dmamap_unload(sc->se_tag, cd->se_tx_map[i]); - m_free(cd->se_tx_mbuf[i]); - cd->se_tx_mbuf[i] = NULL; - } - cur_tx->se_sts_size = 0; - cur_tx->se_cmdsts = 0; - cur_tx->se_ptr = 0; - cur_tx->se_flags &= RING_END; - } - - if (i != cd->se_tx_cons) { - /* we freed up some buffers */ - cd->se_tx_cons = i; - ifp->if_flags &= ~IFF_OACTIVE; + cur_tx->se_sts_size = 0; + cur_tx->se_cmdsts = 0; + cur_tx->se_ptr = 0; + cur_tx->se_flags &= RING_END; } - sc->se_watchdog_timer = (cd->se_tx_cnt == 0) ? 0 : 5; + cd->se_tx_cons = i; + if (cd->se_tx_cnt == 0) + ifp->if_timer = 0; } void -se_tick(xsc) - void *xsc; +se_tick(void *xsc) { - struct se_softc *sc = xsc; - struct mii_data *mii; - struct ifnet *ifp = sc->se_ifp; - int s; + struct se_softc *sc = xsc; + struct mii_data *mii; + struct ifnet *ifp = &sc->sc_ac.ac_if; + int s; s = splnet(); - - sc->in_tick = 1; - mii = &sc->sc_mii; mii_tick(mii); - - se_watchdog(ifp); - - if (!sc->se_link && mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) - { - sc->se_link++; - if (!IFQ_IS_EMPTY(&ifp->if_snd)) - se_start(ifp); + if ((sc->sc_flags & SE_FLAG_LINK) == 0) { + se_miibus_statchg(&sc->sc_dev); + if ((sc->sc_flags & SE_FLAG_LINK) != 0 && + !IFQ_IS_EMPTY(&ifp->if_snd)) + se_start(ifp); } + splx(s); - timeout_add_sec(&sc->se_timeout, 1); - - sc->in_tick = 0; - - splx(s); - return; + timeout_add_sec(&sc->sc_tick_tmo, 1); } int -se_intr(arg) - void *arg; +se_intr(void *arg) { - struct se_softc *sc = arg; - struct ifnet *ifp = sc->se_ifp; - int status; - int claimed = 0; - - if (sc->se_stopped) /* Most likely shared interrupt */ - return (claimed); - - DISABLE_INTERRUPTS(sc); + struct se_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ac.ac_if; + uint32_t status; + + status = CSR_READ_4(sc, IntrStatus); + if (status == 0xffffffff || (status & SE_INTRS) == 0) { + /* Not ours. */ + return 0; + } + /* Ack interrupts/ */ + CSR_WRITE_4(sc, IntrStatus, status); + /* Disable further interrupts. */ + CSR_WRITE_4(sc, IntrMask, 0); for (;;) { - /* Reading the ISR register clears all interrupts. */ - status = CSR_READ_4(sc, IntrStatus); - if ((status == 0xffffffff) || (status == 0x0)) - break; - - claimed = 1; /* XXX just a guess to put this here */ - - CSR_WRITE_4(sc, IntrStatus, status); - - if (status & TxQInt) - se_txeof(sc); - - if (status & RxQInt) - se_rxeof(sc); + if ((ifp->if_flags & IFF_RUNNING) == 0) + break; + if ((status & (INTR_RX_DONE | INTR_RX_IDLE)) != 0) { + se_rxeof(sc); + /* Wakeup Rx MAC. */ + if ((status & INTR_RX_IDLE) != 0) + CSR_WRITE_4(sc, RX_CTL, + 0x1a00 | 0x000c | RX_CTL_POLL | RX_CTL_ENB); + } + if ((status & (INTR_TX_DONE | INTR_TX_IDLE)) != 0) + se_txeof(sc); + status = CSR_READ_4(sc, IntrStatus); + if ((status & SE_INTRS) == 0) + break; + /* Ack interrupts. */ + CSR_WRITE_4(sc, IntrStatus, status); } - ENABLE_INTERRUPTS(sc); - - if (!IFQ_IS_EMPTY(&ifp->if_snd)) - se_start(ifp); + if ((ifp->if_flags & IFF_RUNNING) != 0) { + /* Re-enable interrupts */ + CSR_WRITE_4(sc, IntrMask, SE_INTRS); + if (!IFQ_IS_EMPTY(&ifp->if_snd)) + se_start(ifp); + } - return (claimed); + return 1; } /* @@ -1034,90 +1087,88 @@ se_intr(arg) * pointers to the fragment pointers. */ int -se_encap(sc, m_head, txidx) - struct se_softc *sc; - struct mbuf *m_head; - u_int32_t *txidx; +se_encap(struct se_softc *sc, struct mbuf *m_head, uint32_t *txidx) { - struct mbuf *m; - struct se_list_data *ld = &sc->se_ldata; - struct se_chain_data *cd = &sc->se_cdata; - int error, i, cnt = 0; +#ifdef SE_DEBUG + struct ifnet *ifp = &sc->sc_ac.ac_if; +#endif + struct mbuf *m; + struct se_list_data *ld = &sc->se_ldata; + struct se_chain_data *cd = &sc->se_cdata; + struct se_desc *desc; + uint i, cnt = 0; + int rc; /* * If there's no way we can send any packets, return now. */ - if (SE_TX_RING_CNT - cd->se_tx_cnt < 2) - return (ENOBUFS); - -#if 1 - if (m_defrag(m_head, M_DONTWAIT)) { - printf("unable to defragment MBUFs\n"); - return (ENOBUFS); - } -#else - m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES); - if (m == NULL) { - printf("se_encap: unable to allocate MBUF\n"); - return (ENOBUFS); - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m, caddr_t)); - m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len; - map = cd->se_tx_map[i]; - error = bus_dmamap_load_mbuf(sc->se_tag, map, - m, BUS_DMA_NOWAIT); - if (error) { - printf("unable to load the MBUF\n"); - return (ENOBUFS); + if (SE_TX_RING_CNT - cd->se_tx_cnt < 2) { +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: encap failed, not enough TX desc\n", + ifp->if_xname); +#endif + return ENOBUFS; } + + if (m_defrag(m_head, M_DONTWAIT) != 0) { +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: m_defrag failed\n", ifp->if_xname); #endif - + return ENOBUFS; /* XXX should not be fatal */ + } + /* - * Start packing the mbufs in this chain into + * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. + * of fragments or hit the end of the mbuf chain. */ i = *txidx; for (m = m_head; m != NULL; m = m->m_next) { - if (m->m_len == 0) - continue; - if ((SE_TX_RING_CNT - (cd->se_tx_cnt + cnt)) < 2) - return (ENOBUFS); - cd->se_tx_mbuf[i] = m; - error = bus_dmamap_load_mbuf(sc->se_tag, cd->se_tx_map[i], - m, BUS_DMA_NOWAIT); - if (error) { - printf("unable to load the MBUF\n"); - return (ENOBUFS); - } - - ld->se_tx_ring[i].se_sts_size = - htole32(cd->se_tx_map[i]->dm_segs->ds_len); - ld->se_tx_ring[i].se_cmdsts = - htole32(OWNbit | INTbit | PADbit | CRCbit | DEFbit); - ld->se_tx_ring[i].se_ptr = - htole32(cd->se_tx_map[i]->dm_segs->ds_addr); - ld->se_tx_ring[i].se_flags |= - htole32(cd->se_tx_map[i]->dm_segs->ds_len); - KASSERT(cd->se_tx_map[i]->dm_nsegs == 1); - - bus_dmamap_sync(sc->se_tag, cd->se_tx_map[i], 0, - cd->se_tx_map[i]->dm_mapsize, - BUS_DMASYNC_PREWRITE); - SE_INC(i, SE_TX_RING_CNT); - cnt++; + if (m->m_len == 0) + continue; + if ((SE_TX_RING_CNT - (cd->se_tx_cnt + cnt)) < 2) { +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: encap failed, not enough TX desc\n", + ifp->if_xname); +#endif + return ENOBUFS; + } + cd->se_tx_mbuf[i] = m; + rc = bus_dmamap_load_mbuf(sc->sc_dmat, cd->se_tx_map[i], + m, BUS_DMA_NOWAIT); + if (rc != 0) + return ENOBUFS; + KASSERT(cd->se_tx_map[i]->dm_nsegs == 1); + bus_dmamap_sync(sc->sc_dmat, cd->se_tx_map[i], 0, + cd->se_tx_map[i]->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + desc = &ld->se_tx_ring[i]; + desc->se_sts_size = htole32(cd->se_tx_map[i]->dm_segs->ds_len); + desc->se_ptr = + htole32((uint32_t)cd->se_tx_map[i]->dm_segs->ds_addr); + desc->se_flags = htole32(cd->se_tx_map[i]->dm_segs->ds_len); + if (i == SE_TX_RING_CNT - 1) + desc->se_flags |= htole32(RING_END); + desc->se_cmdsts = htole32(TDC_OWN | TDC_INTR | TDC_DEF | + TDC_CRC | TDC_PAD | TDC_BST); + + SE_INC(i, SE_TX_RING_CNT); + cnt++; } - if (m != NULL) { - printf("unable to encap all MBUFs\n"); - return (ENOBUFS); - } + /* can't happen */ + if (m != NULL) + return ENOBUFS; cd->se_tx_cnt += cnt; *txidx = i; - return (0); + return 0; } /* @@ -1127,147 +1178,121 @@ se_encap(sc, m_head, txidx) * physical addresses. */ void -se_start(ifp) - struct ifnet *ifp; +se_start(struct ifnet *ifp) { - struct se_softc *sc = ifp->if_softc; - struct mbuf *m_head = NULL; - struct se_chain_data *cd = &sc->se_cdata; - u_int32_t i, queued = 0; - - if (!sc->se_link) { - return; - } - - if (ifp->if_flags & IFF_OACTIVE) { - return; + struct se_softc *sc = ifp->if_softc; + struct mbuf *m_head = NULL; + struct se_chain_data *cd = &sc->se_cdata; + uint i, queued = 0; + + if ((sc->sc_flags & SE_FLAG_LINK) == 0 || + (ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) { +#ifdef SE_DEBUG + if (ifp->if_flags & IFF_DEBUG) + printf("%s: can't tx, flags 0x%x 0x%04x\n", + ifp->if_xname, sc->sc_flags, (uint)ifp->if_flags); +#endif + return; } i = cd->se_tx_prod; while (cd->se_tx_mbuf[i] == NULL) { - IFQ_POLL(&ifp->if_snd, m_head); - if (m_head == NULL) - break; + IFQ_POLL(&ifp->if_snd, m_head); + if (m_head == NULL) + break; - if (se_encap(sc, m_head, &i)) { - ifp->if_flags |= IFF_OACTIVE; - break; - } + if (se_encap(sc, m_head, &i) != 0) { + ifp->if_flags |= IFF_OACTIVE; + break; + } - /* now we are committed to transmit the packet */ - IFQ_DEQUEUE(&ifp->if_snd, m_head); - queued++; + /* now we are committed to transmit the packet */ + IFQ_DEQUEUE(&ifp->if_snd, m_head); + queued++; - /* - * If there's a BPF listener, bounce a copy of this frame - * to him. - */ + /* + * If there's a BPF listener, bounce a copy of this frame + * to him. + */ #if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); #endif } - if (queued) { - /* Transmit */ - cd->se_tx_prod = i; - SE_SETBIT(sc, TxControl, CmdReset); - - /* - * Set a timeout in case the chip goes out to lunch. - */ - sc->se_watchdog_timer = 5; + if (queued > 0) { + /* Transmit */ + cd->se_tx_prod = i; + CSR_WRITE_4(sc, TX_CTL, 0x1a00 | TX_CTL_ENB | TX_CTL_POLL); + ifp->if_timer = 5; } } -/* TODO: Find out right return codes */ int -se_init(ifp) - struct ifnet *ifp; +se_init(struct ifnet *ifp) { - struct se_softc *sc = ifp->if_softc; - int s; + struct se_softc *sc = ifp->if_softc; + uint16_t rxfilt; + int i; - s = splnet(); + splassert(IPL_NET); + + if ((ifp->if_flags & IFF_RUNNING) != 0) + return 0; /* * Cancel pending I/O and free all RX/TX buffers. */ se_stop(sc); - sc->se_stopped = 0; + se_reset(sc); /* Init circular RX list. */ if (se_list_rx_init(sc) == ENOBUFS) { - printf("initialization failed: no " - "memory for rx buffers\n"); - se_stop(sc); - splx(s); - return 1; + se_stop(sc); /* XXX necessary? */ + return ENOBUFS; } /* Init TX descriptors. */ se_list_tx_init(sc); - se_reset(sc); - /* * Load the address of the RX and TX lists. */ - CSR_WRITE_4(sc, TxDescStartAddr, - sc->se_ldata.se_tx_dmamap->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, RxDescStartAddr, - sc->se_ldata.se_rx_dmamap->dm_segs[0].ds_addr); - -/* CSR_WRITE_4(sc, PMControl, 0xffc00000); */ - CSR_WRITE_4(sc, Reserved2, 0); - - CSR_WRITE_4(sc, IntrStatus, 0xffffffff); - DISABLE_INTERRUPTS(sc); - - - /* - * Default is 100Mbps. - * A bit strange: 100Mbps is 0x1801 elsewhere -- FR 2005/06/09 - */ - CSR_WRITE_4(sc, StationControl, 0x04001801); // 1901 - - CSR_WRITE_4(sc, GMacIOCR, 0x0); - CSR_WRITE_4(sc, GMacIOCTL, 0x0); - - CSR_WRITE_4(sc, TxMacControl, 0x2364); /* 0x60 */ - CSR_WRITE_4(sc, TxMacTimeLimit, 0x000f); - CSR_WRITE_4(sc, RGMIIDelay, 0x0); - CSR_WRITE_4(sc, Reserved3, 0x0); - - CSR_WRITE_4(sc, RxWakeOnLan, 0x80ff0000); - CSR_WRITE_4(sc, RxWakeOnLanData, 0x80ff0000); - CSR_WRITE_4(sc, RxMPSControl, 0x0); - CSR_WRITE_4(sc, Reserved4, 0x0); - - SE_PCI_COMMIT(); - - /* - * Load the multicast filter. - */ - se_setmulti(sc); + CSR_WRITE_4(sc, TX_DESC, + (uint32_t)sc->se_ldata.se_tx_dmamap->dm_segs[0].ds_addr); + CSR_WRITE_4(sc, RX_DESC, + (uint32_t)sc->se_ldata.se_rx_dmamap->dm_segs[0].ds_addr); + + CSR_WRITE_4(sc, TxMacControl, 0x60); + CSR_WRITE_4(sc, RxWakeOnLan, 0); + CSR_WRITE_4(sc, RxWakeOnLanData, 0); + CSR_WRITE_2(sc, RxMPSControl, ETHER_MAX_LEN + SE_RX_PAD_BYTES); + + for (i = 0; i < ETHER_ADDR_LEN; i++) + CSR_WRITE_1(sc, RxMacAddr + i, sc->sc_ac.ac_enaddr[i]); + /* Configure RX MAC. */ + rxfilt = RXMAC_STRIP_FCS | RXMAC_PAD_ENB | RXMAC_CSUM_ENB; + CSR_WRITE_2(sc, RxMacControl, rxfilt); + se_iff(sc); /* - * Enable interrupts. + * Clear and enable interrupts. */ - ENABLE_INTERRUPTS(sc); + CSR_WRITE_4(sc, IntrStatus, 0xFFFFFFFF); + CSR_WRITE_4(sc, IntrMask, SE_INTRS); /* Enable receiver and transmitter. */ - SE_SETBIT(sc, TxControl, CmdTxEnb | CmdReset); - SE_SETBIT(sc, RxControl, CmdRxEnb | CmdReset); + CSR_WRITE_4(sc, TX_CTL, 0x1a00 | TX_CTL_ENB); + CSR_WRITE_4(sc, RX_CTL, 0x1a00 | 0x000c | RX_CTL_POLL | RX_CTL_ENB); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - if (!sc->in_tick) - timeout_add_sec(&sc->se_timeout, 1); + sc->sc_flags &= ~SE_FLAG_LINK; + mii_mediachg(&sc->sc_mii); + timeout_add_sec(&sc->sc_tick_tmo, 1); - splx(s); return 0; } @@ -1275,34 +1300,29 @@ se_init(ifp) * Set media options. */ int -se_ifmedia_upd(ifp) - struct ifnet *ifp; +se_ifmedia_upd(struct ifnet *ifp) { - struct se_softc *sc = ifp->if_softc; - struct mii_data *mii; + struct se_softc *sc = ifp->if_softc; + struct mii_data *mii; mii = &sc->sc_mii; - sc->se_link = 0; + sc->sc_flags &= ~SE_FLAG_LINK; if (mii->mii_instance) { - struct mii_softc *miisc; - LIST_FOREACH(miisc, &mii->mii_phys, mii_list) - mii_phy_reset(miisc); + struct mii_softc *miisc; + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) + mii_phy_reset(miisc); } - mii_mediachg(mii); - - return (0); + return mii_mediachg(mii); } /* * Report current media status. */ void -se_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; +se_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { - struct se_softc *sc = ifp->if_softc; - struct mii_data *mii; + struct se_softc *sc = ifp->if_softc; + struct mii_data *mii; mii = &sc->sc_mii; mii_pollstat(mii); @@ -1311,71 +1331,74 @@ se_ifmedia_sts(ifp, ifmr) } int -se_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; +se_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { - struct se_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - struct mii_data *mii; - int s, error = 0; + struct se_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; +#ifdef INET + struct ifaddr *ifa = (struct ifaddr *)data; +#endif + int s, rc = 0; s = splnet(); switch (command) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + if ((ifp->if_flags & IFF_RUNNING) == 0) + rc = se_init(ifp); + if (rc == 0) { +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) + arp_ifinit(&sc->sc_ac, ifa); +#endif + } + break; case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) - se_init(ifp); - else if (ifp->if_flags & IFF_RUNNING) - se_stop(sc); - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - se_setmulti(sc); - error = 0; - break; + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING) + rc = ENETRESET; + else + rc = se_init(ifp); + } else { + if (ifp->if_flags & IFF_RUNNING) + se_stop(sc); + } + break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: - mii = &sc->sc_mii; - error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); - break; + rc = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command); + break; default: - error = ether_ioctl(ifp, &sc->arpcom, command, data); - break; + rc = ether_ioctl(ifp, &sc->sc_ac, command, data); + break; + } + + if (rc == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) + se_iff(sc); + rc = 0; } splx(s); - return (error); + return rc; } void -se_watchdog(ifp) - struct ifnet *ifp; +se_watchdog(struct ifnet *ifp) { - struct se_softc *sc = ifp->if_softc; - int s; - - if (sc->se_stopped) - return; + struct se_softc *sc = ifp->if_softc; + int s; - if (sc->se_watchdog_timer == 0 || --sc->se_watchdog_timer >0) - return; - - printf("watchdog timeout\n"); - sc->se_ifp->if_oerrors++; + printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname); + ifp->if_oerrors++; s = splnet(); - se_stop(sc); - se_reset(sc); + ifp->if_flags &= ~IFF_RUNNING; se_init(ifp); - - if (!IFQ_IS_EMPTY(&sc->se_ifp->if_snd)) - se_start(sc->se_ifp); - + if (!IFQ_IS_EMPTY(&ifp->if_snd)) + se_start(ifp); splx(s); - return; } /* @@ -1383,44 +1406,27 @@ se_watchdog(ifp) * RX and TX lists. */ void -se_stop(sc) - struct se_softc *sc; +se_stop(struct se_softc *sc) { - struct ifnet *ifp = sc->se_ifp; - - if (sc->se_stopped) - return; - - sc->se_watchdog_timer = 0; - - timeout_del(&sc->se_timeout); + struct ifnet *ifp = &sc->sc_ac.ac_if; + ifp->if_timer = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + timeout_del(&sc->sc_tick_tmo); + mii_down(&sc->sc_mii); - DISABLE_INTERRUPTS(sc); - - CSR_WRITE_4(sc, IntrControl, 0x8000); - SE_PCI_COMMIT(); - DELAY(100); - CSR_WRITE_4(sc, IntrControl, 0x0); - - SE_CLRBIT(sc, TxControl, CmdTxEnb); - SE_CLRBIT(sc, RxControl, CmdRxEnb); - DELAY(100); - CSR_WRITE_4(sc, TxDescStartAddr, 0); - CSR_WRITE_4(sc, RxDescStartAddr, 0); - - sc->se_link = 0; + CSR_WRITE_4(sc, IntrMask, 0); + CSR_READ_4(sc, IntrMask); + CSR_WRITE_4(sc, IntrStatus, 0xffffffff); + /* Stop TX/RX MAC. */ + CSR_WRITE_4(sc, TX_CTL, 0x1a00); + CSR_WRITE_4(sc, RX_CTL, 0x1a00); + /* XXX Can we assume active DMA cycles gone? */ + DELAY(2000); + CSR_WRITE_4(sc, IntrMask, 0); + CSR_WRITE_4(sc, IntrStatus, 0xffffffff); - /* - * Free data in the RX lists. - */ + sc->sc_flags &= ~SE_FLAG_LINK; se_list_rx_free(sc); - - /* - * Free the TX list buffers. - */ se_list_tx_free(sc); - - sc->se_stopped = 1; } diff --git a/sys/dev/pci/if_sereg.h b/sys/dev/pci/if_sereg.h index 009741716f9..cc619ec6198 100644 --- a/sys/dev/pci/if_sereg.h +++ b/sys/dev/pci/if_sereg.h @@ -1,7 +1,7 @@ -/* $OpenBSD: if_sereg.h,v 1.2 2010/04/02 22:42:55 jsg Exp $ */ +/* $OpenBSD: if_sereg.h,v 1.3 2010/09/04 12:47:00 miod Exp $ */ /*- - * Copyright (c) 2009, 2010 Christopher Zimmermann <madroach@zakweb.de> + * Copyright (c) 2008, 2009, 2010 Nikolay Denev <ndenev@gmail.com> * Copyright (c) 2007, 2008 Alexander Pohoyda <alexander.pohoyda@gmx.net> * Copyright (c) 1997, 1998, 1999 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. @@ -34,256 +34,238 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: src/sys/dev/sge/if_sgereg.h,v 1.7 2010/07/08 18:22:49 yongari Exp $ */ -struct se_desc { - volatile u_int32_t se_sts_size; - volatile u_int32_t se_cmdsts; - volatile u_int32_t se_ptr; - volatile u_int32_t se_flags; -}; - -#define SE_RX_RING_CNT 1000 /* [8, 1024] */ -#define SE_TX_RING_CNT 1000 /* [8, 8192] */ - -#define SE_RX_RING_SZ (SE_RX_RING_CNT * sizeof(struct se_desc)) -#define SE_TX_RING_SZ (SE_TX_RING_CNT * sizeof(struct se_desc)) - -struct se_list_data { - struct se_desc *se_rx_ring; - struct se_desc *se_tx_ring; - bus_dmamap_t se_rx_dmamap; - bus_dmamap_t se_tx_dmamap; -}; - -struct se_chain_data { - struct mbuf *se_rx_mbuf[SE_RX_RING_CNT]; - struct mbuf *se_tx_mbuf[SE_TX_RING_CNT]; - bus_dmamap_t se_rx_map[SE_RX_RING_CNT]; - bus_dmamap_t se_tx_map[SE_TX_RING_CNT]; - int se_rx_prod; - int se_tx_prod; - int se_tx_cons; - int se_tx_cnt; -}; - -struct se_softc { - struct device sc_dev; - void *sc_ih; - struct ifnet *se_ifp; /* interface info */ - struct resource *se_res[2]; - void *se_intrhand; - mii_data_t sc_mii; - struct arpcom arpcom; - - u_int8_t se_link; - - bus_space_handle_t se_bhandle; - bus_space_tag_t se_btag; - bus_dma_tag_t se_tag; - - struct se_list_data se_ldata; - struct se_chain_data se_cdata; - - struct timeout se_timeout; - int in_tick; - int se_watchdog_timer; - int se_stopped; -}; - - -#define SE_PCI_LOMEM 0x10 - -enum sis19x_registers { - TxControl = 0x00, - TxDescStartAddr = 0x04, - Reserved0 = 0x08, // unused - TxNextDescAddr = 0x0c, // unused - - RxControl = 0x10, - RxDescStartAddr = 0x14, - Reserved1 = 0x18, // unused - RxNextDescAddr = 0x1c, // unused - - IntrStatus = 0x20, - IntrMask = 0x24, - IntrControl = 0x28, - IntrTimer = 0x2c, // unused - - PMControl = 0x30, // unused - Reserved2 = 0x34, // unused - ROMControl = 0x38, - ROMInterface = 0x3c, - StationControl = 0x40, - GMIIControl = 0x44, - GMacIOCR = 0x48, - GMacIOCTL = 0x4c, - TxMacControl = 0x50, - TxMacTimeLimit = 0x54, - RGMIIDelay = 0x58, - Reserved3 = 0x5c, - RxMacControl = 0x60, // 1 WORD - RxMacAddr = 0x62, // 6x BYTE - RxHashTable = 0x68, // 1 LONG - RxHashTable2 = 0x6c, // 1 LONG - RxWakeOnLan = 0x70, - RxWakeOnLanData = 0x74, - RxMPSControl = 0x78, - Reserved4 = 0x7c, -}; - -enum sis19x_register_content { - /* IntrStatus */ - SoftInt = 0x40000000, // unused - Timeup = 0x20000000, // unused - PauseFrame = 0x00080000, // unused - MagicPacket = 0x00040000, // unused - WakeupFrame = 0x00020000, // unused - LinkChange = 0x00010000, - RxQEmpty = 0x00000080, //! RXIDLE - RxQInt = 0x00000040, //! RXDONE - TxQ1Empty = 0x00000020, // unused - TxQ1Int = 0x00000010, // unused - TxQEmpty = 0x00000008, //! TXIDLE - TxQInt = 0x00000004, //! TXDONE - RxHalt = 0x00000002, //! RXHALT - TxHalt = 0x00000001, //! TXHALT - - /* RxStatusDesc */ - RxRES = 0x00200000, // unused - RxCRC = 0x00080000, - RxRUNT = 0x00100000, // unused - RxRWT = 0x00400000, // unused - - /* {Rx/Tx}CmdBits */ - CmdReset = 0x10, - CmdRxEnb = 0x01, /* Linux does not use it, but 0x8 */ - CmdTxEnb = 0x01, - - /* RxMacControl */ - AcceptBroadcast = 0x0800, - AcceptMulticast = 0x0400, - AcceptMyPhys = 0x0200, - AcceptAllPhys = 0x0100, - AcceptErr = 0x0020, // unused - AcceptRunt = 0x0010, // unused -}; +#define TX_CTL 0x00 +#define TX_DESC 0x04 +#define Reserved0 0x08 +#define TX_NEXT 0x0c + +#define RX_CTL 0x10 +#define RX_DESC 0x14 +#define Reserved1 0x18 +#define RX_NEXT 0x1c + +#define IntrStatus 0x20 +#define IntrMask 0x24 +#define IntrControl 0x28 +#define IntrTimer 0x2c + +#define PMControl 0x30 +#define Reserved2 0x34 +#define ROMControl 0x38 +#define ROMInterface 0x3c +#define StationControl 0x40 +#define GMIIControl 0x44 +#define GMacIOCR 0x48 +#define GMacIOCTL 0x4c +#define TxMacControl 0x50 +#define TxMacTimeLimit 0x54 +#define RGMIIDelay 0x58 +#define Reserved3 0x5c +#define RxMacControl 0x60 /* 1 WORD */ +#define RxMacAddr 0x62 /* 6x BYTE */ +#define RxHashTable 0x68 /* 1 LONG */ +#define RxHashTable2 0x6c /* 1 LONG */ +#define RxWakeOnLan 0x70 +#define RxWakeOnLanData 0x74 +#define RxMPSControl 0x78 +#define Reserved4 0x7c /* - * register space access macros + * IntrStatus Register Content */ -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->se_btag, sc->se_bhandle, reg, val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->se_btag, sc->se_bhandle, reg, val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->se_btag, sc->se_bhandle, reg) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->se_btag, sc->se_bhandle, reg) +#define INTR_SOFT 0x40000000 +#define INTR_TIMER 0x20000000 +#define INTR_PAUSE_FRAME 0x00080000 +#define INTR_MAGIC_FRAME 0x00040000 +#define INTR_WAKE_FRAME 0x00020000 +#define INTR_LINK 0x00010000 +#define INTR_RX_IDLE 0x00000080 +#define INTR_RX_DONE 0x00000040 +#define INTR_TXQ1_IDLE 0x00000020 +#define INTR_TXQ1_DONE 0x00000010 +#define INTR_TX_IDLE 0x00000008 +#define INTR_TX_DONE 0x00000004 +#define INTR_RX_HALT 0x00000002 +#define INTR_TX_HALT 0x00000001 + +#define SE_INTRS \ + (INTR_RX_IDLE | INTR_RX_DONE | INTR_TXQ1_IDLE | \ + INTR_TXQ1_DONE |INTR_TX_IDLE | INTR_TX_DONE | \ + INTR_TX_HALT | INTR_RX_HALT) -#define SE_PCI_COMMIT() CSR_READ_4(sc, IntrControl) - -#define SE_SETBIT(_sc, _reg, x) \ - CSR_WRITE_4(_sc, _reg, CSR_READ_4(_sc, _reg) | (x)) +/* + * RxStatusDesc Register Content + */ +#define RxRES 0x00200000 +#define RxCRC 0x00080000 +#define RxRUNT 0x00100000 +#define RxRWT 0x00400000 -#define SE_CLRBIT(_sc, _reg, x) \ - CSR_WRITE_4(_sc, _reg, CSR_READ_4(_sc, _reg) & ~(x)) +/* + * RX_CTL Register Content + */ +#define RX_CTL_POLL 0x00000010 +#define RX_CTL_ENB 0x00000001 -#define DISABLE_INTERRUPTS(sc) CSR_WRITE_4(sc, IntrMask, 0x0) -#define ENABLE_INTERRUPTS(sc) CSR_WRITE_4(sc, IntrMask, RxQEmpty | RxQInt | \ - TxQInt | RxHalt | TxHalt) +/* + * TX_CTL Register Content + */ +#define TX_CTL_POLL 0x00000010 +#define TX_CTL_ENB 0x00000001 +/* + * RxMacControl Register Content + */ +#define AcceptBroadcast 0x0800 +#define AcceptMulticast 0x0400 +#define AcceptMyPhys 0x0200 +#define AcceptAllPhys 0x0100 +#define AcceptErr 0x0020 +#define AcceptRunt 0x0010 +#define RXMAC_STRIP_VLAN 0x0020 +#define RXMAC_STRIP_FCS 0x0010 +#define RXMAC_PAD_ENB 0x0004 +#define RXMAC_CSUM_ENB 0x0002 + +#define SE_RX_PAD_BYTES 10 + +/* Station control register. */ +#define SC_LOOPBACK 0x80000000 +#define SC_RGMII 0x00008000 +#define SC_FDX 0x00001000 +#define SC_SPEED_MASK 0x00000c00 +#define SC_SPEED_10 0x00000400 +#define SC_SPEED_100 0x00000800 +#define SC_SPEED_1000 0x00000c00 /* * Gigabit Media Independent Interface CTL register */ -#define GMI_DATA 0xffff0000 -#define GMI_DATA_SHIFT 16 -#define GMI_REG 0x0000f800 -#define GMI_REG_SHIFT 11 -#define GMI_PHY 0x000007c0 -#define GMI_PHY_SHIFT 6 -#define GMI_OP 0x00000020 -#define GMI_OP_SHIFT 5 -#define GMI_OP_WR (1 << GMI_OP_SHIFT) -#define GMI_OP_RD (0 << GMI_OP_SHIFT) -#define GMI_REQ 0x00000010 -#define GMI_MDIO 0x00000008 /* not used */ -#define GMI_MDDIR 0x00000004 /* not used */ -#define GMI_MDC 0x00000002 /* not used */ -#define GMI_MDEN 0x00000001 /* not used */ - -enum CommandStatus { - OWNbit = 0x80000000, - INTbit = 0x40000000, - IPbit = 0x20000000, - TCPbit = 0x10000000, - UDPbit = 0x08000000, - DEFbit = 0x00200000, - CRCbit = 0x00020000, - PADbit = 0x00010000, -}; - +#define GMI_DATA 0xffff0000 +#define GMI_DATA_SHIFT 16 +#define GMI_REG 0x0000f800 +#define GMI_REG_SHIFT 11 +#define GMI_PHY 0x000007c0 +#define GMI_PHY_SHIFT 6 +#define GMI_OP_WR 0x00000020 +#define GMI_OP_RD 0x00000000 +#define GMI_REQ 0x00000010 +#define GMI_MDIO 0x00000008 +#define GMI_MDDIR 0x00000004 +#define GMI_MDC 0x00000002 +#define GMI_MDEN 0x00000001 + +/* Tx descriptor command bits. */ +#define TDC_OWN 0x80000000 +#define TDC_INTR 0x40000000 +#define TDC_THOL3 0x30000000 +#define TDC_THOL2 0x20000000 +#define TDC_THOL1 0x10000000 +#define TDC_THOL0 0x00000000 +#define TDC_LS 0x08000000 +#define TDC_IP_CSUM 0x04000000 +#define TDC_TCP_CSUM 0x02000000 +#define TDC_UDP_CSUM 0x01000000 +#define TDC_BST 0x00800000 +#define TDC_EXT 0x00400000 +#define TDC_DEF 0x00200000 +#define TDC_BKF 0x00100000 +#define TDC_CRS 0x00080000 +#define TDC_COL 0x00040000 +#define TDC_CRC 0x00020000 +#define TDC_PAD 0x00010000 +#define TDC_VLAN_MASK 0x0000FFFF + +#define SE_TX_INTR_FRAMES 32 /* - * RX descriptor status bits + * TX descriptor status bits. */ -#define RDS_TAGON 0x80000000 -#define RDS_DESCS 0x3f000000 -#define RDS_ABORT 0x00800000 -#define RDS_SHORT 0x00400000 -#define RDS_LIMIT 0x00200000 -#define RDS_MIIER 0x00100000 -#define RDS_OVRUN 0x00080000 -#define RDS_NIBON 0x00040000 -#define RDS_COLON 0x00020000 -#define RDS_CRCOK 0x00010000 -#define RX_ERR_BITS \ - (RDS_COLON | RDS_NIBON | RDS_OVRUN | RDS_MIIER | \ - RDS_LIMIT | RDS_SHORT | RDS_ABORT) - -#define RING_END 0x80000000 - -#define SE_RXSIZE(x) letoh32((x)->se_sts_size & 0x0000ffff) -#define SE_RXSTATUS(x) letoh32((x)->se_sts_size & 0xffff0000) - -#undef SE_OWNDESC -#define SE_OWNDESC(x) ((x)->se_cmdsts & OWNbit) - -#define SE_INC(x, y) (x) = (((x) == ((y)-1)) ? 0 : (x)+1) - +#define TDS_OWC 0x00080000 +#define TDS_ABT 0x00040000 +#define TDS_FIFO 0x00020000 +#define TDS_CRS 0x00010000 +#define TDS_COLLS 0x0000ffff +#define SE_TX_ERROR(x) ((x) & (TDS_OWC | TDS_ABT | TDS_FIFO | TDS_CRS)) +#define TX_ERR_BITS "\20" \ + "\21CRS\22FIFO\23ABT\24OWC" + +/* Rx descriptor command bits. */ +#define RDC_OWN 0x80000000 +#define RDC_INTR 0x40000000 +#define RDC_IP_CSUM 0x20000000 +#define RDC_TCP_CSUM 0x10000000 +#define RDC_UDP_CSUM 0x08000000 +#define RDC_IP_CSUM_OK 0x04000000 +#define RDC_TCP_CSUM_OK 0x02000000 +#define RDC_UDP_CSUM_OK 0x01000000 +#define RDC_WAKEUP 0x00400000 +#define RDC_MAGIC 0x00200000 +#define RDC_PAUSE 0x00100000 +#define RDC_BCAST 0x000c0000 +#define RDC_MCAST 0x00080000 +#define RDC_UCAST 0x00040000 +#define RDC_CRCOFF 0x00020000 +#define RDC_PREADD 0x00010000 +#define RDC_VLAN_MASK 0x0000FFFF /* - * TX descriptor status bits + * RX descriptor status bits */ -#define TDS_OWC 0x00080000 -#define TDS_ABT 0x00040000 -#define TDS_FIFO 0x00020000 -#define TDS_CRS 0x00010000 -#define TDS_COLLS 0x0000ffff -#define TX_ERR_BITS (TDS_OWC | TDS_ABT | TDS_FIFO | TDS_CRS) +#define RDS_VLAN 0x80000000 +#define RDS_DESCS 0x3f000000 +#define RDS_ABORT 0x00800000 +#define RDS_SHORT 0x00400000 +#define RDS_LIMIT 0x00200000 +#define RDS_MIIER 0x00100000 +#define RDS_OVRUN 0x00080000 +#define RDS_NIBON 0x00040000 +#define RDS_COLON 0x00020000 +#define RDS_CRCOK 0x00010000 +#define SE_RX_ERROR(x) \ + ((x) & (RDS_COLON | RDS_NIBON | RDS_OVRUN | RDS_MIIER | \ + RDS_LIMIT | RDS_SHORT | RDS_ABORT)) +#define SE_RX_NSEGS(x) (((x) & RDS_DESCS) >> 24) +#define RX_ERR_BITS "\20" \ + "\21CRCOK\22COLON\23NIBON\24OVRUN" \ + "\25MIIER\26LIMIT\27SHORT\30ABORT" \ + "\40VLAN" + +#define RING_END 0x80000000 +#define SE_RX_BYTES(x) ((x) & 0xFFFF) +#define SE_INC(x, y) (x) = (((x) + 1) % y) /* Taken from Solaris driver */ -#define EI_DATA 0xffff0000 -#define EI_DATA_SHIFT 16 -#define EI_OFFSET 0x0000fc00 -#define EI_OFFSET_SHIFT 10 -#define EI_OP 0x00000300 -#define EI_OP_SHIFT 8 -#define EI_OP_RD (2 << EI_OP_SHIFT) -#define EI_OP_WR (1 << EI_OP_SHIFT) -#define EI_REQ 0x00000080 -#define EI_DO 0x00000008 /* not used */ -#define EI_DI 0x00000004 /* not used */ -#define EI_CLK 0x00000002 /* not used */ -#define EI_CS 0x00000001 +#define EI_DATA 0xffff0000 +#define EI_DATA_SHIFT 16 +#define EI_OFFSET 0x0000fc00 +#define EI_OFFSET_SHIFT 10 +#define EI_OP 0x00000300 +#define EI_OP_SHIFT 8 +#define EI_OP_RD (2 << EI_OP_SHIFT) +#define EI_OP_WR (1 << EI_OP_SHIFT) +#define EI_REQ 0x00000080 +#define EI_DO 0x00000008 +#define EI_DI 0x00000004 +#define EI_CLK 0x00000002 +#define EI_CS 0x00000001 /* * EEPROM Addresses */ -#define EEPROMSignature 0x00 -#define EEPROMCLK 0x01 -#define EEPROMInfo 0x02 -#define EEPROMMACAddr 0x03 +#define EEPROMSignature 0x00 +#define EEPROMCLK 0x01 +#define EEPROMInfo 0x02 +#define EEPROMMACAddr 0x03 + +#define SE_TIMEOUT 1000 + +struct se_desc { + volatile u_int32_t se_sts_size; + volatile u_int32_t se_cmdsts; + volatile u_int32_t se_ptr; + volatile u_int32_t se_flags; +}; |