net/ngbe: support device start/stop

Setup MSI-X interrupt, complete PHY configuration and set device link
speed to start device. Disable interrupt, stop hardware and clear queues
to stop device.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
This commit is contained in:
Jiawen Wu 2021-07-08 17:32:34 +08:00 committed by Andrew Rybchenko
parent a58e7c312c
commit 3518df5774
14 changed files with 778 additions and 0 deletions

View File

@ -47,6 +47,10 @@ static inline s32 ngbe_mac_reset_hw_dummy(struct ngbe_hw *TUP0)
{
return NGBE_ERR_OPS_DUMMY;
}
static inline s32 ngbe_mac_start_hw_dummy(struct ngbe_hw *TUP0)
{
return NGBE_ERR_OPS_DUMMY;
}
static inline s32 ngbe_mac_stop_hw_dummy(struct ngbe_hw *TUP0)
{
return NGBE_ERR_OPS_DUMMY;
@ -74,6 +78,11 @@ static inline s32 ngbe_mac_check_link_dummy(struct ngbe_hw *TUP0, u32 *TUP1,
{
return NGBE_ERR_OPS_DUMMY;
}
static inline s32 ngbe_mac_get_link_capabilities_dummy(struct ngbe_hw *TUP0,
u32 *TUP1, bool *TUP2)
{
return NGBE_ERR_OPS_DUMMY;
}
static inline s32 ngbe_mac_set_rar_dummy(struct ngbe_hw *TUP0, u32 TUP1,
u8 *TUP2, u32 TUP3, u32 TUP4)
{
@ -110,6 +119,10 @@ static inline s32 ngbe_phy_identify_dummy(struct ngbe_hw *TUP0)
{
return NGBE_ERR_OPS_DUMMY;
}
static inline s32 ngbe_phy_init_hw_dummy(struct ngbe_hw *TUP0)
{
return NGBE_ERR_OPS_DUMMY;
}
static inline s32 ngbe_phy_reset_hw_dummy(struct ngbe_hw *TUP0)
{
return NGBE_ERR_OPS_DUMMY;
@ -151,12 +164,14 @@ static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw)
hw->rom.validate_checksum = ngbe_rom_validate_checksum_dummy;
hw->mac.init_hw = ngbe_mac_init_hw_dummy;
hw->mac.reset_hw = ngbe_mac_reset_hw_dummy;
hw->mac.start_hw = ngbe_mac_start_hw_dummy;
hw->mac.stop_hw = ngbe_mac_stop_hw_dummy;
hw->mac.get_mac_addr = ngbe_mac_get_mac_addr_dummy;
hw->mac.acquire_swfw_sync = ngbe_mac_acquire_swfw_sync_dummy;
hw->mac.release_swfw_sync = ngbe_mac_release_swfw_sync_dummy;
hw->mac.setup_link = ngbe_mac_setup_link_dummy;
hw->mac.check_link = ngbe_mac_check_link_dummy;
hw->mac.get_link_capabilities = ngbe_mac_get_link_capabilities_dummy;
hw->mac.set_rar = ngbe_mac_set_rar_dummy;
hw->mac.clear_rar = ngbe_mac_clear_rar_dummy;
hw->mac.set_vmdq = ngbe_mac_set_vmdq_dummy;
@ -165,6 +180,7 @@ static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw)
hw->mac.init_thermal_sensor_thresh = ngbe_mac_init_thermal_ssth_dummy;
hw->mac.check_overtemp = ngbe_mac_check_overtemp_dummy;
hw->phy.identify = ngbe_phy_identify_dummy;
hw->phy.init_hw = ngbe_phy_init_hw_dummy;
hw->phy.reset_hw = ngbe_phy_reset_hw_dummy;
hw->phy.read_reg = ngbe_phy_read_reg_dummy;
hw->phy.write_reg = ngbe_phy_write_reg_dummy;

View File

@ -9,6 +9,22 @@
#include "ngbe_mng.h"
#include "ngbe_hw.h"
/**
* ngbe_start_hw - Prepare hardware for Tx/Rx
* @hw: pointer to hardware structure
*
* Starts the hardware.
**/
s32 ngbe_start_hw(struct ngbe_hw *hw)
{
DEBUGFUNC("ngbe_start_hw");
/* Clear adapter stopped flag */
hw->adapter_stopped = false;
return 0;
}
/**
* ngbe_init_hw - Generic hardware initialization
* @hw: pointer to hardware structure
@ -27,6 +43,10 @@ s32 ngbe_init_hw(struct ngbe_hw *hw)
/* Reset the hardware */
status = hw->mac.reset_hw(hw);
if (status == 0) {
/* Start the HW */
status = hw->mac.start_hw(hw);
}
if (status != 0)
DEBUGOUT("Failed to initialize HW, STATUS = %d\n", status);
@ -633,6 +653,29 @@ s32 ngbe_check_mac_link_em(struct ngbe_hw *hw, u32 *speed,
return status;
}
s32 ngbe_get_link_capabilities_em(struct ngbe_hw *hw,
u32 *speed,
bool *autoneg)
{
s32 status = 0;
DEBUGFUNC("\n");
hw->mac.autoneg = *autoneg;
switch (hw->sub_device_id) {
case NGBE_SUB_DEV_ID_EM_RTL_SGMII:
*speed = NGBE_LINK_SPEED_1GB_FULL |
NGBE_LINK_SPEED_100M_FULL |
NGBE_LINK_SPEED_10M_FULL;
break;
default:
break;
}
return status;
}
s32 ngbe_setup_mac_link_em(struct ngbe_hw *hw,
u32 speed,
bool autoneg_wait_to_complete)
@ -842,6 +885,7 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw)
/* MAC */
mac->init_hw = ngbe_init_hw;
mac->reset_hw = ngbe_reset_hw_em;
mac->start_hw = ngbe_start_hw;
mac->get_mac_addr = ngbe_get_mac_addr;
mac->stop_hw = ngbe_stop_hw;
mac->acquire_swfw_sync = ngbe_acquire_swfw_sync;
@ -855,6 +899,7 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw)
mac->clear_vmdq = ngbe_clear_vmdq;
/* Link */
mac->get_link_capabilities = ngbe_get_link_capabilities_em;
mac->check_link = ngbe_check_mac_link_em;
mac->setup_link = ngbe_setup_mac_link_em;
@ -871,6 +916,10 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw)
mac->max_rx_queues = NGBE_EM_MAX_RX_QUEUES;
mac->max_tx_queues = NGBE_EM_MAX_TX_QUEUES;
mac->default_speeds = NGBE_LINK_SPEED_10M_FULL |
NGBE_LINK_SPEED_100M_FULL |
NGBE_LINK_SPEED_1GB_FULL;
return 0;
}

