summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/pkgdefs/SUNWigb/postinstall10
-rw-r--r--usr/src/uts/common/io/igb/igb_debug.h12
-rw-r--r--usr/src/uts/common/io/igb/igb_main.c591
-rw-r--r--usr/src/uts/common/io/igb/igb_osdep.c39
-rw-r--r--usr/src/uts/common/io/igb/igb_stat.c16
-rw-r--r--usr/src/uts/common/io/igb/igb_sw.h14
6 files changed, 376 insertions, 306 deletions
diff --git a/usr/src/pkgdefs/SUNWigb/postinstall b/usr/src/pkgdefs/SUNWigb/postinstall
index f5284bfbe6..b5ce16aee6 100644
--- a/usr/src/pkgdefs/SUNWigb/postinstall
+++ b/usr/src/pkgdefs/SUNWigb/postinstall
@@ -21,11 +21,9 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# Function: check_add_drv()
#
@@ -131,5 +129,9 @@ check_add_drv()
check_add_drv -i \
'"pciex8086,10a7"
"pciex8086,10a9"
- "pciex8086,10d6"' \
+ "pciex8086,10c9"
+ "pciex8086,10d6"
+ "pciex8086,10e6"
+ "pciex8086,10e7"
+ "pciex8086,10e8"' \
-b "$BASEDIR" igb
diff --git a/usr/src/uts/common/io/igb/igb_debug.h b/usr/src/uts/common/io/igb/igb_debug.h
index a21745537e..3026856360 100644
--- a/usr/src/uts/common/io/igb/igb_debug.h
+++ b/usr/src/uts/common/io/igb/igb_debug.h
@@ -1,7 +1,7 @@
/*
* CDDL HEADER START
*
- * Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
@@ -22,15 +22,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDL.
*/
#ifndef _IGB_DEBUG_H
#define _IGB_DEBUG_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -51,8 +49,8 @@ extern "C" {
#define IGB_DEBUGLOG_3(adapter, fmt, d1, d2, d3) \
igb_log((adapter), (fmt), (d1), (d2), (d3))
-#define IGB_DEBUG_STAT_COND(val, cond) if (cond) (val)++;
-#define IGB_DEBUG_STAT(val) (val)++;
+#define IGB_DEBUG_STAT_COND(val, cond) if (cond) (val)++
+#define IGB_DEBUG_STAT(val) (val)++
#else
@@ -66,7 +64,7 @@ extern "C" {
#endif /* IGB_DEBUG */
-#define IGB_STAT(val) (val)++;
+#define IGB_STAT(val) (val)++
#ifdef IGB_DEBUG
diff --git a/usr/src/uts/common/io/igb/igb_main.c b/usr/src/uts/common/io/igb/igb_main.c
index 7a69a7bd6d..9e75df9ff5 100644
--- a/usr/src/uts/common/io/igb/igb_main.c
+++ b/usr/src/uts/common/io/igb/igb_main.c
@@ -29,7 +29,7 @@
#include "igb_sw.h"
static char ident[] = "Intel 1Gb Ethernet";
-static char igb_version[] = "igb 1.1.4";
+static char igb_version[] = "igb 1.1.5";
/*
* Local function protoypes
@@ -41,17 +41,16 @@ static void igb_init_properties(igb_t *);
static int igb_init_driver_settings(igb_t *);
static void igb_init_locks(igb_t *);
static void igb_destroy_locks(igb_t *);
+static int igb_init_mac_address(igb_t *);
static int igb_init(igb_t *);
-static int igb_chip_start(igb_t *);
-static void igb_chip_stop(igb_t *);
+static int igb_init_adapter(igb_t *);
+static void igb_stop_adapter(igb_t *);
static int igb_reset(igb_t *);
static void igb_tx_clean(igb_t *);
static boolean_t igb_tx_drain(igb_t *);
static boolean_t igb_rx_drain(igb_t *);
static int igb_alloc_rings(igb_t *);
-static int igb_init_rings(igb_t *);
static void igb_free_rings(igb_t *);
-static void igb_fini_rings(igb_t *);
static void igb_setup_rings(igb_t *);
static void igb_setup_rx(igb_t *);
static void igb_setup_tx(igb_t *);
@@ -205,15 +204,17 @@ static adapter_info_t igb_82575_cap = {
/* capabilities */
(IGB_FLAG_HAS_DCA | /* capability flags */
- IGB_FLAG_VMDQ_POOL)
+ IGB_FLAG_VMDQ_POOL),
+
+ 0xffc00000 /* mask for RXDCTL register */
};
static adapter_info_t igb_82576_cap = {
/* limits */
- 12, /* maximum number of rx queues */
+ 16, /* maximum number of rx queues */
1, /* minimum number of rx queues */
4, /* default number of rx queues */
- 12, /* maximum number of tx queues */
+ 16, /* maximum number of tx queues */
1, /* minimum number of tx queues */
4, /* default number of tx queues */
65535, /* maximum interrupt throttle rate */
@@ -227,7 +228,9 @@ static adapter_info_t igb_82576_cap = {
/* capabilities */
(IGB_FLAG_HAS_DCA | /* capability flags */
IGB_FLAG_VMDQ_POOL |
- IGB_FLAG_NEED_CTX_IDX)
+ IGB_FLAG_NEED_CTX_IDX),
+
+ 0xffe00000 /* mask for RXDCTL register */
};
/*
@@ -423,25 +426,22 @@ igb_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
igb->attach_progress |= ATTACH_PROGRESS_LOCKS;
/*
- * Initialize chipset hardware
+ * Allocate DMA resources
*/
- mutex_enter(&igb->gen_lock);
- if (igb_init(igb) != IGB_SUCCESS) {
- mutex_exit(&igb->gen_lock);
- igb_error(igb, "Failed to initialize adapter");
+ if (igb_alloc_dma(igb) != IGB_SUCCESS) {
+ igb_error(igb, "Failed to allocate DMA resources");
goto attach_fail;
}
- mutex_exit(&igb->gen_lock);
- igb->attach_progress |= ATTACH_PROGRESS_INIT;
+ igb->attach_progress |= ATTACH_PROGRESS_ALLOC_DMA;
/*
- * Initialize DMA and hardware settings for rx/tx rings
+ * Initialize the adapter and setup the rx/tx rings
*/
- if (igb_init_rings(igb) != IGB_SUCCESS) {
- igb_error(igb, "Failed to initialize rings");
+ if (igb_init(igb) != IGB_SUCCESS) {
+ igb_error(igb, "Failed to initialize adapter");
goto attach_fail;
}
- igb->attach_progress |= ATTACH_PROGRESS_INIT_RINGS;
+ igb->attach_progress |= ATTACH_PROGRESS_INIT_ADAPTER;
/*
* Initialize statistics
@@ -617,7 +617,9 @@ igb_quiesce(dev_info_t *devinfo)
return (DDI_SUCCESS);
}
-
+/*
+ * igb_unconfigure - release all resources held by this instance
+ */
static void
igb_unconfigure(dev_info_t *devinfo, igb_t *igb)
{
@@ -673,16 +675,16 @@ igb_unconfigure(dev_info_t *devinfo, igb_t *igb)
/*
* Release the DMA resources of rx/tx rings
*/
- if (igb->attach_progress & ATTACH_PROGRESS_INIT_RINGS) {
- igb_fini_rings(igb);
+ if (igb->attach_progress & ATTACH_PROGRESS_ALLOC_DMA) {
+ igb_free_dma(igb);
}
/*
- * Stop the chipset
+ * Stop the adapter
*/
- if (igb->attach_progress & ATTACH_PROGRESS_INIT) {
+ if (igb->attach_progress & ATTACH_PROGRESS_INIT_ADAPTER) {
mutex_enter(&igb->gen_lock);
- igb_chip_stop(igb);
+ igb_stop_adapter(igb);
mutex_exit(&igb->gen_lock);
if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
@@ -1059,6 +1061,11 @@ igb_suspend(dev_info_t *devinfo)
igb->igb_state |= IGB_SUSPENDED;
+ if (!(igb->igb_state & IGB_STARTED)) {
+ mutex_exit(&igb->gen_lock);
+ return (DDI_SUCCESS);
+ }
+
igb_stop(igb);
mutex_exit(&igb->gen_lock);
@@ -1071,25 +1078,70 @@ igb_suspend(dev_info_t *devinfo)
return (DDI_SUCCESS);
}
+static int
+igb_init(igb_t *igb)
+{
+ int i;
+
+ mutex_enter(&igb->gen_lock);
+
+ /*
+ * Initilize the adapter
+ */
+ if (igb_init_adapter(igb) != IGB_SUCCESS) {
+ mutex_exit(&igb->gen_lock);
+ igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
+ return (IGB_FAILURE);
+ }
+
+ /*
+ * Setup the rx/tx rings
+ */
+ for (i = 0; i < igb->num_rx_rings; i++)
+ mutex_enter(&igb->rx_rings[i].rx_lock);
+ for (i = 0; i < igb->num_tx_rings; i++)
+ mutex_enter(&igb->tx_rings[i].tx_lock);
+
+ igb_setup_rings(igb);
+
+ for (i = igb->num_tx_rings - 1; i >= 0; i--)
+ mutex_exit(&igb->tx_rings[i].tx_lock);
+ for (i = igb->num_rx_rings - 1; i >= 0; i--)
+ mutex_exit(&igb->rx_rings[i].rx_lock);
+
+ mutex_exit(&igb->gen_lock);
+
+ return (IGB_SUCCESS);
+}
+
/*
- * igb_init - Initialize the device
+ * igb_init_mac_address - Initialize the default MAC address
+ *
+ * On success, the MAC address is entered in the igb->hw.mac.addr
+ * and hw->mac.perm_addr fields and the adapter's RAR(0) receive
+ * address register.
+ *
+ * Important side effects:
+ * 1. adapter is reset - this is required to put it in a known state.
+ * 2. all of non-volatile memory (NVM) is read & checksummed - NVM is where
+ * MAC address and all default settings are stored, so a valid checksum
+ * is required.
*/
static int
-igb_init(igb_t *igb)
+igb_init_mac_address(igb_t *igb)
{
struct e1000_hw *hw = &igb->hw;
- uint32_t pba;
- uint32_t high_water;
ASSERT(mutex_owned(&igb->gen_lock));
/*
* Reset chipset to put the hardware in a known state
- * before we try to do anything with the eeprom
+ * before we try to get MAC address from NVM.
*/
if (e1000_reset_hw(hw) != E1000_SUCCESS) {
- igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
- goto init_fail;
+ igb_error(igb, "Adapter reset failed.");
+ goto init_mac_fail;
}
/*
@@ -1105,12 +1157,55 @@ igb_init(igb_t *igb)
igb_error(igb,
"Invalid NVM checksum. Please contact "
"the vendor to update the NVM.");
- igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
- goto init_fail;
+ goto init_mac_fail;
}
}
/*
+ * Get the mac address
+ * This function should handle SPARC case correctly.
+ */
+ if (!igb_find_mac_address(igb)) {
+ igb_error(igb, "Failed to get the mac address");
+ goto init_mac_fail;
+ }
+
+ /* Validate mac address */
+ if (!is_valid_mac_addr(hw->mac.addr)) {
+ igb_error(igb, "Invalid mac address");
+ goto init_mac_fail;
+ }
+
+ return (IGB_SUCCESS);
+
+init_mac_fail:
+ return (IGB_FAILURE);
+}
+
+/*
+ * igb_init_adapter - Initialize the adapter
+ */
+static int
+igb_init_adapter(igb_t *igb)
+{
+ struct e1000_hw *hw = &igb->hw;
+ uint32_t pba;
+ uint32_t high_water;
+ int i;
+
+ ASSERT(mutex_owned(&igb->gen_lock));
+
+ /*
+ * In order to obtain the default MAC address, this will reset the
+ * adapter and validate the NVM that the address and many other
+ * default settings come from.
+ */
+ if (igb_init_mac_address(igb) != IGB_SUCCESS) {
+ igb_error(igb, "Failed to initialize MAC address");
+ goto init_adapter_fail;
+ }
+
+ /*
* Setup flow control
*
* These parameters set thresholds for the adapter's generation(Tx)
@@ -1125,6 +1220,11 @@ igb_init(igb_t *igb)
* 90% of the Rx FIFO size, or the full Rx FIFO size minus one full
* frame.
*/
+ /*
+ * The default setting of PBA is correct for 82575 and other supported
+ * adapters do not have the E1000_PBA register, so PBA value is only
+ * used for calculation here and is never written to the adapter.
+ */
if (hw->mac.type == e1000_82575) {
pba = E1000_PBA_34K;
} else {
@@ -1147,13 +1247,15 @@ igb_init(igb_t *igb)
hw->fc.pause_time = E1000_FC_PAUSE_TIME;
hw->fc.send_xon = B_TRUE;
+ e1000_validate_mdi_setting(hw);
+
/*
- * Reset the chipset hardware the second time to validate
- * the PBA setting.
+ * Reset the chipset hardware the second time to put PBA settings
+ * into effect.
*/
if (e1000_reset_hw(hw) != E1000_SUCCESS) {
- igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
- goto init_fail;
+ igb_error(igb, "Second reset failed");
+ goto init_adapter_fail;
}
/*
@@ -1176,120 +1278,22 @@ igb_init(igb_t *igb)
(void) igb_setup_link(igb, B_FALSE);
/*
- * Initialize the chipset hardware
+ * Configure/Initialize hardware
*/
- if (igb_chip_start(igb) != IGB_SUCCESS) {
- igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
- goto init_fail;
- }
-
- if (igb_check_acc_handle(igb->osdep.cfg_handle) != DDI_FM_OK) {
- goto init_fail;
- }
-
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
- goto init_fail;
+ if (e1000_init_hw(hw) != E1000_SUCCESS) {
+ igb_error(igb, "Failed to initialize hardware");
+ goto init_adapter_fail;
}
- return (IGB_SUCCESS);
-
-init_fail:
- /*
- * Reset PHY if possible
- */
- if (e1000_check_reset_block(hw) == E1000_SUCCESS)
- (void) e1000_phy_hw_reset(hw);
-
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
-
- return (IGB_FAILURE);
-}
-
-/*
- * igb_init_rings - Allocate DMA resources for all rx/tx rings and
- * initialize relevant hardware settings.
- */
-static int
-igb_init_rings(igb_t *igb)
-{
- int i;
-
- /*
- * Allocate buffers for all the rx/tx rings
- */
- if (igb_alloc_dma(igb) != IGB_SUCCESS)
- return (IGB_FAILURE);
-
/*
- * Setup the rx/tx rings
+ * Disable wakeup control by default
*/
- mutex_enter(&igb->gen_lock);
-
- for (i = 0; i < igb->num_rx_rings; i++)
- mutex_enter(&igb->rx_rings[i].rx_lock);
- for (i = 0; i < igb->num_tx_rings; i++)
- mutex_enter(&igb->tx_rings[i].tx_lock);
-
- igb_setup_rings(igb);
-
- for (i = igb->num_tx_rings - 1; i >= 0; i--)
- mutex_exit(&igb->tx_rings[i].tx_lock);
- for (i = igb->num_rx_rings - 1; i >= 0; i--)
- mutex_exit(&igb->rx_rings[i].rx_lock);
-
- mutex_exit(&igb->gen_lock);
-
- return (IGB_SUCCESS);
-}
-
-/*
- * igb_fini_rings - Release DMA resources of all rx/tx rings
- */
-static void
-igb_fini_rings(igb_t *igb)
-{
- /*
- * Release the DMA/memory resources of rx/tx rings
- */
- igb_free_dma(igb);
-}
-
-/*
- * igb_chip_start - Initialize and start the chipset hardware
- */
-static int
-igb_chip_start(igb_t *igb)
-{
- struct e1000_hw *hw = &igb->hw;
- int i;
-
- ASSERT(mutex_owned(&igb->gen_lock));
-
- /*
- * Get the mac address
- * This function should handle SPARC case correctly.
- */
- if (!igb_find_mac_address(igb)) {
- igb_error(igb, "Failed to get the mac address");
- return (IGB_FAILURE);
- }
-
- /* Validate mac address */
- if (!is_valid_mac_addr(hw->mac.addr)) {
- igb_error(igb, "Invalid mac address");
- return (IGB_FAILURE);
- }
-
- /* Disable wakeup control by default */
E1000_WRITE_REG(hw, E1000_WUC, 0);
/*
- * Configure/Initialize hardware
+ * Record phy info in hw struct
*/
- if (e1000_init_hw(hw) != E1000_SUCCESS) {
- igb_error(igb, "Failed to initialize hardware");
- return (IGB_FAILURE);
- }
+ (void) e1000_get_phy_info(hw);
/*
* Make sure driver has control
@@ -1297,6 +1301,12 @@ igb_chip_start(igb_t *igb)
igb_get_driver_control(hw);
/*
+ * Restore LED settings to the default from EEPROM
+ * to meet the standard for Sun platforms.
+ */
+ (void) e1000_cleanup_led(hw);
+
+ /*
* Setup MSI-X interrupts
*/
if (igb->intr_type == DDI_INTR_TYPE_MSIX)
@@ -1318,24 +1328,28 @@ igb_chip_start(igb_t *igb)
for (i = 0; i < igb->intr_cnt; i++)
E1000_WRITE_REG(hw, E1000_EITR(i), igb->intr_throttling[i]);
- /* Enable PCI-E master */
- if (hw->bus.type == e1000_bus_type_pci_express) {
- e1000_enable_pciex_master(hw);
- }
-
/*
* Save the state of the phy
*/
igb_get_phy_state(igb);
return (IGB_SUCCESS);
+
+init_adapter_fail:
+ /*
+ * Reset PHY if possible
+ */
+ if (e1000_check_reset_block(hw) == E1000_SUCCESS)
+ (void) e1000_phy_hw_reset(hw);
+
+ return (IGB_FAILURE);
}
/*
- * igb_chip_stop - Stop the chipset hardware
+ * igb_stop_adapter - Stop the adapter
*/
static void
-igb_chip_stop(igb_t *igb)
+igb_stop_adapter(igb_t *igb)
{
struct e1000_hw *hw = &igb->hw;
@@ -1353,10 +1367,8 @@ igb_chip_stop(igb_t *igb)
}
/*
- * Reset PHY if possible
+ * e1000_phy_hw_reset is not needed here, MAC reset above is sufficient
*/
- if (e1000_check_reset_block(hw) == E1000_SUCCESS)
- (void) e1000_phy_hw_reset(hw);
}
/*
@@ -1391,9 +1403,9 @@ igb_reset(igb_t *igb)
mutex_enter(&igb->tx_rings[i].tx_lock);
/*
- * Stop the chipset hardware
+ * Stop the adapter
*/
- igb_chip_stop(igb);
+ igb_stop_adapter(igb);
/*
* Clean the pending tx data/resources
@@ -1401,9 +1413,9 @@ igb_reset(igb_t *igb)
igb_tx_clean(igb);
/*
- * Start the chipset hardware
+ * Start the adapter
*/
- if (igb_chip_start(igb) != IGB_SUCCESS) {
+ if (igb_init_adapter(igb) != IGB_SUCCESS) {
igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
goto reset_failure;
}
@@ -1606,20 +1618,20 @@ igb_start(igb_t *igb)
mutex_enter(&igb->tx_rings[i].tx_lock);
/*
- * Start the chipset hardware
+ * Start the adapter
*/
- if (!(igb->attach_progress & ATTACH_PROGRESS_INIT)) {
- if (igb_init(igb) != IGB_SUCCESS) {
+ if ((igb->attach_progress & ATTACH_PROGRESS_INIT_ADAPTER) == 0) {
+ if (igb_init_adapter(igb) != IGB_SUCCESS) {
igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
goto start_failure;
}
- igb->attach_progress |= ATTACH_PROGRESS_INIT;
- }
+ igb->attach_progress |= ATTACH_PROGRESS_INIT_ADAPTER;
- /*
- * Setup the rx/tx rings
- */
- igb_setup_rings(igb);
+ /*
+ * Setup the rx/tx rings
+ */
+ igb_setup_rings(igb);
+ }
/*
* Enable adapter interrupts
@@ -1661,7 +1673,7 @@ igb_stop(igb_t *igb)
ASSERT(mutex_owned(&igb->gen_lock));
- igb->attach_progress &= ~ ATTACH_PROGRESS_INIT;
+ igb->attach_progress &= ~ATTACH_PROGRESS_INIT_ADAPTER;
/*
* Disable the adapter interrupts
@@ -1679,9 +1691,9 @@ igb_stop(igb_t *igb)
mutex_enter(&igb->tx_rings[i].tx_lock);
/*
- * Stop the chipset hardware
+ * Stop the adapter
*/
- igb_chip_stop(igb);
+ igb_stop_adapter(igb);
/*
* Clean the pending tx data/resources
@@ -1804,12 +1816,15 @@ igb_setup_rx_ring(igb_rx_ring_t *rx_ring)
uint32_t size;
uint32_t buf_low;
uint32_t buf_high;
- uint32_t reg_val;
+ uint32_t rxdctl;
int i;
ASSERT(mutex_owned(&rx_ring->rx_lock));
ASSERT(mutex_owned(&igb->gen_lock));
+ /*
+ * Initialize descriptor ring with buffer addresses
+ */
for (i = 0; i < igb->rx_ring_size; i++) {
rcb = rx_ring->work_list[i];
rbd = &rx_ring->rbd_ring[i];
@@ -1819,24 +1834,36 @@ igb_setup_rx_ring(igb_rx_ring_t *rx_ring)
}
/*
+ * Initialize the base address registers
+ */
+ buf_low = (uint32_t)rx_ring->rbd_area.dma_address;
+ buf_high = (uint32_t)(rx_ring->rbd_area.dma_address >> 32);
+ E1000_WRITE_REG(hw, E1000_RDBAH(rx_ring->index), buf_high);
+ E1000_WRITE_REG(hw, E1000_RDBAL(rx_ring->index), buf_low);
+
+ /*
* Initialize the length register
*/
size = rx_ring->ring_size * sizeof (union e1000_adv_rx_desc);
E1000_WRITE_REG(hw, E1000_RDLEN(rx_ring->index), size);
/*
- * Initialize the base address registers
+ * Initialize buffer size & descriptor type
*/
- buf_low = (uint32_t)rx_ring->rbd_area.dma_address;
- buf_high = (uint32_t)(rx_ring->rbd_area.dma_address >> 32);
- E1000_WRITE_REG(hw, E1000_RDBAH(rx_ring->index), buf_high);
- E1000_WRITE_REG(hw, E1000_RDBAL(rx_ring->index), buf_low);
+ E1000_WRITE_REG(hw, E1000_SRRCTL(rx_ring->index),
+ ((igb->rx_buf_size >> E1000_SRRCTL_BSIZEPKT_SHIFT) |
+ E1000_SRRCTL_DESCTYPE_ADV_ONEBUF));
/*
- * Setup head & tail pointers
+ * Setup the Receive Descriptor Control Register (RXDCTL)
*/
- E1000_WRITE_REG(hw, E1000_RDT(rx_ring->index), rx_ring->ring_size - 1);
- E1000_WRITE_REG(hw, E1000_RDH(rx_ring->index), 0);
+ rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(rx_ring->index));
+ rxdctl &= igb->capab->rxdctl_mask;
+ rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
+ rxdctl |= 16; /* pthresh */
+ rxdctl |= 8 << 8; /* hthresh */
+ rxdctl |= 1 << 16; /* wthresh */
+ E1000_WRITE_REG(hw, E1000_RXDCTL(rx_ring->index), rxdctl);
rx_ring->rbd_next = 0;
@@ -1851,26 +1878,6 @@ igb_setup_rx_ring(igb_rx_ring_t *rx_ring)
rx_ring->rcb_tail = 0;
rx_ring->rcb_free = rx_ring->free_list_size;
}
-
- /*
- * Setup the Receive Descriptor Control Register (RXDCTL)
- */
- reg_val = E1000_READ_REG(hw, E1000_RXDCTL(rx_ring->index));
- reg_val |= E1000_RXDCTL_QUEUE_ENABLE;
- reg_val &= 0xFFF00000;
- reg_val |= 16; /* pthresh */
- reg_val |= 8 << 8; /* hthresh */
- reg_val |= 1 << 16; /* wthresh */
- E1000_WRITE_REG(hw, E1000_RXDCTL(rx_ring->index), reg_val);
-
- /*
- * Setup the Split and Replication Receive Control Register.
- * Set the rx buffer size and the advanced descriptor type.
- */
- reg_val = (igb->rx_buf_size >> E1000_SRRCTL_BSIZEPKT_SHIFT) |
- E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
-
- E1000_WRITE_REG(hw, E1000_SRRCTL(rx_ring->index), reg_val);
}
static void
@@ -1879,35 +1886,50 @@ igb_setup_rx(igb_t *igb)
igb_rx_ring_t *rx_ring;
igb_rx_group_t *rx_group;
struct e1000_hw *hw = &igb->hw;
- uint32_t reg_val, rctl;
+ uint32_t rctl, rxcsum;
uint32_t ring_per_group;
int i;
/*
- * Setup the Receive Control Register (RCTL), and ENABLE the
- * receiver. The initial configuration is to: Enable the receiver,
- * accept broadcasts, discard bad packets (and long packets),
- * disable VLAN filter checking, set the receive descriptor
- * minimum threshold size to 1/2, and the receive buffer size to
- * 2k.
+ * Setup the Receive Control Register (RCTL), and enable the
+ * receiver. The initial configuration is to: enable the receiver,
+ * accept broadcasts, discard bad packets, accept long packets,
+ * disable VLAN filter checking, and set receive buffer size to
+ * 2k. For 82575, also set the receive descriptor minimum
+ * threshold size to 1/2 the ring.
*/
rctl = E1000_READ_REG(hw, E1000_RCTL);
/*
- * only used for wakeup control. This driver doesn't do wakeup
- * but leave this here for completeness.
+ * Clear the field used for wakeup control. This driver doesn't do
+ * wakeup but leave this here for completeness.
*/
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
- rctl |= E1000_RCTL_EN | /* Enable Receive Unit */
- E1000_RCTL_BAM | /* Accept Broadcast Packets */
- E1000_RCTL_LPE | /* Large Packet Enable bit */
- (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
- E1000_RCTL_RDMTS_HALF |
- E1000_RCTL_SECRC | /* Strip Ethernet CRC */
- E1000_RCTL_LBM_NO; /* Loopback Mode = none */
+ switch (hw->mac.type) {
+ case e1000_82575:
+ rctl |= (E1000_RCTL_EN | /* Enable Receive Unit */
+ E1000_RCTL_BAM | /* Accept Broadcast Packets */
+ E1000_RCTL_LPE | /* Large Packet Enable */
+ /* Multicast filter offset */
+ (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
+ E1000_RCTL_RDMTS_HALF | /* rx descriptor threshold */
+ E1000_RCTL_SECRC); /* Strip Ethernet CRC */
+ break;
- E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+ case e1000_82576:
+ rctl |= (E1000_RCTL_EN | /* Enable Receive Unit */
+ E1000_RCTL_BAM | /* Accept Broadcast Packets */
+ E1000_RCTL_LPE | /* Large Packet Enable */
+ /* Multicast filter offset */
+ (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
+ E1000_RCTL_SECRC); /* Strip Ethernet CRC */
+ break;
+
+ default:
+ igb_log(igb, "unsupported MAC type: %d", hw->mac.type);
+ return; /* should never come here; this will cause rx failure */
+ }
for (i = 0; i < igb->num_rx_groups; i++) {
rx_group = &igb->rx_groups[i];
@@ -1916,7 +1938,8 @@ igb_setup_rx(igb_t *igb)
}
/*
- * igb_setup_rx_ring must be called after configuring RCTL
+ * Set up all rx descriptor rings - must be called before receive unit
+ * enabled.
*/
ring_per_group = igb->num_rx_rings / igb->num_rx_groups;
for (i = 0; i < igb->num_rx_rings; i++) {
@@ -1938,11 +1961,11 @@ igb_setup_rx(igb_t *igb)
* Hardware checksum settings
*/
if (igb->rx_hcksum_enable) {
- reg_val =
+ rxcsum =
E1000_RXCSUM_TUOFL | /* TCP/UDP checksum */
E1000_RXCSUM_IPOFL; /* IP checksum */
- E1000_WRITE_REG(hw, E1000_RXCSUM, reg_val);
+ E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
}
/*
@@ -1972,6 +1995,31 @@ igb_setup_rx(igb_t *igb)
igb_setup_mac_rss_classify(igb);
break;
}
+
+ /*
+ * Enable the receive unit - must be done after all
+ * the rx setup above.
+ */
+ E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+
+ /*
+ * Initialize all adapter ring head & tail pointers - must
+ * be done after receive unit is enabled
+ */
+ for (i = 0; i < igb->num_rx_rings; i++) {
+ rx_ring = &igb->rx_rings[i];
+ E1000_WRITE_REG(hw, E1000_RDH(i), 0);
+ E1000_WRITE_REG(hw, E1000_RDT(i), rx_ring->ring_size - 1);
+ }
+
+ /*
+ * 82575 with manageability enabled needs a special flush to make
+ * sure the fifos start clean.
+ */
+ if ((hw->mac.type == e1000_82575) &&
+ (E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN)) {
+ e1000_rx_fifo_flush_82575(hw);
+ }
}
static void
@@ -2061,14 +2109,6 @@ igb_setup_tx_ring(igb_tx_ring_t *tx_ring)
}
/*
- * Enable specific tx ring, it is required by multiple tx
- * ring support.
- */
- reg_val = E1000_READ_REG(hw, E1000_TXDCTL(tx_ring->index));
- reg_val |= E1000_TXDCTL_QUEUE_ENABLE;
- E1000_WRITE_REG(hw, E1000_TXDCTL(tx_ring->index), reg_val);
-
- /*
* Initialize hardware checksum offload settings
*/
tx_ring->hcksum_context.hcksum_flags = 0;
@@ -2105,8 +2145,6 @@ igb_setup_tx(igb_t *igb)
reg_val |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
- e1000_config_collision_dist(hw);
-
/* Enable transmits */
reg_val |= E1000_TCTL_EN;
@@ -2800,18 +2838,33 @@ static boolean_t
igb_is_link_up(igb_t *igb)
{
struct e1000_hw *hw = &igb->hw;
- boolean_t link_up;
+ boolean_t link_up = B_FALSE;
ASSERT(mutex_owned(&igb->gen_lock));
- (void) e1000_check_for_link(hw);
-
- if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) ||
- ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
- (hw->mac.serdes_has_link))) {
- link_up = B_TRUE;
- } else {
- link_up = B_FALSE;
+ /*
+ * get_link_status is set in the interrupt handler on link-status-change
+ * or rx sequence error interrupt. get_link_status will stay
+ * false until the e1000_check_for_link establishes link only
+ * for copper adapters.
+ */
+ switch (hw->phy.media_type) {
+ case e1000_media_type_copper:
+ if (hw->mac.get_link_status) {
+ (void) e1000_check_for_link(hw);
+ link_up = !hw->mac.get_link_status;
+ } else {
+ link_up = B_TRUE;
+ }
+ break;
+ case e1000_media_type_fiber:
+ (void) e1000_check_for_link(hw);
+ link_up = (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU);
+ break;
+ case e1000_media_type_internal_serdes:
+ (void) e1000_check_for_link(hw);
+ link_up = hw->mac.serdes_has_link;
+ break;
}
return (link_up);
@@ -2876,11 +2929,11 @@ static void
igb_local_timer(void *arg)
{
igb_t *igb = (igb_t *)arg;
- struct e1000_hw *hw = &igb->hw;
- boolean_t link_changed;
+ boolean_t link_changed = B_FALSE;
if (igb_stall_check(igb)) {
igb_fm_ereport(igb, DDI_FM_DEVICE_STALL);
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
igb->reset_count++;
if (igb_reset(igb) == IGB_SUCCESS)
ddi_fm_service_impact(igb->dip,
@@ -2888,18 +2941,13 @@ igb_local_timer(void *arg)
}
mutex_enter(&igb->gen_lock);
- link_changed = igb_link_check(igb);
+ if (!(igb->igb_state & IGB_SUSPENDED) && (igb->igb_state & IGB_STARTED))
+ link_changed = igb_link_check(igb);
mutex_exit(&igb->gen_lock);
if (link_changed)
mac_link_update(igb->mac_hdl, igb->link_state);
- /*
- * Set Timer Interrupts
- */
- if (igb->intr_type != DDI_INTR_TYPE_MSIX)
- E1000_WRITE_REG(hw, E1000_ICS, E1000_IMS_RXT0);
-
if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
@@ -3190,6 +3238,9 @@ igb_enable_adapter_interrupts_82576(igb_t *igb)
{
struct e1000_hw *hw = &igb->hw;
+ /* Clear any pending interrupts */
+ (void) E1000_READ_REG(hw, E1000_ICR);
+
if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
/* Interrupt enabling for MSI-X */
@@ -3220,6 +3271,9 @@ igb_enable_adapter_interrupts_82575(igb_t *igb)
struct e1000_hw *hw = &igb->hw;
uint32_t reg;
+ /* Clear any pending interrupts */
+ (void) E1000_READ_REG(hw, E1000_ICR);
+
if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
/* Interrupt enabling for MSI-X */
E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
@@ -3430,25 +3484,41 @@ igb_set_internal_mac_loopback(igb_t *igb)
struct e1000_hw *hw;
uint32_t ctrl;
uint32_t rctl;
+ uint32_t ctrl_ext;
+ uint16_t phy_ctrl;
+ uint16_t phy_status;
hw = &igb->hw;
- /* Set the Receive Control register */
- rctl = E1000_READ_REG(hw, E1000_RCTL);
- rctl &= ~E1000_RCTL_LBM_TCVR;
- rctl |= E1000_RCTL_LBM_MAC;
- E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+ (void) e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);
+ phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+ (void) e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl);
+
+ (void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
+
+ /* Set link mode to PHY (00b) in the Extended Control register */
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
/* Set the Device Control register */
ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ if (!(phy_status & MII_SR_LINK_STATUS))
+ ctrl |= E1000_CTRL_ILOS; /* Set ILOS when the link is down */
ctrl &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
ctrl |= (E1000_CTRL_SLU | /* Force link up */
E1000_CTRL_FRCSPD | /* Force speed */
E1000_CTRL_FRCDPX | /* Force duplex */
E1000_CTRL_SPD_1000 | /* Force speed to 1000 */
E1000_CTRL_FD); /* Force full duplex */
- ctrl &= ~E1000_CTRL_ILOS; /* Clear ILOS when there's a link */
+
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+ /* Set the Receive Control register */
+ rctl = E1000_READ_REG(hw, E1000_RCTL);
+ rctl &= ~E1000_RCTL_LBM_TCVR;
+ rctl |= E1000_RCTL_LBM_MAC;
+ E1000_WRITE_REG(hw, E1000_RCTL, rctl);
}
/*
@@ -3797,13 +3867,24 @@ igb_intr_tx_other(void *arg1, void *arg2)
igb_intr_tx_work(&igb->tx_rings[0]);
/*
- * Need check cause bits and only link change will
- * be processed
+ * Check for "other" causes.
*/
if (icr & E1000_ICR_LSC) {
igb_intr_link_work(igb);
}
+ /*
+ * The DOUTSYNC bit indicates a tx packet dropped because
+ * DMA engine gets "out of sync". There isn't a real fix
+ * for this. The Intel recommendation is to count the number
+ * of occurrences so user can detect when it is happening.
+ * The issue is non-fatal and there's no recovery action
+ * available.
+ */
+ if (icr & E1000_ICR_DOUTSYNC) {
+ IGB_STAT(igb->dout_sync);
+ }
+
return (DDI_INTR_CLAIMED);
}
diff --git a/usr/src/uts/common/io/igb/igb_osdep.c b/usr/src/uts/common/io/igb/igb_osdep.c
index 99151cd10f..c17cf9d419 100644
--- a/usr/src/uts/common/io/igb/igb_osdep.c
+++ b/usr/src/uts/common/io/igb/igb_osdep.c
@@ -60,39 +60,26 @@ e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
}
/*
- * The real intent of this routine is to return the value from pci-e
- * config space at offset reg into the capability space.
- * ICH devices are "PCI Express"-ish. They have a configuration space,
- * but do not contain PCI Express Capability registers, so this returns
- * the equivalent of "not supported"
+ * Return the 16-bit value from pci-e config space at offset reg into the pci-e
+ * capability block.
*/
int32_t
e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
{
- *value = pci_config_get16(OS_DEP(hw)->cfg_handle,
- PCI_EX_CONF_CAP + reg);
+ uint32_t pcie_cap = PCI_EX_CONF_CAP; /* default */
- return (0);
-}
-
-/*
- * Enables PCI-Express master access.
- *
- * hw: Struct containing variables accessed by shared code
- *
- * returns: - none.
- */
-void
-e1000_enable_pciex_master(struct e1000_hw *hw)
-{
- uint32_t ctrl;
+ switch (hw->mac.type) {
+ case e1000_82575:
+ pcie_cap = 0xa0;
+ break;
+ case e1000_82576:
+ pcie_cap = 0xa0;
+ break;
+ }
- if (hw->bus.type != e1000_bus_type_pci_express)
- return;
+ *value = pci_config_get16(OS_DEP(hw)->cfg_handle, (pcie_cap + reg));
- ctrl = E1000_READ_REG(hw, E1000_CTRL);
- ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
- E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ return (0);
}
/*
diff --git a/usr/src/uts/common/io/igb/igb_stat.c b/usr/src/uts/common/io/igb/igb_stat.c
index 809fb88661..a16d8bec3f 100644
--- a/usr/src/uts/common/io/igb/igb_stat.c
+++ b/usr/src/uts/common/io/igb/igb_stat.c
@@ -1,7 +1,7 @@
/*
* CDDL HEADER START
*
- * Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
@@ -22,12 +22,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDL.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "igb_sw.h"
/*
@@ -57,10 +55,10 @@ igb_update_stats(kstat_t *ks, int rw)
* Basic information.
*/
igb_ks->link_speed.value.ui64 = igb->link_speed;
-
-#ifdef IGB_DEBUG
igb_ks->reset_count.value.ui64 = igb->reset_count;
+ igb_ks->dout_sync.value.ui64 = igb->dout_sync;
+#ifdef IGB_DEBUG
igb_ks->rx_frame_error.value.ui64 = 0;
igb_ks->rx_cksum_error.value.ui64 = 0;
igb_ks->rx_exceed_pkt.value.ui64 = 0;
@@ -175,10 +173,12 @@ igb_init_stats(igb_t *igb)
*/
kstat_named_init(&igb_ks->link_speed, "link_speed",
KSTAT_DATA_UINT64);
-
-#ifdef IGB_DEBUG
kstat_named_init(&igb_ks->reset_count, "reset_count",
KSTAT_DATA_UINT64);
+ kstat_named_init(&igb_ks->dout_sync, "DMA_out_sync",
+ KSTAT_DATA_UINT64);
+
+#ifdef IGB_DEBUG
kstat_named_init(&igb_ks->rx_frame_error, "rx_frame_error",
KSTAT_DATA_UINT64);
kstat_named_init(&igb_ks->rx_cksum_error, "rx_cksum_error",
diff --git a/usr/src/uts/common/io/igb/igb_sw.h b/usr/src/uts/common/io/igb/igb_sw.h
index 4cd1045c16..5f7c977f0b 100644
--- a/usr/src/uts/common/io/igb/igb_sw.h
+++ b/usr/src/uts/common/io/igb/igb_sw.h
@@ -183,8 +183,8 @@ extern "C" {
#define ATTACH_PROGRESS_ALLOC_RINGS 0x0010 /* Rings allocated */
#define ATTACH_PROGRESS_ADD_INTR 0x0020 /* Intr handlers added */
#define ATTACH_PROGRESS_LOCKS 0x0040 /* Locks initialized */
-#define ATTACH_PROGRESS_INIT 0x0080 /* Device initialized */
-#define ATTACH_PROGRESS_INIT_RINGS 0x0100 /* Rings initialized */
+#define ATTACH_PROGRESS_INIT_ADAPTER 0x0080 /* Adapter initialized */
+#define ATTACH_PROGRESS_ALLOC_DMA 0x0100 /* DMA resources allocated */
#define ATTACH_PROGRESS_STATS 0x0200 /* Kstats created */
#define ATTACH_PROGRESS_NDD 0x0400 /* NDD initialized */
#define ATTACH_PROGRESS_MAC 0x0800 /* MAC registered */
@@ -364,6 +364,7 @@ typedef struct adapter_info {
igb_nic_func_t setup_msix; /* set up msi-x vectors */
/* capabilities */
uint32_t flags; /* capability flags */
+ uint32_t rxdctl_mask; /* mask for RXDCTL register */
} adapter_info_t;
/*
@@ -628,7 +629,7 @@ typedef struct igb_rx_ring {
#endif
struct igb *igb; /* Pointer to igb struct */
- mac_ring_handle_t ring_handle; /* call back ring handle */
+ mac_ring_handle_t ring_handle; /* call back ring handle */
uint32_t group_index; /* group index */
uint64_t ring_gen_num;
} igb_rx_ring_t;
@@ -661,6 +662,7 @@ typedef struct igb {
uint32_t attach_progress;
uint32_t loopback_mode;
uint32_t max_frame_size;
+ uint32_t dout_sync;
uint32_t mr_enable; /* Enable multiple rings */
uint32_t vmdq_mode; /* Mode of VMDq */
@@ -693,6 +695,7 @@ typedef struct igb {
boolean_t rx_hcksum_enable; /* Rx h/w cksum offload */
uint32_t rx_copy_thresh; /* Rx copy threshold */
uint32_t rx_limit_per_intr; /* Rx pkts per interrupt */
+
uint32_t intr_throttling[MAX_NUM_EITR];
uint32_t intr_force;
@@ -740,9 +743,9 @@ typedef struct igb {
typedef struct igb_stat {
kstat_named_t link_speed; /* Link Speed */
-#ifdef IGB_DEBUG
kstat_named_t reset_count; /* Reset Count */
-
+ kstat_named_t dout_sync; /* DMA out of sync */
+#ifdef IGB_DEBUG
kstat_named_t rx_frame_error; /* Rx Error in Packet */
kstat_named_t rx_cksum_error; /* Rx Checksum Error */
kstat_named_t rx_exceed_pkt; /* Rx Exceed Max Pkt Count */
@@ -810,7 +813,6 @@ typedef struct igb_stat {
/*
* Function prototypes in e1000_osdep.c
*/
-void e1000_enable_pciex_master(struct e1000_hw *);
void e1000_rar_clear(struct e1000_hw *hw, uint32_t);
void e1000_rar_set_vmdq(struct e1000_hw *hw, const uint8_t *, uint32_t,
uint32_t, uint8_t);