summaryrefslogtreecommitdiffstats
path: root/sys/dev/em/if_em.c
diff options
context:
space:
mode:
authorjfv <jfv@FreeBSD.org>2008-04-02 22:00:36 +0000
committerjfv <jfv@FreeBSD.org>2008-04-02 22:00:36 +0000
commit9d514d84b92dc7bd134ec57eb7acb796a66a8dda (patch)
tree2cabe422ddeb41719a9799b5ef8082e237e16d78 /sys/dev/em/if_em.c
parent05341f326e97955d31e4bd671d2fabef9f105746 (diff)
downloadFreeBSD-src-9d514d84b92dc7bd134ec57eb7acb796a66a8dda.zip
FreeBSD-src-9d514d84b92dc7bd134ec57eb7acb796a66a8dda.tar.gz
This update primarily addresses the ability to have both the em
and the igb driver static in the kernel. But it also reflects some other bug fixes in my development stream at Intel. PR 122373 is also fixed in this code.
Diffstat (limited to 'sys/dev/em/if_em.c')
-rw-r--r--sys/dev/em/if_em.c304
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
+
OpenPOWER on IntegriCloud