View File

@ -14,6 +14,7 @@
#define NGBE_EM_MC_TBL_SIZE 32
s32 ngbe_init_hw(struct ngbe_hw *hw);
s32 ngbe_start_hw(struct ngbe_hw *hw);
s32 ngbe_reset_hw_em(struct ngbe_hw *hw);
s32 ngbe_stop_hw(struct ngbe_hw *hw);
s32 ngbe_get_mac_addr(struct ngbe_hw *hw, u8 *mac_addr);
@ -22,6 +23,9 @@ void ngbe_set_lan_id_multi_port(struct ngbe_hw *hw);
s32 ngbe_check_mac_link_em(struct ngbe_hw *hw, u32 *speed,
bool *link_up, bool link_up_wait_to_complete);
s32 ngbe_get_link_capabilities_em(struct ngbe_hw *hw,
u32 *speed,
bool *autoneg);
s32 ngbe_setup_mac_link_em(struct ngbe_hw *hw,
u32 speed,
bool autoneg_wait_to_complete);

View File

@ -426,16 +426,19 @@ s32 ngbe_init_phy(struct ngbe_hw *hw)
/* Set necessary function pointers based on PHY type */
switch (hw->phy.type) {
case ngbe_phy_rtl:
hw->phy.init_hw = ngbe_init_phy_rtl;
hw->phy.check_link = ngbe_check_phy_link_rtl;
hw->phy.setup_link = ngbe_setup_phy_link_rtl;
break;
case ngbe_phy_mvl:
case ngbe_phy_mvl_sfi:
hw->phy.init_hw = ngbe_init_phy_mvl;
hw->phy.check_link = ngbe_check_phy_link_mvl;
hw->phy.setup_link = ngbe_setup_phy_link_mvl;
break;
case ngbe_phy_yt8521s:
case ngbe_phy_yt8521s_sfi:
hw->phy.init_hw = ngbe_init_phy_yt;
hw->phy.check_link = ngbe_check_phy_link_yt;
hw->phy.setup_link = ngbe_setup_phy_link_yt;
default:

View File

@ -48,6 +48,70 @@ s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw,
return 0;
}
s32 ngbe_init_phy_mvl(struct ngbe_hw *hw)
{
s32 ret_val = 0;
u16 value = 0;
int i;
DEBUGFUNC("ngbe_init_phy_mvl");
/* enable interrupts, only link status change and an done is allowed */
ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 2);
ngbe_read_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, &value);
value &= ~MVL_RGM_CTL2_TTC;
value |= MVL_RGM_CTL2_RTC;
ngbe_write_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, value);
hw->phy.write_reg(hw, MVL_CTRL, 0, MVL_CTRL_RESET);
for (i = 0; i < 15; i++) {
ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
if (value & MVL_CTRL_RESET)
msleep(1);
else
break;
}
if (i == 15) {
DEBUGOUT("phy reset exceeds maximum waiting period.\n");
return NGBE_ERR_TIMEOUT;
}
ret_val = hw->phy.reset_hw(hw);
if (ret_val)
return ret_val;
/* set LED2 to interrupt output and INTn active low */
ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
ngbe_read_phy_reg_mdi(hw, MVL_LEDTCR, 0, &value);
value |= MVL_LEDTCR_INTR_EN;
value &= ~(MVL_LEDTCR_INTR_POL);
ngbe_write_phy_reg_mdi(hw, MVL_LEDTCR, 0, value);
if (hw->phy.type == ngbe_phy_mvl_sfi) {
hw->phy.read_reg(hw, MVL_CTRL1, 0, &value);
value &= ~MVL_CTRL1_INTR_POL;
ngbe_write_phy_reg_mdi(hw, MVL_CTRL1, 0, value);
}
/* enable link status change and AN complete interrupts */
value = MVL_INTR_EN_ANC | MVL_INTR_EN_LSC;
hw->phy.write_reg(hw, MVL_INTR_EN, 0, value);
/* LED control */
ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
ngbe_read_phy_reg_mdi(hw, MVL_LEDFCR, 0, &value);
value &= ~(MVL_LEDFCR_CTL0 | MVL_LEDFCR_CTL1);
value |= MVL_LEDFCR_CTL0_CONF | MVL_LEDFCR_CTL1_CONF;
ngbe_write_phy_reg_mdi(hw, MVL_LEDFCR, 0, value);
ngbe_read_phy_reg_mdi(hw, MVL_LEDPCR, 0, &value);
value &= ~(MVL_LEDPCR_CTL0 | MVL_LEDPCR_CTL1);
value |= MVL_LEDPCR_CTL0_CONF | MVL_LEDPCR_CTL1_CONF;
ngbe_write_phy_reg_mdi(hw, MVL_LEDPCR, 0, value);
return ret_val;
}
s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
bool autoneg_wait_to_complete)
{

View File

@ -86,6 +86,7 @@ s32 ngbe_read_phy_reg_mvl(struct ngbe_hw *hw, u32 reg_addr, u32 device_type,
u16 *phy_data);
s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw, u32 reg_addr, u32 device_type,
u16 phy_data);
s32 ngbe_init_phy_mvl(struct ngbe_hw *hw);
s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw);

