From a3a1d2d2a9fc086771e3a694606b72a947f461c4 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 24 Jan 2004 06:34:02 +0000 Subject: [PATCH] Synch the XL driver with FreeBSD-4.x. --- sys/dev/netif/xl/if_xl.c | 784 ++++++++++++++++++++++++------------ sys/dev/netif/xl/if_xlreg.h | 52 ++- 2 files changed, 554 insertions(+), 282 deletions(-) diff --git a/sys/dev/netif/xl/if_xl.c b/sys/dev/netif/xl/if_xl.c index 7d0385f4bd..90846d1af2 100644 --- a/sys/dev/netif/xl/if_xl.c +++ b/sys/dev/netif/xl/if_xl.c @@ -29,10 +29,8 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/if_xl.c,v 1.72.2.25 2003/02/05 22:03:58 mbr Exp $ - * $DragonFly: src/sys/dev/netif/xl/if_xl.c,v 1.6 2004/01/06 01:40:50 dillon Exp $ - * - * $FreeBSD: src/sys/pci/if_xl.c,v 1.72.2.25 2003/02/05 22:03:58 mbr Exp $ + * $FreeBSD: src/sys/pci/if_xl.c,v 1.72.2.28 2003/10/08 06:01:57 murray Exp $ + * $DragonFly: src/sys/dev/netif/xl/if_xl.c,v 1.7 2004/01/24 06:34:02 dillon Exp $ */ /* @@ -83,7 +81,7 @@ * (3c59x) also supported a bus master mode, however for those chips * you could only DMA packets to/from a contiguous memory buffer. For * transmission this would mean copying the contents of the queued mbuf - * chain into a an mbuf cluster and then DMAing the cluster. This extra + * chain into an mbuf cluster and then DMAing the cluster. This extra * copy would sort of defeat the purpose of the bus master support for * any packet that doesn't fit into a single mbuf. * @@ -107,8 +105,8 @@ #include #include #include +#include #include -#include #include #include @@ -117,15 +115,14 @@ #include #include #include +#include #include -#include /* for vtophys */ -#include /* for vtophys */ -#include /* for DELAY */ #include #include #include +#include /* for DELAY */ #include #include #include @@ -139,18 +136,6 @@ /* "controller miibus0" required. See GENERIC if you get errors here. */ #include "miibus_if.h" -/* - * The following #define causes the code to use PIO to access the - * chip's registers instead of memory mapped mode. The reason PIO mode - * is on by default is that the Etherlink XL manual seems to indicate - * that only the newer revision chips (3c905B) support both PIO and - * memory mapped access. Since we want to be compatible with the older - * bus master chips, we use PIO here. If you comment this out, the - * driver will use memory mapped I/O, which may be faster but which - * might not work on some devices. - */ -#define XL_USEIOSPACE - #include "if_xlreg.h" #define XL905B_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) @@ -262,6 +247,11 @@ static int xl_list_tx_init_90xB (struct xl_softc *); static void xl_wait (struct xl_softc *); static void xl_mediacheck (struct xl_softc *); static void xl_choose_xcvr (struct xl_softc *, int); +static void xl_dma_map_addr (void *, bus_dma_segment_t *, int, int); +static void xl_dma_map_rxbuf (void *, bus_dma_segment_t *, int, bus_size_t, + int); +static void xl_dma_map_txbuf (void *, bus_dma_segment_t *, int, bus_size_t, + int); #ifdef notdef static void xl_testpacket (struct xl_softc *); #endif @@ -271,14 +261,6 @@ static int xl_miibus_writereg (device_t, int, int, int); static void xl_miibus_statchg (device_t); static void xl_miibus_mediainit (device_t); -#ifdef XL_USEIOSPACE -#define XL_RES SYS_RES_IOPORT -#define XL_RID XL_PCI_LOIO -#else -#define XL_RES SYS_RES_MEMORY -#define XL_RID XL_PCI_LOMEM -#endif - static device_method_t xl_methods[] = { /* Device interface */ DEVMETHOD(device_probe, xl_probe), @@ -314,6 +296,65 @@ MODULE_DEPEND(if_xl, miibus, 1, 1, 1); DRIVER_MODULE(if_xl, pci, xl_driver, xl_devclass, 0, 0); DRIVER_MODULE(miibus, xl, miibus_driver, miibus_devclass, 0, 0); +static void +xl_dma_map_addr(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg, error; +{ + u_int32_t *paddr; + + paddr = arg; + *paddr = segs->ds_addr; +} + +static void +xl_dma_map_rxbuf(arg, segs, nseg, mapsize, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + bus_size_t mapsize; + int error; +{ + u_int32_t *paddr; + + if (error) + return; + KASSERT(nseg == 1, ("xl_dma_map_rxbuf: too many DMA segments")); + paddr = arg; + *paddr = segs->ds_addr; +} + +static void +xl_dma_map_txbuf(arg, segs, nseg, mapsize, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + bus_size_t mapsize; + int error; +{ + struct xl_list *l; + int i, total_len; + + if (error) + return; + + KASSERT(nseg <= XL_MAXFRAGS, ("too many DMA segments")); + + total_len = 0; + l = arg; + for (i = 0; i < nseg; i++) { + KASSERT(segs[i].ds_len <= MCLBYTES, ("segment size too large")); + l->xl_frag[i].xl_addr = htole32(segs[i].ds_addr); + l->xl_frag[i].xl_len = htole32(segs[i].ds_len); + total_len += segs[i].ds_len; + } + l->xl_frag[nseg - 1].xl_len = htole32(segs[nseg - 1].ds_len | + XL_LAST_FRAG); + l->xl_status = htole32(total_len); + l->xl_next = 0; +} + /* * Murphy's law says that it's possible the chip can wedge and * the 'command in progress' bit may never clear. Hence, we wait @@ -350,11 +391,11 @@ xl_wait(sc) */ #define MII_SET(x) \ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \ - CSR_READ_2(sc, XL_W4_PHY_MGMT) | x) + CSR_READ_2(sc, XL_W4_PHY_MGMT) | (x)) #define MII_CLR(x) \ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \ - CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~x) + CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~(x)) /* * Sync the PHYs by setting data bit and strobing the clock 32 times. @@ -370,9 +411,11 @@ xl_mii_sync(sc) for (i = 0; i < 32; i++) { MII_SET(XL_MII_CLK); - DELAY(1); + MII_SET(XL_MII_DATA); + MII_SET(XL_MII_DATA); MII_CLR(XL_MII_CLK); - DELAY(1); + MII_SET(XL_MII_DATA); + MII_SET(XL_MII_DATA); } return; @@ -398,9 +441,7 @@ xl_mii_send(sc, bits, cnt) } else { MII_CLR(XL_MII_DATA); } - DELAY(1); MII_CLR(XL_MII_CLK); - DELAY(1); MII_SET(XL_MII_CLK); } } @@ -450,19 +491,15 @@ xl_mii_readreg(sc, frame) /* Idle bit */ MII_CLR((XL_MII_CLK|XL_MII_DATA)); - DELAY(1); MII_SET(XL_MII_CLK); - DELAY(1); /* Turn off xmit. */ MII_CLR(XL_MII_DIR); /* Check for ack */ MII_CLR(XL_MII_CLK); - DELAY(1); ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA; MII_SET(XL_MII_CLK); - DELAY(1); /* * Now try reading data bits. If the ack failed, we still @@ -471,31 +508,24 @@ xl_mii_readreg(sc, frame) if (ack) { for(i = 0; i < 16; i++) { MII_CLR(XL_MII_CLK); - DELAY(1); MII_SET(XL_MII_CLK); - DELAY(1); } goto fail; } for (i = 0x8000; i; i >>= 1) { MII_CLR(XL_MII_CLK); - DELAY(1); if (!ack) { if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA) frame->mii_data |= i; - DELAY(1); } MII_SET(XL_MII_CLK); - DELAY(1); } fail: MII_CLR(XL_MII_CLK); - DELAY(1); MII_SET(XL_MII_CLK); - DELAY(1); splx(s); @@ -516,6 +546,7 @@ xl_mii_writereg(sc, frame) int s; s = splimp(); + /* * Set up frame for TX. */ @@ -545,9 +576,7 @@ xl_mii_writereg(sc, frame) /* Idle bit. */ MII_SET(XL_MII_CLK); - DELAY(1); MII_CLR(XL_MII_CLK); - DELAY(1); /* * Turn off xmit. @@ -869,8 +898,8 @@ xl_setmulti_hash(sc) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|i); /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { + for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; + ifma = ifma->ifma_link.le_next) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = xl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); @@ -1047,6 +1076,16 @@ xl_reset(sc) ((sc->xl_flags & XL_FLAG_WEIRDRESET) ? XL_RESETOPT_DISADVFD:0)); + /* + * If we're using memory mapped register mode, pause briefly + * after issuing the reset command before trying to access any + * other registers. With my 3c575C cardbus card, failing to do + * this results in the system locking up while trying to poll + * the command busy bit in the status register. + */ + if (sc->xl_flags & XL_FLAG_USE_MMIO) + DELAY(100000); + for (i = 0; i < XL_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY)) @@ -1059,7 +1098,7 @@ xl_reset(sc) /* Reset TX and RX. */ /* Note: the RX reset takes an absurd amount of time * on newer versions of the Tornado chips such as those - * on the 3c905CX and newer 3c908C cards. We wait an + * on the 3c905CX and newer 3c908C cards. We wait an * extra amount of time so that xl_wait() doesn't complain * and annoy the users. */ @@ -1265,17 +1304,20 @@ xl_attach(dev) { int s; u_char eaddr[ETHER_ADDR_LEN]; + u_int16_t xcvr[2]; u_int32_t command; struct xl_softc *sc; struct ifnet *ifp; int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - int unit, error = 0, rid; + int unit, error = 0, rid, res; s = splimp(); sc = device_get_softc(dev); unit = device_get_unit(dev); + ifmedia_init(&sc->ifmedia, 0, xl_ifmedia_upd, xl_ifmedia_sts); + sc->xl_flags = 0; if (pci_get_device(dev) == TC_DEVICEID_HURRICANE_555) sc->xl_flags |= XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_PHYOK; @@ -1311,7 +1353,7 @@ xl_attach(dev) XL_FLAG_INVERT_LED_PWR; if (pci_get_device(dev) == TC_DEVICEID_TORNADO_10_100BT_920B) sc->xl_flags |= XL_FLAG_PHYOK; - +#ifndef BURN_BRIDGES /* * If this is a 3c905B, we have to check one extra thing. * The 905B supports power management and may be placed in @@ -1350,7 +1392,7 @@ xl_attach(dev) pci_write_config(dev, XL_PCI_LOMEM, membase, 4); pci_write_config(dev, XL_PCI_INTLINE, irq, 4); } - +#endif /* * Map control/status registers. */ @@ -1359,28 +1401,36 @@ xl_attach(dev) pci_enable_io(dev, SYS_RES_MEMORY); command = pci_read_config(dev, PCIR_COMMAND, 4); -#ifdef XL_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("xl%d: failed to enable I/O ports!\n", unit); - error = ENXIO; - goto fail; - } -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("xl%d: failed to enable memory mapping!\n", unit); + if (!(command & PCIM_CMD_PORTEN) && !(command & PCIM_CMD_MEMEN)) { + printf("xl%d: failed to enable I/O ports and memory mappings!\n", unit); error = ENXIO; goto fail; } -#endif - rid = XL_RID; - sc->xl_res = bus_alloc_resource(dev, XL_RES, &rid, + rid = XL_PCI_LOMEM; + res = SYS_RES_MEMORY; + +#if 0 + sc->xl_res = bus_alloc_resource(dev, res, &rid, 0, ~0, 1, RF_ACTIVE); +#endif - if (sc->xl_res == NULL) { - printf ("xl%d: couldn't map ports/memory\n", unit); - error = ENXIO; - goto fail; + if (sc->xl_res != NULL) { + sc->xl_flags |= XL_FLAG_USE_MMIO; + if (bootverbose) + printf("xl%d: using memory mapped I/O\n", unit); + } else { + rid = XL_PCI_LOIO; + res = SYS_RES_IOPORT; + sc->xl_res = bus_alloc_resource(dev, res, &rid, + 0, ~0, 1, RF_ACTIVE); + if (sc->xl_res == NULL) { + printf ("xl%d: couldn't map ports/memory\n", unit); + error = ENXIO; + goto fail; + } + if (bootverbose) + printf("xl%d: using port I/O\n", unit); } sc->xl_btag = rman_get_bustag(sc->xl_res); @@ -1393,7 +1443,6 @@ xl_attach(dev) if (sc->xl_fres == NULL) { printf ("xl%d: couldn't map ports/memory\n", unit); - bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res); error = ENXIO; goto fail; } @@ -1402,33 +1451,16 @@ xl_attach(dev) sc->xl_fhandle = rman_get_bushandle(sc->xl_fres); } + /* Allocate interrupt */ rid = 0; sc->xl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); - if (sc->xl_irq == NULL) { printf("xl%d: couldn't map interrupt\n", unit); - if (sc->xl_fres != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - XL_PCI_FUNCMEM, sc->xl_fres); - bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res); error = ENXIO; goto fail; } - error = bus_setup_intr(dev, sc->xl_irq, INTR_TYPE_NET, - xl_intr, sc, &sc->xl_intrhand); - - if (error) { - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq); - if (sc->xl_fres != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - XL_PCI_FUNCMEM, sc->xl_fres); - bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res); - printf("xl%d: couldn't set up irq\n", unit); - goto fail; - } - /* Reset the adapter. */ xl_reset(sc); @@ -1437,12 +1469,6 @@ xl_attach(dev) */ if (xl_read_eeprom(sc, (caddr_t)&eaddr, XL_EE_OEM_ADR0, 3, 1)) { printf("xl%d: failed to read station address\n", sc->xl_unit); - bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq); - if (sc->xl_fres != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - XL_PCI_FUNCMEM, sc->xl_fres); - bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res); error = ENXIO; goto fail; } @@ -1456,30 +1482,110 @@ xl_attach(dev) callout_handle_init(&sc->xl_stat_ch); bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); - sc->xl_ldata = contigmalloc(sizeof(struct xl_list_data), M_DEVBUF, - M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); + /* + * Now allocate a tag for the DMA descriptor lists and a chunk + * of DMA-able memory based on the tag. Also obtain the DMA + * addresses of the RX and TX ring, which we'll need later. + * All of our lists are allocated as a contiguous block + * of memory. + */ + error = bus_dma_tag_create(NULL, 8, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + XL_RX_LIST_SZ, 1, XL_RX_LIST_SZ, 0, + &sc->xl_ldata.xl_rx_tag); + if (error) { + printf("xl%d: failed to allocate rx dma tag\n", unit); + goto fail; + } + + error = bus_dmamem_alloc(sc->xl_ldata.xl_rx_tag, + (void **)&sc->xl_ldata.xl_rx_list, BUS_DMA_NOWAIT, + &sc->xl_ldata.xl_rx_dmamap); + if (error) { + printf("xl%d: no memory for rx list buffers!\n", unit); + bus_dma_tag_destroy(sc->xl_ldata.xl_rx_tag); + sc->xl_ldata.xl_rx_tag = NULL; + goto fail; + } + + error = bus_dmamap_load(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, sc->xl_ldata.xl_rx_list, + XL_RX_LIST_SZ, xl_dma_map_addr, + &sc->xl_ldata.xl_rx_dmaaddr, BUS_DMA_NOWAIT); + if (error) { + printf("xl%d: cannot get dma address of the rx ring!\n", unit); + bus_dmamem_free(sc->xl_ldata.xl_rx_tag, sc->xl_ldata.xl_rx_list, + sc->xl_ldata.xl_rx_dmamap); + bus_dma_tag_destroy(sc->xl_ldata.xl_rx_tag); + sc->xl_ldata.xl_rx_tag = NULL; + goto fail; + } + + error = bus_dma_tag_create(NULL, 8, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + XL_TX_LIST_SZ, 1, XL_TX_LIST_SZ, 0, + &sc->xl_ldata.xl_tx_tag); + if (error) { + printf("xl%d: failed to allocate tx dma tag\n", unit); + goto fail; + } - if (sc->xl_ldata == NULL) { + error = bus_dmamem_alloc(sc->xl_ldata.xl_tx_tag, + (void **)&sc->xl_ldata.xl_tx_list, BUS_DMA_NOWAIT, + &sc->xl_ldata.xl_tx_dmamap); + if (error) { printf("xl%d: no memory for list buffers!\n", unit); - bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq); - if (sc->xl_fres != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - XL_PCI_FUNCMEM, sc->xl_fres); - bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res); - error = ENXIO; + bus_dma_tag_destroy(sc->xl_ldata.xl_tx_tag); + sc->xl_ldata.xl_tx_tag = NULL; + goto fail; + } + + error = bus_dmamap_load(sc->xl_ldata.xl_tx_tag, + sc->xl_ldata.xl_tx_dmamap, sc->xl_ldata.xl_tx_list, + XL_TX_LIST_SZ, xl_dma_map_addr, + &sc->xl_ldata.xl_tx_dmaaddr, BUS_DMA_NOWAIT); + if (error) { + printf("xl%d: cannot get dma address of the tx ring!\n", unit); + bus_dmamem_free(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_list, + sc->xl_ldata.xl_tx_dmamap); + bus_dma_tag_destroy(sc->xl_ldata.xl_tx_tag); + sc->xl_ldata.xl_tx_tag = NULL; + goto fail; + } + + /* + * Allocate a DMA tag for the mapping of mbufs. + */ + error = bus_dma_tag_create(NULL, 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MCLBYTES * XL_MAXFRAGS, XL_MAXFRAGS, MCLBYTES, 0, + &sc->xl_mtag); + if (error) { + printf("xl%d: failed to allocate mbuf dma tag\n", unit); goto fail; } - bzero(sc->xl_ldata, sizeof(struct xl_list_data)); + bzero(sc->xl_ldata.xl_tx_list, XL_TX_LIST_SZ); + bzero(sc->xl_ldata.xl_rx_list, XL_RX_LIST_SZ); + + /* We need a spare DMA map for the RX ring. */ + error = bus_dmamap_create(sc->xl_mtag, 0, &sc->xl_tmpmap); + if (error) + goto fail; /* * Figure out the card type. 3c905B adapters have the * 'supportsNoTxLength' bit set in the capabilities * word in the EEPROM. + * Note: my 3c575C cardbus card lies. It returns a value + * of 0x1578 for its capabilities word, which is somewhat + * nonsensical. Another way to distinguish a 3c90x chip + * from a 3c90xB/C chip is to check for the 'supportsLargePackets' + * bit. This will only be set for 3c90x boomerage chips. */ xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0); - if (sc->xl_caps & XL_CAPS_NO_TXLENGTH) + if (sc->xl_caps & XL_CAPS_NO_TXLENGTH || + !(sc->xl_caps & XL_CAPS_LARGE_PKTS)) sc->xl_type = XL_TYPE_905B; else sc->xl_type = XL_TYPE_90X; @@ -1491,12 +1597,14 @@ xl_attach(dev) ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = xl_ioctl; ifp->if_output = ether_output; + ifp->if_capabilities = 0; if (sc->xl_type == XL_TYPE_905B) { ifp->if_start = xl_start_90xB; ifp->if_hwassist = XL905B_CSUM_FEATURES; - ifp->if_capabilities = IFCAP_HWCSUM; - } else + ifp->if_capabilities |= IFCAP_HWCSUM; + } else { ifp->if_start = xl_start; + } ifp->if_watchdog = xl_watchdog; ifp->if_init = xl_init; ifp->if_baudrate = 10000000; @@ -1514,7 +1622,8 @@ xl_attach(dev) printf("xl%d: media options word: %x\n", sc->xl_unit, sc->xl_media); - xl_read_eeprom(sc, (char *)&sc->xl_xcvr, XL_EE_ICFG_0, 2, 0); + xl_read_eeprom(sc, (char *)&xcvr, XL_EE_ICFG_0, 2, 0); + sc->xl_xcvr = xcvr[0] | xcvr[1] << 16; sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK; sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS; @@ -1528,11 +1637,6 @@ xl_attach(dev) if (mii_phy_probe(dev, &sc->xl_miibus, xl_ifmedia_upd, xl_ifmedia_sts)) { printf("xl%d: no PHY found!\n", sc->xl_unit); - bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq); - bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res); - contigfree(sc->xl_ldata, - sizeof(struct xl_list_data), M_DEVBUF); error = ENXIO; goto fail; } @@ -1551,9 +1655,6 @@ xl_attach(dev) /* * Do ifmedia setup. */ - - ifmedia_init(&sc->ifmedia, 0, xl_ifmedia_upd, xl_ifmedia_sts); - if (sc->xl_media & XL_MEDIAOPT_BT) { if (bootverbose) printf("xl%d: found 10baseT\n", sc->xl_unit); @@ -1652,17 +1753,43 @@ done: */ ether_ifattach(ifp, ETHER_BPF_SUPPORTED); + /* + * Tell the upper layer(s) we support long frames. + */ + ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); + + /* Hook interrupt last to avoid having to lock softc */ + error = bus_setup_intr(dev, sc->xl_irq, INTR_TYPE_NET, + xl_intr, sc, &sc->xl_intrhand); + if (error) { + printf("xl%d: couldn't set up irq\n", unit); + ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); + goto fail; + } + fail: + if (error) + xl_detach(dev); + splx(s); + return(error); } +/* + * Shutdown hardware and free up resources. This can be called any + * time after the mutex has been initialized. It is called in both + * the error case in attach and the normal detach case so it needs + * to be careful about only freeing resources that have actually been + * allocated. + */ static int xl_detach(dev) device_t dev; { struct xl_softc *sc; struct ifnet *ifp; + int rid, res; int s; s = splimp(); @@ -1670,25 +1797,51 @@ xl_detach(dev) sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; + if (sc->xl_flags & XL_FLAG_USE_MMIO) { + rid = XL_PCI_LOMEM; + res = SYS_RES_MEMORY; + } else { + rid = XL_PCI_LOIO; + res = SYS_RES_IOPORT; + } + xl_reset(sc); xl_stop(sc); ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); - - /* Delete any miibus and phy devices attached to this interface */ - if (sc->xl_miibus != NULL) { - bus_generic_detach(dev); + + if (sc->xl_miibus) device_delete_child(dev, sc->xl_miibus); - } + bus_generic_detach(dev); + ifmedia_removeall(&sc->ifmedia); - bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq); + if (sc->xl_intrhand) + bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand); + if (sc->xl_irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq); if (sc->xl_fres != NULL) bus_release_resource(dev, SYS_RES_MEMORY, XL_PCI_FUNCMEM, sc->xl_fres); - bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res); + if (sc->xl_res) + bus_release_resource(dev, res, rid, sc->xl_res); - ifmedia_removeall(&sc->ifmedia); - contigfree(sc->xl_ldata, sizeof(struct xl_list_data), M_DEVBUF); + if (sc->xl_mtag) { + bus_dmamap_destroy(sc->xl_mtag, sc->xl_tmpmap); + bus_dma_tag_destroy(sc->xl_mtag); + } + if (sc->xl_ldata.xl_rx_tag) { + bus_dmamap_unload(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap); + bus_dmamem_free(sc->xl_ldata.xl_rx_tag, sc->xl_ldata.xl_rx_list, + sc->xl_ldata.xl_rx_dmamap); + bus_dma_tag_destroy(sc->xl_ldata.xl_rx_tag); + } + if (sc->xl_ldata.xl_tx_tag) { + bus_dmamap_unload(sc->xl_ldata.xl_tx_tag, + sc->xl_ldata.xl_tx_dmamap); + bus_dmamem_free(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_list, + sc->xl_ldata.xl_tx_dmamap); + bus_dma_tag_destroy(sc->xl_ldata.xl_tx_tag); + } splx(s); @@ -1704,12 +1857,18 @@ xl_list_tx_init(sc) { struct xl_chain_data *cd; struct xl_list_data *ld; - int i; + int error, i; cd = &sc->xl_cdata; - ld = sc->xl_ldata; + ld = &sc->xl_ldata; for (i = 0; i < XL_TX_LIST_CNT; i++) { cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i]; + error = bus_dmamap_create(sc->xl_mtag, 0, + &cd->xl_tx_chain[i].xl_map); + if (error) + return(error); + cd->xl_tx_chain[i].xl_phys = ld->xl_tx_dmaaddr + + i * sizeof(struct xl_list); if (i == (XL_TX_LIST_CNT - 1)) cd->xl_tx_chain[i].xl_next = NULL; else @@ -1719,24 +1878,31 @@ xl_list_tx_init(sc) cd->xl_tx_free = &cd->xl_tx_chain[0]; cd->xl_tx_tail = cd->xl_tx_head = NULL; + bus_dmamap_sync(ld->xl_tx_tag, ld->xl_tx_dmamap, BUS_DMASYNC_PREWRITE); return(0); } /* * Initialize the transmit descriptors. */ -static int xl_list_tx_init_90xB(sc) +static int +xl_list_tx_init_90xB(sc) struct xl_softc *sc; { struct xl_chain_data *cd; struct xl_list_data *ld; - int i; + int error, i; cd = &sc->xl_cdata; - ld = sc->xl_ldata; + ld = &sc->xl_ldata; for (i = 0; i < XL_TX_LIST_CNT; i++) { cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i]; - cd->xl_tx_chain[i].xl_phys = vtophys(&ld->xl_tx_list[i]); + error = bus_dmamap_create(sc->xl_mtag, 0, + &cd->xl_tx_chain[i].xl_map); + if (error) + return(error); + cd->xl_tx_chain[i].xl_phys = ld->xl_tx_dmaaddr + + i * sizeof(struct xl_list); if (i == (XL_TX_LIST_CNT - 1)) cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[0]; else @@ -1749,14 +1915,14 @@ static int xl_list_tx_init_90xB(sc) &cd->xl_tx_chain[i - 1]; } - bzero((char *)ld->xl_tx_list, - sizeof(struct xl_list) * XL_TX_LIST_CNT); - ld->xl_tx_list[0].xl_status = XL_TXSTAT_EMPTY; + bzero(ld->xl_tx_list, XL_TX_LIST_SZ); + ld->xl_tx_list[0].xl_status = htole32(XL_TXSTAT_EMPTY); cd->xl_tx_prod = 1; cd->xl_tx_cons = 1; cd->xl_tx_cnt = 0; + bus_dmamap_sync(ld->xl_tx_tag, ld->xl_tx_dmamap, BUS_DMASYNC_PREWRITE); return(0); } @@ -1771,27 +1937,32 @@ xl_list_rx_init(sc) { struct xl_chain_data *cd; struct xl_list_data *ld; - int i; + int error, i, next; + u_int32_t nextptr; cd = &sc->xl_cdata; - ld = sc->xl_ldata; + ld = &sc->xl_ldata; for (i = 0; i < XL_RX_LIST_CNT; i++) { - cd->xl_rx_chain[i].xl_ptr = - (struct xl_list_onefrag *)&ld->xl_rx_list[i]; - if (xl_newbuf(sc, &cd->xl_rx_chain[i]) == ENOBUFS) - return(ENOBUFS); - if (i == (XL_RX_LIST_CNT - 1)) { - cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[0]; - ld->xl_rx_list[i].xl_next = - vtophys(&ld->xl_rx_list[0]); - } else { - cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[i + 1]; - ld->xl_rx_list[i].xl_next = - vtophys(&ld->xl_rx_list[i + 1]); - } + cd->xl_rx_chain[i].xl_ptr = &ld->xl_rx_list[i]; + error = bus_dmamap_create(sc->xl_mtag, 0, + &cd->xl_rx_chain[i].xl_map); + if (error) + return(error); + error = xl_newbuf(sc, &cd->xl_rx_chain[i]); + if (error) + return(error); + if (i == (XL_RX_LIST_CNT - 1)) + next = 0; + else + next = i + 1; + nextptr = ld->xl_rx_dmaaddr + + next * sizeof(struct xl_list_onefrag); + cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[next]; + ld->xl_rx_list[i].xl_next = htole32(nextptr); } + bus_dmamap_sync(ld->xl_rx_tag, ld->xl_rx_dmamap, BUS_DMASYNC_PREWRITE); cd->xl_rx_head = &cd->xl_rx_chain[0]; return(0); @@ -1799,6 +1970,8 @@ xl_list_rx_init(sc) /* * Initialize an RX descriptor and attach an MBUF cluster. + * If we fail to do so, we need to leave the old mbuf and + * the old DMA map untouched so that it can be reused. */ static int xl_newbuf(sc, c) @@ -1806,27 +1979,36 @@ xl_newbuf(sc, c) struct xl_chain_onefrag *c; { struct mbuf *m_new = NULL; + bus_dmamap_t map; + int error; + u_int32_t baddr; - MGETHDR(m_new, M_DONTWAIT, MT_DATA); + m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); if (m_new == NULL) return(ENOBUFS); - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - return(ENOBUFS); - } - m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; /* Force longword alignment for packet payload. */ m_adj(m_new, ETHER_ALIGN); + error = bus_dmamap_load_mbuf(sc->xl_mtag, sc->xl_tmpmap, m_new, + xl_dma_map_rxbuf, &baddr, BUS_DMA_NOWAIT); + if (error) { + m_freem(m_new); + printf("xl%d: can't map mbuf (error %d)\n", sc->xl_unit, error); + return(error); + } + + bus_dmamap_unload(sc->xl_mtag, c->xl_map); + map = c->xl_map; + c->xl_map = sc->xl_tmpmap; + sc->xl_tmpmap = map; c->xl_mbuf = m_new; - c->xl_ptr->xl_frag.xl_addr = vtophys(mtod(m_new, caddr_t)); - c->xl_ptr->xl_frag.xl_len = MCLBYTES | XL_LAST_FRAG; + c->xl_ptr->xl_frag.xl_len = htole32(m_new->m_len | XL_LAST_FRAG); c->xl_ptr->xl_status = 0; - + c->xl_ptr->xl_frag.xl_addr = htole32(baddr); + bus_dmamap_sync(sc->xl_mtag, c->xl_map, BUS_DMASYNC_PREREAD); return(0); } @@ -1861,7 +2043,7 @@ static void xl_rxeof(sc) struct xl_softc *sc; { - struct ether_header *eh; + struct ether_header *eh; struct mbuf *m; struct ifnet *ifp; struct xl_chain_onefrag *cur_rx; @@ -1872,9 +2054,21 @@ xl_rxeof(sc) again: - while((rxstat = sc->xl_cdata.xl_rx_head->xl_ptr->xl_status)) { + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, sc->xl_ldata.xl_rx_dmamap, + BUS_DMASYNC_POSTREAD); + while((rxstat = le32toh(sc->xl_cdata.xl_rx_head->xl_ptr->xl_status))) { cur_rx = sc->xl_cdata.xl_rx_head; sc->xl_cdata.xl_rx_head = cur_rx->xl_next; + total_len = rxstat & XL_RXSTAT_LENMASK; + + /* + * Since we have told the chip to allow large frames, + * we need to trap giant frame errors in software. We allow + * a little more than the normal frame size to account for + * frames with VLAN tags. + */ + if (total_len > XL_MAX_FRAMELEN) + rxstat |= (XL_RXSTAT_UP_ERROR|XL_RXSTAT_OVERSIZE); /* * If an error occurs, update stats, clear the @@ -1885,25 +2079,30 @@ again: if (rxstat & XL_RXSTAT_UP_ERROR) { ifp->if_ierrors++; cur_rx->xl_ptr->xl_status = 0; + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); continue; } /* - * If there error bit was not set, the upload complete + * If the error bit was not set, the upload complete * bit should be set which means we have a valid packet. * If not, something truly strange has happened. */ if (!(rxstat & XL_RXSTAT_UP_CMPLT)) { printf("xl%d: bad receive status -- " - "packet dropped", sc->xl_unit); + "packet dropped\n", sc->xl_unit); ifp->if_ierrors++; cur_rx->xl_ptr->xl_status = 0; + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); continue; } /* No errors; receive the packet. */ + bus_dmamap_sync(sc->xl_mtag, cur_rx->xl_map, + BUS_DMASYNC_POSTREAD); m = cur_rx->xl_mbuf; - total_len = cur_rx->xl_ptr->xl_status & XL_RXSTAT_LENMASK; /* * Try to conjure up a new mbuf cluster. If that @@ -1912,11 +2111,15 @@ again: * result in a lost packet, but there's little else we * can do in this situation. */ - if (xl_newbuf(sc, cur_rx) == ENOBUFS) { + if (xl_newbuf(sc, cur_rx)) { ifp->if_ierrors++; cur_rx->xl_ptr->xl_status = 0; + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); continue; } + bus_dmamap_sync(sc->xl_ldata.xl_rx_tag, + sc->xl_ldata.xl_rx_dmamap, BUS_DMASYNC_PREWRITE); ifp->if_ipackets++; eh = mtod(m, struct ether_header *); @@ -1926,7 +2129,7 @@ again: /* Remove header from mbuf and pass it on. */ m_adj(m, sizeof(struct ether_header)); - if (sc->xl_type == XL_TYPE_905B) { + if (ifp->if_capenable & IFCAP_RXCSUM) { /* Do IP checksum checking. */ if (rxstat & XL_RXSTAT_IPCKOK) m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; @@ -1941,6 +2144,7 @@ again: m->m_pkthdr.csum_data = 0xffff; } } + ether_input(ifp, eh, m); } @@ -1960,8 +2164,7 @@ again: CSR_READ_4(sc, XL_UPLIST_STATUS) & XL_PKTSTAT_UP_STALLED) { CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL); xl_wait(sc); - CSR_WRITE_4(sc, XL_UPLIST_PTR, - vtophys(&sc->xl_ldata->xl_rx_list[0])); + CSR_WRITE_4(sc, XL_UPLIST_PTR, sc->xl_ldata.xl_rx_dmaaddr); sc->xl_cdata.xl_rx_head = &sc->xl_cdata.xl_rx_chain[0]; CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL); goto again; @@ -2002,6 +2205,9 @@ xl_txeof(sc) break; sc->xl_cdata.xl_tx_head = cur_tx->xl_next; + bus_dmamap_sync(sc->xl_mtag, cur_tx->xl_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->xl_mtag, cur_tx->xl_map); m_freem(cur_tx->xl_mbuf); cur_tx->xl_mbuf = NULL; ifp->if_opackets++; @@ -2017,7 +2223,7 @@ xl_txeof(sc) if (CSR_READ_4(sc, XL_DMACTL) & XL_DMACTL_DOWN_STALLED || !CSR_READ_4(sc, XL_DOWNLIST_PTR)) { CSR_WRITE_4(sc, XL_DOWNLIST_PTR, - vtophys(sc->xl_cdata.xl_tx_head->xl_ptr)); + sc->xl_cdata.xl_tx_head->xl_phys); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL); } } @@ -2025,7 +2231,8 @@ xl_txeof(sc) return; } -static void xl_txeof_90xB(sc) +static void +xl_txeof_90xB(sc) struct xl_softc *sc; { struct xl_chain *cur_tx = NULL; @@ -2034,15 +2241,21 @@ static void xl_txeof_90xB(sc) ifp = &sc->arpcom.ac_if; + bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap, + BUS_DMASYNC_POSTREAD); idx = sc->xl_cdata.xl_tx_cons; while(idx != sc->xl_cdata.xl_tx_prod) { cur_tx = &sc->xl_cdata.xl_tx_chain[idx]; - if (!(cur_tx->xl_ptr->xl_status & XL_TXSTAT_DL_COMPLETE)) + if (!(le32toh(cur_tx->xl_ptr->xl_status) & + XL_TXSTAT_DL_COMPLETE)) break; if (cur_tx->xl_mbuf != NULL) { + bus_dmamap_sync(sc->xl_mtag, cur_tx->xl_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->xl_mtag, cur_tx->xl_map); m_freem(cur_tx->xl_mbuf); cur_tx->xl_mbuf = NULL; } @@ -2094,7 +2307,7 @@ xl_txeoc(sc) } else { if (sc->xl_cdata.xl_tx_head != NULL) CSR_WRITE_4(sc, XL_DOWNLIST_PTR, - vtophys(sc->xl_cdata.xl_tx_head->xl_ptr)); + sc->xl_cdata.xl_tx_head->xl_phys); } /* * Remember to set this for the @@ -2249,29 +2462,24 @@ xl_encap(sc, c, m_head) struct xl_chain *c; struct mbuf *m_head; { - int frag; - struct xl_frag *f = NULL; - int total_len; - struct mbuf *m; + int error; + u_int32_t status; + struct ifnet *ifp; + + ifp = &sc->arpcom.ac_if; /* * 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. */ - m = m_head; - total_len = 0; + error = bus_dmamap_load_mbuf(sc->xl_mtag, c->xl_map, m_head, + xl_dma_map_txbuf, c->xl_ptr, BUS_DMA_NOWAIT); - for (m = m_head, frag = 0; m != NULL; m = m->m_next) { - if (m->m_len != 0) { - if (frag == XL_MAXFRAGS) - break; - total_len += m->m_len; - f = &c->xl_ptr->xl_frag[frag]; - f->xl_addr = vtophys(mtod(m, vm_offset_t)); - f->xl_len = m->m_len; - frag++; - } + if (error && error != EFBIG) { + m_freem(m_head); + printf("xl%d: can't map mbuf (error %d)\n", sc->xl_unit, error); + return(1); } /* @@ -2282,51 +2490,43 @@ xl_encap(sc, c, m_head) * pointers/counters; it wouldn't gain us anything, * and would waste cycles. */ - if (m != NULL) { - struct mbuf *m_new = NULL; + if (error) { + struct mbuf *m_new; - MGETHDR(m_new, M_DONTWAIT, MT_DATA); + m_new = m_defrag(m_head, M_DONTWAIT); if (m_new == NULL) { - printf("xl%d: no memory for tx list", sc->xl_unit); + m_freem(m_head); return(1); + } else { + m_head = m_new; } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("xl%d: no memory for tx list", - sc->xl_unit); - return(1); - } + + error = bus_dmamap_load_mbuf(sc->xl_mtag, c->xl_map, + m_head, xl_dma_map_txbuf, c->xl_ptr, BUS_DMA_NOWAIT); + if (error) { + m_freem(m_head); + printf("xl%d: can't map mbuf (error %d)\n", + sc->xl_unit, error); + return(1); } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - f = &c->xl_ptr->xl_frag[0]; - f->xl_addr = vtophys(mtod(m_new, caddr_t)); - f->xl_len = total_len = m_new->m_len; } if (sc->xl_type == XL_TYPE_905B) { - c->xl_ptr->xl_status = XL_TXSTAT_RND_DEFEAT; + status = XL_TXSTAT_RND_DEFEAT; if (m_head->m_pkthdr.csum_flags) { if (m_head->m_pkthdr.csum_flags & CSUM_IP) - c->xl_ptr->xl_status |= XL_TXSTAT_IPCKSUM; + status |= XL_TXSTAT_IPCKSUM; if (m_head->m_pkthdr.csum_flags & CSUM_TCP) - c->xl_ptr->xl_status |= XL_TXSTAT_TCPCKSUM; + status |= XL_TXSTAT_TCPCKSUM; if (m_head->m_pkthdr.csum_flags & CSUM_UDP) - c->xl_ptr->xl_status |= XL_TXSTAT_UDPCKSUM; + status |= XL_TXSTAT_UDPCKSUM; } - } else - c->xl_ptr->xl_status = total_len; + c->xl_ptr->xl_status = htole32(status); + } c->xl_mbuf = m_head; - f->xl_len |= XL_LAST_FRAG; - c->xl_ptr->xl_next = 0; - + bus_dmamap_sync(sc->xl_mtag, c->xl_map, BUS_DMASYNC_PREWRITE); return(0); } @@ -2343,9 +2543,11 @@ xl_start(ifp) struct xl_softc *sc; struct mbuf *m_head = NULL; struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx; + struct xl_chain *prev_tx; + u_int32_t status; + int error; sc = ifp->if_softc; - /* * Check for an available queue slot. If there are none, * punt. @@ -2367,18 +2569,23 @@ xl_start(ifp) break; /* Pick a descriptor off the free list. */ + prev_tx = cur_tx; cur_tx = sc->xl_cdata.xl_tx_free; - sc->xl_cdata.xl_tx_free = cur_tx->xl_next; - - cur_tx->xl_next = NULL; /* Pack the data into the descriptor. */ - xl_encap(sc, cur_tx, m_head); + error = xl_encap(sc, cur_tx, m_head); + if (error) { + cur_tx = prev_tx; + continue; + } + + sc->xl_cdata.xl_tx_free = cur_tx->xl_next; + cur_tx->xl_next = NULL; /* Chain it together. */ if (prev != NULL) { prev->xl_next = cur_tx; - prev->xl_ptr->xl_next = vtophys(cur_tx->xl_ptr); + prev->xl_ptr->xl_next = htole32(cur_tx->xl_phys); } prev = cur_tx; @@ -2393,8 +2600,9 @@ xl_start(ifp) /* * If there are no packets queued, bail. */ - if (cur_tx == NULL) + if (cur_tx == NULL) { return; + } /* * Place the request for the upload interrupt @@ -2403,7 +2611,10 @@ xl_start(ifp) * get an interupt once for the whole chain rather than * once for each packet. */ - cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR; + cur_tx->xl_ptr->xl_status = htole32(le32toh(cur_tx->xl_ptr->xl_status) | + XL_TXSTAT_DL_INTR); + bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap, + BUS_DMASYNC_PREWRITE); /* * Queue the packets. If the TX channel is clear, update @@ -2415,16 +2626,17 @@ xl_start(ifp) if (sc->xl_cdata.xl_tx_head != NULL) { sc->xl_cdata.xl_tx_tail->xl_next = start_tx; sc->xl_cdata.xl_tx_tail->xl_ptr->xl_next = - vtophys(start_tx->xl_ptr); - sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status &= - ~XL_TXSTAT_DL_INTR; + htole32(start_tx->xl_phys); + status = sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status; + sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status = + htole32(le32toh(status) & ~XL_TXSTAT_DL_INTR); sc->xl_cdata.xl_tx_tail = cur_tx; } else { sc->xl_cdata.xl_tx_head = start_tx; sc->xl_cdata.xl_tx_tail = cur_tx; } if (!CSR_READ_4(sc, XL_DOWNLIST_PTR)) - CSR_WRITE_4(sc, XL_DOWNLIST_PTR, vtophys(start_tx->xl_ptr)); + CSR_WRITE_4(sc, XL_DOWNLIST_PTR, start_tx->xl_phys); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL); @@ -2455,18 +2667,21 @@ xl_start(ifp) return; } -static void xl_start_90xB(ifp) +static void +xl_start_90xB(ifp) struct ifnet *ifp; { struct xl_softc *sc; struct mbuf *m_head = NULL; struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx; - int idx; + struct xl_chain *prev_tx; + int error, idx; sc = ifp->if_softc; - if (ifp->if_flags & IFF_OACTIVE) + if (ifp->if_flags & IFF_OACTIVE) { return; + } idx = sc->xl_cdata.xl_tx_prod; start_tx = &sc->xl_cdata.xl_tx_chain[idx]; @@ -2482,14 +2697,19 @@ static void xl_start_90xB(ifp) if (m_head == NULL) break; + prev_tx = cur_tx; cur_tx = &sc->xl_cdata.xl_tx_chain[idx]; /* Pack the data into the descriptor. */ - xl_encap(sc, cur_tx, m_head); + error = xl_encap(sc, cur_tx, m_head); + if (error) { + cur_tx = prev_tx; + continue; + } /* Chain it together. */ if (prev != NULL) - prev->xl_ptr->xl_next = cur_tx->xl_phys; + prev->xl_ptr->xl_next = htole32(cur_tx->xl_phys); prev = cur_tx; /* @@ -2506,8 +2726,9 @@ static void xl_start_90xB(ifp) /* * If there are no packets queued, bail. */ - if (cur_tx == NULL) + if (cur_tx == NULL) { return; + } /* * Place the request for the upload interrupt @@ -2516,11 +2737,14 @@ static void xl_start_90xB(ifp) * get an interupt once for the whole chain rather than * once for each packet. */ - cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR; + cur_tx->xl_ptr->xl_status = htole32(le32toh(cur_tx->xl_ptr->xl_status) | + XL_TXSTAT_DL_INTR); + bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap, + BUS_DMASYNC_PREWRITE); /* Start transmission */ sc->xl_cdata.xl_tx_prod = idx; - start_tx->xl_prev->xl_ptr->xl_next = start_tx->xl_phys; + start_tx->xl_prev->xl_ptr->xl_next = htole32(start_tx->xl_phys); /* * Set a timeout in case the chip goes out to lunch. @@ -2536,9 +2760,10 @@ xl_init(xsc) { struct xl_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; - int s, i; + int error, i; u_int16_t rxfilt = 0; struct mii_data *mii = NULL; + int s; s = splimp(); @@ -2576,9 +2801,10 @@ xl_init(xsc) xl_wait(sc); #endif /* Init circular RX list. */ - if (xl_list_rx_init(sc) == ENOBUFS) { - printf("xl%d: initialization failed: no " - "memory for rx buffers\n", sc->xl_unit); + error = xl_list_rx_init(sc); + if (error) { + printf("xl%d: initialization of the rx ring failed (%d)\n", + sc->xl_unit, error); xl_stop(sc); splx(s); return; @@ -2586,9 +2812,15 @@ xl_init(xsc) /* Init TX descriptors. */ if (sc->xl_type == XL_TYPE_905B) - xl_list_tx_init_90xB(sc); + error = xl_list_tx_init_90xB(sc); else - xl_list_tx_init(sc); + error = xl_list_tx_init(sc); + if (error) { + printf("xl%d: initialization of the tx ring failed (%d)\n", + sc->xl_unit, error); + xl_stop(sc); + splx(s); + } /* * Set the TX freethresh value. @@ -2663,7 +2895,7 @@ xl_init(xsc) */ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL); xl_wait(sc); - CSR_WRITE_4(sc, XL_UPLIST_PTR, vtophys(&sc->xl_ldata->xl_rx_list[0])); + CSR_WRITE_4(sc, XL_UPLIST_PTR, sc->xl_ldata.xl_rx_dmaaddr); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL); xl_wait(sc); @@ -2675,7 +2907,7 @@ xl_init(xsc) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL); xl_wait(sc); CSR_WRITE_4(sc, XL_DOWNLIST_PTR, - vtophys(&sc->xl_ldata->xl_tx_list[0])); + sc->xl_cdata.xl_tx_chain[0].xl_phys); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL); xl_wait(sc); } @@ -2690,9 +2922,22 @@ xl_init(xsc) else CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); - /* increase packet size to allow reception of 802.1q or ISL packets */ - if (sc->xl_type == XL_TYPE_905B) + /* + * increase packet size to allow reception of 802.1q or ISL packets. + * For the 3c90x chip, set the 'allow large packets' bit in the MAC + * control register. For 3c90xB/C chips, use the RX packet size + * register. + */ + + if (sc->xl_type == XL_TYPE_905B) CSR_WRITE_2(sc, XL_W3_MAXPKTSIZE, XL_PACKET_SIZE); + else { + u_int8_t macctl; + macctl = CSR_READ_1(sc, XL_W3_MAC_CTRL); + macctl |= XL_MACCTRL_ALLOW_LARGE_PACK; + CSR_WRITE_1(sc, XL_W3_MAC_CTRL, macctl); + } + /* Clear out the stats counters. */ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE); sc->xl_stats_no_timeout = 1; @@ -2708,7 +2953,8 @@ xl_init(xsc) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS); - if (sc->xl_flags & XL_FLAG_FUNCREG) bus_space_write_4 (sc->xl_ftag, sc->xl_fhandle, 4, 0x8000); + if (sc->xl_flags & XL_FLAG_FUNCREG) + bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, 4, 0x8000); /* Set the RX early threshold */ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_THRESH|(XL_PACKET_SIZE >>2)); @@ -2729,10 +2975,10 @@ xl_init(xsc) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - (void)splx(s); - sc->xl_stat_ch = timeout(xl_stats_update, sc, hz); + splx(s); + return; } @@ -2853,9 +3099,10 @@ xl_ioctl(ifp, command, data) { struct xl_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; + int error = 0; struct mii_data *mii = NULL; u_int8_t rxfilt; + int s; s = splimp(); @@ -2911,13 +3158,19 @@ xl_ioctl(ifp, command, data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; + case SIOCSIFCAP: + ifp->if_capenable = ifr->ifr_reqcap; + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist = XL905B_CSUM_FEATURES; + else + ifp->if_hwassist = 0; + break; default: error = EINVAL; break; } - (void)splx(s); - + splx(s); return(error); } @@ -2993,23 +3246,29 @@ xl_stop(sc) */ for (i = 0; i < XL_RX_LIST_CNT; i++) { if (sc->xl_cdata.xl_rx_chain[i].xl_mbuf != NULL) { + bus_dmamap_unload(sc->xl_mtag, + sc->xl_cdata.xl_rx_chain[i].xl_map); + bus_dmamap_destroy(sc->xl_mtag, + sc->xl_cdata.xl_rx_chain[i].xl_map); m_freem(sc->xl_cdata.xl_rx_chain[i].xl_mbuf); sc->xl_cdata.xl_rx_chain[i].xl_mbuf = NULL; } } - bzero((char *)&sc->xl_ldata->xl_rx_list, - sizeof(sc->xl_ldata->xl_rx_list)); + bzero(sc->xl_ldata.xl_rx_list, XL_RX_LIST_SZ); /* * Free the TX list buffers. */ for (i = 0; i < XL_TX_LIST_CNT; i++) { if (sc->xl_cdata.xl_tx_chain[i].xl_mbuf != NULL) { + bus_dmamap_unload(sc->xl_mtag, + sc->xl_cdata.xl_tx_chain[i].xl_map); + bus_dmamap_destroy(sc->xl_mtag, + sc->xl_cdata.xl_tx_chain[i].xl_map); m_freem(sc->xl_cdata.xl_tx_chain[i].xl_mbuf); sc->xl_cdata.xl_tx_chain[i].xl_mbuf = NULL; } } - bzero((char *)&sc->xl_ldata->xl_tx_list, - sizeof(sc->xl_ldata->xl_tx_list)); + bzero(sc->xl_ldata.xl_tx_list, XL_TX_LIST_SZ); ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); @@ -3041,10 +3300,12 @@ xl_suspend(dev) struct xl_softc *sc; int s; + s = splimp(); + sc = device_get_softc(dev); - s = splimp(); xl_stop(sc); + splx(s); return(0); @@ -3059,6 +3320,7 @@ xl_resume(dev) int s; s = splimp(); + sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; diff --git a/sys/dev/netif/xl/if_xlreg.h b/sys/dev/netif/xl/if_xlreg.h index bf6ca1af1f..e2f4255313 100644 --- a/sys/dev/netif/xl/if_xlreg.h +++ b/sys/dev/netif/xl/if_xlreg.h @@ -29,8 +29,8 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/if_xlreg.h,v 1.25.2.7 2003/01/25 23:00:10 silby Exp $ - * $DragonFly: src/sys/dev/netif/xl/if_xlreg.h,v 1.2 2003/06/17 04:28:57 dillon Exp $ + * $FreeBSD: src/sys/pci/if_xlreg.h,v 1.25.2.8 2003/08/10 21:55:57 silby Exp $ + * $DragonFly: src/sys/dev/netif/xl/if_xlreg.h,v 1.3 2004/01/24 06:34:02 dillon Exp $ */ #define XL_EE_READ 0x0080 /* read, 5 bit address */ @@ -83,7 +83,11 @@ #define XL_CAPS_PWRMGMT 0x2000 #define XL_PACKET_SIZE 1540 - +#ifndef ETHER_VLAN_ENCAP_LEN +#define ETHER_VLAN_ENCAP_LEN 4 +#endif +#define XL_MAX_FRAMELEN (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) + /* * Register layouts. */ @@ -421,6 +425,15 @@ #define XL_LAST_FRAG 0x80000000 +#define XL_MAXFRAGS 63 +#define XL_RX_LIST_CNT 128 +#define XL_TX_LIST_CNT 256 +#define XL_RX_LIST_SZ XL_RX_LIST_CNT * sizeof(struct xl_list_onefrag) +#define XL_TX_LIST_SZ XL_TX_LIST_CNT * sizeof(struct xl_list) +#define XL_MIN_FRAMELEN 60 +#define ETHER_ALIGN 2 +#define XL_INC(x, y) (x) = (x + 1) % y + /* * Boomerang/Cyclone TX/RX list structure. * For the TX lists, bits 0 to 12 of the status word indicate @@ -435,7 +448,7 @@ struct xl_frag { struct xl_list { u_int32_t xl_next; /* final entry has 0 nextptr */ u_int32_t xl_status; - struct xl_frag xl_frag[63]; + struct xl_frag xl_frag[XL_MAXFRAGS]; }; struct xl_list_onefrag { @@ -444,17 +457,15 @@ struct xl_list_onefrag { struct xl_frag xl_frag; }; -#define XL_MAXFRAGS 63 -#define XL_RX_LIST_CNT 128 -#define XL_TX_LIST_CNT 256 -#define XL_MIN_FRAMELEN 60 -#define ETHER_ALIGN 2 -#define XL_INC(x, y) (x) = (x + 1) % y - struct xl_list_data { - struct xl_list_onefrag xl_rx_list[XL_RX_LIST_CNT]; - struct xl_list xl_tx_list[XL_TX_LIST_CNT]; - unsigned char xl_pad[XL_MIN_FRAMELEN]; + struct xl_list_onefrag *xl_rx_list; + struct xl_list *xl_tx_list; + u_int32_t xl_rx_dmaaddr; + bus_dma_tag_t xl_rx_tag; + bus_dmamap_t xl_rx_dmamap; + u_int32_t xl_tx_dmaaddr; + bus_dma_tag_t xl_tx_tag; + bus_dmamap_t xl_tx_dmamap; }; struct xl_chain { @@ -463,12 +474,14 @@ struct xl_chain { struct xl_chain *xl_next; struct xl_chain *xl_prev; u_int32_t xl_phys; + bus_dmamap_t xl_map; }; struct xl_chain_onefrag { struct xl_list_onefrag *xl_ptr; struct mbuf *xl_mbuf; struct xl_chain_onefrag *xl_next; + bus_dmamap_t xl_map; }; struct xl_chain_data { @@ -562,6 +575,7 @@ struct xl_mii_frame { #define XL_FLAG_INVERT_LED_PWR 0x0020 #define XL_FLAG_INVERT_MII_PWR 0x0040 #define XL_FLAG_NO_XCVR_PWR 0x0080 +#define XL_FLAG_USE_MMIO 0x0100 #define XL_NO_XCVR_PWR_MAGICBITS 0x0900 @@ -575,6 +589,8 @@ struct xl_softc { struct resource *xl_res; device_t xl_miibus; struct xl_type *xl_info; /* 3Com adapter info */ + bus_dma_tag_t xl_mtag; + bus_dmamap_t xl_tmpmap; /* spare DMA map */ u_int8_t xl_unit; /* interface number */ u_int8_t xl_type; u_int32_t xl_xcvr; @@ -583,7 +599,7 @@ struct xl_softc { u_int8_t xl_stats_no_timeout; u_int16_t xl_tx_thresh; int xl_if_flags; - struct xl_list_data *xl_ldata; + struct xl_list_data xl_ldata; struct xl_chain_data xl_cdata; struct callout_handle xl_stat_ch; int xl_flags; @@ -711,12 +727,6 @@ struct xl_stats { #define XL_PME_EN 0x0010 #define XL_PME_STATUS 0x8000 -#ifdef __alpha__ -#undef vtophys -#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va) - -#endif - #ifndef IFM_10_FL #define IFM_10_FL 13 /* 10baseFL - Fiber */ #endif -- 2.41.0