Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/e1000/if_em.c
Show All 26 Lines | /****************************************************************************** | ||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
POSSIBILITY OF SUCH DAMAGE. | POSSIBILITY OF SUCH DAMAGE. | ||||
******************************************************************************/ | ******************************************************************************/ | ||||
/*$FreeBSD$*/ | /*$FreeBSD$*/ | ||||
#include "opt_em.h" | |||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#ifdef HAVE_KERNEL_OPTION_HEADERS | #ifdef HAVE_KERNEL_OPTION_HEADERS | ||||
#include "opt_device_polling.h" | #include "opt_device_polling.h" | ||||
#endif | #endif | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
▲ Show 20 Lines • Show All 251 Lines • ▼ Show 20 Lines | |||||
/* MSIX handlers */ | /* MSIX handlers */ | ||||
static void em_msix_tx(void *); | static void em_msix_tx(void *); | ||||
static void em_msix_rx(void *); | static void em_msix_rx(void *); | ||||
static void em_msix_link(void *); | static void em_msix_link(void *); | ||||
static void em_handle_tx(void *context, int pending); | static void em_handle_tx(void *context, int pending); | ||||
static void em_handle_rx(void *context, int pending); | static void em_handle_rx(void *context, int pending); | ||||
static void em_handle_link(void *context, int pending); | static void em_handle_link(void *context, int pending); | ||||
#ifdef EM_MULTIQUEUE | |||||
static void em_enable_vectors_82574(struct adapter *); | |||||
#endif | |||||
static void em_set_sysctl_value(struct adapter *, const char *, | static void em_set_sysctl_value(struct adapter *, const char *, | ||||
const char *, int *, int); | const char *, int *, int); | ||||
static int em_set_flowcntl(SYSCTL_HANDLER_ARGS); | static int em_set_flowcntl(SYSCTL_HANDLER_ARGS); | ||||
static int em_sysctl_eee(SYSCTL_HANDLER_ARGS); | static int em_sysctl_eee(SYSCTL_HANDLER_ARGS); | ||||
static __inline void em_rx_discard(struct rx_ring *, int); | static __inline void em_rx_discard(struct rx_ring *, int); | ||||
#ifdef DEVICE_POLLING | #ifdef DEVICE_POLLING | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | |||||
static int em_debug_sbp = FALSE; | static int em_debug_sbp = FALSE; | ||||
SYSCTL_INT(_hw_em, OID_AUTO, sbp, CTLFLAG_RDTUN, &em_debug_sbp, 0, | SYSCTL_INT(_hw_em, OID_AUTO, sbp, CTLFLAG_RDTUN, &em_debug_sbp, 0, | ||||
"Show bad packets in promiscuous mode"); | "Show bad packets in promiscuous mode"); | ||||
static int em_enable_msix = TRUE; | static int em_enable_msix = TRUE; | ||||
SYSCTL_INT(_hw_em, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &em_enable_msix, 0, | SYSCTL_INT(_hw_em, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &em_enable_msix, 0, | ||||
"Enable MSI-X interrupts"); | "Enable MSI-X interrupts"); | ||||
#ifdef EM_MULTIQUEUE | |||||
static int em_num_queues = 2; | |||||
SYSCTL_INT(_hw_em, OID_AUTO, num_queues, CTLFLAG_RDTUN, &em_num_queues, 0, | |||||
"82574 only: Number of queues to configure, 0 indicates autoconfigure"); | |||||
#endif | |||||
/* How many packets rxeof tries to clean at a time */ | /* How many packets rxeof tries to clean at a time */ | ||||
static int em_rx_process_limit = 100; | static int em_rx_process_limit = 100; | ||||
SYSCTL_INT(_hw_em, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_em, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, | ||||
&em_rx_process_limit, 0, | &em_rx_process_limit, 0, | ||||
"Maximum number of received packets to process " | "Maximum number of received packets to process " | ||||
"at a time, -1 means unlimited"); | "at a time, -1 means unlimited"); | ||||
/* Energy efficient ethernet - default to OFF */ | /* Energy efficient ethernet - default to OFF */ | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | if ((pci_vendor_id == ent->vendor_id) && | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
ent++; | ent++; | ||||
} | } | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
#ifdef EM_MULTIQUEUE | |||||
/* | |||||
* 82574 only: | |||||
* Write a new value to the EEPROM increasing the number of MSIX | |||||
* vectors from 3 to 5, for proper multiqueue support. | |||||
*/ | |||||
static void | |||||
em_enable_vectors_82574(struct adapter *adapter) | |||||
{ | |||||
struct e1000_hw *hw = &adapter->hw; | |||||
device_t dev = adapter->dev; | |||||
u16 edata; | |||||
e1000_read_nvm(hw, EM_NVM_PCIE_CTRL, 1, &edata); | |||||
printf("Current cap: %#06x\n", edata); | |||||
if (((edata & EM_NVM_MSIX_N_MASK) >> EM_NVM_MSIX_N_SHIFT) != 4 | |||||
&& adapter->num_queues > 1) { | |||||
device_printf(dev, "Writing to eeprom: increasing " | |||||
"reported MSIX vectors from 3 to 5...\n"); | |||||
edata &= ~(EM_NVM_MSIX_N_MASK); | |||||
edata |= 4 << EM_NVM_MSIX_N_SHIFT; | |||||
e1000_write_nvm(hw, EM_NVM_PCIE_CTRL, 1, &edata); | |||||
e1000_update_nvm_checksum(hw); | |||||
device_printf(dev, "Writing to eeprom: done\n"); | |||||
} | |||||
} | |||||
#endif | |||||
/********************************************************************* | /********************************************************************* | ||||
* Device initialization routine | * Device initialization routine | ||||
* | * | ||||
* The attach entry point is called when the driver is being loaded. | * The attach entry point is called when the driver is being loaded. | ||||
* This routine identifies the type of hardware, allocates all resources | * This routine identifies the type of hardware, allocates all resources | ||||
* and initializes the hardware. | * and initializes the hardware. | ||||
* | * | ||||
* return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | em_attach(device_t dev) | ||||
/* Do Shared Code initialization */ | /* Do Shared Code initialization */ | ||||
if (e1000_setup_init_funcs(hw, TRUE)) { | if (e1000_setup_init_funcs(hw, TRUE)) { | ||||
device_printf(dev, "Setup of Shared code failed\n"); | device_printf(dev, "Setup of Shared code failed\n"); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto err_pci; | goto err_pci; | ||||
} | } | ||||
/* | |||||
* Setup MSI/X or MSI if PCI Express | |||||
*/ | |||||
adapter->msix = em_setup_msix(adapter); | |||||
e1000_get_bus_info(hw); | e1000_get_bus_info(hw); | ||||
/* Set up some sysctls for the tunable interrupt delays */ | /* Set up some sysctls for the tunable interrupt delays */ | ||||
em_add_int_delay_sysctl(adapter, "rx_int_delay", | em_add_int_delay_sysctl(adapter, "rx_int_delay", | ||||
"receive interrupt delay in usecs", &adapter->rx_int_delay, | "receive interrupt delay in usecs", &adapter->rx_int_delay, | ||||
E1000_REGISTER(hw, E1000_RDTR), em_rx_int_delay_dflt); | E1000_REGISTER(hw, E1000_RDTR), em_rx_int_delay_dflt); | ||||
em_add_int_delay_sysctl(adapter, "tx_int_delay", | em_add_int_delay_sysctl(adapter, "tx_int_delay", | ||||
"transmit interrupt delay in usecs", &adapter->tx_int_delay, | "transmit interrupt delay in usecs", &adapter->tx_int_delay, | ||||
▲ Show 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | |||||
**********************************************************************/ | **********************************************************************/ | ||||
static int | static int | ||||
em_mq_start_locked(if_t ifp, struct tx_ring *txr, struct mbuf *m) | em_mq_start_locked(if_t ifp, struct tx_ring *txr, struct mbuf *m) | ||||
{ | { | ||||
struct adapter *adapter = txr->adapter; | struct adapter *adapter = txr->adapter; | ||||
struct mbuf *next; | struct mbuf *next; | ||||
int err = 0, enq = 0; | int err = 0, enq = 0; | ||||
EM_TX_LOCK_ASSERT(txr); | |||||
if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != | if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != | ||||
IFF_DRV_RUNNING || adapter->link_active == 0) { | IFF_DRV_RUNNING || adapter->link_active == 0) { | ||||
if (m != NULL) | if (m != NULL) | ||||
err = drbr_enqueue(ifp, txr->br, m); | err = drbr_enqueue(ifp, txr->br, m); | ||||
return (err); | return (err); | ||||
} | } | ||||
enq = 0; | enq = 0; | ||||
Show All 38 Lines | |||||
/* | /* | ||||
** Multiqueue capable stack interface | ** Multiqueue capable stack interface | ||||
*/ | */ | ||||
static int | static int | ||||
em_mq_start(if_t ifp, struct mbuf *m) | em_mq_start(if_t ifp, struct mbuf *m) | ||||
{ | { | ||||
struct adapter *adapter = if_getsoftc(ifp); | struct adapter *adapter = if_getsoftc(ifp); | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
int error; | int i, error; | ||||
if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) | |||||
i = m->m_pkthdr.flowid % adapter->num_queues; | |||||
else | |||||
i = curcpu % adapter->num_queues; | |||||
txr = &adapter->tx_rings[i]; | |||||
if (EM_TX_TRYLOCK(txr)) { | if (EM_TX_TRYLOCK(txr)) { | ||||
error = em_mq_start_locked(ifp, txr, m); | error = em_mq_start_locked(ifp, txr, m); | ||||
EM_TX_UNLOCK(txr); | EM_TX_UNLOCK(txr); | ||||
} else | } else | ||||
error = drbr_enqueue(ifp, txr->br, m); | error = drbr_enqueue(ifp, txr->br, m); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,455 Lines • ▼ Show 20 Lines | if (adapter->memory == NULL) { | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
adapter->osdep.mem_bus_space_tag = | adapter->osdep.mem_bus_space_tag = | ||||
rman_get_bustag(adapter->memory); | rman_get_bustag(adapter->memory); | ||||
adapter->osdep.mem_bus_space_handle = | adapter->osdep.mem_bus_space_handle = | ||||
rman_get_bushandle(adapter->memory); | rman_get_bushandle(adapter->memory); | ||||
adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; | adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; | ||||
/* Default to a single queue */ | |||||
adapter->num_queues = 1; | |||||
/* | |||||
* Setup MSI/X or MSI if PCI Express | |||||
*/ | |||||
adapter->msix = em_setup_msix(adapter); | |||||
adapter->hw.back = &adapter->osdep; | adapter->hw.back = &adapter->osdep; | ||||
return (0); | return (0); | ||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Setup the Legacy or MSI Interrupt handler | * Setup the Legacy or MSI Interrupt handler | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | for (int i = 0; i < adapter->num_queues; i++, txr++, rxr++) { | ||||
} | } | ||||
#if __FreeBSD_version >= 800504 | #if __FreeBSD_version >= 800504 | ||||
bus_describe_intr(dev, rxr->res, rxr->tag, "rx %d", i); | bus_describe_intr(dev, rxr->res, rxr->tag, "rx %d", i); | ||||
#endif | #endif | ||||
rxr->msix = vector++; /* NOTE increment vector for TX */ | rxr->msix = vector++; /* NOTE increment vector for TX */ | ||||
TASK_INIT(&rxr->rx_task, 0, em_handle_rx, rxr); | TASK_INIT(&rxr->rx_task, 0, em_handle_rx, rxr); | ||||
rxr->tq = taskqueue_create_fast("em_rxq", M_NOWAIT, | rxr->tq = taskqueue_create_fast("em_rxq", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &rxr->tq); | taskqueue_thread_enqueue, &rxr->tq); | ||||
taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq", | taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq (qid %d)", | ||||
device_get_nameunit(adapter->dev)); | device_get_nameunit(adapter->dev), i); | ||||
/* | /* | ||||
** Set the bit to enable interrupt | ** Set the bit to enable interrupt | ||||
** in E1000_IMS -- bits 20 and 21 | ** in E1000_IMS -- bits 20 and 21 | ||||
** are for RX0 and RX1, note this has | ** are for RX0 and RX1, note this has | ||||
** NOTHING to do with the MSIX vector | ** NOTHING to do with the MSIX vector | ||||
*/ | */ | ||||
rxr->ims = 1 << (20 + i); | rxr->ims = 1 << (20 + i); | ||||
adapter->ivars |= (8 | rxr->msix) << (i * 4); | adapter->ivars |= (8 | rxr->msix) << (i * 4); | ||||
Show All 16 Lines | #endif | ||||
} | } | ||||
#if __FreeBSD_version >= 800504 | #if __FreeBSD_version >= 800504 | ||||
bus_describe_intr(dev, txr->res, txr->tag, "tx %d", i); | bus_describe_intr(dev, txr->res, txr->tag, "tx %d", i); | ||||
#endif | #endif | ||||
txr->msix = vector++; /* Increment vector for next pass */ | txr->msix = vector++; /* Increment vector for next pass */ | ||||
TASK_INIT(&txr->tx_task, 0, em_handle_tx, txr); | TASK_INIT(&txr->tx_task, 0, em_handle_tx, txr); | ||||
txr->tq = taskqueue_create_fast("em_txq", M_NOWAIT, | txr->tq = taskqueue_create_fast("em_txq", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &txr->tq); | taskqueue_thread_enqueue, &txr->tq); | ||||
taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq", | taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq (qid %d)", | ||||
device_get_nameunit(adapter->dev)); | device_get_nameunit(adapter->dev), i); | ||||
/* | /* | ||||
** Set the bit to enable interrupt | ** Set the bit to enable interrupt | ||||
** in E1000_IMS -- bits 22 and 23 | ** in E1000_IMS -- bits 22 and 23 | ||||
** are for TX0 and TX1, note this has | ** are for TX0 and TX1, note this has | ||||
** NOTHING to do with the MSIX vector | ** NOTHING to do with the MSIX vector | ||||
*/ | */ | ||||
txr->ims = 1 << (22 + i); | txr->ims = 1 << (22 + i); | ||||
adapter->ivars |= (8 | txr->msix) << (8 + (i * 4)); | adapter->ivars |= (8 | txr->msix) << (8 + (i * 4)); | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | |||||
* Setup MSI or MSI/X | * Setup MSI or MSI/X | ||||
*/ | */ | ||||
static int | static int | ||||
em_setup_msix(struct adapter *adapter) | em_setup_msix(struct adapter *adapter) | ||||
{ | { | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int val; | int val; | ||||
/* Nearly always going to use one queue */ | |||||
adapter->num_queues = 1; | |||||
/* | /* | ||||
** Setup MSI/X for Hartwell: tests have shown | ** Try using MSI-X for Hartwell adapters | ||||
** use of two queues to be unstable, and to | |||||
** provide no great gain anyway, so we simply | |||||
** seperate the interrupts and use a single queue. | |||||
*/ | */ | ||||
if ((adapter->hw.mac.type == e1000_82574) && | if ((adapter->hw.mac.type == e1000_82574) && | ||||
(em_enable_msix == TRUE)) { | (em_enable_msix == TRUE)) { | ||||
#ifdef EM_MULTIQUEUE | |||||
adapter->num_queues = (em_num_queues == 1) ? 1 : 2; | |||||
if (adapter->num_queues > 1) | |||||
em_enable_vectors_82574(adapter); | |||||
#endif | |||||
/* Map the MSIX BAR */ | /* Map the MSIX BAR */ | ||||
int rid = PCIR_BAR(EM_MSIX_BAR); | int rid = PCIR_BAR(EM_MSIX_BAR); | ||||
adapter->msix_mem = bus_alloc_resource_any(dev, | adapter->msix_mem = bus_alloc_resource_any(dev, | ||||
SYS_RES_MEMORY, &rid, RF_ACTIVE); | SYS_RES_MEMORY, &rid, RF_ACTIVE); | ||||
if (adapter->msix_mem == NULL) { | if (adapter->msix_mem == NULL) { | ||||
/* May not be enabled */ | /* May not be enabled */ | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Unable to map MSIX table \n"); | "Unable to map MSIX table \n"); | ||||
goto msi; | goto msi; | ||||
} | } | ||||
val = pci_msix_count(dev); | val = pci_msix_count(dev); | ||||
/* We only need/want 3 vectors */ | |||||
#ifdef EM_MULTIQUEUE | |||||
/* We need 5 vectors in the multiqueue case */ | |||||
if (adapter->num_queues == 2) { | |||||
if (val >= 5) | |||||
val = 5; | |||||
else { | |||||
adapter->num_queues = 1; | |||||
device_printf(adapter->dev, | |||||
"Insufficient MSIX vectors for >1 queue, " | |||||
"using single queue...\n"); | |||||
goto msix_one; | |||||
} | |||||
} else | |||||
msix_one: | |||||
#endif | |||||
if (val >= 3) | if (val >= 3) | ||||
val = 3; | val = 3; | ||||
else { | else { | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"MSIX: insufficient vectors, using MSI\n"); | "Insufficient MSIX vectors, using MSI\n"); | ||||
goto msi; | goto msi; | ||||
} | } | ||||
if ((pci_alloc_msix(dev, &val) == 0) && (val == 3)) { | if ((pci_alloc_msix(dev, &val) == 0)) { | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Using MSIX interrupts " | "Using MSIX interrupts " | ||||
"with %d vectors\n", val); | "with %d vectors\n", val); | ||||
return (val); | return (val); | ||||
} | } | ||||
/* | /* | ||||
** If MSIX alloc failed or provided us with | ** If MSIX alloc failed or provided us with | ||||
** less than needed, free and fall through to MSI | ** less than needed, free and fall through to MSI | ||||
*/ | */ | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
} | } | ||||
msi: | msi: | ||||
if (adapter->msix_mem != NULL) { | if (adapter->msix_mem != NULL) { | ||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
PCIR_BAR(EM_MSIX_BAR), adapter->msix_mem); | PCIR_BAR(EM_MSIX_BAR), adapter->msix_mem); | ||||
adapter->msix_mem = NULL; | adapter->msix_mem = NULL; | ||||
} | } | ||||
val = 1; | val = 1; | ||||
if (pci_alloc_msi(dev, &val) == 0) { | if (pci_alloc_msi(dev, &val) == 0) { | ||||
device_printf(adapter->dev,"Using an MSI interrupt\n"); | device_printf(adapter->dev, "Using an MSI interrupt\n"); | ||||
return (val); | return (val); | ||||
} | } | ||||
/* Should only happen due to manual configuration */ | /* Should only happen due to manual configuration */ | ||||
device_printf(adapter->dev,"No MSI/MSIX using a Legacy IRQ\n"); | device_printf(adapter->dev,"No MSI/MSIX using a Legacy IRQ\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,511 Lines • ▼ Show 20 Lines | if (hw->mac.type == e1000_82574) { | ||||
for (int i = 0; i < 4; i++) | for (int i = 0; i < 4; i++) | ||||
E1000_WRITE_REG(hw, E1000_EITR_82574(i), | E1000_WRITE_REG(hw, E1000_EITR_82574(i), | ||||
DEFAULT_ITR); | DEFAULT_ITR); | ||||
/* Disable accelerated acknowledge */ | /* Disable accelerated acknowledge */ | ||||
E1000_WRITE_REG(hw, E1000_RFCTL, E1000_RFCTL_ACK_DIS); | E1000_WRITE_REG(hw, E1000_RFCTL, E1000_RFCTL_ACK_DIS); | ||||
} | } | ||||
rxcsum = E1000_READ_REG(hw, E1000_RXCSUM); | rxcsum = E1000_READ_REG(hw, E1000_RXCSUM); | ||||
if (if_getcapenable(ifp) & IFCAP_RXCSUM) | if (if_getcapenable(ifp) & IFCAP_RXCSUM) { | ||||
#ifdef EM_MULTIQUEUE | |||||
rxcsum |= E1000_RXCSUM_TUOFL | | |||||
E1000_RXCSUM_IPOFL | | |||||
E1000_RXCSUM_PCSD; | |||||
#else | |||||
rxcsum |= E1000_RXCSUM_TUOFL; | rxcsum |= E1000_RXCSUM_TUOFL; | ||||
else | #endif | ||||
} else | |||||
rxcsum &= ~E1000_RXCSUM_TUOFL; | rxcsum &= ~E1000_RXCSUM_TUOFL; | ||||
E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum); | E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum); | ||||
#ifdef EM_MULTIQUEUE | |||||
if (adapter->num_queues > 1) { | |||||
uint32_t rss_key[10]; | |||||
uint32_t reta; | |||||
int i; | |||||
/* | /* | ||||
* Configure RSS key | |||||
*/ | |||||
arc4rand(rss_key, sizeof(rss_key), 0); | |||||
for (i = 0; i < 10; ++i) | |||||
E1000_WRITE_REG_ARRAY(hw,E1000_RSSRK(0), i, rss_key[i]); | |||||
/* | |||||
* Configure RSS redirect table in following fashion: | |||||
* (hash & ring_cnt_mask) == rdr_table[(hash & rdr_table_mask)] | |||||
*/ | |||||
reta = 0; | |||||
for (i = 0; i < 4; ++i) { | |||||
uint32_t q; | |||||
q = (i % 2) << 7; | |||||
reta |= q << (8 * i); | |||||
} | |||||
for (i = 0; i < 32; ++i) | |||||
E1000_WRITE_REG(hw, E1000_RETA(i), reta); | |||||
E1000_WRITE_REG(hw, E1000_MRQC, E1000_MRQC_RSS_ENABLE_2Q | | |||||
E1000_MRQC_RSS_FIELD_IPV4_TCP | | |||||
E1000_MRQC_RSS_FIELD_IPV4 | | |||||
E1000_MRQC_RSS_FIELD_IPV6_TCP_EX | | |||||
E1000_MRQC_RSS_FIELD_IPV6_EX | | |||||
E1000_MRQC_RSS_FIELD_IPV6 | | |||||
E1000_MRQC_RSS_FIELD_IPV6_TCP); | |||||
} | |||||
#endif | |||||
/* | |||||
** XXX TEMPORARY WORKAROUND: on some systems with 82573 | ** XXX TEMPORARY WORKAROUND: on some systems with 82573 | ||||
** long latencies are observed, like Lenovo X60. This | ** long latencies are observed, like Lenovo X60. This | ||||
** change eliminates the problem, but since having positive | ** change eliminates the problem, but since having positive | ||||
** values in RDTR is a known source of problems on other | ** values in RDTR is a known source of problems on other | ||||
** platforms another solution is being sought. | ** platforms another solution is being sought. | ||||
*/ | */ | ||||
if (hw->mac.type == e1000_82573) | if (hw->mac.type == e1000_82573) | ||||
E1000_WRITE_REG(hw, E1000_RDTR, 0x20); | E1000_WRITE_REG(hw, E1000_RDTR, 0x20); | ||||
Show All 16 Lines | #ifdef DEV_NETMAP | ||||
*/ | */ | ||||
if (if_getcapenable(ifp) & IFCAP_NETMAP) { | if (if_getcapenable(ifp) & IFCAP_NETMAP) { | ||||
struct netmap_adapter *na = netmap_getna(adapter->ifp); | struct netmap_adapter *na = netmap_getna(adapter->ifp); | ||||
rdt -= nm_kr_rxspace(&na->rx_rings[i]); | rdt -= nm_kr_rxspace(&na->rx_rings[i]); | ||||
} | } | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
E1000_WRITE_REG(hw, E1000_RDT(i), rdt); | E1000_WRITE_REG(hw, E1000_RDT(i), rdt); | ||||
} | } | ||||
/* Set PTHRESH for improved jumbo performance */ | /* Set PTHRESH for improved jumbo performance */ | ||||
if (((adapter->hw.mac.type == e1000_ich9lan) || | if (((adapter->hw.mac.type == e1000_ich9lan) || | ||||
(adapter->hw.mac.type == e1000_pch2lan) || | (adapter->hw.mac.type == e1000_pch2lan) || | ||||
(adapter->hw.mac.type == e1000_ich10lan)) && | (adapter->hw.mac.type == e1000_ich10lan)) && | ||||
(if_getmtu(ifp) > ETHERMTU)) { | (if_getmtu(ifp) > ETHERMTU)) { | ||||
u32 rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0)); | u32 rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0)); | ||||
E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 3); | E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 3); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,443 Lines • Show Last 20 Lines |