View File

@ -38,6 +38,64 @@ s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw,
return 0;
}
s32 ngbe_init_phy_rtl(struct ngbe_hw *hw)
{
int i;
u16 value = 0;
/* enable interrupts, only link status change and an done is allowed */
value = RTL_INER_LSC | RTL_INER_ANC;
hw->phy.write_reg(hw, RTL_INER, 0xa42, value);
hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
for (i = 0; i < 15; i++) {
if (!rd32m(hw, NGBE_STAT,
NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id)))
break;
msec_delay(10);
}
if (i == 15) {
DEBUGOUT("GPhy reset exceeds maximum times.\n");
return NGBE_ERR_PHY_TIMEOUT;
}
for (i = 0; i < 1000; i++) {
hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
if (value & RTL_INSR_ACCESS)
break;
}
hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EFUSE);
for (i = 0; i < 1000; i++) {
hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
if (value & RTL_INSR_ACCESS)
break;
}
if (i == 1000)
return NGBE_ERR_PHY_TIMEOUT;
hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EXTINI);
for (i = 0; i < 1000; i++) {
hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
if (value & RTL_INSR_ACCESS)
break;
}
if (i == 1000)
return NGBE_ERR_PHY_TIMEOUT;
for (i = 0; i < 1000; i++) {
hw->phy.read_reg(hw, RTL_GSR, 0xa42, &value);
if ((value & RTL_GSR_ST) == RTL_GSR_ST_LANON)
break;
}
if (i == 1000)
return NGBE_ERR_PHY_TIMEOUT;
return 0;
}
/**
* ngbe_setup_phy_link_rtl - Set and restart auto-neg
* @hw: pointer to hardware structure

View File

@ -80,6 +80,8 @@ s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw, u32 reg_addr, u32 device_type,
s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw,
u32 speed, bool autoneg_wait_to_complete);
s32 ngbe_init_phy_rtl(struct ngbe_hw *hw);
s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw);
s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw,
u32 *speed, bool *link_up);

View File

@ -98,6 +98,32 @@ s32 ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw *hw,
return 0;
}
s32 ngbe_init_phy_yt(struct ngbe_hw *hw)
{
u16 value = 0;
DEBUGFUNC("ngbe_init_phy_yt");
if (hw->phy.type != ngbe_phy_yt8521s_sfi)
return 0;
/* select sds area register */
ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
/* enable interrupts */
ngbe_write_phy_reg_mdi(hw, YT_INTR, 0, YT_INTR_ENA_MASK);
/* select fiber_to_rgmii first in multiplex */
ngbe_read_phy_reg_ext_yt(hw, YT_MISC, 0, &value);
value |= YT_MISC_FIBER_PRIO;
ngbe_write_phy_reg_ext_yt(hw, YT_MISC, 0, value);
hw->phy.read_reg(hw, YT_BCR, 0, &value);
value |= YT_BCR_PWDN;
hw->phy.write_reg(hw, YT_BCR, 0, value);
return 0;
}
s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed,
bool autoneg_wait_to_complete)
{

View File

@ -65,6 +65,7 @@ s32 ngbe_read_phy_reg_sds_ext_yt(struct ngbe_hw *hw,
u32 reg_addr, u32 device_type, u16 *phy_data);
s32 ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw *hw,
u32 reg_addr, u32 device_type, u16 phy_data);
s32 ngbe_init_phy_yt(struct ngbe_hw *hw);
s32 ngbe_reset_phy_yt(struct ngbe_hw *hw);

