Date: Mon, 7 Dec 2009 21:30:54 +0000 (UTC) From: Jack F Vogel <jfv@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r200239 - head/sys/dev/ixgbe Message-ID: <200912072130.nB7LUsX1066653@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jfv Date: Mon Dec 7 21:30:54 2009 New Revision: 200239 URL: http://svn.freebsd.org/changeset/base/200239 Log: Update driver to Intel version 2.0.7: This adds new feature support for the 82599, a hardware assist to LRO, doing this required a large revamp to the RX cleanup code because the descriptor ring may not be processed out of order, this necessitated the elimination of global pointers. Additionally, the RX routine now does not refresh mbufs on every descriptor, rather it will do a range, and then update the hardware pointer at that time. These are performance oriented changes. The TX side now has a cleaner simpler watchdog algorithm as well, in TX cleanup a read of ticks is stored, that can then be compared in local_timer to determine if there is a hang. Various other cleanups along the way, thanks to all who have provided input and testing. Modified: head/sys/dev/ixgbe/ixgbe.c head/sys/dev/ixgbe/ixgbe.h head/sys/dev/ixgbe/ixgbe_82598.c head/sys/dev/ixgbe/ixgbe_82599.c head/sys/dev/ixgbe/ixgbe_api.c head/sys/dev/ixgbe/ixgbe_api.h head/sys/dev/ixgbe/ixgbe_common.c head/sys/dev/ixgbe/ixgbe_common.h head/sys/dev/ixgbe/ixgbe_osdep.h head/sys/dev/ixgbe/ixgbe_phy.c head/sys/dev/ixgbe/ixgbe_phy.h head/sys/dev/ixgbe/ixgbe_type.h Modified: head/sys/dev/ixgbe/ixgbe.c ============================================================================== --- head/sys/dev/ixgbe/ixgbe.c Mon Dec 7 21:24:07 2009 (r200238) +++ head/sys/dev/ixgbe/ixgbe.c Mon Dec 7 21:30:54 2009 (r200239) @@ -46,7 +46,7 @@ int ixgbe_display_debug_stat /********************************************************************* * Driver version *********************************************************************/ -char ixgbe_driver_version[] = "1.8.9"; +char ixgbe_driver_version[] = "2.0.7"; /********************************************************************* * PCI Device ID Table @@ -64,16 +64,19 @@ static ixgbe_vendor_info_t ixgbe_vendor_ {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_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_82598AT2, 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}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0}, {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0}, + {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0}, /* required last entry */ {0, 0, 0, 0, 0} }; @@ -102,7 +105,6 @@ static int ixgbe_mq_start_locked(struct static void ixgbe_qflush(struct ifnet *); #endif static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); -static void ixgbe_watchdog(struct adapter *); static void ixgbe_init(void *); static void ixgbe_init_locked(struct adapter *); static void ixgbe_stop(void *); @@ -116,8 +118,8 @@ static int ixgbe_allocate_queues(struct static int ixgbe_setup_msix(struct adapter *); static void ixgbe_free_pci_resources(struct adapter *); static void ixgbe_local_timer(void *); -static int ixgbe_hardware_init(struct adapter *); static void ixgbe_setup_interface(device_t, struct adapter *); +static void ixgbe_config_link(struct adapter *); static int ixgbe_allocate_transmit_buffers(struct tx_ring *); static int ixgbe_setup_transmit_structures(struct adapter *); @@ -132,6 +134,7 @@ static int ixgbe_setup_receive_ring(stru static void ixgbe_initialize_receive_units(struct adapter *); static void ixgbe_free_receive_structures(struct adapter *); static void ixgbe_free_receive_buffers(struct rx_ring *); +static void ixgbe_setup_hw_rsc(struct rx_ring *); static void ixgbe_init_moderation(struct adapter *); static void ixgbe_enable_intr(struct adapter *); @@ -146,7 +149,7 @@ static void ixgbe_set_multi(struct a 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, u8); +static int ixgbe_get_buf(struct rx_ring *, int, int); 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); @@ -186,6 +189,10 @@ static void ixgbe_handle_link(void *, in static void ixgbe_handle_msf(void *, int); static void ixgbe_handle_mod(void *, int); +#ifdef IXGBE_FDIR +static void ixgbe_atr(struct tx_ring *, struct mbuf *); +static void ixgbe_reinit_fdir(void *, int); +#endif /********************************************************************* * FreeBSD Device Interface Entry Points @@ -239,6 +246,15 @@ static int ixgbe_flow_control = ixgbe_fc TUNABLE_INT("hw.ixgbe.flow_control", &ixgbe_flow_control); /* +** Smart speed setting, default to on +** this only works as a compile option +** right now as its during attach, set +** this to 'ixgbe_smart_speed_off' to +** disable. +*/ +static int ixgbe_smart_speed = ixgbe_smart_speed_on; + +/* * MSIX should be the default for best performance, * but this allows it to be forced off for testing. */ @@ -271,7 +287,7 @@ TUNABLE_INT("hw.ixgbe.txd", &ixgbe_txd); static int ixgbe_rxd = DEFAULT_RXD; TUNABLE_INT("hw.ixgbe.rxd", &ixgbe_rxd); -/* Total number of Interfaces - need for config sanity check */ +/* Keep running tab on them for sanity check */ static int ixgbe_total_ports; /* @@ -288,6 +304,27 @@ static u32 ixgbe_shadow_vfta[IXGBE_VFTA_ */ static int ixgbe_num_segs = IXGBE_82598_SCATTER; +#ifdef IXGBE_FDIR +/* +** For Flow Director: this is the +** number of TX packets we sample +** for the filter pool, this means +** every 20th packet will be probed. +** +** This feature can be disabled by +** setting this to 0. +*/ +static int atr_sample_rate = 20; +/* +** Flow Director actually 'steals' +** part of the packet buffer as its +** filter pool, this variable controls +** how much it uses: +** 0 = 64K, 1 = 128K, 2 = 256K +*/ +static int fdir_pballoc = 1; +#endif + /********************************************************************* * Device identification routine * @@ -356,7 +393,7 @@ ixgbe_attach(device_t dev) struct adapter *adapter; struct ixgbe_hw *hw; int error = 0; - u16 pci_device_id; + u16 pci_device_id, csum; u32 ctrl_ext; INIT_DEBUGOUT("ixgbe_attach: begin"); @@ -376,10 +413,14 @@ ixgbe_attach(device_t dev) case IXGBE_DEV_ID_82598EB_CX4 : adapter->optics = IFM_10G_CX4; break; + case IXGBE_DEV_ID_82598 : case IXGBE_DEV_ID_82598AF_DUAL_PORT : case IXGBE_DEV_ID_82598_DA_DUAL_PORT : case IXGBE_DEV_ID_82598AF_SINGLE_PORT : + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM : + case IXGBE_DEV_ID_82598EB_SFP_LOM : case IXGBE_DEV_ID_82598AT : + case IXGBE_DEV_ID_82598AT2 : adapter->optics = IFM_10G_SR; break; case IXGBE_DEV_ID_82598EB_XF_LR : @@ -390,10 +431,13 @@ ixgbe_attach(device_t dev) ixgbe_num_segs = IXGBE_82599_SCATTER; break; case IXGBE_DEV_ID_82599_KX4 : + case IXGBE_DEV_ID_82599_KX4_MEZZ: + case IXGBE_DEV_ID_82599_CX4 : adapter->optics = IFM_10G_CX4; ixgbe_num_segs = IXGBE_82599_SCATTER; break; case IXGBE_DEV_ID_82599_XAUI_LOM : + case IXGBE_DEV_ID_82599_COMBO_BACKPLANE : ixgbe_num_segs = IXGBE_82599_SCATTER; default: break; @@ -504,13 +548,40 @@ ixgbe_attach(device_t dev) goto err_late; } - /* Initialize the hardware */ - if (ixgbe_hardware_init(adapter)) { - device_printf(dev,"Unable to initialize the hardware\n"); + /* Make sure we have a good EEPROM before we read from it */ + if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { + device_printf(dev,"The EEPROM Checksum Is Not Valid\n"); error = EIO; goto err_late; } + /* Pick up the smart speed setting */ + if (hw->mac.type == ixgbe_mac_82599EB) + hw->phy.smart_speed = ixgbe_smart_speed; + + /* Get Hardware Flow Control setting */ + hw->fc.requested_mode = ixgbe_fc_full; + hw->fc.pause_time = IXGBE_FC_PAUSE; + hw->fc.low_water = IXGBE_FC_LO; + hw->fc.high_water = IXGBE_FC_HI; + hw->fc.send_xon = TRUE; + + error = ixgbe_init_hw(hw); + if (error == IXGBE_ERR_EEPROM_VERSION) { + device_printf(dev, "This device is a pre-production adapter/" + "LOM. Please be aware there may be issues associated " + "with your hardware.\n If you are experiencing problems " + "please contact your Intel or hardware representative " + "who provided you with this hardware.\n"); + } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) + device_printf(dev,"Unsupported SFP+ Module\n"); + + if (error) { + error = EIO; + device_printf(dev,"Hardware Initialization Failure\n"); + goto err_late; + } + if ((adapter->msix > 1) && (ixgbe_enable_msix)) error = ixgbe_allocate_msix(adapter); else @@ -529,10 +600,10 @@ ixgbe_attach(device_t dev) adapter->cycles.mask = (u64)-1; adapter->cycles.mult = 1; adapter->cycles.shift = IXGBE_TSYNC_SHIFT; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_TIMINCA, (1<<24) | + IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, (1<<24) | IXGBE_TSYNC_CYCLE_TIME * IXGBE_TSYNC_SHIFT); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_SYSTIML, 0x00000000); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_SYSTIMH, 0xFF800000); + IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0x00000000); + IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0xFF800000); // JFV - this is not complete yet #endif @@ -551,6 +622,24 @@ ixgbe_attach(device_t dev) adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); + /* Print PCIE bus type/speed/width info */ + ixgbe_get_bus_info(hw); + device_printf(dev,"PCI Express Bus: Speed %s %s\n", + ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s": + (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"), + (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : + (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : + (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : + ("Unknown")); + + if (hw->bus.width <= ixgbe_bus_width_pcie_x4) { + device_printf(dev, "PCI-Express bandwidth available" + " for this card\n is not sufficient for" + " optimal performance.\n"); + device_printf(dev, "For optimal performance a x8 " + "PCI-Express slot is required.\n"); + } + /* let hardware know driver is loaded */ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; @@ -616,6 +705,9 @@ ixgbe_detach(device_t dev) taskqueue_drain(adapter->tq, &adapter->link_task); taskqueue_drain(adapter->tq, &adapter->mod_task); taskqueue_drain(adapter->tq, &adapter->msf_task); +#ifdef IXGBE_FDIR + taskqueue_drain(adapter->tq, &adapter->fdir_task); +#endif taskqueue_free(adapter->tq); } @@ -700,8 +792,8 @@ ixgbe_start_locked(struct tx_ring *txr, /* Send a copy of the frame to the BPF listener */ ETHER_BPF_MTAP(ifp, m_head); - /* Set timeout in case hardware has problems transmitting */ - txr->watchdog_timer = IXGBE_TX_TIMEOUT; + /* Set watchdog on */ + txr->watchdog_check = TRUE; } return; @@ -770,16 +862,17 @@ ixgbe_mq_start_locked(struct ifnet *ifp, /* If nothing queued go right to xmit */ if (drbr_empty(ifp, txr->br)) { - if (ixgbe_xmit(txr, &m)) { - if (m && (err = drbr_enqueue(ifp, txr->br, m)) != 0) - return (err); + if ((err = ixgbe_xmit(txr, &m)) != 0) { + if (m != NULL) + err = drbr_enqueue(ifp, txr->br, m); + return (err); } else { /* Success, update stats */ drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags); /* Send a copy of the frame to the BPF listener */ ETHER_BPF_MTAP(ifp, m); /* Set the watchdog */ - txr->watchdog_timer = IXGBE_TX_TIMEOUT; + txr->watchdog_check = TRUE; } } else if ((err = drbr_enqueue(ifp, txr->br, m)) != 0) @@ -796,11 +889,15 @@ process: next = drbr_dequeue(ifp, txr->br); if (next == NULL) break; - if (ixgbe_xmit(txr, &next)) + if ((err = ixgbe_xmit(txr, &next)) != 0) { + if (next != NULL) + err = drbr_enqueue(ifp, txr->br, next); break; + } + drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); ETHER_BPF_MTAP(ifp, next); /* Set the watchdog */ - txr->watchdog_timer = IXGBE_TX_TIMEOUT; + txr->watchdog_check = TRUE; } if (txr->tx_avail <= IXGBE_TX_OP_THRESHOLD) @@ -843,27 +940,10 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c { struct adapter *adapter = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; -#ifdef INET - struct ifaddr *ifa = (struct ifaddr *) data; -#endif int error = 0; switch (command) { - case SIOCSIFADDR: -#ifdef INET - IOCTL_DEBUGOUT("ioctl: SIOCxIFADDR (Get/Set Interface Addr)"); - if (ifa->ifa_addr->sa_family == AF_INET) { - ifp->if_flags |= IFF_UP; - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - IXGBE_CORE_LOCK(adapter); - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - arp_ifinit(ifp, ifa); - } else -#endif - ether_ioctl(ifp, command, data); - break; + case SIOCSIFMTU: IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); if (ifr->ifr_mtu > IXGBE_MAX_FRAME_SIZE - ETHER_HDR_LEN) { @@ -919,7 +999,8 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c ifp->if_capenable ^= IFCAP_HWCSUM; if (mask & IFCAP_TSO4) ifp->if_capenable ^= IFCAP_TSO4; - if (mask & IFCAP_LRO) + /* Only allow changing when using header split */ + if ((mask & IFCAP_LRO) && (ixgbe_header_split)) ifp->if_capenable ^= IFCAP_LRO; if (mask & IFCAP_VLAN_HWTAGGING) ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; @@ -948,84 +1029,6 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c } /********************************************************************* - * Watchdog entry point - * - * This routine is called by the local timer - * to detect hardware hangs . - * - **********************************************************************/ - -static void -ixgbe_watchdog(struct adapter *adapter) -{ - device_t dev = adapter->dev; - struct tx_ring *txr = adapter->tx_rings; - struct ixgbe_hw *hw = &adapter->hw; - bool tx_hang = FALSE; - - IXGBE_CORE_LOCK_ASSERT(adapter); - - /* - * The timer is set to 5 every time ixgbe_start() queues a packet. - * Then ixgbe_txeof() keeps resetting to 5 as long as it cleans at - * least one descriptor. - * Finally, anytime all descriptors are clean the timer is - * set to 0. - */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - u32 head, tail; - - IXGBE_TX_LOCK(txr); - if (txr->watchdog_timer == 0 || --txr->watchdog_timer) { - IXGBE_TX_UNLOCK(txr); - continue; - } else { - head = IXGBE_READ_REG(hw, IXGBE_TDH(i)); - tail = IXGBE_READ_REG(hw, IXGBE_TDT(i)); - if (head == tail) { /* last minute check */ - IXGBE_TX_UNLOCK(txr); - continue; - } - /* Well, seems something is really hung */ - tx_hang = TRUE; - IXGBE_TX_UNLOCK(txr); - break; - } - } - if (tx_hang == FALSE) - return; - - /* - * If we are in this routine because of pause frames, then don't - * reset the hardware. - */ - if (IXGBE_READ_REG(hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF) { - txr = adapter->tx_rings; /* reset pointer */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { - IXGBE_TX_LOCK(txr); - txr->watchdog_timer = IXGBE_TX_TIMEOUT; - IXGBE_TX_UNLOCK(txr); - } - return; - } - - - device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); - for (int i = 0; i < adapter->num_queues; i++, txr++) { - device_printf(dev,"Queue(%d) tdh = %d, hw tdt = %d\n", i, - IXGBE_READ_REG(hw, IXGBE_TDH(i)), - IXGBE_READ_REG(hw, IXGBE_TDT(i))); - device_printf(dev,"TX(%d) desc avail = %d," - "Next TX to Clean = %d\n", - i, txr->tx_avail, txr->next_tx_to_clean); - } - adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - adapter->watchdog_events++; - - ixgbe_init_locked(adapter); -} - -/********************************************************************* * Init entry point * * This routine is used in two ways. It is used by the stack as @@ -1052,19 +1055,14 @@ ixgbe_init_locked(struct adapter *adapte hw = &adapter->hw; mtx_assert(&adapter->core_mtx, MA_OWNED); - ixgbe_stop(adapter); - /* Get the latest mac address, User can use a LAA */ - bcopy(IF_LLADDR(adapter->ifp), adapter->hw.mac.addr, + bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); - ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, 1); - adapter->hw.addr_ctrl.rar_used_count = 1; + ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); + hw->addr_ctrl.rar_used_count = 1; - /* Initialize the hardware */ - if (ixgbe_hardware_init(adapter)) { - device_printf(dev, "Unable to initialize the hardware\n"); - return; - } + /* Do a warm reset */ + ixgbe_reset_hw(hw); /* Prepare transmit descriptors and buffers */ if (ixgbe_setup_transmit_structures(adapter)) { @@ -1102,7 +1100,7 @@ ixgbe_init_locked(struct adapter *adapte gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); - if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + if (hw->mac.type == ixgbe_mac_82599EB) { gpie |= IXGBE_SDP1_GPIEN; gpie |= IXGBE_SDP2_GPIEN; } @@ -1117,7 +1115,7 @@ ixgbe_init_locked(struct adapter *adapte gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD; } - IXGBE_WRITE_REG(&adapter->hw, IXGBE_GPIE, gpie); + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); /* Set the various hardware offload abilities */ ifp->if_hwassist = 0; @@ -1128,28 +1126,35 @@ ixgbe_init_locked(struct adapter *adapte /* Set MTU size */ if (ifp->if_mtu > ETHERMTU) { - mhadd = IXGBE_READ_REG(&adapter->hw, IXGBE_MHADD); + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); mhadd &= ~IXGBE_MHADD_MFS_MASK; mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_MHADD, mhadd); + IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); } /* Now enable all the queues */ for (int i = 0; i < adapter->num_queues; i++) { - txdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(i)); + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); txdctl |= IXGBE_TXDCTL_ENABLE; /* Set WTHRESH to 8, burst writeback */ txdctl |= (8 << 16); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(i), txdctl); + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), txdctl); } for (int i = 0; i < adapter->num_queues; i++) { - rxdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(i)); - /* PTHRESH set to 32 */ - rxdctl |= 0x0020; + rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + if (hw->mac.type == ixgbe_mac_82598EB) { + /* + ** PTHRESH = 21 + ** HTHRESH = 4 + ** WTHRESH = 8 + */ + rxdctl &= ~0x3FFFFF; + rxdctl |= 0x080420; + } rxdctl |= IXGBE_RXDCTL_ENABLE; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(i), rxdctl); + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); for (k = 0; k < 10; k++) { if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) & IXGBE_RXDCTL_ENABLE) @@ -1166,7 +1171,7 @@ ixgbe_init_locked(struct adapter *adapte /* Enable Receive engine */ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); - if (adapter->hw.mac.type == ixgbe_mac_82598EB) + if (hw->mac.type == ixgbe_mac_82598EB) rxctrl |= IXGBE_RXCTRL_DMBYPS; rxctrl |= IXGBE_RXCTRL_RXEN; IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl); @@ -1181,7 +1186,11 @@ ixgbe_init_locked(struct adapter *adapte ixgbe_set_ivar(adapter, 0, 0, 1); } - ixgbe_enable_intr(adapter); +#ifdef IXGBE_FDIR + /* Init Flow director */ + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); +#endif /* ** Check on any SFP devices that @@ -1194,14 +1203,12 @@ ixgbe_init_locked(struct adapter *adapte ixgbe_detach(dev); return; } - if (ixgbe_is_sfp(hw)) { - if (hw->phy.multispeed_fiber) { - hw->mac.ops.setup_sfp(hw); - taskqueue_enqueue(adapter->tq, &adapter->msf_task); - } else - taskqueue_enqueue(adapter->tq, &adapter->mod_task); - } else - taskqueue_enqueue(adapter->tq, &adapter->link_task); + + /* Config/Enable Link */ + ixgbe_config_link(adapter); + + /* And now turn on interrupts */ + ixgbe_enable_intr(adapter); /* Now inform the stack we're ready */ ifp->if_drv_flags |= IFF_DRV_RUNNING; @@ -1269,7 +1276,7 @@ ixgbe_disable_queue(struct adapter *adap } static inline void -ixgbe_rearm_rx_queues(struct adapter *adapter, u64 queues) +ixgbe_rearm_queues(struct adapter *adapter, u64 queues) { u32 mask; @@ -1464,11 +1471,25 @@ ixgbe_msix_link(void *arg) taskqueue_enqueue(adapter->tq, &adapter->link_task); if (adapter->hw.mac.type == ixgbe_mac_82599EB) { +#ifdef IXGBE_FDIR + if (reg_eicr & IXGBE_EICR_FLOW_DIR) { + /* This is probably overkill :) */ + if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) + return; + /* Clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR); + /* Turn off the interface */ + adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + taskqueue_enqueue(adapter->tq, &adapter->fdir_task); + } else +#endif if (reg_eicr & IXGBE_EICR_ECC) { device_printf(adapter->dev, "\nCRITICAL: ECC ERROR!! " "Please Reboot!!\n"); IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); - } else if (reg_eicr & IXGBE_EICR_GPI_SDP1) { + } else + + if (reg_eicr & IXGBE_EICR_GPI_SDP1) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); taskqueue_enqueue(adapter->tq, &adapter->msf_task); @@ -1553,11 +1574,9 @@ ixgbe_init_moderation(struct adapter *ad } /* TX irq moderation rate is fixed */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_queues; i++, txr++) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(txr->msix), ixgbe_ave_latency); - txr->watchdog_timer = FALSE; - } /* RX moderation will be adapted over time, set default */ for (int i = 0; i < adapter->num_queues; i++, rxr++) { @@ -1633,7 +1652,6 @@ ixgbe_media_change(struct ifnet * ifp) switch (IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO: - adapter->hw.mac.autoneg = TRUE; adapter->hw.phy.autoneg_advertised = IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_10GB_FULL; break; @@ -1690,7 +1708,7 @@ ixgbe_xmit(struct tx_ring *txr, struct m * used because it will contain the index of * the one we tell the hardware to report back */ - first = txr->next_avail_tx_desc; + first = txr->next_avail_desc; txbuf = &txr->tx_buffers[first]; txbuf_mapped = txbuf; map = txbuf->map; @@ -1767,12 +1785,22 @@ ixgbe_xmit(struct tx_ring *txr, struct m cmd_type_len |= IXGBE_ADVTXD_MAC_TSTAMP; #endif +#ifdef IXGBE_FDIR + /* Do the flow director magic */ + if ((txr->atr_sample) && (!adapter->fdir_reinit)) { + ++txr->atr_count; + if (txr->atr_count >= atr_sample_rate) { + ixgbe_atr(txr, m_head); + txr->atr_count = 0; + } + } +#endif /* Record payload length */ if (paylen == 0) olinfo_status |= m_head->m_pkthdr.len << IXGBE_ADVTXD_PAYLEN_SHIFT; - i = txr->next_avail_tx_desc; + i = txr->next_avail_desc; for (j = 0; j < nsegs; j++) { bus_size_t seglen; bus_addr_t segaddr; @@ -1798,7 +1826,7 @@ ixgbe_xmit(struct tx_ring *txr, struct m txd->read.cmd_type_len |= htole32(IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS); txr->tx_avail -= nsegs; - txr->next_avail_tx_desc = i; + txr->next_avail_desc = i; txbuf->m_head = m_head; txbuf->map = map; @@ -1939,7 +1967,7 @@ ixgbe_mc_array_itr(struct ixgbe_hw *hw, * Timer routine * * This routine checks for link status,updates statistics, - * and runs the watchdog timer. + * and runs the watchdog check. * **********************************************************************/ @@ -1948,6 +1976,9 @@ ixgbe_local_timer(void *arg) { struct adapter *adapter = arg; struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; + struct tx_ring *txr = adapter->tx_rings; + bool tx_hung = FALSE; mtx_assert(&adapter->core_mtx, MA_OWNED); @@ -1962,16 +1993,31 @@ ixgbe_local_timer(void *arg) ixgbe_print_hw_stats(adapter); } /* - * Each tick we check the watchdog - * to protect against hardware hangs. - */ - ixgbe_watchdog(adapter); - + ** Check for time since any descriptor was cleaned + */ + for (int i = 0; i < adapter->num_queues; i++, txr++) { + if (txr->watchdog_check == FALSE) + continue; + if ((ticks - txr->watchdog_time) > IXGBE_WATCHDOG) { + tx_hung = TRUE; + goto hung; + } + } out: - /* Trigger an RX interrupt on all queues */ - ixgbe_rearm_rx_queues(adapter, adapter->rx_mask); - callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); + return; + +hung: + device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + device_printf(dev,"Queue(%d) tdh = %d, hw tdt = %d\n", txr->me, + IXGBE_READ_REG(&adapter->hw, IXGBE_TDH(txr->me)), + IXGBE_READ_REG(&adapter->hw, IXGBE_TDT(txr->me))); + device_printf(dev,"TX(%d) desc avail = %d," + "Next TX to Clean = %d\n", + txr->me, txr->tx_avail, txr->next_to_clean); + adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + adapter->watchdog_events++; + ixgbe_init_locked(adapter); } /* @@ -2004,7 +2050,7 @@ ixgbe_update_link_status(struct adapter adapter->link_active = FALSE; for (int i = 0; i < adapter->num_queues; i++, txr++) - txr->watchdog_timer = FALSE; + txr->watchdog_check = FALSE; } } @@ -2113,6 +2159,9 @@ ixgbe_allocate_legacy(struct adapter *ad TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); +#ifdef IXGBE_FDIR + TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); +#endif adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, taskqueue_thread_enqueue, &adapter->tq); taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", @@ -2242,6 +2291,9 @@ ixgbe_allocate_msix(struct adapter *adap TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); +#ifdef IXGBE_FDIR + TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); +#endif adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, taskqueue_thread_enqueue, &adapter->tq); taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", @@ -2432,65 +2484,15 @@ mem: /********************************************************************* * - * Initialize the hardware to a configuration as specified by the - * adapter structure. The controller is reset, the EEPROM is - * verified, the MAC address is set, then the shared initialization - * routines are called. - * - **********************************************************************/ -static int -ixgbe_hardware_init(struct adapter *adapter) -{ - device_t dev = adapter->dev; - u32 ret; - u16 csum; - - csum = 0; - /* Issue a global reset */ - adapter->hw.adapter_stopped = FALSE; - ixgbe_stop_adapter(&adapter->hw); - - /* Make sure we have a good EEPROM before we read from it */ - if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { - device_printf(dev,"The EEPROM Checksum Is Not Valid\n"); - return (EIO); - } - - /* Get Hardware Flow Control setting */ - 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; - adapter->hw.fc.send_xon = TRUE; - - ret = ixgbe_init_hw(&adapter->hw); - if (ret == IXGBE_ERR_EEPROM_VERSION) { - device_printf(dev, "This device is a pre-production adapter/" - "LOM. Please be aware there may be issues associated " - "with your hardware.\n If you are experiencing problems " - "please contact your Intel or hardware representative " - "who provided you with this hardware.\n"); - } else if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev,"Unsupported SFP+ Module\n"); - return (EIO); - } else if (ret != 0 ) { - device_printf(dev,"Hardware Initialization Failure\n"); - return (EIO); - } - - return (0); -} - -/********************************************************************* - * * Setup networking device structure and register an interface. * **********************************************************************/ static void ixgbe_setup_interface(device_t dev, struct adapter *adapter) { - struct ifnet *ifp; struct ixgbe_hw *hw = &adapter->hw; + struct ifnet *ifp; + INIT_DEBUGOUT("ixgbe_setup_interface: begin"); ifp = adapter->ifp = if_alloc(IFT_ETHER); @@ -2522,17 +2524,12 @@ ixgbe_setup_interface(device_t dev, stru ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4 | IFCAP_VLAN_HWCSUM; ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; - ifp->if_capabilities |= IFCAP_JUMBO_MTU | IFCAP_LRO; + ifp->if_capabilities |= IFCAP_JUMBO_MTU; + if (ixgbe_header_split) + ifp->if_capabilities |= IFCAP_LRO; ifp->if_capenable = ifp->if_capabilities; - 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 - ixgbe_setup_link_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, - TRUE, FALSE); - /* * Specify the media types supported by this adapter and register * callbacks to update media and link information @@ -2549,7 +2546,51 @@ ixgbe_setup_interface(device_t dev, stru } ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); + return; +} + +static void +ixgbe_config_link(struct adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 autoneg, err = 0; + bool sfp, negotiate; + + switch (hw->phy.type) { + case ixgbe_phy_sfp_avago: + case ixgbe_phy_sfp_ftl: + case ixgbe_phy_sfp_intel: + case ixgbe_phy_sfp_unknown: + case ixgbe_phy_tw_tyco: + case ixgbe_phy_tw_unknown: + sfp = TRUE; + default: + sfp = FALSE; + } + if (sfp) { + if (hw->phy.multispeed_fiber) { + hw->mac.ops.setup_sfp(hw); + taskqueue_enqueue(adapter->tq, &adapter->msf_task); + } else + taskqueue_enqueue(adapter->tq, &adapter->mod_task); + } else { + if (hw->mac.ops.check_link) + err = ixgbe_check_link(hw, &autoneg, + &adapter->link_up, FALSE); + if (err) + goto out; + autoneg = hw->phy.autoneg_advertised; + if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) + err = hw->mac.ops.get_link_capabilities(hw, + &autoneg, &negotiate); + if (err) + goto out; + if (hw->mac.ops.setup_link) + err = hw->mac.ops.setup_link(hw, autoneg, + negotiate, adapter->link_up); + } +out: return; } @@ -2833,8 +2874,8 @@ ixgbe_setup_transmit_ring(struct tx_ring bzero((void *)txr->tx_base, (sizeof(union ixgbe_adv_tx_desc)) * adapter->num_tx_desc); /* Reset indices */ - txr->next_avail_tx_desc = 0; - txr->next_tx_to_clean = 0; + txr->next_avail_desc = 0; + txr->next_to_clean = 0; /* Free any existing tx buffers. */ txbuf = txr->tx_buffers; @@ -2850,6 +2891,12 @@ ixgbe_setup_transmit_ring(struct tx_ring txbuf->eop_index = -1; } +#ifdef IXGBE_FDIR + /* Set the rate at which we sample packets */ + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + txr->atr_sample = atr_sample_rate; +#endif + /* Set number of descriptors available */ txr->tx_avail = adapter->num_tx_desc; @@ -2888,6 +2935,7 @@ ixgbe_initialize_transmit_units(struct a for (int i = 0; i < adapter->num_queues; i++, txr++) { u64 tdba = txr->txdma.dma_paddr; + u32 txctrl; IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (tdba & 0x00000000ffffffffULL)); @@ -2901,15 +2949,43 @@ ixgbe_initialize_transmit_units(struct a /* Setup Transmit Descriptor Cmd Settings */ txr->txd_cmd = IXGBE_TXD_CMD_IFCS; + txr->watchdog_check = FALSE; + + /* Disable Head Writeback */ + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + break; + case ixgbe_mac_82599EB: + default: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); + break; + } + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); + break; + case ixgbe_mac_82599EB: + default: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), txctrl); + break; + } - txr->watchdog_timer = 0; } if (hw->mac.type == ixgbe_mac_82599EB) { - u32 dmatxctl; + u32 dmatxctl, rttdcs; dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); dmatxctl |= IXGBE_DMATXCTL_TE; IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); + /* Disable arbiter to set MTQC */ + rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); + rttdcs |= IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); + IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); + rttdcs &= ~IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); } return; @@ -3009,7 +3085,7 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, u16 etype; u8 ipproto = 0; bool offload = TRUE; - int ctxd = txr->next_avail_tx_desc; + int ctxd = txr->next_avail_desc; u16 vtag = 0; @@ -3099,7 +3175,7 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, /* We've consumed the first desc, adjust counters */ if (++ctxd == adapter->num_tx_desc) ctxd = 0; - txr->next_avail_tx_desc = ctxd; + txr->next_avail_desc = ctxd; --txr->tx_avail; return (offload); @@ -3140,7 +3216,7 @@ ixgbe_tso_setup(struct tx_ring *txr, str if (mp->m_len < ehdrlen + sizeof(struct ip) + sizeof(struct tcphdr)) return FALSE; - ctxd = txr->next_avail_tx_desc; + ctxd = txr->next_avail_desc; tx_buffer = &txr->tx_buffers[ctxd]; TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912072130.nB7LUsX1066653>