From owner-svn-src-all@FreeBSD.ORG Tue Apr 14 00:23:14 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1E586106566C; Tue, 14 Apr 2009 00:23:14 +0000 (UTC) (envelope-from jfv@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0A6258FC16; Tue, 14 Apr 2009 00:23:14 +0000 (UTC) (envelope-from jfv@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n3E0NEEw088344; Tue, 14 Apr 2009 00:23:14 GMT (envelope-from jfv@svn.freebsd.org) Received: (from jfv@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n3E0NDiT088341; Tue, 14 Apr 2009 00:23:13 GMT (envelope-from jfv@svn.freebsd.org) Message-Id: <200904140023.n3E0NDiT088341@svn.freebsd.org> From: Jack F Vogel Date: Tue, 14 Apr 2009 00:23:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r191030 - stable/7/sys/dev/ixgbe X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 14 Apr 2009 00:23:14 -0000 Author: jfv Date: Tue Apr 14 00:23:13 2009 New Revision: 191030 URL: http://svn.freebsd.org/changeset/base/191030 Log: MFC ixgbe version 1.7.4 for FreeBSD 7.2, this is earlier than planned but coordinated with and approved by RE. Most important reason for this was so that FreeBSD 7.2 will have native support for the 82599 controller which is part of the Nehalem launch. The driver now does pluggable optics, multispeed fiber, and header split. I am adding this to the GENERIC kernel only in the amd64 architecture since its where I expect most use and others were untested. Enjoy! Approved by: re Added: stable/7/sys/dev/ixgbe/ixgbe_82599.c (contents, props changed) Modified: stable/7/sys/dev/ixgbe/LICENSE stable/7/sys/dev/ixgbe/ixgbe.c stable/7/sys/dev/ixgbe/ixgbe.h stable/7/sys/dev/ixgbe/ixgbe_82598.c stable/7/sys/dev/ixgbe/ixgbe_api.c stable/7/sys/dev/ixgbe/ixgbe_api.h stable/7/sys/dev/ixgbe/ixgbe_common.c stable/7/sys/dev/ixgbe/ixgbe_common.h stable/7/sys/dev/ixgbe/ixgbe_osdep.h stable/7/sys/dev/ixgbe/ixgbe_phy.c stable/7/sys/dev/ixgbe/ixgbe_phy.h stable/7/sys/dev/ixgbe/ixgbe_type.h Modified: stable/7/sys/dev/ixgbe/LICENSE ============================================================================== --- stable/7/sys/dev/ixgbe/LICENSE Mon Apr 13 23:50:44 2009 (r191029) +++ stable/7/sys/dev/ixgbe/LICENSE Tue Apr 14 00:23:13 2009 (r191030) @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2009, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Modified: stable/7/sys/dev/ixgbe/ixgbe.c ============================================================================== --- stable/7/sys/dev/ixgbe/ixgbe.c Mon Apr 13 23:50:44 2009 (r191029) +++ stable/7/sys/dev/ixgbe/ixgbe.c Tue Apr 14 00:23:13 2009 (r191030) @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2009, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ int ixgbe_display_debug_stat /********************************************************************* * Driver version *********************************************************************/ -char ixgbe_driver_version[] = "1.6.2"; +char ixgbe_driver_version[] = "1.7.4"; /********************************************************************* * PCI Device ID Table @@ -71,6 +71,8 @@ static ixgbe_vendor_info_t ixgbe_vendor_ {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_SFP, 0, 0, 0}, /* required last entry */ {0, 0, 0, 0, 0} }; @@ -104,7 +106,9 @@ static int ixgbe_allocate_pci_resou static int ixgbe_allocate_msix(struct adapter *); static int ixgbe_allocate_legacy(struct adapter *); static int ixgbe_allocate_queues(struct adapter *); +#if __FreeBSD_version >= 602105 static int ixgbe_setup_msix(struct adapter *); +#endif static void ixgbe_free_pci_resources(struct adapter *); static void ixgbe_local_timer(void *); static int ixgbe_hardware_init(struct adapter *); @@ -124,6 +128,7 @@ static void ixgbe_initialize_receive static void ixgbe_free_receive_structures(struct adapter *); static void ixgbe_free_receive_buffers(struct rx_ring *); +static void ixgbe_init_moderation(struct adapter *); static void ixgbe_enable_intr(struct adapter *); static void ixgbe_disable_intr(struct adapter *); static void ixgbe_update_stats_counters(struct adapter *); @@ -146,7 +151,7 @@ static int ixgbe_dma_malloc(struct adapt static void ixgbe_dma_free(struct adapter *, struct ixgbe_dma_alloc *); 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 int 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, s8); static void ixgbe_configure_ivars(struct adapter *); @@ -157,6 +162,12 @@ static void ixgbe_register_vlan(void *, static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); #endif +#ifdef IXGBE_TIMESYNC +/* Precision Time sync support */ +static int ixgbe_tsync_init(struct adapter *); +static void ixgbe_tsync_disable(struct adapter *); +#endif + static void ixgbe_update_aim(struct rx_ring *); /* Support for pluggable optic modules */ @@ -165,14 +176,19 @@ static bool ixgbe_sfp_probe(struct adapt /* Legacy (single vector interrupt handler */ static void ixgbe_legacy_irq(void *); +#if __FreeBSD_version >= 602105 /* The MSI/X Interrupt handlers */ static void ixgbe_msix_tx(void *); static void ixgbe_msix_rx(void *); static void ixgbe_msix_link(void *); +#endif -/* Legacy interrupts use deferred handlers */ -static void ixgbe_handle_tx(void *context, int pending); -static void ixgbe_handle_rx(void *context, int pending); +/* Deferred interrupt tasklets */ +static void ixgbe_handle_tx(void *, int); +static void ixgbe_handle_rx(void *, int); +static void ixgbe_handle_link(void *, int); +static void ixgbe_handle_msf(void *, int); +static void ixgbe_handle_mod(void *, int); /********************************************************************* @@ -213,8 +229,8 @@ 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_ave_latency = IXGBE_AVE_LATENCY; +TUNABLE_INT("hw.ixgbe.ave_latency", &ixgbe_ave_latency); static int ixgbe_bulk_latency = IXGBE_BULK_LATENCY; TUNABLE_INT("hw.ixgbe.bulk_latency", &ixgbe_bulk_latency); @@ -222,8 +238,8 @@ TUNABLE_INT("hw.ixgbe.bulk_latency", &ix 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 = ixgbe_fc_none; +/* Flow control setting, default to off */ +static int ixgbe_flow_control = ixgbe_fc_full; TUNABLE_INT("hw.ixgbe.flow_control", &ixgbe_flow_control); /* @@ -239,11 +255,16 @@ TUNABLE_INT("hw.ixgbe.enable_lro", &ixgb * MSIX should be the default for best performance, * but this allows it to be forced off for testing. */ +#if __FreeBSD_version >= 602105 static int ixgbe_enable_msix = 1; +#else +static int ixgbe_enable_msix = 0; +#endif TUNABLE_INT("hw.ixgbe.enable_msix", &ixgbe_enable_msix); /* * Enable RX Header Split + * WARNING: disable this if bridging or forwarding!! */ static int ixgbe_rx_hdr_split = 1; TUNABLE_INT("hw.ixgbe.rx_hdr_split", &ixgbe_rx_hdr_split); @@ -268,6 +289,13 @@ TUNABLE_INT("hw.ixgbe.rxd", &ixgbe_rxd); /* Total number of Interfaces - need for config sanity check */ static int ixgbe_total_ports; +/* +** The number of scatter-gather segments +** differs for 82598 and 82599, default to +** the former. +*/ +static int ixgbe_num_segs = IXGBE_82598_SCATTER; + /********************************************************************* * Device identification routine * @@ -312,6 +340,7 @@ ixgbe_probe(device_t dev) ixgbe_strings[ent->index], ixgbe_driver_version); device_set_desc_copy(dev, adapter_name); + ++ixgbe_total_ports; return (0); } ent++; @@ -333,6 +362,7 @@ static int ixgbe_attach(device_t dev) { struct adapter *adapter; + struct ixgbe_hw *hw; int error = 0; u16 pci_device_id; u32 ctrl_ext; @@ -342,37 +372,34 @@ ixgbe_attach(device_t dev) /* Allocate, clear, and link in our adapter structure */ adapter = device_get_softc(dev); adapter->dev = adapter->osdep.dev = dev; + hw = &adapter->hw; /* Core Lock Init*/ IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); - /* Keep track of number of ports and optics */ + /* Keep track of optics */ pci_device_id = pci_get_device(dev); switch (pci_device_id) { case IXGBE_DEV_ID_82598_CX4_DUAL_PORT : + case IXGBE_DEV_ID_82598EB_CX4 : 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_82598_DA_DUAL_PORT : case IXGBE_DEV_ID_82598AF_SINGLE_PORT : + case IXGBE_DEV_ID_82598AT : 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; + case IXGBE_DEV_ID_82599_SFP : + adapter->optics = IFM_10G_SR; + ixgbe_num_segs = IXGBE_82599_SCATTER; break; - case IXGBE_DEV_ID_82598AT : - ixgbe_total_ports += 1; - case IXGBE_DEV_ID_82598_DA_DUAL_PORT : - ixgbe_total_ports += 2; + case IXGBE_DEV_ID_82599_KX4 : + adapter->optics = IFM_10G_CX4; + ixgbe_num_segs = IXGBE_82599_SCATTER; default: break; } @@ -474,7 +501,7 @@ ixgbe_attach(device_t dev) } /* Initialize the shared code */ - error = ixgbe_init_shared_code(&adapter->hw); + error = ixgbe_init_shared_code(hw); if (error == IXGBE_ERR_SFP_NOT_PRESENT) { /* ** No optics in this port, set up @@ -525,11 +552,11 @@ ixgbe_attach(device_t dev) 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_READ_REG(hw, IXGBE_CTRL_EXT); ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); INIT_DEBUGOUT("ixgbe_attach: end"); return (0); @@ -590,6 +617,14 @@ ixgbe_detach(device_t dev) } } + /* Drain the Link queue */ + if (adapter->tq) { + taskqueue_drain(adapter->tq, &adapter->link_task); + taskqueue_drain(adapter->tq, &adapter->mod_task); + taskqueue_drain(adapter->tq, &adapter->msf_task); + taskqueue_free(adapter->tq); + } + /* let hardware know driver is unloading */ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; @@ -662,6 +697,19 @@ ixgbe_start_locked(struct tx_ring *txr, IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; + /* + * Force a cleanup if number of TX descriptors + * available is below the threshold. If it fails + * to get above, then abort transmit. + */ + if (txr->tx_avail <= IXGBE_TX_CLEANUP_THRESHOLD) { + ixgbe_txeof(txr); + /* Make sure things have improved */ + if (txr->tx_avail <= IXGBE_TX_OP_THRESHOLD) { + txr->no_tx_desc_avail++; + break; + } + } if (ixgbe_xmit(txr, &m_head)) { if (m_head == NULL) @@ -701,7 +749,8 @@ ixgbe_start(struct ifnet *ifp) txr = &adapter->tx_rings[queue]; if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXGBE_TX_LOCK(txr); + if (IXGBE_TX_TRYLOCK(txr) == 0) + return; ixgbe_start_locked(txr, ifp); IXGBE_TX_UNLOCK(txr); } @@ -803,6 +852,67 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c #endif break; } +#ifdef IXGBE_TIMESYNC + /* + ** IOCTL support for Precision Time (IEEE 1588) Support + */ + case IXGBE_TIMESYNC_READTS: + { + u32 rx_ctl, tx_ctl; + struct ixgbe_tsync_read *tdata; + + tdata = (struct ixgbe_tsync_read *) ifr->ifr_data; + + if (tdata->read_current_time) { + getnanotime(&tdata->system_time); + tdata->network_time = IXGBE_READ_REG(&adapter->hw, + IXGBE_SYSTIML); + tdata->network_time |= + (u64)IXGBE_READ_REG(&adapter->hw, + IXGBE_SYSTIMH ) << 32; + } + + rx_ctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TSYNCRXCTL); + tx_ctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TSYNCTXCTL); + + if (rx_ctl & 0x1) { + u32 tmp; + unsigned char *tmp_cp; + + tdata->rx_valid = 1; + tdata->rx_stamp = IXGBE_READ_REG(&adapter->hw, + IXGBE_RXSTMPL); + tdata->rx_stamp |= (u64)IXGBE_READ_REG(&adapter->hw, + IXGBE_RXSTMPH) << 32; + + tmp = IXGBE_READ_REG(&adapter->hw, IXGBE_RXSATRL); + tmp_cp = (unsigned char *) &tmp; + tdata->srcid[0] = tmp_cp[0]; + tdata->srcid[1] = tmp_cp[1]; + tdata->srcid[2] = tmp_cp[2]; + tdata->srcid[3] = tmp_cp[3]; + tmp = IXGBE_READ_REG(&adapter->hw, IXGBE_RXSATRH); + tmp_cp = (unsigned char *) &tmp; + tdata->srcid[4] = tmp_cp[0]; + tdata->srcid[5] = tmp_cp[1]; + tdata->seqid = tmp >> 16; + tdata->seqid = htons(tdata->seqid); + } else + tdata->rx_valid = 0; + + if (tx_ctl & 0x1) { + tdata->tx_valid = 1; + tdata->tx_stamp = IXGBE_READ_REG(&adapter->hw, + IXGBE_TXSTMPL); + tdata->tx_stamp |= (u64) IXGBE_READ_REG(&adapter->hw, + IXGBE_TXSTMPH) << 32; + } else + tdata->tx_valid = 0; + + return (0); + } +#endif /* IXGBE_TIMESYNC */ + default: IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); error = ether_ioctl(ifp, command, data); @@ -905,13 +1015,12 @@ 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 k, txdctl, mhadd, gpie; u32 rxdctl, rxctrl; + int err; INIT_DEBUGOUT("ixgbe_init: begin"); @@ -951,13 +1060,6 @@ ixgbe_init_locked(struct adapter *adapte ixgbe_initialize_transmit_units(adapter); - /* TX irq moderation rate is fixed */ - for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_EITR(txr->msix), ixgbe_ave_latency); - txr->watchdog_timer = FALSE; - } - /* Setup Multicast table */ ixgbe_set_multi(adapter); @@ -980,23 +1082,21 @@ ixgbe_init_locked(struct adapter *adapte /* Configure RX settings */ ixgbe_initialize_receive_units(adapter); - /* RX moderation will be adapted over time, set default */ - for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_EITR(rxr->msix), ixgbe_low_latency); - } - - /* Set Link moderation */ - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_EITR(adapter->linkvec), IXGBE_LINK_ITR); + /* Configure Interrupt Moderation */ + ixgbe_init_moderation(adapter); gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + gpie |= IXGBE_SDP1_GPIEN; + gpie |= IXGBE_SDP2_GPIEN; + } + /* Enable Fan Failure Interrupt */ - if (adapter->hw.phy.media_type == ixgbe_media_type_copper) + if (hw->device_id == IXGBE_DEV_ID_82598AT) gpie |= IXGBE_SDP1_GPIEN; - if (adapter->msix) { + if (adapter->msix > 2) { /* Enable Enhanced MSIX mode */ gpie |= IXGBE_GPIE_MSIX_MODE; gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | @@ -1058,9 +1158,40 @@ ixgbe_init_locked(struct adapter *adapte /* Set up MSI/X routing */ if (ixgbe_enable_msix) ixgbe_configure_ivars(adapter); + else { /* Simple settings for Legacy/MSI */ + ixgbe_set_ivar(adapter, 0, 0, 0); + ixgbe_set_ivar(adapter, 0, 0, 1); + } ixgbe_enable_intr(adapter); + /* + ** Check on any SFP devices that + ** need to be kick-started + */ + err = hw->phy.ops.identify(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + device_printf(dev, + "Unsupported SFP+ module type was detected.\n"); + 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); + + +#ifdef IXGBE_TIMESYNC + /* Initialize IEEE 1588 support */ + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + ixgbe_tsync_init(adapter); +#endif + /* Now inform the stack we're ready */ ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; @@ -1081,7 +1212,7 @@ ixgbe_init(void *arg) /* -** MSIX Interrupt Handlers +** MSIX Interrupt Tasklets */ static void @@ -1136,7 +1267,8 @@ ixgbe_legacy_irq(void *arg) struct ixgbe_hw *hw = &adapter->hw; struct tx_ring *txr = adapter->tx_rings; struct rx_ring *rxr = adapter->rx_rings; - u32 reg_eicr; + bool more; + u32 reg_eicr, loop = MAX_LOOP; reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); @@ -1148,7 +1280,15 @@ ixgbe_legacy_irq(void *arg) if (ixgbe_rxeof(rxr, adapter->rx_process_limit)) taskqueue_enqueue(rxr->tq, &rxr->rx_task); - if (ixgbe_txeof(txr)) + + IXGBE_TX_LOCK(txr); + ++txr->tx_irq; + do { + more = ixgbe_txeof(txr); + } while (loop-- && more); + IXGBE_TX_UNLOCK(txr); + + if (more) taskqueue_enqueue(txr->tq, &txr->tx_task); /* Check for fan failure */ @@ -1160,20 +1300,27 @@ ixgbe_legacy_irq(void *arg) } /* Link status change */ - if (reg_eicr & IXGBE_EICR_LSC) + if (reg_eicr & IXGBE_EICR_LSC) { + ixgbe_check_link(&adapter->hw, + &adapter->link_speed, &adapter->link_up, 0); ixgbe_update_link_status(adapter); + } + + /* Update interrupt rate */ + if (ixgbe_enable_aim == TRUE) + ixgbe_update_aim(rxr); ixgbe_enable_intr(adapter); return; } +#if __FreeBSD_version >= 602105 /********************************************************************* * * MSI TX Interrupt Service routine * **********************************************************************/ - void ixgbe_msix_tx(void *arg) { @@ -1181,6 +1328,8 @@ ixgbe_msix_tx(void *arg) struct adapter *adapter = txr->adapter; bool more; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, txr->eims); + IXGBE_TX_LOCK(txr); ++txr->tx_irq; more = ixgbe_txeof(txr); @@ -1198,7 +1347,6 @@ ixgbe_msix_tx(void *arg) * MSIX RX Interrupt Service routine * **********************************************************************/ - static void ixgbe_msix_rx(void *arg) { @@ -1206,18 +1354,72 @@ ixgbe_msix_rx(void *arg) struct adapter *adapter = rxr->adapter; bool more; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->eims); + ++rxr->rx_irq; - more = ixgbe_rxeof(rxr, -1); + more = ixgbe_rxeof(rxr, adapter->rx_process_limit); + + /* Update interrupt rate */ + if (ixgbe_enable_aim == TRUE) + ixgbe_update_aim(rxr); + 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; } + +static void +ixgbe_msix_link(void *arg) +{ + struct adapter *adapter = arg; + struct ixgbe_hw *hw = &adapter->hw; + u32 reg_eicr; + + ++adapter->link_irq; + + /* First get the cause */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, IXGBE_EIMS_OTHER); + reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); + /* Clear with write */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); + + /* Link status change */ + if (reg_eicr & IXGBE_EICR_LSC) + taskqueue_enqueue(adapter->tq, &adapter->link_task); + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + 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); + } + 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); + } else if (reg_eicr & IXGBE_EICR_GPI_SDP2) { + /* Clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); + taskqueue_enqueue(adapter->tq, &adapter->mod_task); + } + } + + /* Check for fan failure */ + if ((hw->device_id == IXGBE_DEV_ID_82598AT) && + (reg_eicr & IXGBE_EICR_GPI_SDP1)) { + device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " + "REPLACE IMMEDIATELY!!\n"); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); + } + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + return; +} +#endif /* FreeBSD_version >= 602105 */ + /* ** Routine to do adjust the RX EITR value based on traffic, ** its a simple three state model, but seems to help. @@ -1267,33 +1469,36 @@ ixgbe_update_aim(struct rx_ring *rxr) return; } - static void -ixgbe_msix_link(void *arg) +ixgbe_init_moderation(struct adapter *adapter) { - struct adapter *adapter = arg; - struct ixgbe_hw *hw = &adapter->hw; - u32 reg_eicr; - - ++adapter->link_irq; + struct rx_ring *rxr = adapter->rx_rings; + struct tx_ring *txr = adapter->tx_rings; - reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + /* Single interrupt - MSI or Legacy? */ + if (adapter->msix < 2) { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(0), 100); + return; + } - if (reg_eicr & IXGBE_EICR_LSC) - ixgbe_update_link_status(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; + } - /* 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(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1); + /* 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); } - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); - return; -} + /* Set Link moderation */ + IXGBE_WRITE_REG(&adapter->hw, + IXGBE_EITR(adapter->linkvec), IXGBE_LINK_ITR); +} /********************************************************************* * @@ -1382,12 +1587,12 @@ static int ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) { struct adapter *adapter = txr->adapter; - u32 olinfo_status = 0, cmd_type_len = 0; + u32 olinfo_status = 0, cmd_type_len; u32 paylen = 0; int i, j, error, nsegs; - int first, last = 0; + int first, last = 0, offload = 0; struct mbuf *m_head; - bus_dma_segment_t segs[IXGBE_MAX_SCATTER]; + bus_dma_segment_t segs[ixgbe_num_segs]; bus_dmamap_t map; struct ixgbe_tx_buf *txbuf, *txbuf_mapped; union ixgbe_adv_tx_desc *txd = NULL; @@ -1395,26 +1600,12 @@ ixgbe_xmit(struct tx_ring *txr, struct m m_head = *m_headp; /* Basic descriptor defines */ - cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA; - cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT; + cmd_type_len = (IXGBE_ADVTXD_DTYP_DATA | + IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT); if (m_head->m_flags & M_VLANTAG) cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; - /* - * Force a cleanup if number of TX descriptors - * available is below the threshold. If it fails - * to get above, then abort transmit. - */ - if (txr->tx_avail <= IXGBE_TX_CLEANUP_THRESHOLD) { - ixgbe_txeof(txr); - /* Make sure things have improved */ - if (txr->tx_avail <= IXGBE_TX_OP_THRESHOLD) { - txr->no_tx_desc_avail++; - return (ENOBUFS); - } - } - /* * Important to capture the first descriptor * used because it will contain the index of @@ -1475,19 +1666,27 @@ ixgbe_xmit(struct tx_ring *txr, struct m m_head = *m_headp; /* - ** Set the appropriate offload context + ** Set up the appropriate offload context ** this becomes the first descriptor of ** a packet. */ - if (ixgbe_tso_setup(txr, m_head, &paylen)) { - cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; - olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; - olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; - olinfo_status |= paylen << IXGBE_ADVTXD_PAYLEN_SHIFT; - ++adapter->tso_tx; - } else if (ixgbe_tx_ctx_setup(txr, m_head)) + if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { + if (ixgbe_tso_setup(txr, m_head, &paylen)) { + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; - + olinfo_status |= paylen << IXGBE_ADVTXD_PAYLEN_SHIFT; + ++adapter->tso_tx; + } else + return (ENXIO); + } else /* Offloads other than TSO */ + offload = ixgbe_tx_ctx_setup(txr, m_head); + if (offload == TRUE) + olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; +#ifdef IXGBE_TIMESYNC + if (offload == IXGBE_TIMESTAMP) + cmd_type_len |= IXGBE_ADVTXD_TSTAMP; +#endif /* Record payload length */ if (paylen == 0) olinfo_status |= m_head->m_pkthdr.len << @@ -1513,6 +1712,7 @@ ixgbe_xmit(struct tx_ring *txr, struct m i = 0; txbuf->m_head = NULL; + txbuf->eop_index = -1; } txd->read.cmd_type_len |= @@ -1526,6 +1726,7 @@ ixgbe_xmit(struct tx_ring *txr, struct m /* Set the index of the descriptor that will be marked done */ txbuf = &txr->tx_buffers[first]; + txbuf->eop_index = last; bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); @@ -1685,17 +1886,20 @@ out: callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); } +/* +** Note: this routine updates the OS on the link state +** the real check of the hardware only happens with +** a link interrupt. +*/ static void ixgbe_update_link_status(struct adapter *adapter) { - boolean_t link_up = FALSE; struct ifnet *ifp = adapter->ifp; struct tx_ring *txr = adapter->tx_rings; device_t dev = adapter->dev; - ixgbe_check_link(&adapter->hw, &adapter->link_speed, &link_up, 0); - if (link_up){ + if (adapter->link_up){ if (adapter->link_active == FALSE) { if (bootverbose) device_printf(dev,"Link is up %d Gbps %s \n", @@ -1720,7 +1924,6 @@ ixgbe_update_link_status(struct adapter } - /********************************************************************* * * This routine disables all traffic on the adapter by issuing a @@ -1743,6 +1946,11 @@ ixgbe_stop(void *arg) /* Tell the stack that the interface is no longer active */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); +#ifdef IXGBE_TIMESYNC + /* Disable IEEE 1588 support */ + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + ixgbe_tsync_disable(adapter); +#endif ixgbe_reset_hw(&adapter->hw); adapter->hw.adapter_stopped = FALSE; ixgbe_stop_adapter(&adapter->hw); @@ -1817,8 +2025,13 @@ ixgbe_allocate_legacy(struct adapter *ad device_get_nameunit(adapter->dev)); taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq", device_get_nameunit(adapter->dev)); + if ((error = bus_setup_intr(dev, adapter->res[0], +#if __FreeBSD_version >= 700000 INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, +#else + INTR_TYPE_NET | INTR_MPSAFE, ixgbe_legacy_irq, +#endif adapter, &adapter->tag[0])) != 0) { device_printf(dev, "Failed to register fast interrupt " "handler: %d\n", error); @@ -1833,6 +2046,7 @@ ixgbe_allocate_legacy(struct adapter *ad } +#if __FreeBSD_version >= 602105 /********************************************************************* * * Setup MSIX Interrupt resources and handlers @@ -1859,7 +2073,10 @@ ixgbe_allocate_msix(struct adapter *adap } /* Set the handler function */ error = bus_setup_intr(dev, adapter->res[vector], - INTR_TYPE_NET | INTR_MPSAFE, NULL, + INTR_TYPE_NET | INTR_MPSAFE, +#if __FreeBSD_version > 700000 + NULL, +#endif ixgbe_msix_tx, txr, &adapter->tag[vector]); if (error) { adapter->res[vector] = NULL; @@ -1867,7 +2084,7 @@ ixgbe_allocate_msix(struct adapter *adap return (error); } txr->msix = vector; - txr->eims = IXGBE_IVAR_TX_QUEUE(vector); + txr->eims = 1 << 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); @@ -1888,15 +2105,18 @@ ixgbe_allocate_msix(struct adapter *adap } /* Set the handler function */ error = bus_setup_intr(dev, adapter->res[vector], - INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_msix_rx, - rxr, &adapter->tag[vector]); + INTR_TYPE_NET | INTR_MPSAFE, +#if __FreeBSD_version > 700000 + NULL, +#endif + ixgbe_msix_rx, rxr, &adapter->tag[vector]); if (error) { adapter->res[vector] = NULL; device_printf(dev, "Failed to register RX handler"); return (error); } rxr->msix = vector; - rxr->eims = IXGBE_IVAR_RX_QUEUE(vector); + rxr->eims = 1 << vector; /* used in local timer */ adapter->rx_mask |= rxr->eims; TASK_INIT(&rxr->rx_task, 0, ixgbe_handle_rx, rxr); @@ -1916,19 +2136,37 @@ ixgbe_allocate_msix(struct adapter *adap } /* Set the link handler function */ error = bus_setup_intr(dev, adapter->res[vector], - INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_msix_link, - adapter, &adapter->tag[vector]); + INTR_TYPE_NET | INTR_MPSAFE, +#if __FreeBSD_version > 700000 + NULL, +#endif + ixgbe_msix_link, adapter, &adapter->tag[vector]); if (error) { adapter->res[vector] = NULL; device_printf(dev, "Failed to register LINK handler"); return (error); } adapter->linkvec = vector; + /* Tasklets for Link, SFP and Multispeed Fiber */ + 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); + adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, + taskqueue_thread_enqueue, &adapter->tq); + taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", + device_get_nameunit(adapter->dev)); return (0); } +#else /* Freebsd 6.1/2 */ +static int +ixgbe_allocate_msix(struct adapter *adapter) +{ + return (1); +} +#endif - +#if __FreeBSD_version >= 602105 /* * Setup Either MSI/X or MSI */ @@ -1996,6 +2234,7 @@ msi: device_printf(adapter->dev,"Using MSI interrupt\n"); return (msgs); } +#endif /* FreeBSD_version >= 602105 */ static int ixgbe_allocate_pci_resources(struct adapter *adapter) @@ -2031,9 +2270,10 @@ ixgbe_allocate_pci_resources(struct adap adapter->num_tx_queues = 1; adapter->num_rx_queues = 1; +#if __FreeBSD_version >= 602105 /* Now setup MSI or MSI/X */ adapter->msix = ixgbe_setup_msix(adapter); - +#endif adapter->hw.back = &adapter->osdep; return (0); } @@ -2051,7 +2291,10 @@ ixgbe_free_pci_resources(struct adapter if (adapter->msix == 0) adapter->msix = 1; - rid = PCIR_BAR(MSIX_82598_BAR); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + rid = PCIR_BAR(MSIX_82598_BAR); + else + rid = PCIR_BAR(MSIX_82599_BAR); /* * First release all the interrupt resources: @@ -2071,12 +2314,14 @@ ixgbe_free_pci_resources(struct adapter } } +#if __FreeBSD_version >= 602105 if (adapter->msix) pci_release_msi(dev); if (adapter->msix_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, rid, adapter->msix_mem); +#endif if (adapter->pci_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, @@ -2215,7 +2460,7 @@ ixgbe_dma_malloc(struct adapter *adapter int r; r = bus_dma_tag_create(NULL, /* parent */ - PAGE_SIZE, 0, /* alignment, bounds */ + 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ @@ -2415,12 +2660,12 @@ ixgbe_allocate_transmit_buffers(struct t * Setup DMA descriptor areas. */ if ((error = bus_dma_tag_create(NULL, /* parent */ - PAGE_SIZE, 0, /* alignment, bounds */ + 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ IXGBE_TSO_SIZE, /* maxsize */ - IXGBE_MAX_SCATTER, /* nsegments */ + ixgbe_num_segs, /* nsegments */ PAGE_SIZE, /* maxsegsize */ 0, /* flags */ NULL, /* lockfunc */ @@ -2484,6 +2729,8 @@ ixgbe_setup_transmit_ring(struct tx_ring m_freem(txbuf->m_head); txbuf->m_head = NULL; } + /* Clear the EOP index */ + txbuf->eop_index = -1; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***