diff options
Diffstat (limited to 'sys/dev/em/if_em.c')
-rw-r--r-- | sys/dev/em/if_em.c | 304 |
1 files changed, 124 insertions, 180 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index c5f412c..584b4be 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -1,36 +1,36 @@ -/************************************************************************** - -Copyright (c) 2001-2008, Intel Corporation -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of the Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -***************************************************************************/ -/* $FreeBSD$ */ +/****************************************************************************** + + Copyright (c) 2001-2008, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/*$FreeBSD$*/ #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_device_polling.h" @@ -86,7 +86,7 @@ int em_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char em_driver_version[] = "6.8.4"; +char em_driver_version[] = "6.8.8"; /********************************************************************* @@ -187,7 +187,6 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, E1000_DEV_ID_ICH9_IFE, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH9_IFE_GT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH9_IFE_G, PCI_ANY_ID, PCI_ANY_ID, 0}, - /* required last entry */ { 0, 0, 0, 0, 0} }; @@ -285,7 +284,8 @@ static void em_get_hw_control(struct adapter *); static void em_release_hw_control(struct adapter *); static void em_enable_wakeup(device_t); -#ifndef EM_FAST_IRQ + +#ifdef EM_LEGACY_IRQ static void em_intr(void *); #else /* FAST IRQ */ #if __FreeBSD_version < 700000 @@ -302,7 +302,7 @@ static void em_handle_rxtx(void *context, int pending); static void em_handle_rx(void *context, int pending); static void em_handle_tx(void *context, int pending); static void em_handle_link(void *context, int pending); -#endif /* EM_FAST_IRQ */ +#endif /* EM_LEGACY_IRQ */ #ifdef DEVICE_POLLING static poll_handler_t em_poll; @@ -361,7 +361,7 @@ TUNABLE_INT("hw.em.rxd", &em_rxd); TUNABLE_INT("hw.em.txd", &em_txd); TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down); -#ifdef EM_FAST_IRQ +#ifndef EM_LEGACY_IRQ /* How many packets rxeof tries to clean at a time */ static int em_rx_process_limit = 100; TUNABLE_INT("hw.em.rx_process_limit", &em_rx_process_limit); @@ -523,7 +523,7 @@ em_attach(device_t dev) em_tx_abs_int_delay_dflt); } -#ifdef EM_FAST_IRQ +#ifndef EM_LEGACY_IRQ /* Sysctls for limiting the amount of work done in the taskqueue */ em_add_rx_process_limit(adapter, "rx_processing_limit", "max number of rx packets to process", &adapter->rx_process_limit, @@ -1180,6 +1180,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) break; } + default: error = ether_ioctl(ifp, command, data); break; @@ -1211,8 +1212,11 @@ em_watchdog(struct adapter *adapter) ** Finally, anytime all descriptors are clean the timer is ** set to 0. */ - if ((adapter->watchdog_timer == 0) || (--adapter->watchdog_timer)) + EM_TX_LOCK(adapter); + if ((adapter->watchdog_timer == 0) || (--adapter->watchdog_timer)) { + EM_TX_UNLOCK(adapter); return; + } /* If we are in this routine because of pause frames, then * don't reset the hardware. @@ -1220,6 +1224,7 @@ em_watchdog(struct adapter *adapter) if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_TXOFF) { adapter->watchdog_timer = EM_TX_TIMEOUT; + EM_TX_UNLOCK(adapter); return; } @@ -1378,6 +1383,7 @@ em_init_locked(struct adapter *adapter) callout_reset(&adapter->timer, hz, em_local_timer, adapter); e1000_clear_hw_cntrs_base_generic(&adapter->hw); + #ifdef DEVICE_POLLING /* * Only enable interrupts if we are not polling, make sure @@ -1389,6 +1395,7 @@ em_init_locked(struct adapter *adapter) #endif /* DEVICE_POLLING */ em_enable_intr(adapter); + /* Don't reset the phy next time init gets called */ adapter->hw.phy.reset_disable = TRUE; } @@ -1427,7 +1434,6 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { callout_stop(&adapter->timer); adapter->hw.mac.get_link_status = 1; - e1000_check_for_link(&adapter->hw); em_update_link_status(adapter); callout_reset(&adapter->timer, hz, em_local_timer, adapter); @@ -1445,7 +1451,7 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) } #endif /* DEVICE_POLLING */ -#ifndef EM_FAST_IRQ +#ifdef EM_LEGACY_IRQ /********************************************************************* * * Legacy Interrupt Service routine @@ -1496,7 +1502,6 @@ em_intr(void *arg) if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { callout_stop(&adapter->timer); adapter->hw.mac.get_link_status = 1; - e1000_check_for_link(&adapter->hw); em_update_link_status(adapter); /* Deal with TX cruft when link lost */ em_tx_purge(adapter); @@ -1524,15 +1529,11 @@ em_handle_link(void *context, int pending) ifp = adapter->ifp; - EM_CORE_LOCK(adapter); - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - EM_CORE_UNLOCK(adapter); + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) return; - } + EM_CORE_LOCK(adapter); callout_stop(&adapter->timer); - adapter->hw.mac.get_link_status = 1; - e1000_check_for_link(&adapter->hw); em_update_link_status(adapter); /* Deal with TX cruft when link lost */ em_tx_purge(adapter); @@ -1540,12 +1541,6 @@ em_handle_link(void *context, int pending) EM_CORE_UNLOCK(adapter); } -#if __FreeBSD_version >= 700000 -#if !defined(NET_LOCK_GIANT) -#define NET_LOCK_GIANT() -#define NET_UNLOCK_GIANT() -#endif -#endif /* Combined RX/TX handler, used by Legacy and MSI */ static void @@ -1554,7 +1549,6 @@ em_handle_rxtx(void *context, int pending) struct adapter *adapter = context; struct ifnet *ifp = adapter->ifp; - NET_LOCK_GIANT(); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { if (em_rxeof(adapter, adapter->rx_process_limit) != 0) @@ -1651,8 +1645,10 @@ em_irq_fast(void *arg) taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); /* Link status change */ - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) + if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + adapter->hw.mac.get_link_status = 1; taskqueue_enqueue(taskqueue_fast, &adapter->link_task); + } if (reg_icr & E1000_ICR_RXO) adapter->rx_overruns++; @@ -1748,7 +1744,6 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) INIT_DEBUGOUT("em_media_status: begin"); EM_CORE_LOCK(adapter); - e1000_check_for_link(&adapter->hw); em_update_link_status(adapter); ifmr->ifm_status = IFM_AVALID; @@ -1993,7 +1988,12 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) tso_desc = TRUE; } else #endif - if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) + /* + ** Timesync needs to check the packet header + ** so call checksum code to do so, but don't + ** penalize the code if not defined. + */ + if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) em_transmit_checksum_setup(adapter, m_head, &txd_upper, &txd_lower); @@ -2378,7 +2378,6 @@ em_local_timer(void *arg) EM_CORE_LOCK_ASSERT(adapter); - e1000_check_for_link(&adapter->hw); em_update_link_status(adapter); em_update_stats_counters(adapter); @@ -2404,45 +2403,66 @@ em_local_timer(void *arg) static void em_update_link_status(struct adapter *adapter) { + struct e1000_hw *hw = &adapter->hw; struct ifnet *ifp = adapter->ifp; device_t dev = adapter->dev; + u32 link_check = 0; + + /* Get the cached link value or read phy for real */ + switch (hw->phy.media_type) { + case e1000_media_type_copper: + if (hw->mac.get_link_status) { + /* Do the work to read phy */ + e1000_check_for_link(hw); + link_check = !hw->mac.get_link_status; + } else + link_check = TRUE; + break; + case e1000_media_type_fiber: + e1000_check_for_link(hw); + link_check = (E1000_READ_REG(hw, E1000_STATUS) & + E1000_STATUS_LU); + break; + case e1000_media_type_internal_serdes: + e1000_check_for_link(hw); + link_check = adapter->hw.mac.serdes_has_link; + break; + default: + case e1000_media_type_unknown: + break; + } - if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & - E1000_STATUS_LU) { - if (adapter->link_active == 0) { - e1000_get_speed_and_duplex(&adapter->hw, - &adapter->link_speed, &adapter->link_duplex); - /* Check if we must disable SPEED_MODE bit on PCI-E */ - if ((adapter->link_speed != SPEED_1000) && - ((adapter->hw.mac.type == e1000_82571) || - (adapter->hw.mac.type == e1000_82572))) { - int tarc0; - - tarc0 = E1000_READ_REG(&adapter->hw, - E1000_TARC(0)); - tarc0 &= ~SPEED_MODE_BIT; - E1000_WRITE_REG(&adapter->hw, - E1000_TARC(0), tarc0); - } - if (bootverbose) - device_printf(dev, "Link is up %d Mbps %s\n", - adapter->link_speed, - ((adapter->link_duplex == FULL_DUPLEX) ? - "Full Duplex" : "Half Duplex")); - adapter->link_active = 1; - adapter->smartspeed = 0; - ifp->if_baudrate = adapter->link_speed * 1000000; - if_link_state_change(ifp, LINK_STATE_UP); - } - } else { - if (adapter->link_active == 1) { - ifp->if_baudrate = adapter->link_speed = 0; - adapter->link_duplex = 0; - if (bootverbose) - device_printf(dev, "Link is Down\n"); - adapter->link_active = 0; - if_link_state_change(ifp, LINK_STATE_DOWN); + /* Now check for a transition */ + if (link_check && (adapter->link_active == 0)) { + e1000_get_speed_and_duplex(hw, &adapter->link_speed, + &adapter->link_duplex); + /* Check if we must disable SPEED_MODE bit on PCI-E */ + if ((adapter->link_speed != SPEED_1000) && + ((hw->mac.type == e1000_82571) || + (hw->mac.type == e1000_82572))) { + int tarc0; + tarc0 = E1000_READ_REG(hw, E1000_TARC(0)); + tarc0 &= ~SPEED_MODE_BIT; + E1000_WRITE_REG(hw, E1000_TARC(0), tarc0); } + if (bootverbose) + device_printf(dev, "Link is up %d Mbps %s\n", + adapter->link_speed, + ((adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex")); + adapter->link_active = 1; + adapter->smartspeed = 0; + ifp->if_baudrate = adapter->link_speed * 1000000; + if_link_state_change(ifp, LINK_STATE_UP); + } else if (!link_check && (adapter->link_active == 1)) { + ifp->if_baudrate = adapter->link_speed = 0; + adapter->link_duplex = 0; + if (bootverbose) + device_printf(dev, "Link is Down\n"); + adapter->link_active = 0; + /* Link down, disable watchdog */ + adapter->watchdog_timer = FALSE; + if_link_state_change(ifp, LINK_STATE_DOWN); } } @@ -2473,6 +2493,7 @@ em_stop(void *arg) /* Tell the stack that the interface is no longer active */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + e1000_reset_hw(&adapter->hw); if (adapter->hw.mac.type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); @@ -2616,7 +2637,7 @@ em_allocate_legacy(struct adapter *adapter) return (ENXIO); } -#ifndef EM_FAST_IRQ +#ifdef EM_LEGACY_IRQ /* We do Legacy setup */ if ((error = bus_setup_intr(dev, adapter->res[0], #if __FreeBSD_version > 700000 @@ -2654,7 +2675,7 @@ em_allocate_legacy(struct adapter *adapter) adapter->tq = NULL; return (error); } -#endif /* EM_FAST_IRQ */ +#endif /* EM_LEGACY_IRQ */ return (0); } @@ -3383,9 +3404,6 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, tx_buffer = &adapter->tx_buffer_area[curr_txd]; TXD = (struct e1000_context_desc *) &adapter->tx_desc_base[curr_txd]; - *txd_lower = E1000_TXD_CMD_DEXT | /* Extended descr type */ - E1000_TXD_DTYP_D; /* Data descr */ - /* * Determine where frame payload starts. * Jump over vlan headers if already present, @@ -3488,6 +3506,8 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, break; } + *txd_lower = E1000_TXD_CMD_DEXT | /* Extended descr type */ + E1000_TXD_DTYP_D; /* Data descr */ TXD->tcp_seg_setup.data = htole32(0); TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd); @@ -3651,6 +3671,7 @@ em_tso_setup(struct adapter *adapter, struct mbuf *mp, u32 *txd_upper, return TRUE; } + #endif /* __FreeBSD_version >= 700000 */ /********************************************************************** @@ -4274,7 +4295,7 @@ discard: i = 0; if (m != NULL) { adapter->next_rx_desc_to_check = i; -#ifndef EM_FAST_IRQ +#ifdef EM_LEGACY_IRQ EM_CORE_UNLOCK(adapter); (*ifp->if_input)(ifp, m); EM_CORE_LOCK(adapter); @@ -4557,84 +4578,6 @@ em_is_valid_ether_addr(u8 *addr) } /* - * NOTE: the following routines using the e1000 - * naming style are provided to the shared - * code which expects that rather than 'em' - */ - -void -e1000_write_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - pci_write_config(((struct e1000_osdep *)hw->back)->dev, reg, *value, 2); -} - -void -e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - *value = pci_read_config(((struct e1000_osdep *)hw->back)->dev, reg, 2); -} - -void -e1000_pci_set_mwi(struct e1000_hw *hw) -{ - pci_write_config(((struct e1000_osdep *)hw->back)->dev, PCIR_COMMAND, - (hw->bus.pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2); -} - -void -e1000_pci_clear_mwi(struct e1000_hw *hw) -{ - pci_write_config(((struct e1000_osdep *)hw->back)->dev, PCIR_COMMAND, - (hw->bus.pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2); -} - -/* - * Read the PCI Express capabilities - */ -int -e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - int error = E1000_SUCCESS; - u16 cap_off; - - switch (hw->mac.type) { - - case e1000_82571: - case e1000_82572: - case e1000_82573: - case e1000_80003es2lan: - cap_off = 0xE0; - e1000_read_pci_cfg(hw, cap_off + reg, value); - break; - default: - error = ~E1000_NOT_IMPLEMENTED; - break; - } - - return (error); -} - -int -e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size) -{ - int32_t error = 0; - - hw->dev_spec = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); - if (hw->dev_spec == NULL) - error = ENOMEM; - - return (error); -} - -void -e1000_free_dev_spec_struct(struct e1000_hw *hw) -{ - if (hw->dev_spec != NULL) - free(hw->dev_spec, M_DEVBUF); - return; -} - -/* * Enable PCI Wake On Lan capability */ void @@ -5054,7 +4997,7 @@ em_add_int_delay_sysctl(struct adapter *adapter, const char *name, info, 0, em_sysctl_int_delay, "I", description); } -#ifdef EM_FAST_IRQ +#ifndef EM_LEGACY_IRQ static void em_add_rx_process_limit(struct adapter *adapter, const char *name, const char *description, int *limit, int value) @@ -5065,3 +5008,4 @@ em_add_rx_process_limit(struct adapter *adapter, const char *name, OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description); } #endif + |