diff options
Diffstat (limited to 'sys/dev/igb/if_igb.c')
-rw-r--r-- | sys/dev/igb/if_igb.c | 238 |
1 files changed, 97 insertions, 141 deletions
diff --git a/sys/dev/igb/if_igb.c b/sys/dev/igb/if_igb.c index 1f878bf..59243ee 100644 --- a/sys/dev/igb/if_igb.c +++ b/sys/dev/igb/if_igb.c @@ -88,7 +88,7 @@ int igb_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char igb_driver_version[] = "1.1.4"; +char igb_driver_version[] = "version - 1.1.6"; /********************************************************************* @@ -173,7 +173,7 @@ static bool igb_rxeof(struct rx_ring *, int); static int igb_fixup_rx(struct rx_ring *); #endif static void igb_rx_checksum(u32, struct mbuf *); -static bool igb_tx_ctx_setup(struct tx_ring *, struct mbuf *); +static int igb_tx_ctx_setup(struct tx_ring *, struct mbuf *); static bool igb_tso_setup(struct tx_ring *, struct mbuf *, u32 *); static void igb_set_promisc(struct adapter *); static void igb_disable_promisc(struct adapter *); @@ -943,11 +943,14 @@ igb_watchdog(struct adapter *adapter) ** if any time out we do the reset. */ for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { + IGB_TX_LOCK(txr); if (txr->watchdog_timer == 0 || - (--txr->watchdog_timer)) + (--txr->watchdog_timer)) { + IGB_TX_UNLOCK(txr); continue; - else { + } else { tx_hang = TRUE; + IGB_TX_UNLOCK(txr); break; } } @@ -960,8 +963,11 @@ igb_watchdog(struct adapter *adapter) if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_TXOFF) { txr = adapter->tx_rings; /* reset pointer */ - for (int i = 0; i < adapter->num_tx_queues; i++, txr++) + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { + IGB_TX_LOCK(txr); txr->watchdog_timer = IGB_TX_TIMEOUT; + IGB_TX_UNLOCK(txr); + } return; } @@ -1129,7 +1135,6 @@ igb_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { callout_stop(&adapter->timer); adapter->hw.mac.get_link_status = 1; - e1000_check_for_link(&adapter->hw); igb_update_link_status(adapter); callout_reset(&adapter->timer, hz, igb_local_timer, adapter); @@ -1143,7 +1148,7 @@ igb_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) igb_txeof(txr); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - igb_start_locked(txr, ifp); + igb_start_locked(txr); IGB_TX_UNLOCK(txr); } #endif /* DEVICE_POLLING */ @@ -1162,14 +1167,9 @@ igb_handle_link(void *context, int pending) IGB_CORE_LOCK(adapter); callout_stop(&adapter->timer); - adapter->hw.mac.get_link_status = 1; - e1000_check_for_link(&adapter->hw); igb_update_link_status(adapter); callout_reset(&adapter->timer, hz, igb_local_timer, adapter); IGB_CORE_UNLOCK(adapter); - /* Rearm this interrupt */ - E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC); - E1000_WRITE_REG(&adapter->hw, E1000_EIMS, E1000_EIMS_OTHER); } static void @@ -1237,10 +1237,12 @@ static int igb_irq_fast(void *arg) { struct adapter *adapter = arg; - struct ifnet *ifp; + struct ifnet *ifp = adapter->ifp; uint32_t reg_icr; - ifp = adapter->ifp; + /* Should not happen, but... */ + if (ifp->if_capenable & IFCAP_POLLING) + return FILTER_STRAY; reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); @@ -1264,8 +1266,10 @@ igb_irq_fast(void *arg) taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); /* Link status change */ - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + adapter->hw.mac.get_link_status = 1; taskqueue_enqueue(taskqueue_fast, &adapter->link_task); + } if (reg_icr & E1000_ICR_RXO) adapter->rx_overruns++; @@ -1330,15 +1334,13 @@ static void igb_msix_link(void *arg) { struct adapter *adapter = arg; - u32 eicr, icr; + u32 icr; ++adapter->link_irq; - eicr = E1000_READ_REG(&adapter->hw, E1000_EICR); - if (eicr & E1000_EIMS_OTHER) { - icr = E1000_READ_REG(&adapter->hw, E1000_ICR); - if (!(icr & E1000_ICR_LSC)) - goto spurious; - } + icr = E1000_READ_REG(&adapter->hw, E1000_ICR); + if (!(icr & E1000_ICR_LSC)) + goto spurious; + adapter->hw.mac.get_link_status = 1; taskqueue_enqueue(taskqueue_fast, &adapter->link_task); spurious: @@ -1365,7 +1367,6 @@ igb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) INIT_DEBUGOUT("igb_media_status: begin"); IGB_CORE_LOCK(adapter); - e1000_check_for_link(&adapter->hw); igb_update_link_status(adapter); ifmr->ifm_status = IFM_AVALID; @@ -1482,7 +1483,7 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp) struct mbuf *m_head; u32 olinfo_status = 0, cmd_type_len = 0; int nsegs, i, j, error, first, last = 0; - u32 hdrlen = 0; + u32 hdrlen = 0, offload = 0; m_head = *m_headp; @@ -1580,9 +1581,9 @@ igb_xmit(struct tx_ring *txr, struct mbuf **m_headp) return (ENXIO); } else /* Do all other context descriptor setup */ - if (igb_tx_ctx_setup(txr, m_head)) + offload = igb_tx_ctx_setup(txr, m_head); + if (offload == TRUE) olinfo_status |= E1000_TXD_POPTS_TXSM << 8; - /* Calculate payload length */ olinfo_status |= ((m_head->m_pkthdr.len - hdrlen) << E1000_ADVTXD_PAYLEN_SHIFT); @@ -1732,7 +1733,6 @@ igb_local_timer(void *arg) IGB_CORE_LOCK_ASSERT(adapter); - e1000_check_for_link(&adapter->hw); igb_update_link_status(adapter); igb_update_stats_counters(adapter); @@ -1752,37 +1752,58 @@ igb_local_timer(void *arg) static void igb_update_link_status(struct adapter *adapter) { + struct e1000_hw *hw = &adapter->hw; struct ifnet *ifp = adapter->ifp; device_t dev = adapter->dev; struct tx_ring *txr = adapter->tx_rings; + u32 link_check = 0; + + /* Get the cached link value or read for real */ + switch (hw->phy.media_type) { + case e1000_media_type_copper: + if (hw->mac.get_link_status) { + /* Do the work to read phy */ + e1000_check_for_link(hw); + link_check = !hw->mac.get_link_status; + } else + link_check = TRUE; + break; + case e1000_media_type_fiber: + e1000_check_for_link(hw); + link_check = (E1000_READ_REG(hw, E1000_STATUS) & + E1000_STATUS_LU); + break; + case e1000_media_type_internal_serdes: + e1000_check_for_link(hw); + link_check = adapter->hw.mac.serdes_has_link; + break; + default: + case e1000_media_type_unknown: + break; + } - if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & - E1000_STATUS_LU) { - if (adapter->link_active == 0) { - e1000_get_speed_and_duplex(&adapter->hw, - &adapter->link_speed, &adapter->link_duplex); - if (bootverbose) - device_printf(dev, "Link is up %d Mbps %s\n", - adapter->link_speed, - ((adapter->link_duplex == FULL_DUPLEX) ? - "Full Duplex" : "Half Duplex")); - adapter->link_active = 1; - ifp->if_baudrate = adapter->link_speed * 1000000; - if_link_state_change(ifp, LINK_STATE_UP); - } - } else { - if (adapter->link_active == 1) { - ifp->if_baudrate = adapter->link_speed = 0; - adapter->link_duplex = 0; - if (bootverbose) - device_printf(dev, "Link is Down\n"); - adapter->link_active = 0; - if_link_state_change(ifp, LINK_STATE_DOWN); - /* Turn off watchdogs */ - for (int i = 0; i < adapter->num_tx_queues; - i++, txr++) - txr->watchdog_timer = FALSE; - } + /* Now we check if a transition has happened */ + if (link_check && (adapter->link_active == 0)) { + e1000_get_speed_and_duplex(&adapter->hw, + &adapter->link_speed, &adapter->link_duplex); + if (bootverbose) + device_printf(dev, "Link is up %d Mbps %s\n", + adapter->link_speed, + ((adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex")); + adapter->link_active = 1; + ifp->if_baudrate = adapter->link_speed * 1000000; + if_link_state_change(ifp, LINK_STATE_UP); + } else if (!link_check && (adapter->link_active == 1)) { + ifp->if_baudrate = adapter->link_speed = 0; + adapter->link_duplex = 0; + if (bootverbose) + device_printf(dev, "Link is Down\n"); + adapter->link_active = 0; + if_link_state_change(ifp, LINK_STATE_DOWN); + /* Turn off watchdogs */ + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) + txr->watchdog_timer = FALSE; } } @@ -1988,7 +2009,7 @@ igb_allocate_msix(struct adapter *adapter) txr->msix = adapter->rid[vector] - 1; } else { txr->eims = 1 << vector; - txr->msix = adapter->rid[vector]; + txr->msix = vector; } } @@ -2017,7 +2038,7 @@ igb_allocate_msix(struct adapter *adapter) rxr->msix = adapter->rid[vector] - 1; } else { rxr->eims = 1 << vector; - rxr->msix = adapter->rid[vector]; + rxr->msix = vector; } } @@ -2040,7 +2061,7 @@ igb_allocate_msix(struct adapter *adapter) if (adapter->hw.mac.type == e1000_82575) adapter->linkvec = adapter->rid[vector] - 1; else - adapter->linkvec = adapter->rid[vector]; + adapter->linkvec = vector; /* Make tasklet for deferred link interrupt handling */ TASK_INIT(&adapter->link_task, 0, igb_handle_link, adapter); @@ -2298,7 +2319,10 @@ igb_setup_interface(device_t dev, struct adapter *adapter) ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; #ifdef DEVICE_POLLING - ifp->if_capabilities |= IFCAP_POLLING; + if (adapter->msix > 1) + device_printf(adapter->dev, "POLLING not supported with MSIX\n"); + else + ifp->if_capabilities |= IFCAP_POLLING; #endif /* @@ -2889,7 +2913,7 @@ igb_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *hdrlen) * **********************************************************************/ -static boolean_t +static int igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp) { struct adapter *adapter = txr->adapter; @@ -3740,9 +3764,6 @@ discard: } rxr->next_to_check = i; - if (--i < 0) - i = adapter->num_rx_desc - 1; - /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), rxr->last_cleaned); IGB_RX_UNLOCK(rxr); @@ -3792,7 +3813,7 @@ igb_fixup_rx(struct rx_ring *rxr) rxr->fmp = n; } else { adapter->dropped_pkts++; - m_freem(rxr->fmp); + m_freem(adapter->fmp); rxr->fmp = NULL; error = ENOMEM; } @@ -3982,71 +4003,6 @@ igb_is_valid_ether_addr(uint8_t *addr) return (TRUE); } -/* - * NOTE: the following routines using the e1000 - * naming style are provided to the shared - * code which expects that rather than 'em' - */ - -void -e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) -{ - pci_write_config(((struct e1000_osdep *)hw->back)->dev, reg, *value, 2); -} - -void -e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) -{ - *value = pci_read_config(((struct e1000_osdep *)hw->back)->dev, reg, 2); -} - -void -e1000_pci_set_mwi(struct e1000_hw *hw) -{ - pci_write_config(((struct e1000_osdep *)hw->back)->dev, PCIR_COMMAND, - (hw->bus.pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); -} - -void -e1000_pci_clear_mwi(struct e1000_hw *hw) -{ - pci_write_config(((struct e1000_osdep *)hw->back)->dev, PCIR_COMMAND, - (hw->bus.pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2); -} - -/* - * Read the PCI Express capabilities - */ -int32_t -e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) -{ - u32 result; - - pci_find_extcap(((struct e1000_osdep *)hw->back)->dev, - reg, &result); - *value = (u16)result; - return (E1000_SUCCESS); -} - -int32_t -e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, uint32_t size) -{ - int32_t error = 0; - - hw->dev_spec = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); - if (hw->dev_spec == NULL) - error = ENOMEM; - - return (error); -} - -void -e1000_free_dev_spec_struct(struct e1000_hw *hw) -{ - if (hw->dev_spec != NULL) - free(hw->dev_spec, M_DEVBUF); - return; -} /* * Enable PCI Wake On Lan capability @@ -4207,26 +4163,26 @@ igb_print_debug_info(struct adapter *adapter) device_printf(dev, "Queue(%d) tdh = %d, tdt = %d\n", i, E1000_READ_REG(&adapter->hw, E1000_TDH(i)), E1000_READ_REG(&adapter->hw, E1000_TDT(i))); - device_printf(dev, "no descriptors avail event = %lld\n", - (long long)txr->no_desc_avail); - device_printf(dev, "TX(%d) IRQ Handled = %lld\n", txr->me, - (long long)txr->tx_irq); - device_printf(dev, "TX(%d) Packets sent = %lld\n", txr->me, - (long long)txr->tx_packets); + device_printf(dev, "no descriptors avail event = %lu\n", + txr->no_desc_avail); + device_printf(dev, "TX(%d) MSIX IRQ Handled = %lu\n", txr->me, + txr->tx_irq); + device_printf(dev, "TX(%d) Packets sent = %lu\n", txr->me, + txr->tx_packets); } for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { device_printf(dev, "Queue(%d) rdh = %d, rdt = %d\n", i, E1000_READ_REG(&adapter->hw, E1000_RDH(i)), E1000_READ_REG(&adapter->hw, E1000_RDT(i))); - device_printf(dev, "RX(%d) Packets received = %lld\n", rxr->me, - (long long)rxr->rx_packets); - device_printf(dev, "RX(%d) Byte count = %lld\n", rxr->me, - (long long)rxr->rx_bytes); - device_printf(dev, "RX(%d) IRQ Handled = %lld\n", rxr->me, - (long long)rxr->rx_irq); + device_printf(dev, "RX(%d) Packets received = %lu\n", rxr->me, + rxr->rx_packets); + device_printf(dev, "RX(%d) Byte count = %lu\n", rxr->me, + rxr->rx_bytes); + device_printf(dev, "RX(%d) MSIX IRQ Handled = %lu\n", rxr->me, + rxr->rx_irq); } - device_printf(dev, "LINK IRQ Handled = %u\n", adapter->link_irq); + device_printf(dev, "LINK MSIX IRQ Handled = %u\n", adapter->link_irq); device_printf(dev, "Std mbuf failed = %ld\n", adapter->mbuf_alloc_failed); |