diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ahci/ahci.c | 2 | ||||
-rw-r--r-- | sys/dev/cas/if_cas.c | 39 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_api.c | 2 | ||||
-rw-r--r-- | sys/dev/e1000/e1000_hw.h | 2 | ||||
-rw-r--r-- | sys/dev/e1000/if_em.c | 138 | ||||
-rw-r--r-- | sys/dev/e1000/if_igb.c | 326 | ||||
-rw-r--r-- | sys/dev/e1000/if_igb.h | 17 | ||||
-rw-r--r-- | sys/dev/fxp/if_fxp.c | 36 | ||||
-rw-r--r-- | sys/dev/fxp/if_fxpvar.h | 4 | ||||
-rw-r--r-- | sys/dev/gem/if_gem.c | 16 | ||||
-rw-r--r-- | sys/dev/mii/bmtphy.c | 67 | ||||
-rw-r--r-- | sys/dev/mii/gentbi.c | 2 | ||||
-rw-r--r-- | sys/dev/mii/inphy.c | 5 | ||||
-rw-r--r-- | sys/dev/mii/mii.c | 10 | ||||
-rw-r--r-- | sys/dev/mii/miidevs | 2 | ||||
-rw-r--r-- | sys/dev/mii/nsgphy.c | 2 | ||||
-rw-r--r-- | sys/dev/mii/nsphyter.c | 6 | ||||
-rw-r--r-- | sys/dev/mii/ukphy.c | 2 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 29 | ||||
-rw-r--r-- | sys/dev/pci/pci_pci.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/controller/usb_controller.c | 8 | ||||
-rw-r--r-- | sys/dev/usb/serial/u3g.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/usb_bus.h | 2 | ||||
-rw-r--r-- | sys/dev/usb/usb_pf.c | 1661 | ||||
-rw-r--r-- | sys/dev/usb/usb_pf.h | 225 | ||||
-rw-r--r-- | sys/dev/usb/usbdevs | 10 |
26 files changed, 478 insertions, 2139 deletions
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 6794f45..4b93d9b 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -858,7 +858,7 @@ ahci_ch_attach(device_t dev) ch->caps = ctlr->caps; ch->caps2 = ctlr->caps2; ch->quirks = ctlr->quirks; - ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1, + ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1; mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF); resource_int_value(device_get_name(dev), device_get_unit(dev), "pm_level", &ch->pm_level); diff --git a/sys/dev/cas/if_cas.c b/sys/dev/cas/if_cas.c index e454fa1..0fe4fc5 100644 --- a/sys/dev/cas/if_cas.c +++ b/sys/dev/cas/if_cas.c @@ -346,7 +346,7 @@ cas_attach(struct cas_softc *sc) } error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, cas_mediachange, cas_mediastatus, BMSR_DEFCAPMASK, - MII_PHY_ANY, MII_OFFSET_ANY, 0); + MII_PHY_ANY, MII_OFFSET_ANY, MIIF_DOPAUSE); } /* * Fall back on an internal PHY if no external PHY was found. @@ -366,7 +366,7 @@ cas_attach(struct cas_softc *sc) } error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, cas_mediachange, cas_mediastatus, BMSR_DEFCAPMASK, - MII_PHY_ANY, MII_OFFSET_ANY, 0); + MII_PHY_ANY, MII_OFFSET_ANY, MIIF_DOPAUSE); } } else { /* @@ -388,7 +388,7 @@ cas_attach(struct cas_softc *sc) BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, cas_mediachange, cas_mediastatus, BMSR_DEFCAPMASK, - CAS_PHYAD_EXTERNAL, MII_OFFSET_ANY, 0); + CAS_PHYAD_EXTERNAL, MII_OFFSET_ANY, MIIF_DOPAUSE); } if (error != 0) { device_printf(sc->sc_dev, "attaching PHYs failed\n"); @@ -1093,8 +1093,7 @@ cas_init_locked(struct cas_softc *sc) /* Set the PAUSE thresholds. We use the maximum OFF threshold. */ CAS_WRITE_4(sc, CAS_RX_PTHRS, - ((111 * 64) << CAS_RX_PTHRS_XOFF_SHFT) | - ((15 * 64) << CAS_RX_PTHRS_XON_SHFT)); + (111 << CAS_RX_PTHRS_XOFF_SHFT) | (15 << CAS_RX_PTHRS_XON_SHFT)); /* RX blanking */ CAS_WRITE_4(sc, CAS_RX_BLANK, @@ -1339,7 +1338,7 @@ cas_init_regs(struct cas_softc *sc) CAS_WRITE_4(sc, CAS_MAC_PREAMBLE_LEN, 0x7); CAS_WRITE_4(sc, CAS_MAC_JAM_SIZE, 0x4); CAS_WRITE_4(sc, CAS_MAC_ATTEMPT_LIMIT, 0x10); - CAS_WRITE_4(sc, CAS_MAC_CTRL_TYPE, 0x8088); + CAS_WRITE_4(sc, CAS_MAC_CTRL_TYPE, 0x8808); /* random number seed */ CAS_WRITE_4(sc, CAS_MAC_RANDOM_SEED, @@ -1572,11 +1571,11 @@ cas_tint(struct cas_softc *sc) } #ifdef CAS_DEBUG - CTR4(KTR_CAS, "%s: CAS_TX_STATE_MACHINE %x CAS_TX_DESC_BASE %llx " + CTR5(KTR_CAS, "%s: CAS_TX_SM1 %x CAS_TX_SM2 %x CAS_TX_DESC_BASE %llx " "CAS_TX_COMP3 %x", - __func__, CAS_READ_4(sc, CAS_TX_STATE_MACHINE), - ((long long)CAS_READ_4(sc, CAS_TX_DESC_BASE_HI3) << 32) | - CAS_READ_4(sc, CAS_TX_DESC_BASE_LO3), + __func__, CAS_READ_4(sc, CAS_TX_SM1), CAS_READ_4(sc, CAS_TX_SM2), + ((long long)CAS_READ_4(sc, CAS_TX_DESC3_BASE_HI) << 32) | + CAS_READ_4(sc, CAS_TX_DESC3_BASE_LO), CAS_READ_4(sc, CAS_TX_COMP3)); #endif @@ -1638,7 +1637,7 @@ cas_rint(struct cas_softc *sc) rxhead = CAS_READ_4(sc, CAS_RX_COMP_HEAD); #ifdef CAS_DEBUG CTR4(KTR_CAS, "%s: sc->sc_rxcptr %d, sc->sc_rxdptr %d, head %d", - __func__, sc->rxcptr, sc->sc_rxdptr, rxhead); + __func__, sc->sc_rxcptr, sc->sc_rxdptr, rxhead); #endif skip = 0; CAS_CDSYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); @@ -1865,7 +1864,7 @@ cas_rint(struct cas_softc *sc) #ifdef CAS_DEBUG CTR4(KTR_CAS, "%s: done sc->sc_rxcptr %d, sc->sc_rxdptr %d, head %d", - __func__, sc->rxcptr, sc->sc_rxdptr, + __func__, sc->sc_rxcptr, sc->sc_rxdptr, CAS_READ_4(sc, CAS_RX_COMP_HEAD)); #endif } @@ -1988,7 +1987,7 @@ cas_intr_task(void *arg, int pending __unused) #ifdef CAS_DEBUG CTR4(KTR_CAS, "%s: %s: cplt %x, status %x", device_get_name(sc->sc_dev), __func__, - (status >> CAS_STATUS_TX_COMP3_SHIFT), (u_int)status); + (status >> CAS_STATUS_TX_COMP3_SHFT), (u_int)status); /* * PCS interrupts must be cleared, otherwise no traffic is passed! @@ -2100,15 +2099,15 @@ cas_watchdog(struct cas_softc *sc) #ifdef CAS_DEBUG CTR4(KTR_CAS, - "%s: CAS_RX_CONFIG %x CAS_MAC_RX_STATUS %x CAS_MAC_RX_CONFIG %x", - __func__, CAS_READ_4(sc, CAS_RX_CONFIG), + "%s: CAS_RX_CONF %x CAS_MAC_RX_STATUS %x CAS_MAC_RX_CONF %x", + __func__, CAS_READ_4(sc, CAS_RX_CONF), CAS_READ_4(sc, CAS_MAC_RX_STATUS), - CAS_READ_4(sc, CAS_MAC_RX_CONFIG)); + CAS_READ_4(sc, CAS_MAC_RX_CONF)); CTR4(KTR_CAS, - "%s: CAS_TX_CONFIG %x CAS_MAC_TX_STATUS %x CAS_MAC_TX_CONFIG %x", - __func__, CAS_READ_4(sc, CAS_TX_CONFIG), + "%s: CAS_TX_CONF %x CAS_MAC_TX_STATUS %x CAS_MAC_TX_CONF %x", + __func__, CAS_READ_4(sc, CAS_TX_CONF), CAS_READ_4(sc, CAS_MAC_TX_STATUS), - CAS_READ_4(sc, CAS_MAC_TX_CONFIG)); + CAS_READ_4(sc, CAS_MAC_TX_CONF)); #endif if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) @@ -2356,14 +2355,12 @@ cas_mii_statchg(device_t dev) v = CAS_READ_4(sc, CAS_MAC_CTRL_CONF) & ~(CAS_MAC_CTRL_CONF_TXP | CAS_MAC_CTRL_CONF_RXP); -#ifdef notyet if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) v |= CAS_MAC_CTRL_CONF_RXP; if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) v |= CAS_MAC_CTRL_CONF_TXP; -#endif CAS_WRITE_4(sc, CAS_MAC_CTRL_CONF, v); /* diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c index 3ae023c..b3a7ef9 100644 --- a/sys/dev/e1000/e1000_api.c +++ b/sys/dev/e1000/e1000_api.c @@ -312,6 +312,8 @@ s32 e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82580_SGMII: case E1000_DEV_ID_82580_COPPER_DUAL: case E1000_DEV_ID_82580_QUAD_FIBER: + case E1000_DEV_ID_DH89XXCC_SGMII: + case E1000_DEV_ID_DH89XXCC_SERDES: mac->type = e1000_82580; break; case E1000_DEV_ID_82576_VF: diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h index ca9c97d..e80e870 100644 --- a/sys/dev/e1000/e1000_hw.h +++ b/sys/dev/e1000/e1000_hw.h @@ -150,6 +150,8 @@ struct e1000_hw; #define E1000_DEV_ID_82580_SGMII 0x1511 #define E1000_DEV_ID_82580_COPPER_DUAL 0x1516 #define E1000_DEV_ID_82580_QUAD_FIBER 0x1527 +#define E1000_DEV_ID_DH89XXCC_SGMII 0x0436 +#define E1000_DEV_ID_DH89XXCC_SERDES 0x0438 #define E1000_REVISION_0 0 #define E1000_REVISION_1 1 #define E1000_REVISION_2 2 diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index c41e144..6728a98 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -93,7 +93,7 @@ int em_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char em_driver_version[] = "7.1.7"; +char em_driver_version[] = "7.1.8"; /********************************************************************* * PCI Device ID Table @@ -272,6 +272,7 @@ static void em_get_wakeup(device_t); static void em_enable_wakeup(device_t); static int em_enable_phy_wakeup(struct adapter *); static void em_led_func(void *, int); +static void em_disable_aspm(struct adapter *); static int em_irq_fast(void *); @@ -1229,9 +1230,9 @@ em_init_locked(struct adapter *adapter) break; case e1000_ich9lan: case e1000_ich10lan: - case e1000_pchlan: pba = E1000_PBA_10K; break; + case e1000_pchlan: case e1000_pch2lan: pba = E1000_PBA_26K; break; @@ -2762,6 +2763,7 @@ em_reset(struct adapter *adapter) /* Issue a global reset */ e1000_reset_hw(hw); E1000_WRITE_REG(hw, E1000_WUC, 0); + em_disable_aspm(adapter); if (e1000_init_hw(hw) < 0) { device_printf(dev, "Hardware Initialization Failed\n"); @@ -4205,68 +4207,66 @@ em_rxeof(struct rx_ring *rxr, int count, int *done) len = le16toh(cur->length); eop = (status & E1000_RXD_STAT_EOP) != 0; - count--; - if (((cur->errors & E1000_RXD_ERR_FRAME_ERR_MASK) == 0) && - (rxr->discard == FALSE)) { + if ((rxr->discard == TRUE) || (cur->errors & + E1000_RXD_ERR_FRAME_ERR_MASK)) { + ifp->if_ierrors++; + ++rxr->rx_discarded; + if (!eop) /* Catch subsequent segs */ + rxr->discard = TRUE; + else + rxr->discard = FALSE; + em_rx_discard(rxr, i); + goto next_desc; + } - /* Assign correct length to the current fragment */ - mp = rxr->rx_buffers[i].m_head; - mp->m_len = len; + /* Assign correct length to the current fragment */ + mp = rxr->rx_buffers[i].m_head; + mp->m_len = len; - /* Trigger for refresh */ - rxr->rx_buffers[i].m_head = NULL; + /* Trigger for refresh */ + rxr->rx_buffers[i].m_head = NULL; - if (rxr->fmp == NULL) { - mp->m_pkthdr.len = len; - rxr->fmp = mp; /* Store the first mbuf */ - rxr->lmp = mp; - } else { - /* Chain mbuf's together */ - mp->m_flags &= ~M_PKTHDR; - rxr->lmp->m_next = mp; - rxr->lmp = rxr->lmp->m_next; - rxr->fmp->m_pkthdr.len += len; - } + /* First segment? */ + if (rxr->fmp == NULL) { + mp->m_pkthdr.len = len; + rxr->fmp = rxr->lmp = mp; + } else { + /* Chain mbuf's together */ + mp->m_flags &= ~M_PKTHDR; + rxr->lmp->m_next = mp; + rxr->lmp = mp; + rxr->fmp->m_pkthdr.len += len; + } - if (eop) { - rxr->fmp->m_pkthdr.rcvif = ifp; - ifp->if_ipackets++; - em_receive_checksum(cur, rxr->fmp); + if (eop) { + --count; + sendmp = rxr->fmp; + sendmp->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + em_receive_checksum(cur, sendmp); #ifndef __NO_STRICT_ALIGNMENT - if (adapter->max_frame_size > - (MCLBYTES - ETHER_ALIGN) && - em_fixup_rx(rxr) != 0) - goto skip; + if (adapter->max_frame_size > + (MCLBYTES - ETHER_ALIGN) && + em_fixup_rx(rxr) != 0) + goto skip; #endif - if (status & E1000_RXD_STAT_VP) { - rxr->fmp->m_pkthdr.ether_vtag = - (le16toh(cur->special) & - E1000_RXD_SPC_VLAN_MASK); - rxr->fmp->m_flags |= M_VLANTAG; - } + if (status & E1000_RXD_STAT_VP) { + sendmp->m_pkthdr.ether_vtag = + (le16toh(cur->special) & + E1000_RXD_SPC_VLAN_MASK); + sendmp->m_flags |= M_VLANTAG; + } #ifdef EM_MULTIQUEUE - rxr->fmp->m_pkthdr.flowid = rxr->msix; - rxr->fmp->m_flags |= M_FLOWID; + sendmp->m_pkthdr.flowid = rxr->msix; + sendmp->m_flags |= M_FLOWID; #endif #ifndef __NO_STRICT_ALIGNMENT skip: #endif - sendmp = rxr->fmp; - rxr->fmp = NULL; - rxr->lmp = NULL; - } - } else { - ifp->if_ierrors++; - ++rxr->rx_discarded; - if (!eop) /* Catch subsequent segs */ - rxr->discard = TRUE; - else - rxr->discard = FALSE; - em_rx_discard(rxr, i); - sendmp = NULL; + rxr->fmp = rxr->lmp = NULL; } - +next_desc: /* Zero out the receive descriptors status. */ cur->status = 0; ++rxdone; /* cumulative for POLL */ @@ -4293,10 +4293,7 @@ skip: } /* Catch any remaining refresh work */ - if (processed != 0) { - em_refresh_mbufs(rxr, i); - processed = 0; - } + em_refresh_mbufs(rxr, i); rxr->next_to_check = i; if (done != NULL) @@ -4878,6 +4875,37 @@ em_led_func(void *arg, int onoff) EM_CORE_UNLOCK(adapter); } +/* +** Disable the L0S and L1 LINK states +*/ +static void +em_disable_aspm(struct adapter *adapter) +{ + int base, reg; + u16 link_cap,link_ctrl; + device_t dev = adapter->dev; + + switch (adapter->hw.mac.type) { + case e1000_82573: + case e1000_82574: + case e1000_82583: + break; + default: + return; + } + if (pci_find_extcap(dev, PCIY_EXPRESS, &base) != 0) + return; + reg = base + PCIR_EXPRESS_LINK_CAP; + link_cap = pci_read_config(dev, reg, 2); + if ((link_cap & PCIM_LINK_CAP_ASPM) == 0) + return; + reg = base + PCIR_EXPRESS_LINK_CTL; + link_ctrl = pci_read_config(dev, reg, 2); + link_ctrl &= 0xFFFC; /* turn off bit 1 and 2 */ + pci_write_config(dev, reg, link_ctrl, 2); + return; +} + /********************************************************************** * * Update the board statistics counters. diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c index ee7ba71..14ccede 100644 --- a/sys/dev/e1000/if_igb.c +++ b/sys/dev/e1000/if_igb.c @@ -99,7 +99,7 @@ int igb_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char igb_driver_version[] = "version - 2.0.4"; +char igb_driver_version[] = "version - 2.0.7"; /********************************************************************* @@ -137,6 +137,10 @@ static igb_vendor_info_t igb_vendor_info_array[] = { 0x8086, E1000_DEV_ID_82580_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82580_COPPER_DUAL, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82580_QUAD_FIBER, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_DH89XXCC_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_DH89XXCC_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} }; @@ -307,11 +311,19 @@ static int igb_enable_msix = 1; TUNABLE_INT("hw.igb.enable_msix", &igb_enable_msix); /* - * Header split has seemed to be beneficial in - * many circumstances tested, however there have - * been some stability issues, so the default is - * off. - */ +** Tuneable Interrupt rate +*/ +static int igb_max_interrupt_rate = 8000; +TUNABLE_INT("hw.igb.max_interrupt_rate", &igb_max_interrupt_rate); + +/* +** Header split causes the packet header to +** be dma'd to a seperate mbuf from the payload. +** this can have memory alignment benefits. But +** another plus is that small packets often fit +** into the header and thus use no cluster. Its +** a very workload dependent type feature. +*/ static bool igb_header_split = FALSE; TUNABLE_INT("hw.igb.hdr_split", &igb_header_split); @@ -330,15 +342,6 @@ TUNABLE_INT("hw.igb.rx_process_limit", &igb_rx_process_limit); static int igb_fc_setting = e1000_fc_full; TUNABLE_INT("hw.igb.fc_setting", &igb_fc_setting); -/* -** Shadow VFTA table, this is needed because -** the real filter table gets cleared during -** a soft reset and the driver needs to be able -** to repopulate it. -*/ -static u32 igb_shadow_vfta[IGB_VFTA_SIZE]; - - /********************************************************************* * Device identification routine * @@ -818,7 +821,7 @@ igb_start_locked(struct tx_ring *txr, struct ifnet *ifp) /* Set watchdog on */ txr->watchdog_time = ticks; - txr->watchdog_check = TRUE; + txr->queue_status = IGB_QUEUE_WORKING; } } @@ -922,7 +925,7 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m) } if (enq > 0) { /* Set the watchdog */ - txr->watchdog_check = TRUE; + txr->queue_status = IGB_QUEUE_WORKING; txr->watchdog_time = ticks; } return (err); @@ -1049,6 +1052,11 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } break; case SIOCSIFMEDIA: + /* + ** As the speed/duplex settings are being + ** changed, we need toreset the PHY. + */ + adapter->hw.phy.reset_disable = FALSE; /* Check SOL/IDER usage */ IGB_CORE_LOCK(adapter); if (e1000_check_reset_block(&adapter->hw)) { @@ -1161,19 +1169,6 @@ igb_init_locked(struct adapter *adapter) E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); - /* Use real VLAN Filter support? */ - if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { - if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) - /* Use real VLAN Filter support */ - igb_setup_vlan_hw_support(adapter); - else { - u32 ctrl; - ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); - ctrl |= E1000_CTRL_VME; - E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); - } - } - /* Set hardware offload abilities */ ifp->if_hwassist = 0; if (ifp->if_capenable & IFCAP_TXCSUM) { @@ -1201,10 +1196,12 @@ igb_init_locked(struct adapter *adapter) ** Figure out the desired mbuf pool ** for doing jumbo/packetsplit */ - if (ifp->if_mtu > ETHERMTU) + if (adapter->max_frame_size <= 2048) + adapter->rx_mbuf_sz = MCLBYTES; + else if (adapter->max_frame_size <= 4096) adapter->rx_mbuf_sz = MJUMPAGESIZE; else - adapter->rx_mbuf_sz = MCLBYTES; + adapter->rx_mbuf_sz = MJUM9BYTES; /* Prepare receive descriptors and buffers */ if (igb_setup_receive_structures(adapter)) { @@ -1213,6 +1210,19 @@ igb_init_locked(struct adapter *adapter) } igb_initialize_receive_units(adapter); + /* Use real VLAN Filter support? */ + if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { + if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) + /* Use real VLAN Filter support */ + igb_setup_vlan_hw_support(adapter); + else { + u32 ctrl; + ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); + ctrl |= E1000_CTRL_VME; + E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); + } + } + /* Don't lose promiscuous settings */ igb_set_promisc(adapter); @@ -1225,9 +1235,6 @@ igb_init_locked(struct adapter *adapter) if (adapter->msix > 1) /* Set up queue routing */ igb_configure_queues(adapter); - /* Set up VLAN tag offload and filter */ - igb_setup_vlan_hw_support(adapter); - /* this clears any pending interrupts */ E1000_READ_REG(&adapter->hw, E1000_ICR); #ifdef DEVICE_POLLING @@ -1627,11 +1634,6 @@ igb_media_change(struct ifnet *ifp) device_printf(adapter->dev, "Unsupported media type\n"); } - /* As the speed/duplex settings my have changed we need to - * reset the PHY. - */ - adapter->hw.phy.reset_disable = FALSE; - igb_init_locked(adapter); IGB_CORE_UNLOCK(adapter); @@ -1947,18 +1949,9 @@ igb_local_timer(void *arg) /* ** Watchdog: check for time since any descriptor was cleaned */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - IGB_TX_LOCK(txr); - if ((txr->watchdog_check == FALSE) || - (txr->tx_avail == adapter->num_tx_desc)) { - IGB_TX_UNLOCK(txr); - continue; - } - if ((ticks - txr->watchdog_time) > IGB_WATCHDOG) + for (int i = 0; i < adapter->num_queues; i++, txr++) + if (txr->queue_status == IGB_QUEUE_HUNG) goto timeout; - IGB_TX_UNLOCK(txr); - } - out: callout_reset(&adapter->timer, hz, igb_local_timer, adapter); return; @@ -1973,7 +1966,6 @@ timeout: txr->me, txr->tx_avail, txr->next_to_clean); adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; adapter->watchdog_events++; - IGB_TX_UNLOCK(txr); igb_init_locked(adapter); } @@ -2037,7 +2029,7 @@ igb_update_link_status(struct adapter *adapter) if_link_state_change(ifp, LINK_STATE_DOWN); /* Turn off watchdogs */ for (int i = 0; i < adapter->num_queues; i++, txr++) - txr->watchdog_check = FALSE; + txr->queue_status = IGB_QUEUE_IDLE; } } @@ -2069,7 +2061,7 @@ igb_stop(void *arg) /* Unarm watchdog timer. */ for (int i = 0; i < adapter->num_queues; i++, txr++) { IGB_TX_LOCK(txr); - txr->watchdog_check = FALSE; + txr->queue_status = IGB_QUEUE_IDLE; IGB_TX_UNLOCK(txr); } @@ -2280,8 +2272,7 @@ igb_configure_queues(struct adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct igb_queue *que; - u32 tmp, ivar = 0; - u32 newitr = IGB_DEFAULT_ITR; + u32 tmp, ivar = 0, newitr = 0; /* First turn on RSS capability */ if (adapter->hw.mac.type > e1000_82575) @@ -2398,6 +2389,9 @@ igb_configure_queues(struct adapter *adapter) } /* Set the starting interrupt rate */ + if (igb_max_interrupt_rate > 0) + newitr = (4000000 / igb_max_interrupt_rate) & 0x7FFC; + if (hw->mac.type == e1000_82575) newitr |= newitr << 16; else @@ -2509,6 +2503,8 @@ igb_setup_msix(struct adapter *adapter) /* Manual override */ if (igb_num_queues != 0) queues = igb_num_queues; + if (queues > 8) /* max queues */ + queues = 8; /* Can have max of 4 queues on 82575 */ if ((adapter->hw.mac.type == e1000_82575) && (queues > 4)) @@ -2636,7 +2632,7 @@ igb_reset(struct adapter *adapter) fc->send_xon = TRUE; /* Set Flow control, use the tunable location if sane */ - if ((igb_fc_setting >= 0) || (igb_fc_setting < 4)) + if ((igb_fc_setting >= 0) && (igb_fc_setting < 4)) fc->requested_mode = igb_fc_setting; else fc->requested_mode = e1000_fc_none; @@ -2728,10 +2724,11 @@ igb_setup_interface(device_t dev, struct adapter *adapter) ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM; ifp->if_capabilities |= IFCAP_TSO4; ifp->if_capabilities |= IFCAP_JUMBO_MTU; - if (igb_header_split) - ifp->if_capabilities |= IFCAP_LRO; - ifp->if_capenable = ifp->if_capabilities; + + /* Don't enable LRO by default */ + ifp->if_capabilities |= IFCAP_LRO; + #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif @@ -3172,7 +3169,7 @@ igb_initialize_transmit_units(struct adapter *adapter) E1000_READ_REG(hw, E1000_TDBAL(i)), E1000_READ_REG(hw, E1000_TDLEN(i))); - txr->watchdog_check = FALSE; + txr->queue_status = IGB_QUEUE_IDLE; txdctl |= IGB_TX_PTHRESH; txdctl |= IGB_TX_HTHRESH << 8; @@ -3184,14 +3181,14 @@ igb_initialize_transmit_units(struct adapter *adapter) if (adapter->hw.mac.type == e1000_vfadapt) return; + e1000_config_collision_dist(hw); + /* Program the Transmit Control Register */ tctl = E1000_READ_REG(hw, E1000_TCTL); tctl &= ~E1000_TCTL_CT; tctl |= (E1000_TCTL_PSP | E1000_TCTL_RTLC | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT)); - e1000_config_collision_dist(hw); - /* This write will effectively turn on the transmit unit. */ E1000_WRITE_REG(hw, E1000_TCTL, tctl); } @@ -3500,16 +3497,19 @@ static bool igb_txeof(struct tx_ring *txr) { struct adapter *adapter = txr->adapter; - int first, last, done; + int first, last, done, processed; struct igb_tx_buffer *tx_buffer; struct e1000_tx_desc *tx_desc, *eop_desc; struct ifnet *ifp = adapter->ifp; IGB_TX_LOCK_ASSERT(txr); - if (txr->tx_avail == adapter->num_tx_desc) + if (txr->tx_avail == adapter->num_tx_desc) { + txr->queue_status = IGB_QUEUE_IDLE; return FALSE; + } + processed = 0; first = txr->next_to_clean; tx_desc = &txr->tx_base[first]; tx_buffer = &txr->tx_buffers[first]; @@ -3536,6 +3536,7 @@ igb_txeof(struct tx_ring *txr) tx_desc->lower.data = 0; tx_desc->buffer_addr = 0; ++txr->tx_avail; + ++processed; if (tx_buffer->m_head) { txr->bytes += @@ -3575,6 +3576,15 @@ igb_txeof(struct tx_ring *txr) txr->next_to_clean = first; + /* + ** Watchdog calculation, we know there's + ** work outstanding or the first return + ** would have been taken, so none processed + ** for too long indicates a hang. + */ + if ((!processed) && ((ticks - txr->watchdog_time) > IGB_WATCHDOG)) + txr->queue_status = IGB_QUEUE_HUNG; + /* * If we have enough room, clear IFF_DRV_OACTIVE * to tell the stack that it is OK to send packets. @@ -3583,7 +3593,7 @@ igb_txeof(struct tx_ring *txr) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; /* All clean, turn off the watchdog */ if (txr->tx_avail == adapter->num_tx_desc) { - txr->watchdog_check = FALSE; + txr->queue_status = IGB_QUEUE_IDLE; return (FALSE); } } @@ -3615,51 +3625,59 @@ igb_refresh_mbufs(struct rx_ring *rxr, int limit) cleaned = -1; /* Signify no completions */ while (i != limit) { rxbuf = &rxr->rx_buffers[i]; - if ((rxbuf->m_head == NULL) && (rxr->hdr_split)) { + /* No hdr mbuf used with header split off */ + if (rxr->hdr_split == FALSE) + goto no_split; + if (rxbuf->m_head == NULL) { mh = m_gethdr(M_DONTWAIT, MT_DATA); if (mh == NULL) goto update; - mh->m_pkthdr.len = mh->m_len = MHLEN; - mh->m_len = MHLEN; - mh->m_flags |= M_PKTHDR; - m_adj(mh, ETHER_ALIGN); - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->htag, - rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - printf("GET BUF: dmamap load" - " failure - %d\n", error); - m_free(mh); - goto update; - } - rxbuf->m_head = mh; - bus_dmamap_sync(rxr->htag, rxbuf->hmap, - BUS_DMASYNC_PREREAD); - rxr->rx_base[i].read.hdr_addr = - htole64(hseg[0].ds_addr); - } + } else + mh = rxbuf->m_head; + mh->m_pkthdr.len = mh->m_len = MHLEN; + mh->m_len = MHLEN; + mh->m_flags |= M_PKTHDR; + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->htag, + rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("Refresh mbufs: hdr dmamap load" + " failure - %d\n", error); + m_free(mh); + rxbuf->m_head = NULL; + goto update; + } + rxbuf->m_head = mh; + bus_dmamap_sync(rxr->htag, rxbuf->hmap, + BUS_DMASYNC_PREREAD); + rxr->rx_base[i].read.hdr_addr = + htole64(hseg[0].ds_addr); +no_split: if (rxbuf->m_pack == NULL) { mp = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, adapter->rx_mbuf_sz); if (mp == NULL) goto update; - mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->ptag, - rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - printf("GET BUF: dmamap load" - " failure - %d\n", error); - m_free(mp); - goto update; - } - rxbuf->m_pack = mp; - bus_dmamap_sync(rxr->ptag, rxbuf->pmap, - BUS_DMASYNC_PREREAD); - rxr->rx_base[i].read.pkt_addr = - htole64(pseg[0].ds_addr); + } else + mp = rxbuf->m_pack; + + mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz; + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->ptag, + rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("Refresh mbufs: payload dmamap load" + " failure - %d\n", error); + m_free(mp); + rxbuf->m_pack = NULL; + goto update; } + rxbuf->m_pack = mp; + bus_dmamap_sync(rxr->ptag, rxbuf->pmap, + BUS_DMASYNC_PREREAD); + rxr->rx_base[i].read.pkt_addr = + htole64(pseg[0].ds_addr); cleaned = i; /* Calculate next index */ @@ -3722,9 +3740,9 @@ igb_allocate_receive_buffers(struct rx_ring *rxr) BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - MJUMPAGESIZE, /* maxsize */ + MJUM9BYTES, /* maxsize */ 1, /* nsegments */ - MJUMPAGESIZE, /* maxsegsize */ + MJUM9BYTES, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ @@ -3826,7 +3844,7 @@ igb_setup_receive_ring(struct rx_ring *rxr) rxr->hdr_split = TRUE; /* Now replenish the ring mbufs */ - for (int j = 0; j != adapter->num_rx_desc; ++j) { + for (int j = 0; j < adapter->num_rx_desc; ++j) { struct mbuf *mh, *mp; rxbuf = &rxr->rx_buffers[j]; @@ -3897,8 +3915,8 @@ skip_head: ** are undesireable in similar setups. */ if (ifp->if_capenable & IFCAP_LRO) { - int err = tcp_lro_init(lro); - if (err) { + error = tcp_lro_init(lro); + if (error) { device_printf(dev, "LRO Initialization failed!\n"); goto fail; } @@ -3940,7 +3958,9 @@ fail: */ for (int j = 0; j > i; ++j) { rxr = &adapter->rx_rings[i]; + IGB_RX_LOCK(rxr); igb_free_receive_ring(rxr); + IGB_RX_UNLOCK(rxr); } return (ENOBUFS); @@ -3983,9 +4003,13 @@ igb_initialize_receive_units(struct adapter *adapter) */ if (ifp->if_mtu > ETHERMTU) { rctl |= E1000_RCTL_LPE; - srrctl |= 4096 >> E1000_SRRCTL_BSIZEPKT_SHIFT; - rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX; - + if (adapter->rx_mbuf_sz == MJUMPAGESIZE) { + srrctl |= 4096 >> E1000_SRRCTL_BSIZEPKT_SHIFT; + rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX; + } else if (adapter->rx_mbuf_sz > MJUMPAGESIZE) { + srrctl |= 8192 >> E1000_SRRCTL_BSIZEPKT_SHIFT; + rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX; + } /* Set maximum packet len */ psize = adapter->max_frame_size; /* are we on a vlan? */ @@ -4194,11 +4218,11 @@ igb_free_receive_buffers(struct rx_ring *rxr) static __inline void igb_rx_discard(struct rx_ring *rxr, int i) { - struct adapter *adapter = rxr->adapter; struct igb_rx_buf *rbuf; - struct mbuf *mh, *mp; rbuf = &rxr->rx_buffers[i]; + + /* Partially received? Free the chain */ if (rxr->fmp != NULL) { rxr->fmp->m_flags |= M_PKTHDR; m_freem(rxr->fmp); @@ -4206,19 +4230,23 @@ igb_rx_discard(struct rx_ring *rxr, int i) rxr->lmp = NULL; } - mh = rbuf->m_head; - mp = rbuf->m_pack; + /* + ** With advanced descriptors the writeback + ** clobbers the buffer addrs, so its easier + ** to just free the existing mbufs and take + ** the normal refresh path to get new buffers + ** and mapping. + */ + if (rbuf->m_head) { + m_free(rbuf->m_head); + rbuf->m_head = NULL; + } - /* Reuse loaded DMA map and just update mbuf chain */ - if (mh) { /* with no hdr split would be null */ - mh->m_len = MHLEN; - mh->m_flags |= M_PKTHDR; - mh->m_next = NULL; + if (rbuf->m_pack) { + m_free(rbuf->m_pack); + rbuf->m_pack = NULL; } - mp->m_len = mp->m_pkthdr.len = adapter->rx_mbuf_sz; - mp->m_data = mp->m_ext.ext_buf; - mp->m_next = NULL; return; } @@ -4333,10 +4361,9 @@ igb_rxeof(struct igb_queue *que, int count, int *done) E1000_RXDADV_HDRBUFLEN_SHIFT; if (hlen > IGB_HDR_BUF) hlen = IGB_HDR_BUF; - /* Handle the header mbuf */ mh = rxr->rx_buffers[i].m_head; mh->m_len = hlen; - /* clear buf info for refresh */ + /* clear buf pointer for refresh */ rxbuf->m_head = NULL; /* ** Get the payload length, this @@ -4347,7 +4374,7 @@ igb_rxeof(struct igb_queue *que, int count, int *done) mp = rxr->rx_buffers[i].m_pack; mp->m_len = plen; mh->m_next = mp; - /* clear buf info for refresh */ + /* clear buf pointer */ rxbuf->m_pack = NULL; rxr->rx_split_packets++; } @@ -4368,7 +4395,7 @@ igb_rxeof(struct igb_queue *que, int count, int *done) /* Initial frame - setup */ if (rxr->fmp == NULL) { mh->m_pkthdr.len = mh->m_len; - /* Store the first mbuf */ + /* Save the head of the chain */ rxr->fmp = mh; rxr->lmp = mh; if (mp != NULL) { @@ -4533,12 +4560,15 @@ igb_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) if ((vtag == 0) || (vtag > 4095)) /* Invalid */ return; + IGB_CORE_LOCK(adapter); index = (vtag >> 5) & 0x7F; bit = vtag & 0x1F; - igb_shadow_vfta[index] |= (1 << bit); + adapter->shadow_vfta[index] |= (1 << bit); ++adapter->num_vlans; /* Re-init to load the changes */ - igb_init(adapter); + if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) + igb_init_locked(adapter); + IGB_CORE_UNLOCK(adapter); } /* @@ -4557,12 +4587,15 @@ igb_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) if ((vtag == 0) || (vtag > 4095)) /* Invalid */ return; + IGB_CORE_LOCK(adapter); index = (vtag >> 5) & 0x7F; bit = vtag & 0x1F; - igb_shadow_vfta[index] &= ~(1 << bit); + adapter->shadow_vfta[index] &= ~(1 << bit); --adapter->num_vlans; /* Re-init to load the changes */ - igb_init(adapter); + if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) + igb_init_locked(adapter); + IGB_CORE_UNLOCK(adapter); } static void @@ -4585,12 +4618,13 @@ igb_setup_vlan_hw_support(struct adapter *adapter) ** we need to repopulate it now. */ for (int i = 0; i < IGB_VFTA_SIZE; i++) - if (igb_shadow_vfta[i] != 0) { + if (adapter->shadow_vfta[i] != 0) { if (hw->mac.type == e1000_vfadapt) - e1000_vfta_set_vf(hw, igb_shadow_vfta[i], TRUE); + e1000_vfta_set_vf(hw, + adapter->shadow_vfta[i], TRUE); else E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, - i, igb_shadow_vfta[i]); + i, adapter->shadow_vfta[i]); } if (hw->mac.type == e1000_vfadapt) @@ -4994,6 +5028,28 @@ igb_sysctl_reg_handler(SYSCTL_HANDLER_ARGS) } /* +** Tuneable interrupt rate handler +*/ +static int +igb_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) +{ + struct igb_queue *que = ((struct igb_queue *)oidp->oid_arg1); + int error; + u32 reg, usec, rate; + + reg = E1000_READ_REG(&que->adapter->hw, E1000_EITR(que->msix)); + usec = ((reg & 0x7FFC) >> 2); + if (usec > 0) + rate = 1000000 / usec; + else + rate = 0; + error = sysctl_handle_int(oidp, &rate, 0, req); + if (error || !req->newptr) + return error; + return 0; +} + +/* * Add sysctl variables, one per statistic, to the system. */ static void @@ -5065,6 +5121,12 @@ igb_add_hw_stats(struct adapter *adapter) CTLFLAG_RD, NULL, "Queue Name"); queue_list = SYSCTL_CHILDREN(queue_node); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", + CTLFLAG_RD, &adapter->queues[i], + sizeof(&adapter->queues[i]), + igb_sysctl_interrupt_rate_handler, + "IU", "Interrupt Rate"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", CTLFLAG_RD, adapter, E1000_TDH(txr->me), igb_sysctl_reg_handler, "IU", diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h index 059a8b9..15fdceb 100644 --- a/sys/dev/e1000/if_igb.h +++ b/sys/dev/e1000/if_igb.h @@ -190,6 +190,9 @@ #define IGB_TX_BUFFER_SIZE ((uint32_t) 1514) #define IGB_FC_PAUSE_TIME 0x0680 #define IGB_EEPROM_APME 0x400; +#define IGB_QUEUE_IDLE 0 +#define IGB_QUEUE_WORKING 1 +#define IGB_QUEUE_HUNG 2 /* * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be @@ -237,7 +240,7 @@ /* Define the starting Interrupt rate per Queue */ #define IGB_INTS_PER_SEC 8000 -#define IGB_DEFAULT_ITR 1000000000/(IGB_INTS_PER_SEC * 256) +#define IGB_DEFAULT_ITR ((1000000/IGB_INTS_PER_SEC) << 2) #define IGB_LINK_ITR 2000 @@ -300,7 +303,7 @@ struct tx_ring { u32 bytes; u32 packets; - bool watchdog_check; + int queue_status; int watchdog_time; int tdt; int tdh; @@ -384,7 +387,15 @@ struct adapter { int wol; int has_manage; - /* Info about the board itself */ + /* + ** Shadow VFTA table, this is needed because + ** the real vlan filter table gets cleared during + ** a soft reset and the driver needs to be able + ** to repopulate it. + */ + u32 shadow_vfta[IGB_VFTA_SIZE]; + + /* Info about the interface */ u8 link_active; u16 link_speed; u16 link_duplex; diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index 5710ca7..2d522c3 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -107,11 +107,11 @@ static int tx_threshold = 64; /* * The configuration byte map has several undefined fields which * must be one or must be zero. Set up a template for these bits. - * The actual configuration is performed in fxp_init. + * The actual configuration is performed in fxp_init_body. * * See struct fxp_cb_config for the bit definitions. */ -static u_char fxp_cb_config_template[] = { +static const u_char const fxp_cb_config_template[] = { 0x0, 0x0, /* cb_status */ 0x0, 0x0, /* cb_command */ 0x0, 0x0, 0x0, 0x0, /* link_addr */ @@ -155,7 +155,7 @@ static u_char fxp_cb_config_template[] = { * particular variants, but we don't currently differentiate between * them. */ -static struct fxp_ident fxp_ident_table[] = { +static const struct fxp_ident const fxp_ident_table[] = { { 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" }, @@ -217,7 +217,7 @@ static int fxp_shutdown(device_t dev); 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 const 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); @@ -366,12 +366,12 @@ fxp_dma_wait(struct fxp_softc *sc, volatile uint16_t *status, device_printf(sc->dev, "DMA timeout\n"); } -static struct fxp_ident * +static const struct fxp_ident * fxp_find_ident(device_t dev) { uint16_t devid; uint8_t revid; - struct fxp_ident *ident; + const struct fxp_ident *ident; if (pci_get_vendor(dev) == FXP_VENDORID_INTEL) { devid = pci_get_device(dev); @@ -392,7 +392,7 @@ fxp_find_ident(device_t dev) static int fxp_probe(device_t dev) { - struct fxp_ident *ident; + const struct fxp_ident *ident; ident = fxp_find_ident(dev); if (ident != NULL) { @@ -1614,21 +1614,7 @@ fxp_encap(struct fxp_softc *sc, struct mbuf **m_head) /* * Advance the end of list forward. */ - -#ifdef __alpha__ - /* - * On platforms which can't access memory in 16-bit - * granularities, we must prevent the card from DMA'ing - * up the status while we update the command field. - * This could cause us to overwrite the completion status. - * XXX This is probably bogus and we're _not_ looking - * for atomicity here. - */ - atomic_clear_16(&sc->fxp_desc.tx_last->tx_cb->cb_command, - htole16(FXP_CB_COMMAND_S)); -#else sc->fxp_desc.tx_last->tx_cb->cb_command &= htole16(~FXP_CB_COMMAND_S); -#endif /*__alpha__*/ sc->fxp_desc.tx_last = txp; /* @@ -2985,13 +2971,13 @@ static uint32_t fxp_ucode_d102e[] = D102_E_RCVBUNDLE_UCODE; #define UCODE(x) x, sizeof(x)/sizeof(uint32_t) -struct ucode { +static const struct ucode { uint32_t revision; uint32_t *ucode; int length; u_short int_delay_offset; u_short bundle_max_offset; -} ucode_table[] = { +} const ucode_table[] = { { FXP_REV_82558_A4, UCODE(fxp_ucode_d101a), D101_CPUSAVER_DWORD, 0 }, { FXP_REV_82558_B0, UCODE(fxp_ucode_d101b0), D101_CPUSAVER_DWORD, 0 }, { FXP_REV_82559_A0, UCODE(fxp_ucode_d101ma), @@ -3010,7 +2996,7 @@ struct ucode { static void fxp_load_ucode(struct fxp_softc *sc) { - struct ucode *uc; + const struct ucode *uc; struct fxp_cb_ucode *cbp; int i; @@ -3177,11 +3163,13 @@ sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) static int sysctl_hw_fxp_int_delay(SYSCTL_HANDLER_ARGS) { + return (sysctl_int_range(oidp, arg1, arg2, req, 300, 3000)); } static int sysctl_hw_fxp_bundle_max(SYSCTL_HANDLER_ARGS) { + return (sysctl_int_range(oidp, arg1, arg2, req, 1, 0xffff)); } diff --git a/sys/dev/fxp/if_fxpvar.h b/sys/dev/fxp/if_fxpvar.h index de44636..ca7f7f5 100644 --- a/sys/dev/fxp/if_fxpvar.h +++ b/sys/dev/fxp/if_fxpvar.h @@ -146,7 +146,7 @@ struct fxp_ident { uint16_t devid; int16_t revid; /* -1 matches anything */ uint8_t ich; - char *name; + const char *name; }; struct fxp_hwstats { @@ -182,7 +182,7 @@ struct fxp_softc { 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; + const struct fxp_ident *ident; struct mtx sc_mtx; bus_dma_tag_t fxp_txmtag; /* bus DMA tag for Tx mbufs */ bus_dma_tag_t fxp_rxmtag; /* bus DMA tag for Rx mbufs */ diff --git a/sys/dev/gem/if_gem.c b/sys/dev/gem/if_gem.c index 5c5750e..e8d9400 100644 --- a/sys/dev/gem/if_gem.c +++ b/sys/dev/gem/if_gem.c @@ -302,7 +302,7 @@ gem_attach(struct gem_softc *sc) } error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, gem_mediachange, gem_mediastatus, BMSR_DEFCAPMASK, phy, - MII_OFFSET_ANY, 0); + MII_OFFSET_ANY, MIIF_DOPAUSE); } /* @@ -330,7 +330,7 @@ gem_attach(struct gem_softc *sc) } error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, gem_mediachange, gem_mediastatus, BMSR_DEFCAPMASK, phy, - MII_OFFSET_ANY, 0); + MII_OFFSET_ANY, MIIF_DOPAUSE); } /* @@ -352,7 +352,7 @@ gem_attach(struct gem_softc *sc) sc->sc_flags |= GEM_SERDES; error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, gem_mediachange, gem_mediastatus, BMSR_DEFCAPMASK, - GEM_PHYAD_EXTERNAL, MII_OFFSET_ANY, 0); + GEM_PHYAD_EXTERNAL, MII_OFFSET_ANY, MIIF_DOPAUSE); } if (error != 0) { device_printf(sc->sc_dev, "attaching PHYs failed\n"); @@ -712,6 +712,9 @@ gem_reset_rx(struct gem_softc *sc) if (!GEM_BANK1_BITWAIT(sc, GEM_RX_CONFIG, GEM_RX_CONFIG_RXDMA_EN, 0)) device_printf(sc->sc_dev, "cannot disable RX DMA\n"); + /* Wait 5ms extra. */ + DELAY(5000); + /* Finally, reset the ERX. */ GEM_BANK2_WRITE_4(sc, GEM_RESET, GEM_RESET_RX); GEM_BANK2_BARRIER(sc, GEM_RESET, 4, @@ -784,6 +787,9 @@ gem_reset_tx(struct gem_softc *sc) if (!GEM_BANK1_BITWAIT(sc, GEM_TX_CONFIG, GEM_TX_CONFIG_TXDMA_EN, 0)) device_printf(sc->sc_dev, "cannot disable TX DMA\n"); + /* Wait 5ms extra. */ + DELAY(5000); + /* Finally, reset the ETX. */ GEM_BANK2_WRITE_4(sc, GEM_RESET, GEM_RESET_TX); GEM_BANK2_BARRIER(sc, GEM_RESET, 4, @@ -1239,7 +1245,7 @@ gem_init_regs(struct gem_softc *sc) GEM_BANK1_WRITE_4(sc, GEM_MAC_PREAMBLE_LEN, 0x7); GEM_BANK1_WRITE_4(sc, GEM_MAC_JAM_SIZE, 0x4); GEM_BANK1_WRITE_4(sc, GEM_MAC_ATTEMPT_LIMIT, 0x10); - GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_TYPE, 0x8088); + GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_TYPE, 0x8808); /* random number seed */ GEM_BANK1_WRITE_4(sc, GEM_MAC_RANDOM_SEED, @@ -2039,14 +2045,12 @@ gem_mii_statchg(device_t dev) v = GEM_BANK1_READ_4(sc, GEM_MAC_CONTROL_CONFIG) & ~(GEM_MAC_CC_RX_PAUSE | GEM_MAC_CC_TX_PAUSE); -#ifdef notyet if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) v |= GEM_MAC_CC_RX_PAUSE; if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) v |= GEM_MAC_CC_TX_PAUSE; -#endif GEM_BANK1_WRITE_4(sc, GEM_MAC_CONTROL_CONFIG, v); if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0 && diff --git a/sys/dev/mii/bmtphy.c b/sys/dev/mii/bmtphy.c index 63d1df1..6f53349 100644 --- a/sys/dev/mii/bmtphy.c +++ b/sys/dev/mii/bmtphy.c @@ -85,6 +85,11 @@ __FBSDID("$FreeBSD$"); static int bmtphy_probe(device_t); static int bmtphy_attach(device_t); +struct bmtphy_softc { + struct mii_softc mii_sc; + int mii_model; +}; + static device_method_t bmtphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bmtphy_probe), @@ -100,18 +105,21 @@ static devclass_t bmtphy_devclass; static driver_t bmtphy_driver = { "bmtphy", bmtphy_methods, - sizeof(struct mii_softc) + sizeof(struct bmtphy_softc) }; DRIVER_MODULE(bmtphy, miibus, bmtphy_driver, bmtphy_devclass, 0, 0); static int bmtphy_service(struct mii_softc *, struct mii_data *, int); static void bmtphy_status(struct mii_softc *); +static void bmtphy_reset(struct mii_softc *); static const struct mii_phydesc bmtphys_dp[] = { MII_PHY_DESC(BROADCOM, BCM4401), MII_PHY_DESC(BROADCOM, BCM5201), + MII_PHY_DESC(BROADCOM, BCM5214), MII_PHY_DESC(BROADCOM, BCM5221), + MII_PHY_DESC(BROADCOM, BCM5222), MII_PHY_END }; @@ -137,11 +145,13 @@ bmtphy_probe(device_t dev) static int bmtphy_attach(device_t dev) { - struct mii_softc *sc; - struct mii_attach_args *ma; - struct mii_data *mii; + struct bmtphy_softc *bsc; + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; - sc = device_get_softc(dev); + bsc = device_get_softc(dev); + sc = &bsc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); mii = ma->mii_data; @@ -153,7 +163,11 @@ bmtphy_attach(device_t dev) sc->mii_service = bmtphy_service; sc->mii_pdata = mii; - mii_phy_reset(sc); + sc->mii_flags |= MIIF_NOMANPAUSE; + + bsc->mii_model = MII_MODEL(ma->mii_id2); + + bmtphy_reset(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); @@ -194,16 +208,15 @@ bmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) /* Callback if something changed. */ mii_phy_update(sc, cmd); - return (0); } static void bmtphy_status(struct mii_softc *sc) { - struct mii_data *mii; - struct ifmedia_entry *ife; - int bmsr, bmcr, aux_csr; + struct mii_data *mii; + struct ifmedia_entry *ife; + int bmsr, bmcr, aux_csr; mii = sc->mii_pdata; ife = mii->mii_media.ifm_cur; @@ -212,7 +225,6 @@ bmtphy_status(struct mii_softc *sc) mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); - aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); if (bmsr & BMSR_LINK) mii->mii_media_status |= IFM_ACTIVE; @@ -238,14 +250,45 @@ bmtphy_status(struct mii_softc *sc) return; } + aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR); if (aux_csr & AUX_CSR_SPEED) mii->mii_media_active |= IFM_100_TX; else mii->mii_media_active |= IFM_10_T; if (aux_csr & AUX_CSR_FDX) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= + IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } + +static void +bmtphy_reset(struct mii_softc *sc) +{ + struct bmtphy_softc *bsc; + u_int16_t data; + + bsc = (struct bmtphy_softc *)sc; + + mii_phy_reset(sc); + + if (bsc->mii_model == MII_MODEL_BROADCOM_BCM5221) { + /* Enable shadow register mode. */ + data = PHY_READ(sc, 0x1f); + PHY_WRITE(sc, 0x1f, data | 0x0080); + + /* Enable APD (Auto PowerDetect). */ + data = PHY_READ(sc, MII_BMTPHY_AUX2); + PHY_WRITE(sc, MII_BMTPHY_AUX2, data | 0x0020); + + /* Enable clocks across APD for Auto-MDIX functionality. */ + data = PHY_READ(sc, MII_BMTPHY_INTR); + PHY_WRITE(sc, MII_BMTPHY_INTR, data | 0x0004); + + /* Disable shadow register mode. */ + data = PHY_READ(sc, 0x1f); + PHY_WRITE(sc, 0x1f, data & ~0x0080); + } +} diff --git a/sys/dev/mii/gentbi.c b/sys/dev/mii/gentbi.c index f5d3a8b..a36f16a 100644 --- a/sys/dev/mii/gentbi.c +++ b/sys/dev/mii/gentbi.c @@ -172,6 +172,8 @@ gentbi_attach(device_t dev) sc->mii_service = gentbi_service; sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOMANPAUSE; + mii_phy_reset(sc); /* diff --git a/sys/dev/mii/inphy.c b/sys/dev/mii/inphy.c index 6830b5a..1293641 100644 --- a/sys/dev/mii/inphy.c +++ b/sys/dev/mii/inphy.c @@ -113,6 +113,8 @@ inphy_attach(device_t dev) sc->mii_service = inphy_service; sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOMANPAUSE; + ifmedia_add(&mii->mii_media, IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), MII_MEDIA_100_TX, NULL); @@ -197,7 +199,8 @@ inphy_status(struct mii_softc *sc) else mii->mii_media_active |= IFM_10_T; if (scr & SCR_FDX) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= + IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else diff --git a/sys/dev/mii/mii.c b/sys/dev/mii/mii.c index 3df5dfa..8485691 100644 --- a/sys/dev/mii/mii.c +++ b/sys/dev/mii/mii.c @@ -137,7 +137,7 @@ miibus_attach(device_t dev) free(children, M_TEMP); } if (nchildren == 0) { - device_printf(dev, "cannot get children"); + device_printf(dev, "cannot get children\n"); return (ENXIO); } ivars = device_get_ivars(dev); @@ -311,12 +311,12 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp, int bmsr, first, i, nchildren, offset, phymax, phymin, rv; if (phyloc != MII_PHY_ANY && offloc != MII_OFFSET_ANY) { - printf("%s: phyloc and offloc specified", __func__); + printf("%s: phyloc and offloc specified\n", __func__); return (EINVAL); } if (offloc != MII_OFFSET_ANY && (offloc < 0 || offloc >= MII_NPHY)) { - printf("%s: ivalid offloc %d", __func__, offloc); + printf("%s: ivalid offloc %d\n", __func__, offloc); return (EINVAL); } @@ -325,7 +325,7 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp, phymax = MII_NPHY - 1; } else { if (phyloc < 0 || phyloc >= MII_NPHY) { - printf("%s: ivalid phyloc %d", __func__, phyloc); + printf("%s: ivalid phyloc %d\n", __func__, phyloc); return (EINVAL); } phymin = phymax = phyloc; @@ -352,7 +352,7 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp, if (ivars->ifp != ifp || ivars->ifmedia_upd != ifmedia_upd || ivars->ifmedia_sts != ifmedia_sts || ivars->mii_flags != flags) { - printf("%s: non-matching invariant", __func__); + printf("%s: non-matching invariant\n", __func__); return (EINVAL); } /* diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs index ec0b846..24cd551 100644 --- a/sys/dev/mii/miidevs +++ b/sys/dev/mii/miidevs @@ -128,7 +128,9 @@ model ATHEROS F1_7 0x0007 Atheros F1 10/100/1000 PHY model BROADCOM 3C905B 0x0012 3c905B 10/100 internal PHY model BROADCOM 3C905C 0x0017 3c905C 10/100 internal PHY model BROADCOM BCM5201 0x0021 BCM5201 10/100baseTX PHY +model BROADCOM BCM5214 0x0028 BCM5214 Quad 10/100 PHY model BROADCOM BCM5221 0x001e BCM5221 10/100baseTX PHY +model BROADCOM BCM5222 0x0032 BCM5222 Dual 10/100 PHY model BROADCOM BCM4401 0x0036 BCM4401 10/100baseTX PHY model xxBROADCOM BCM5400 0x0004 Broadcom 1000baseTX PHY model xxBROADCOM BCM5401 0x0005 BCM5401 10/100/1000baseTX PHY diff --git a/sys/dev/mii/nsgphy.c b/sys/dev/mii/nsgphy.c index 7cdee42..4177912 100644 --- a/sys/dev/mii/nsgphy.c +++ b/sys/dev/mii/nsgphy.c @@ -135,6 +135,8 @@ nsgphy_attach(device_t dev) sc->mii_service = nsgphy_service; sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOMANPAUSE; + mii_phy_reset(sc); /* diff --git a/sys/dev/mii/nsphyter.c b/sys/dev/mii/nsphyter.c index 5489504..c302181 100644 --- a/sys/dev/mii/nsphyter.c +++ b/sys/dev/mii/nsphyter.c @@ -143,6 +143,8 @@ nsphyter_attach(device_t dev) sc->mii_service = nsphyter_service; sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOMANPAUSE; + #if 1 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) @@ -242,12 +244,8 @@ nsphyter_status(struct mii_softc *sc) else mii->mii_media_active |= IFM_100_TX; if ((physts & PHYSTS_DUPLEX) != 0) -#ifdef notyet mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); -#else - mii->mii_media_active |= IFM_FDX; -#endif else mii->mii_media_active |= IFM_HDX; } else diff --git a/sys/dev/mii/ukphy.c b/sys/dev/mii/ukphy.c index 05b1b45..10842b7 100644 --- a/sys/dev/mii/ukphy.c +++ b/sys/dev/mii/ukphy.c @@ -136,6 +136,8 @@ ukphy_attach(device_t dev) sc->mii_service = ukphy_service; sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOMANPAUSE; + mii_phy_reset(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 6069b6d..e3b6159 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -3022,8 +3022,35 @@ pci_resume(device_t dev) if (!device_is_attached(child)) pci_cfg_save(child, dinfo, 1); } + + /* + * Resume critical devices first, then everything else later. + */ + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + switch (pci_get_class(child)) { + case PCIC_DISPLAY: + case PCIC_MEMORY: + case PCIC_BRIDGE: + case PCIC_BASEPERIPH: + DEVICE_RESUME(child); + break; + } + } + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + switch (pci_get_class(child)) { + case PCIC_DISPLAY: + case PCIC_MEMORY: + case PCIC_BRIDGE: + case PCIC_BASEPERIPH: + break; + default: + DEVICE_RESUME(child); + } + } free(devlist, M_TEMP); - return (bus_generic_resume(dev)); + return (0); } static void diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index 7915818..199c132 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -860,7 +860,9 @@ host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, case 0x00171166: case 0x01011166: case 0x010f1014: + case 0x01101166: case 0x02011166: + case 0x02251166: case 0x03021014: *busnum = read_config(bus, slot, func, 0x44, 1); break; diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c index afc2118..d774d34 100644 --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -207,6 +207,8 @@ usb_detach(device_t dev) usb_proc_free(&bus->control_xfer_proc); + usbpf_detach(bus); + return (0); } @@ -435,6 +437,8 @@ usb_attach_sub(device_t dev, struct usb_bus *bus) usb_devclass_ptr = devclass_find("usbus"); mtx_unlock(&Giant); + usbpf_attach(bus); + /* Initialise USB process messages */ bus->explore_msg[0].hdr.pm_callback = &usb_bus_explore; bus->explore_msg[0].bus = bus; @@ -548,8 +552,6 @@ usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, TAILQ_INIT(&bus->intr_q.head); - usbpf_attach(bus, &bus->uif); - #if USB_HAVE_BUSDMA usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags, dmat, &bus->bus_mtx, NULL, 32, USB_BUS_DMA_TAG_MAX); @@ -597,8 +599,6 @@ usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) usb_dma_tag_unsetup(bus->dma_parent_tag); #endif - usbpf_detach(bus); - mtx_destroy(&bus->bus_mtx); } diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index 646063a..c19f1fd 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -281,12 +281,12 @@ static const struct usb_device_id u3g_devs[] = { U3G_DEV(HUAWEI, E143D, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E143E, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E143F, U3GINIT_HUAWEI), - U3G_DEV(HUAWEI, E14AC, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E180V, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E220, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E220BIS, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, MOBILE, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E1752, U3GINIT_HUAWEISCSI), + U3G_DEV(HUAWEI, E1820, U3GINIT_HUAWEISCSI), U3G_DEV(HUAWEI, K3765, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, K3765_INIT, U3GINIT_HUAWEISCSI), U3G_DEV(KYOCERA2, CDMA_MSM_K, 0), diff --git a/sys/dev/usb/usb_bus.h b/sys/dev/usb/usb_bus.h index c5dfeff..1dd9d6a 100644 --- a/sys/dev/usb/usb_bus.h +++ b/sys/dev/usb/usb_bus.h @@ -86,7 +86,7 @@ struct usb_bus { struct usb_bus_methods *methods; /* filled by HC driver */ struct usb_device **devices; - struct usbpf_if *uif; /* USB Packet Filter */ + struct ifnet *ifp; /* only for USB Packet Filter */ usb_power_mask_t hw_power_state; /* see USB_HW_POWER_XXX */ usb_size_t uframe_usage[USB_HS_MICRO_FRAMES_MAX]; diff --git a/sys/dev/usb/usb_pf.c b/sys/dev/usb/usb_pf.c index 3f5f204..c2925c2 100644 --- a/sys/dev/usb/usb_pf.c +++ b/sys/dev/usb/usb_pf.c @@ -43,6 +43,8 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <sys/sockio.h> #include <net/if.h> +#include <net/if_types.h> +#include <net/bpf.h> #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> @@ -55,1623 +57,39 @@ __FBSDID("$FreeBSD$"); #include <dev/usb/usb_pf.h> #include <dev/usb/usb_transfer.h> -/* - * All usbpf implementations are extracted from bpf(9) APIs and it's - * specialized for USB packet filtering between the driver and the host - * controller. - */ - -MALLOC_DEFINE(M_USBPF, "USBPktFilter", "USB Packet Filter"); - -/* - * Rotate the packet buffers in descriptor ud. Move the store buffer into the - * hold slot, and the free buffer ino the store slot. Zero the length of the - * new store buffer. Descriptor lock should be held. - */ -#define USBPF_ROTATE_BUFFERS(ud) do { \ - (ud)->ud_hbuf = (ud)->ud_sbuf; \ - (ud)->ud_hlen = (ud)->ud_slen; \ - (ud)->ud_sbuf = (ud)->ud_fbuf; \ - (ud)->ud_slen = 0; \ - (ud)->ud_fbuf = NULL; \ - usbpf_bufheld(ud); \ -} while (0) - -#ifndef __i386__ -#define USBPF_ALIGN -#endif - -#ifndef USBPF_ALIGN -#define USBPF_EXTRACT_SHORT(p) ((u_int16_t)ntohs(*(u_int16_t *)p)) -#define USBPF_EXTRACT_LONG(p) (ntohl(*(u_int32_t *)p)) -#else -#define USBPF_EXTRACT_SHORT(p) \ - ((u_int16_t) \ - ((u_int16_t)*((u_char *)p+0)<<8| \ - (u_int16_t)*((u_char *)p+1)<<0)) -#define USBPF_EXTRACT_LONG(p) \ - ((u_int32_t)*((u_char *)p+0)<<24| \ - (u_int32_t)*((u_char *)p+1)<<16| \ - (u_int32_t)*((u_char *)p+2)<<8| \ - (u_int32_t)*((u_char *)p+3)<<0) -#endif - -/* - * Number of scratch memory words (for USBPF_LD|USBPF_MEM and USBPF_ST). - */ -#define USBPF_MEMWORDS 16 - -/* Values for ud_state */ -#define USBPF_IDLE 0 /* no select in progress */ -#define USBPF_WAITING 1 /* waiting for read timeout in select */ -#define USBPF_TIMED_OUT 2 /* read timeout has expired in select */ - -#define PRIUSB 26 /* interruptible */ - -/* Frame directions */ -enum usbpf_direction { - USBPF_D_IN, /* See incoming frames */ - USBPF_D_INOUT, /* See incoming and outgoing frames */ - USBPF_D_OUT /* See outgoing frames */ -}; - -static void usbpf_append_bytes(struct usbpf_d *, caddr_t, u_int, void *, - u_int); -static void usbpf_attachd(struct usbpf_d *, struct usbpf_if *); -static void usbpf_detachd(struct usbpf_d *); -static int usbpf_canfreebuf(struct usbpf_d *); -static void usbpf_buf_reclaimed(struct usbpf_d *); -static int usbpf_canwritebuf(struct usbpf_d *); - -static d_open_t usbpf_open; -static d_read_t usbpf_read; -static d_write_t usbpf_write; -static d_ioctl_t usbpf_ioctl; -static d_poll_t usbpf_poll; -static d_kqfilter_t usbpf_kqfilter; - -static struct cdevsw usbpf_cdevsw = { - .d_version = D_VERSION, - .d_open = usbpf_open, - .d_read = usbpf_read, - .d_write = usbpf_write, - .d_ioctl = usbpf_ioctl, - .d_poll = usbpf_poll, - .d_name = "usbpf", - .d_kqfilter = usbpf_kqfilter, -}; - -static LIST_HEAD(, usbpf_if) usbpf_iflist; -static struct mtx usbpf_mtx; /* global lock */ -static int usbpf_uifd_cnt; - -static int usbpf_bufsize = 4096; -#define USBPF_MINBUFSIZE 32 -#define USBPF_MAXBUFSIZE 0x80000 -static int usbpf_maxbufsize = USBPF_MAXBUFSIZE; -#define USBPF_MAXINSNS 512 -static int usbpf_maxinsns = USBPF_MAXINSNS; - -static void -usbpf_buffer_init(struct usbpf_d *ud) -{ - - ud->ud_bufsize = usbpf_bufsize; -} - -/* - * Free USBPF kernel buffers on device close. - */ -static void -usbpf_buffer_free(struct usbpf_d *ud) -{ - - if (ud->ud_sbuf != NULL) - free(ud->ud_sbuf, M_USBPF); - if (ud->ud_hbuf != NULL) - free(ud->ud_hbuf, M_USBPF); - if (ud->ud_fbuf != NULL) - free(ud->ud_fbuf, M_USBPF); - -#ifdef INVARIANTS - ud->ud_sbuf = ud->ud_hbuf = ud->ud_fbuf = (caddr_t)~0; -#endif -} - -static void -usbpf_buffer_alloc(struct usbpf_d *ud) -{ - - KASSERT(ud->ud_fbuf == NULL, ("%s: ud_fbuf != NULL", __func__)); - KASSERT(ud->ud_sbuf == NULL, ("%s: ud_sbuf != NULL", __func__)); - KASSERT(ud->ud_hbuf == NULL, ("%s: ud_hbuf != NULL", __func__)); - - ud->ud_fbuf = (caddr_t)malloc(ud->ud_bufsize, M_USBPF, M_WAITOK); - ud->ud_sbuf = (caddr_t)malloc(ud->ud_bufsize, M_USBPF, M_WAITOK); - ud->ud_hbuf = NULL; - ud->ud_slen = 0; - ud->ud_hlen = 0; -} - -/* - * Copy buffer storage to user space in read(). - */ -static int -usbpf_buffer_uiomove(struct usbpf_d *ud, caddr_t buf, u_int len, - struct uio *uio) -{ - - return (uiomove(buf, len, uio)); -} - -/* - * Simple data copy to the current kernel buffer. - */ -static void -usbpf_buffer_append_bytes(struct usbpf_d *ud, caddr_t buf, u_int offset, - void *src, u_int len) -{ - u_char *src_bytes; - - src_bytes = (u_char *)src; - bcopy(src_bytes, buf + offset, len); -} - -/* - * Allocate or resize buffers. - */ -static int -usbpf_buffer_ioctl_sblen(struct usbpf_d *ud, u_int *i) -{ - u_int size; - - USBPFD_LOCK(ud); - if (ud->ud_bif != NULL) { - USBPFD_UNLOCK(ud); - return (EINVAL); - } - size = *i; - if (size > usbpf_maxbufsize) - *i = size = usbpf_maxbufsize; - else if (size < USBPF_MINBUFSIZE) - *i = size = USBPF_MINBUFSIZE; - ud->ud_bufsize = size; - USBPFD_UNLOCK(ud); - return (0); -} - -static const u_short usbpf_code_map[] = { - 0x10ff, /* 0x00-0x0f: 1111111100001000 */ - 0x3070, /* 0x10-0x1f: 0000111000001100 */ - 0x3131, /* 0x20-0x2f: 1000110010001100 */ - 0x3031, /* 0x30-0x3f: 1000110000001100 */ - 0x3131, /* 0x40-0x4f: 1000110010001100 */ - 0x1011, /* 0x50-0x5f: 1000100000001000 */ - 0x1013, /* 0x60-0x6f: 1100100000001000 */ - 0x1010, /* 0x70-0x7f: 0000100000001000 */ - 0x0093, /* 0x80-0x8f: 1100100100000000 */ - 0x0000, /* 0x90-0x9f: 0000000000000000 */ - 0x0000, /* 0xa0-0xaf: 0000000000000000 */ - 0x0002, /* 0xb0-0xbf: 0100000000000000 */ - 0x0000, /* 0xc0-0xcf: 0000000000000000 */ - 0x0000, /* 0xd0-0xdf: 0000000000000000 */ - 0x0000, /* 0xe0-0xef: 0000000000000000 */ - 0x0000 /* 0xf0-0xff: 0000000000000000 */ -}; - -#define USBPF_VALIDATE_CODE(c) \ - ((c) <= 0xff && (usbpf_code_map[(c) >> 4] & (1 << ((c) & 0xf))) != 0) - -/* - * Return true if the 'fcode' is a valid filter program. - * The constraints are that each jump be forward and to a valid - * code. The code must terminate with either an accept or reject. - * - * The kernel needs to be able to verify an application's filter code. - * Otherwise, a bogus program could easily crash the system. - */ -static int -usbpf_validate(const struct usbpf_insn *f, int len) -{ - register int i; - register const struct usbpf_insn *p; - - /* Do not accept negative length filter. */ - if (len < 0) - return (0); - - /* An empty filter means accept all. */ - if (len == 0) - return (1); - - for (i = 0; i < len; ++i) { - p = &f[i]; - /* - * Check that the code is valid. - */ - if (!USBPF_VALIDATE_CODE(p->code)) - return (0); - /* - * Check that that jumps are forward, and within - * the code block. - */ - if (USBPF_CLASS(p->code) == USBPF_JMP) { - register u_int offset; - - if (p->code == (USBPF_JMP|USBPF_JA)) - offset = p->k; - else - offset = p->jt > p->jf ? p->jt : p->jf; - if (offset >= (u_int)(len - i) - 1) - return (0); - continue; - } - /* - * Check that memory operations use valid addresses. - */ - if (p->code == USBPF_ST || p->code == USBPF_STX || - p->code == (USBPF_LD|USBPF_MEM) || - p->code == (USBPF_LDX|USBPF_MEM)) { - if (p->k >= USBPF_MEMWORDS) - return (0); - continue; - } - /* - * Check for constant division by 0. - */ - if (p->code == (USBPF_ALU|USBPF_DIV|USBPF_K) && p->k == 0) - return (0); - } - return (USBPF_CLASS(f[len - 1].code) == USBPF_RET); -} - -#ifdef _KERNEL -#define MINDEX(m, k) \ -{ \ - register int len = m->m_len; \ - \ - while (k >= len) { \ - k -= len; \ - m = m->m_next; \ - if (m == 0) \ - return (0); \ - len = m->m_len; \ - } \ -} - -static u_int16_t m_xhalf(struct mbuf *m, usbpf_u_int32 k, int *err); -static u_int32_t m_xword(struct mbuf *m, usbpf_u_int32 k, int *err); - -static u_int32_t -m_xword(struct mbuf *m, usbpf_u_int32 k, int *err) -{ - size_t len; - u_char *cp, *np; - struct mbuf *m0; - - len = m->m_len; - while (k >= len) { - k -= len; - m = m->m_next; - if (m == 0) - goto bad; - len = m->m_len; - } - cp = mtod(m, u_char *) + k; - if (len - k >= 4) { - *err = 0; - return (USBPF_EXTRACT_LONG(cp)); - } - m0 = m->m_next; - if (m0 == 0 || m0->m_len + len - k < 4) - goto bad; - *err = 0; - np = mtod(m0, u_char *); - switch (len - k) { - case 1: - return (((u_int32_t)cp[0] << 24) | - ((u_int32_t)np[0] << 16) | - ((u_int32_t)np[1] << 8) | - (u_int32_t)np[2]); - - case 2: - return (((u_int32_t)cp[0] << 24) | - ((u_int32_t)cp[1] << 16) | - ((u_int32_t)np[0] << 8) | - (u_int32_t)np[1]); - - default: - return (((u_int32_t)cp[0] << 24) | - ((u_int32_t)cp[1] << 16) | - ((u_int32_t)cp[2] << 8) | - (u_int32_t)np[0]); - } - bad: - *err = 1; - return (0); -} - -static u_int16_t -m_xhalf(struct mbuf *m, usbpf_u_int32 k, int *err) -{ - size_t len; - u_char *cp; - struct mbuf *m0; - - len = m->m_len; - while (k >= len) { - k -= len; - m = m->m_next; - if (m == 0) - goto bad; - len = m->m_len; - } - cp = mtod(m, u_char *) + k; - if (len - k >= 2) { - *err = 0; - return (USBPF_EXTRACT_SHORT(cp)); - } - m0 = m->m_next; - if (m0 == 0) - goto bad; - *err = 0; - return ((cp[0] << 8) | mtod(m0, u_char *)[0]); - bad: - *err = 1; - return (0); -} -#endif - -/* - * Execute the filter program starting at pc on the packet p - * wirelen is the length of the original packet - * buflen is the amount of data present - */ -static u_int -usbpf_filter(const struct usbpf_insn *pc, u_char *p, u_int wirelen, - u_int buflen) -{ - u_int32_t A = 0, X = 0; - usbpf_u_int32 k; - u_int32_t mem[USBPF_MEMWORDS]; - - /* - * XXX temporarily the filter system is disabled because currently it - * could not handle the some machine code properly that leads to - * kernel crash by invalid usage. - */ - return ((u_int)-1); - - if (pc == NULL) - /* - * No filter means accept all. - */ - return ((u_int)-1); - - --pc; - while (1) { - ++pc; - switch (pc->code) { - default: -#ifdef _KERNEL - return (0); -#else - abort(); -#endif - - case USBPF_RET|USBPF_K: - return ((u_int)pc->k); - - case USBPF_RET|USBPF_A: - return ((u_int)A); - - case USBPF_LD|USBPF_W|USBPF_ABS: - k = pc->k; - if (k > buflen || sizeof(int32_t) > buflen - k) { -#ifdef _KERNEL - int merr; - - if (buflen != 0) - return (0); - A = m_xword((struct mbuf *)p, k, &merr); - if (merr != 0) - return (0); - continue; -#else - return (0); -#endif - } -#ifdef USBPF_ALIGN - if (((intptr_t)(p + k) & 3) != 0) - A = USBPF_EXTRACT_LONG(&p[k]); - else -#endif - A = ntohl(*(int32_t *)(p + k)); - continue; - - case USBPF_LD|USBPF_H|USBPF_ABS: - k = pc->k; - if (k > buflen || sizeof(int16_t) > buflen - k) { -#ifdef _KERNEL - int merr; - - if (buflen != 0) - return (0); - A = m_xhalf((struct mbuf *)p, k, &merr); - continue; -#else - return (0); -#endif - } - A = USBPF_EXTRACT_SHORT(&p[k]); - continue; - - case USBPF_LD|USBPF_B|USBPF_ABS: - k = pc->k; - if (k >= buflen) { -#ifdef _KERNEL - struct mbuf *m; - - if (buflen != 0) - return (0); - m = (struct mbuf *)p; - MINDEX(m, k); - A = mtod(m, u_char *)[k]; - continue; -#else - return (0); -#endif - } - A = p[k]; - continue; - - case USBPF_LD|USBPF_W|USBPF_LEN: - A = wirelen; - continue; - - case USBPF_LDX|USBPF_W|USBPF_LEN: - X = wirelen; - continue; - - case USBPF_LD|USBPF_W|USBPF_IND: - k = X + pc->k; - if (pc->k > buflen || X > buflen - pc->k || - sizeof(int32_t) > buflen - k) { -#ifdef _KERNEL - int merr; - - if (buflen != 0) - return (0); - A = m_xword((struct mbuf *)p, k, &merr); - if (merr != 0) - return (0); - continue; -#else - return (0); -#endif - } -#ifdef USBPF_ALIGN - if (((intptr_t)(p + k) & 3) != 0) - A = USBPF_EXTRACT_LONG(&p[k]); - else -#endif - A = ntohl(*(int32_t *)(p + k)); - continue; - - case USBPF_LD|USBPF_H|USBPF_IND: - k = X + pc->k; - if (X > buflen || pc->k > buflen - X || - sizeof(int16_t) > buflen - k) { -#ifdef _KERNEL - int merr; - - if (buflen != 0) - return (0); - A = m_xhalf((struct mbuf *)p, k, &merr); - if (merr != 0) - return (0); - continue; -#else - return (0); -#endif - } - A = USBPF_EXTRACT_SHORT(&p[k]); - continue; - - case USBPF_LD|USBPF_B|USBPF_IND: - k = X + pc->k; - if (pc->k >= buflen || X >= buflen - pc->k) { -#ifdef _KERNEL - struct mbuf *m; - - if (buflen != 0) - return (0); - m = (struct mbuf *)p; - MINDEX(m, k); - A = mtod(m, u_char *)[k]; - continue; -#else - return (0); -#endif - } - A = p[k]; - continue; - - case USBPF_LDX|USBPF_MSH|USBPF_B: - k = pc->k; - if (k >= buflen) { -#ifdef _KERNEL - register struct mbuf *m; - - if (buflen != 0) - return (0); - m = (struct mbuf *)p; - MINDEX(m, k); - X = (mtod(m, u_char *)[k] & 0xf) << 2; - continue; -#else - return (0); -#endif - } - X = (p[pc->k] & 0xf) << 2; - continue; - - case USBPF_LD|USBPF_IMM: - A = pc->k; - continue; - - case USBPF_LDX|USBPF_IMM: - X = pc->k; - continue; - - case USBPF_LD|USBPF_MEM: - A = mem[pc->k]; - continue; - - case USBPF_LDX|USBPF_MEM: - X = mem[pc->k]; - continue; - - case USBPF_ST: - mem[pc->k] = A; - continue; - - case USBPF_STX: - mem[pc->k] = X; - continue; - - case USBPF_JMP|USBPF_JA: - pc += pc->k; - continue; - - case USBPF_JMP|USBPF_JGT|USBPF_K: - pc += (A > pc->k) ? pc->jt : pc->jf; - continue; - - case USBPF_JMP|USBPF_JGE|USBPF_K: - pc += (A >= pc->k) ? pc->jt : pc->jf; - continue; - - case USBPF_JMP|USBPF_JEQ|USBPF_K: - pc += (A == pc->k) ? pc->jt : pc->jf; - continue; - - case USBPF_JMP|USBPF_JSET|USBPF_K: - pc += (A & pc->k) ? pc->jt : pc->jf; - continue; - - case USBPF_JMP|USBPF_JGT|USBPF_X: - pc += (A > X) ? pc->jt : pc->jf; - continue; - - case USBPF_JMP|USBPF_JGE|USBPF_X: - pc += (A >= X) ? pc->jt : pc->jf; - continue; - - case USBPF_JMP|USBPF_JEQ|USBPF_X: - pc += (A == X) ? pc->jt : pc->jf; - continue; - - case USBPF_JMP|USBPF_JSET|USBPF_X: - pc += (A & X) ? pc->jt : pc->jf; - continue; - - case USBPF_ALU|USBPF_ADD|USBPF_X: - A += X; - continue; - - case USBPF_ALU|USBPF_SUB|USBPF_X: - A -= X; - continue; - - case USBPF_ALU|USBPF_MUL|USBPF_X: - A *= X; - continue; - - case USBPF_ALU|USBPF_DIV|USBPF_X: - if (X == 0) - return (0); - A /= X; - continue; - - case USBPF_ALU|USBPF_AND|USBPF_X: - A &= X; - continue; - - case USBPF_ALU|USBPF_OR|USBPF_X: - A |= X; - continue; - - case USBPF_ALU|USBPF_LSH|USBPF_X: - A <<= X; - continue; - - case USBPF_ALU|USBPF_RSH|USBPF_X: - A >>= X; - continue; - - case USBPF_ALU|USBPF_ADD|USBPF_K: - A += pc->k; - continue; - - case USBPF_ALU|USBPF_SUB|USBPF_K: - A -= pc->k; - continue; - - case USBPF_ALU|USBPF_MUL|USBPF_K: - A *= pc->k; - continue; - - case USBPF_ALU|USBPF_DIV|USBPF_K: - A /= pc->k; - continue; - - case USBPF_ALU|USBPF_AND|USBPF_K: - A &= pc->k; - continue; - - case USBPF_ALU|USBPF_OR|USBPF_K: - A |= pc->k; - continue; - - case USBPF_ALU|USBPF_LSH|USBPF_K: - A <<= pc->k; - continue; - - case USBPF_ALU|USBPF_RSH|USBPF_K: - A >>= pc->k; - continue; - - case USBPF_ALU|USBPF_NEG: - A = -A; - continue; - - case USBPF_MISC|USBPF_TAX: - X = A; - continue; - - case USBPF_MISC|USBPF_TXA: - A = X; - continue; - } - } -} - -static void -usbpf_free(struct usbpf_d *ud) -{ - - switch (ud->ud_bufmode) { - case USBPF_BUFMODE_BUFFER: - return (usbpf_buffer_free(ud)); - default: - panic("usbpf_buf_free"); - } -} - -/* - * Notify the buffer model that a buffer has moved into the hold position. - */ -static void -usbpf_bufheld(struct usbpf_d *ud) -{ - - USBPFD_LOCK_ASSERT(ud); -} - -/* - * Free buffers currently in use by a descriptor. - * Called on close. - */ -static void -usbpf_freed(struct usbpf_d *ud) -{ - - /* - * We don't need to lock out interrupts since this descriptor has - * been detached from its interface and it yet hasn't been marked - * free. - */ - usbpf_free(ud); - if (ud->ud_rfilter != NULL) - free((caddr_t)ud->ud_rfilter, M_USBPF); - if (ud->ud_wfilter != NULL) - free((caddr_t)ud->ud_wfilter, M_USBPF); - mtx_destroy(&ud->ud_mtx); -} - -/* - * Close the descriptor by detaching it from its interface, - * deallocating its buffers, and marking it free. - */ -static void -usbpf_dtor(void *data) -{ - struct usbpf_d *ud = data; - - USBPFD_LOCK(ud); - if (ud->ud_state == USBPF_WAITING) - callout_stop(&ud->ud_callout); - ud->ud_state = USBPF_IDLE; - USBPFD_UNLOCK(ud); - funsetown(&ud->ud_sigio); - mtx_lock(&usbpf_mtx); - if (ud->ud_bif) - usbpf_detachd(ud); - mtx_unlock(&usbpf_mtx); - selwakeuppri(&ud->ud_sel, PRIUSB); - knlist_destroy(&ud->ud_sel.si_note); - callout_drain(&ud->ud_callout); - usbpf_freed(ud); - free(ud, M_USBPF); -} - -/* - * Open device. Returns ENXIO for illegal minor device number, - * EBUSY if file is open by another process. - */ -/* ARGSUSED */ -static int -usbpf_open(struct cdev *dev, int flags, int fmt, struct thread *td) -{ - struct usbpf_d *ud; - int error; - - ud = malloc(sizeof(*ud), M_USBPF, M_WAITOK | M_ZERO); - error = devfs_set_cdevpriv(ud, usbpf_dtor); - if (error != 0) { - free(ud, M_USBPF); - return (error); - } - - usbpf_buffer_init(ud); - ud->ud_bufmode = USBPF_BUFMODE_BUFFER; - ud->ud_sig = SIGIO; - ud->ud_direction = USBPF_D_INOUT; - ud->ud_pid = td->td_proc->p_pid; - mtx_init(&ud->ud_mtx, devtoname(dev), "usbpf cdev lock", MTX_DEF); - callout_init_mtx(&ud->ud_callout, &ud->ud_mtx, 0); - knlist_init_mtx(&ud->ud_sel.si_note, &ud->ud_mtx); - - return (0); -} - -static int -usbpf_uiomove(struct usbpf_d *ud, caddr_t buf, u_int len, struct uio *uio) -{ - - if (ud->ud_bufmode != USBPF_BUFMODE_BUFFER) - return (EOPNOTSUPP); - return (usbpf_buffer_uiomove(ud, buf, len, uio)); -} - -/* - * usbpf_read - read next chunk of packets from buffers - */ -static int -usbpf_read(struct cdev *dev, struct uio *uio, int ioflag) -{ - struct usbpf_d *ud; - int error; - int non_block; - int timed_out; - - error = devfs_get_cdevpriv((void **)&ud); - if (error != 0) - return (error); - - /* - * Restrict application to use a buffer the same size as - * as kernel buffers. - */ - if (uio->uio_resid != ud->ud_bufsize) - return (EINVAL); - - non_block = ((ioflag & O_NONBLOCK) != 0); - - USBPFD_LOCK(ud); - ud->ud_pid = curthread->td_proc->p_pid; - if (ud->ud_bufmode != USBPF_BUFMODE_BUFFER) { - USBPFD_UNLOCK(ud); - return (EOPNOTSUPP); - } - if (ud->ud_state == USBPF_WAITING) - callout_stop(&ud->ud_callout); - timed_out = (ud->ud_state == USBPF_TIMED_OUT); - ud->ud_state = USBPF_IDLE; - /* - * If the hold buffer is empty, then do a timed sleep, which - * ends when the timeout expires or when enough packets - * have arrived to fill the store buffer. - */ - while (ud->ud_hbuf == NULL) { - if (ud->ud_slen != 0) { - /* - * A packet(s) either arrived since the previous - * read or arrived while we were asleep. - */ - if (ud->ud_immediate || non_block || timed_out) { - /* - * Rotate the buffers and return what's here - * if we are in immediate mode, non-blocking - * flag is set, or this descriptor timed out. - */ - USBPF_ROTATE_BUFFERS(ud); - break; - } - } - - /* - * No data is available, check to see if the usbpf device - * is still pointed at a real interface. If not, return - * ENXIO so that the userland process knows to rebind - * it before using it again. - */ - if (ud->ud_bif == NULL) { - USBPFD_UNLOCK(ud); - return (ENXIO); - } - - if (non_block) { - USBPFD_UNLOCK(ud); - return (EWOULDBLOCK); - } - error = msleep(ud, &ud->ud_mtx, PRIUSB|PCATCH, - "uff", ud->ud_rtout); - if (error == EINTR || error == ERESTART) { - USBPFD_UNLOCK(ud); - return (error); - } - if (error == EWOULDBLOCK) { - /* - * On a timeout, return what's in the buffer, - * which may be nothing. If there is something - * in the store buffer, we can rotate the buffers. - */ - if (ud->ud_hbuf) - /* - * We filled up the buffer in between - * getting the timeout and arriving - * here, so we don't need to rotate. - */ - break; - - if (ud->ud_slen == 0) { - USBPFD_UNLOCK(ud); - return (0); - } - USBPF_ROTATE_BUFFERS(ud); - break; - } - } - /* - * At this point, we know we have something in the hold slot. - */ - USBPFD_UNLOCK(ud); - - /* - * Move data from hold buffer into user space. - * We know the entire buffer is transferred since - * we checked above that the read buffer is usbpf_bufsize bytes. - * - * XXXRW: More synchronization needed here: what if a second thread - * issues a read on the same fd at the same time? Don't want this - * getting invalidated. - */ - error = usbpf_uiomove(ud, ud->ud_hbuf, ud->ud_hlen, uio); - - USBPFD_LOCK(ud); - ud->ud_fbuf = ud->ud_hbuf; - ud->ud_hbuf = NULL; - ud->ud_hlen = 0; - usbpf_buf_reclaimed(ud); - USBPFD_UNLOCK(ud); - - return (error); -} - -static int -usbpf_write(struct cdev *dev, struct uio *uio, int ioflag) -{ - - /* NOT IMPLEMENTED */ - return (ENOSYS); -} - -static int -usbpf_ioctl_sblen(struct usbpf_d *ud, u_int *i) -{ - - if (ud->ud_bufmode != USBPF_BUFMODE_BUFFER) - return (EOPNOTSUPP); - return (usbpf_buffer_ioctl_sblen(ud, i)); -} - -/* - * Reset a descriptor by flushing its packet buffer and clearing the receive - * and drop counts. This is doable for kernel-only buffers, but with - * zero-copy buffers, we can't write to (or rotate) buffers that are - * currently owned by userspace. It would be nice if we could encapsulate - * this logic in the buffer code rather than here. - */ -static void -usbpf_reset_d(struct usbpf_d *ud) -{ - - USBPFD_LOCK_ASSERT(ud); - - if ((ud->ud_hbuf != NULL) && - (ud->ud_bufmode != USBPF_BUFMODE_ZBUF || usbpf_canfreebuf(ud))) { - /* Free the hold buffer. */ - ud->ud_fbuf = ud->ud_hbuf; - ud->ud_hbuf = NULL; - ud->ud_hlen = 0; - usbpf_buf_reclaimed(ud); - } - if (usbpf_canwritebuf(ud)) - ud->ud_slen = 0; - ud->ud_rcount = 0; - ud->ud_dcount = 0; - ud->ud_fcount = 0; - ud->ud_wcount = 0; - ud->ud_wfcount = 0; - ud->ud_wdcount = 0; - ud->ud_zcopy = 0; -} - -static int -usbpf_setif(struct usbpf_d *ud, struct usbpf_ifreq *ufr) -{ - struct usbpf_if *uif; - struct usb_bus *theywant; - - theywant = usb_bus_find(ufr->ufr_name); - if (theywant == NULL || theywant->uif == NULL) - return (ENXIO); - - uif = theywant->uif; - - switch (ud->ud_bufmode) { - case USBPF_BUFMODE_BUFFER: - if (ud->ud_sbuf == NULL) - usbpf_buffer_alloc(ud); - KASSERT(ud->ud_sbuf != NULL, ("%s: ud_sbuf == NULL", __func__)); - break; - - default: - panic("usbpf_setif: bufmode %d", ud->ud_bufmode); - } - if (uif != ud->ud_bif) { - if (ud->ud_bif) - /* - * Detach if attached to something else. - */ - usbpf_detachd(ud); - - usbpf_attachd(ud, uif); - } - USBPFD_LOCK(ud); - usbpf_reset_d(ud); - USBPFD_UNLOCK(ud); - return (0); -} - -/* - * Set d's packet filter program to fp. If this file already has a filter, - * free it and replace it. Returns EINVAL for bogus requests. - */ -static int -usbpf_setf(struct usbpf_d *ud, struct usbpf_program *fp, u_long cmd) -{ - struct usbpf_insn *fcode, *old; - u_int wfilter, flen, size; - - if (cmd == UIOCSETWF) { - old = ud->ud_wfilter; - wfilter = 1; - } else { - wfilter = 0; - old = ud->ud_rfilter; - } - if (fp->uf_insns == NULL) { - if (fp->uf_len != 0) - return (EINVAL); - USBPFD_LOCK(ud); - if (wfilter) - ud->ud_wfilter = NULL; - else { - ud->ud_rfilter = NULL; - if (cmd == UIOCSETF) - usbpf_reset_d(ud); - } - USBPFD_UNLOCK(ud); - if (old != NULL) - free((caddr_t)old, M_USBPF); - return (0); - } - flen = fp->uf_len; - if (flen > usbpf_maxinsns) - return (EINVAL); - - size = flen * sizeof(*fp->uf_insns); - fcode = (struct usbpf_insn *)malloc(size, M_USBPF, M_WAITOK); - if (copyin((caddr_t)fp->uf_insns, (caddr_t)fcode, size) == 0 && - usbpf_validate(fcode, (int)flen)) { - USBPFD_LOCK(ud); - if (wfilter) - ud->ud_wfilter = fcode; - else { - ud->ud_rfilter = fcode; - if (cmd == UIOCSETF) - usbpf_reset_d(ud); - } - USBPFD_UNLOCK(ud); - if (old != NULL) - free((caddr_t)old, M_USBPF); - - return (0); - } - free((caddr_t)fcode, M_USBPF); - return (EINVAL); -} - -static int -usbpf_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, - struct thread *td) -{ - struct usbpf_d *ud; - int error; - - error = devfs_get_cdevpriv((void **)&ud); - if (error != 0) - return (error); - - /* - * Refresh PID associated with this descriptor. - */ - USBPFD_LOCK(ud); - ud->ud_pid = td->td_proc->p_pid; - if (ud->ud_state == USBPF_WAITING) - callout_stop(&ud->ud_callout); - ud->ud_state = USBPF_IDLE; - USBPFD_UNLOCK(ud); - - if (ud->ud_locked == 1) { - switch (cmd) { - case UIOCGBLEN: - case UIOCSBLEN: - case UIOCVERSION: - break; - default: - return (EPERM); - } - } - - switch (cmd) { - - default: - error = EINVAL; - break; - - /* - * Get buffer len [for read()]. - */ - case UIOCGBLEN: - *(u_int *)addr = ud->ud_bufsize; - break; - - /* - * Set buffer length. - */ - case UIOCSBLEN: - error = usbpf_ioctl_sblen(ud, (u_int *)addr); - break; - - /* - * Set read filter. - */ - case UIOCSETF: - error = usbpf_setf(ud, (struct usbpf_program *)addr, cmd); - break; - - /* - * Set read timeout. - */ - case UIOCSRTIMEOUT: - { - struct timeval *tv = (struct timeval *)addr; - - /* - * Subtract 1 tick from tvtohz() since this isn't - * a one-shot timer. - */ - if ((error = itimerfix(tv)) == 0) - ud->ud_rtout = tvtohz(tv) - 1; - break; - } - - /* - * Get read timeout. - */ - case UIOCGRTIMEOUT: - { - struct timeval *tv = (struct timeval *)addr; - - tv->tv_sec = ud->ud_rtout / hz; - tv->tv_usec = (ud->ud_rtout % hz) * tick; - break; - } - - /* - * Get packet stats. - */ - case UIOCGSTATS: - { - struct usbpf_stat *us = (struct usbpf_stat *)addr; - - /* XXXCSJP overflow */ - us->us_recv = ud->ud_rcount; - us->us_drop = ud->ud_dcount; - break; - } - - case UIOCVERSION: - { - struct usbpf_version *uv = (struct usbpf_version *)addr; - - uv->uv_major = USBPF_MAJOR_VERSION; - uv->uv_minor = USBPF_MINOR_VERSION; - break; - } - - /* - * Set interface. - */ - case UIOCSETIF: - error = usbpf_setif(ud, (struct usbpf_ifreq *)addr); - break; - - } - return (error); -} - -/* - * Support for select() and poll() system calls - * - * Return true iff the specific operation will not block indefinitely. - * Otherwise, return false but make a note that a selwakeup() must be done. - */ -static int -usbpf_poll(struct cdev *dev, int events, struct thread *td) -{ - - /* NOT IMPLEMENTED */ - return (ENOSYS); -} - -/* - * Support for kevent() system call. Register EVFILT_READ filters and - * reject all others. - */ -int -usbpf_kqfilter(struct cdev *dev, struct knote *kn) -{ - - /* NOT IMPLEMENTED */ - return (ENOSYS); -} - -/* - * Attach file to the usbpf interface, i.e. make d listen on bp. - */ -static void -usbpf_attachd(struct usbpf_d *ud, struct usbpf_if *uif) +void +usbpf_attach(struct usb_bus *ubus) { + struct ifnet *ifp; - USBPFIF_LOCK(uif); - ud->ud_bif = uif; - LIST_INSERT_HEAD(&uif->uif_dlist, ud, ud_next); + ifp = ubus->ifp = if_alloc(IFT_USB); + if_initname(ifp, "usbus", device_get_unit(ubus->bdev)); + if_attach(ifp); - usbpf_uifd_cnt++; - USBPFIF_UNLOCK(uif); -} - -/* - * Detach a file from its interface. - */ -static void -usbpf_detachd(struct usbpf_d *ud) -{ - struct usbpf_if *uif; - struct usb_bus *ubus; - - uif = ud->ud_bif; - USBPFIF_LOCK(uif); - USBPFD_LOCK(ud); - ubus = ud->ud_bif->uif_ubus; + KASSERT(sizeof(struct usbpf_pkthdr) == USBPF_HDR_LEN, + ("wrong USB pf header length (%zd)", sizeof(struct usbpf_pkthdr))); /* - * Remove d from the interface's descriptor list. + * XXX According to the specification of DLT_USB, it indicates packets + * beginning with USB setup header. But not sure all packets would be. */ - LIST_REMOVE(ud, ud_next); - - usbpf_uifd_cnt--; - ud->ud_bif = NULL; - USBPFD_UNLOCK(ud); - USBPFIF_UNLOCK(uif); -} - -void -usbpf_attach(struct usb_bus *ubus, struct usbpf_if **driverp) -{ - struct usbpf_if *uif; - - uif = malloc(sizeof(*uif), M_USBPF, M_WAITOK | M_ZERO); - LIST_INIT(&uif->uif_dlist); - uif->uif_ubus = ubus; - mtx_init(&uif->uif_mtx, "usbpf interface lock", NULL, MTX_DEF); - KASSERT(*driverp == NULL, - ("usbpf_attach: driverp already initialized")); - *driverp = uif; - - mtx_lock(&usbpf_mtx); - LIST_INSERT_HEAD(&usbpf_iflist, uif, uif_next); - mtx_unlock(&usbpf_mtx); + bpfattach(ifp, DLT_USB, USBPF_HDR_LEN); if (bootverbose) device_printf(ubus->parent, "usbpf attached\n"); } -/* - * If there are processes sleeping on this descriptor, wake them up. - */ -static __inline void -usbpf_wakeup(struct usbpf_d *ud) -{ - - USBPFD_LOCK_ASSERT(ud); - if (ud->ud_state == USBPF_WAITING) { - callout_stop(&ud->ud_callout); - ud->ud_state = USBPF_IDLE; - } - wakeup(ud); - if (ud->ud_async && ud->ud_sig && ud->ud_sigio) - pgsigio(&ud->ud_sigio, ud->ud_sig, 0); - - selwakeuppri(&ud->ud_sel, PRIUSB); - KNOTE_LOCKED(&ud->ud_sel.si_note, 0); -} - void usbpf_detach(struct usb_bus *ubus) { - struct usbpf_if *uif; - struct usbpf_d *ud; - - /* Locate USBPF interface information */ - mtx_lock(&usbpf_mtx); - LIST_FOREACH(uif, &usbpf_iflist, uif_next) { - if (ubus == uif->uif_ubus) - break; - } - - /* Interface wasn't attached */ - if ((uif == NULL) || (uif->uif_ubus == NULL)) { - mtx_unlock(&usbpf_mtx); - printf("usbpf_detach: not attached\n"); /* XXX */ - return; - } - - LIST_REMOVE(uif, uif_next); - mtx_unlock(&usbpf_mtx); - - while ((ud = LIST_FIRST(&uif->uif_dlist)) != NULL) { - usbpf_detachd(ud); - USBPFD_LOCK(ud); - usbpf_wakeup(ud); - USBPFD_UNLOCK(ud); - } - - mtx_destroy(&uif->uif_mtx); - free(uif, M_USBPF); -} - -/* Time stamping functions */ -#define USBPF_T_MICROTIME 0x0000 -#define USBPF_T_NANOTIME 0x0001 -#define USBPF_T_BINTIME 0x0002 -#define USBPF_T_NONE 0x0003 -#define USBPF_T_FORMAT_MASK 0x0003 -#define USBPF_T_NORMAL 0x0000 -#define USBPF_T_FAST 0x0100 -#define USBPF_T_MONOTONIC 0x0200 -#define USBPF_T_FORMAT(t) ((t) & USBPF_T_FORMAT_MASK) - -#define USBPF_TSTAMP_NONE 0 -#define USBPF_TSTAMP_FAST 1 -#define USBPF_TSTAMP_NORMAL 2 - -static int -usbpf_ts_quality(int tstype) -{ - - if (tstype == USBPF_T_NONE) - return (USBPF_TSTAMP_NONE); - if ((tstype & USBPF_T_FAST) != 0) - return (USBPF_TSTAMP_FAST); - - return (USBPF_TSTAMP_NORMAL); -} - -static int -usbpf_gettime(struct bintime *bt, int tstype) -{ - int quality; - - quality = usbpf_ts_quality(tstype); - if (quality == USBPF_TSTAMP_NONE) - return (quality); - if (quality == USBPF_TSTAMP_NORMAL) - binuptime(bt); - else - getbinuptime(bt); - - return (quality); -} - -/* - * If the buffer mechanism has a way to decide that a held buffer can be made - * free, then it is exposed via the usbpf_canfreebuf() interface. (1) is - * returned if the buffer can be discarded, (0) is returned if it cannot. - */ -static int -usbpf_canfreebuf(struct usbpf_d *ud) -{ - - USBPFD_LOCK_ASSERT(ud); - - return (0); -} - -/* - * Allow the buffer model to indicate that the current store buffer is - * immutable, regardless of the appearance of space. Return (1) if the - * buffer is writable, and (0) if not. - */ -static int -usbpf_canwritebuf(struct usbpf_d *ud) -{ - - USBPFD_LOCK_ASSERT(ud); - return (1); -} + struct ifnet *ifp = ubus->ifp; -/* - * Notify buffer model that an attempt to write to the store buffer has - * resulted in a dropped packet, in which case the buffer may be considered - * full. - */ -static void -usbpf_buffull(struct usbpf_d *ud) -{ - - USBPFD_LOCK_ASSERT(ud); -} - -/* - * This function gets called when the free buffer is re-assigned. - */ -static void -usbpf_buf_reclaimed(struct usbpf_d *ud) -{ - - USBPFD_LOCK_ASSERT(ud); - - switch (ud->ud_bufmode) { - case USBPF_BUFMODE_BUFFER: - return; - - default: - panic("usbpf_buf_reclaimed"); + if (ifp != NULL) { + bpfdetach(ifp); + if_detach(ifp); + if_free(ifp); } -} - -#define SIZEOF_USBPF_HDR(type) \ - (offsetof(type, uh_hdrlen) + sizeof(((type *)0)->uh_hdrlen)) - -static int -usbpf_hdrlen(struct usbpf_d *ud) -{ - int hdrlen; - - hdrlen = ud->ud_bif->uif_hdrlen; - hdrlen += SIZEOF_USBPF_HDR(struct usbpf_xhdr); - hdrlen = USBPF_WORDALIGN(hdrlen); - - return (hdrlen - ud->ud_bif->uif_hdrlen); -} - -static void -usbpf_bintime2ts(struct bintime *bt, struct usbpf_ts *ts, int tstype) -{ - struct bintime bt2; - struct timeval tsm; - struct timespec tsn; - - if ((tstype & USBPF_T_MONOTONIC) == 0) { - bt2 = *bt; - bintime_add(&bt2, &boottimebin); - bt = &bt2; - } - switch (USBPF_T_FORMAT(tstype)) { - case USBPF_T_MICROTIME: - bintime2timeval(bt, &tsm); - ts->ut_sec = tsm.tv_sec; - ts->ut_frac = tsm.tv_usec; - break; - case USBPF_T_NANOTIME: - bintime2timespec(bt, &tsn); - ts->ut_sec = tsn.tv_sec; - ts->ut_frac = tsn.tv_nsec; - break; - case USBPF_T_BINTIME: - ts->ut_sec = bt->sec; - ts->ut_frac = bt->frac; - break; - } -} - -/* - * Move the packet data from interface memory (pkt) into the - * store buffer. "cpfn" is the routine called to do the actual data - * transfer. bcopy is passed in to copy contiguous chunks, while - * usbpf_append_mbuf is passed in to copy mbuf chains. In the latter case, - * pkt is really an mbuf. - */ -static void -catchpacket(struct usbpf_d *ud, u_char *pkt, u_int pktlen, u_int snaplen, - void (*cpfn)(struct usbpf_d *, caddr_t, u_int, void *, u_int), - struct bintime *bt) -{ - struct usbpf_xhdr hdr; - int caplen, curlen, hdrlen, totlen; - int do_wakeup = 0; - int do_timestamp; - int tstype; - - USBPFD_LOCK_ASSERT(ud); - - /* - * Detect whether user space has released a buffer back to us, and if - * so, move it from being a hold buffer to a free buffer. This may - * not be the best place to do it (for example, we might only want to - * run this check if we need the space), but for now it's a reliable - * spot to do it. - */ - if (ud->ud_fbuf == NULL && usbpf_canfreebuf(ud)) { - ud->ud_fbuf = ud->ud_hbuf; - ud->ud_hbuf = NULL; - ud->ud_hlen = 0; - usbpf_buf_reclaimed(ud); - } - - /* - * Figure out how many bytes to move. If the packet is - * greater or equal to the snapshot length, transfer that - * much. Otherwise, transfer the whole packet (unless - * we hit the buffer size limit). - */ - hdrlen = usbpf_hdrlen(ud); - totlen = hdrlen + min(snaplen, pktlen); - if (totlen > ud->ud_bufsize) - totlen = ud->ud_bufsize; - - /* - * Round up the end of the previous packet to the next longword. - * - * Drop the packet if there's no room and no hope of room - * If the packet would overflow the storage buffer or the storage - * buffer is considered immutable by the buffer model, try to rotate - * the buffer and wakeup pending processes. - */ - curlen = USBPF_WORDALIGN(ud->ud_slen); - if (curlen + totlen > ud->ud_bufsize || !usbpf_canwritebuf(ud)) { - if (ud->ud_fbuf == NULL) { - /* - * There's no room in the store buffer, and no - * prospect of room, so drop the packet. Notify the - * buffer model. - */ - usbpf_buffull(ud); - ++ud->ud_dcount; - return; - } - USBPF_ROTATE_BUFFERS(ud); - do_wakeup = 1; - curlen = 0; - } else if (ud->ud_immediate || ud->ud_state == USBPF_TIMED_OUT) - /* - * Immediate mode is set, or the read timeout has already - * expired during a select call. A packet arrived, so the - * reader should be woken up. - */ - do_wakeup = 1; - caplen = totlen - hdrlen; - tstype = ud->ud_tstamp; - do_timestamp = tstype != USBPF_T_NONE; - - /* - * Append the usbpf header. Note we append the actual header size, but - * move forward the length of the header plus padding. - */ - bzero(&hdr, sizeof(hdr)); - if (do_timestamp) - usbpf_bintime2ts(bt, &hdr.uh_tstamp, tstype); - hdr.uh_datalen = pktlen; - hdr.uh_hdrlen = hdrlen; - hdr.uh_caplen = caplen; - usbpf_append_bytes(ud, ud->ud_sbuf, curlen, &hdr, sizeof(hdr)); - - /* - * Copy the packet data into the store buffer and update its length. - */ - (*cpfn)(ud, ud->ud_sbuf, curlen + hdrlen, pkt, caplen); - ud->ud_slen = curlen + totlen; - - if (do_wakeup) - usbpf_wakeup(ud); -} - -/* - * Incoming linkage from device drivers. Process the packet pkt, of length - * pktlen, which is stored in a contiguous buffer. The packet is parsed - * by each process' filter, and if accepted, stashed into the corresponding - * buffer. - */ -static void -usbpf_tap(struct usbpf_if *uif, u_char *pkt, u_int pktlen) -{ - struct bintime bt; - struct usbpf_d *ud; - u_int slen; - int gottime; - - gottime = USBPF_TSTAMP_NONE; - USBPFIF_LOCK(uif); - LIST_FOREACH(ud, &uif->uif_dlist, ud_next) { - USBPFD_LOCK(ud); - ++ud->ud_rcount; - slen = usbpf_filter(ud->ud_rfilter, pkt, pktlen, pktlen); - if (slen != 0) { - ud->ud_fcount++; - if (gottime < usbpf_ts_quality(ud->ud_tstamp)) - gottime = usbpf_gettime(&bt, ud->ud_tstamp); - catchpacket(ud, pkt, pktlen, slen, - usbpf_append_bytes, &bt); - } - USBPFD_UNLOCK(ud); - } - USBPFIF_UNLOCK(uif); + ubus->ifp = NULL; } static uint32_t @@ -1763,11 +181,7 @@ usbpf_xfertap(struct usb_xfer *xfer, int type) int i; char *buf, *ptr, *end; - /* - * NB: usbpf_uifd_cnt isn't protected by USBPFIF_LOCK() because it's - * not harmful. - */ - if (usbpf_uifd_cnt == 0) + if (!bpf_peers_present(bus->ifp->if_bpf)) return; /* @@ -1777,7 +191,7 @@ usbpf_xfertap(struct usb_xfer *xfer, int type) * read filter to pass a virtually linear buffer. */ buf = ptr = malloc(sizeof(struct usbpf_pkthdr) + (USB_PAGE_SIZE * 5), - M_USBPF, M_NOWAIT); + M_TEMP, M_NOWAIT); if (buf == NULL) { printf("usbpf_xfertap: out of memory\n"); /* XXX */ return; @@ -1827,36 +241,7 @@ usbpf_xfertap(struct usb_xfer *xfer, int type) ptr += xfer->frlengths[i]; } - usbpf_tap(bus->uif, buf, ptr - buf); + bpf_tap(bus->ifp->if_bpf, buf, ptr - buf); done: - free(buf, M_USBPF); + free(buf, M_TEMP); } - -static void -usbpf_append_bytes(struct usbpf_d *ud, caddr_t buf, u_int offset, void *src, - u_int len) -{ - - USBPFD_LOCK_ASSERT(ud); - - switch (ud->ud_bufmode) { - case USBPF_BUFMODE_BUFFER: - return (usbpf_buffer_append_bytes(ud, buf, offset, src, len)); - default: - panic("usbpf_buf_append_bytes"); - } -} - -static void -usbpf_drvinit(void *unused) -{ - struct cdev *dev; - - mtx_init(&usbpf_mtx, "USB packet filter global lock", NULL, - MTX_DEF); - LIST_INIT(&usbpf_iflist); - - dev = make_dev(&usbpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "usbpf"); -} - -SYSINIT(usbpf_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, usbpf_drvinit, NULL); diff --git a/sys/dev/usb/usb_pf.h b/sys/dev/usb/usb_pf.h index f5ed9a0..58b9ce9 100644 --- a/sys/dev/usb/usb_pf.h +++ b/sys/dev/usb/usb_pf.h @@ -37,190 +37,6 @@ #ifndef _DEV_USB_PF_H #define _DEV_USB_PF_H -#ifdef _KERNEL -#include <sys/callout.h> -#include <sys/selinfo.h> -#include <sys/queue.h> -#include <sys/conf.h> -#endif - -typedef int32_t usbpf_int32; -typedef u_int32_t usbpf_u_int32; -typedef int64_t usbpf_int64; -typedef u_int64_t usbpf_u_int64; - -struct usbpf_if; - -/* - * Alignment macros. USBPF_WORDALIGN rounds up to the next - * even multiple of USBPF_ALIGNMENT. - */ -#define USBPF_ALIGNMENT sizeof(long) -#define USBPF_WORDALIGN(x) (((x)+(USBPF_ALIGNMENT-1))&~(USBPF_ALIGNMENT-1)) - -/* - * The instruction encodings. - */ - -/* instruction classes */ -#define USBPF_CLASS(code) ((code) & 0x07) -#define USBPF_LD 0x00 -#define USBPF_LDX 0x01 -#define USBPF_ST 0x02 -#define USBPF_STX 0x03 -#define USBPF_ALU 0x04 -#define USBPF_JMP 0x05 -#define USBPF_RET 0x06 -#define USBPF_MISC 0x07 - -/* ld/ldx fields */ -#define USBPF_SIZE(code) ((code) & 0x18) -#define USBPF_W 0x00 -#define USBPF_H 0x08 -#define USBPF_B 0x10 -#define USBPF_MODE(code) ((code) & 0xe0) -#define USBPF_IMM 0x00 -#define USBPF_ABS 0x20 -#define USBPF_IND 0x40 -#define USBPF_MEM 0x60 -#define USBPF_LEN 0x80 -#define USBPF_MSH 0xa0 - -/* alu/jmp fields */ -#define USBPF_OP(code) ((code) & 0xf0) -#define USBPF_ADD 0x00 -#define USBPF_SUB 0x10 -#define USBPF_MUL 0x20 -#define USBPF_DIV 0x30 -#define USBPF_OR 0x40 -#define USBPF_AND 0x50 -#define USBPF_LSH 0x60 -#define USBPF_RSH 0x70 -#define USBPF_NEG 0x80 -#define USBPF_JA 0x00 -#define USBPF_JEQ 0x10 -#define USBPF_JGT 0x20 -#define USBPF_JGE 0x30 -#define USBPF_JSET 0x40 -#define USBPF_SRC(code) ((code) & 0x08) -#define USBPF_K 0x00 -#define USBPF_X 0x08 - -/* ret - USBPF_K and USBPF_X also apply */ -#define USBPF_RVAL(code) ((code) & 0x18) -#define USBPF_A 0x10 - -/* misc */ -#define USBPF_MISCOP(code) ((code) & 0xf8) -#define USBPF_TAX 0x00 -#define USBPF_TXA 0x80 - -/* - * The instruction data structure. - */ -struct usbpf_insn { - u_short code; - u_char jt; - u_char jf; - usbpf_u_int32 k; -}; - -#ifdef _KERNEL - -/* - * Descriptor associated with each open uff file. - */ - -struct usbpf_d { - LIST_ENTRY(usbpf_d) ud_next; /* Linked list of descriptors */ - /* - * Buffer slots: two memory buffers store the incoming packets. - * The model has three slots. Sbuf is always occupied. - * sbuf (store) - Receive interrupt puts packets here. - * hbuf (hold) - When sbuf is full, put buffer here and - * wakeup read (replace sbuf with fbuf). - * fbuf (free) - When read is done, put buffer here. - * On receiving, if sbuf is full and fbuf is 0, packet is dropped. - */ - caddr_t ud_sbuf; /* store slot */ - caddr_t ud_hbuf; /* hold slot */ - caddr_t ud_fbuf; /* free slot */ - int ud_slen; /* current length of store buffer */ - int ud_hlen; /* current length of hold buffer */ - - int ud_bufsize; /* absolute length of buffers */ - - struct usbpf_if *ud_bif; /* interface descriptor */ - u_long ud_rtout; /* Read timeout in 'ticks' */ - struct usbpf_insn *ud_rfilter; /* read filter code */ - struct usbpf_insn *ud_wfilter; /* write filter code */ - void *ud_bfilter; /* binary filter code */ - u_int64_t ud_rcount; /* number of packets received */ - u_int64_t ud_dcount; /* number of packets dropped */ - - u_char ud_promisc; /* true if listening promiscuously */ - u_char ud_state; /* idle, waiting, or timed out */ - u_char ud_immediate; /* true to return on packet arrival */ - int ud_hdrcmplt; /* false to fill in src lladdr automatically */ - int ud_direction; /* select packet direction */ - int ud_tstamp; /* select time stamping function */ - int ud_feedback; /* true to feed back sent packets */ - int ud_async; /* non-zero if packet reception should generate signal */ - int ud_sig; /* signal to send upon packet reception */ - struct sigio * ud_sigio; /* information for async I/O */ - struct selinfo ud_sel; /* bsd select info */ - struct mtx ud_mtx; /* mutex for this descriptor */ - struct callout ud_callout; /* for USBPF timeouts with select */ - struct label *ud_label; /* MAC label for descriptor */ - u_int64_t ud_fcount; /* number of packets which matched filter */ - pid_t ud_pid; /* PID which created descriptor */ - int ud_locked; /* true if descriptor is locked */ - u_int ud_bufmode; /* Current buffer mode. */ - u_int64_t ud_wcount; /* number of packets written */ - u_int64_t ud_wfcount; /* number of packets that matched write filter */ - u_int64_t ud_wdcount; /* number of packets dropped during a write */ - u_int64_t ud_zcopy; /* number of zero copy operations */ - u_char ud_compat32; /* 32-bit stream on LP64 system */ -}; - -#define USBPFD_LOCK(ud) mtx_lock(&(ud)->ud_mtx) -#define USBPFD_UNLOCK(ud) mtx_unlock(&(ud)->ud_mtx) -#define USBPFD_LOCK_ASSERT(ud) mtx_assert(&(ud)->ud_mtx, MA_OWNED) - -/* - * Descriptor associated with each attached hardware interface. - */ -struct usbpf_if { - LIST_ENTRY(usbpf_if) uif_next; /* list of all interfaces */ - LIST_HEAD(, usbpf_d) uif_dlist; /* descriptor list */ - u_int uif_hdrlen; /* length of link header */ - struct usb_bus *uif_ubus; /* corresponding interface */ - struct mtx uif_mtx; /* mutex for interface */ -}; - -#define USBPFIF_LOCK(uif) mtx_lock(&(uif)->uif_mtx) -#define USBPFIF_UNLOCK(uif) mtx_unlock(&(uif)->uif_mtx) - -#endif - -/* - * Structure prepended to each packet. - */ -struct usbpf_ts { - usbpf_int64 ut_sec; /* seconds */ - usbpf_u_int64 ut_frac; /* fraction */ -}; -struct usbpf_xhdr { - struct usbpf_ts uh_tstamp; /* time stamp */ - usbpf_u_int32 uh_caplen; /* length of captured portion */ - usbpf_u_int32 uh_datalen; /* original length of packet */ - u_short uh_hdrlen; /* length of uff header (this struct - plus alignment padding) */ -}; - -#define USBPF_BUFMODE_BUFFER 1 /* Kernel buffers with read(). */ -#define USBPF_BUFMODE_ZBUF 2 /* Zero-copy buffers. */ - struct usbpf_pkthdr { int up_busunit; /* Host controller unit number */ u_char up_address; /* USB device address */ @@ -268,50 +84,13 @@ struct usbpf_pkthdr { u_char up_reserved[96]; }; -struct usbpf_version { - u_short uv_major; - u_short uv_minor; -}; -#define USBPF_MAJOR_VERSION 1 -#define USBPF_MINOR_VERSION 1 - -#define USBPF_IFNAMSIZ 32 -struct usbpf_ifreq { - /* bus name, e.g. "usbus0" */ - char ufr_name[USBPF_IFNAMSIZ]; -}; - -/* - * Structure for UIOCSETF. - */ -struct usbpf_program { - u_int uf_len; - struct usbpf_insn *uf_insns; -}; - -/* - * Struct returned by UIOCGSTATS. - */ -struct usbpf_stat { - u_int us_recv; /* number of packets received */ - u_int us_drop; /* number of packets dropped */ -}; - -#define UIOCGBLEN _IOR('U', 102, u_int) -#define UIOCSBLEN _IOWR('U', 102, u_int) -#define UIOCSETF _IOW('U', 103, struct usbpf_program) -#define UIOCSETIF _IOW('U', 108, struct usbpf_ifreq) -#define UIOCSRTIMEOUT _IOW('U', 109, struct timeval) -#define UIOCGRTIMEOUT _IOR('U', 110, struct timeval) -#define UIOCGSTATS _IOR('U', 111, struct usbpf_stat) -#define UIOCVERSION _IOR('U', 113, struct usbpf_version) -#define UIOCSETWF _IOW('U', 123, struct usbpf_program) +#define USBPF_HDR_LEN 128 #define USBPF_XFERTAP_SUBMIT 0 #define USBPF_XFERTAP_DONE 1 #ifdef _KERNEL -void usbpf_attach(struct usb_bus *, struct usbpf_if **); +void usbpf_attach(struct usb_bus *); void usbpf_detach(struct usb_bus *); void usbpf_xfertap(struct usb_xfer *, int); #endif diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 91fe9f4..a34ec3c 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -1789,8 +1789,8 @@ product HTC LEGENDINTERNET 0x0ffe HTC Legend Internet Sharing /* HUAWEI products */ product HUAWEI MOBILE 0x1001 Huawei Mobile -product HUAWEI E220 0x1003 Huawei HSDPA modem -product HUAWEI E220BIS 0x1004 Huawei HSDPA modem +product HUAWEI E220 0x1003 HSDPA modem +product HUAWEI E220BIS 0x1004 HSDPA modem product HUAWEI E1401 0x1401 3G modem product HUAWEI E1402 0x1402 3G modem product HUAWEI E1403 0x1403 3G modem @@ -1802,7 +1802,7 @@ product HUAWEI E1408 0x1408 3G modem product HUAWEI E1409 0x1409 3G modem product HUAWEI E140A 0x140a 3G modem product HUAWEI E140B 0x140b 3G modem -product HUAWEI E180V 0x140c Huawei Mobile E180V +product HUAWEI E180V 0x140c E180V product HUAWEI E140D 0x140d 3G modem product HUAWEI E140E 0x140e 3G modem product HUAWEI E140F 0x140f 3G modem @@ -1856,8 +1856,8 @@ product HUAWEI E143E 0x143e 3G modem product HUAWEI E143F 0x143f 3G modem product HUAWEI E1752 0x1446 3G modem product HUAWEI K3765 0x1465 3G modem -product HUAWEI E14AC 0x14ac 3G modem -product HUAWEI K3765_INIT 0x1520 HUAWEI Mobile K3765 Initial +product HUAWEI E1820 0x14ac E1820 HSPA+ USB Slider +product HUAWEI K3765_INIT 0x1520 K3765 Initial /* HUAWEI 3com products */ product HUAWEI3COM WUB320G 0x0009 Aolynk WUB320g |