View File

@ -94,15 +94,20 @@ struct ngbe_rom_info {
struct ngbe_mac_info {
s32 (*init_hw)(struct ngbe_hw *hw);
s32 (*reset_hw)(struct ngbe_hw *hw);
s32 (*start_hw)(struct ngbe_hw *hw);
s32 (*stop_hw)(struct ngbe_hw *hw);
s32 (*get_mac_addr)(struct ngbe_hw *hw, u8 *mac_addr);
s32 (*acquire_swfw_sync)(struct ngbe_hw *hw, u32 mask);
void (*release_swfw_sync)(struct ngbe_hw *hw, u32 mask);
/* Link */
s32 (*setup_link)(struct ngbe_hw *hw, u32 speed,
bool autoneg_wait_to_complete);
s32 (*check_link)(struct ngbe_hw *hw, u32 *speed,
bool *link_up, bool link_up_wait_to_complete);
s32 (*get_link_capabilities)(struct ngbe_hw *hw,
u32 *speed, bool *autoneg);
/* RAR */
s32 (*set_rar)(struct ngbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
u32 enable_addr);
@ -128,11 +133,13 @@ struct ngbe_mac_info {
bool set_lben;
u32 max_link_up_time;
u32 default_speeds;
bool autoneg;
};
struct ngbe_phy_info {
s32 (*identify)(struct ngbe_hw *hw);
s32 (*init_hw)(struct ngbe_hw *hw);
s32 (*reset_hw)(struct ngbe_hw *hw);
s32 (*read_reg)(struct ngbe_hw *hw, u32 reg_addr,
u32 device_type, u16 *phy_data);
@ -180,6 +187,8 @@ struct ngbe_hw {
uint64_t isb_dma;
void IOMEM *isb_mem;
u16 nb_rx_queues;
u16 nb_tx_queues;
bool is_pf;
};

View File

@ -15,9 +15,17 @@
#include "ngbe_rxtx.h"
static int ngbe_dev_close(struct rte_eth_dev *dev);
static int ngbe_dev_link_update(struct rte_eth_dev *dev,
int wait_to_complete);
static void ngbe_dev_link_status_print(struct rte_eth_dev *dev);
static int ngbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev, uint8_t on);
static int ngbe_dev_macsec_interrupt_setup(struct rte_eth_dev *dev);
static int ngbe_dev_misc_interrupt_setup(struct rte_eth_dev *dev);
static int ngbe_dev_rxq_interrupt_setup(struct rte_eth_dev *dev);
static void ngbe_dev_interrupt_handler(void *param);
static void ngbe_dev_interrupt_delayed_handler(void *param);
static void ngbe_configure_msix(struct rte_eth_dev *dev);
/*
* The set of PCI devices this driver supports
@ -54,6 +62,25 @@ static const struct rte_eth_desc_lim tx_desc_lim = {
static const struct eth_dev_ops ngbe_eth_dev_ops;
static inline int32_t
ngbe_pf_reset_hw(struct ngbe_hw *hw)
{
uint32_t ctrl_ext;
int32_t status;
status = hw->mac.reset_hw(hw);
ctrl_ext = rd32(hw, NGBE_PORTCTL);
/* Set PF Reset Done bit so PF/VF Mail Ops can work */
ctrl_ext |= NGBE_PORTCTL_RSTDONE;
wr32(hw, NGBE_PORTCTL, ctrl_ext);
ngbe_flush(hw);
if (status == NGBE_ERR_SFP_NOT_PRESENT)
status = 0;
return status;
}
static inline void
ngbe_enable_intr(struct rte_eth_dev *dev)
{
@ -198,6 +225,13 @@ eth_ngbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
wr32(hw, NGBE_PORTCTL, ctrl_ext);
ngbe_flush(hw);
PMD_INIT_LOG(DEBUG, "MAC: %d, PHY: %d",
(int)hw->mac.type, (int)hw->phy.type);
PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x",
eth_dev->data->port_id, pci_dev->id.vendor_id,
pci_dev->id.device_id);
rte_intr_callback_register(intr_handle,
ngbe_dev_interrupt_handler, eth_dev);
@ -272,6 +306,249 @@ ngbe_dev_configure(struct rte_eth_dev *dev)
return 0;
}
static void
ngbe_dev_phy_intr_setup(struct rte_eth_dev *dev)
{
struct ngbe_hw *hw = ngbe_dev_hw(dev);
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
wr32(hw, NGBE_GPIODIR, NGBE_GPIODIR_DDR(1));
wr32(hw, NGBE_GPIOINTEN, NGBE_GPIOINTEN_INT(3));
wr32(hw, NGBE_GPIOINTTYPE, NGBE_GPIOINTTYPE_LEVEL(0));
if (hw->phy.type == ngbe_phy_yt8521s_sfi)
wr32(hw, NGBE_GPIOINTPOL, NGBE_GPIOINTPOL_ACT(0));
else
wr32(hw, NGBE_GPIOINTPOL, NGBE_GPIOINTPOL_ACT(3));
intr->mask_misc |= NGBE_ICRMISC_GPIO;
}
/*
* Configure device link speed and setup link.
* It returns 0 on success.
*/
static int
ngbe_dev_start(struct rte_eth_dev *dev)
{
struct ngbe_hw *hw = ngbe_dev_hw(dev);
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
uint32_t intr_vector = 0;
int err;
bool link_up = false, negotiate = false;
uint32_t speed = 0;
uint32_t allowed_speeds = 0;
int status;
uint32_t *link_speeds;
PMD_INIT_FUNC_TRACE();
/* disable uio/vfio intr/eventfd mapping */
rte_intr_disable(intr_handle);
/* stop adapter */
hw->adapter_stopped = 0;
ngbe_stop_hw(hw);
/* reinitialize adapter, this calls reset and start */
hw->nb_rx_queues = dev->data->nb_rx_queues;
hw->nb_tx_queues = dev->data->nb_tx_queues;
status = ngbe_pf_reset_hw(hw);
if (status != 0)
return -1;
hw->mac.start_hw(hw);
hw->mac.get_link_status = true;
ngbe_dev_phy_intr_setup(dev);
/* check and configure queue intr-vector mapping */
if ((rte_intr_cap_multiple(intr_handle) ||
!RTE_ETH_DEV_SRIOV(dev).active) &&
dev->data->dev_conf.intr_conf.rxq != 0) {
intr_vector = dev->data->nb_rx_queues;
if (rte_intr_efd_enable(intr_handle, intr_vector))
return -1;
}
if (rte_intr_dp_is_en(intr_handle) && intr_handle->intr_vec == NULL) {
intr_handle->intr_vec =
rte_zmalloc("intr_vec",
dev->data->nb_rx_queues * sizeof(int), 0);
if (intr_handle->intr_vec == NULL) {
PMD_INIT_LOG(ERR,
"Failed to allocate %d rx_queues intr_vec",
dev->data->nb_rx_queues);
return -ENOMEM;
}
}
/* confiugre MSI-X for sleep until Rx interrupt */
ngbe_configure_msix(dev);
/* initialize transmission unit */
ngbe_dev_tx_init(dev);
/* This can fail when allocating mbufs for descriptor rings */
err = ngbe_dev_rx_init(dev);
if (err != 0) {
PMD_INIT_LOG(ERR, "Unable to initialize Rx hardware");
goto error;
}
err = ngbe_dev_rxtx_start(dev);
if (err < 0) {
PMD_INIT_LOG(ERR, "Unable to start rxtx queues");
goto error;
}
err = hw->mac.check_link(hw, &speed, &link_up, 0);
if (err != 0)
goto error;
dev->data->dev_link.link_status = link_up;
link_speeds = &dev->data->dev_conf.link_speeds;
if (*link_speeds == ETH_LINK_SPEED_AUTONEG)
negotiate = true;
err = hw->mac.get_link_capabilities(hw, &speed, &negotiate);
if (err != 0)
goto error;
allowed_speeds = 0;
if (hw->mac.default_speeds & NGBE_LINK_SPEED_1GB_FULL)
allowed_speeds |= ETH_LINK_SPEED_1G;
if (hw->mac.default_speeds & NGBE_LINK_SPEED_100M_FULL)
allowed_speeds |= ETH_LINK_SPEED_100M;
if (hw->mac.default_speeds & NGBE_LINK_SPEED_10M_FULL)
allowed_speeds |= ETH_LINK_SPEED_10M;
if (*link_speeds & ~allowed_speeds) {
PMD_INIT_LOG(ERR, "Invalid link setting");
goto error;
}
speed = 0x0;
if (*link_speeds == ETH_LINK_SPEED_AUTONEG) {
speed = hw->mac.default_speeds;
} else {
if (*link_speeds & ETH_LINK_SPEED_1G)
speed |= NGBE_LINK_SPEED_1GB_FULL;
if (*link_speeds & ETH_LINK_SPEED_100M)
speed |= NGBE_LINK_SPEED_100M_FULL;
if (*link_speeds & ETH_LINK_SPEED_10M)
speed |= NGBE_LINK_SPEED_10M_FULL;
}
hw->phy.init_hw(hw);
err = hw->mac.setup_link(hw, speed, link_up);
if (err != 0)
goto error;
if (rte_intr_allow_others(intr_handle)) {
ngbe_dev_misc_interrupt_setup(dev);
/* check if lsc interrupt is enabled */
if (dev->data->dev_conf.intr_conf.lsc != 0)
ngbe_dev_lsc_interrupt_setup(dev, TRUE);
else
ngbe_dev_lsc_interrupt_setup(dev, FALSE);
ngbe_dev_macsec_interrupt_setup(dev);
ngbe_set_ivar_map(hw, -1, 1, NGBE_MISC_VEC_ID);
} else {
rte_intr_callback_unregister(intr_handle,
ngbe_dev_interrupt_handler, dev);
if (dev->data->dev_conf.intr_conf.lsc != 0)
PMD_INIT_LOG(INFO,
"LSC won't enable because of no intr multiplex");
}
/* check if rxq interrupt is enabled */
if (dev->data->dev_conf.intr_conf.rxq != 0 &&
rte_intr_dp_is_en(intr_handle))
ngbe_dev_rxq_interrupt_setup(dev);
/* enable UIO/VFIO intr/eventfd mapping */
rte_intr_enable(intr_handle);
/* resume enabled intr since HW reset */
ngbe_enable_intr(dev);
if ((hw->sub_system_id & NGBE_OEM_MASK) == NGBE_LY_M88E1512_SFP ||
(hw->sub_system_id & NGBE_OEM_MASK) == NGBE_LY_YT8521S_SFP) {
/* gpio0 is used to power on/off control*/
wr32(hw, NGBE_GPIODATA, 0);
}
/*
* Update link status right before return, because it may
* start link configuration process in a separate thread.
*/
ngbe_dev_link_update(dev, 0);
return 0;
error:
PMD_INIT_LOG(ERR, "failure in dev start: %d", err);
ngbe_dev_clear_queues(dev);
return -EIO;
}
/*
* Stop device: disable rx and tx functions to allow for reconfiguring.
*/
static int
ngbe_dev_stop(struct rte_eth_dev *dev)
{
struct rte_eth_link link;
struct ngbe_hw *hw = ngbe_dev_hw(dev);
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
if (hw->adapter_stopped)
return 0;
PMD_INIT_FUNC_TRACE();
if ((hw->sub_system_id & NGBE_OEM_MASK) == NGBE_LY_M88E1512_SFP ||
(hw->sub_system_id & NGBE_OEM_MASK) == NGBE_LY_YT8521S_SFP) {
/* gpio0 is used to power on/off control*/
wr32(hw, NGBE_GPIODATA, NGBE_GPIOBIT_0);
}
/* disable interrupts */
ngbe_disable_intr(hw);
/* reset the NIC */
ngbe_pf_reset_hw(hw);
hw->adapter_stopped = 0;
/* stop adapter */
ngbe_stop_hw(hw);
ngbe_dev_clear_queues(dev);
/* Clear recorded link status */
memset(&link, 0, sizeof(link));
rte_eth_linkstatus_set(dev, &link);
if (!rte_intr_allow_others(intr_handle))
/* resume to the default handler */
rte_intr_callback_register(intr_handle,
ngbe_dev_interrupt_handler,
(void *)dev);
/* Clean datapath event and queue/vec mapping */
rte_intr_efd_disable(intr_handle);
if (intr_handle->intr_vec != NULL) {
rte_free(intr_handle->intr_vec);
intr_handle->intr_vec = NULL;
}
hw->adapter_stopped = true;
dev->data->dev_started = 0;
return 0;
}
/*
* Reset and stop device.
*/
@ -414,6 +691,106 @@ ngbe_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
return ngbe_dev_link_update_share(dev, wait_to_complete);
}
/**
* It clears the interrupt causes and enables the interrupt.
* It will be called once only during NIC initialized.
*
* @param dev
* Pointer to struct rte_eth_dev.
* @param on
* Enable or Disable.
*
* @return
* - On success, zero.
* - On failure, a negative value.
*/
static int
ngbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev, uint8_t on)
{
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
ngbe_dev_link_status_print(dev);
if (on != 0) {
intr->mask_misc |= NGBE_ICRMISC_PHY;
intr->mask_misc |= NGBE_ICRMISC_GPIO;
} else {
intr->mask_misc &= ~NGBE_ICRMISC_PHY;
intr->mask_misc &= ~NGBE_ICRMISC_GPIO;
}
return 0;
}
/**
* It clears the interrupt causes and enables the interrupt.
* It will be called once only during NIC initialized.
*
* @param dev
* Pointer to struct rte_eth_dev.
*
* @return
* - On success, zero.
* - On failure, a negative value.
*/
static int
ngbe_dev_misc_interrupt_setup(struct rte_eth_dev *dev)
{
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
u64 mask;
mask = NGBE_ICR_MASK;
mask &= (1ULL << NGBE_MISC_VEC_ID);
intr->mask |= mask;
intr->mask_misc |= NGBE_ICRMISC_GPIO;
return 0;
}
/**
* It clears the interrupt causes and enables the interrupt.
* It will be called once only during NIC initialized.
*
* @param dev
* Pointer to struct rte_eth_dev.
*
* @return
* - On success, zero.
* - On failure, a negative value.
*/
static int
ngbe_dev_rxq_interrupt_setup(struct rte_eth_dev *dev)
{
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
u64 mask;
mask = NGBE_ICR_MASK;
mask &= ~((1ULL << NGBE_RX_VEC_START) - 1);
intr->mask |= mask;
return 0;
}
/**
* It clears the interrupt causes and enables the interrupt.
* It will be called once only during NIC initialized.
*
* @param dev
* Pointer to struct rte_eth_dev.
*
* @return
* - On success, zero.
* - On failure, a negative value.
*/
static int
ngbe_dev_macsec_interrupt_setup(struct rte_eth_dev *dev)
{
struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
intr->mask_misc |= NGBE_ICRMISC_LNKSEC;
return 0;
}
/*
* It reads ICR and sets flag for the link_update.
*
@ -610,9 +987,103 @@ ngbe_dev_interrupt_handler(void *param)
ngbe_dev_interrupt_action(dev);
}
/**
* Set the IVAR registers, mapping interrupt causes to vectors
* @param hw
* pointer to ngbe_hw struct
* @direction
* 0 for Rx, 1 for Tx, -1 for other causes
* @queue
* queue to map the corresponding interrupt to
* @msix_vector
* the vector to map to the corresponding queue
*/
void
ngbe_set_ivar_map(struct ngbe_hw *hw, int8_t direction,
uint8_t queue, uint8_t msix_vector)
{
uint32_t tmp, idx;
if (direction == -1) {
/* other causes */
msix_vector |= NGBE_IVARMISC_VLD;
idx = 0;
tmp = rd32(hw, NGBE_IVARMISC);
tmp &= ~(0xFF << idx);
tmp |= (msix_vector << idx);
wr32(hw, NGBE_IVARMISC, tmp);
} else {
/* rx or tx causes */
/* Workround for ICR lost */
idx = ((16 * (queue & 1)) + (8 * direction));
tmp = rd32(hw, NGBE_IVAR(queue >> 1));
tmp &= ~(0xFF << idx);
tmp |= (msix_vector << idx);
wr32(hw, NGBE_IVAR(queue >> 1), tmp);
}
}
/**
* Sets up the hardware to properly generate MSI-X interrupts
* @hw
* board private structure
*/
static void
ngbe_configure_msix(struct rte_eth_dev *dev)
{
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
struct ngbe_hw *hw = ngbe_dev_hw(dev);
uint32_t queue_id, base = NGBE_MISC_VEC_ID;
uint32_t vec = NGBE_MISC_VEC_ID;
uint32_t gpie;
/*
* Won't configure MSI-X register if no mapping is done
* between intr vector and event fd
* but if MSI-X has been enabled already, need to configure
* auto clean, auto mask and throttling.
*/
gpie = rd32(hw, NGBE_GPIE);
if (!rte_intr_dp_is_en(intr_handle) &&
!(gpie & NGBE_GPIE_MSIX))
return;
if (rte_intr_allow_others(intr_handle)) {
base = NGBE_RX_VEC_START;
vec = base;
}
/* setup GPIE for MSI-X mode */
gpie = rd32(hw, NGBE_GPIE);
gpie |= NGBE_GPIE_MSIX;
wr32(hw, NGBE_GPIE, gpie);
/* Populate the IVAR table and set the ITR values to the
* corresponding register.
*/
if (rte_intr_dp_is_en(intr_handle)) {
for (queue_id = 0; queue_id < dev->data->nb_rx_queues;
queue_id++) {
/* by default, 1:1 mapping */
ngbe_set_ivar_map(hw, 0, queue_id, vec);
intr_handle->intr_vec[queue_id] = vec;
if (vec < base + intr_handle->nb_efd - 1)
vec++;
}
ngbe_set_ivar_map(hw, -1, 1, NGBE_MISC_VEC_ID);
}
wr32(hw, NGBE_ITR(NGBE_MISC_VEC_ID),
NGBE_ITR_IVAL_1G(NGBE_QUEUE_ITR_INTERVAL_DEFAULT)
| NGBE_ITR_WRDSA);
}
static const struct eth_dev_ops ngbe_eth_dev_ops = {
.dev_configure = ngbe_dev_configure,
.dev_infos_get = ngbe_dev_info_get,
.dev_start = ngbe_dev_start,
.dev_stop = ngbe_dev_stop,
.link_update = ngbe_dev_link_update,
.rx_queue_setup = ngbe_dev_rx_queue_setup,
.rx_queue_release = ngbe_dev_rx_queue_release,

View File

@ -13,7 +13,10 @@
#define NGBE_FLAG_MACSEC ((uint32_t)(1 << 3))
#define NGBE_FLAG_NEED_LINK_CONFIG ((uint32_t)(1 << 4))
#define NGBE_QUEUE_ITR_INTERVAL_DEFAULT 500 /* 500us */
#define NGBE_MISC_VEC_ID RTE_INTR_VEC_ZERO_OFFSET
#define NGBE_RX_VEC_START RTE_INTR_VEC_RXTX_OFFSET
/* structure for interrupt relative data */
struct ngbe_interrupt {
@ -59,6 +62,11 @@ ngbe_dev_intr(struct rte_eth_dev *dev)
return intr;
}
/*
* Rx/Tx function prototypes
*/
void ngbe_dev_clear_queues(struct rte_eth_dev *dev);
void ngbe_dev_rx_queue_release(void *rxq);
void ngbe_dev_tx_queue_release(void *txq);
@ -72,6 +80,15 @@ int ngbe_dev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
uint16_t nb_tx_desc, unsigned int socket_id,
const struct rte_eth_txconf *tx_conf);
int ngbe_dev_rx_init(struct rte_eth_dev *dev);
void ngbe_dev_tx_init(struct rte_eth_dev *dev);
int ngbe_dev_rxtx_start(struct rte_eth_dev *dev);
void ngbe_set_ivar_map(struct ngbe_hw *hw, int8_t direction,
uint8_t queue, uint8_t msix_vector);
int
ngbe_dev_link_update_share(struct rte_eth_dev *dev,
int wait_to_complete);

