Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixgbe/if_ix.c
Show All 34 Lines | |||||
#ifndef IXGBE_STANDALONE_BUILD | #ifndef IXGBE_STANDALONE_BUILD | ||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#endif | #endif | ||||
#include "ixgbe.h" | #include "ixgbe.h" | ||||
#ifdef RSS | |||||
#include <net/rss_config.h> | |||||
#include <netinet/in_rss.h> | |||||
#endif | |||||
/********************************************************************* | /********************************************************************* | ||||
* Set this to one to display debug statistics | * Set this to one to display debug statistics | ||||
*********************************************************************/ | *********************************************************************/ | ||||
int ixgbe_display_debug_stats = 0; | int ixgbe_display_debug_stats = 0; | ||||
/********************************************************************* | /********************************************************************* | ||||
* Driver version | * Driver version | ||||
*********************************************************************/ | *********************************************************************/ | ||||
char ixgbe_driver_version[] = "2.8.3"; | char ixgbe_driver_version[] = "3.1.0"; | ||||
/********************************************************************* | /********************************************************************* | ||||
* PCI Device ID Table | * PCI Device ID Table | ||||
* | * | ||||
* Used by probe to select devices to load on | * Used by probe to select devices to load on | ||||
* Last field stores an index into ixgbe_strings | * Last field stores an index into ixgbe_strings | ||||
* Last entry must be all 0s | * Last entry must be all 0s | ||||
* | * | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
static int ixgbe_allocate_pci_resources(struct adapter *); | static int ixgbe_allocate_pci_resources(struct adapter *); | ||||
static void ixgbe_get_slot_info(struct ixgbe_hw *); | static void ixgbe_get_slot_info(struct ixgbe_hw *); | ||||
static int ixgbe_allocate_msix(struct adapter *); | static int ixgbe_allocate_msix(struct adapter *); | ||||
static int ixgbe_allocate_legacy(struct adapter *); | static int ixgbe_allocate_legacy(struct adapter *); | ||||
static int ixgbe_setup_msix(struct adapter *); | static int ixgbe_setup_msix(struct adapter *); | ||||
static void ixgbe_free_pci_resources(struct adapter *); | static void ixgbe_free_pci_resources(struct adapter *); | ||||
static void ixgbe_local_timer(void *); | static void ixgbe_local_timer(void *); | ||||
static int ixgbe_setup_interface(device_t, struct adapter *); | static int ixgbe_setup_interface(device_t, struct adapter *); | ||||
static void ixgbe_config_gpie(struct adapter *); | |||||
static void ixgbe_config_dmac(struct adapter *); | static void ixgbe_config_dmac(struct adapter *); | ||||
static void ixgbe_config_delay_values(struct adapter *); | static void ixgbe_config_delay_values(struct adapter *); | ||||
static void ixgbe_config_link(struct adapter *); | static void ixgbe_config_link(struct adapter *); | ||||
static void ixgbe_check_eee_support(struct adapter *); | static void ixgbe_check_eee_support(struct adapter *); | ||||
static void ixgbe_check_wol_support(struct adapter *); | static void ixgbe_check_wol_support(struct adapter *); | ||||
static int ixgbe_setup_low_power_mode(struct adapter *); | static int ixgbe_setup_low_power_mode(struct adapter *); | ||||
static void ixgbe_rearm_queues(struct adapter *, u64); | static void ixgbe_rearm_queues(struct adapter *, u64); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
static void ixgbe_handle_msf(void *, int); | static void ixgbe_handle_msf(void *, int); | ||||
static void ixgbe_handle_mod(void *, int); | static void ixgbe_handle_mod(void *, int); | ||||
static void ixgbe_handle_phy(void *, int); | static void ixgbe_handle_phy(void *, int); | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
static void ixgbe_reinit_fdir(void *, int); | static void ixgbe_reinit_fdir(void *, int); | ||||
#endif | #endif | ||||
#ifdef PCI_IOV | |||||
static void ixgbe_ping_all_vfs(struct adapter *); | |||||
static void ixgbe_handle_mbx(void *, int); | |||||
static int ixgbe_init_iov(device_t, u16, const nvlist_t *); | |||||
static void ixgbe_uninit_iov(device_t); | |||||
static int ixgbe_add_vf(device_t, u16, const nvlist_t *); | |||||
static void ixgbe_initialize_iov(struct adapter *); | |||||
static void ixgbe_recalculate_max_frame(struct adapter *); | |||||
static void ixgbe_init_vf(struct adapter *, struct ixgbe_vf *); | |||||
#endif /* PCI_IOV */ | |||||
/********************************************************************* | /********************************************************************* | ||||
* FreeBSD Device Interface Entry Points | * FreeBSD Device Interface Entry Points | ||||
*********************************************************************/ | *********************************************************************/ | ||||
static device_method_t ix_methods[] = { | static device_method_t ix_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, ixgbe_probe), | DEVMETHOD(device_probe, ixgbe_probe), | ||||
DEVMETHOD(device_attach, ixgbe_attach), | DEVMETHOD(device_attach, ixgbe_attach), | ||||
DEVMETHOD(device_detach, ixgbe_detach), | DEVMETHOD(device_detach, ixgbe_detach), | ||||
DEVMETHOD(device_shutdown, ixgbe_shutdown), | DEVMETHOD(device_shutdown, ixgbe_shutdown), | ||||
DEVMETHOD(device_suspend, ixgbe_suspend), | DEVMETHOD(device_suspend, ixgbe_suspend), | ||||
DEVMETHOD(device_resume, ixgbe_resume), | DEVMETHOD(device_resume, ixgbe_resume), | ||||
#ifdef PCI_IOV | |||||
DEVMETHOD(pci_iov_init, ixgbe_init_iov), | |||||
DEVMETHOD(pci_iov_uninit, ixgbe_uninit_iov), | |||||
DEVMETHOD(pci_iov_add_vf, ixgbe_add_vf), | |||||
#endif /* PCI_IOV */ | |||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t ix_driver = { | static driver_t ix_driver = { | ||||
"ix", ix_methods, sizeof(struct adapter), | "ix", ix_methods, sizeof(struct adapter), | ||||
}; | }; | ||||
devclass_t ix_devclass; | devclass_t ix_devclass; | ||||
DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0); | DRIVER_MODULE(ix, pci, ix_driver, ix_devclass, 0, 0); | ||||
MODULE_DEPEND(ix, pci, 1, 1, 1); | MODULE_DEPEND(ix, pci, 1, 1, 1); | ||||
MODULE_DEPEND(ix, ether, 1, 1, 1); | MODULE_DEPEND(ix, ether, 1, 1, 1); | ||||
#ifdef DEV_NETMAP | |||||
MODULE_DEPEND(ix, netmap, 1, 1, 1); | |||||
#endif /* DEV_NETMAP */ | |||||
/* | /* | ||||
** TUNEABLE PARAMETERS: | ** TUNEABLE PARAMETERS: | ||||
*/ | */ | ||||
static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, | static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, | ||||
"IXGBE driver parameters"); | "IXGBE driver parameters"); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
* Number of Queues, can be set to 0, | * Number of Queues, can be set to 0, | ||||
* it then autoconfigures based on the | * it then autoconfigures based on the | ||||
* number of cpus with a max of 8. This | * number of cpus with a max of 8. This | ||||
* can be overriden manually here. | * can be overriden manually here. | ||||
*/ | */ | ||||
static int ixgbe_num_queues = 0; | static int ixgbe_num_queues = 0; | ||||
TUNABLE_INT("hw.ix.num_queues", &ixgbe_num_queues); | TUNABLE_INT("hw.ix.num_queues", &ixgbe_num_queues); | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, | SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, | ||||
"Number of queues to configure up to a maximum of 8; " | "Number of queues to configure, 0 indicates autoconfigure"); | ||||
"0 indicates autoconfigure"); | |||||
/* | /* | ||||
** Number of TX descriptors per ring, | ** Number of TX descriptors per ring, | ||||
** setting higher than RX as this seems | ** setting higher than RX as this seems | ||||
** the better performing choice. | ** the better performing choice. | ||||
*/ | */ | ||||
static int ixgbe_txd = PERFORM_TXD; | static int ixgbe_txd = PERFORM_TXD; | ||||
TUNABLE_INT("hw.ix.txd", &ixgbe_txd); | TUNABLE_INT("hw.ix.txd", &ixgbe_txd); | ||||
Show All 35 Lines | |||||
* Additional comments are in ixgbe_netmap.h . | * Additional comments are in ixgbe_netmap.h . | ||||
* | * | ||||
* <dev/netmap/ixgbe_netmap.h> contains functions for netmap support | * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support | ||||
* that extend the standard driver. | * that extend the standard driver. | ||||
*/ | */ | ||||
#include <dev/netmap/ixgbe_netmap.h> | #include <dev/netmap/ixgbe_netmap.h> | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); | |||||
/********************************************************************* | /********************************************************************* | ||||
* Device identification routine | * Device identification routine | ||||
* | * | ||||
* ixgbe_probe determines if the driver should be loaded on | * ixgbe_probe determines if the driver should be loaded on | ||||
* adapter based on PCI vendor/device id of the adapter. | * adapter based on PCI vendor/device id of the adapter. | ||||
* | * | ||||
* return BUS_PROBE_DEFAULT on success, positive on failure | * return BUS_PROBE_DEFAULT on success, positive on failure | ||||
*********************************************************************/ | *********************************************************************/ | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | ixgbe_attach(device_t dev) | ||||
/* Allocate our TX/RX Queues */ | /* Allocate our TX/RX Queues */ | ||||
if (ixgbe_allocate_queues(adapter)) { | if (ixgbe_allocate_queues(adapter)) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto err_out; | goto err_out; | ||||
} | } | ||||
/* Allocate multicast array memory. */ | /* Allocate multicast array memory. */ | ||||
adapter->mta = malloc(sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * | adapter->mta = malloc(sizeof(*adapter->mta) * | ||||
MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); | MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); | ||||
if (adapter->mta == NULL) { | if (adapter->mta == NULL) { | ||||
device_printf(dev, "Can not allocate multicast setup array\n"); | device_printf(dev, "Can not allocate multicast setup array\n"); | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
/* Initialize the shared code */ | /* Initialize the shared code */ | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | ixgbe_attach(device_t dev) | ||||
adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | ||||
ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ||||
adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | ||||
ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ||||
/* Check PCIE slot type/speed/width */ | /* Check PCIE slot type/speed/width */ | ||||
ixgbe_get_slot_info(hw); | ixgbe_get_slot_info(hw); | ||||
/* Set an initial default flow control value */ | /* Set an initial default flow control value */ | ||||
adapter->fc = ixgbe_fc_full; | adapter->fc = ixgbe_fc_full; | ||||
#ifdef PCI_IOV | |||||
if ((hw->mac.type != ixgbe_mac_82598EB) && (adapter->msix > 1)) { | |||||
nvlist_t *pf_schema, *vf_schema; | |||||
hw->mbx.ops.init_params(hw); | |||||
pf_schema = pci_iov_schema_alloc_node(); | |||||
vf_schema = pci_iov_schema_alloc_node(); | |||||
pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); | |||||
pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", | |||||
IOV_SCHEMA_HASDEFAULT, TRUE); | |||||
pci_iov_schema_add_bool(vf_schema, "allow-set-mac", | |||||
IOV_SCHEMA_HASDEFAULT, FALSE); | |||||
pci_iov_schema_add_bool(vf_schema, "allow-promisc", | |||||
IOV_SCHEMA_HASDEFAULT, FALSE); | |||||
error = pci_iov_attach(dev, pf_schema, vf_schema); | |||||
if (error != 0) { | |||||
device_printf(dev, | |||||
"Error %d setting up SR-IOV\n", error); | |||||
} | |||||
} | |||||
#endif /* PCI_IOV */ | |||||
/* Check for certain supported features */ | /* Check for certain supported features */ | ||||
ixgbe_check_wol_support(adapter); | ixgbe_check_wol_support(adapter); | ||||
ixgbe_check_eee_support(adapter); | ixgbe_check_eee_support(adapter); | ||||
/* Add sysctls */ | /* Add sysctls */ | ||||
ixgbe_add_device_sysctls(adapter); | ixgbe_add_device_sysctls(adapter); | ||||
ixgbe_add_hw_stats(adapter); | ixgbe_add_hw_stats(adapter); | ||||
Show All 40 Lines | ixgbe_detach(device_t dev) | ||||
INIT_DEBUGOUT("ixgbe_detach: begin"); | INIT_DEBUGOUT("ixgbe_detach: begin"); | ||||
/* Make sure VLANS are not using driver */ | /* Make sure VLANS are not using driver */ | ||||
if (adapter->ifp->if_vlantrunk != NULL) { | if (adapter->ifp->if_vlantrunk != NULL) { | ||||
device_printf(dev,"Vlan in use, detach first\n"); | device_printf(dev,"Vlan in use, detach first\n"); | ||||
return (EBUSY); | return (EBUSY); | ||||
} | } | ||||
#ifdef PCI_IOV | |||||
if (pci_iov_detach(dev) != 0) { | |||||
device_printf(dev, "SR-IOV in use; detach first.\n"); | |||||
return (EBUSY); | |||||
} | |||||
#endif /* PCI_IOV */ | |||||
/* Stop the adapter */ | /* Stop the adapter */ | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
ixgbe_setup_low_power_mode(adapter); | ixgbe_setup_low_power_mode(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { | for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { | ||||
if (que->tq) { | if (que->tq) { | ||||
#ifndef IXGBE_LEGACY_TX | #ifndef IXGBE_LEGACY_TX | ||||
taskqueue_drain(que->tq, &txr->txq_task); | taskqueue_drain(que->tq, &txr->txq_task); | ||||
#endif | #endif | ||||
taskqueue_drain(que->tq, &que->que_task); | taskqueue_drain(que->tq, &que->que_task); | ||||
taskqueue_free(que->tq); | taskqueue_free(que->tq); | ||||
} | } | ||||
} | } | ||||
/* Drain the Link queue */ | /* Drain the Link queue */ | ||||
if (adapter->tq) { | if (adapter->tq) { | ||||
taskqueue_drain(adapter->tq, &adapter->link_task); | taskqueue_drain(adapter->tq, &adapter->link_task); | ||||
taskqueue_drain(adapter->tq, &adapter->mod_task); | taskqueue_drain(adapter->tq, &adapter->mod_task); | ||||
taskqueue_drain(adapter->tq, &adapter->msf_task); | taskqueue_drain(adapter->tq, &adapter->msf_task); | ||||
#ifdef PCI_IOV | |||||
taskqueue_drain(adapter->tq, &adapter->mbx_task); | |||||
#endif | |||||
taskqueue_drain(adapter->tq, &adapter->phy_task); | taskqueue_drain(adapter->tq, &adapter->phy_task); | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
taskqueue_drain(adapter->tq, &adapter->fdir_task); | taskqueue_drain(adapter->tq, &adapter->fdir_task); | ||||
#endif | #endif | ||||
taskqueue_free(adapter->tq); | taskqueue_free(adapter->tq); | ||||
} | } | ||||
/* let hardware know driver is unloading */ | /* let hardware know driver is unloading */ | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | case SIOCSIFMTU: | ||||
if (ifr->ifr_mtu > IXGBE_MAX_MTU) { | if (ifr->ifr_mtu > IXGBE_MAX_MTU) { | ||||
error = EINVAL; | error = EINVAL; | ||||
} else { | } else { | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
ifp->if_mtu = ifr->ifr_mtu; | ifp->if_mtu = ifr->ifr_mtu; | ||||
adapter->max_frame_size = | adapter->max_frame_size = | ||||
ifp->if_mtu + IXGBE_MTU_HDR; | ifp->if_mtu + IXGBE_MTU_HDR; | ||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
#ifdef PCI_IOV | |||||
ixgbe_recalculate_max_frame(adapter); | |||||
#endif | |||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
} | } | ||||
break; | break; | ||||
case SIOCSIFFLAGS: | case SIOCSIFFLAGS: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); | IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
if (ifp->if_flags & IFF_UP) { | if (ifp->if_flags & IFF_UP) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | |||||
#define IXGBE_MHADD_MFS_SHIFT 16 | #define IXGBE_MHADD_MFS_SHIFT 16 | ||||
static void | static void | ||||
ixgbe_init_locked(struct adapter *adapter) | ixgbe_init_locked(struct adapter *adapter) | ||||
{ | { | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 k, txdctl, mhadd, gpie; | struct tx_ring *txr; | ||||
struct rx_ring *rxr; | |||||
u32 txdctl, mhadd; | |||||
u32 rxdctl, rxctrl; | u32 rxdctl, rxctrl; | ||||
#ifdef PCI_IOV | |||||
enum ixgbe_iov_mode mode; | |||||
#endif | |||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | mtx_assert(&adapter->core_mtx, MA_OWNED); | ||||
INIT_DEBUGOUT("ixgbe_init_locked: begin"); | INIT_DEBUGOUT("ixgbe_init_locked: begin"); | ||||
hw->adapter_stopped = FALSE; | hw->adapter_stopped = FALSE; | ||||
ixgbe_stop_adapter(hw); | ixgbe_stop_adapter(hw); | ||||
callout_stop(&adapter->timer); | callout_stop(&adapter->timer); | ||||
#ifdef PCI_IOV | |||||
mode = ixgbe_get_iov_mode(adapter); | |||||
adapter->pool = ixgbe_max_vfs(mode); | |||||
/* Queue indices may change with IOV mode */ | |||||
for (int i = 0; i < adapter->num_queues; i++) { | |||||
adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i); | |||||
adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i); | |||||
} | |||||
#endif | |||||
/* reprogram the RAR[0] in case user changed it. */ | /* reprogram the RAR[0] in case user changed it. */ | ||||
ixgbe_set_rar(hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); | ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV); | ||||
/* Get the latest mac address, User can use a LAA */ | /* Get the latest mac address, User can use a LAA */ | ||||
bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, | bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); | ||||
IXGBE_ETH_LENGTH_OF_ADDRESS); | ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); | ||||
ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); | |||||
hw->addr_ctrl.rar_used_count = 1; | hw->addr_ctrl.rar_used_count = 1; | ||||
/* Set the various hardware offload abilities */ | /* Set the various hardware offload abilities */ | ||||
ifp->if_hwassist = 0; | ifp->if_hwassist = 0; | ||||
if (ifp->if_capenable & IFCAP_TSO) | if (ifp->if_capenable & IFCAP_TSO) | ||||
ifp->if_hwassist |= CSUM_TSO; | ifp->if_hwassist |= CSUM_TSO; | ||||
if (ifp->if_capenable & IFCAP_TXCSUM) { | if (ifp->if_capenable & IFCAP_TXCSUM) { | ||||
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ||||
#if __FreeBSD_version >= 800000 | #if __FreeBSD_version >= 800000 | ||||
if (hw->mac.type != ixgbe_mac_82598EB) | if (hw->mac.type != ixgbe_mac_82598EB) | ||||
ifp->if_hwassist |= CSUM_SCTP; | ifp->if_hwassist |= CSUM_SCTP; | ||||
#endif | #endif | ||||
} | } | ||||
/* Prepare transmit descriptors and buffers */ | /* Prepare transmit descriptors and buffers */ | ||||
if (ixgbe_setup_transmit_structures(adapter)) { | if (ixgbe_setup_transmit_structures(adapter)) { | ||||
device_printf(dev, "Could not setup transmit structures\n"); | device_printf(dev, "Could not setup transmit structures\n"); | ||||
ixgbe_stop(adapter); | ixgbe_stop(adapter); | ||||
return; | return; | ||||
} | } | ||||
ixgbe_init_hw(hw); | ixgbe_init_hw(hw); | ||||
#ifdef PCI_IOV | |||||
ixgbe_initialize_iov(adapter); | |||||
#endif | |||||
ixgbe_initialize_transmit_units(adapter); | ixgbe_initialize_transmit_units(adapter); | ||||
/* Setup Multicast table */ | /* Setup Multicast table */ | ||||
ixgbe_set_multi(adapter); | ixgbe_set_multi(adapter); | ||||
/* | /* | ||||
** Determine the correct mbuf pool | ** Determine the correct mbuf pool | ||||
** for doing jumbo frames | ** for doing jumbo frames | ||||
*/ | */ | ||||
if (adapter->max_frame_size <= 2048) | if (adapter->max_frame_size <= MCLBYTES) | ||||
adapter->rx_mbuf_sz = MCLBYTES; | adapter->rx_mbuf_sz = MCLBYTES; | ||||
else if (adapter->max_frame_size <= 4096) | |||||
adapter->rx_mbuf_sz = MJUMPAGESIZE; | |||||
else if (adapter->max_frame_size <= 9216) | |||||
adapter->rx_mbuf_sz = MJUM9BYTES; | |||||
else | else | ||||
adapter->rx_mbuf_sz = MJUM16BYTES; | adapter->rx_mbuf_sz = MJUMPAGESIZE; | ||||
/* Prepare receive descriptors and buffers */ | /* Prepare receive descriptors and buffers */ | ||||
if (ixgbe_setup_receive_structures(adapter)) { | if (ixgbe_setup_receive_structures(adapter)) { | ||||
device_printf(dev, "Could not setup receive structures\n"); | device_printf(dev, "Could not setup receive structures\n"); | ||||
ixgbe_stop(adapter); | ixgbe_stop(adapter); | ||||
return; | return; | ||||
} | } | ||||
/* Configure RX settings */ | /* Configure RX settings */ | ||||
ixgbe_initialize_receive_units(adapter); | ixgbe_initialize_receive_units(adapter); | ||||
gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); | /* Enable SDP & MSIX interrupts based on adapter */ | ||||
ixgbe_config_gpie(adapter); | |||||
/* Enable Fan Failure Interrupt */ | |||||
gpie |= IXGBE_SDP1_GPIEN_BY_MAC(hw); | |||||
/* Add for Module detection */ | |||||
if (hw->mac.type == ixgbe_mac_82599EB) | |||||
gpie |= IXGBE_SDP2_GPIEN; | |||||
/* | |||||
* Thermal Failure Detection (X540) | |||||
* Link Detection (X552) | |||||
*/ | |||||
if (hw->mac.type == ixgbe_mac_X540 || | |||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || | |||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) | |||||
gpie |= IXGBE_SDP0_GPIEN_X540; | |||||
if (adapter->msix > 1) { | |||||
/* Enable Enhanced MSIX mode */ | |||||
gpie |= IXGBE_GPIE_MSIX_MODE; | |||||
gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | | |||||
IXGBE_GPIE_OCD; | |||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); | |||||
/* Set MTU size */ | /* Set MTU size */ | ||||
if (ifp->if_mtu > ETHERMTU) { | if (ifp->if_mtu > ETHERMTU) { | ||||
/* aka IXGBE_MAXFRS on 82599 and newer */ | /* aka IXGBE_MAXFRS on 82599 and newer */ | ||||
mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); | mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); | ||||
mhadd &= ~IXGBE_MHADD_MFS_MASK; | mhadd &= ~IXGBE_MHADD_MFS_MASK; | ||||
mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; | mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; | ||||
IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); | IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); | ||||
} | } | ||||
/* Now enable all the queues */ | /* Now enable all the queues */ | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); | txr = &adapter->tx_rings[i]; | ||||
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); | |||||
txdctl |= IXGBE_TXDCTL_ENABLE; | txdctl |= IXGBE_TXDCTL_ENABLE; | ||||
/* Set WTHRESH to 8, burst writeback */ | /* Set WTHRESH to 8, burst writeback */ | ||||
txdctl |= (8 << 16); | txdctl |= (8 << 16); | ||||
/* | /* | ||||
* When the internal queue falls below PTHRESH (32), | * When the internal queue falls below PTHRESH (32), | ||||
* start prefetching as long as there are at least | * start prefetching as long as there are at least | ||||
* HTHRESH (1) buffers ready. The values are taken | * HTHRESH (1) buffers ready. The values are taken | ||||
* from the Intel linux driver 3.8.21. | * from the Intel linux driver 3.8.21. | ||||
* Prefetching enables tx line rate even with 1 queue. | * Prefetching enables tx line rate even with 1 queue. | ||||
*/ | */ | ||||
txdctl |= (32 << 0) | (1 << 8); | txdctl |= (32 << 0) | (1 << 8); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), txdctl); | IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); | ||||
} | } | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0, j = 0; i < adapter->num_queues; i++) { | ||||
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); | rxr = &adapter->rx_rings[i]; | ||||
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); | |||||
if (hw->mac.type == ixgbe_mac_82598EB) { | if (hw->mac.type == ixgbe_mac_82598EB) { | ||||
/* | /* | ||||
** PTHRESH = 21 | ** PTHRESH = 21 | ||||
** HTHRESH = 4 | ** HTHRESH = 4 | ||||
** WTHRESH = 8 | ** WTHRESH = 8 | ||||
*/ | */ | ||||
rxdctl &= ~0x3FFFFF; | rxdctl &= ~0x3FFFFF; | ||||
rxdctl |= 0x080420; | rxdctl |= 0x080420; | ||||
} | } | ||||
rxdctl |= IXGBE_RXDCTL_ENABLE; | rxdctl |= IXGBE_RXDCTL_ENABLE; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); | IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); | ||||
for (k = 0; k < 10; k++) { | for (; j < 10; j++) { | ||||
if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) & | if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & | ||||
IXGBE_RXDCTL_ENABLE) | IXGBE_RXDCTL_ENABLE) | ||||
break; | break; | ||||
else | else | ||||
msec_delay(1); | msec_delay(1); | ||||
} | } | ||||
wmb(); | wmb(); | ||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
/* | /* | ||||
Show All 12 Lines | #ifdef DEV_NETMAP | ||||
* RDT points to the last slot available for reception (?), | * RDT points to the last slot available for reception (?), | ||||
* so RDT = num_rx_desc - 1 means the whole ring is available. | * so RDT = num_rx_desc - 1 means the whole ring is available. | ||||
*/ | */ | ||||
if (ifp->if_capenable & IFCAP_NETMAP) { | if (ifp->if_capenable & IFCAP_NETMAP) { | ||||
struct netmap_adapter *na = NA(adapter->ifp); | struct netmap_adapter *na = NA(adapter->ifp); | ||||
struct netmap_kring *kring = &na->rx_rings[i]; | struct netmap_kring *kring = &na->rx_rings[i]; | ||||
int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); | int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDT(i), t); | IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), t); | ||||
} else | } else | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDT(i), adapter->num_rx_desc - 1); | IXGBE_WRITE_REG(hw, IXGBE_RDT(rxr->me), adapter->num_rx_desc - 1); | ||||
} | } | ||||
/* Enable Receive engine */ | /* Enable Receive engine */ | ||||
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); | rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); | ||||
if (hw->mac.type == ixgbe_mac_82598EB) | if (hw->mac.type == ixgbe_mac_82598EB) | ||||
rxctrl |= IXGBE_RXCTRL_DMBYPS; | rxctrl |= IXGBE_RXCTRL_DMBYPS; | ||||
rxctrl |= IXGBE_RXCTRL_RXEN; | rxctrl |= IXGBE_RXCTRL_RXEN; | ||||
ixgbe_enable_rx_dma(hw, rxctrl); | ixgbe_enable_rx_dma(hw, rxctrl); | ||||
Show All 22 Lines | if (hw->mac.type != ixgbe_mac_82598EB) { | ||||
u32 hdrm = 32 << fdir_pballoc; | u32 hdrm = 32 << fdir_pballoc; | ||||
hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); | hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); | ||||
ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); | ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
** Check on any SFP devices that | * Check on any SFP devices that | ||||
** need to be kick-started | * need to be kick-started | ||||
*/ | */ | ||||
if (hw->phy.type == ixgbe_phy_none) { | if (hw->phy.type == ixgbe_phy_none) { | ||||
int err = hw->phy.ops.identify(hw); | int err = hw->phy.ops.identify(hw); | ||||
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Unsupported SFP+ module type was detected.\n"); | "Unsupported SFP+ module type was detected.\n"); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
/* Set moderation on the Link interrupt */ | /* Set moderation on the Link interrupt */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); | IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); | ||||
/* Configure Energy Efficient Ethernet for supported devices */ | /* Configure Energy Efficient Ethernet for supported devices */ | ||||
if (adapter->eee_support) | |||||
ixgbe_setup_eee(hw, adapter->eee_enabled); | ixgbe_setup_eee(hw, adapter->eee_enabled); | ||||
/* Config/Enable Link */ | /* Config/Enable Link */ | ||||
ixgbe_config_link(adapter); | ixgbe_config_link(adapter); | ||||
/* Hardware Packet Buffer & Flow Control setup */ | /* Hardware Packet Buffer & Flow Control setup */ | ||||
ixgbe_config_delay_values(adapter); | ixgbe_config_delay_values(adapter); | ||||
/* Initialize the FC settings */ | /* Initialize the FC settings */ | ||||
ixgbe_start_hw(hw); | ixgbe_start_hw(hw); | ||||
/* Set up VLAN support and filter */ | /* Set up VLAN support and filter */ | ||||
ixgbe_setup_vlan_hw_support(adapter); | ixgbe_setup_vlan_hw_support(adapter); | ||||
/* Setup DMA Coalescing */ | /* Setup DMA Coalescing */ | ||||
ixgbe_config_dmac(adapter); | ixgbe_config_dmac(adapter); | ||||
/* And now turn on interrupts */ | /* And now turn on interrupts */ | ||||
ixgbe_enable_intr(adapter); | ixgbe_enable_intr(adapter); | ||||
#ifdef PCI_IOV | |||||
/* Enable the use of the MBX by the VF's */ | |||||
{ | |||||
u32 reg = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); | |||||
reg |= IXGBE_CTRL_EXT_PFRSTD; | |||||
IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg); | |||||
} | |||||
#endif | |||||
/* Now inform the stack we're ready */ | /* Now inform the stack we're ready */ | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | ifp->if_drv_flags |= IFF_DRV_RUNNING; | ||||
return; | return; | ||||
} | } | ||||
static void | static void | ||||
ixgbe_init(void *arg) | ixgbe_init(void *arg) | ||||
{ | { | ||||
struct adapter *adapter = arg; | struct adapter *adapter = arg; | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return; | return; | ||||
} | } | ||||
static void | static void | ||||
ixgbe_config_gpie(struct adapter *adapter) | |||||
{ | |||||
struct ixgbe_hw *hw = &adapter->hw; | |||||
u32 gpie; | |||||
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); | |||||
/* Fan Failure Interrupt */ | |||||
if (hw->device_id == IXGBE_DEV_ID_82598AT) | |||||
gpie |= IXGBE_SDP1_GPIEN; | |||||
/* | |||||
* Module detection (SDP2) | |||||
* Media ready (SDP1) | |||||
*/ | |||||
if (hw->mac.type == ixgbe_mac_82599EB) { | |||||
gpie |= IXGBE_SDP2_GPIEN; | |||||
if (hw->device_id != IXGBE_DEV_ID_82599_QSFP_SF_QP) | |||||
gpie |= IXGBE_SDP1_GPIEN; | |||||
} | |||||
/* | |||||
* Thermal Failure Detection (X540) | |||||
* Link Detection (X557) | |||||
*/ | |||||
if (hw->mac.type == ixgbe_mac_X540 || | |||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || | |||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) | |||||
gpie |= IXGBE_SDP0_GPIEN_X540; | |||||
if (adapter->msix > 1) { | |||||
/* Enable Enhanced MSIX mode */ | |||||
gpie |= IXGBE_GPIE_MSIX_MODE; | |||||
gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | | |||||
IXGBE_GPIE_OCD; | |||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); | |||||
return; | |||||
} | |||||
/* | |||||
* Requires adapter->max_frame_size to be set. | |||||
*/ | |||||
static void | |||||
ixgbe_config_delay_values(struct adapter *adapter) | ixgbe_config_delay_values(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 rxpb, frame, size, tmp; | u32 rxpb, frame, size, tmp; | ||||
frame = adapter->max_frame_size; | frame = adapter->max_frame_size; | ||||
/* Calculate High Water */ | /* Calculate High Water */ | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
ixgbe_handle_que(void *context, int pending) | ixgbe_handle_que(void *context, int pending) | ||||
{ | { | ||||
struct ix_queue *que = context; | struct ix_queue *que = context; | ||||
struct adapter *adapter = que->adapter; | struct adapter *adapter = que->adapter; | ||||
struct tx_ring *txr = que->txr; | struct tx_ring *txr = que->txr; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
bool more; | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | ||||
more = ixgbe_rxeof(que); | ixgbe_rxeof(que); | ||||
IXGBE_TX_LOCK(txr); | IXGBE_TX_LOCK(txr); | ||||
ixgbe_txeof(txr); | ixgbe_txeof(txr); | ||||
#ifndef IXGBE_LEGACY_TX | #ifndef IXGBE_LEGACY_TX | ||||
if (!drbr_empty(ifp, txr->br)) | if (!drbr_empty(ifp, txr->br)) | ||||
ixgbe_mq_start_locked(ifp, txr); | ixgbe_mq_start_locked(ifp, txr); | ||||
#else | #else | ||||
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | ||||
ixgbe_start_locked(txr, ifp); | ixgbe_start_locked(txr, ifp); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | ||||
ixgbe_start_locked(txr, ifp); | ixgbe_start_locked(txr, ifp); | ||||
#else | #else | ||||
if (!drbr_empty(ifp, txr->br)) | if (!drbr_empty(ifp, txr->br)) | ||||
ixgbe_mq_start_locked(ifp, txr); | ixgbe_mq_start_locked(ifp, txr); | ||||
#endif | #endif | ||||
IXGBE_TX_UNLOCK(txr); | IXGBE_TX_UNLOCK(txr); | ||||
/* Check for fan failure */ | /* Check for fan failure */ | ||||
if ((hw->phy.media_type == ixgbe_media_type_copper) && | if ((hw->device_id == IXGBE_DEV_ID_82598AT) && | ||||
(reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) { | (reg_eicr & IXGBE_EICR_GPI_SDP1)) { | ||||
device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " | device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " | ||||
"REPLACE IMMEDIATELY!!\n"); | "REPLACE IMMEDIATELY!!\n"); | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); | IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); | ||||
} | } | ||||
/* Link status change */ | /* Link status change */ | ||||
if (reg_eicr & IXGBE_EICR_LSC) | if (reg_eicr & IXGBE_EICR_LSC) | ||||
taskqueue_enqueue(adapter->tq, &adapter->link_task); | taskqueue_enqueue(adapter->tq, &adapter->link_task); | ||||
Show All 22 Lines | ixgbe_msix_que(void *arg) | ||||
struct ix_queue *que = arg; | struct ix_queue *que = arg; | ||||
struct adapter *adapter = que->adapter; | struct adapter *adapter = que->adapter; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
struct tx_ring *txr = que->txr; | struct tx_ring *txr = que->txr; | ||||
struct rx_ring *rxr = que->rxr; | struct rx_ring *rxr = que->rxr; | ||||
bool more; | bool more; | ||||
u32 newitr = 0; | u32 newitr = 0; | ||||
/* Protect against spurious interrupts */ | /* Protect against spurious interrupts */ | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | ||||
return; | return; | ||||
ixgbe_disable_queue(adapter, que->msix); | ixgbe_disable_queue(adapter, que->msix); | ||||
++que->irqs; | ++que->irqs; | ||||
more = ixgbe_rxeof(que); | more = ixgbe_rxeof(que); | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | #endif | ||||
/* Check for over temp condition */ | /* Check for over temp condition */ | ||||
if (reg_eicr & IXGBE_EICR_TS) { | if (reg_eicr & IXGBE_EICR_TS) { | ||||
device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! " | device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! " | ||||
"PHY IS SHUT DOWN!!\n"); | "PHY IS SHUT DOWN!!\n"); | ||||
device_printf(adapter->dev, "System shutdown required!\n"); | device_printf(adapter->dev, "System shutdown required!\n"); | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); | IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); | ||||
} | } | ||||
#ifdef PCI_IOV | |||||
if (reg_eicr & IXGBE_EICR_MAILBOX) | |||||
taskqueue_enqueue(adapter->tq, &adapter->mbx_task); | |||||
#endif | |||||
} | } | ||||
/* Pluggable optics-related interrupt */ | /* Pluggable optics-related interrupt */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) | ||||
mod_mask = IXGBE_EICR_GPI_SDP0_X540; | mod_mask = IXGBE_EICR_GPI_SDP0_X540; | ||||
else | else | ||||
mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); | mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) | ||||
ifmr->ifm_active = IFM_ETHER; | ifmr->ifm_active = IFM_ETHER; | ||||
if (!adapter->link_active) { | if (!adapter->link_active) { | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return; | return; | ||||
} | } | ||||
ifmr->ifm_status |= IFM_ACTIVE; | ifmr->ifm_status |= IFM_ACTIVE; | ||||
layer = ixgbe_get_supported_physical_layer(hw); | layer = adapter->phy_layer; | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T || | ||||
layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || | layer & IXGBE_PHYSICAL_LAYER_1000BASE_T || | ||||
layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) | layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) | ||||
switch (adapter->link_speed) { | switch (adapter->link_speed) { | ||||
case IXGBE_LINK_SPEED_10GB_FULL: | case IXGBE_LINK_SPEED_10GB_FULL: | ||||
ifmr->ifm_active |= IFM_10G_T | IFM_FDX; | ifmr->ifm_active |= IFM_10G_T | IFM_FDX; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | |||||
* This routine is called whenever multicast address list is updated. | * This routine is called whenever multicast address list is updated. | ||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
#define IXGBE_RAR_ENTRIES 16 | #define IXGBE_RAR_ENTRIES 16 | ||||
static void | static void | ||||
ixgbe_set_multi(struct adapter *adapter) | ixgbe_set_multi(struct adapter *adapter) | ||||
{ | { | ||||
u32 fctrl; | u32 fctrl; | ||||
u8 *mta; | |||||
u8 *update_ptr; | u8 *update_ptr; | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct ixgbe_mc_addr *mta; | |||||
int mcnt = 0; | int mcnt = 0; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); | IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); | ||||
mta = adapter->mta; | mta = adapter->mta; | ||||
bzero(mta, sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * | bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); | ||||
MAX_NUM_MULTICAST_ADDRESSES); | |||||
#if __FreeBSD_version < 800000 | #if __FreeBSD_version < 800000 | ||||
IF_ADDR_LOCK(ifp); | IF_ADDR_LOCK(ifp); | ||||
#else | #else | ||||
if_maddr_rlock(ifp); | if_maddr_rlock(ifp); | ||||
#endif | #endif | ||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | ||||
if (ifma->ifma_addr->sa_family != AF_LINK) | if (ifma->ifma_addr->sa_family != AF_LINK) | ||||
continue; | continue; | ||||
if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) | if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) | ||||
break; | break; | ||||
bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), | bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), | ||||
&mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], | mta[mcnt].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); | ||||
IXGBE_ETH_LENGTH_OF_ADDRESS); | mta[mcnt].vmdq = adapter->pool; | ||||
mcnt++; | mcnt++; | ||||
} | } | ||||
#if __FreeBSD_version < 800000 | #if __FreeBSD_version < 800000 | ||||
IF_ADDR_UNLOCK(ifp); | IF_ADDR_UNLOCK(ifp); | ||||
#else | #else | ||||
if_maddr_runlock(ifp); | if_maddr_runlock(ifp); | ||||
#endif | #endif | ||||
fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); | fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); | ||||
fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | ||||
if (ifp->if_flags & IFF_PROMISC) | if (ifp->if_flags & IFF_PROMISC) | ||||
fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | ||||
else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || | else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || | ||||
ifp->if_flags & IFF_ALLMULTI) { | ifp->if_flags & IFF_ALLMULTI) { | ||||
fctrl |= IXGBE_FCTRL_MPE; | fctrl |= IXGBE_FCTRL_MPE; | ||||
fctrl &= ~IXGBE_FCTRL_UPE; | fctrl &= ~IXGBE_FCTRL_UPE; | ||||
} else | } else | ||||
fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); | ||||
if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { | if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { | ||||
update_ptr = mta; | update_ptr = (u8 *)mta; | ||||
ixgbe_update_mc_addr_list(&adapter->hw, | ixgbe_update_mc_addr_list(&adapter->hw, | ||||
update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); | update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* This is an iterator function now needed by the multicast | * This is an iterator function now needed by the multicast | ||||
* shared code. It simply feeds the shared code routine the | * shared code. It simply feeds the shared code routine the | ||||
* addresses in the array of ixgbe_set_multi() one by one. | * addresses in the array of ixgbe_set_multi() one by one. | ||||
*/ | */ | ||||
static u8 * | static u8 * | ||||
ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ||||
{ | { | ||||
u8 *addr = *update_ptr; | struct ixgbe_mc_addr *mta; | ||||
u8 *newptr; | |||||
*vmdq = 0; | |||||
newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; | mta = (struct ixgbe_mc_addr *)*update_ptr; | ||||
*update_ptr = newptr; | *vmdq = mta->vmdq; | ||||
return addr; | |||||
*update_ptr = (u8*)(mta + 1);; | |||||
return (mta->addr); | |||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* Timer routine | * Timer routine | ||||
* | * | ||||
* This routine checks for link status,updates statistics, | * This routine checks for link status,updates statistics, | ||||
* and runs the watchdog check. | * and runs the watchdog check. | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
watchdog: | watchdog: | ||||
device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); | device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); | ||||
adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | ||||
adapter->watchdog_events++; | adapter->watchdog_events++; | ||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
} | } | ||||
/* | /* | ||||
** Note: this routine updates the OS on the link state | ** Note: this routine updates the OS on the link state | ||||
** the real check of the hardware only happens with | ** the real check of the hardware only happens with | ||||
** a link interrupt. | ** a link interrupt. | ||||
*/ | */ | ||||
static void | static void | ||||
ixgbe_update_link_status(struct adapter *adapter) | ixgbe_update_link_status(struct adapter *adapter) | ||||
{ | { | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
if (adapter->link_up){ | if (adapter->link_up){ | ||||
if (adapter->link_active == FALSE) { | if (adapter->link_active == FALSE) { | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev,"Link is up %d Gbps %s \n", | device_printf(dev,"Link is up %d Gbps %s \n", | ||||
((adapter->link_speed == 128)? 10:1), | ((adapter->link_speed == 128)? 10:1), | ||||
"Full Duplex"); | "Full Duplex"); | ||||
adapter->link_active = TRUE; | adapter->link_active = TRUE; | ||||
/* Update any Flow Control changes */ | /* Update any Flow Control changes */ | ||||
ixgbe_fc_enable(&adapter->hw); | ixgbe_fc_enable(&adapter->hw); | ||||
/* Update DMA coalescing config */ | /* Update DMA coalescing config */ | ||||
ixgbe_config_dmac(adapter); | ixgbe_config_dmac(adapter); | ||||
if_link_state_change(ifp, LINK_STATE_UP); | if_link_state_change(ifp, LINK_STATE_UP); | ||||
#ifdef PCI_IOV | |||||
ixgbe_ping_all_vfs(adapter); | |||||
#endif | |||||
} | } | ||||
} else { /* Link down */ | } else { /* Link down */ | ||||
if (adapter->link_active == TRUE) { | if (adapter->link_active == TRUE) { | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev,"Link is Down\n"); | device_printf(dev,"Link is Down\n"); | ||||
if_link_state_change(ifp, LINK_STATE_DOWN); | if_link_state_change(ifp, LINK_STATE_DOWN); | ||||
adapter->link_active = FALSE; | adapter->link_active = FALSE; | ||||
#ifdef PCI_IOV | |||||
ixgbe_ping_all_vfs(adapter); | |||||
#endif | |||||
} | } | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
static void | static void | ||||
ixgbe_setup_optics(struct adapter *adapter) | ixgbe_setup_optics(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
int layer; | int layer; | ||||
layer = ixgbe_get_supported_physical_layer(hw); | layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { | ||||
adapter->optics = IFM_10G_T; | adapter->optics = IFM_10G_T; | ||||
return; | return; | ||||
} | } | ||||
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { | if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { | ||||
adapter->optics = IFM_1000_T; | adapter->optics = IFM_1000_T; | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
ixgbe_allocate_msix(struct adapter *adapter) | ixgbe_allocate_msix(struct adapter *adapter) | ||||
{ | { | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
int error, rid, vector = 0; | int error, rid, vector = 0; | ||||
int cpu_id = 0; | int cpu_id = 0; | ||||
#ifdef RSS | |||||
cpuset_t cpu_mask; | |||||
#endif | |||||
#ifdef RSS | |||||
/* | |||||
* If we're doing RSS, the number of queues needs to | |||||
* match the number of RSS buckets that are configured. | |||||
* | |||||
* + If there's more queues than RSS buckets, we'll end | |||||
* up with queues that get no traffic. | |||||
* | |||||
* + If there's more RSS buckets than queues, we'll end | |||||
* up having multiple RSS buckets map to the same queue, | |||||
* so there'll be some contention. | |||||
*/ | |||||
if (adapter->num_queues != rss_getnumbuckets()) { | |||||
device_printf(dev, | |||||
"%s: number of queues (%d) != number of RSS buckets (%d)" | |||||
"; performance will be impacted.\n", | |||||
__func__, | |||||
adapter->num_queues, | |||||
rss_getnumbuckets()); | |||||
} | |||||
#endif | |||||
for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { | for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { | ||||
rid = vector + 1; | rid = vector + 1; | ||||
que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | ||||
RF_SHAREABLE | RF_ACTIVE); | RF_SHAREABLE | RF_ACTIVE); | ||||
if (que->res == NULL) { | if (que->res == NULL) { | ||||
device_printf(dev,"Unable to allocate" | device_printf(dev,"Unable to allocate" | ||||
" bus resource: que interrupt [%d]\n", vector); | " bus resource: que interrupt [%d]\n", vector); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Set the handler function */ | /* Set the handler function */ | ||||
error = bus_setup_intr(dev, que->res, | error = bus_setup_intr(dev, que->res, | ||||
INTR_TYPE_NET | INTR_MPSAFE, NULL, | INTR_TYPE_NET | INTR_MPSAFE, NULL, | ||||
ixgbe_msix_que, que, &que->tag); | ixgbe_msix_que, que, &que->tag); | ||||
if (error) { | if (error) { | ||||
que->res = NULL; | que->res = NULL; | ||||
device_printf(dev, "Failed to register QUE handler"); | device_printf(dev, "Failed to register QUE handler"); | ||||
return (error); | return (error); | ||||
} | } | ||||
#if __FreeBSD_version >= 800504 | #if __FreeBSD_version >= 800504 | ||||
bus_describe_intr(dev, que->res, que->tag, "que %d", i); | bus_describe_intr(dev, que->res, que->tag, "que %d", i); | ||||
#endif | #endif | ||||
que->msix = vector; | que->msix = vector; | ||||
adapter->active_queues |= (u64)(1 << que->msix); | adapter->active_queues |= (u64)(1 << que->msix); | ||||
#ifdef RSS | |||||
/* | /* | ||||
* The queue ID is used as the RSS layer bucket ID. | |||||
* We look up the queue ID -> RSS CPU ID and select | |||||
* that. | |||||
*/ | |||||
cpu_id = rss_getcpu(i % rss_getnumbuckets()); | |||||
#else | |||||
/* | |||||
* Bind the msix vector, and thus the | * Bind the msix vector, and thus the | ||||
* rings to the corresponding cpu. | * rings to the corresponding cpu. | ||||
* | * | ||||
* This just happens to match the default RSS round-robin | * This just happens to match the default RSS round-robin | ||||
* bucket -> queue -> CPU allocation. | * bucket -> queue -> CPU allocation. | ||||
*/ | */ | ||||
if (adapter->num_queues > 1) | if (adapter->num_queues > 1) | ||||
cpu_id = i; | cpu_id = i; | ||||
#endif | |||||
if (adapter->num_queues > 1) | if (adapter->num_queues > 1) | ||||
bus_bind_intr(dev, que->res, cpu_id); | bus_bind_intr(dev, que->res, cpu_id); | ||||
#ifdef IXGBE_DEBUG | |||||
#ifdef RSS | |||||
device_printf(dev, | |||||
"Bound RSS bucket %d to CPU %d\n", | |||||
i, cpu_id); | |||||
#else | |||||
device_printf(dev, | |||||
"Bound queue %d to cpu %d\n", | |||||
i, cpu_id); | |||||
#endif | |||||
#endif /* IXGBE_DEBUG */ | |||||
#ifndef IXGBE_LEGACY_TX | #ifndef IXGBE_LEGACY_TX | ||||
TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); | TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); | ||||
#endif | #endif | ||||
TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); | TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); | ||||
que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, | que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &que->tq); | taskqueue_thread_enqueue, &que->tq); | ||||
#ifdef RSS | |||||
CPU_SETOF(cpu_id, &cpu_mask); | |||||
taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, | |||||
&cpu_mask, | |||||
"%s (bucket %d)", | |||||
device_get_nameunit(adapter->dev), | |||||
cpu_id); | |||||
#else | |||||
taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", | taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", | ||||
device_get_nameunit(adapter->dev)); | device_get_nameunit(adapter->dev)); | ||||
#endif | |||||
} | } | ||||
/* and Link */ | /* and Link */ | ||||
rid = vector + 1; | rid = vector + 1; | ||||
adapter->res = bus_alloc_resource_any(dev, | adapter->res = bus_alloc_resource_any(dev, | ||||
SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); | SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); | ||||
if (!adapter->res) { | if (!adapter->res) { | ||||
device_printf(dev,"Unable to allocate" | device_printf(dev,"Unable to allocate" | ||||
Show All 12 Lines | |||||
#if __FreeBSD_version >= 800504 | #if __FreeBSD_version >= 800504 | ||||
bus_describe_intr(dev, adapter->res, adapter->tag, "link"); | bus_describe_intr(dev, adapter->res, adapter->tag, "link"); | ||||
#endif | #endif | ||||
adapter->vector = vector; | adapter->vector = vector; | ||||
/* Tasklets for Link, SFP and Multispeed Fiber */ | /* Tasklets for Link, SFP and Multispeed Fiber */ | ||||
TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); | TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); | ||||
TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); | TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); | ||||
TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); | TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); | ||||
#ifdef PCI_IOV | |||||
TASK_INIT(&adapter->mbx_task, 0, ixgbe_handle_mbx, adapter); | |||||
#endif | |||||
TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); | TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); | TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); | ||||
#endif | #endif | ||||
adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, | adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &adapter->tq); | taskqueue_thread_enqueue, &adapter->tq); | ||||
taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", | taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", | ||||
device_get_nameunit(adapter->dev)); | device_get_nameunit(adapter->dev)); | ||||
Show All 31 Lines | adapter->msix_mem = bus_alloc_resource_any(dev, | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Unable to map MSIX table \n"); | "Unable to map MSIX table \n"); | ||||
goto msi; | goto msi; | ||||
} | } | ||||
/* Figure out a reasonable auto config value */ | /* Figure out a reasonable auto config value */ | ||||
queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus; | queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus; | ||||
#ifdef RSS | |||||
/* If we're doing RSS, clamp at the number of RSS buckets */ | |||||
if (queues > rss_getnumbuckets()) | |||||
queues = rss_getnumbuckets(); | |||||
#endif | |||||
if (ixgbe_num_queues != 0) | if (ixgbe_num_queues != 0) | ||||
queues = ixgbe_num_queues; | queues = ixgbe_num_queues; | ||||
/* Set max queues to 8 when autoconfiguring */ | |||||
else if ((ixgbe_num_queues == 0) && (queues > 8)) | |||||
queues = 8; | |||||
/* reflect correct sysctl value */ | /* reflect correct sysctl value */ | ||||
ixgbe_num_queues = queues; | ixgbe_num_queues = queues; | ||||
/* | /* | ||||
** Want one vector (RX/TX pair) per queue | ** Want one vector (RX/TX pair) per queue | ||||
** plus an additional for Link. | ** plus an additional for Link. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | if (ifp == NULL) { | ||||
return (-1); | return (-1); | ||||
} | } | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ||||
if_initbaudrate(ifp, IF_Gbps(10)); | if_initbaudrate(ifp, IF_Gbps(10)); | ||||
ifp->if_init = ixgbe_init; | ifp->if_init = ixgbe_init; | ||||
ifp->if_softc = adapter; | ifp->if_softc = adapter; | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ||||
ifp->if_ioctl = ixgbe_ioctl; | ifp->if_ioctl = ixgbe_ioctl; | ||||
#if __FreeBSD_version >= 1100036 | |||||
if_setgetcounterfn(ifp, ixgbe_get_counter); | |||||
#endif | |||||
#if __FreeBSD_version >= 1100045 | |||||
/* TSO parameters */ | /* TSO parameters */ | ||||
ifp->if_hw_tsomax = 65518; | ifp->if_hw_tsomax = 65518; | ||||
ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; | ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; | ||||
ifp->if_hw_tsomaxsegsize = 2048; | ifp->if_hw_tsomaxsegsize = 2048; | ||||
#endif | |||||
#ifndef IXGBE_LEGACY_TX | #ifndef IXGBE_LEGACY_TX | ||||
ifp->if_transmit = ixgbe_mq_start; | ifp->if_transmit = ixgbe_mq_start; | ||||
ifp->if_qflush = ixgbe_qflush; | ifp->if_qflush = ixgbe_qflush; | ||||
#else | #else | ||||
ifp->if_start = ixgbe_start; | ifp->if_start = ixgbe_start; | ||||
IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); | IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); | ||||
ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; | ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; | ||||
IFQ_SET_READY(&ifp->if_snd); | IFQ_SET_READY(&ifp->if_snd); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
ixgbe_add_media_types(struct adapter *adapter) | ixgbe_add_media_types(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int layer; | int layer; | ||||
layer = ixgbe_get_supported_physical_layer(hw); | layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); | ||||
/* Media types with matching FreeBSD media defines */ | /* Media types with matching FreeBSD media defines */ | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); | ||||
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) | if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); | ||||
if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) | if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | ixgbe_initialize_transmit_units(struct adapter *adapter) | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
/* Setup the Base and Length of the Tx Descriptor Ring */ | /* Setup the Base and Length of the Tx Descriptor Ring */ | ||||
for (int i = 0; i < adapter->num_queues; i++, txr++) { | for (int i = 0; i < adapter->num_queues; i++, txr++) { | ||||
u64 tdba = txr->txdma.dma_paddr; | u64 tdba = txr->txdma.dma_paddr; | ||||
u32 txctrl = 0; | u32 txctrl = 0; | ||||
int j = txr->me; | |||||
IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), | IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), | ||||
(tdba & 0x00000000ffffffffULL)); | (tdba & 0x00000000ffffffffULL)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), | IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), | ||||
adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); | adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); | ||||
/* Setup the HW Tx Head and Tail descriptor pointers */ | /* Setup the HW Tx Head and Tail descriptor pointers */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0); | IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0); | IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); | ||||
/* Cache the tail address */ | /* Cache the tail address */ | ||||
txr->tail = IXGBE_TDT(txr->me); | txr->tail = IXGBE_TDT(j); | ||||
/* Disable Head Writeback */ | /* Disable Head Writeback */ | ||||
switch (hw->mac.type) { | switch (hw->mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); | txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); | ||||
break; | break; | ||||
case ixgbe_mac_82599EB: | case ixgbe_mac_82599EB: | ||||
case ixgbe_mac_X540: | case ixgbe_mac_X540: | ||||
default: | default: | ||||
txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); | txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); | ||||
break; | break; | ||||
} | } | ||||
txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; | txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; | ||||
switch (hw->mac.type) { | switch (hw->mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); | IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); | ||||
break; | break; | ||||
case ixgbe_mac_82599EB: | case ixgbe_mac_82599EB: | ||||
case ixgbe_mac_X540: | case ixgbe_mac_X540: | ||||
default: | default: | ||||
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), txctrl); | IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (hw->mac.type != ixgbe_mac_82598EB) { | if (hw->mac.type != ixgbe_mac_82598EB) { | ||||
u32 dmatxctl, rttdcs; | u32 dmatxctl, rttdcs; | ||||
#ifdef PCI_IOV | |||||
enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter); | |||||
#endif | |||||
dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); | dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); | ||||
dmatxctl |= IXGBE_DMATXCTL_TE; | dmatxctl |= IXGBE_DMATXCTL_TE; | ||||
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); | IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); | ||||
/* Disable arbiter to set MTQC */ | /* Disable arbiter to set MTQC */ | ||||
rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); | rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); | ||||
rttdcs |= IXGBE_RTTDCS_ARBDIS; | rttdcs |= IXGBE_RTTDCS_ARBDIS; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | ||||
#ifdef PCI_IOV | |||||
IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode)); | |||||
#else | |||||
IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); | IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); | ||||
#endif | |||||
rttdcs &= ~IXGBE_RTTDCS_ARBDIS; | rttdcs &= ~IXGBE_RTTDCS_ARBDIS; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
static void | static void | ||||
ixgbe_initialise_rss_mapping(struct adapter *adapter) | ixgbe_initialise_rss_mapping(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
uint32_t reta; | u32 reta = 0, mrqc, rss_key[10]; | ||||
int i, j, queue_id, table_size; | int queue_id, table_size, index_mult; | ||||
int index_mult; | #ifdef RSS | ||||
uint32_t rss_key[10]; | u32 rss_hash_config; | ||||
uint32_t mrqc; | #endif | ||||
#ifdef PCI_IOV | |||||
enum ixgbe_iov_mode mode; | |||||
#endif | |||||
/* Setup RSS */ | #ifdef RSS | ||||
reta = 0; | /* Fetch the configured RSS key */ | ||||
rss_getkey((uint8_t *) &rss_key); | |||||
#else | |||||
/* set up random bits */ | /* set up random bits */ | ||||
arc4rand(&rss_key, sizeof(rss_key), 0); | arc4rand(&rss_key, sizeof(rss_key), 0); | ||||
#endif | |||||
/* Set multiplier for RETA setup and table size based on MAC */ | /* Set multiplier for RETA setup and table size based on MAC */ | ||||
index_mult = 0x1; | index_mult = 0x1; | ||||
table_size = 128; | table_size = 128; | ||||
switch (adapter->hw.mac.type) { | switch (adapter->hw.mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
index_mult = 0x11; | index_mult = 0x11; | ||||
break; | break; | ||||
case ixgbe_mac_X550: | case ixgbe_mac_X550: | ||||
case ixgbe_mac_X550EM_x: | case ixgbe_mac_X550EM_x: | ||||
table_size = 512; | table_size = 512; | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
/* Set up the redirection table */ | /* Set up the redirection table */ | ||||
for (i = 0, j = 0; i < table_size; i++, j++) { | for (int i = 0, j = 0; i < table_size; i++, j++) { | ||||
if (j == adapter->num_queues) j = 0; | if (j == adapter->num_queues) j = 0; | ||||
#ifdef RSS | |||||
/* | |||||
* Fetch the RSS bucket id for the given indirection entry. | |||||
* Cap it at the number of configured buckets (which is | |||||
* num_queues.) | |||||
*/ | |||||
queue_id = rss_get_indirection_to_bucket(i); | |||||
queue_id = queue_id % adapter->num_queues; | |||||
#else | |||||
queue_id = (j * index_mult); | queue_id = (j * index_mult); | ||||
#endif | |||||
/* | /* | ||||
* The low 8 bits are for hash value (n+0); | * The low 8 bits are for hash value (n+0); | ||||
* The next 8 bits are for hash value (n+1), etc. | * The next 8 bits are for hash value (n+1), etc. | ||||
*/ | */ | ||||
reta = reta >> 8; | reta = reta >> 8; | ||||
reta = reta | ( ((uint32_t) queue_id) << 24); | reta = reta | ( ((uint32_t) queue_id) << 24); | ||||
if ((i & 3) == 3) { | if ((i & 3) == 3) { | ||||
if (i < 128) | if (i < 128) | ||||
IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); | IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); | ||||
else | else | ||||
IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); | IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); | ||||
reta = 0; | reta = 0; | ||||
} | } | ||||
} | } | ||||
/* Now fill our hash function seeds */ | /* Now fill our hash function seeds */ | ||||
for (int i = 0; i < 10; i++) | for (int i = 0; i < 10; i++) | ||||
IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); | IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); | ||||
/* Perform hash on these packet types */ | /* Perform hash on these packet types */ | ||||
#ifdef RSS | |||||
mrqc = IXGBE_MRQC_RSSEN; | |||||
rss_hash_config = rss_gethashconfig(); | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) | |||||
device_printf(adapter->dev, | |||||
"%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " | |||||
"but not supported\n", __func__); | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) | |||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; | |||||
#else | |||||
/* | /* | ||||
* Disable UDP - IP fragments aren't currently being handled | * Disable UDP - IP fragments aren't currently being handled | ||||
* and so we end up with a mix of 2-tuple and 4-tuple | * and so we end up with a mix of 2-tuple and 4-tuple | ||||
* traffic. | * traffic. | ||||
*/ | */ | ||||
mrqc = IXGBE_MRQC_RSSEN | mrqc = IXGBE_MRQC_RSSEN | ||||
| IXGBE_MRQC_RSS_FIELD_IPV4 | | IXGBE_MRQC_RSS_FIELD_IPV4 | ||||
| IXGBE_MRQC_RSS_FIELD_IPV4_TCP | | IXGBE_MRQC_RSS_FIELD_IPV4_TCP | ||||
#if 0 | |||||
| IXGBE_MRQC_RSS_FIELD_IPV4_UDP | |||||
#endif | |||||
| IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | ||||
| IXGBE_MRQC_RSS_FIELD_IPV6_EX | | IXGBE_MRQC_RSS_FIELD_IPV6_EX | ||||
| IXGBE_MRQC_RSS_FIELD_IPV6 | | IXGBE_MRQC_RSS_FIELD_IPV6 | ||||
| IXGBE_MRQC_RSS_FIELD_IPV6_TCP | | IXGBE_MRQC_RSS_FIELD_IPV6_TCP | ||||
#if 0 | |||||
| IXGBE_MRQC_RSS_FIELD_IPV6_UDP | |||||
| IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP | |||||
#endif | |||||
; | ; | ||||
#endif /* RSS */ | |||||
#ifdef PCI_IOV | |||||
mode = ixgbe_get_iov_mode(adapter); | |||||
mrqc |= ixgbe_get_mrqc(mode); | |||||
#endif | |||||
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); | IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); | ||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Setup receive registers and features. | * Setup receive registers and features. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); | IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); | ||||
bufsz = (adapter->rx_mbuf_sz + | bufsz = (adapter->rx_mbuf_sz + | ||||
BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | ||||
for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (int i = 0; i < adapter->num_queues; i++, rxr++) { | ||||
u64 rdba = rxr->rxdma.dma_paddr; | u64 rdba = rxr->rxdma.dma_paddr; | ||||
int j = rxr->me; | |||||
/* Setup the Base and Length of the Rx Descriptor Ring */ | /* Setup the Base and Length of the Rx Descriptor Ring */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), | IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), | ||||
(rdba & 0x00000000ffffffffULL)); | (rdba & 0x00000000ffffffffULL)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), | IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), | ||||
adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | ||||
/* Set up the SRRCTL register */ | /* Set up the SRRCTL register */ | ||||
srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); | srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); | ||||
srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | ||||
srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | ||||
srrctl |= bufsz; | srrctl |= bufsz; | ||||
srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; | srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; | ||||
/* | /* | ||||
* Set DROP_EN iff we have no flow control and >1 queue. | * Set DROP_EN iff we have no flow control and >1 queue. | ||||
* Note that srrctl was cleared shortly before during reset, | * Note that srrctl was cleared shortly before during reset, | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | ixgbe_setup_vlan_hw_support(struct adapter *adapter) | ||||
if (adapter->num_vlans == 0) | if (adapter->num_vlans == 0) | ||||
return; | return; | ||||
/* Setup the queues for vlans */ | /* Setup the queues for vlans */ | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
rxr = &adapter->rx_rings[i]; | rxr = &adapter->rx_rings[i]; | ||||
/* On 82599 the VLAN enable is per/queue in RXDCTL */ | /* On 82599 the VLAN enable is per/queue in RXDCTL */ | ||||
if (hw->mac.type != ixgbe_mac_82598EB) { | if (hw->mac.type != ixgbe_mac_82598EB) { | ||||
ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); | ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); | ||||
ctrl |= IXGBE_RXDCTL_VME; | ctrl |= IXGBE_RXDCTL_VME; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl); | IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); | ||||
} | } | ||||
rxr->vtag_strip = TRUE; | rxr->vtag_strip = TRUE; | ||||
} | } | ||||
if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) | if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) | ||||
return; | return; | ||||
/* | /* | ||||
** A soft reset zero's out the VFTA, so | ** A soft reset zero's out the VFTA, so | ||||
Show All 33 Lines | case ixgbe_mac_82599EB: | ||||
/* Temperature sensor on some adapters */ | /* Temperature sensor on some adapters */ | ||||
mask |= IXGBE_EIMS_GPI_SDP0; | mask |= IXGBE_EIMS_GPI_SDP0; | ||||
/* SFP+ (RX_LOS_N & MOD_ABS_N) */ | /* SFP+ (RX_LOS_N & MOD_ABS_N) */ | ||||
mask |= IXGBE_EIMS_GPI_SDP1; | mask |= IXGBE_EIMS_GPI_SDP1; | ||||
mask |= IXGBE_EIMS_GPI_SDP2; | mask |= IXGBE_EIMS_GPI_SDP2; | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
mask |= IXGBE_EIMS_FLOW_DIR; | mask |= IXGBE_EIMS_FLOW_DIR; | ||||
#endif | #endif | ||||
#ifdef PCI_IOV | |||||
mask |= IXGBE_EIMS_MAILBOX; | |||||
#endif | |||||
break; | break; | ||||
case ixgbe_mac_X540: | case ixgbe_mac_X540: | ||||
/* Detect if Thermal Sensor is enabled */ | /* Detect if Thermal Sensor is enabled */ | ||||
fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); | fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); | ||||
if (fwsm & IXGBE_FWSM_TS_ENABLED) | if (fwsm & IXGBE_FWSM_TS_ENABLED) | ||||
mask |= IXGBE_EIMS_TS; | mask |= IXGBE_EIMS_TS; | ||||
mask |= IXGBE_EIMS_ECC; | mask |= IXGBE_EIMS_ECC; | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
mask |= IXGBE_EIMS_FLOW_DIR; | mask |= IXGBE_EIMS_FLOW_DIR; | ||||
#endif | #endif | ||||
break; | break; | ||||
case ixgbe_mac_X550: | case ixgbe_mac_X550: | ||||
case ixgbe_mac_X550EM_x: | case ixgbe_mac_X550EM_x: | ||||
/* MAC thermal sensor is automatically enabled */ | /* MAC thermal sensor is automatically enabled */ | ||||
mask |= IXGBE_EIMS_TS; | mask |= IXGBE_EIMS_TS; | ||||
/* Some devices use SDP0 for important information */ | /* Some devices use SDP0 for important information */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || | ||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) | hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) | ||||
mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); | mask |= IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); | ||||
mask |= IXGBE_EIMS_ECC; | mask |= IXGBE_EIMS_ECC; | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
mask |= IXGBE_EIMS_FLOW_DIR; | mask |= IXGBE_EIMS_FLOW_DIR; | ||||
#endif | #endif | ||||
#ifdef PCI_IOV | |||||
mask |= IXGBE_EIMS_MAILBOX; | |||||
#endif | |||||
/* falls through */ | /* falls through */ | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); | IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); | ||||
/* With MSI-X we use auto clear */ | /* With MSI-X we use auto clear */ | ||||
if (adapter->msix_mem) { | if (adapter->msix_mem) { | ||||
mask = IXGBE_EIMS_ENABLE_MASK; | mask = IXGBE_EIMS_ENABLE_MASK; | ||||
/* Don't autoclear Link */ | /* Don't autoclear Link */ | ||||
mask &= ~IXGBE_EIMS_OTHER; | mask &= ~IXGBE_EIMS_OTHER; | ||||
mask &= ~IXGBE_EIMS_LSC; | mask &= ~IXGBE_EIMS_LSC; | ||||
#ifdef PCI_IOV | |||||
mask &= ~IXGBE_EIMS_MAILBOX; | |||||
#endif | |||||
IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); | IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); | ||||
} | } | ||||
/* | /* | ||||
** Now enable all queues, this is done separately to | ** Now enable all queues, this is done separately to | ||||
** allow for handling the extended (beyond 32) MSIX | ** allow for handling the extended (beyond 32) MSIX | ||||
** vectors that can be used by 82599 | ** vectors that can be used by 82599 | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Lines | ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
ixgbe_configure_ivars(struct adapter *adapter) | ixgbe_configure_ivars(struct adapter *adapter) | ||||
{ | { | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
u32 newitr; | u32 newitr; | ||||
if (ixgbe_max_interrupt_rate > 0) | if (ixgbe_max_interrupt_rate > 0) | ||||
newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; | newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; | ||||
else { | else { | ||||
/* | /* | ||||
** Disable DMA coalescing if interrupt moderation is | ** Disable DMA coalescing if interrupt moderation is | ||||
** disabled. | ** disabled. | ||||
*/ | */ | ||||
adapter->dmac = 0; | adapter->dmac = 0; | ||||
newitr = 0; | newitr = 0; | ||||
} | } | ||||
for (int i = 0; i < adapter->num_queues; i++, que++) { | for (int i = 0; i < adapter->num_queues; i++, que++) { | ||||
struct rx_ring *rxr = &adapter->rx_rings[i]; | |||||
struct tx_ring *txr = &adapter->tx_rings[i]; | |||||
/* First the RX queue entry */ | /* First the RX queue entry */ | ||||
ixgbe_set_ivar(adapter, i, que->msix, 0); | ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); | ||||
/* ... and the TX */ | /* ... and the TX */ | ||||
ixgbe_set_ivar(adapter, i, que->msix, 1); | ixgbe_set_ivar(adapter, txr->me, que->msix, 1); | ||||
/* Set an Initial EITR value */ | /* Set an Initial EITR value */ | ||||
IXGBE_WRITE_REG(&adapter->hw, | IXGBE_WRITE_REG(&adapter->hw, | ||||
IXGBE_EITR(que->msix), newitr); | IXGBE_EITR(que->msix), newitr); | ||||
} | } | ||||
/* For the Link interrupt */ | /* For the Link interrupt */ | ||||
ixgbe_set_ivar(adapter, 1, adapter->vector, -1); | ixgbe_set_ivar(adapter, 1, adapter->vector, -1); | ||||
} | } | ||||
/* | /* | ||||
** ixgbe_sfp_probe - called in the local timer to | ** ixgbe_sfp_probe - called in the local timer to | ||||
** determine if a port had optics inserted. | ** determine if a port had optics inserted. | ||||
*/ | */ | ||||
static bool ixgbe_sfp_probe(struct adapter *adapter) | static bool | ||||
ixgbe_sfp_probe(struct adapter *adapter) | |||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
bool result = FALSE; | bool result = FALSE; | ||||
if ((hw->phy.type == ixgbe_phy_nl) && | if ((hw->phy.type == ixgbe_phy_nl) && | ||||
(hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { | (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { | ||||
s32 ret = hw->phy.ops.identify_sfp(hw); | s32 ret = hw->phy.ops.identify_sfp(hw); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | ixgbe_handle_mod(void *context, int pending) | ||||
u32 err; | u32 err; | ||||
err = hw->phy.ops.identify_sfp(hw); | err = hw->phy.ops.identify_sfp(hw); | ||||
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Unsupported SFP+ module type was detected.\n"); | "Unsupported SFP+ module type was detected.\n"); | ||||
return; | return; | ||||
} | } | ||||
err = hw->mac.ops.setup_sfp(hw); | err = hw->mac.ops.setup_sfp(hw); | ||||
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Setup failure - unsupported SFP+ module type.\n"); | "Setup failure - unsupported SFP+ module type.\n"); | ||||
return; | return; | ||||
} | } | ||||
taskqueue_enqueue(adapter->tq, &adapter->msf_task); | taskqueue_enqueue(adapter->tq, &adapter->msf_task); | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | |||||
* Checks whether the adapter supports Energy Efficient Ethernet | * Checks whether the adapter supports Energy Efficient Ethernet | ||||
* or not, based on device ID. | * or not, based on device ID. | ||||
*/ | */ | ||||
static void | static void | ||||
ixgbe_check_eee_support(struct adapter *adapter) | ixgbe_check_eee_support(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
adapter->eee_support = adapter->eee_enabled = | adapter->eee_enabled = !!(hw->mac.ops.setup_eee); | ||||
(hw->device_id == IXGBE_DEV_ID_X550T || | |||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_KR); | |||||
} | } | ||||
/* | /* | ||||
* Checks whether the adapter's ports are capable of | * Checks whether the adapter's ports are capable of | ||||
* Wake On LAN by reading the adapter's NVM. | * Wake On LAN by reading the adapter's NVM. | ||||
* | * | ||||
* Sets each port's hw->wol_enabled value depending | * Sets each port's hw->wol_enabled value depending | ||||
* on the value read here. | * on the value read here. | ||||
▲ Show 20 Lines • Show All 359 Lines • ▼ Show 20 Lines | ixgbe_add_device_sysctls(struct adapter *adapter) | ||||
/* for X550 devices */ | /* for X550 devices */ | ||||
if (hw->mac.type >= ixgbe_mac_X550) | if (hw->mac.type >= ixgbe_mac_X550) | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | ||||
ixgbe_sysctl_dmac, "I", "DMA Coalesce"); | ixgbe_sysctl_dmac, "I", "DMA Coalesce"); | ||||
/* for X550T and X550EM backplane devices */ | /* for X550T and X550EM backplane devices */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550T || | if (hw->mac.ops.setup_eee) { | ||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { | |||||
struct sysctl_oid *eee_node; | struct sysctl_oid *eee_node; | ||||
struct sysctl_oid_list *eee_list; | struct sysctl_oid_list *eee_list; | ||||
eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", | eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", | ||||
CTLFLAG_RD, NULL, | CTLFLAG_RD, NULL, | ||||
"Energy Efficient Ethernet sysctls"); | "Energy Efficient Ethernet sysctls"); | ||||
eee_list = SYSCTL_CHILDREN(eee_node); | eee_list = SYSCTL_CHILDREN(eee_node); | ||||
▲ Show 20 Lines • Show All 613 Lines • ▼ Show 20 Lines | |||||
* Values: | * Values: | ||||
* 0 - disabled | * 0 - disabled | ||||
* 1 - enabled | * 1 - enabled | ||||
*/ | */ | ||||
static int | static int | ||||
ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
struct ixgbe_hw *hw = &adapter->hw; | |||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
int new_eee_enabled, error = 0; | int new_eee_enabled, error = 0; | ||||
new_eee_enabled = adapter->eee_enabled; | new_eee_enabled = adapter->eee_enabled; | ||||
error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req); | error = sysctl_handle_int(oidp, &new_eee_enabled, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
if (new_eee_enabled == adapter->eee_enabled) | if (new_eee_enabled == adapter->eee_enabled) | ||||
return (0); | return (0); | ||||
if (new_eee_enabled > 0 && !adapter->eee_support) | if (new_eee_enabled > 0 && !hw->mac.ops.setup_eee) | ||||
return (ENODEV); | return (ENODEV); | ||||
else | else | ||||
adapter->eee_enabled = !!(new_eee_enabled); | adapter->eee_enabled = !!(new_eee_enabled); | ||||
/* Re-initialize hardware if it's already running */ | /* Re-initialize hardware if it's already running */ | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
ixgbe_init(adapter); | ixgbe_init(adapter); | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | |||||
** disabled. | ** disabled. | ||||
*/ | */ | ||||
static void | static void | ||||
ixgbe_enable_rx_drop(struct adapter *adapter) | ixgbe_enable_rx_drop(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); | struct rx_ring *rxr = &adapter->rx_rings[i]; | ||||
u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); | |||||
srrctl |= IXGBE_SRRCTL_DROP_EN; | srrctl |= IXGBE_SRRCTL_DROP_EN; | ||||
IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); | IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); | ||||
} | } | ||||
#ifdef PCI_IOV | |||||
/* enable drop for each vf */ | |||||
for (int i = 0; i < adapter->num_vfs; i++) { | |||||
IXGBE_WRITE_REG(hw, IXGBE_QDE, | |||||
(IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | | |||||
IXGBE_QDE_ENABLE)); | |||||
} | } | ||||
#endif | |||||
} | |||||
static void | static void | ||||
ixgbe_disable_rx_drop(struct adapter *adapter) | ixgbe_disable_rx_drop(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); | struct rx_ring *rxr = &adapter->rx_rings[i]; | ||||
u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); | |||||
srrctl &= ~IXGBE_SRRCTL_DROP_EN; | srrctl &= ~IXGBE_SRRCTL_DROP_EN; | ||||
IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); | IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); | ||||
} | } | ||||
#ifdef PCI_IOV | |||||
/* disable drop for each vf */ | |||||
for (int i = 0; i < adapter->num_vfs; i++) { | |||||
IXGBE_WRITE_REG(hw, IXGBE_QDE, | |||||
(IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); | |||||
} | } | ||||
#endif | |||||
} | |||||
static void | static void | ||||
ixgbe_rearm_queues(struct adapter *adapter, u64 queues) | ixgbe_rearm_queues(struct adapter *adapter, u64 queues) | ||||
{ | { | ||||
u32 mask; | u32 mask; | ||||
switch (adapter->hw.mac.type) { | switch (adapter->hw.mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
Show All 9 Lines | case ixgbe_mac_X550EM_x: | ||||
mask = (queues >> 32); | mask = (queues >> 32); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
#ifdef PCI_IOV | |||||
/* | |||||
** Support functions for SRIOV/VF management | |||||
*/ | |||||
static void | |||||
ixgbe_ping_all_vfs(struct adapter *adapter) | |||||
{ | |||||
struct ixgbe_vf *vf; | |||||
for (int i = 0; i < adapter->num_vfs; i++) { | |||||
vf = &adapter->vfs[i]; | |||||
if (vf->flags & IXGBE_VF_ACTIVE) | |||||
ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); | |||||
} | |||||
} | |||||
static void | |||||
ixgbe_vf_set_default_vlan(struct adapter *adapter, struct ixgbe_vf *vf, | |||||
uint16_t tag) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t vmolr, vmvir; | |||||
hw = &adapter->hw; | |||||
vf->vlan_tag = tag; | |||||
vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); | |||||
/* Do not receive packets that pass inexact filters. */ | |||||
vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE); | |||||
/* Disable Multicast Promicuous Mode. */ | |||||
vmolr &= ~IXGBE_VMOLR_MPE; | |||||
/* Accept broadcasts. */ | |||||
vmolr |= IXGBE_VMOLR_BAM; | |||||
if (tag == 0) { | |||||
/* Accept non-vlan tagged traffic. */ | |||||
//vmolr |= IXGBE_VMOLR_AUPE; | |||||
/* Allow VM to tag outgoing traffic; no default tag. */ | |||||
vmvir = 0; | |||||
} else { | |||||
/* Require vlan-tagged traffic. */ | |||||
vmolr &= ~IXGBE_VMOLR_AUPE; | |||||
/* Tag all traffic with provided vlan tag. */ | |||||
vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT); | |||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); | |||||
} | |||||
static boolean_t | |||||
ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf) | |||||
{ | |||||
/* | |||||
* Frame size compatibility between PF and VF is only a problem on | |||||
* 82599-based cards. X540 and later support any combination of jumbo | |||||
* frames on PFs and VFs. | |||||
*/ | |||||
if (adapter->hw.mac.type != ixgbe_mac_82599EB) | |||||
return (TRUE); | |||||
switch (vf->api_ver) { | |||||
case IXGBE_API_VER_1_0: | |||||
case IXGBE_API_VER_UNKNOWN: | |||||
/* | |||||
* On legacy (1.0 and older) VF versions, we don't support jumbo | |||||
* frames on either the PF or the VF. | |||||
*/ | |||||
if (adapter->max_frame_size > ETHER_MAX_LEN || | |||||
vf->max_frame_size > ETHER_MAX_LEN) | |||||
return (FALSE); | |||||
return (TRUE); | |||||
break; | |||||
case IXGBE_API_VER_1_1: | |||||
default: | |||||
/* | |||||
* 1.1 or later VF versions always work if they aren't using | |||||
* jumbo frames. | |||||
*/ | |||||
if (vf->max_frame_size <= ETHER_MAX_LEN) | |||||
return (TRUE); | |||||
/* | |||||
* Jumbo frames only work with VFs if the PF is also using jumbo | |||||
* frames. | |||||
*/ | |||||
if (adapter->max_frame_size <= ETHER_MAX_LEN) | |||||
return (TRUE); | |||||
return (FALSE); | |||||
} | |||||
} | |||||
static void | |||||
ixgbe_process_vf_reset(struct adapter *adapter, struct ixgbe_vf *vf) | |||||
{ | |||||
ixgbe_vf_set_default_vlan(adapter, vf, vf->default_vlan); | |||||
// XXX clear multicast addresses | |||||
ixgbe_clear_rar(&adapter->hw, vf->rar_index); | |||||
vf->api_ver = IXGBE_API_VER_UNKNOWN; | |||||
} | |||||
static void | |||||
ixgbe_vf_enable_transmit(struct adapter *adapter, struct ixgbe_vf *vf) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t vf_index, vfte; | |||||
hw = &adapter->hw; | |||||
vf_index = IXGBE_VF_INDEX(vf->pool); | |||||
vfte = IXGBE_READ_REG(hw, IXGBE_VFTE(vf_index)); | |||||
vfte |= IXGBE_VF_BIT(vf->pool); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_index), vfte); | |||||
} | |||||
static void | |||||
ixgbe_vf_enable_receive(struct adapter *adapter, struct ixgbe_vf *vf) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t vf_index, vfre; | |||||
hw = &adapter->hw; | |||||
vf_index = IXGBE_VF_INDEX(vf->pool); | |||||
vfre = IXGBE_READ_REG(hw, IXGBE_VFRE(vf_index)); | |||||
if (ixgbe_vf_frame_size_compatible(adapter, vf)) | |||||
vfre |= IXGBE_VF_BIT(vf->pool); | |||||
else | |||||
vfre &= ~IXGBE_VF_BIT(vf->pool); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_index), vfre); | |||||
} | |||||
static void | |||||
ixgbe_vf_reset_msg(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t ack; | |||||
uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN]; | |||||
hw = &adapter->hw; | |||||
ixgbe_process_vf_reset(adapter, vf); | |||||
if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { | |||||
ixgbe_set_rar(&adapter->hw, vf->rar_index, | |||||
vf->ether_addr, vf->pool, TRUE); | |||||
ack = IXGBE_VT_MSGTYPE_ACK; | |||||
} else | |||||
ack = IXGBE_VT_MSGTYPE_NACK; | |||||
ixgbe_vf_enable_transmit(adapter, vf); | |||||
ixgbe_vf_enable_receive(adapter, vf); | |||||
vf->flags |= IXGBE_VF_CTS; | |||||
resp[0] = IXGBE_VF_RESET | ack | IXGBE_VT_MSGTYPE_CTS; | |||||
bcopy(vf->ether_addr, &resp[1], ETHER_ADDR_LEN); | |||||
resp[3] = hw->mac.mc_filter_type; | |||||
ixgbe_write_mbx(hw, resp, IXGBE_VF_PERMADDR_MSG_LEN, vf->pool); | |||||
} | |||||
static void | |||||
ixgbe_vf_set_mac(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) | |||||
{ | |||||
uint8_t *mac; | |||||
mac = (uint8_t*)&msg[1]; | |||||
/* Check that the VF has permission to change the MAC address. */ | |||||
if (!(vf->flags & IXGBE_VF_CAP_MAC) && ixgbe_vf_mac_changed(vf, mac)) { | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
if (ixgbe_validate_mac_addr(mac) != 0) { | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); | |||||
ixgbe_set_rar(&adapter->hw, vf->rar_index, vf->ether_addr, | |||||
vf->pool, TRUE); | |||||
ixgbe_send_vf_ack(adapter, vf, msg[0]); | |||||
} | |||||
/* | |||||
** VF multicast addresses are set by using the appropriate bit in | |||||
** 1 of 128 32 bit addresses (4096 possible). | |||||
*/ | |||||
static void | |||||
ixgbe_vf_set_mc_addr(struct adapter *adapter, struct ixgbe_vf *vf, u32 *msg) | |||||
{ | |||||
u16 *list = (u16*)&msg[1]; | |||||
int entries; | |||||
u32 vmolr, vec_bit, vec_reg, mta_reg; | |||||
entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; | |||||
entries = min(entries, IXGBE_MAX_VF_MC); | |||||
vmolr = IXGBE_READ_REG(&adapter->hw, IXGBE_VMOLR(vf->pool)); | |||||
vf->num_mc_hashes = entries; | |||||
/* Set the appropriate MTA bit */ | |||||
for (int i = 0; i < entries; i++) { | |||||
vf->mc_hash[i] = list[i]; | |||||
vec_reg = (vf->mc_hash[i] >> 5) & 0x7F; | |||||
vec_bit = vf->mc_hash[i] & 0x1F; | |||||
mta_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_MTA(vec_reg)); | |||||
mta_reg |= (1 << vec_bit); | |||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_MTA(vec_reg), mta_reg); | |||||
} | |||||
vmolr |= IXGBE_VMOLR_ROMPE; | |||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_VMOLR(vf->pool), vmolr); | |||||
ixgbe_send_vf_ack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
static void | |||||
ixgbe_vf_set_vlan(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
int enable; | |||||
uint16_t tag; | |||||
hw = &adapter->hw; | |||||
enable = IXGBE_VT_MSGINFO(msg[0]); | |||||
tag = msg[1] & IXGBE_VLVF_VLANID_MASK; | |||||
if (!(vf->flags & IXGBE_VF_CAP_VLAN)) { | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
/* It is illegal to enable vlan tag 0. */ | |||||
if (tag == 0 && enable != 0){ | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
ixgbe_set_vfta(hw, tag, vf->pool, enable); | |||||
ixgbe_send_vf_ack(adapter, vf, msg[0]); | |||||
} | |||||
static void | |||||
ixgbe_vf_set_lpe(struct adapter *adapter, struct ixgbe_vf *vf, uint32_t *msg) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t vf_max_size, pf_max_size, mhadd; | |||||
hw = &adapter->hw; | |||||
vf_max_size = msg[1]; | |||||
if (vf_max_size < ETHER_CRC_LEN) { | |||||
/* We intentionally ACK invalid LPE requests. */ | |||||
ixgbe_send_vf_ack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
vf_max_size -= ETHER_CRC_LEN; | |||||
if (vf_max_size > IXGBE_MAX_FRAME_SIZE) { | |||||
/* We intentionally ACK invalid LPE requests. */ | |||||
ixgbe_send_vf_ack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
vf->max_frame_size = vf_max_size; | |||||
ixgbe_update_max_frame(adapter, vf->max_frame_size); | |||||
/* | |||||
* We might have to disable reception to this VF if the frame size is | |||||
* not compatible with the config on the PF. | |||||
*/ | |||||
ixgbe_vf_enable_receive(adapter, vf); | |||||
mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); | |||||
pf_max_size = (mhadd & IXGBE_MHADD_MFS_MASK) >> IXGBE_MHADD_MFS_SHIFT; | |||||
if (pf_max_size < adapter->max_frame_size) { | |||||
mhadd &= ~IXGBE_MHADD_MFS_MASK; | |||||
mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; | |||||
IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); | |||||
} | |||||
ixgbe_send_vf_ack(adapter, vf, msg[0]); | |||||
} | |||||
static void | |||||
ixgbe_vf_set_macvlan(struct adapter *adapter, struct ixgbe_vf *vf, | |||||
uint32_t *msg) | |||||
{ | |||||
//XXX implement this | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
} | |||||
static void | |||||
ixgbe_vf_api_negotiate(struct adapter *adapter, struct ixgbe_vf *vf, | |||||
uint32_t *msg) | |||||
{ | |||||
switch (msg[1]) { | |||||
case IXGBE_API_VER_1_0: | |||||
case IXGBE_API_VER_1_1: | |||||
vf->api_ver = msg[1]; | |||||
ixgbe_send_vf_ack(adapter, vf, msg[0]); | |||||
break; | |||||
default: | |||||
vf->api_ver = IXGBE_API_VER_UNKNOWN; | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
break; | |||||
} | |||||
} | |||||
static void | |||||
ixgbe_vf_get_queues(struct adapter *adapter, struct ixgbe_vf *vf, | |||||
uint32_t *msg) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t resp[IXGBE_VF_GET_QUEUES_RESP_LEN]; | |||||
int num_queues; | |||||
hw = &adapter->hw; | |||||
/* GET_QUEUES is not supported on pre-1.1 APIs. */ | |||||
switch (msg[0]) { | |||||
case IXGBE_API_VER_1_0: | |||||
case IXGBE_API_VER_UNKNOWN: | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
resp[0] = IXGBE_VF_GET_QUEUES | IXGBE_VT_MSGTYPE_ACK | | |||||
IXGBE_VT_MSGTYPE_CTS; | |||||
num_queues = ixgbe_vf_queues(ixgbe_get_iov_mode(adapter)); | |||||
resp[IXGBE_VF_TX_QUEUES] = num_queues; | |||||
resp[IXGBE_VF_RX_QUEUES] = num_queues; | |||||
resp[IXGBE_VF_TRANS_VLAN] = (vf->default_vlan != 0); | |||||
resp[IXGBE_VF_DEF_QUEUE] = 0; | |||||
ixgbe_write_mbx(hw, resp, IXGBE_VF_GET_QUEUES_RESP_LEN, vf->pool); | |||||
} | |||||
static void | |||||
ixgbe_process_vf_msg(struct adapter *adapter, struct ixgbe_vf *vf) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t msg[IXGBE_VFMAILBOX_SIZE]; | |||||
int error; | |||||
hw = &adapter->hw; | |||||
error = ixgbe_read_mbx(hw, msg, IXGBE_VFMAILBOX_SIZE, vf->pool); | |||||
if (error != 0) | |||||
return; | |||||
CTR3(KTR_MALLOC, "%s: received msg %x from %d", | |||||
adapter->ifp->if_xname, msg[0], vf->pool); | |||||
if (msg[0] == IXGBE_VF_RESET) { | |||||
ixgbe_vf_reset_msg(adapter, vf, msg); | |||||
return; | |||||
} | |||||
if (!(vf->flags & IXGBE_VF_CTS)) { | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
return; | |||||
} | |||||
switch (msg[0] & IXGBE_VT_MSG_MASK) { | |||||
case IXGBE_VF_SET_MAC_ADDR: | |||||
ixgbe_vf_set_mac(adapter, vf, msg); | |||||
break; | |||||
case IXGBE_VF_SET_MULTICAST: | |||||
ixgbe_vf_set_mc_addr(adapter, vf, msg); | |||||
break; | |||||
case IXGBE_VF_SET_VLAN: | |||||
ixgbe_vf_set_vlan(adapter, vf, msg); | |||||
break; | |||||
case IXGBE_VF_SET_LPE: | |||||
ixgbe_vf_set_lpe(adapter, vf, msg); | |||||
break; | |||||
case IXGBE_VF_SET_MACVLAN: | |||||
ixgbe_vf_set_macvlan(adapter, vf, msg); | |||||
break; | |||||
case IXGBE_VF_API_NEGOTIATE: | |||||
ixgbe_vf_api_negotiate(adapter, vf, msg); | |||||
break; | |||||
case IXGBE_VF_GET_QUEUES: | |||||
ixgbe_vf_get_queues(adapter, vf, msg); | |||||
break; | |||||
default: | |||||
ixgbe_send_vf_nack(adapter, vf, msg[0]); | |||||
} | |||||
} | |||||
/* | |||||
* Tasklet for handling VF -> PF mailbox messages. | |||||
*/ | |||||
static void | |||||
ixgbe_handle_mbx(void *context, int pending) | |||||
{ | |||||
struct adapter *adapter; | |||||
struct ixgbe_hw *hw; | |||||
struct ixgbe_vf *vf; | |||||
int i; | |||||
adapter = context; | |||||
hw = &adapter->hw; | |||||
IXGBE_CORE_LOCK(adapter); | |||||
for (i = 0; i < adapter->num_vfs; i++) { | |||||
vf = &adapter->vfs[i]; | |||||
if (vf->flags & IXGBE_VF_ACTIVE) { | |||||
if (ixgbe_check_for_rst(hw, vf->pool) == 0) | |||||
ixgbe_process_vf_reset(adapter, vf); | |||||
if (ixgbe_check_for_msg(hw, vf->pool) == 0) | |||||
ixgbe_process_vf_msg(adapter, vf); | |||||
if (ixgbe_check_for_ack(hw, vf->pool) == 0) | |||||
ixgbe_process_vf_ack(adapter, vf); | |||||
} | |||||
} | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
} | |||||
static int | |||||
ixgbe_init_iov(device_t dev, u16 num_vfs, const nvlist_t *config) | |||||
{ | |||||
struct adapter *adapter; | |||||
enum ixgbe_iov_mode mode; | |||||
adapter = device_get_softc(dev); | |||||
adapter->num_vfs = num_vfs; | |||||
mode = ixgbe_get_iov_mode(adapter); | |||||
if (num_vfs > ixgbe_max_vfs(mode)) { | |||||
adapter->num_vfs = 0; | |||||
return (ENOSPC); | |||||
} | |||||
IXGBE_CORE_LOCK(adapter); | |||||
adapter->vfs = malloc(sizeof(*adapter->vfs) * num_vfs, M_IXGBE, | |||||
M_NOWAIT | M_ZERO); | |||||
if (adapter->vfs == NULL) { | |||||
adapter->num_vfs = 0; | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
return (ENOMEM); | |||||
} | |||||
ixgbe_init_locked(adapter); | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
return (0); | |||||
} | |||||
static void | |||||
ixgbe_uninit_iov(device_t dev) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
struct adapter *adapter; | |||||
uint32_t pf_reg, vf_reg; | |||||
adapter = device_get_softc(dev); | |||||
hw = &adapter->hw; | |||||
IXGBE_CORE_LOCK(adapter); | |||||
/* Enable rx/tx for the PF and disable it for all VFs. */ | |||||
pf_reg = IXGBE_VF_INDEX(adapter->pool); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRE(pf_reg), | |||||
IXGBE_VF_BIT(adapter->pool)); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFTE(pf_reg), | |||||
IXGBE_VF_BIT(adapter->pool)); | |||||
if (pf_reg == 0) | |||||
vf_reg = 1; | |||||
else | |||||
vf_reg = 0; | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), 0); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), 0); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, 0); | |||||
free(adapter->vfs, M_IXGBE); | |||||
adapter->vfs = NULL; | |||||
adapter->num_vfs = 0; | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
} | |||||
static void | |||||
ixgbe_initialize_iov(struct adapter *adapter) | |||||
{ | |||||
struct ixgbe_hw *hw = &adapter->hw; | |||||
uint32_t mrqc, mtqc, vt_ctl, vf_reg, gcr_ext, gpie; | |||||
enum ixgbe_iov_mode mode; | |||||
int i; | |||||
mode = ixgbe_get_iov_mode(adapter); | |||||
if (mode == IXGBE_NO_VM) | |||||
return; | |||||
IXGBE_CORE_LOCK_ASSERT(adapter); | |||||
mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC); | |||||
mrqc &= ~IXGBE_MRQC_MRQE_MASK; | |||||
switch (mode) { | |||||
case IXGBE_64_VM: | |||||
mrqc |= IXGBE_MRQC_VMDQRSS64EN; | |||||
break; | |||||
case IXGBE_32_VM: | |||||
mrqc |= IXGBE_MRQC_VMDQRSS32EN; | |||||
break; | |||||
default: | |||||
panic("Unexpected SR-IOV mode %d", mode); | |||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); | |||||
mtqc = IXGBE_MTQC_VT_ENA; | |||||
switch (mode) { | |||||
case IXGBE_64_VM: | |||||
mtqc |= IXGBE_MTQC_64VF; | |||||
break; | |||||
case IXGBE_32_VM: | |||||
mtqc |= IXGBE_MTQC_32VF; | |||||
break; | |||||
default: | |||||
panic("Unexpected SR-IOV mode %d", mode); | |||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc); | |||||
gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); | |||||
gcr_ext |= IXGBE_GCR_EXT_MSIX_EN; | |||||
gcr_ext &= ~IXGBE_GCR_EXT_VT_MODE_MASK; | |||||
switch (mode) { | |||||
case IXGBE_64_VM: | |||||
gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64; | |||||
break; | |||||
case IXGBE_32_VM: | |||||
gcr_ext |= IXGBE_GCR_EXT_VT_MODE_32; | |||||
break; | |||||
default: | |||||
panic("Unexpected SR-IOV mode %d", mode); | |||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); | |||||
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); | |||||
gcr_ext &= ~IXGBE_GPIE_VTMODE_MASK; | |||||
switch (mode) { | |||||
case IXGBE_64_VM: | |||||
gpie |= IXGBE_GPIE_VTMODE_64; | |||||
break; | |||||
case IXGBE_32_VM: | |||||
gpie |= IXGBE_GPIE_VTMODE_32; | |||||
break; | |||||
default: | |||||
panic("Unexpected SR-IOV mode %d", mode); | |||||
} | |||||
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); | |||||
/* Enable rx/tx for the PF. */ | |||||
vf_reg = IXGBE_VF_INDEX(adapter->pool); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFRE(vf_reg), | |||||
IXGBE_VF_BIT(adapter->pool)); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VFTE(vf_reg), | |||||
IXGBE_VF_BIT(adapter->pool)); | |||||
/* Allow VM-to-VM communication. */ | |||||
IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); | |||||
vt_ctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; | |||||
vt_ctl |= (adapter->pool << IXGBE_VT_CTL_POOL_SHIFT); | |||||
IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl); | |||||
for (i = 0; i < adapter->num_vfs; i++) | |||||
ixgbe_init_vf(adapter, &adapter->vfs[i]); | |||||
} | |||||
/* | |||||
** Check the max frame setting of all active VF's | |||||
*/ | |||||
static void | |||||
ixgbe_recalculate_max_frame(struct adapter *adapter) | |||||
{ | |||||
struct ixgbe_vf *vf; | |||||
IXGBE_CORE_LOCK_ASSERT(adapter); | |||||
for (int i = 0; i < adapter->num_vfs; i++) { | |||||
vf = &adapter->vfs[i]; | |||||
if (vf->flags & IXGBE_VF_ACTIVE) | |||||
ixgbe_update_max_frame(adapter, vf->max_frame_size); | |||||
} | |||||
} | |||||
static void | |||||
ixgbe_init_vf(struct adapter *adapter, struct ixgbe_vf *vf) | |||||
{ | |||||
struct ixgbe_hw *hw; | |||||
uint32_t vf_index, pfmbimr; | |||||
IXGBE_CORE_LOCK_ASSERT(adapter); | |||||
hw = &adapter->hw; | |||||
if (!(vf->flags & IXGBE_VF_ACTIVE)) | |||||
return; | |||||
vf_index = IXGBE_VF_INDEX(vf->pool); | |||||
pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index)); | |||||
pfmbimr |= IXGBE_VF_BIT(vf->pool); | |||||
IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); | |||||
ixgbe_vf_set_default_vlan(adapter, vf, vf->vlan_tag); | |||||
// XXX multicast addresses | |||||
if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { | |||||
ixgbe_set_rar(&adapter->hw, vf->rar_index, | |||||
vf->ether_addr, vf->pool, TRUE); | |||||
} | |||||
ixgbe_vf_enable_transmit(adapter, vf); | |||||
ixgbe_vf_enable_receive(adapter, vf); | |||||
ixgbe_send_vf_msg(adapter, vf, IXGBE_PF_CONTROL_MSG); | |||||
} | |||||
static int | |||||
ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config) | |||||
{ | |||||
struct adapter *adapter; | |||||
struct ixgbe_vf *vf; | |||||
const void *mac; | |||||
adapter = device_get_softc(dev); | |||||
KASSERT(vfnum < adapter->num_vfs, ("VF index %d is out of range %d", | |||||
vfnum, adapter->num_vfs)); | |||||
IXGBE_CORE_LOCK(adapter); | |||||
vf = &adapter->vfs[vfnum]; | |||||
vf->pool= vfnum; | |||||
/* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */ | |||||
vf->rar_index = vfnum + 1; | |||||
vf->default_vlan = 0; | |||||
vf->max_frame_size = ETHER_MAX_LEN; | |||||
ixgbe_update_max_frame(adapter, vf->max_frame_size); | |||||
if (nvlist_exists_binary(config, "mac-addr")) { | |||||
mac = nvlist_get_binary(config, "mac-addr", NULL); | |||||
bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN); | |||||
if (nvlist_get_bool(config, "allow-set-mac")) | |||||
vf->flags |= IXGBE_VF_CAP_MAC; | |||||
} else | |||||
/* | |||||
* If the administrator has not specified a MAC address then | |||||
* we must allow the VF to choose one. | |||||
*/ | |||||
vf->flags |= IXGBE_VF_CAP_MAC; | |||||
vf->flags = IXGBE_VF_ACTIVE; | |||||
ixgbe_init_vf(adapter, vf); | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
return (0); | |||||
} | |||||
#endif /* PCI_IOV */ | |||||