Date: Sat, 28 May 2011 11:07:30 GMT From: cumay <164837122@qq.com> To: freebsd-gnats-submit@FreeBSD.org Subject: i386/157378: fxp.ich.patch Message-ID: <201105281107.p4SB7U7D012249@red.freebsd.org> Resent-Message-ID: <201105281110.p4SBA9RM042296@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 157378 >Category: i386 >Synopsis: fxp.ich.patch >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-i386 >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat May 28 11:10:09 UTC 2011 >Closed-Date: >Last-Modified: >Originator: cumay >Release: freebsd 4.11 >Organization: no >Environment: freebsd 4.11 >Description: I got a patch fxp.ich.patch whitch can fix this problem .but it can't be used for freebsd 4.11. badlly expecting freebsd team can modify fxp.ich.patch for freebsd 4.11. I like 4.11 very much. Thanks for your great help. >How-To-Repeat: I got a patch fxp.ich.patch whitch can fix this problem .but it can't be used for freebsd 4.11. badlly expecting freebsd team can modify fxp.ich.patch for freebsd 4.11. I like 4.11 very much. Thanks for your great help. >Fix: Patch attached with submission follows: Index: sys/dev/fxp/if_fxpvar.h =================================================================== --- sys/dev/fxp/if_fxpvar.h (revision 194231) +++ sys/dev/fxp/if_fxpvar.h (working copy) @@ -142,6 +142,13 @@ bus_dma_tag_t rx_tag; }; +struct fxp_ident { + uint16_t devid; + int16_t revid; /* -1 matches anything */ + uint8_t ich; + char *name; +}; + /* * NOTE: Elements are ordered for optimal cacheline behavior, and NOT * for functional grouping. @@ -151,8 +158,10 @@ struct resource *fxp_res[2]; /* I/O and IRQ resources */ struct resource_spec *fxp_spec; /* the resource spec we used */ void *ih; /* interrupt handler cookie */ + struct fxp_ident *ident; struct mtx sc_mtx; - bus_dma_tag_t fxp_mtag; /* bus DMA tag for mbufs */ + bus_dma_tag_t fxp_txmtag; /* bus DMA tag for Tx mbufs */ + bus_dma_tag_t fxp_rxmtag; /* bus DMA tag for Rx mbufs */ bus_dma_tag_t fxp_stag; /* bus DMA tag for stats */ bus_dmamap_t fxp_smap; /* bus DMA map for stats */ bus_dma_tag_t cbl_tag; /* DMA tag for the TxCB list */ @@ -164,7 +173,6 @@ int maxtxseg; /* maximum # of TX segments */ int maxsegsize; /* maximum size of a TX segment */ int tx_queued; /* # of active TxCB's */ - int need_mcsetup; /* multicast filter needs programming */ struct fxp_stats *fxp_stats; /* Pointer to interface stats */ uint32_t stats_addr; /* DMA address of the stats structure */ int rx_idle_secs; /* # of seconds RX has been idle */ @@ -184,6 +192,7 @@ int cu_resume_bug; int revision; int flags; + int if_flags; uint8_t rfa_size; uint32_t tx_cmd; }; @@ -194,7 +203,6 @@ #define FXP_FLAG_EXT_TXCB 0x0008 /* enable use of extended TXCB */ #define FXP_FLAG_SERIAL_MEDIA 0x0010 /* 10Mbps serial interface */ #define FXP_FLAG_LONG_PKT_EN 0x0020 /* enable long packet reception */ -#define FXP_FLAG_ALL_MCAST 0x0040 /* accept all multicast frames */ #define FXP_FLAG_CU_RESUME_BUG 0x0080 /* requires workaround for CU_RESUME */ #define FXP_FLAG_UCODE 0x0100 /* ucode is loaded */ #define FXP_FLAG_DEFERRED_RNR 0x0200 /* DEVICE_POLLING deferred RNR */ @@ -203,6 +211,7 @@ #define FXP_FLAG_82559_RXCSUM 0x1000 /* 82559 compatible RX checksum */ #define FXP_FLAG_WOLCAP 0x2000 /* WOL capability */ #define FXP_FLAG_WOL 0x4000 /* WOL active */ +#define FXP_FLAG_RXBUG 0x8000 /* Rx lock-up bug */ /* Macros to ease CSR access. */ #define CSR_READ_1(sc, reg) bus_read_1(sc->fxp_res[0], reg) Index: sys/dev/fxp/if_fxp.c =================================================================== --- sys/dev/fxp/if_fxp.c (revision 194231) +++ sys/dev/fxp/if_fxp.c (working copy) @@ -140,12 +140,6 @@ 0x5 /* 21 */ }; -struct fxp_ident { - uint16_t devid; - int16_t revid; /* -1 matches anything */ - char *name; -}; - /* * Claim various Intel PCI device identifiers for this driver. The * sub-vendor and sub-device field are extensively used to identify @@ -153,52 +147,52 @@ * them. */ static struct fxp_ident fxp_ident_table[] = { - { 0x1029, -1, "Intel 82559 PCI/CardBus Pro/100" }, - { 0x1030, -1, "Intel 82559 Pro/100 Ethernet" }, - { 0x1031, -1, "Intel 82801CAM (ICH3) Pro/100 VE Ethernet" }, - { 0x1032, -1, "Intel 82801CAM (ICH3) Pro/100 VE Ethernet" }, - { 0x1033, -1, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, - { 0x1034, -1, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, - { 0x1035, -1, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, - { 0x1036, -1, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, - { 0x1037, -1, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, - { 0x1038, -1, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, - { 0x1039, -1, "Intel 82801DB (ICH4) Pro/100 VE Ethernet" }, - { 0x103A, -1, "Intel 82801DB (ICH4) Pro/100 Ethernet" }, - { 0x103B, -1, "Intel 82801DB (ICH4) Pro/100 VM Ethernet" }, - { 0x103C, -1, "Intel 82801DB (ICH4) Pro/100 Ethernet" }, - { 0x103D, -1, "Intel 82801DB (ICH4) Pro/100 VE Ethernet" }, - { 0x103E, -1, "Intel 82801DB (ICH4) Pro/100 VM Ethernet" }, - { 0x1050, -1, "Intel 82801BA (D865) Pro/100 VE Ethernet" }, - { 0x1051, -1, "Intel 82562ET (ICH5/ICH5R) Pro/100 VE Ethernet" }, - { 0x1059, -1, "Intel 82551QM Pro/100 M Mobile Connection" }, - { 0x1064, -1, "Intel 82562EZ (ICH6)" }, - { 0x1065, -1, "Intel 82562ET/EZ/GT/GZ PRO/100 VE Ethernet" }, - { 0x1068, -1, "Intel 82801FBM (ICH6-M) Pro/100 VE Ethernet" }, - { 0x1069, -1, "Intel 82562EM/EX/GX Pro/100 Ethernet" }, - { 0x1091, -1, "Intel 82562GX Pro/100 Ethernet" }, - { 0x1092, -1, "Intel Pro/100 VE Network Connection" }, - { 0x1093, -1, "Intel Pro/100 VM Network Connection" }, - { 0x1094, -1, "Intel Pro/100 946GZ (ICH7) Network Connection" }, - { 0x1209, -1, "Intel 82559ER Embedded 10/100 Ethernet" }, - { 0x1229, 0x01, "Intel 82557 Pro/100 Ethernet" }, - { 0x1229, 0x02, "Intel 82557 Pro/100 Ethernet" }, - { 0x1229, 0x03, "Intel 82557 Pro/100 Ethernet" }, - { 0x1229, 0x04, "Intel 82558 Pro/100 Ethernet" }, - { 0x1229, 0x05, "Intel 82558 Pro/100 Ethernet" }, - { 0x1229, 0x06, "Intel 82559 Pro/100 Ethernet" }, - { 0x1229, 0x07, "Intel 82559 Pro/100 Ethernet" }, - { 0x1229, 0x08, "Intel 82559 Pro/100 Ethernet" }, - { 0x1229, 0x09, "Intel 82559ER Pro/100 Ethernet" }, - { 0x1229, 0x0c, "Intel 82550 Pro/100 Ethernet" }, - { 0x1229, 0x0d, "Intel 82550 Pro/100 Ethernet" }, - { 0x1229, 0x0e, "Intel 82550 Pro/100 Ethernet" }, - { 0x1229, 0x0f, "Intel 82551 Pro/100 Ethernet" }, - { 0x1229, 0x10, "Intel 82551 Pro/100 Ethernet" }, - { 0x1229, -1, "Intel 82557/8/9 Pro/100 Ethernet" }, - { 0x2449, -1, "Intel 82801BA/CAM (ICH2/3) Pro/100 Ethernet" }, - { 0x27dc, -1, "Intel 82801GB (ICH7) 10/100 Ethernet" }, - { 0, -1, NULL }, + { 0x1029, -1, 0, "Intel 82559 PCI/CardBus Pro/100" }, + { 0x1030, -1, 0, "Intel 82559 Pro/100 Ethernet" }, + { 0x1031, -1, 3, "Intel 82801CAM (ICH3) Pro/100 VE Ethernet" }, + { 0x1032, -1, 3, "Intel 82801CAM (ICH3) Pro/100 VE Ethernet" }, + { 0x1033, -1, 3, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, + { 0x1034, -1, 3, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, + { 0x1035, -1, 3, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, + { 0x1036, -1, 3, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, + { 0x1037, -1, 3, "Intel 82801CAM (ICH3) Pro/100 Ethernet" }, + { 0x1038, -1, 3, "Intel 82801CAM (ICH3) Pro/100 VM Ethernet" }, + { 0x1039, -1, 4, "Intel 82801DB (ICH4) Pro/100 VE Ethernet" }, + { 0x103A, -1, 4, "Intel 82801DB (ICH4) Pro/100 Ethernet" }, + { 0x103B, -1, 4, "Intel 82801DB (ICH4) Pro/100 VM Ethernet" }, + { 0x103C, -1, 4, "Intel 82801DB (ICH4) Pro/100 Ethernet" }, + { 0x103D, -1, 4, "Intel 82801DB (ICH4) Pro/100 VE Ethernet" }, + { 0x103E, -1, 4, "Intel 82801DB (ICH4) Pro/100 VM Ethernet" }, + { 0x1050, -1, 5, "Intel 82801BA (D865) Pro/100 VE Ethernet" }, + { 0x1051, -1, 5, "Intel 82562ET (ICH5/ICH5R) Pro/100 VE Ethernet" }, + { 0x1059, -1, 0, "Intel 82551QM Pro/100 M Mobile Connection" }, + { 0x1064, -1, 6, "Intel 82562EZ (ICH6)" }, + { 0x1065, -1, 6, "Intel 82562ET/EZ/GT/GZ PRO/100 VE Ethernet" }, + { 0x1068, -1, 6, "Intel 82801FBM (ICH6-M) Pro/100 VE Ethernet" }, + { 0x1069, -1, 6, "Intel 82562EM/EX/GX Pro/100 Ethernet" }, + { 0x1091, -1, 7, "Intel 82562GX Pro/100 Ethernet" }, + { 0x1092, -1, 7, "Intel Pro/100 VE Network Connection" }, + { 0x1093, -1, 7, "Intel Pro/100 VM Network Connection" }, + { 0x1094, -1, 7, "Intel Pro/100 946GZ (ICH7) Network Connection" }, + { 0x1209, -1, 0, "Intel 82559ER Embedded 10/100 Ethernet" }, + { 0x1229, 0x01, 0, "Intel 82557 Pro/100 Ethernet" }, + { 0x1229, 0x02, 0, "Intel 82557 Pro/100 Ethernet" }, + { 0x1229, 0x03, 0, "Intel 82557 Pro/100 Ethernet" }, + { 0x1229, 0x04, 0, "Intel 82558 Pro/100 Ethernet" }, + { 0x1229, 0x05, 0, "Intel 82558 Pro/100 Ethernet" }, + { 0x1229, 0x06, 0, "Intel 82559 Pro/100 Ethernet" }, + { 0x1229, 0x07, 0, "Intel 82559 Pro/100 Ethernet" }, + { 0x1229, 0x08, 0, "Intel 82559 Pro/100 Ethernet" }, + { 0x1229, 0x09, 0, "Intel 82559ER Pro/100 Ethernet" }, + { 0x1229, 0x0c, 0, "Intel 82550 Pro/100 Ethernet" }, + { 0x1229, 0x0d, 0, "Intel 82550 Pro/100 Ethernet" }, + { 0x1229, 0x0e, 0, "Intel 82550 Pro/100 Ethernet" }, + { 0x1229, 0x0f, 0, "Intel 82551 Pro/100 Ethernet" }, + { 0x1229, 0x10, 0, "Intel 82551 Pro/100 Ethernet" }, + { 0x1229, -1, 0, "Intel 82557/8/9 Pro/100 Ethernet" }, + { 0x2449, -1, 2, "Intel 82801BA/CAM (ICH2/3) Pro/100 Ethernet" }, + { 0x27dc, -1, 7, "Intel 82801GB (ICH7) 10/100 Ethernet" }, + { 0, -1, 0, NULL }, }; #ifdef FXP_IP_CSUM_WAR @@ -214,6 +208,7 @@ static int fxp_suspend(device_t dev); static int fxp_resume(device_t dev); +static struct fxp_ident *fxp_find_ident(device_t dev); static void fxp_intr(void *xsc); static void fxp_rxcsum(struct fxp_softc *sc, struct ifnet *ifp, struct mbuf *m, uint16_t status, int pos); @@ -360,11 +355,8 @@ device_printf(sc->dev, "DMA timeout\n"); } -/* - * Return identification string if this device is ours. - */ -static int -fxp_probe(device_t dev) +static struct fxp_ident * +fxp_find_ident(device_t dev) { uint16_t devid; uint8_t revid; @@ -376,11 +368,26 @@ for (ident = fxp_ident_table; ident->name != NULL; ident++) { if (ident->devid == devid && (ident->revid == revid || ident->revid == -1)) { - device_set_desc(dev, ident->name); - return (BUS_PROBE_DEFAULT); + return (ident); } } } + return (NULL); +} + +/* + * Return identification string if this device is ours. + */ +static int +fxp_probe(device_t dev) +{ + struct fxp_ident *ident; + + ident = fxp_find_ident(dev); + if (ident != NULL) { + device_set_desc(dev, ident->name); + return (BUS_PROBE_DEFAULT); + } return (ENXIO); } @@ -466,10 +473,14 @@ } /* - * Reset to a stable state. + * Put CU/RU idle state and prepare full reset. */ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); DELAY(10); + /* Full reset and disable interrupts. */ + CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SOFTWARE_RESET); + DELAY(10); + CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE); /* * Find out how large of an SEEPROM we have. @@ -479,11 +490,17 @@ /* * Find out the chip revision; lump all 82557 revs together. */ - fxp_read_eeprom(sc, &data, 5, 1); - if ((data >> 8) == 1) - sc->revision = FXP_REV_82557; - else - sc->revision = pci_get_revid(dev); + sc->ident = fxp_find_ident(dev); + if (sc->ident->ich > 0) { + /* Assume ICH controllers are 82559. */ + sc->revision = FXP_REV_82559_A0; + } else { + fxp_read_eeprom(sc, &data, 5, 1); + if ((data >> 8) == 1) + sc->revision = FXP_REV_82557; + else + sc->revision = pci_get_revid(dev); + } /* * Check availability of WOL. 82559ER does not support WOL. @@ -496,6 +513,13 @@ sc->flags |= FXP_FLAG_WOLCAP; } + /* Receiver lock-up workaround detection. */ + fxp_read_eeprom(sc, &data, 3, 1); + if ((data & 0x03) != 0x03) { + sc->flags |= FXP_FLAG_RXBUG; + device_printf(dev, "Enabling Rx lock-up workaround\n"); + } + /* * Determine whether we must use the 503 serial interface. */ @@ -549,9 +573,8 @@ * * See Intel 82801BA/82801BAM Specification Update, Errata #30. */ - i = pci_get_device(dev); - if (i == 0x2449 || (i > 0x1030 && i < 0x1039) || - sc->revision >= FXP_REV_82559_A0) { + if ((sc->ident->ich >= 2 && sc->ident->ich <= 3) || + (sc->ident->ich == 0 && sc->revision >= FXP_REV_82559_A0)) { fxp_read_eeprom(sc, &data, 10, 1); if (data & 0x02) { /* STB enable */ uint16_t cksum; @@ -642,29 +665,40 @@ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, sc->maxsegsize * sc->maxtxseg + sizeof(struct ether_vlan_header), sc->maxtxseg, sc->maxsegsize, 0, - busdma_lock_mutex, &Giant, &sc->fxp_mtag); + busdma_lock_mutex, &Giant, &sc->fxp_txmtag); if (error) { - device_printf(dev, "could not allocate dma tag\n"); + device_printf(dev, "could not create TX DMA tag\n"); goto fail; } + error = bus_dma_tag_create(bus_get_dma_tag(dev), 2, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + MCLBYTES, 1, MCLBYTES, 0, + busdma_lock_mutex, &Giant, &sc->fxp_rxmtag); + if (error) { + device_printf(dev, "could not create RX DMA tag\n"); + goto fail; + } + error = bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, sizeof(struct fxp_stats), 1, sizeof(struct fxp_stats), 0, busdma_lock_mutex, &Giant, &sc->fxp_stag); if (error) { - device_printf(dev, "could not allocate dma tag\n"); + device_printf(dev, "could not create stats DMA tag\n"); goto fail; } error = bus_dmamem_alloc(sc->fxp_stag, (void **)&sc->fxp_stats, BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->fxp_smap); - if (error) + if (error) { + device_printf(dev, "could not allocate stats DMA memory\n"); goto fail; + } error = bus_dmamap_load(sc->fxp_stag, sc->fxp_smap, sc->fxp_stats, sizeof(struct fxp_stats), fxp_dma_map_addr, &sc->stats_addr, 0); if (error) { - device_printf(dev, "could not map the stats buffer\n"); + device_printf(dev, "could not load the stats DMA buffer\n"); goto fail; } @@ -673,20 +707,22 @@ FXP_TXCB_SZ, 1, FXP_TXCB_SZ, 0, busdma_lock_mutex, &Giant, &sc->cbl_tag); if (error) { - device_printf(dev, "could not allocate dma tag\n"); + device_printf(dev, "could not create TxCB DMA tag\n"); goto fail; } error = bus_dmamem_alloc(sc->cbl_tag, (void **)&sc->fxp_desc.cbl_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->cbl_map); - if (error) + if (error) { + device_printf(dev, "could not allocate TxCB DMA memory\n"); goto fail; + } error = bus_dmamap_load(sc->cbl_tag, sc->cbl_map, sc->fxp_desc.cbl_list, FXP_TXCB_SZ, fxp_dma_map_addr, &sc->fxp_desc.cbl_addr, 0); if (error) { - device_printf(dev, "could not map DMA memory\n"); + device_printf(dev, "could not load TxCB DMA buffer\n"); goto fail; } @@ -695,18 +731,23 @@ sizeof(struct fxp_cb_mcs), 1, sizeof(struct fxp_cb_mcs), 0, busdma_lock_mutex, &Giant, &sc->mcs_tag); if (error) { - device_printf(dev, "could not allocate dma tag\n"); + device_printf(dev, + "could not create multicast setup DMA tag\n"); goto fail; } error = bus_dmamem_alloc(sc->mcs_tag, (void **)&sc->mcsp, - BUS_DMA_NOWAIT, &sc->mcs_map); - if (error) + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->mcs_map); + if (error) { + device_printf(dev, + "could not allocate multicast setup DMA memory\n"); goto fail; + } error = bus_dmamap_load(sc->mcs_tag, sc->mcs_map, sc->mcsp, sizeof(struct fxp_cb_mcs), fxp_dma_map_addr, &sc->mcs_addr, 0); if (error) { - device_printf(dev, "can't map the multicast setup command\n"); + device_printf(dev, + "can't load the multicast setup DMA buffer\n"); goto fail; } @@ -718,13 +759,13 @@ tcbp = sc->fxp_desc.cbl_list; for (i = 0; i < FXP_NTXCB; i++) { txp[i].tx_cb = tcbp + i; - error = bus_dmamap_create(sc->fxp_mtag, 0, &txp[i].tx_map); + error = bus_dmamap_create(sc->fxp_txmtag, 0, &txp[i].tx_map); if (error) { device_printf(dev, "can't create DMA map for TX\n"); goto fail; } } - error = bus_dmamap_create(sc->fxp_mtag, 0, &sc->spare_map); + error = bus_dmamap_create(sc->fxp_rxmtag, 0, &sc->spare_map); if (error) { device_printf(dev, "can't create spare DMA map\n"); goto fail; @@ -736,7 +777,7 @@ sc->fxp_desc.rx_head = sc->fxp_desc.rx_tail = NULL; for (i = 0; i < FXP_NRFABUFS; i++) { rxp = &sc->fxp_desc.rx_list[i]; - error = bus_dmamap_create(sc->fxp_mtag, 0, &rxp->rx_map); + error = bus_dmamap_create(sc->fxp_rxmtag, 0, &rxp->rx_map); if (error) { device_printf(dev, "can't create DMA map for RX\n"); goto fail; @@ -910,29 +951,32 @@ bus_dmamem_free(sc->mcs_tag, sc->mcsp, sc->mcs_map); } bus_release_resources(sc->dev, sc->fxp_spec, sc->fxp_res); - if (sc->fxp_mtag) { + if (sc->fxp_rxmtag) { for (i = 0; i < FXP_NRFABUFS; i++) { rxp = &sc->fxp_desc.rx_list[i]; if (rxp->rx_mbuf != NULL) { - bus_dmamap_sync(sc->fxp_mtag, rxp->rx_map, + bus_dmamap_sync(sc->fxp_rxmtag, rxp->rx_map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->fxp_mtag, rxp->rx_map); + bus_dmamap_unload(sc->fxp_rxmtag, rxp->rx_map); m_freem(rxp->rx_mbuf); } - bus_dmamap_destroy(sc->fxp_mtag, rxp->rx_map); + bus_dmamap_destroy(sc->fxp_rxmtag, rxp->rx_map); } - bus_dmamap_destroy(sc->fxp_mtag, sc->spare_map); + bus_dmamap_destroy(sc->fxp_rxmtag, sc->spare_map); + bus_dma_tag_destroy(sc->fxp_rxmtag); + } + if (sc->fxp_txmtag) { for (i = 0; i < FXP_NTXCB; i++) { txp = &sc->fxp_desc.tx_list[i]; if (txp->tx_mbuf != NULL) { - bus_dmamap_sync(sc->fxp_mtag, txp->tx_map, + bus_dmamap_sync(sc->fxp_txmtag, txp->tx_map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->fxp_mtag, txp->tx_map); + bus_dmamap_unload(sc->fxp_txmtag, txp->tx_map); m_freem(txp->tx_mbuf); } - bus_dmamap_destroy(sc->fxp_mtag, txp->tx_map); + bus_dmamap_destroy(sc->fxp_txmtag, txp->tx_map); } - bus_dma_tag_destroy(sc->fxp_mtag); + bus_dma_tag_destroy(sc->fxp_txmtag); } if (sc->fxp_stag) bus_dma_tag_destroy(sc->fxp_stag); @@ -960,7 +1004,6 @@ #endif FXP_LOCK(sc); - sc->suspended = 1; /* Do same thing as we do for suspend */ /* * Stop DMA and drop transmit queue, but disable interrupts first. */ @@ -970,6 +1013,14 @@ callout_drain(&sc->stat_ch); /* + * Force off IFF_UP flag, otherwise active BPF listeners + * can call fxp_ioctl to clear promiscuous mode and fxp_init + * will rearm fxp_tick which in turn will panic the system + * when kernel tries to call fxp_tick which is not present + * anymore. + */ + sc->ifp->if_flags &= ~IFF_UP; + /* * Close down routes etc. */ ether_ifdetach(sc->ifp); @@ -1279,12 +1330,8 @@ FXP_LOCK_ASSERT(sc, MA_OWNED); - /* - * See if we need to suspend xmit until the multicast filter - * has been reprogrammed (which can only be done at the head - * of the command chain). - */ - if (sc->need_mcsetup) + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) return; if (sc->tx_queued > FXP_NTXCB_HIWAT) @@ -1324,7 +1371,8 @@ * going again if suspended. */ if (txqueued > 0) { - bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); fxp_scb_wait(sc); fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_RESUME); /* @@ -1498,7 +1546,7 @@ *m_head = m; } - error = bus_dmamap_load_mbuf_sg(sc->fxp_mtag, txp->tx_map, *m_head, + error = bus_dmamap_load_mbuf_sg(sc->fxp_txmtag, txp->tx_map, *m_head, segs, &nseg, 0); if (error == EFBIG) { m = m_collapse(*m_head, M_DONTWAIT, sc->maxtxseg); @@ -1508,7 +1556,7 @@ return (ENOMEM); } *m_head = m; - error = bus_dmamap_load_mbuf_sg(sc->fxp_mtag, txp->tx_map, + error = bus_dmamap_load_mbuf_sg(sc->fxp_txmtag, txp->tx_map, *m_head, segs, &nseg, 0); if (error != 0) { m_freem(*m_head); @@ -1524,7 +1572,7 @@ } KASSERT(nseg <= sc->maxtxseg, ("too many DMA segments")); - bus_dmamap_sync(sc->fxp_mtag, txp->tx_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->fxp_txmtag, txp->tx_map, BUS_DMASYNC_PREWRITE); cbp = txp->tx_cb; for (i = 0; i < nseg; i++) { @@ -1694,7 +1742,8 @@ * First ACK all the interrupts in this pass. */ CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack); - fxp_intr_body(sc, ifp, statack, -1); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + fxp_intr_body(sc, ifp, statack, -1); } FXP_UNLOCK(sc); } @@ -1706,14 +1755,15 @@ struct fxp_tx *txp; ifp = sc->ifp; - bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); for (txp = sc->fxp_desc.tx_first; sc->tx_queued && (le16toh(txp->tx_cb->cb_status) & FXP_CB_STATUS_C) != 0; txp = txp->tx_next) { if (txp->tx_mbuf != NULL) { - bus_dmamap_sync(sc->fxp_mtag, txp->tx_map, + bus_dmamap_sync(sc->fxp_txmtag, txp->tx_map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->fxp_mtag, txp->tx_map); + bus_dmamap_unload(sc->fxp_txmtag, txp->tx_map); m_freem(txp->tx_mbuf); txp->tx_mbuf = NULL; /* clear this to reset csum offload bits */ @@ -1723,12 +1773,10 @@ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } sc->fxp_desc.tx_first = txp; - bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, BUS_DMASYNC_PREWRITE); - if (sc->tx_queued == 0) { + bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + if (sc->tx_queued == 0) sc->watchdog_timer = 0; - if (sc->need_mcsetup) - fxp_mc_setup(sc); - } } static void @@ -1878,7 +1926,7 @@ m = rxp->rx_mbuf; rfa = (struct fxp_rfa *)(m->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE); - bus_dmamap_sync(sc->fxp_mtag, rxp->rx_map, + bus_dmamap_sync(sc->fxp_rxmtag, rxp->rx_map, BUS_DMASYNC_POSTREAD); #ifdef DEVICE_POLLING /* loop at most count times if count >=0 */ @@ -1952,6 +2000,8 @@ (*ifp->if_input)(ifp, m); FXP_LOCK(sc); rx_npkts++; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return (rx_npkts); } else { /* Reuse RFA and loaded DMA map. */ ifp->if_iqdrops++; @@ -1993,7 +2043,7 @@ if (sp->rx_good) { ifp->if_ipackets += le32toh(sp->rx_good); sc->rx_idle_secs = 0; - } else { + } else if (sc->flags & FXP_FLAG_RXBUG) { /* * Receiver's been idle for another second. */ @@ -2035,7 +2085,9 @@ */ if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) { sc->rx_idle_secs = 0; - fxp_mc_setup(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + fxp_init_body(sc); + return; } /* * If there is no pending command, start another stats @@ -2113,9 +2165,10 @@ if (txp != NULL) { for (i = 0; i < FXP_NTXCB; i++) { if (txp[i].tx_mbuf != NULL) { - bus_dmamap_sync(sc->fxp_mtag, txp[i].tx_map, + bus_dmamap_sync(sc->fxp_txmtag, txp[i].tx_map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->fxp_mtag, txp[i].tx_map); + bus_dmamap_unload(sc->fxp_txmtag, + txp[i].tx_map); m_freem(txp[i].tx_mbuf); txp[i].tx_mbuf = NULL; /* clear this to reset csum offload bits */ @@ -2123,7 +2176,8 @@ } } } - bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); sc->tx_queued = 0; } @@ -2175,7 +2229,6 @@ struct fxp_cb_ias *cb_ias; struct fxp_cb_tx *tcbp; struct fxp_tx *txp; - struct fxp_cb_mcs *mcsp; int i, prm; FXP_LOCK_ASSERT(sc, MA_OWNED); @@ -2213,30 +2266,19 @@ /* * Attempt to load microcode if requested. + * For ICH based controllers do not load microcode. */ - if (ifp->if_flags & IFF_LINK0 && (sc->flags & FXP_FLAG_UCODE) == 0) - fxp_load_ucode(sc); + if (sc->ident->ich == 0) { + if (ifp->if_flags & IFF_LINK0 && + (sc->flags & FXP_FLAG_UCODE) == 0) + fxp_load_ucode(sc); + } /* - * Initialize the multicast address list. + * Set IFF_ALLMULTI status. It's needed in configure action + * command. */ - if (fxp_mc_addrs(sc)) { - mcsp = sc->mcsp; - mcsp->cb_status = 0; - mcsp->cb_command = - htole16(FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_EL); - mcsp->link_addr = 0xffffffff; - /* - * Start the multicast setup command. - */ - fxp_scb_wait(sc); - bus_dmamap_sync(sc->mcs_tag, sc->mcs_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->mcs_addr); - fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); - /* ...and wait for it to complete. */ - fxp_dma_wait(sc, &mcsp->cb_status, sc->mcs_tag, sc->mcs_map); - } + fxp_mc_addrs(sc); /* * We temporarily use memory that contains the TxCB list to @@ -2310,7 +2352,7 @@ cbp->force_fdx = 0; /* (don't) force full duplex */ cbp->fdx_pin_en = 1; /* (enable) FDX# pin */ cbp->multi_ia = 0; /* (don't) accept multiple IAs */ - cbp->mc_all = sc->flags & FXP_FLAG_ALL_MCAST ? 1 : 0; + cbp->mc_all = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; cbp->gamla_rx = sc->flags & FXP_FLAG_EXT_RFA ? 1 : 0; cbp->vlan_strip_en = ((sc->flags & FXP_FLAG_EXT_RFA) != 0 && (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) ? 1 : 0; @@ -2366,11 +2408,17 @@ fxp_scb_wait(sc); bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->fxp_desc.cbl_addr); fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ fxp_dma_wait(sc, &cb_ias->cb_status, sc->cbl_tag, sc->cbl_map); /* + * Initialize the multicast address list. + */ + fxp_mc_setup(sc); + + /* * Initialize transmit control block (TxCB) list. */ txp = sc->fxp_desc.tx_list; @@ -2395,11 +2443,13 @@ * unit. It will execute the NOP and then suspend. */ tcbp->cb_command = htole16(FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S); - bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); sc->fxp_desc.tx_first = sc->fxp_desc.tx_last = txp; sc->tx_queued = 1; fxp_scb_wait(sc); + CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->fxp_desc.cbl_addr); fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); /* @@ -2545,7 +2595,7 @@ le32enc(&rfa->rbd_addr, 0xffffffff); /* Map the RFA into DMA memory. */ - error = bus_dmamap_load(sc->fxp_mtag, sc->spare_map, rfa, + error = bus_dmamap_load(sc->fxp_rxmtag, sc->spare_map, rfa, MCLBYTES - RFA_ALIGNMENT_FUDGE, fxp_dma_map_addr, &rxp->rx_addr, 0); if (error) { @@ -2554,13 +2604,13 @@ } if (rxp->rx_mbuf != NULL) - bus_dmamap_unload(sc->fxp_mtag, rxp->rx_map); + bus_dmamap_unload(sc->fxp_rxmtag, rxp->rx_map); tmp_map = sc->spare_map; sc->spare_map = rxp->rx_map; rxp->rx_map = tmp_map; rxp->rx_mbuf = m; - bus_dmamap_sync(sc->fxp_mtag, rxp->rx_map, + bus_dmamap_sync(sc->fxp_rxmtag, rxp->rx_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return (0); } @@ -2582,7 +2632,7 @@ p_rx->rx_next = rxp; le32enc(&p_rfa->link_addr, rxp->rx_addr); p_rfa->rfa_control = 0; - bus_dmamap_sync(sc->fxp_mtag, p_rx->rx_map, + bus_dmamap_sync(sc->fxp_rxmtag, p_rx->rx_map, BUS_DMASYNC_PREWRITE); } else { rxp->rx_next = NULL; @@ -2626,7 +2676,7 @@ le32enc(&rfa->link_addr, 0xffffffff); le32enc(&rfa->rbd_addr, 0xffffffff); - bus_dmamap_sync(sc->fxp_mtag, rxp->rx_map, + bus_dmamap_sync(sc->fxp_rxmtag, rxp->rx_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); } @@ -2680,11 +2730,6 @@ switch (command) { case SIOCSIFFLAGS: FXP_LOCK(sc); - if (ifp->if_flags & IFF_ALLMULTI) - sc->flags |= FXP_FLAG_ALL_MCAST; - else - sc->flags &= ~FXP_FLAG_ALL_MCAST; - /* * If interface is marked up and not running, then start it. * If it is marked down and running, stop it. @@ -2692,35 +2737,24 @@ * such as IFF_PROMISC are handled. */ if (ifp->if_flags & IFF_UP) { - fxp_init_body(sc); + if (((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) && + ((ifp->if_flags ^ sc->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI | IFF_LINK0)) != 0) + fxp_init_body(sc); + else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + fxp_init_body(sc); } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) fxp_stop(sc); } + sc->if_flags = ifp->if_flags; FXP_UNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: - FXP_LOCK(sc); - if (ifp->if_flags & IFF_ALLMULTI) - sc->flags |= FXP_FLAG_ALL_MCAST; - else - sc->flags &= ~FXP_FLAG_ALL_MCAST; - /* - * Multicast list has changed; set the hardware filter - * accordingly. - */ - if ((sc->flags & FXP_FLAG_ALL_MCAST) == 0) - fxp_mc_setup(sc); - /* - * fxp_mc_setup() can set FXP_FLAG_ALL_MCAST, so check it - * again rather than else {}. - */ - if (sc->flags & FXP_FLAG_ALL_MCAST) - fxp_init_body(sc); - FXP_UNLOCK(sc); - error = 0; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + fxp_init(sc); break; case SIOCSIFMEDIA: @@ -2824,13 +2858,13 @@ int nmcasts; nmcasts = 0; - if ((sc->flags & FXP_FLAG_ALL_MCAST) == 0) { + if ((ifp->if_flags & IFF_ALLMULTI) == 0) { IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (nmcasts >= MAXMCADDR) { - sc->flags |= FXP_FLAG_ALL_MCAST; + ifp->if_flags |= IFF_ALLMULTI; nmcasts = 0; break; } @@ -2855,87 +2889,28 @@ * points to the TxCB ring, but the mcsetup descriptor itself is not part * of it. We then can do 'CU_START' on the mcsetup descriptor and have it * lead into the regular TxCB ring when it completes. - * - * This function must be called at splimp. */ static void fxp_mc_setup(struct fxp_softc *sc) { - struct fxp_cb_mcs *mcsp = sc->mcsp; - struct fxp_tx *txp; + struct fxp_cb_mcs *mcsp; int count; FXP_LOCK_ASSERT(sc, MA_OWNED); - /* - * If there are queued commands, we must wait until they are all - * completed. If we are already waiting, then add a NOP command - * with interrupt option so that we're notified when all commands - * have been completed - fxp_start() ensures that no additional - * TX commands will be added when need_mcsetup is true. - */ - if (sc->tx_queued) { - /* - * need_mcsetup will be true if we are already waiting for the - * NOP command to be completed (see below). In this case, bail. - */ - if (sc->need_mcsetup) - return; - sc->need_mcsetup = 1; - /* - * Add a NOP command with interrupt so that we are notified - * when all TX commands have been processed. - */ - txp = sc->fxp_desc.tx_last->tx_next; - txp->tx_mbuf = NULL; - txp->tx_cb->cb_status = 0; - txp->tx_cb->cb_command = htole16(FXP_CB_COMMAND_NOP | - FXP_CB_COMMAND_S | FXP_CB_COMMAND_I); - /* - * Advance the end of list forward. - */ - sc->fxp_desc.tx_last->tx_cb->cb_command &= - htole16(~FXP_CB_COMMAND_S); - bus_dmamap_sync(sc->cbl_tag, sc->cbl_map, BUS_DMASYNC_PREWRITE); - sc->fxp_desc.tx_last = txp; - sc->tx_queued++; - /* - * Issue a resume in case the CU has just suspended. - */ - fxp_scb_wait(sc); - fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_RESUME); - /* - * Set a 5 second timer just in case we don't hear from the - * card again. - */ - sc->watchdog_timer = 5; - - return; - } - sc->need_mcsetup = 0; - - /* - * Initialize multicast setup descriptor. - */ + mcsp = sc->mcsp; mcsp->cb_status = 0; - mcsp->cb_command = htole16(FXP_CB_COMMAND_MCAS | - FXP_CB_COMMAND_S | FXP_CB_COMMAND_I); - mcsp->link_addr = htole32(sc->fxp_desc.cbl_addr); - txp = &sc->fxp_desc.mcs_tx; - txp->tx_mbuf = NULL; - txp->tx_cb = (struct fxp_cb_tx *)sc->mcsp; - txp->tx_next = sc->fxp_desc.tx_list; - (void) fxp_mc_addrs(sc); - sc->fxp_desc.tx_first = sc->fxp_desc.tx_last = txp; - sc->tx_queued = 1; + mcsp->cb_command = htole16(FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_EL); + mcsp->link_addr = 0xffffffff; + fxp_mc_addrs(sc); /* - * Wait until command unit is not active. This should never - * be the case when nothing is queued, but make sure anyway. + * Wait until command unit is idle. This should never be the + * case when nothing is queued, but make sure anyway. */ count = 100; - while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == - FXP_SCB_CUS_ACTIVE && --count) + while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) != + FXP_SCB_CUS_IDLE && --count) DELAY(10); if (count == 0) { device_printf(sc->dev, "command queue timeout\n"); @@ -2946,12 +2921,12 @@ * Start the multicast setup command. */ fxp_scb_wait(sc); - bus_dmamap_sync(sc->mcs_tag, sc->mcs_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->mcs_tag, sc->mcs_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->mcs_addr); fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START); - - sc->watchdog_timer = 2; - return; + /* ...and wait for it to complete. */ + fxp_dma_wait(sc, &mcsp->cb_status, sc->mcs_tag, sc->mcs_map); } static uint32_t fxp_ucode_d101a[] = D101_A_RCVBUNDLE_UCODE; >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105281107.p4SB7U7D012249>