diff options
author | jfv <jfv@FreeBSD.org> | 2008-11-26 23:41:18 +0000 |
---|---|---|
committer | jfv <jfv@FreeBSD.org> | 2008-11-26 23:41:18 +0000 |
commit | 62188214bdac09b8b3fe223bd994d8aef28db6db (patch) | |
tree | da2cf29f3a19749ccacb115e679f319ba8aeae8f /sys/dev/ixgbe/ixgbe.c | |
parent | 8c32a341579fa9f728f1a37365754b5507e3c538 (diff) | |
download | FreeBSD-src-62188214bdac09b8b3fe223bd994d8aef28db6db.zip FreeBSD-src-62188214bdac09b8b3fe223bd994d8aef28db6db.tar.gz |
Updated ixgbe driver - version 1.6.2
-This version has header split, and as a result a number of
aspects of the code have been improved/simplified.
- Interrupt handling refined for performance
- Many small bugs fixed along the way
MFC after: ASAP - in time for 7.1
Diffstat (limited to 'sys/dev/ixgbe/ixgbe.c')
-rw-r--r-- | sys/dev/ixgbe/ixgbe.c | 1253 |
1 files changed, 759 insertions, 494 deletions
diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c index 26f4066..81100fa 100644 --- a/sys/dev/ixgbe/ixgbe.c +++ b/sys/dev/ixgbe/ixgbe.c @@ -36,9 +36,6 @@ #include "opt_device_polling.h" #endif -/* Undefine this if not using CURRENT */ -#define IXGBE_VLAN_EVENTS - #include "ixgbe.h" /********************************************************************* @@ -49,7 +46,7 @@ int ixgbe_display_debug_stats = 0; /********************************************************************* * Driver version *********************************************************************/ -char ixgbe_driver_version[] = "1.4.7"; +char ixgbe_driver_version[] = "1.6.2"; /********************************************************************* * PCI Device ID Table @@ -65,11 +62,15 @@ static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = { {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} }; @@ -128,14 +129,14 @@ static void ixgbe_disable_intr(struct adapter *); 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); @@ -147,15 +148,20 @@ static void ixgbe_add_rx_process_limit(struct adapter *, const char *, 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_VLAN_EVENTS +#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 *); @@ -168,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 @@ -199,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); /* @@ -213,7 +232,7 @@ TUNABLE_INT("hw.ixgbe.flow_control", &ixgbe_flow_control); * 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); /* @@ -224,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 */ @@ -243,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 * @@ -260,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"); @@ -289,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); } @@ -342,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"); @@ -353,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)), @@ -374,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"); @@ -428,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; @@ -459,14 +518,14 @@ ixgbe_attach(device_t dev) /* Initialize statistics */ ixgbe_update_stats_counters(adapter); -#ifdef IXGBE_VLAN_EVENTS +#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; @@ -521,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; } } @@ -529,22 +587,21 @@ ixgbe_detach(device_t dev) if (rxr->tq) { taskqueue_drain(rxr->tq, &rxr->rx_task); taskqueue_free(rxr->tq); - rxr->tq = NULL; } } -#ifdef IXGBE_VLAN_EVENTS + /* 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); -#endif - - /* 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); @@ -848,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"); @@ -872,17 +932,16 @@ ixgbe_init_locked(struct adapter *adapter) return; } -#ifndef IXGBE_VLAN_EVENTS - /* With events this is done when a vlan registers */ +#ifndef IXGBE_HW_VLAN_SUPPORT if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { - u32 ctrl; + 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"); @@ -892,15 +951,24 @@ ixgbe_init_locked(struct adapter *adapter) 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)) { @@ -912,10 +980,22 @@ ixgbe_init_locked(struct adapter *adapter) /* 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; @@ -955,12 +1035,29 @@ ixgbe_init_locked(struct adapter *adapter) 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); @@ -984,7 +1081,7 @@ ixgbe_init(void *arg) /* -** Legacy Deferred Interrupt Handlers +** MSIX Interrupt Handlers */ static void @@ -992,11 +1089,14 @@ ixgbe_handle_rx(void *context, int pending) { 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 @@ -1005,15 +1105,21 @@ ixgbe_handle_tx(void *context, int pending) 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); } @@ -1026,34 +1132,38 @@ ixgbe_handle_tx(void *context, int pending) 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; } @@ -1067,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 * **********************************************************************/ @@ -1093,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) { @@ -1164,7 +1327,7 @@ ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) 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; } @@ -1220,7 +1383,7 @@ ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) { 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; @@ -1230,7 +1393,6 @@ ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) union ixgbe_adv_tx_desc *txd = NULL; m_head = *m_headp; - paylen = 0; /* Basic descriptor defines */ cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA; @@ -1274,7 +1436,7 @@ ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) 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); @@ -1326,6 +1488,11 @@ ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) } 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; @@ -1346,19 +1513,10 @@ ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) 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; @@ -1375,8 +1533,8 @@ ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) * 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: @@ -1504,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); } @@ -1701,6 +1868,11 @@ ixgbe_allocate_msix(struct adapter *adapter) } 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 */ @@ -1725,6 +1897,13 @@ ixgbe_allocate_msix(struct adapter *adapter) } 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 */ @@ -1759,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"); @@ -1773,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; } @@ -1853,7 +2041,8 @@ ixgbe_allocate_pci_resources(struct adapter *adapter) 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 @@ -1862,6 +2051,8 @@ ixgbe_free_pci_resources(struct adapter * 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 @@ -1885,7 +2076,7 @@ ixgbe_free_pci_resources(struct adapter * 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, @@ -1920,7 +2111,7 @@ ixgbe_hardware_init(struct adapter *adapter) } /* 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; @@ -1977,8 +2168,7 @@ ixgbe_setup_interface(device_t dev, struct adapter *adapter) 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 @@ -1991,10 +2181,9 @@ ixgbe_setup_interface(device_t dev, struct adapter *adapter) */ 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, @@ -2095,7 +2284,6 @@ ixgbe_allocate_queues(struct adapter *adapter) 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 */ @@ -2134,9 +2322,9 @@ ixgbe_allocate_queues(struct adapter *adapter) 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)) { @@ -2169,10 +2357,10 @@ ixgbe_allocate_queues(struct adapter *adapter) 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)) { @@ -2554,11 +2742,6 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp) 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 */ @@ -2652,11 +2835,6 @@ ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *paylen) 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; @@ -2778,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; - - - bus_dma_segment_t segs[1]; + struct adapter *adapter = rxr->adapter; + bus_dma_segment_t seg[2]; struct ixgbe_rx_buf *rxbuf; + struct mbuf *mh, *mp; + bus_dmamap_t map; + int nsegs, error; + int merr = 0; - /* Are we going to Jumbo clusters? */ - if (adapter->bigbufs) { - size = MJUMPAGESIZE; - s = 1; - }; - - mp = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); - if (mp == NULL) { - adapter->mbuf_alloc_failed++; - return (ENOBUFS); - } - mp->m_len = mp->m_pkthdr.len = size; - - if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) - m_adj(mp, ETHER_ALIGN); + rxbuf = &rxr->rx_buffers[i]; + /* First get our header and payload mbuf */ + if (clean & IXGBE_CLEAN_HDR) { + mh = m_gethdr(M_DONTWAIT, MT_DATA); + if (mh == NULL) + goto remap; + } else /* reuse */ + mh = rxr->rx_buffers[i].m_head; + + mh->m_len = MHLEN; + mh->m_flags |= M_PKTHDR; + + if (clean & IXGBE_CLEAN_PKT) { + mp = m_getjcl(M_DONTWAIT, MT_DATA, + M_PKTHDR, adapter->rx_mbuf_sz); + if (mp == NULL) + goto remap; + mp->m_len = adapter->rx_mbuf_sz; + mp->m_flags &= ~M_PKTHDR; + } else { /* reusing */ + mp = rxr->rx_buffers[i].m_pack; + mp->m_len = adapter->rx_mbuf_sz; + mp->m_flags &= ~M_PKTHDR; + } /* - * Using memory from the mbuf cluster pool, invoke the bus_dma - * machinery to arrange the memory mapping. - */ - error = bus_dmamap_load_mbuf_sg(rxr->rxtag[s], rxr->spare_map[s], - mp, segs, &nsegs, BUS_DMA_NOWAIT); - if (error) { - m_free(mp); + ** Need to create a chain for the following + ** dmamap call at this point. + */ + mh->m_next = mp; + mh->m_pkthdr.len = mh->m_len + mp->m_len; + + /* Get the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->rxtag, + rxr->spare_map, mh, seg, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("GET BUF: dmamap load failure - %d\n", error); + m_free(mh); return (error); } - /* Now check our target buffer for existing mapping */ - rxbuf = &rxr->rx_buffers[i]; - old = rxbuf->bigbuf; + /* Unload old mapping and update buffer struct */ if (rxbuf->m_head != NULL) - bus_dmamap_unload(rxr->rxtag[old], rxbuf->map[old]); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + map = rxbuf->map; + rxbuf->map = rxr->spare_map; + rxr->spare_map = map; + rxbuf->m_head = mh; + rxbuf->m_pack = mp; + bus_dmamap_sync(rxr->rxtag, + rxbuf->map, BUS_DMASYNC_PREREAD); + + /* Update descriptor */ + rxr->rx_base[i].read.hdr_addr = htole64(seg[0].ds_addr); + rxr->rx_base[i].read.pkt_addr = htole64(seg[1].ds_addr); - map = rxbuf->map[old]; - rxbuf->map[s] = rxr->spare_map[s]; - rxr->spare_map[old] = map; - bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], BUS_DMASYNC_PREREAD); - rxbuf->m_head = mp; - rxbuf->bigbuf = s; - - rxr->rx_base[i].read.pkt_addr = htole64(segs[0].ds_addr); - -#ifndef NO_82598_A0_SUPPORT - /* A0 needs to One's Compliment descriptors */ - if (adapter->hw.revision_id == 0) { - struct dhack {u32 a1; u32 a2; u32 b1; u32 b2;}; - struct dhack *d; + return (0); - d = (struct dhack *)&rxr->rx_base[i]; - d->a1 = ~(d->a1); - d->a2 = ~(d->a2); + /* + ** If we get here, we have an mbuf resource + ** issue, so we discard the incoming packet + ** and attempt to reuse existing mbufs next + ** pass thru the ring, but to do so we must + ** fix up the descriptor which had the address + ** clobbered with writeback info. + */ +remap: + adapter->mbuf_header_failed++; + merr = ENOBUFS; + /* Is there a reusable buffer? */ + mh = rxr->rx_buffers[i].m_head; + if (mh == NULL) /* Nope, init error */ + return (merr); + mp = rxr->rx_buffers[i].m_pack; + if (mp == NULL) /* Nope, init error */ + return (merr); + /* Get our old mapping */ + rxbuf = &rxr->rx_buffers[i]; + error = bus_dmamap_load_mbuf_sg(rxr->rxtag, + rxbuf->map, mh, seg, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + /* We really have a problem */ + m_free(mh); + return (error); } -#endif + /* Now fix the descriptor as needed */ + rxr->rx_base[i].read.hdr_addr = htole64(seg[0].ds_addr); + rxr->rx_base[i].read.pkt_addr = htole64(seg[1].ds_addr); - return (0); + return (merr); } + /********************************************************************* * * Allocate memory for rx_buffer structures. Since we use one @@ -2873,45 +3085,30 @@ ixgbe_allocate_receive_buffers(struct rx_ring *rxr) goto fail; } - /* First make the small (2K) tag/map */ - if ((error = bus_dma_tag_create(NULL, /* parent */ - PAGE_SIZE, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MCLBYTES, /* maxsize */ - 1, /* nsegments */ - MCLBYTES, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &rxr->rxtag[0]))) { - device_printf(dev, "Unable to create RX Small DMA tag\n"); - goto fail; - } - - /* Next make the large (4K) tag/map */ + /* + ** The tag is made to accomodate the largest buffer size + ** with packet split (hence the two segments, even though + ** it may not always use this. + */ if ((error = bus_dma_tag_create(NULL, /* parent */ PAGE_SIZE, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - MJUMPAGESIZE, /* maxsize */ - 1, /* nsegments */ + MJUM16BYTES, /* maxsize */ + 2, /* nsegments */ MJUMPAGESIZE, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ - &rxr->rxtag[1]))) { - device_printf(dev, "Unable to create RX Large DMA tag\n"); + &rxr->rxtag))) { + device_printf(dev, "Unable to create RX DMA tag\n"); goto fail; } - /* Create the spare maps (used by getbuf) */ - error = bus_dmamap_create(rxr->rxtag[0], BUS_DMA_NOWAIT, - &rxr->spare_map[0]); - error = bus_dmamap_create(rxr->rxtag[1], BUS_DMA_NOWAIT, - &rxr->spare_map[1]); + /* Create the spare map (used by getbuf) */ + error = bus_dmamap_create(rxr->rxtag, BUS_DMA_NOWAIT, + &rxr->spare_map); if (error) { device_printf(dev, "%s: bus_dmamap_create failed: %d\n", __func__, error); @@ -2920,16 +3117,10 @@ ixgbe_allocate_receive_buffers(struct rx_ring *rxr) for (i = 0; i < adapter->num_rx_desc; i++, rxbuf++) { rxbuf = &rxr->rx_buffers[i]; - error = bus_dmamap_create(rxr->rxtag[0], - BUS_DMA_NOWAIT, &rxbuf->map[0]); + error = bus_dmamap_create(rxr->rxtag, + BUS_DMA_NOWAIT, &rxbuf->map); if (error) { - device_printf(dev, "Unable to create Small RX DMA map\n"); - goto fail; - } - error = bus_dmamap_create(rxr->rxtag[1], - BUS_DMA_NOWAIT, &rxbuf->map[1]); - if (error) { - device_printf(dev, "Unable to create Large RX DMA map\n"); + device_printf(dev, "Unable to create RX DMA map\n"); goto fail; } } @@ -2954,38 +3145,41 @@ ixgbe_setup_receive_ring(struct rx_ring *rxr) device_t dev; struct ixgbe_rx_buf *rxbuf; struct lro_ctrl *lro = &rxr->lro; - int j, rsize, s = 0; + int j, rsize; adapter = rxr->adapter; dev = adapter->dev; - rsize = roundup2(adapter->num_rx_desc * - sizeof(union ixgbe_adv_rx_desc), 4096); + /* Clear the ring contents */ + rsize = roundup2(adapter->num_rx_desc * + sizeof(union ixgbe_adv_rx_desc), DBA_ALIGN); bzero((void *)rxr->rx_base, rsize); /* - ** Free current RX buffers: the size buffer - ** that is loaded is indicated by the buffer - ** bigbuf value. + ** Free current RX buffer structs and their mbufs */ for (int i = 0; i < adapter->num_rx_desc; i++) { rxbuf = &rxr->rx_buffers[i]; - s = rxbuf->bigbuf; if (rxbuf->m_head != NULL) { - bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], + bus_dmamap_sync(rxr->rxtag, rxbuf->map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); - m_freem(rxbuf->m_head); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + if (rxbuf->m_head) { + rxbuf->m_head->m_next = rxbuf->m_pack; + m_freem(rxbuf->m_head); + } rxbuf->m_head = NULL; + rxbuf->m_pack = NULL; } } + /* Now refresh the mbufs */ for (j = 0; j < adapter->num_rx_desc; j++) { - if (ixgbe_get_buf(rxr, j) == ENOBUFS) { + if (ixgbe_get_buf(rxr, j, IXGBE_CLEAN_ALL) == ENOBUFS) { rxr->rx_buffers[j].m_head = NULL; + rxr->rx_buffers[j].m_pack = NULL; + rxr->rx_base[j].read.hdr_addr = 0; rxr->rx_base[j].read.pkt_addr = 0; - /* If we fail some may have change size */ - s = adapter->bigbufs; goto fail; } } @@ -3001,27 +3195,26 @@ ixgbe_setup_receive_ring(struct rx_ring *rxr) if (ixgbe_enable_lro) { int err = tcp_lro_init(lro); if (err) { - device_printf(dev,"LRO Initialization failed!\n"); + INIT_DEBUGOUT("LRO Initialization failed!\n"); goto fail; } - device_printf(dev,"RX LRO Initialized\n"); + INIT_DEBUGOUT("RX LRO Initialized\n"); lro->ifp = adapter->ifp; } - return (0); + fail: /* - * We need to clean up any buffers allocated so far - * 'j' is the failing index, decrement it to get the - * last success. + * We need to clean up any buffers allocated + * so far, 'j' is the failing index. */ - for (--j; j < 0; j--) { - rxbuf = &rxr->rx_buffers[j]; + for (int i = 0; i < j; i++) { + rxbuf = &rxr->rx_buffers[i]; if (rxbuf->m_head != NULL) { - bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], + bus_dmamap_sync(rxr->rxtag, rxbuf->map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); m_freem(rxbuf->m_head); rxbuf->m_head = NULL; } @@ -3038,9 +3231,9 @@ static int ixgbe_setup_receive_structures(struct adapter *adapter) { struct rx_ring *rxr = adapter->rx_rings; - int i, j, s; + int j; - for (i = 0; i < adapter->num_rx_queues; i++, rxr++) + for (j = 0; j < adapter->num_rx_queues; j++, rxr++) if (ixgbe_setup_receive_ring(rxr)) goto fail; @@ -3049,19 +3242,17 @@ fail: /* * Free RX buffers allocated so far, we will only handle * the rings that completed, the failing case will have - * cleaned up for itself. The value of 'i' will be the - * failed ring so we must pre-decrement it. + * cleaned up for itself. 'j' failed, so its the terminus. */ - rxr = adapter->rx_rings; - for (--i; i > 0; i--, rxr++) { - for (j = 0; j < adapter->num_rx_desc; j++) { + for (int i = 0; i < j; ++i) { + rxr = &adapter->rx_rings[i]; + for (int n = 0; n < adapter->num_rx_desc; n++) { struct ixgbe_rx_buf *rxbuf; - rxbuf = &rxr->rx_buffers[j]; - s = rxbuf->bigbuf; + rxbuf = &rxr->rx_buffers[n]; if (rxbuf->m_head != NULL) { - bus_dmamap_sync(rxr->rxtag[s], rxbuf->map[s], + bus_dmamap_sync(rxr->rxtag, rxbuf->map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); m_freem(rxbuf->m_head); rxbuf->m_head = NULL; } @@ -3073,110 +3264,109 @@ fail: /********************************************************************* * - * Enable receive unit. + * Setup receive registers and features. * **********************************************************************/ +#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 + static void ixgbe_initialize_receive_units(struct adapter *adapter) { struct rx_ring *rxr = adapter->rx_rings; + struct ixgbe_hw *hw = &adapter->hw; struct ifnet *ifp = adapter->ifp; u32 rxctrl, fctrl, srrctl, rxcsum; - u32 mrqc, hlreg, linkvec; - u32 random[10]; - int i,j; - union { - u8 c[128]; - u32 i[32]; - } reta; + u32 reta, mrqc = 0, hlreg, random[10]; /* * Make sure receives are disabled while * setting up the descriptor ring */ - rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); /* Enable broadcasts */ - fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); fctrl |= IXGBE_FCTRL_BAM; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); + fctrl |= IXGBE_FCTRL_DPF; + fctrl |= IXGBE_FCTRL_PMCF; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); - hlreg = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); - if (ifp->if_mtu > ETHERMTU) - hlreg |= IXGBE_HLREG0_JUMBOEN; - else - hlreg &= ~IXGBE_HLREG0_JUMBOEN; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, hlreg); - - srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0)); + srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(0)); srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; - if (adapter->bigbufs) + + hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); + /* Set for Jumbo Frames? */ + if (ifp->if_mtu > ETHERMTU) { + hlreg |= IXGBE_HLREG0_JUMBOEN; srrctl |= 4096 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - else + } else { + hlreg &= ~IXGBE_HLREG0_JUMBOEN; srrctl |= 2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl); + } + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); - /* Set Queue moderation rate */ - for (i = 0; i < IXGBE_MSGS; i++) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(i), DEFAULT_ITR); + if (ixgbe_rx_hdr_split) { + /* Use a standard mbuf for the header */ + srrctl |= ((IXGBE_RX_HDR << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) + & IXGBE_SRRCTL_BSIZEHDR_MASK); + srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; + } else + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; - /* Set Link moderation lower */ - linkvec = adapter->num_tx_queues + adapter->num_rx_queues; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(linkvec), LINK_ITR); + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(0), srrctl); for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { u64 rdba = rxr->rxdma.dma_paddr; /* Setup the Base and Length of the Rx Descriptor Ring */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAL(i), + IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & 0x00000000ffffffffULL)); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAH(i), (rdba >> 32)); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDLEN(i), + IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); /* Setup the HW Rx Head and Tail Descriptor Pointers */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDH(i), 0); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(i), - adapter->num_rx_desc - 1); + IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); } - rxcsum = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCSUM); + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + /* Setup RSS */ if (adapter->num_rx_queues > 1) { + int i, j; + reta = 0; + /* set up random bits */ arc4rand(&random, sizeof(random), 0); - /* Create reta data */ - for (i = 0; i < 128; ) - for (j = 0; j < adapter->num_rx_queues && - i < 128; j++, i++) - reta.c[i] = j; - /* Set up the redirection table */ - for (i = 0; i < 32; i++) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RETA(i), reta.i[i]); + for (i = 0, j = 0; i < 128; i++, j++) { + if (j == adapter->num_rx_queues) j = 0; + reta = (reta << 8) | (j * 0x11); + if ((i & 3) == 3) + IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); + } /* Now fill our hash function seeds */ for (int i = 0; i < 10; i++) - IXGBE_WRITE_REG_ARRAY(&adapter->hw, - IXGBE_RSSRK(0), i, random[i]); - - mrqc = IXGBE_MRQC_RSSEN - /* Perform hash on these packet types */ - | IXGBE_MRQC_RSS_FIELD_IPV4 - | IXGBE_MRQC_RSS_FIELD_IPV4_TCP - | IXGBE_MRQC_RSS_FIELD_IPV4_UDP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX - | IXGBE_MRQC_RSS_FIELD_IPV6 - | IXGBE_MRQC_RSS_FIELD_IPV6_TCP - | IXGBE_MRQC_RSS_FIELD_IPV6_UDP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_MRQC, mrqc); + IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random[i]); + + /* Perform hash on these packet types */ + mrqc |= IXGBE_MRQC_RSSEN + | IXGBE_MRQC_RSS_FIELD_IPV4 + | IXGBE_MRQC_RSS_FIELD_IPV4_TCP + | IXGBE_MRQC_RSS_FIELD_IPV4_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX + | IXGBE_MRQC_RSS_FIELD_IPV6 + | IXGBE_MRQC_RSS_FIELD_IPV6_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); /* RSS and RX IPP Checksum are mutually exclusive */ rxcsum |= IXGBE_RXCSUM_PCSD; @@ -3188,11 +3378,7 @@ ixgbe_initialize_receive_units(struct adapter *adapter) if (!(rxcsum & IXGBE_RXCSUM_PCSD)) rxcsum |= IXGBE_RXCSUM_IPPCSE; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCSUM, rxcsum); - - /* Enable Receive engine */ - rxctrl |= (IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rxctrl); + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); return; } @@ -3235,10 +3421,11 @@ ixgbe_free_receive_buffers(struct rx_ring *rxr) if (rxr->rx_buffers != NULL) { rxbuf = &rxr->rx_buffers[0]; for (int i = 0; i < adapter->num_rx_desc; i++) { - int s = rxbuf->bigbuf; if (rxbuf->map != NULL) { - bus_dmamap_unload(rxr->rxtag[s], rxbuf->map[s]); - bus_dmamap_destroy(rxr->rxtag[s], rxbuf->map[s]); + bus_dmamap_sync(rxr->rxtag, rxbuf->map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rxr->rxtag, rxbuf->map); + bus_dmamap_destroy(rxr->rxtag, rxbuf->map); } if (rxbuf->m_head != NULL) { m_freem(rxbuf->m_head); @@ -3251,11 +3438,9 @@ ixgbe_free_receive_buffers(struct rx_ring *rxr) free(rxr->rx_buffers, M_DEVBUF); rxr->rx_buffers = NULL; } - for (int s = 0; s < 2; s++) { - if (rxr->rxtag[s] != NULL) { - bus_dma_tag_destroy(rxr->rxtag[s]); - rxr->rxtag[s] = NULL; - } + if (rxr->rxtag != NULL) { + bus_dma_tag_destroy(rxr->rxtag); + rxr->rxtag = NULL; } return; } @@ -3269,6 +3454,7 @@ ixgbe_free_receive_buffers(struct rx_ring *rxr) * We loop at most count times if count is > 0, or until done if * count < 0. * + * Return TRUE for more work, FALSE for all clean. *********************************************************************/ static bool ixgbe_rxeof(struct rx_ring *rxr, int count) @@ -3277,10 +3463,8 @@ ixgbe_rxeof(struct rx_ring *rxr, int count) struct ifnet *ifp = adapter->ifp; struct lro_ctrl *lro = &rxr->lro; struct lro_entry *queued; - struct mbuf *mp; - int len, i, eop = 0; - u8 accept_frame = 0; - u32 staterr; + int i; + u32 staterr; union ixgbe_adv_rx_desc *cur; @@ -3294,70 +3478,127 @@ ixgbe_rxeof(struct rx_ring *rxr, int count) return FALSE; } + /* Sync the ring */ + bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, + BUS_DMASYNC_POSTREAD); + while ((staterr & IXGBE_RXD_STAT_DD) && (count != 0) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) { - struct mbuf *m = NULL; - int s; + struct mbuf *sendmp, *mh, *mp; + u16 hlen, plen, hdr; + u8 dopayload, accept_frame, eop; + - mp = rxr->rx_buffers[i].m_head; - s = rxr->rx_buffers[i].bigbuf; - bus_dmamap_sync(rxr->rxtag[s], rxr->rx_buffers[i].map[s], - BUS_DMASYNC_POSTREAD); accept_frame = 1; + hlen = plen = 0; + sendmp = mh = mp = NULL; + + /* Sync the buffers */ + bus_dmamap_sync(rxr->rxtag, rxr->rx_buffers[i].map, + BUS_DMASYNC_POSTREAD); + + /* + ** The way the hardware is configured to + ** split, it will ONLY use the header buffer + ** when header split is enabled, otherwise we + ** get normal behavior, ie, both header and + ** payload are DMA'd into the payload buffer. + ** + ** The fmp test is to catch the case where a + ** packet spans multiple descriptors, in that + ** case only the first header is valid. + */ + if ((ixgbe_rx_hdr_split) && (rxr->fmp == NULL)){ + hdr = le16toh(cur-> + wb.lower.lo_dword.hs_rss.hdr_info); + hlen = (hdr & IXGBE_RXDADV_HDRBUFLEN_MASK) >> + IXGBE_RXDADV_HDRBUFLEN_SHIFT; + if (hlen > IXGBE_RX_HDR) + hlen = IXGBE_RX_HDR; + plen = le16toh(cur->wb.upper.length); + /* Handle the header mbuf */ + mh = rxr->rx_buffers[i].m_head; + mh->m_len = hlen; + dopayload = IXGBE_CLEAN_HDR; + /* + ** Get the payload length, this + ** could be zero if its a small + ** packet. + */ + if (plen) { + mp = rxr->rx_buffers[i].m_pack; + mp->m_len = plen; + mp->m_next = NULL; + mp->m_flags &= ~M_PKTHDR; + mh->m_next = mp; + mh->m_flags |= M_PKTHDR; + dopayload = IXGBE_CLEAN_ALL; + rxr->rx_split_packets++; + } else { /* small packets */ + mh->m_flags &= ~M_PKTHDR; + mh->m_next = NULL; + } + } else { + /* + ** Either no header split, or a + ** secondary piece of a fragmented + ** split packet. + */ + mh = rxr->rx_buffers[i].m_pack; + mh->m_flags |= M_PKTHDR; + mh->m_len = le16toh(cur->wb.upper.length); + dopayload = IXGBE_CLEAN_PKT; + } + if (staterr & IXGBE_RXD_STAT_EOP) { count--; eop = 1; - } else { + } else eop = 0; - } - len = cur->wb.upper.length; if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) accept_frame = 0; if (accept_frame) { - /* Get a fresh buffer first */ - if (ixgbe_get_buf(rxr, i) != 0) { + if (ixgbe_get_buf(rxr, i, dopayload) != 0) { ifp->if_iqdrops++; goto discard; } - - /* Assign correct length to the current fragment */ - mp->m_len = len; - + /* Initial frame - setup */ if (rxr->fmp == NULL) { - mp->m_pkthdr.len = len; - rxr->fmp = mp; /* Store the first mbuf */ - rxr->lmp = mp; + mh->m_flags |= M_PKTHDR; + mh->m_pkthdr.len = mh->m_len; + rxr->fmp = mh; /* Store the first mbuf */ + rxr->lmp = mh; + if (mp) { /* Add payload if split */ + mh->m_pkthdr.len += mp->m_len; + rxr->lmp = mh->m_next; + } } else { /* Chain mbuf's together */ - mp->m_flags &= ~M_PKTHDR; - rxr->lmp->m_next = mp; + mh->m_flags &= ~M_PKTHDR; + rxr->lmp->m_next = mh; rxr->lmp = rxr->lmp->m_next; - rxr->fmp->m_pkthdr.len += len; + rxr->fmp->m_pkthdr.len += mh->m_len; } if (eop) { rxr->fmp->m_pkthdr.rcvif = ifp; ifp->if_ipackets++; - rxr->packet_count++; - rxr->byte_count += rxr->fmp->m_pkthdr.len; - - ixgbe_rx_checksum(adapter, - staterr, rxr->fmp); - + rxr->rx_packets++; + /* capture data for AIM */ + rxr->bytes += rxr->fmp->m_pkthdr.len; + rxr->rx_bytes += rxr->bytes; + if (ifp->if_capenable & IFCAP_RXCSUM) + ixgbe_rx_checksum(staterr, rxr->fmp); + else + rxr->fmp->m_pkthdr.csum_flags = 0; if (staterr & IXGBE_RXD_STAT_VP) { -#if __FreeBSD_version < 700000 - VLAN_INPUT_TAG_NEW(ifp, rxr->fmp, - (le16toh(cur->wb.upper.vlan) & - IXGBE_RX_DESC_SPECIAL_VLAN_MASK)); -#else rxr->fmp->m_pkthdr.ether_vtag = - le16toh(cur->wb.upper.vlan); - rxr->fmp->m_flags |= M_VLANTAG; -#endif + le16toh(cur->wb.upper.vlan); + rxr->fmp->m_flags |= M_VLANTAG; } - m = rxr->fmp; + sendmp = rxr->fmp; rxr->fmp = NULL; rxr->lmp = NULL; } @@ -3365,23 +3606,26 @@ ixgbe_rxeof(struct rx_ring *rxr, int count) ifp->if_ierrors++; discard: /* Reuse loaded DMA map and just update mbuf chain */ - mp = rxr->rx_buffers[i].m_head; - mp->m_len = mp->m_pkthdr.len = - (rxr->rx_buffers[i].bigbuf ? MJUMPAGESIZE:MCLBYTES); + if (hlen) { + mh = rxr->rx_buffers[i].m_head; + mh->m_len = MHLEN; + mh->m_next = NULL; + } + mp = rxr->rx_buffers[i].m_pack; + mp->m_len = mp->m_pkthdr.len = adapter->rx_mbuf_sz; mp->m_data = mp->m_ext.ext_buf; mp->m_next = NULL; - if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) + if (adapter->max_frame_size <= + (MCLBYTES - ETHER_ALIGN)) m_adj(mp, ETHER_ALIGN); if (rxr->fmp != NULL) { + /* handles the whole chain */ m_freem(rxr->fmp); rxr->fmp = NULL; rxr->lmp = NULL; } - m = NULL; + sendmp = NULL; } - - /* Zero out the receive descriptors status */ - cur->wb.upper.status_error = 0; bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); @@ -3390,17 +3634,18 @@ discard: if (++i == adapter->num_rx_desc) i = 0; - /* Now send up to the stack */ - if (m != NULL) { - rxr->next_to_check = i; + /* + ** Now send up to the stack, + ** note the the value of next_to_check + ** is safe because we keep the RX lock + ** thru this call. + */ + if (sendmp != NULL) { /* Use LRO if possible */ - if ((!lro->lro_cnt) || (tcp_lro_rx(lro, m, 0))) { - IXGBE_RX_UNLOCK(rxr); - (*ifp->if_input)(ifp, m); - IXGBE_RX_LOCK(rxr); - i = rxr->next_to_check; - } + if ((!lro->lro_cnt) || (tcp_lro_rx(lro, sendmp, 0))) + (*ifp->if_input)(ifp, sendmp); } + /* Get next descriptor */ cur = &rxr->rx_base[i]; staterr = cur->wb.upper.status_error; @@ -3409,23 +3654,28 @@ discard: /* Advance the IXGB's Receive Queue "Tail Pointer" */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(rxr->me), rxr->last_cleaned); - IXGBE_RX_UNLOCK(rxr); /* - ** Flush any outstanding LRO work - ** this may call into the stack and - ** must not hold a driver lock. - */ - while(!SLIST_EMPTY(&lro->lro_active)) { + * Flush any outstanding LRO work + */ + while (!SLIST_EMPTY(&lro->lro_active)) { queued = SLIST_FIRST(&lro->lro_active); SLIST_REMOVE_HEAD(&lro->lro_active, next); tcp_lro_flush(lro, queued); } - if (!(staterr & IXGBE_RXD_STAT_DD)) - return FALSE; + IXGBE_RX_UNLOCK(rxr); - return TRUE; + /* + ** Leaving with more to clean? + ** then schedule another interrupt. + */ + if (staterr & IXGBE_RXD_STAT_DD) { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, rxr->eims); + return TRUE; + } + + return FALSE; } /********************************************************************* @@ -3436,19 +3686,11 @@ discard: * *********************************************************************/ static void -ixgbe_rx_checksum(struct adapter *adapter, - u32 staterr, struct mbuf * mp) +ixgbe_rx_checksum(u32 staterr, struct mbuf * mp) { - struct ifnet *ifp = adapter->ifp; u16 status = (u16) staterr; u8 errors = (u8) (staterr >> 24); - /* Not offloading */ - if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) { - mp->m_pkthdr.csum_flags = 0; - return; - } - if (status & IXGBE_RXD_STAT_IPCS) { /* Did it pass? */ if (!(errors & IXGBE_RXD_ERR_IPE)) { @@ -3470,7 +3712,8 @@ ixgbe_rx_checksum(struct adapter *adapter, return; } -#ifdef IXGBE_VLAN_EVENTS + +#ifdef IXGBE_HW_VLAN_SUPPORT /* * This routine is run via an vlan * config EVENT @@ -3479,7 +3722,7 @@ static void ixgbe_register_vlan(void *unused, struct ifnet *ifp, u16 vtag) { struct adapter *adapter = ifp->if_softc; - u32 ctrl; + u32 ctrl, rctl, index, vfta; ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE; @@ -3498,6 +3741,7 @@ static void ixgbe_unregister_vlan(void *unused, struct ifnet *ifp, u16 vtag) { struct adapter *adapter = ifp->if_softc; + u32 index, vfta; /* Remove entry in the hardware filter table */ ixgbe_set_vfta(&adapter->hw, vtag, 0, FALSE); @@ -3513,7 +3757,7 @@ ixgbe_unregister_vlan(void *unused, struct ifnet *ifp, u16 vtag) IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); } } -#endif /* IXGBE_VLAN_EVENTS */ +#endif static void ixgbe_enable_intr(struct adapter *adapter) @@ -3524,16 +3768,17 @@ ixgbe_enable_intr(struct adapter *adapter) /* Enable Fan Failure detection */ if (hw->phy.media_type == ixgbe_media_type_copper) mask |= IXGBE_EIMS_GPI_SDP1; + + IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); + /* With RSS we use auto clear */ if (adapter->msix_mem) { /* Dont autoclear Link */ mask &= ~IXGBE_EIMS_OTHER; mask &= ~IXGBE_EIMS_LSC; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, - adapter->eims_mask | mask); + IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); } - IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); IXGBE_WRITE_FLUSH(hw); return; @@ -3560,17 +3805,38 @@ ixgbe_read_pci_cfg(struct ixgbe_hw *hw, u32 reg) return (value); } +/* +** Setup the correct IVAR register for a particular MSIX interrupt +** (yes this is all very magic and confusing :) +** - entry is the register array entry +** - vector is the MSIX vector for this queue +** - type is RX/TX/MISC +*/ static void -ixgbe_set_ivar(struct adapter *adapter, u16 entry, u8 vector) +ixgbe_set_ivar(struct adapter *adapter, u16 entry, u8 vector, s8 type) { + struct ixgbe_hw *hw = &adapter->hw; u32 ivar, index; vector |= IXGBE_IVAR_ALLOC_VAL; - index = (entry >> 2) & 0x1F; - ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index)); - ivar &= ~(0xFF << (8 * (entry & 0x3))); - ivar |= (vector << (8 * (entry & 0x3))); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); + + switch (hw->mac.type) { + + case ixgbe_mac_82598EB: + if (type == -1) + entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; + else + entry += (type * 64); + index = (entry >> 2) & 0x1F; + ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); + ivar &= ~(0xFF << (8 * (entry & 0x3))); + ivar |= (vector << (8 * (entry & 0x3))); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); + break; + + default: + break; + } } static void @@ -3579,22 +3845,48 @@ ixgbe_configure_ivars(struct adapter *adapter) struct tx_ring *txr = adapter->tx_rings; struct rx_ring *rxr = adapter->rx_rings; - for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { - ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i), rxr->msix); - adapter->eims_mask |= rxr->eims; - } + for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) + ixgbe_set_ivar(adapter, i, rxr->msix, 0); - for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { - ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), txr->msix); - adapter->eims_mask |= txr->eims; - } + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) + ixgbe_set_ivar(adapter, i, txr->msix, 1); /* For the Link interrupt */ - ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, - adapter->linkvec); - adapter->eims_mask |= IXGBE_IVAR_OTHER_CAUSES_INDEX; + ixgbe_set_ivar(adapter, 1, adapter->linkvec, -1); +} + +/* +** ixgbe_sfp_probe - called in the local timer to +** determine if a port had optics inserted. +*/ +static bool ixgbe_sfp_probe(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + device_t dev = adapter->dev; + bool result = FALSE; + + if ((hw->phy.type == ixgbe_phy_nl) && + (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { + s32 ret = hw->phy.ops.identify_sfp(hw); + if (ret) + goto out; + ret = hw->phy.ops.reset(hw); + if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { + device_printf(dev,"Unsupported SFP+ module detected!"); + printf(" Reload driver with supported module.\n"); + adapter->sfp_probe = FALSE; + goto out; + } else + device_printf(dev,"SFP+ module detected!\n"); + /* We now have supported optics */ + adapter->sfp_probe = FALSE; + result = TRUE; + } +out: + return (result); } + /********************************************************************** * * Update the board statistics counters. @@ -3643,9 +3935,6 @@ ixgbe_update_stats_counters(struct adapter *adapter) adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); - adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); - adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); - lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); adapter->stats.lxontxc += lxon; lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); @@ -3700,10 +3989,7 @@ ixgbe_print_hw_stats(struct adapter * adapter) device_printf(dev,"Std Mbuf Failed = %lu\n", - adapter->mbuf_alloc_failed); - device_printf(dev,"Std Cluster Failed = %lu\n", - adapter->mbuf_cluster_failed); - + adapter->mbuf_defrag_failed); device_printf(dev,"Missed Packets = %llu\n", (long long)adapter->stats.mpc[0]); device_printf(dev,"Receive length errors = %llu\n", @@ -3760,10 +4046,12 @@ ixgbe_print_debug_info(struct adapter *adapter) device_printf(dev,"Queue[%d]: rdh = %d, hw rdt = %d\n", i, IXGBE_READ_REG(hw, IXGBE_RDH(i)), IXGBE_READ_REG(hw, IXGBE_RDT(i))); - device_printf(dev,"RX(%d) Packets Received: %lu\n", - rxr->me, (long)rxr->packet_count); + device_printf(dev,"RX(%d) Packets Received: %lld\n", + rxr->me, (long long)rxr->rx_packets); + device_printf(dev,"RX(%d) Split RX Packets: %lld\n", + rxr->me, (long long)rxr->rx_split_packets); device_printf(dev,"RX(%d) Bytes Received: %lu\n", - rxr->me, (long)rxr->byte_count); + rxr->me, (long)rxr->rx_bytes); device_printf(dev,"RX(%d) IRQ Handled: %lu\n", rxr->me, (long)rxr->rx_irq); device_printf(dev,"RX(%d) LRO Queued= %d\n", @@ -3777,7 +4065,7 @@ ixgbe_print_debug_info(struct adapter *adapter) IXGBE_READ_REG(hw, IXGBE_TDH(i)), IXGBE_READ_REG(hw, IXGBE_TDT(i))); device_printf(dev,"TX(%d) Packets Sent: %lu\n", - txr->me, (long)txr->tx_packets); + txr->me, (long)txr->total_packets); device_printf(dev,"TX(%d) IRQ Handled: %lu\n", txr->me, (long)txr->tx_irq); device_printf(dev,"TX(%d) NO Desc Avail: %lu\n", @@ -3852,11 +4140,11 @@ ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS) case ixgbe_fc_rx_pause: case ixgbe_fc_tx_pause: case ixgbe_fc_full: - adapter->hw.fc.type = ixgbe_flow_control; + adapter->hw.fc.requested_mode = ixgbe_flow_control; break; case ixgbe_fc_none: default: - adapter->hw.fc.type = ixgbe_fc_none; + adapter->hw.fc.requested_mode = ixgbe_fc_none; } ixgbe_setup_fc(&adapter->hw, 0); @@ -3872,26 +4160,3 @@ ixgbe_add_rx_process_limit(struct adapter *adapter, const char *name, SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description); } - -#ifndef NO_82598_A0_SUPPORT -/* - * A0 Workaround: invert descriptor for hardware - */ -void -desc_flip(void *desc) -{ - struct dhack {u32 a1; u32 a2; u32 b1; u32 b2;}; - struct dhack *d; - - d = (struct dhack *)desc; - d->a1 = ~(d->a1); - d->a2 = ~(d->a2); - d->b1 = ~(d->b1); - d->b2 = ~(d->b2); - d->b2 &= 0xFFFFFFF0; - d->b1 &= ~IXGBE_ADVTXD_DCMD_RS; -} -#endif - - - |