summaryrefslogtreecommitdiffstats
path: root/sys/dev/em/if_em.c
diff options
context:
space:
mode:
authorjfv <jfv@FreeBSD.org>2008-04-25 21:19:41 +0000
committerjfv <jfv@FreeBSD.org>2008-04-25 21:19:41 +0000
commitb504776a58ec435e17a4e3c2dbb82849593dc2b0 (patch)
treeba89bf27aac0358813a723b89ba73f0917631cec /sys/dev/em/if_em.c
parent69e5e2aed2db0e4c5f9b33170d1b901503485a2b (diff)
downloadFreeBSD-src-b504776a58ec435e17a4e3c2dbb82849593dc2b0.zip
FreeBSD-src-b504776a58ec435e17a4e3c2dbb82849593dc2b0.tar.gz
This delta has a few important items:
PR 122839 is fixed in both em and in igb Second, the issue on building modules since the static kernel build changes is now resolved. I was not able to get the fancier directory hierarchy working, but this works, both em and igb build as modules now. Third, there is now support in em for two new NICs, Hartwell (or 82574) is a low cost PCIE dual port adapter that has MSIX, for this release it uses 3 vectors only, RX, TX, and LINK. In the next release I will add a second TX and RX queue. Also, there is support here for ICH10, the followon to ICH9. Both of these are early releases, general availability will follow soon. Fourth: On Hartwell and ICH10 we now have IEEE 1588 PTP support, I have implemented this in a provisional way so that early adopters may try and comment on the functionality. The IOCTL structure may change. This feature is off by default, you need to edit the Makefile and add the EM_TIMESYNC define to get the code. Enjoy all!!
Diffstat (limited to 'sys/dev/em/if_em.c')
-rw-r--r--sys/dev/em/if_em.c470
1 files changed, 376 insertions, 94 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index 584b4be..506d2de 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -50,6 +50,10 @@
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
+#ifdef EM_TIMESYNC
+#include <sys/ioccom.h>
+#include <sys/time.h>
+#endif
#include <machine/bus.h>
#include <machine/resource.h>
@@ -76,6 +80,7 @@
#include <dev/pci/pcireg.h>
#include "e1000_api.h"
+#include "e1000_82571.h" /* For Hartwell */
#include "if_em.h"
/*********************************************************************
@@ -86,7 +91,7 @@ int em_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char em_driver_version[] = "6.8.8";
+char em_driver_version[] = "6.9.0";
/*********************************************************************
@@ -187,6 +192,9 @@ 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},
+ { 0x8086, E1000_DEV_ID_82574L, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_ICH10_D_BM_LM, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_ICH10_D_BM_LF, PCI_ANY_ID, PCI_ANY_ID, 0},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
@@ -284,6 +292,11 @@ static void em_get_hw_control(struct adapter *);
static void em_release_hw_control(struct adapter *);
static void em_enable_wakeup(device_t);
+#ifdef EM_TIMESYNC
+/* Precision Time sync support */
+static int em_tsync_init(struct adapter *);
+static void em_tsync_disable(struct adapter *);
+#endif
#ifdef EM_LEGACY_IRQ
static void em_intr(void *);
@@ -293,9 +306,10 @@ static void em_irq_fast(void *);
#else
static int em_irq_fast(void *);
#endif
-static int em_tx_fast(void *);
-static int em_rx_fast(void *);
-static int em_link_fast(void *);
+/* MSIX handlers */
+static void em_msix_tx(void *);
+static void em_msix_rx(void *);
+static void em_msix_link(void *);
static void em_add_rx_process_limit(struct adapter *, const char *,
const char *, int *, int);
static void em_handle_rxtx(void *context, int pending);
@@ -352,6 +366,10 @@ static int em_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV);
static int em_rxd = EM_DEFAULT_RXD;
static int em_txd = EM_DEFAULT_TXD;
static int em_smart_pwr_down = FALSE;
+/* Controls whether promiscuous also shows bad packets */
+static int em_debug_sbp = FALSE;
+/* Local switch for MSI/MSIX */
+static int em_enable_msi = TRUE;
TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
@@ -360,6 +378,8 @@ TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt);
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);
+TUNABLE_INT("hw.em.sbp", &em_debug_sbp);
+TUNABLE_INT("hw.em.enable_msi", &em_enable_msi);
#ifndef EM_LEGACY_IRQ
/* How many packets rxeof tries to clean at a time */
@@ -445,6 +465,7 @@ em_attach(device_t dev)
adapter->dev = adapter->osdep.dev = dev;
EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
EM_TX_LOCK_INIT(adapter, device_get_nameunit(dev));
+ EM_RX_LOCK_INIT(adapter, device_get_nameunit(dev));
/* SYSCTL stuff */
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
@@ -477,6 +498,7 @@ em_attach(device_t dev)
** identified
*/
if ((adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) {
int rid = EM_BAR_TYPE_FLASH;
adapter->flash = bus_alloc_resource_any(dev,
@@ -770,6 +792,7 @@ err_tx_desc:
err_pci:
em_free_pci_resources(adapter);
EM_TX_LOCK_DESTROY(adapter);
+ EM_RX_LOCK_DESTROY(adapter);
EM_CORE_LOCK_DESTROY(adapter);
return (error);
@@ -818,6 +841,7 @@ em_detach(device_t dev)
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) &&
e1000_check_mng_mode(&adapter->hw))
em_release_hw_control(adapter);
@@ -856,6 +880,7 @@ em_detach(device_t dev)
}
EM_TX_LOCK_DESTROY(adapter);
+ EM_RX_LOCK_DESTROY(adapter);
EM_CORE_LOCK_DESTROY(adapter);
return (0);
@@ -891,6 +916,7 @@ em_suspend(device_t dev)
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) &&
e1000_check_mng_mode(&adapter->hw))
em_release_hw_control(adapter);
@@ -915,12 +941,8 @@ em_resume(device_t dev)
EM_CORE_LOCK(adapter);
em_init_locked(adapter);
em_init_manageability(adapter);
-
- if ((ifp->if_flags & IFF_UP) &&
- (ifp->if_drv_flags & IFF_DRV_RUNNING))
- em_start_locked(ifp);
-
EM_CORE_UNLOCK(adapter);
+ em_start(ifp);
return bus_generic_resume(dev);
}
@@ -1050,6 +1072,8 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case e1000_82571:
case e1000_82572:
case e1000_ich9lan:
+ case e1000_ich10lan:
+ case e1000_82574:
case e1000_80003es2lan: /* Limit Jumbo Frame size */
max_frame_size = 9234;
break;
@@ -1082,7 +1106,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if (ifp->if_flags & IFF_UP) {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
if ((ifp->if_flags ^ adapter->if_flags) &
- IFF_PROMISC) {
+ (IFF_PROMISC | IFF_ALLMULTI)) {
em_disable_promisc(adapter);
em_set_promisc(adapter);
}
@@ -1180,6 +1204,69 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
}
+#ifdef EM_TIMESYNC
+ /*
+ ** IOCTL support for Precision Time (IEEE 1588) Support
+ */
+ case EM_TIMESYNC_READTS:
+ {
+ u32 rx_ctl, tx_ctl;
+ struct em_tsync_read *tdata;
+
+ tdata = (struct em_tsync_read *) ifr->ifr_data;
+
+ IOCTL_DEBUGOUT("Reading Timestamp\n");
+
+ if (tdata->read_current_time) {
+ getnanotime(&tdata->system_time);
+ tdata->network_time = E1000_READ_REG(&adapter->hw, E1000_SYSTIML);
+ tdata->network_time |=
+ (u64)E1000_READ_REG(&adapter->hw, E1000_SYSTIMH ) << 32;
+ }
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+
+ IOCTL_DEBUGOUT1("RX_CTL value = %u\n", rx_ctl);
+ IOCTL_DEBUGOUT1("TX_CTL value = %u\n", tx_ctl);
+
+ if (rx_ctl & 0x1) {
+ IOCTL_DEBUGOUT("RX timestamp is valid\n");
+ u32 tmp;
+ unsigned char *tmp_cp;
+
+ tdata->rx_valid = 1;
+ tdata->rx_stamp = E1000_READ_REG(&adapter->hw, E1000_RXSTMPL);
+ tdata->rx_stamp |= (u64)E1000_READ_REG(&adapter->hw,
+ E1000_RXSTMPH) << 32;
+
+ tmp = E1000_READ_REG(&adapter->hw, E1000_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 = E1000_READ_REG(&adapter->hw, E1000_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) {
+ IOCTL_DEBUGOUT("TX timestamp is valid\n");
+ tdata->tx_valid = 1;
+ tdata->tx_stamp = E1000_READ_REG(&adapter->hw, E1000_TXSTMPL);
+ tdata->tx_stamp |= (u64) E1000_READ_REG(&adapter->hw,
+ E1000_TXSTMPH) << 32;
+ } else
+ tdata->tx_valid = 0;
+
+ return (0);
+ }
+#endif /* EM_TIMESYNC */
default:
error = ether_ioctl(ifp, command, data);
@@ -1294,7 +1381,11 @@ em_init_locked(struct adapter *adapter)
case e1000_82573: /* 82573: Total Packet Buffer is 32K */
pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */
break;
+ case e1000_82574:
+ pba = E1000_PBA_20K; /* 20K for Rx, 20K for Tx */
+ break;
case e1000_ich9lan:
+ case e1000_ich10lan:
#define E1000_PBA_10K 0x000A
pba = E1000_PBA_10K;
break;
@@ -1383,6 +1474,21 @@ em_init_locked(struct adapter *adapter)
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
e1000_clear_hw_cntrs_base_generic(&adapter->hw);
+ /* MSI/X configuration for 82574 */
+ if (adapter->hw.mac.type == e1000_82574) {
+ int tmp;
+ tmp = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
+ tmp |= E1000_CTRL_EXT_PBA_CLR;
+ E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, tmp);
+ /*
+ ** Set the IVAR - interrupt vector routing.
+ ** Each nibble represents a vector, high bit
+ ** is enable, other 3 bits are the MSIX table
+ ** entry, we map RXQ0 to 0, TXQ0 to 1, and
+ ** Link (other) to 2, hence the magic number.
+ */
+ E1000_WRITE_REG(&adapter->hw, E1000_IVAR, 0x800A0908);
+ }
#ifdef DEVICE_POLLING
/*
@@ -1395,6 +1501,12 @@ em_init_locked(struct adapter *adapter)
#endif /* DEVICE_POLLING */
em_enable_intr(adapter);
+#ifdef EM_TIMESYNC
+ /* Initializae IEEE 1588 Precision Time hardware */
+ if ((adapter->hw.mac.type == e1000_82574) ||
+ (adapter->hw.mac.type == e1000_ich10lan))
+ em_tsync_init(adapter);
+#endif
/* Don't reset the phy next time init gets called */
adapter->hw.phy.reset_disable = TRUE;
@@ -1439,9 +1551,10 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
em_local_timer, adapter);
}
}
- em_rxeof(adapter, count);
EM_CORE_UNLOCK(adapter);
+ em_rxeof(adapter, count);
+
EM_TX_LOCK(adapter);
em_txeof(adapter);
@@ -1462,17 +1575,14 @@ static void
em_intr(void *arg)
{
struct adapter *adapter = arg;
- struct ifnet *ifp;
+ struct ifnet *ifp = adapter->ifp;
u32 reg_icr;
- EM_CORE_LOCK(adapter);
- ifp = adapter->ifp;
- if (ifp->if_capenable & IFCAP_POLLING) {
- EM_CORE_UNLOCK(adapter);
+ if (ifp->if_capenable & IFCAP_POLLING)
return;
- }
+ EM_CORE_LOCK(adapter);
for (;;) {
reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
@@ -1491,12 +1601,14 @@ em_intr(void *arg)
if (reg_icr == 0xffffffff)
break;
+ EM_CORE_UNLOCK(adapter);
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
em_rxeof(adapter, -1);
EM_TX_LOCK(adapter);
em_txeof(adapter);
EM_TX_UNLOCK(adapter);
}
+ EM_CORE_LOCK(adapter);
/* Link status change */
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
@@ -1525,9 +1637,7 @@ static void
em_handle_link(void *context, int pending)
{
struct adapter *adapter = context;
- struct ifnet *ifp;
-
- ifp = adapter->ifp;
+ struct ifnet *ifp = adapter->ifp;
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
return;
@@ -1564,19 +1674,16 @@ em_handle_rxtx(void *context, int pending)
em_enable_intr(adapter);
}
-/* RX deferred handler: used with MSIX */
static void
em_handle_rx(void *context, int pending)
{
struct adapter *adapter = context;
struct ifnet *ifp = adapter->ifp;
- ++adapter->rx_irq;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
(em_rxeof(adapter, adapter->rx_process_limit) != 0))
taskqueue_enqueue(adapter->tq, &adapter->rx_task);
- em_enable_intr(adapter);
}
static void
@@ -1585,17 +1692,13 @@ em_handle_tx(void *context, int pending)
struct adapter *adapter = context;
struct ifnet *ifp = adapter->ifp;
- ++adapter->tx_irq;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
EM_TX_LOCK(adapter);
em_txeof(adapter);
-
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp);
EM_TX_UNLOCK(adapter);
}
-
- em_enable_intr(adapter);
}
/*********************************************************************
@@ -1657,52 +1760,50 @@ em_irq_fast(void *arg)
/*********************************************************************
*
- * MSIX TX Fast Interrupt Service routine
+ * MSIX Interrupt Service Routines
*
**********************************************************************/
+#define EM_MSIX_TX 0x00040000
+#define EM_MSIX_RX 0x00010000
+#define EM_MSIX_LINK 0x00100000
-static int
-em_tx_fast(void *arg)
+static void
+em_msix_tx(void *arg)
{
struct adapter *adapter = arg;
- u32 reg_icr;
-
- reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
- /*
- * Mask interrupts until the taskqueue is finished running. This is
- * cheap, just assume that it is needed. This also works around the
- * MSI message reordering errata on certain systems.
- */
- em_disable_intr(adapter);
- taskqueue_enqueue(adapter->tq, &adapter->tx_task);
+ struct ifnet *ifp = adapter->ifp;
- return FILTER_HANDLED;
+ ++adapter->tx_irq;
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ EM_TX_LOCK(adapter);
+ em_txeof(adapter);
+ EM_TX_UNLOCK(adapter);
+ taskqueue_enqueue(adapter->tq, &adapter->tx_task);
+ }
+ /* Reenable this interrupt */
+ E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_TX);
+ return;
}
/*********************************************************************
*
- * MSIX RX Fast Interrupt Service routine
+ * MSIX RX Interrupt Service routine
*
**********************************************************************/
-static int
-em_rx_fast(void *arg)
+static void
+em_msix_rx(void *arg)
{
struct adapter *adapter = arg;
- u32 reg_icr;
-
- reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
- /*
- * Mask interrupts until the taskqueue is finished running. This is
- * cheap, just assume that it is needed. This also works around the
- * MSI message reordering errata on certain systems.
- */
- em_disable_intr(adapter);
- taskqueue_enqueue(adapter->tq, &adapter->rx_task);
- if (reg_icr & E1000_ICR_RXO)
- adapter->rx_overruns++;
+ struct ifnet *ifp = adapter->ifp;
- return FILTER_HANDLED;
+ ++adapter->rx_irq;
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
+ (em_rxeof(adapter, adapter->rx_process_limit) != 0))
+ taskqueue_enqueue(adapter->tq, &adapter->rx_task);
+ /* Reenable this interrupt */
+ E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_RX);
+ return;
}
/*********************************************************************
@@ -1711,19 +1812,22 @@ em_rx_fast(void *arg)
*
**********************************************************************/
-static int
-em_link_fast(void *arg)
+static void
+em_msix_link(void *arg)
{
struct adapter *adapter = arg;
- u32 reg_eicr;
+ u32 reg_icr;
- reg_eicr = E1000_READ_REG(&adapter->hw, E1000_ICR);
+ ++adapter->link_irq;
+ reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
- if (reg_eicr & (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);
-
- E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC);
- return FILTER_HANDLED;
+ }
+ E1000_WRITE_REG(&adapter->hw, E1000_IMS,
+ EM_MSIX_LINK | E1000_IMS_LSC);
+ return;
}
#endif /* EM_FAST_IRQ */
@@ -1988,12 +2092,14 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp)
tso_desc = TRUE;
} else
#endif
+#ifndef EM_TIMESYNC
/*
** 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)
+#endif
em_transmit_checksum_setup(adapter, m_head,
&txd_upper, &txd_lower);
@@ -2150,6 +2256,11 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp)
m_head->m_pkthdr.len);
}
+#ifdef EM_TIMESYNC
+ if (ctxd->upper.data & E1000_TXD_EXTCMD_TSTAMP) {
+ HW_DEBUGOUT( "@@@ Timestamp bit is set in transmit descriptor\n" );
+ }
+#endif
return (0);
}
@@ -2280,6 +2391,9 @@ em_set_promisc(struct adapter *adapter)
if (ifp->if_flags & IFF_PROMISC) {
reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ /* Turn this on if you want to see bad packets */
+ if (em_debug_sbp)
+ reg_rctl |= E1000_RCTL_SBP;
E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
} else if (ifp->if_flags & IFF_ALLMULTI) {
reg_rctl |= E1000_RCTL_MPE;
@@ -2297,6 +2411,7 @@ em_disable_promisc(struct adapter *adapter)
reg_rctl &= (~E1000_RCTL_UPE);
reg_rctl &= (~E1000_RCTL_MPE);
+ reg_rctl &= (~E1000_RCTL_SBP);
E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
}
@@ -2493,6 +2608,12 @@ em_stop(void *arg)
/* Tell the stack that the interface is no longer active */
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+#ifdef EM_TIMESYNC
+ /* Disable IEEE 1588 Time hardware */
+ if ((adapter->hw.mac.type == e1000_82574) ||
+ (adapter->hw.mac.type == e1000_ich10lan))
+ em_tsync_disable(adapter);
+#endif
e1000_reset_hw(&adapter->hw);
if (adapter->hw.mac.type >= e1000_82544)
@@ -2603,7 +2724,8 @@ em_allocate_pci_resources(struct adapter *adapter)
/*
* Setup MSI/X or MSI if PCI Express
*/
- adapter->msi = em_setup_msix(adapter);
+ if (em_enable_msi)
+ adapter->msi = em_setup_msix(adapter);
adapter->hw.back = &adapter->osdep;
@@ -2725,7 +2847,7 @@ em_allocate_msix(struct adapter *adapter)
/* First slot to RX */
if ((error = bus_setup_intr(dev, adapter->res[0],
- INTR_TYPE_NET, em_rx_fast, NULL, adapter,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_rx, adapter,
&adapter->tag[0])) != 0) {
device_printf(dev, "Failed to register RX handler");
return (error);
@@ -2733,7 +2855,7 @@ em_allocate_msix(struct adapter *adapter)
/* Next TX */
if ((error = bus_setup_intr(dev, adapter->res[1],
- INTR_TYPE_NET, em_tx_fast, NULL, adapter,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_tx, adapter,
&adapter->tag[1])) != 0) {
device_printf(dev, "Failed to register TX handler");
return (error);
@@ -2741,7 +2863,7 @@ em_allocate_msix(struct adapter *adapter)
/* And Link */
if ((error = bus_setup_intr(dev, adapter->res[2],
- INTR_TYPE_NET, em_link_fast, NULL, adapter,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, em_msix_link, adapter,
&adapter->tag[2])) != 0) {
device_printf(dev, "Failed to register TX handler");
return (error);
@@ -2809,6 +2931,30 @@ em_setup_msix(struct adapter *adapter)
if (adapter->hw.mac.type < e1000_82571)
return (0);
+ /* Setup MSI/X for Hartwell */
+ if (adapter->hw.mac.type == e1000_82574) {
+ /* Map the MSIX BAR */
+ int rid = PCIR_BAR(EM_MSIX_BAR);
+ adapter->msix = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (!adapter->msix) {
+ /* May not be enabled */
+ device_printf(adapter->dev,
+ "Unable to map MSIX table \n");
+ goto msi;
+ }
+ val = pci_msix_count(dev);
+ /*
+ ** 82574 can be configured for 5 but
+ ** we limit use to 3.
+ */
+ if (val > 3) val = 3;
+ if ((val) && pci_alloc_msix(dev, &val) == 0) {
+ device_printf(adapter->dev,"Using MSIX interrupts\n");
+ return (val);
+ }
+ }
+msi:
val = pci_msi_count(dev);
if (val == 1 && pci_alloc_msi(dev, &val) == 0) {
adapter->msi = 1;
@@ -2838,6 +2984,7 @@ em_hardware_init(struct adapter *adapter)
/* Get control from any management/hw control */
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich10lan) ||
(adapter->hw.mac.type == e1000_ich9lan)) &&
e1000_check_mng_mode(&adapter->hw))
em_get_hw_control(adapter);
@@ -3463,6 +3610,11 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp,
ipproto = ip6->ip6_nxt;
break;
+#ifdef EM_TIMESYNC
+ case ETHERTYPE_IEEE1588:
+ *txd_upper |= E1000_TXD_EXTCMD_TSTAMP;
+ break;
+#endif
default:
*txd_upper = 0;
*txd_lower = 0;
@@ -3488,6 +3640,15 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp,
break;
case IPPROTO_UDP:
{
+#ifdef EM_TIMESYNC
+ void *hdr = (caddr_t) ip + ip_hlen;
+ struct udphdr *uh = (struct udphdr *)hdr;
+
+ if (uh->uh_dport == htons(TSYNC_PORT)) {
+ *txd_upper |= E1000_TXD_EXTCMD_TSTAMP;
+ IOCTL_DEBUGOUT("@@@ Sending Event Packet\n");
+ }
+#endif
if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
/*
* Start offset for header checksum calculation.
@@ -3506,6 +3667,15 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp,
break;
}
+#ifdef EM_TIMESYNC
+ /*
+ ** We might be here just for TIMESYNC
+ ** which means we don't need the context
+ ** descriptor.
+ */
+ if (!mp->m_pkthdr.csum_flags & CSUM_OFFLOAD)
+ return;
+#endif
*txd_lower = E1000_TXD_CMD_DEXT | /* Extended descr type */
E1000_TXD_DTYP_D; /* Data descr */
TXD->tcp_seg_setup.data = htole32(0);
@@ -3968,6 +4138,9 @@ em_setup_receive_structures(struct adapter *adapter)
* Enable receive unit.
*
**********************************************************************/
+#define MAX_INTS_PER_SEC 8000
+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
+
static void
em_initialize_receive_unit(struct adapter *adapter)
{
@@ -3984,18 +4157,30 @@ em_initialize_receive_unit(struct adapter *adapter)
rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL);
E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
- if(adapter->hw.mac.type >= e1000_82540) {
+ if (adapter->hw.mac.type >= e1000_82540) {
E1000_WRITE_REG(&adapter->hw, E1000_RADV,
adapter->rx_abs_int_delay.value);
/*
* Set the interrupt throttling rate. Value is calculated
* as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns)
*/
-#define MAX_INTS_PER_SEC 8000
-#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
E1000_WRITE_REG(&adapter->hw, E1000_ITR, DEFAULT_ITR);
}
+ /*
+ ** When using MSIX interrupts we need to throttle
+ ** using the EITR register (82574 only)
+ */
+ if (adapter->msix)
+ for (int i = 0; i < 4; i++)
+ E1000_WRITE_REG(&adapter->hw,
+ E1000_EITR_82574(i), DEFAULT_ITR);
+
+ /* Disable accelerated ackknowledge */
+ if (adapter->hw.mac.type == e1000_82574)
+ E1000_WRITE_REG(&adapter->hw,
+ E1000_RFCTL, E1000_RFCTL_ACK_DIS);
+
/* Setup the Base and Length of the Rx Descriptor Ring */
bus_addr = adapter->rxdma.dma_paddr;
E1000_WRITE_REG(&adapter->hw, E1000_RDLEN(0),
@@ -4138,21 +4323,23 @@ em_free_receive_structures(struct adapter *adapter)
static int
em_rxeof(struct adapter *adapter, int count)
{
- struct ifnet *ifp;
+ struct ifnet *ifp = adapter->ifp;;
struct mbuf *mp;
u8 status, accept_frame = 0, eop = 0;
u16 len, desc_len, prev_len_adj;
int i;
struct e1000_rx_desc *current_desc;
- ifp = adapter->ifp;
+ EM_RX_LOCK(adapter);
i = adapter->next_rx_desc_to_check;
current_desc = &adapter->rx_desc_base[i];
bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map,
BUS_DMASYNC_POSTREAD);
- if (!((current_desc->status) & E1000_RXD_STAT_DD))
+ if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
+ EM_RX_UNLOCK(adapter);
return (0);
+ }
while ((current_desc->status & E1000_RXD_STAT_DD) &&
(count != 0) &&
@@ -4295,14 +4482,10 @@ discard:
i = 0;
if (m != NULL) {
adapter->next_rx_desc_to_check = i;
-#ifdef EM_LEGACY_IRQ
- EM_CORE_UNLOCK(adapter);
+ /* Unlock for call into stack */
+ EM_RX_UNLOCK(adapter);
(*ifp->if_input)(ifp, m);
- EM_CORE_LOCK(adapter);
-#else
- /* Already running unlocked */
- (*ifp->if_input)(ifp, m);
-#endif
+ EM_RX_LOCK(adapter);
i = adapter->next_rx_desc_to_check;
}
current_desc = &adapter->rx_desc_base[i];
@@ -4313,6 +4496,7 @@ discard:
if (--i < 0)
i = adapter->num_rx_desc - 1;
E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i);
+ EM_RX_UNLOCK(adapter);
if (!((current_desc->status) & E1000_RXD_STAT_DD))
return (0);
@@ -4422,28 +4606,26 @@ em_enable_hw_vlans(struct adapter *adapter)
E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
}
-#define QUEUE_MASK 0x01500000
-
static void
em_enable_intr(struct adapter *adapter)
{
+ struct e1000_hw *hw = &adapter->hw;
u32 ims_mask = IMS_ENABLE_MASK;
if (adapter->msix) {
- E1000_WRITE_REG(&adapter->hw, E1000_EIMS, QUEUE_MASK);
- E1000_WRITE_REG(&adapter->hw, E1000_EIAC, QUEUE_MASK);
- ims_mask |= QUEUE_MASK;
+ E1000_WRITE_REG(hw, EM_EIAC, EM_MSIX_MASK);
+ ims_mask |= EM_MSIX_MASK;
}
- E1000_WRITE_REG(&adapter->hw, E1000_IMS, ims_mask);
+ E1000_WRITE_REG(hw, E1000_IMS, ims_mask);
}
static void
em_disable_intr(struct adapter *adapter)
{
- if (adapter->msix) {
- E1000_WRITE_REG(&adapter->hw, E1000_EIMC, ~0);
- E1000_WRITE_REG(&adapter->hw, E1000_EIAC, 0);
- }
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (adapter->msix)
+ E1000_WRITE_REG(hw, EM_EIAC, 0);
E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff);
}
@@ -4522,6 +4704,7 @@ em_get_hw_control(struct adapter *adapter)
case e1000_80003es2lan:
case e1000_ich8lan:
case e1000_ich9lan:
+ case e1000_ich10lan:
ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
@@ -4555,6 +4738,7 @@ em_release_hw_control(struct adapter *adapter)
case e1000_80003es2lan:
case e1000_ich8lan:
case e1000_ich9lan:
+ case e1000_ich10lan:
ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
@@ -4841,8 +5025,9 @@ em_print_hw_stats(struct adapter *adapter)
device_printf(dev, "RX overruns = %ld\n", adapter->rx_overruns);
device_printf(dev, "watchdog timeouts = %ld\n",
adapter->watchdog_events);
- device_printf(dev, "TX Interrupts = %ld ", adapter->tx_irq);
- device_printf(dev, "RX Interrupts = %ld\n", adapter->rx_irq);
+ device_printf(dev, "RX MSIX IRQ = %ld TX MSIX IRQ = %ld"
+ " LINK MSIX IRQ = %ld\n", adapter->rx_irq,
+ adapter->tx_irq , adapter->link_irq);
device_printf(dev, "XON Rcvd = %lld\n",
(long long)adapter->stats.xonrxc);
device_printf(dev, "XON Xmtd = %lld\n",
@@ -5009,3 +5194,100 @@ em_add_rx_process_limit(struct adapter *adapter, const char *name,
}
#endif
+#ifdef EM_TIMESYNC
+/*
+ * Initialize the Time Sync Feature
+ */
+static int
+em_tsync_init(struct adapter *adapter)
+{
+ device_t dev = adapter->dev;
+ u32 tx_ctl, rx_ctl;
+
+
+ E1000_WRITE_REG(&adapter->hw, E1000_TIMINCA, (1<<24) |
+ 20833/PICOSECS_PER_TICK);
+
+ adapter->last_stamp = E1000_READ_REG(&adapter->hw, E1000_SYSTIML);
+ adapter->last_stamp |= (u64)E1000_READ_REG(&adapter->hw,
+ E1000_SYSTIMH) << 32ULL;
+
+ /* Enable the TX side */
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ tx_ctl |= 0x10;
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCTXCTL, tx_ctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ if ((tx_ctl & 0x10) == 0) {
+ device_printf(dev, "Failed to enable TX timestamping\n");
+ return (ENXIO);
+ }
+
+ /* Enable RX */
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ rx_ctl |= 0x10; /* Enable the feature */
+ rx_ctl |= 0x0a; /* This value turns on Ver 1 and 2 */
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCRXCTL, rx_ctl);
+
+ /*
+ * Ethertype Stamping (Ethertype = 0x88F7)
+ */
+ E1000_WRITE_REG(&adapter->hw, E1000_RXMTRL, htonl(0x440088f7));
+
+ /*
+ * Source Port Queue Filter Setup:
+ * this is for UDP port filtering
+ */
+ E1000_WRITE_REG(&adapter->hw, E1000_RXUDP, htons(TSYNC_PORT));
+ /* Protocol = UDP, enable Timestamp, and filter on source/protocol */
+
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ if ((rx_ctl & 0x10) == 0) {
+ device_printf(dev, "Failed to enable RX timestamping\n");
+ return (ENXIO);
+ }
+
+ device_printf(dev, "IEEE 1588 Precision Time Protocol enabled\n");
+
+ return (0);
+}
+
+/*
+ * Disable the Time Sync Feature
+ */
+static void
+em_tsync_disable(struct adapter *adapter)
+{
+ u32 tx_ctl, rx_ctl;
+
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ tx_ctl &= ~0x10;
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCTXCTL, tx_ctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ /* Invalidate TX Timestamp */
+ E1000_READ_REG(&adapter->hw, E1000_TXSTMPH);
+
+ tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL);
+ if (tx_ctl & 0x10)
+ HW_DEBUGOUT("Failed to disable TX timestamping\n");
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ rx_ctl &= ~0x10;
+
+ E1000_WRITE_REG(&adapter->hw, E1000_TSYNCRXCTL, rx_ctl);
+ E1000_WRITE_FLUSH(&adapter->hw);
+
+ /* Invalidate RX Timestamp */
+ E1000_READ_REG(&adapter->hw, E1000_RXSATRH);
+
+ rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL);
+ if (rx_ctl & 0x10)
+ HW_DEBUGOUT("Failed to disable RX timestamping\n");
+
+ return;
+}
+#endif /* EM_TIMESYNC */
OpenPOWER on IntegriCloud