Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/e1000/if_em.c
Show First 20 Lines • Show All 404 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/********************************************************************* | /********************************************************************* | ||||
* Tunable default values. | * Tunable default values. | ||||
*********************************************************************/ | *********************************************************************/ | ||||
#define EM_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) | #define EM_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) | ||||
#define EM_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) | #define EM_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) | ||||
#define M_TSO_LEN 66 | |||||
#define MAX_INTS_PER_SEC 8000 | #define MAX_INTS_PER_SEC 8000 | ||||
#define DEFAULT_ITR (1000000000/(MAX_INTS_PER_SEC * 256)) | #define DEFAULT_ITR (1000000000/(MAX_INTS_PER_SEC * 256)) | ||||
/* Allow common code without TSO */ | /* Allow common code without TSO */ | ||||
#ifndef CSUM_TSO | #ifndef CSUM_TSO | ||||
#define CSUM_TSO 0 | #define CSUM_TSO 0 | ||||
#endif | #endif | ||||
#define TSO_WORKAROUND 4 | |||||
static SYSCTL_NODE(_hw, OID_AUTO, em, CTLFLAG_RD, 0, "EM driver parameters"); | static SYSCTL_NODE(_hw, OID_AUTO, em, CTLFLAG_RD, 0, "EM driver parameters"); | ||||
static int em_disable_crc_stripping = 0; | static int em_disable_crc_stripping = 0; | ||||
SYSCTL_INT(_hw_em, OID_AUTO, disable_crc_stripping, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_em, OID_AUTO, disable_crc_stripping, CTLFLAG_RDTUN, | ||||
&em_disable_crc_stripping, 0, "Disable CRC Stripping"); | &em_disable_crc_stripping, 0, "Disable CRC Stripping"); | ||||
static int em_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); | static int em_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); | ||||
static int em_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); | static int em_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
extern struct if_txrx igb_txrx; | extern struct if_txrx igb_txrx; | ||||
extern struct if_txrx em_txrx; | extern struct if_txrx em_txrx; | ||||
extern struct if_txrx lem_txrx; | extern struct if_txrx lem_txrx; | ||||
static struct if_shared_ctx em_sctx_init = { | static struct if_shared_ctx em_sctx_init = { | ||||
.isc_magic = IFLIB_MAGIC, | .isc_magic = IFLIB_MAGIC, | ||||
.isc_q_align = PAGE_SIZE, | .isc_q_align = PAGE_SIZE, | ||||
.isc_tx_maxsize = EM_TSO_SIZE, | .isc_tx_maxsize = EM_TSO_SIZE + sizeof(struct ether_vlan_header), | ||||
.isc_tx_maxsegsize = PAGE_SIZE, | .isc_tx_maxsegsize = PAGE_SIZE, | ||||
.isc_tso_maxsize = EM_TSO_SIZE + sizeof(struct ether_vlan_header), | |||||
.isc_tso_maxsegsize = EM_TSO_SEG_SIZE, | |||||
.isc_rx_maxsize = MJUM9BYTES, | .isc_rx_maxsize = MJUM9BYTES, | ||||
.isc_rx_nsegments = 1, | .isc_rx_nsegments = 1, | ||||
.isc_rx_maxsegsize = MJUM9BYTES, | .isc_rx_maxsegsize = MJUM9BYTES, | ||||
.isc_nfl = 1, | .isc_nfl = 1, | ||||
.isc_nrxqs = 1, | .isc_nrxqs = 1, | ||||
.isc_ntxqs = 1, | .isc_ntxqs = 1, | ||||
.isc_admin_intrcnt = 1, | .isc_admin_intrcnt = 1, | ||||
.isc_vendor_info = em_vendor_info_array, | .isc_vendor_info = em_vendor_info_array, | ||||
▲ Show 20 Lines • Show All 195 Lines • ▼ Show 20 Lines | em_set_num_queues(if_ctx_t ctx) | ||||
default: | default: | ||||
maxqueues = 1; | maxqueues = 1; | ||||
break; | break; | ||||
} | } | ||||
return (maxqueues); | return (maxqueues); | ||||
} | } | ||||
#define LEM_CAPS \ | |||||
IFCAP_HWCSUM | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \ | |||||
IFCAP_VLAN_HWCSUM | IFCAP_WOL | IFCAP_VLAN_HWFILTER | |||||
#define EM_CAPS \ | #define EM_CAPS \ | ||||
IFCAP_TSO4 | IFCAP_TXCSUM | IFCAP_LRO | IFCAP_RXCSUM | IFCAP_VLAN_HWFILTER | IFCAP_WOL_MAGIC | \ | IFCAP_HWCSUM | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \ | ||||
IFCAP_WOL_MCAST | IFCAP_WOL | IFCAP_VLAN_HWTSO | IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING | \ | IFCAP_VLAN_HWCSUM | IFCAP_WOL | IFCAP_VLAN_HWFILTER | IFCAP_TSO4 | \ | ||||
IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO | IFCAP_VLAN_MTU; | IFCAP_LRO | IFCAP_VLAN_HWTSO | ||||
#define IGB_CAPS \ | #define IGB_CAPS \ | ||||
IFCAP_TSO4 | IFCAP_TXCSUM | IFCAP_LRO | IFCAP_RXCSUM | IFCAP_VLAN_HWFILTER | IFCAP_WOL_MAGIC | \ | IFCAP_HWCSUM | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \ | ||||
IFCAP_WOL_MCAST | IFCAP_WOL | IFCAP_VLAN_HWTSO | IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM | \ | IFCAP_VLAN_HWCSUM | IFCAP_WOL | IFCAP_VLAN_HWFILTER | IFCAP_TSO4 | \ | ||||
IFCAP_VLAN_HWTSO | IFCAP_VLAN_MTU | IFCAP_TXCSUM_IPV6 | IFCAP_HWCSUM_IPV6 | IFCAP_JUMBO_MTU; | IFCAP_LRO | IFCAP_VLAN_HWTSO | IFCAP_JUMBO_MTU | IFCAP_HWCSUM_IPV6; | ||||
/********************************************************************* | /********************************************************************* | ||||
* 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. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | em_if_attach_pre(if_ctx_t ctx) | ||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | ||||
OID_AUTO, "rs_dump", CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | OID_AUTO, "rs_dump", CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | ||||
em_get_rs, "I", "Dump RS indexes"); | em_get_rs, "I", "Dump RS indexes"); | ||||
/* Determine hardware and mac info */ | /* Determine hardware and mac info */ | ||||
em_identify_hardware(ctx); | em_identify_hardware(ctx); | ||||
/* Set isc_msix_bar */ | |||||
scctx->isc_msix_bar = PCIR_BAR(EM_MSIX_BAR); | scctx->isc_msix_bar = PCIR_BAR(EM_MSIX_BAR); | ||||
scctx->isc_tx_nsegments = EM_MAX_SCATTER; | scctx->isc_tx_nsegments = EM_MAX_SCATTER; | ||||
scctx->isc_tx_tso_segments_max = scctx->isc_tx_nsegments; | |||||
scctx->isc_tx_tso_size_max = EM_TSO_SIZE; | |||||
scctx->isc_tx_tso_segsize_max = EM_TSO_SEG_SIZE; | |||||
scctx->isc_nrxqsets_max = scctx->isc_ntxqsets_max = em_set_num_queues(ctx); | scctx->isc_nrxqsets_max = scctx->isc_ntxqsets_max = em_set_num_queues(ctx); | ||||
device_printf(dev, "attach_pre capping queues at %d\n", scctx->isc_ntxqsets_max); | device_printf(dev, "attach_pre capping queues at %d\n", scctx->isc_ntxqsets_max); | ||||
scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_IP_TSO; | |||||
if (adapter->hw.mac.type >= igb_mac_min) { | if (adapter->hw.mac.type >= igb_mac_min) { | ||||
int try_second_bar; | int try_second_bar; | ||||
scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] * sizeof(union e1000_adv_tx_desc), EM_DBA_ALIGN); | scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] * sizeof(union e1000_adv_tx_desc), EM_DBA_ALIGN); | ||||
scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] * sizeof(union e1000_adv_rx_desc), EM_DBA_ALIGN); | scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] * sizeof(union e1000_adv_rx_desc), EM_DBA_ALIGN); | ||||
scctx->isc_txd_size[0] = sizeof(union e1000_adv_tx_desc); | scctx->isc_txd_size[0] = sizeof(union e1000_adv_tx_desc); | ||||
scctx->isc_rxd_size[0] = sizeof(union e1000_adv_rx_desc); | scctx->isc_rxd_size[0] = sizeof(union e1000_adv_rx_desc); | ||||
scctx->isc_txrx = &igb_txrx; | scctx->isc_txrx = &igb_txrx; | ||||
scctx->isc_capenable = IGB_CAPS; | scctx->isc_tx_tso_segments_max = EM_MAX_SCATTER; | ||||
scctx->isc_tx_tso_size_max = EM_TSO_SIZE; | |||||
scctx->isc_tx_tso_segsize_max = EM_TSO_SEG_SIZE; | |||||
scctx->isc_capabilities = scctx->isc_capenable = IGB_CAPS; | |||||
scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_TSO | CSUM_IP6_TCP \ | scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_TSO | CSUM_IP6_TCP \ | ||||
| CSUM_IP6_UDP | CSUM_IP6_TCP; | | CSUM_IP6_UDP | CSUM_IP6_TCP; | ||||
if (adapter->hw.mac.type != e1000_82575) | if (adapter->hw.mac.type != e1000_82575) | ||||
scctx->isc_tx_csum_flags |= CSUM_SCTP | CSUM_IP6_SCTP; | scctx->isc_tx_csum_flags |= CSUM_SCTP | CSUM_IP6_SCTP; | ||||
/* | /* | ||||
** Some new devices, as with ixgbe, now may | ** Some new devices, as with ixgbe, now may | ||||
** use a different BAR, so we need to keep | ** use a different BAR, so we need to keep | ||||
** track of which is used. | ** track of which is used. | ||||
*/ | */ | ||||
try_second_bar = pci_read_config(dev, scctx->isc_msix_bar, 4); | try_second_bar = pci_read_config(dev, scctx->isc_msix_bar, 4); | ||||
if (try_second_bar == 0) | if (try_second_bar == 0) | ||||
scctx->isc_msix_bar += 4; | scctx->isc_msix_bar += 4; | ||||
} else if (adapter->hw.mac.type >= em_mac_min) { | } else if (adapter->hw.mac.type >= em_mac_min) { | ||||
scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0]* sizeof(struct e1000_tx_desc), EM_DBA_ALIGN); | scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0]* sizeof(struct e1000_tx_desc), EM_DBA_ALIGN); | ||||
scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] * sizeof(union e1000_rx_desc_extended), EM_DBA_ALIGN); | scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] * sizeof(union e1000_rx_desc_extended), EM_DBA_ALIGN); | ||||
scctx->isc_txd_size[0] = sizeof(struct e1000_tx_desc); | scctx->isc_txd_size[0] = sizeof(struct e1000_tx_desc); | ||||
scctx->isc_rxd_size[0] = sizeof(union e1000_rx_desc_extended); | scctx->isc_rxd_size[0] = sizeof(union e1000_rx_desc_extended); | ||||
scctx->isc_txrx = &em_txrx; | scctx->isc_txrx = &em_txrx; | ||||
scctx->isc_capenable = EM_CAPS; | scctx->isc_tx_tso_segments_max = EM_MAX_SCATTER; | ||||
scctx->isc_tx_tso_size_max = EM_TSO_SIZE; | |||||
scctx->isc_tx_tso_segsize_max = EM_TSO_SEG_SIZE; | |||||
scctx->isc_capabilities = scctx->isc_capenable = EM_CAPS; | |||||
/* | |||||
* For EM-class devices, don't enable IFCAP_{TSO4,VLAN_HWTSO} | |||||
* by default as we don't have workarounds for all associated | |||||
* silicon errata. E. g., with several MACs such as 82573E, | |||||
* TSO only works at Gigabit speed and otherwise can cause the | |||||
* hardware to hang (which also would be next to impossible to | |||||
* work around given that already queued TSO-using descriptors | |||||
* would need to be flushed and vlan(4) reconfigured at runtime | |||||
* in case of a link speed change). Moreover, MACs like 82579 | |||||
* still can hang at Gigabit even with all publicly documented | |||||
* TSO workarounds implemented. Generally, the penality of | |||||
* these workarounds is rather high and may involve copying | |||||
* mbuf data around so advantages of TSO lapse. Still, TSO may | |||||
* work for a few MACs of this class - at least when sticking | |||||
* with Gigabit - in which case users may enable TSO manually. | |||||
*/ | |||||
scctx->isc_capenable &= ~(IFCAP_TSO4 | IFCAP_VLAN_HWTSO); | |||||
scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_IP_TSO; | scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_IP_TSO; | ||||
} else { | } else { | ||||
scctx->isc_txqsizes[0] = roundup2((scctx->isc_ntxd[0] + 1) * sizeof(struct e1000_tx_desc), EM_DBA_ALIGN); | scctx->isc_txqsizes[0] = roundup2((scctx->isc_ntxd[0] + 1) * sizeof(struct e1000_tx_desc), EM_DBA_ALIGN); | ||||
scctx->isc_rxqsizes[0] = roundup2((scctx->isc_nrxd[0] + 1) * sizeof(struct e1000_rx_desc), EM_DBA_ALIGN); | scctx->isc_rxqsizes[0] = roundup2((scctx->isc_nrxd[0] + 1) * sizeof(struct e1000_rx_desc), EM_DBA_ALIGN); | ||||
scctx->isc_txd_size[0] = sizeof(struct e1000_tx_desc); | scctx->isc_txd_size[0] = sizeof(struct e1000_tx_desc); | ||||
scctx->isc_rxd_size[0] = sizeof(struct e1000_rx_desc); | scctx->isc_rxd_size[0] = sizeof(struct e1000_rx_desc); | ||||
scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_IP_TSO; | scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP; | ||||
scctx->isc_txrx = &lem_txrx; | scctx->isc_txrx = &lem_txrx; | ||||
scctx->isc_capenable = EM_CAPS; | scctx->isc_capabilities = scctx->isc_capenable = LEM_CAPS; | ||||
if (adapter->hw.mac.type < e1000_82543) | if (adapter->hw.mac.type < e1000_82543) | ||||
scctx->isc_capenable &= ~(IFCAP_HWCSUM|IFCAP_VLAN_HWCSUM); | scctx->isc_capenable &= ~(IFCAP_HWCSUM|IFCAP_VLAN_HWCSUM); | ||||
scctx->isc_tx_csum_flags = CSUM_TCP | CSUM_UDP | CSUM_IP_TSO; | |||||
scctx->isc_msix_bar = 0; | scctx->isc_msix_bar = 0; | ||||
} | } | ||||
/* Setup PCI resources */ | /* Setup PCI resources */ | ||||
if (em_allocate_pci_resources(ctx)) { | if (em_allocate_pci_resources(ctx)) { | ||||
device_printf(dev, "Allocation of PCI resources failed\n"); | device_printf(dev, "Allocation of PCI resources failed\n"); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto err_pci; | goto err_pci; | ||||
▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | em_if_attach_pre(if_ctx_t ctx) | ||||
/* Disable ULP support */ | /* Disable ULP support */ | ||||
e1000_disable_ulp_lpt_lp(hw, TRUE); | e1000_disable_ulp_lpt_lp(hw, TRUE); | ||||
/* | /* | ||||
* Get Wake-on-Lan and Management info for later use | * Get Wake-on-Lan and Management info for later use | ||||
*/ | */ | ||||
em_get_wakeup(ctx); | em_get_wakeup(ctx); | ||||
/* Enable only WOL MAGIC by default */ | |||||
scctx->isc_capenable &= ~IFCAP_WOL; | |||||
if (adapter->wol != 0) | |||||
scctx->isc_capenable |= IFCAP_WOL_MAGIC; | |||||
iflib_set_mac(ctx, hw->mac.addr); | iflib_set_mac(ctx, hw->mac.addr); | ||||
return (0); | return (0); | ||||
err_late: | err_late: | ||||
em_release_hw_control(adapter); | em_release_hw_control(adapter); | ||||
err_pci: | err_pci: | ||||
em_free_pci_resources(ctx); | em_free_pci_resources(ctx); | ||||
▲ Show 20 Lines • Show All 1,727 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
static int | static int | ||||
em_setup_interface(if_ctx_t ctx) | em_setup_interface(if_ctx_t ctx) | ||||
{ | { | ||||
struct ifnet *ifp = iflib_get_ifp(ctx); | struct ifnet *ifp = iflib_get_ifp(ctx); | ||||
struct adapter *adapter = iflib_get_softc(ctx); | struct adapter *adapter = iflib_get_softc(ctx); | ||||
if_softc_ctx_t scctx = adapter->shared; | if_softc_ctx_t scctx = adapter->shared; | ||||
uint64_t cap = 0; | |||||
INIT_DEBUGOUT("em_setup_interface: begin"); | INIT_DEBUGOUT("em_setup_interface: begin"); | ||||
/* TSO parameters */ | |||||
if_sethwtsomax(ifp, IP_MAXPACKET); | |||||
/* Take m_pullup(9)'s in em_xmit() w/ TSO into acount. */ | |||||
if_sethwtsomaxsegcount(ifp, EM_MAX_SCATTER - 5); | |||||
if_sethwtsomaxsegsize(ifp, EM_TSO_SEG_SIZE); | |||||
/* Single Queue */ | /* Single Queue */ | ||||
if (adapter->tx_num_queues == 1) { | if (adapter->tx_num_queues == 1) { | ||||
if_setsendqlen(ifp, scctx->isc_ntxd[0] - 1); | if_setsendqlen(ifp, scctx->isc_ntxd[0] - 1); | ||||
if_setsendqready(ifp); | if_setsendqready(ifp); | ||||
} | |||||
cap = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4; | |||||
cap |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO | IFCAP_VLAN_MTU; | |||||
/* | |||||
* Tell the upper layer(s) we | |||||
* support full VLAN capability | |||||
*/ | |||||
if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); | |||||
if_setcapabilitiesbit(ifp, cap, 0); | |||||
/* | |||||
* Don't turn this on by default, if vlans are | |||||
* created on another pseudo device (eg. lagg) | |||||
* then vlan events are not passed thru, breaking | |||||
* operation, but with HW FILTER off it works. If | |||||
* using vlans directly on the em driver you can | |||||
* enable this and get full hardware tag filtering. | |||||
*/ | |||||
if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWFILTER,0); | |||||
/* Enable only WOL MAGIC by default */ | |||||
if (adapter->wol) { | |||||
if_setcapenablebit(ifp, IFCAP_WOL_MAGIC, | |||||
IFCAP_WOL_MCAST| IFCAP_WOL_UCAST); | |||||
} else { | |||||
if_setcapenablebit(ifp, 0, IFCAP_WOL_MAGIC | | |||||
IFCAP_WOL_MCAST| IFCAP_WOL_UCAST); | |||||
} | } | ||||
/* | /* | ||||
* Specify the media types supported by this adapter and register | * Specify the media types supported by this adapter and register | ||||
* callbacks to update media and link information | * callbacks to update media and link information | ||||
*/ | */ | ||||
if ((adapter->hw.phy.media_type == e1000_media_type_fiber) || | if ((adapter->hw.phy.media_type == e1000_media_type_fiber) || | ||||
(adapter->hw.phy.media_type == e1000_media_type_internal_serdes)) { | (adapter->hw.phy.media_type == e1000_media_type_internal_serdes)) { | ||||
▲ Show 20 Lines • Show All 1,757 Lines • Show Last 20 Lines |