--- if_fxp.c.orig 2009-06-10 10:15:30.000000000 +0900 +++ if_fxp.c 2009-06-13 14:58:56.000000000 +0900 @@ -496,6 +496,11 @@ 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; + /* * Determine whether we must use the 503 serial interface. */ @@ -960,7 +965,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 +974,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 +1291,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 +1332,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); /* @@ -1694,7 +1703,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,7 +1716,8 @@ 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) { @@ -1723,12 +1734,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 @@ -1952,6 +1961,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 +2004,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 +2046,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 @@ -2123,7 +2136,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 +2189,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); @@ -2218,25 +2231,10 @@ 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 +2308,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 +2364,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 +2399,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); /* @@ -2680,11 +2686,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 +2693,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 +2814,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 +2845,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 +2877,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; --- if_fxpvar.h.orig 2008-11-27 10:57:23.000000000 +0900 +++ if_fxpvar.h 2009-06-13 14:31:45.000000000 +0900 @@ -164,7 +164,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 +183,7 @@ int cu_resume_bug; int revision; int flags; + int if_flags; uint8_t rfa_size; uint32_t tx_cmd; }; @@ -194,7 +194,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 +202,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)