View File

@ -484,3 +484,60 @@ ngbe_dev_rx_queue_setup(struct rte_eth_dev *dev,
return 0;
}
void
ngbe_dev_clear_queues(struct rte_eth_dev *dev)
{
unsigned int i;
struct ngbe_adapter *adapter = ngbe_dev_adapter(dev);
PMD_INIT_FUNC_TRACE();
for (i = 0; i < dev->data->nb_tx_queues; i++) {
struct ngbe_tx_queue *txq = dev->data->tx_queues[i];
if (txq != NULL) {
txq->ops->release_mbufs(txq);
txq->ops->reset(txq);
}
}
for (i = 0; i < dev->data->nb_rx_queues; i++) {
struct ngbe_rx_queue *rxq = dev->data->rx_queues[i];
if (rxq != NULL) {
ngbe_rx_queue_release_mbufs(rxq);
ngbe_reset_rx_queue(adapter, rxq);
}
}
}
/*
* Initializes Receive Unit.
*/
int
ngbe_dev_rx_init(struct rte_eth_dev *dev)
{
RTE_SET_USED(dev);
return -EINVAL;
}
/*
* Initializes Transmit Unit.
*/
void
ngbe_dev_tx_init(struct rte_eth_dev *dev)
{
RTE_SET_USED(dev);
}
/*
* Start Transmit and Receive Units.
*/
int
ngbe_dev_rxtx_start(struct rte_eth_dev *dev)
{
RTE_SET_USED(dev);
return -EINVAL;
}