svn commit: r185505 - stable/7/sys/dev/ixgbe
Jack F Vogel
jfv at FreeBSD.org
Sun Nov 30 20:03:18 PST 2008
Author: jfv
Date: Mon Dec 1 04:03:17 2008
New Revision: 185505
URL: http://svn.freebsd.org/changeset/base/185505
Log:
MFC of version 1.6.2 of the ixgbe driver, contains
header split, new adapter support, and general code
improvement/cleanup.
Approved by:re
Modified:
stable/7/sys/dev/ixgbe/ixgbe.c
stable/7/sys/dev/ixgbe/ixgbe.h
stable/7/sys/dev/ixgbe/ixgbe_82598.c
stable/7/sys/dev/ixgbe/ixgbe_api.c
stable/7/sys/dev/ixgbe/ixgbe_api.h
stable/7/sys/dev/ixgbe/ixgbe_common.c
stable/7/sys/dev/ixgbe/ixgbe_common.h
stable/7/sys/dev/ixgbe/ixgbe_osdep.h
stable/7/sys/dev/ixgbe/ixgbe_phy.c
stable/7/sys/dev/ixgbe/ixgbe_phy.h
stable/7/sys/dev/ixgbe/ixgbe_type.h
Modified: stable/7/sys/dev/ixgbe/ixgbe.c
==============================================================================
--- stable/7/sys/dev/ixgbe/ixgbe.c Mon Dec 1 03:00:26 2008 (r185504)
+++ stable/7/sys/dev/ixgbe/ixgbe.c Mon Dec 1 04:03:17 2008 (r185505)
@@ -46,7 +46,7 @@ int ixgbe_display_debug_stat
/*********************************************************************
* Driver version
*********************************************************************/
-char ixgbe_driver_version[] = "1.4.7";
+char ixgbe_driver_version[] = "1.6.2";
/*********************************************************************
* PCI Device ID Table
@@ -62,11 +62,15 @@ static ixgbe_vendor_info_t ixgbe_vendor_
{
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0},
- {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT_DUAL_PORT, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0},
+ {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0},
+ {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0},
+ {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0},
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0},
+ {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0},
+ {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0},
/* required last entry */
{0, 0, 0, 0, 0}
};
@@ -125,14 +129,14 @@ static void ixgbe_disable_intr(struc
static void ixgbe_update_stats_counters(struct adapter *);
static bool ixgbe_txeof(struct tx_ring *);
static bool ixgbe_rxeof(struct rx_ring *, int);
-static void ixgbe_rx_checksum(struct adapter *, u32, struct mbuf *);
+static void ixgbe_rx_checksum(u32, struct mbuf *);
static void ixgbe_set_promisc(struct adapter *);
static void ixgbe_disable_promisc(struct adapter *);
static void ixgbe_set_multi(struct adapter *);
static void ixgbe_print_hw_stats(struct adapter *);
static void ixgbe_print_debug_info(struct adapter *);
static void ixgbe_update_link_status(struct adapter *);
-static int ixgbe_get_buf(struct rx_ring *, int);
+static int ixgbe_get_buf(struct rx_ring *, int, u8);
static int ixgbe_xmit(struct tx_ring *, struct mbuf **);
static int ixgbe_sysctl_stats(SYSCTL_HANDLER_ARGS);
static int ixgbe_sysctl_debug(SYSCTL_HANDLER_ARGS);
@@ -144,12 +148,19 @@ static void ixgbe_add_rx_process_limit(s
const char *, int *, int);
static boolean_t ixgbe_tx_ctx_setup(struct tx_ring *, struct mbuf *);
static boolean_t ixgbe_tso_setup(struct tx_ring *, struct mbuf *, u32 *);
-static void ixgbe_set_ivar(struct adapter *, u16, u8);
+static void ixgbe_set_ivar(struct adapter *, u16, u8, s8);
static void ixgbe_configure_ivars(struct adapter *);
static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *);
+#ifdef IXGBE_HW_VLAN_SUPPORT
static void ixgbe_register_vlan(void *, struct ifnet *, u16);
static void ixgbe_unregister_vlan(void *, struct ifnet *, u16);
+#endif
+
+static void ixgbe_update_aim(struct rx_ring *);
+
+/* Support for pluggable optic modules */
+static bool ixgbe_sfp_probe(struct adapter *);
/* Legacy (single vector interrupt handler */
static void ixgbe_legacy_irq(void *);
@@ -163,9 +174,6 @@ static void ixgbe_msix_link(void *);
static void ixgbe_handle_tx(void *context, int pending);
static void ixgbe_handle_rx(void *context, int pending);
-#ifndef NO_82598_A0_SUPPORT
-static void desc_flip(void *);
-#endif
/*********************************************************************
* FreeBSD Device Interface Entry Points
@@ -194,12 +202,28 @@ MODULE_DEPEND(ixgbe, ether, 1, 1, 1);
** TUNEABLE PARAMETERS:
*/
+/*
+** These parameters are used in Adaptive
+** Interrupt Moderation. The value is set
+** into EITR and controls the interrupt
+** frequency. They can be modified but
+** be careful in tuning them.
+*/
+static int ixgbe_enable_aim = TRUE;
+TUNABLE_INT("hw.ixgbe.enable_aim", &ixgbe_enable_aim);
+static int ixgbe_low_latency = IXGBE_LOW_LATENCY;
+TUNABLE_INT("hw.ixgbe.low_latency", &ixgbe_low_latency);
+static int ixgbe_ave_latency = IXGBE_LOW_LATENCY;
+TUNABLE_INT("hw.ixgbe.ave_latency", &ixgbe_low_latency);
+static int ixgbe_bulk_latency = IXGBE_BULK_LATENCY;
+TUNABLE_INT("hw.ixgbe.bulk_latency", &ixgbe_bulk_latency);
+
/* How many packets rxeof tries to clean at a time */
static int ixgbe_rx_process_limit = 100;
TUNABLE_INT("hw.ixgbe.rx_process_limit", &ixgbe_rx_process_limit);
/* Flow control setting, default to full */
-static int ixgbe_flow_control = 3;
+static int ixgbe_flow_control = ixgbe_fc_none;
TUNABLE_INT("hw.ixgbe.flow_control", &ixgbe_flow_control);
/*
@@ -208,7 +232,7 @@ TUNABLE_INT("hw.ixgbe.flow_control", &ix
* interface must be reset (down/up) for it
* to take effect.
*/
-static int ixgbe_enable_lro = 0;
+static int ixgbe_enable_lro = 1;
TUNABLE_INT("hw.ixgbe.enable_lro", &ixgbe_enable_lro);
/*
@@ -219,12 +243,18 @@ static int ixgbe_enable_msix = 1;
TUNABLE_INT("hw.ixgbe.enable_msix", &ixgbe_enable_msix);
/*
+ * Enable RX Header Split
+ */
+static int ixgbe_rx_hdr_split = 1;
+TUNABLE_INT("hw.ixgbe.rx_hdr_split", &ixgbe_rx_hdr_split);
+
+/*
* Number of TX/RX Queues, with 0 setting
* it autoconfigures to the number of cpus.
*/
static int ixgbe_tx_queues = 1;
TUNABLE_INT("hw.ixgbe.tx_queues", &ixgbe_tx_queues);
-static int ixgbe_rx_queues = 4;
+static int ixgbe_rx_queues = 1;
TUNABLE_INT("hw.ixgbe.rx_queues", &ixgbe_rx_queues);
/* Number of TX descriptors per ring */
@@ -238,9 +268,6 @@ TUNABLE_INT("hw.ixgbe.rxd", &ixgbe_rxd);
/* Total number of Interfaces - need for config sanity check */
static int ixgbe_total_ports;
-/* Optics type of this interface */
-static int ixgbe_optics;
-
/*********************************************************************
* Device identification routine
*
@@ -255,11 +282,11 @@ ixgbe_probe(device_t dev)
{
ixgbe_vendor_info_t *ent;
- u_int16_t pci_vendor_id = 0;
- u_int16_t pci_device_id = 0;
- u_int16_t pci_subvendor_id = 0;
- u_int16_t pci_subdevice_id = 0;
- char adapter_name[128];
+ u16 pci_vendor_id = 0;
+ u16 pci_device_id = 0;
+ u16 pci_subvendor_id = 0;
+ u16 pci_subdevice_id = 0;
+ char adapter_name[256];
INIT_DEBUGOUT("ixgbe_probe: begin");
@@ -284,41 +311,11 @@ ixgbe_probe(device_t dev)
sprintf(adapter_name, "%s, Version - %s",
ixgbe_strings[ent->index],
ixgbe_driver_version);
- switch (pci_device_id) {
- case IXGBE_DEV_ID_82598AT_DUAL_PORT :
- ixgbe_total_ports += 2;
- break;
- case IXGBE_DEV_ID_82598_CX4_DUAL_PORT :
- ixgbe_optics = IFM_10G_CX4;
- ixgbe_total_ports += 2;
- break;
- case IXGBE_DEV_ID_82598AF_DUAL_PORT :
- ixgbe_optics = IFM_10G_SR;
- ixgbe_total_ports += 2;
- break;
- case IXGBE_DEV_ID_82598AF_SINGLE_PORT :
- ixgbe_optics = IFM_10G_SR;
- ixgbe_total_ports += 1;
- break;
- case IXGBE_DEV_ID_82598EB_XF_LR :
- ixgbe_optics = IFM_10G_LR;
- ixgbe_total_ports += 1;
- break;
- case IXGBE_DEV_ID_82598EB_CX4 :
- ixgbe_optics = IFM_10G_CX4;
- ixgbe_total_ports += 1;
- break;
- case IXGBE_DEV_ID_82598AT :
- ixgbe_total_ports += 1;
- default:
- break;
- }
device_set_desc_copy(dev, adapter_name);
return (0);
}
ent++;
}
-
return (ENXIO);
}
@@ -337,7 +334,8 @@ ixgbe_attach(device_t dev)
{
struct adapter *adapter;
int error = 0;
- u32 ctrl_ext;
+ u16 pci_device_id;
+ u32 ctrl_ext;
INIT_DEBUGOUT("ixgbe_attach: begin");
@@ -348,6 +346,37 @@ ixgbe_attach(device_t dev)
/* Core Lock Init*/
IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
+ /* Keep track of number of ports and optics */
+ pci_device_id = pci_get_device(dev);
+ switch (pci_device_id) {
+ case IXGBE_DEV_ID_82598_CX4_DUAL_PORT :
+ adapter->optics = IFM_10G_CX4;
+ ixgbe_total_ports += 2;
+ break;
+ case IXGBE_DEV_ID_82598AF_DUAL_PORT :
+ adapter->optics = IFM_10G_SR;
+ ixgbe_total_ports += 2;
+ break;
+ case IXGBE_DEV_ID_82598AF_SINGLE_PORT :
+ adapter->optics = IFM_10G_SR;
+ ixgbe_total_ports += 1;
+ break;
+ case IXGBE_DEV_ID_82598EB_XF_LR :
+ adapter->optics = IFM_10G_LR;
+ ixgbe_total_ports += 1;
+ break;
+ case IXGBE_DEV_ID_82598EB_CX4 :
+ adapter->optics = IFM_10G_CX4;
+ ixgbe_total_ports += 1;
+ break;
+ case IXGBE_DEV_ID_82598AT :
+ ixgbe_total_ports += 1;
+ case IXGBE_DEV_ID_82598_DA_DUAL_PORT :
+ ixgbe_total_ports += 2;
+ default:
+ break;
+ }
+
/* SYSCTL APIs */
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
@@ -369,15 +398,37 @@ ixgbe_attach(device_t dev)
OID_AUTO, "enable_lro", CTLTYPE_INT|CTLFLAG_RW,
&ixgbe_enable_lro, 1, "Large Receive Offload");
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "enable_aim", CTLTYPE_INT|CTLFLAG_RW,
+ &ixgbe_enable_aim, 1, "Interrupt Moderation");
+
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "low_latency", CTLTYPE_INT|CTLFLAG_RW,
+ &ixgbe_low_latency, 1, "Low Latency");
+
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "ave_latency", CTLTYPE_INT|CTLFLAG_RW,
+ &ixgbe_ave_latency, 1, "Average Latency");
+
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "bulk_latency", CTLTYPE_INT|CTLFLAG_RW,
+ &ixgbe_bulk_latency, 1, "Bulk Latency");
+
+ SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "hdr_split", CTLTYPE_INT|CTLFLAG_RW,
+ &ixgbe_rx_hdr_split, 1, "RX Header Split");
+
/* Set up the timer callout */
callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
/* Determine hardware revision */
ixgbe_identify_hardware(adapter);
- /* Indicate to RX setup to use Jumbo Clusters */
- adapter->bigbufs = TRUE;
-
/* Do base PCI setup - map BAR0 */
if (ixgbe_allocate_pci_resources(adapter)) {
device_printf(dev, "Allocation of PCI resources failed\n");
@@ -423,7 +474,20 @@ ixgbe_attach(device_t dev)
}
/* Initialize the shared code */
- if (ixgbe_init_shared_code(&adapter->hw)) {
+ error = ixgbe_init_shared_code(&adapter->hw);
+ if (error == IXGBE_ERR_SFP_NOT_PRESENT) {
+ /*
+ ** No optics in this port, set up
+ ** so the timer routine will probe
+ ** for later insertion.
+ */
+ adapter->sfp_probe = TRUE;
+ error = 0;
+ } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+ device_printf(dev,"Unsupported SFP+ module detected!\n");
+ error = EIO;
+ goto err_late;
+ } else if (error) {
device_printf(dev,"Unable to initialize the shared code\n");
error = EIO;
goto err_late;
@@ -454,12 +518,14 @@ ixgbe_attach(device_t dev)
/* Initialize statistics */
ixgbe_update_stats_counters(adapter);
+#ifdef IXGBE_HW_VLAN_SUPPORT
/* Register for VLAN events */
adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
ixgbe_register_vlan, 0, EVENTHANDLER_PRI_FIRST);
adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
ixgbe_unregister_vlan, 0, EVENTHANDLER_PRI_FIRST);
-
+#endif
+
/* let hardware know driver is loaded */
ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
@@ -514,7 +580,6 @@ ixgbe_detach(device_t dev)
if (txr->tq) {
taskqueue_drain(txr->tq, &txr->tx_task);
taskqueue_free(txr->tq);
- txr->tq = NULL;
}
}
@@ -522,20 +587,21 @@ ixgbe_detach(device_t dev)
if (rxr->tq) {
taskqueue_drain(rxr->tq, &rxr->rx_task);
taskqueue_free(rxr->tq);
- rxr->tq = NULL;
}
}
+ /* let hardware know driver is unloading */
+ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+ ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext);
+
+#ifdef IXGBE_HW_VLAN_SUPPORT
/* Unregister VLAN events */
if (adapter->vlan_attach != NULL)
EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach);
if (adapter->vlan_detach != NULL)
EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
-
- /* let hardware know driver is unloading */
- ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
- ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext);
+#endif
ether_ifdetach(adapter->ifp);
callout_drain(&adapter->timer);
@@ -839,10 +905,13 @@ ixgbe_watchdog(struct adapter *adapter)
static void
ixgbe_init_locked(struct adapter *adapter)
{
+ struct rx_ring *rxr = adapter->rx_rings;
+ struct tx_ring *txr = adapter->tx_rings;
struct ifnet *ifp = adapter->ifp;
device_t dev = adapter->dev;
struct ixgbe_hw *hw;
- u32 txdctl, rxdctl, mhadd, gpie;
+ u32 k, txdctl, mhadd, gpie;
+ u32 rxdctl, rxctrl;
INIT_DEBUGOUT("ixgbe_init: begin");
@@ -863,6 +932,16 @@ ixgbe_init_locked(struct adapter *adapte
return;
}
+#ifndef IXGBE_HW_VLAN_SUPPORT
+ if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
+ u32 ctrl;
+
+ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
+ ctrl |= IXGBE_VLNCTRL_VME;
+ ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+ }
+#endif
/* Prepare transmit descriptors and buffers */
if (ixgbe_setup_transmit_structures(adapter)) {
device_printf(dev,"Could not setup transmit structures\n");
@@ -872,15 +951,24 @@ ixgbe_init_locked(struct adapter *adapte
ixgbe_initialize_transmit_units(adapter);
+ /* TX irq moderation rate is fixed */
+ for (int i = 0; i < adapter->num_tx_queues; i++, txr++) {
+ IXGBE_WRITE_REG(&adapter->hw,
+ IXGBE_EITR(txr->msix), ixgbe_ave_latency);
+ txr->watchdog_timer = FALSE;
+ }
+
/* Setup Multicast table */
ixgbe_set_multi(adapter);
/*
- ** If we are resetting MTU smaller than 2K
- ** drop to small RX buffers
+ ** Determine the correct mbuf pool
+ ** for doing jumbo/headersplit
*/
- if (adapter->max_frame_size <= MCLBYTES)
- adapter->bigbufs = FALSE;
+ if (ifp->if_mtu > ETHERMTU)
+ adapter->rx_mbuf_sz = MJUMPAGESIZE;
+ else
+ adapter->rx_mbuf_sz = MCLBYTES;
/* Prepare receive descriptors and buffers */
if (ixgbe_setup_receive_structures(adapter)) {
@@ -892,10 +980,22 @@ ixgbe_init_locked(struct adapter *adapte
/* Configure RX settings */
ixgbe_initialize_receive_units(adapter);
+ /* RX moderation will be adapted over time, set default */
+ for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) {
+ IXGBE_WRITE_REG(&adapter->hw,
+ IXGBE_EITR(rxr->msix), ixgbe_low_latency);
+ }
+
+ /* Set Link moderation */
+ IXGBE_WRITE_REG(&adapter->hw,
+ IXGBE_EITR(adapter->linkvec), IXGBE_LINK_ITR);
+
gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE);
+
/* Enable Fan Failure Interrupt */
if (adapter->hw.phy.media_type == ixgbe_media_type_copper)
gpie |= IXGBE_SDP1_GPIEN;
+
if (adapter->msix) {
/* Enable Enhanced MSIX mode */
gpie |= IXGBE_GPIE_MSIX_MODE;
@@ -935,12 +1035,29 @@ ixgbe_init_locked(struct adapter *adapte
rxdctl |= 0x0020;
rxdctl |= IXGBE_RXDCTL_ENABLE;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(i), rxdctl);
+ for (k = 0; k < 10; k++) {
+ if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) &
+ IXGBE_RXDCTL_ENABLE)
+ break;
+ else
+ msec_delay(1);
+ }
+ wmb();
+ IXGBE_WRITE_REG(hw, IXGBE_RDT(i), adapter->num_rx_desc - 1);
}
+ /* Enable Receive engine */
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ rxctrl |= IXGBE_RXCTRL_DMBYPS;
+ rxctrl |= IXGBE_RXCTRL_RXEN;
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
+
callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
/* Set up MSI/X routing */
- ixgbe_configure_ivars(adapter);
+ if (ixgbe_enable_msix)
+ ixgbe_configure_ivars(adapter);
ixgbe_enable_intr(adapter);
@@ -964,7 +1081,7 @@ ixgbe_init(void *arg)
/*
-** Legacy Deferred Interrupt Handlers
+** MSIX Interrupt Handlers
*/
static void
@@ -972,11 +1089,14 @@ ixgbe_handle_rx(void *context, int pendi
{
struct rx_ring *rxr = context;
struct adapter *adapter = rxr->adapter;
- u32 loop = 0;
+ u32 loop = MAX_LOOP;
+ bool more;
- while (loop++ < MAX_INTR)
- if (ixgbe_rxeof(rxr, adapter->rx_process_limit) == 0)
- break;
+ do {
+ more = ixgbe_rxeof(rxr, -1);
+ } while (loop-- && more);
+ /* Reenable this interrupt */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rxr->eims);
}
static void
@@ -985,15 +1105,21 @@ ixgbe_handle_tx(void *context, int pendi
struct tx_ring *txr = context;
struct adapter *adapter = txr->adapter;
struct ifnet *ifp = adapter->ifp;
- u32 loop = 0;
+ u32 loop = MAX_LOOP;
+ bool more;
- IXGBE_TX_LOCK(txr);
- while (loop++ < MAX_INTR)
- if (ixgbe_txeof(txr) == 0)
- break;
- if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
- ixgbe_start_locked(txr, ifp);
- IXGBE_TX_UNLOCK(txr);
+ IXGBE_TX_LOCK(txr);
+ do {
+ more = ixgbe_txeof(txr);
+ } while (loop-- && more);
+
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ ixgbe_start_locked(txr, ifp);
+
+ IXGBE_TX_UNLOCK(txr);
+
+ /* Reenable this interrupt */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, txr->eims);
}
@@ -1006,34 +1132,38 @@ ixgbe_handle_tx(void *context, int pendi
static void
ixgbe_legacy_irq(void *arg)
{
- u32 reg_eicr;
struct adapter *adapter = arg;
+ struct ixgbe_hw *hw = &adapter->hw;
struct tx_ring *txr = adapter->tx_rings;
struct rx_ring *rxr = adapter->rx_rings;
- struct ixgbe_hw *hw;
+ u32 reg_eicr;
- hw = &adapter->hw;
- reg_eicr = IXGBE_READ_REG(&adapter->hw, IXGBE_EICR);
- if (reg_eicr == 0)
+
+ reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+ if (reg_eicr == 0) {
+ ixgbe_enable_intr(adapter);
return;
+ }
- if (ixgbe_rxeof(rxr, adapter->rx_process_limit) != 0)
+ if (ixgbe_rxeof(rxr, adapter->rx_process_limit))
taskqueue_enqueue(rxr->tq, &rxr->rx_task);
- if (ixgbe_txeof(txr) != 0)
- taskqueue_enqueue(txr->tq, &txr->tx_task);
+ if (ixgbe_txeof(txr))
+ taskqueue_enqueue(txr->tq, &txr->tx_task);
/* Check for fan failure */
if ((hw->phy.media_type == ixgbe_media_type_copper) &&
(reg_eicr & IXGBE_EICR_GPI_SDP1)) {
device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! "
"REPLACE IMMEDIATELY!!\n");
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
- IXGBE_EICR_GPI_SDP1);
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1);
}
+
/* Link status change */
if (reg_eicr & IXGBE_EICR_LSC)
ixgbe_update_link_status(adapter);
+ ixgbe_enable_intr(adapter);
return;
}
@@ -1047,25 +1177,25 @@ ixgbe_legacy_irq(void *arg)
void
ixgbe_msix_tx(void *arg)
{
- struct tx_ring *txr = arg;
- struct adapter *adapter = txr->adapter;
- u32 loop = 0;
+ struct tx_ring *txr = arg;
+ struct adapter *adapter = txr->adapter;
+ bool more;
- ++txr->tx_irq;
IXGBE_TX_LOCK(txr);
- while (loop++ < MAX_INTR)
- if (ixgbe_txeof(txr) == 0)
- break;
+ ++txr->tx_irq;
+ more = ixgbe_txeof(txr);
IXGBE_TX_UNLOCK(txr);
- /* Reenable this interrupt */
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, txr->eims);
-
+ if (more)
+ taskqueue_enqueue(txr->tq, &txr->tx_task);
+ else /* Reenable this interrupt */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, txr->eims);
return;
}
+
/*********************************************************************
*
- * MSI RX Interrupt Service routine
+ * MSIX RX Interrupt Service routine
*
**********************************************************************/
@@ -1073,18 +1203,71 @@ static void
ixgbe_msix_rx(void *arg)
{
struct rx_ring *rxr = arg;
- struct adapter *adapter = rxr->adapter;
- u32 loop = 0;
+ struct adapter *adapter = rxr->adapter;
+ bool more;
++rxr->rx_irq;
- while (loop++ < MAX_INTR)
- if (ixgbe_rxeof(rxr, adapter->rx_process_limit) == 0)
- break;
- /* Reenable this interrupt */
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rxr->eims);
+ more = ixgbe_rxeof(rxr, -1);
+ if (more)
+ taskqueue_enqueue(rxr->tq, &rxr->rx_task);
+ else
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rxr->eims);
+ /* Update interrupt rate */
+ if (ixgbe_enable_aim == TRUE)
+ ixgbe_update_aim(rxr);
return;
}
+/*
+** Routine to do adjust the RX EITR value based on traffic,
+** its a simple three state model, but seems to help.
+**
+** Note that the three EITR values are tuneable using
+** sysctl in real time. The feature can be effectively
+** nullified by setting them equal.
+*/
+#define BULK_THRESHOLD 10000
+#define AVE_THRESHOLD 1600
+
+static void
+ixgbe_update_aim(struct rx_ring *rxr)
+{
+ struct adapter *adapter = rxr->adapter;
+ u32 olditr, newitr;
+
+ /* Update interrupt moderation based on traffic */
+ olditr = rxr->eitr_setting;
+ newitr = olditr;
+
+ /* Idle, don't change setting */
+ if (rxr->bytes == 0)
+ return;
+
+ if (olditr == ixgbe_low_latency) {
+ if (rxr->bytes > AVE_THRESHOLD)
+ newitr = ixgbe_ave_latency;
+ } else if (olditr == ixgbe_ave_latency) {
+ if (rxr->bytes < AVE_THRESHOLD)
+ newitr = ixgbe_low_latency;
+ else if (rxr->bytes > BULK_THRESHOLD)
+ newitr = ixgbe_bulk_latency;
+ } else if (olditr == ixgbe_bulk_latency) {
+ if (rxr->bytes < BULK_THRESHOLD)
+ newitr = ixgbe_ave_latency;
+ }
+
+ if (olditr != newitr) {
+ /* Change interrupt rate */
+ rxr->eitr_setting = newitr;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(rxr->me),
+ newitr | (newitr << 16));
+ }
+
+ rxr->bytes = 0;
+ return;
+}
+
+
static void
ixgbe_msix_link(void *arg)
{
@@ -1144,7 +1327,7 @@ ixgbe_media_status(struct ifnet * ifp, s
ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
break;
case IXGBE_LINK_SPEED_10GB_FULL:
- ifmr->ifm_active |= ixgbe_optics | IFM_FDX;
+ ifmr->ifm_active |= adapter->optics | IFM_FDX;
break;
}
@@ -1200,7 +1383,7 @@ ixgbe_xmit(struct tx_ring *txr, struct m
{
struct adapter *adapter = txr->adapter;
u32 olinfo_status = 0, cmd_type_len = 0;
- u32 paylen;
+ u32 paylen = 0;
int i, j, error, nsegs;
int first, last = 0;
struct mbuf *m_head;
@@ -1210,7 +1393,6 @@ ixgbe_xmit(struct tx_ring *txr, struct m
union ixgbe_adv_tx_desc *txd = NULL;
m_head = *m_headp;
- paylen = 0;
/* Basic descriptor defines */
cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA;
@@ -1254,7 +1436,7 @@ ixgbe_xmit(struct tx_ring *txr, struct m
m = m_defrag(*m_headp, M_DONTWAIT);
if (m == NULL) {
- adapter->mbuf_alloc_failed++;
+ adapter->mbuf_defrag_failed++;
m_freem(*m_headp);
*m_headp = NULL;
return (ENOBUFS);
@@ -1306,6 +1488,11 @@ ixgbe_xmit(struct tx_ring *txr, struct m
} else if (ixgbe_tx_ctx_setup(txr, m_head))
olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8;
+ /* Record payload length */
+ if (paylen == 0)
+ olinfo_status |= m_head->m_pkthdr.len <<
+ IXGBE_ADVTXD_PAYLEN_SHIFT;
+
i = txr->next_avail_tx_desc;
for (j = 0; j < nsegs; j++) {
bus_size_t seglen;
@@ -1326,19 +1513,10 @@ ixgbe_xmit(struct tx_ring *txr, struct m
i = 0;
txbuf->m_head = NULL;
- /*
- ** we have to do this inside the loop right now
- ** because of the hardware workaround.
- */
- if (j == (nsegs -1)) /* Last descriptor gets EOP and RS */
- txd->read.cmd_type_len |=
- htole32(IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS);
-#ifndef NO_82598_A0_SUPPORT
- if (adapter->hw.revision_id == 0)
- desc_flip(txd);
-#endif
}
+ txd->read.cmd_type_len |=
+ htole32(IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS);
txr->tx_avail -= nsegs;
txr->next_avail_tx_desc = i;
@@ -1355,8 +1533,8 @@ ixgbe_xmit(struct tx_ring *txr, struct m
* Advance the Transmit Descriptor Tail (Tdt), this tells the
* hardware that this frame is available to transmit.
*/
+ ++txr->total_packets;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(txr->me), i);
- ++txr->tx_packets;
return (0);
xmit_fail:
@@ -1484,17 +1662,26 @@ ixgbe_local_timer(void *arg)
mtx_assert(&adapter->core_mtx, MA_OWNED);
+ /* Check for pluggable optics */
+ if (adapter->sfp_probe)
+ if (!ixgbe_sfp_probe(adapter))
+ goto out; /* Nothing to do */
+
ixgbe_update_link_status(adapter);
ixgbe_update_stats_counters(adapter);
if (ixgbe_display_debug_stats && ifp->if_drv_flags & IFF_DRV_RUNNING) {
ixgbe_print_hw_stats(adapter);
}
/*
- * Each second we check the watchdog
+ * Each tick we check the watchdog
* to protect against hardware hangs.
*/
ixgbe_watchdog(adapter);
+out:
+ /* Trigger an RX interrupt on all queues */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, adapter->rx_mask);
+
callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
}
@@ -1681,6 +1868,11 @@ ixgbe_allocate_msix(struct adapter *adap
}
txr->msix = vector;
txr->eims = IXGBE_IVAR_TX_QUEUE(vector);
+ TASK_INIT(&txr->tx_task, 0, ixgbe_handle_tx, txr);
+ txr->tq = taskqueue_create_fast("ixgbe_txq", M_NOWAIT,
+ taskqueue_thread_enqueue, &txr->tq);
+ taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq",
+ device_get_nameunit(adapter->dev));
}
/* RX setup */
@@ -1705,6 +1897,13 @@ ixgbe_allocate_msix(struct adapter *adap
}
rxr->msix = vector;
rxr->eims = IXGBE_IVAR_RX_QUEUE(vector);
+ /* used in local timer */
+ adapter->rx_mask |= rxr->eims;
+ TASK_INIT(&rxr->rx_task, 0, ixgbe_handle_rx, rxr);
+ rxr->tq = taskqueue_create_fast("ixgbe_rxq", M_NOWAIT,
+ taskqueue_thread_enqueue, &rxr->tq);
+ taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq",
+ device_get_nameunit(adapter->dev));
}
/* Now for Link changes */
@@ -1739,11 +1938,20 @@ ixgbe_setup_msix(struct adapter *adapter
device_t dev = adapter->dev;
int rid, want, queues, msgs;
+ /* Override by tuneable */
+ if (ixgbe_enable_msix == 0)
+ goto msi;
+
/* First try MSI/X */
- rid = PCIR_BAR(IXGBE_MSIX_BAR);
+ rid = PCIR_BAR(MSIX_82598_BAR);
adapter->msix_mem = bus_alloc_resource_any(dev,
SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (!adapter->msix_mem) {
+ rid += 4; /* 82599 maps in higher BAR */
+ adapter->msix_mem = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ }
+ if (!adapter->msix_mem) {
/* May not be enabled */
device_printf(adapter->dev,
"Unable to map MSIX table \n");
@@ -1753,7 +1961,7 @@ ixgbe_setup_msix(struct adapter *adapter
msgs = pci_msix_count(dev);
if (msgs == 0) { /* system has msix disabled */
bus_release_resource(dev, SYS_RES_MEMORY,
- PCIR_BAR(IXGBE_MSIX_BAR), adapter->msix_mem);
+ rid, adapter->msix_mem);
adapter->msix_mem = NULL;
goto msi;
}
@@ -1833,7 +2041,8 @@ ixgbe_allocate_pci_resources(struct adap
static void
ixgbe_free_pci_resources(struct adapter * adapter)
{
- device_t dev = adapter->dev;
+ device_t dev = adapter->dev;
+ int rid;
/*
* Legacy has this set to 0, but we need
@@ -1842,6 +2051,8 @@ ixgbe_free_pci_resources(struct adapter
if (adapter->msix == 0)
adapter->msix = 1;
+ rid = PCIR_BAR(MSIX_82598_BAR);
+
/*
* First release all the interrupt resources:
* notice that since these are just kept
@@ -1865,7 +2076,7 @@ ixgbe_free_pci_resources(struct adapter
if (adapter->msix_mem != NULL)
bus_release_resource(dev, SYS_RES_MEMORY,
- PCIR_BAR(IXGBE_MSIX_BAR), adapter->msix_mem);
+ rid, adapter->msix_mem);
if (adapter->pci_mem != NULL)
bus_release_resource(dev, SYS_RES_MEMORY,
@@ -1900,7 +2111,7 @@ ixgbe_hardware_init(struct adapter *adap
}
/* Get Hardware Flow Control setting */
- adapter->hw.fc.type = ixgbe_fc_full;
+ adapter->hw.fc.requested_mode = ixgbe_fc_full;
adapter->hw.fc.pause_time = IXGBE_FC_PAUSE;
adapter->hw.fc.low_water = IXGBE_FC_LO;
adapter->hw.fc.high_water = IXGBE_FC_HI;
@@ -1957,8 +2168,7 @@ ixgbe_setup_interface(device_t dev, stru
ifp->if_capenable = ifp->if_capabilities;
- if ((hw->device_id == IXGBE_DEV_ID_82598AT) ||
- (hw->device_id == IXGBE_DEV_ID_82598AT_DUAL_PORT))
+ if (hw->device_id == IXGBE_DEV_ID_82598AT)
ixgbe_setup_link_speed(hw, (IXGBE_LINK_SPEED_10GB_FULL |
IXGBE_LINK_SPEED_1GB_FULL), TRUE, TRUE);
else
@@ -1971,10 +2181,9 @@ ixgbe_setup_interface(device_t dev, stru
*/
ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change,
ixgbe_media_status);
- ifmedia_add(&adapter->media, IFM_ETHER | ixgbe_optics |
+ ifmedia_add(&adapter->media, IFM_ETHER | adapter->optics |
IFM_FDX, 0, NULL);
- if ((hw->device_id == IXGBE_DEV_ID_82598AT) ||
- (hw->device_id == IXGBE_DEV_ID_82598AT_DUAL_PORT)) {
+ if (hw->device_id == IXGBE_DEV_ID_82598AT) {
ifmedia_add(&adapter->media,
IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
ifmedia_add(&adapter->media,
@@ -2075,7 +2284,6 @@ ixgbe_allocate_queues(struct adapter *ad
struct tx_ring *txr;
struct rx_ring *rxr;
int rsize, tsize, error = IXGBE_SUCCESS;
- char name_string[16];
int txconf = 0, rxconf = 0;
/* First allocate the TX ring struct memory */
@@ -2114,9 +2322,9 @@ ixgbe_allocate_queues(struct adapter *ad
txr->me = i;
/* Initialize the TX side lock */
- snprintf(name_string, sizeof(name_string), "%s:tx(%d)",
+ snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
device_get_nameunit(dev), txr->me);
- mtx_init(&txr->tx_mtx, name_string, NULL, MTX_DEF);
+ mtx_init(&txr->tx_mtx, txr->mtx_name, NULL, MTX_DEF);
if (ixgbe_dma_malloc(adapter, tsize,
&txr->txdma, BUS_DMA_NOWAIT)) {
@@ -2149,10 +2357,10 @@ ixgbe_allocate_queues(struct adapter *ad
rxr->adapter = adapter;
rxr->me = i;
- /* Initialize the TX side lock */
- snprintf(name_string, sizeof(name_string), "%s:rx(%d)",
+ /* Initialize the RX side lock */
+ snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
device_get_nameunit(dev), rxr->me);
- mtx_init(&rxr->rx_mtx, name_string, NULL, MTX_DEF);
+ mtx_init(&rxr->rx_mtx, rxr->mtx_name, NULL, MTX_DEF);
if (ixgbe_dma_malloc(adapter, rsize,
&rxr->rxdma, BUS_DMA_NOWAIT)) {
@@ -2534,11 +2742,6 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr,
TXD->seqnum_seed = htole32(0);
TXD->mss_l4len_idx = htole32(0);
-#ifndef NO_82598_A0_SUPPORT
- if (adapter->hw.revision_id == 0)
- desc_flip(TXD);
-#endif
-
tx_buffer->m_head = NULL;
/* We've consumed the first desc, adjust counters */
@@ -2632,11 +2835,6 @@ ixgbe_tso_setup(struct tx_ring *txr, str
TXD->seqnum_seed = htole32(0);
tx_buffer->m_head = NULL;
-#ifndef NO_82598_A0_SUPPORT
- if (adapter->hw.revision_id == 0)
- desc_flip(TXD);
-#endif
-
if (++ctxd == adapter->num_tx_desc)
ctxd = 0;
@@ -2758,76 +2956,110 @@ ixgbe_txeof(struct tx_ring *txr)
*
**********************************************************************/
static int
-ixgbe_get_buf(struct rx_ring *rxr, int i)
+ixgbe_get_buf(struct rx_ring *rxr, int i, u8 clean)
{
- struct adapter *adapter = rxr->adapter;
- struct mbuf *mp;
- bus_dmamap_t map;
- int nsegs, error, old, s = 0;
- int size = MCLBYTES;
-
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-7
mailing list