From: Jiawen Wu Date: Mon, 19 Oct 2020 08:53:45 +0000 (+0800) Subject: net/txgbe: support device start X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=b1f596677d8e69cdc67348c34d073e5240911797;p=dpdk.git net/txgbe: support device start Add device start operation with hardware start and reset. Signed-off-by: Jiawen Wu Reviewed-by: Ferruh Yigit --- diff --git a/drivers/net/txgbe/base/txgbe_eeprom.h b/drivers/net/txgbe/base/txgbe_eeprom.h index e50dfe4f69..2ad6c7e19a 100644 --- a/drivers/net/txgbe/base/txgbe_eeprom.h +++ b/drivers/net/txgbe/base/txgbe_eeprom.h @@ -26,6 +26,7 @@ #define TXGBE_SAN_MAC_ADDR_PORT0_OFFSET 0x0 #define TXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 +#define TXGBE_DEVICE_CAPS_NO_CROSSTALK_WR (1 << 7) #define TXGBE_FW_LESM_PARAMETERS_PTR 0x2 #define TXGBE_FW_LESM_STATE_1 0x1 #define TXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */ diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index a4bb44c925..1b40bfa2f8 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -21,6 +21,71 @@ static s32 txgbe_mta_vector(struct txgbe_hw *hw, u8 *mc_addr); static s32 txgbe_get_san_mac_addr_offset(struct txgbe_hw *hw, u16 *san_mac_offset); +/** + * txgbe_start_hw - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware by filling the bus info structure and media type, clears + * all on chip counters, initializes receive address registers, multicast + * table, VLAN filter table, calls routine to set up link and flow control + * settings, and leaves transmit and receive units disabled and uninitialized + **/ +s32 txgbe_start_hw(struct txgbe_hw *hw) +{ + u16 device_caps; + + DEBUGFUNC("txgbe_start_hw"); + + /* Set the media type */ + hw->phy.media_type = hw->phy.get_media_type(hw); + + /* Clear statistics registers */ + hw->mac.clear_hw_cntrs(hw); + + /* Cache bit indicating need for crosstalk fix */ + switch (hw->mac.type) { + case txgbe_mac_raptor: + hw->mac.get_device_caps(hw, &device_caps); + if (device_caps & TXGBE_DEVICE_CAPS_NO_CROSSTALK_WR) + hw->need_crosstalk_fix = false; + else + hw->need_crosstalk_fix = true; + break; + default: + hw->need_crosstalk_fix = false; + break; + } + + /* Clear adapter stopped flag */ + hw->adapter_stopped = false; + + return 0; +} + +/** + * txgbe_start_hw_gen2 - Init sequence for common device family + * @hw: pointer to hw structure + * + * Performs the init sequence common to the second generation + * of 10 GbE devices. + **/ +s32 txgbe_start_hw_gen2(struct txgbe_hw *hw) +{ + u32 i; + + /* Clear the rate limiters */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + wr32(hw, TXGBE_ARBPOOLIDX, i); + wr32(hw, TXGBE_ARBTXRATE, 0); + } + txgbe_flush(hw); + + /* We need to run link autotry after the driver loads */ + hw->mac.autotry_restart = true; + + return 0; +} + /** * txgbe_init_hw - Generic hardware initialization * @hw: pointer to hardware structure @@ -105,6 +170,59 @@ void txgbe_set_lan_id_multi_port(struct txgbe_hw *hw) bus->func = bus->lan_id; } +/** + * txgbe_stop_hw - Generic stop Tx/Rx units + * @hw: pointer to hardware structure + * + * Sets the adapter_stopped flag within txgbe_hw struct. Clears interrupts, + * disables transmit and receive units. The adapter_stopped flag is used by + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +s32 txgbe_stop_hw(struct txgbe_hw *hw) +{ + u32 reg_val; + u16 i; + + DEBUGFUNC("txgbe_stop_hw"); + + /* + * Set the adapter_stopped flag so other driver functions stop touching + * the hardware + */ + hw->adapter_stopped = true; + + /* Disable the receive unit */ + txgbe_disable_rx(hw); + + /* Clear interrupt mask to stop interrupts from being generated */ + wr32(hw, TXGBE_IENMISC, 0); + wr32(hw, TXGBE_IMS(0), TXGBE_IMS_MASK); + wr32(hw, TXGBE_IMS(1), TXGBE_IMS_MASK); + + /* Clear any pending interrupts, flush previous writes */ + wr32(hw, TXGBE_ICRMISC, TXGBE_ICRMISC_MASK); + wr32(hw, TXGBE_ICR(0), TXGBE_ICR_MASK); + wr32(hw, TXGBE_ICR(1), TXGBE_ICR_MASK); + + /* Disable the transmit unit. Each queue must be disabled. */ + for (i = 0; i < hw->mac.max_tx_queues; i++) + wr32(hw, TXGBE_TXCFG(i), TXGBE_TXCFG_FLUSH); + + /* Disable the receive unit by stopping each queue */ + for (i = 0; i < hw->mac.max_rx_queues; i++) { + reg_val = rd32(hw, TXGBE_RXCFG(i)); + reg_val &= ~TXGBE_RXCFG_ENA; + wr32(hw, TXGBE_RXCFG(i), reg_val); + } + + /* flush all queues disables */ + txgbe_flush(hw); + msec_delay(2); + + return 0; +} + /** * txgbe_validate_mac_addr - Validate MAC address * @mac_addr: pointer to MAC address. @@ -676,6 +794,23 @@ s32 txgbe_check_mac_link(struct txgbe_hw *hw, u32 *speed, return 0; } +/** + * txgbe_get_device_caps - Get additional device capabilities + * @hw: pointer to hardware structure + * @device_caps: the EEPROM word with the extra device capabilities + * + * This function will read the EEPROM location for the device capabilities, + * and return the word through device_caps. + **/ +s32 txgbe_get_device_caps(struct txgbe_hw *hw, u16 *device_caps) +{ + DEBUGFUNC("txgbe_get_device_caps"); + + hw->rom.readw_sw(hw, TXGBE_DEVICE_CAPS, device_caps); + + return 0; +} + /** * txgbe_clear_tx_pending - Clear pending TX work from the PCIe fifo * @hw: pointer to the hardware structure @@ -718,6 +853,38 @@ void txgbe_clear_tx_pending(struct txgbe_hw *hw) wr32(hw, TXGBE_PSRCTL, hlreg0); } +void txgbe_disable_rx(struct txgbe_hw *hw) +{ + u32 pfdtxgswc; + + pfdtxgswc = rd32(hw, TXGBE_PSRCTL); + if (pfdtxgswc & TXGBE_PSRCTL_LBENA) { + pfdtxgswc &= ~TXGBE_PSRCTL_LBENA; + wr32(hw, TXGBE_PSRCTL, pfdtxgswc); + hw->mac.set_lben = true; + } else { + hw->mac.set_lben = false; + } + + wr32m(hw, TXGBE_PBRXCTL, TXGBE_PBRXCTL_ENA, 0); + wr32m(hw, TXGBE_MACRXCFG, TXGBE_MACRXCFG_ENA, 0); +} + +void txgbe_enable_rx(struct txgbe_hw *hw) +{ + u32 pfdtxgswc; + + wr32m(hw, TXGBE_MACRXCFG, TXGBE_MACRXCFG_ENA, TXGBE_MACRXCFG_ENA); + wr32m(hw, TXGBE_PBRXCTL, TXGBE_PBRXCTL_ENA, TXGBE_PBRXCTL_ENA); + + if (hw->mac.set_lben) { + pfdtxgswc = rd32(hw, TXGBE_PSRCTL); + pfdtxgswc |= TXGBE_PSRCTL_LBENA; + wr32(hw, TXGBE_PSRCTL, pfdtxgswc); + hw->mac.set_lben = false; + } +} + /** * txgbe_setup_mac_link_multispeed_fiber - Set MAC link speed * @hw: pointer to hardware structure @@ -1046,6 +1213,38 @@ init_phy_ops_out: return err; } +s32 txgbe_setup_sfp_modules(struct txgbe_hw *hw) +{ + s32 err = 0; + + DEBUGFUNC("txgbe_setup_sfp_modules"); + + if (hw->phy.sfp_type == txgbe_sfp_type_unknown) + return 0; + + txgbe_init_mac_link_ops(hw); + + /* PHY config will finish before releasing the semaphore */ + err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY); + if (err != 0) + return TXGBE_ERR_SWFW_SYNC; + + /* Release the semaphore */ + hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY); + + /* Delay obtaining semaphore again to allow FW access + * prot_autoc_write uses the semaphore too. + */ + msec_delay(hw->rom.semaphore_delay); + + if (err) { + DEBUGOUT("sfp module setup not complete\n"); + return TXGBE_ERR_SFP_SETUP_NOT_COMPLETE; + } + + return err; +} + /** * txgbe_init_ops_pf - Inits func ptrs and MAC type * @hw: pointer to hardware structure @@ -1066,6 +1265,7 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) bus->set_lan_id = txgbe_set_lan_id_multi_port; /* PHY */ + phy->get_media_type = txgbe_get_media_type_raptor; phy->identify = txgbe_identify_phy; phy->init = txgbe_init_phy_raptor; phy->read_reg = txgbe_read_phy_reg; @@ -1082,17 +1282,23 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) /* MAC */ mac->init_hw = txgbe_init_hw; + mac->start_hw = txgbe_start_hw_raptor; mac->get_mac_addr = txgbe_get_mac_addr; + mac->stop_hw = txgbe_stop_hw; mac->reset_hw = txgbe_reset_hw; mac->get_san_mac_addr = txgbe_get_san_mac_addr; mac->set_san_mac_addr = txgbe_set_san_mac_addr; + mac->get_device_caps = txgbe_get_device_caps; mac->autoc_read = txgbe_autoc_read; mac->autoc_write = txgbe_autoc_write; mac->set_rar = txgbe_set_rar; mac->clear_rar = txgbe_clear_rar; mac->init_rx_addrs = txgbe_init_rx_addrs; + mac->enable_rx = txgbe_enable_rx; + mac->disable_rx = txgbe_disable_rx; mac->init_uta_tables = txgbe_init_uta_tables; + mac->setup_sfp = txgbe_setup_sfp_modules; /* Link */ mac->get_link_capabilities = txgbe_get_link_capabilities_raptor; mac->check_link = txgbe_check_mac_link; @@ -1229,6 +1435,52 @@ s32 txgbe_get_link_capabilities_raptor(struct txgbe_hw *hw, return status; } +/** + * txgbe_get_media_type_raptor - Get media type + * @hw: pointer to hardware structure + * + * Returns the media type (fiber, copper, backplane) + **/ +u32 txgbe_get_media_type_raptor(struct txgbe_hw *hw) +{ + u32 media_type; + + DEBUGFUNC("txgbe_get_media_type_raptor"); + + /* Detect if there is a copper PHY attached. */ + switch (hw->phy.type) { + case txgbe_phy_cu_unknown: + case txgbe_phy_tn: + media_type = txgbe_media_type_copper; + return media_type; + default: + break; + } + + switch (hw->device_id) { + case TXGBE_DEV_ID_RAPTOR_KR_KX_KX4: + /* Default device ID is mezzanine card KX/KX4 */ + media_type = txgbe_media_type_backplane; + break; + case TXGBE_DEV_ID_RAPTOR_SFP: + case TXGBE_DEV_ID_WX1820_SFP: + media_type = txgbe_media_type_fiber; + break; + case TXGBE_DEV_ID_RAPTOR_QSFP: + media_type = txgbe_media_type_fiber_qsfp; + break; + case TXGBE_DEV_ID_RAPTOR_XAUI: + case TXGBE_DEV_ID_RAPTOR_SGMII: + media_type = txgbe_media_type_copper; + break; + default: + media_type = txgbe_media_type_unknown; + break; + } + + return media_type; +} + /** * txgbe_start_mac_link_raptor - Setup MAC link settings * @hw: pointer to hardware structure @@ -1648,6 +1900,68 @@ txgbe_check_flash_load(struct txgbe_hw *hw, u32 check_bit) return err; } +static void +txgbe_reset_misc(struct txgbe_hw *hw) +{ + int i; + u32 value; + + wr32(hw, TXGBE_ISBADDRL, hw->isb_dma & 0x00000000FFFFFFFF); + wr32(hw, TXGBE_ISBADDRH, hw->isb_dma >> 32); + + value = rd32_epcs(hw, SR_XS_PCS_CTRL2); + if ((value & 0x3) != SR_PCS_CTRL2_TYPE_SEL_X) + hw->link_status = TXGBE_LINK_STATUS_NONE; + + /* receive packets that size > 2048 */ + wr32m(hw, TXGBE_MACRXCFG, + TXGBE_MACRXCFG_JUMBO, TXGBE_MACRXCFG_JUMBO); + + wr32m(hw, TXGBE_FRMSZ, TXGBE_FRMSZ_MAX_MASK, + TXGBE_FRMSZ_MAX(TXGBE_FRAME_SIZE_DFT)); + + /* clear counters on read */ + wr32m(hw, TXGBE_MACCNTCTL, + TXGBE_MACCNTCTL_RC, TXGBE_MACCNTCTL_RC); + + wr32m(hw, TXGBE_RXFCCFG, + TXGBE_RXFCCFG_FC, TXGBE_RXFCCFG_FC); + wr32m(hw, TXGBE_TXFCCFG, + TXGBE_TXFCCFG_FC, TXGBE_TXFCCFG_FC); + + wr32m(hw, TXGBE_MACRXFLT, + TXGBE_MACRXFLT_PROMISC, TXGBE_MACRXFLT_PROMISC); + + wr32m(hw, TXGBE_RSTSTAT, + TXGBE_RSTSTAT_TMRINIT_MASK, TXGBE_RSTSTAT_TMRINIT(30)); + + /* errata 4: initialize mng flex tbl and wakeup flex tbl*/ + wr32(hw, TXGBE_MNGFLEXSEL, 0); + for (i = 0; i < 16; i++) { + wr32(hw, TXGBE_MNGFLEXDWL(i), 0); + wr32(hw, TXGBE_MNGFLEXDWH(i), 0); + wr32(hw, TXGBE_MNGFLEXMSK(i), 0); + } + wr32(hw, TXGBE_LANFLEXSEL, 0); + for (i = 0; i < 16; i++) { + wr32(hw, TXGBE_LANFLEXDWL(i), 0); + wr32(hw, TXGBE_LANFLEXDWH(i), 0); + wr32(hw, TXGBE_LANFLEXMSK(i), 0); + } + + /* set pause frame dst mac addr */ + wr32(hw, TXGBE_RXPBPFCDMACL, 0xC2000001); + wr32(hw, TXGBE_RXPBPFCDMACH, 0x0180); + + hw->mac.init_thermal_sensor_thresh(hw); + + /* enable mac transmitter */ + wr32m(hw, TXGBE_MACTXCFG, TXGBE_MACTXCFG_TXE, TXGBE_MACTXCFG_TXE); + + for (i = 0; i < 4; i++) + wr32m(hw, TXGBE_IVAR(i), 0x80808080, 0); +} + /** * txgbe_reset_hw - Perform hardware reset * @hw: pointer to hardware structure @@ -1706,6 +2020,8 @@ mac_reset_top: } usec_delay(10); + txgbe_reset_misc(hw); + if (hw->bus.lan_id == 0) { status = txgbe_check_flash_load(hw, TXGBE_ILDRSTAT_SWRST_LAN0); @@ -1778,6 +2094,36 @@ mac_reset_top: return status; } +/** + * txgbe_start_hw_raptor - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. + **/ +s32 txgbe_start_hw_raptor(struct txgbe_hw *hw) +{ + s32 err = 0; + + DEBUGFUNC("txgbe_start_hw_raptor"); + + err = txgbe_start_hw(hw); + if (err != 0) + goto out; + + err = txgbe_start_hw_gen2(hw); + if (err != 0) + goto out; + + /* We need to run link autotry after the driver loads */ + hw->mac.autotry_restart = true; + +out: + return err; +} + + /** * txgbe_verify_lesm_fw_enabled_raptor - Checks LESM FW module state. * @hw: pointer to hardware structure diff --git a/drivers/net/txgbe/base/txgbe_hw.h b/drivers/net/txgbe/base/txgbe_hw.h index 510de5cbe3..f0d3d5b972 100644 --- a/drivers/net/txgbe/base/txgbe_hw.h +++ b/drivers/net/txgbe/base/txgbe_hw.h @@ -8,6 +8,9 @@ #include "txgbe_type.h" s32 txgbe_init_hw(struct txgbe_hw *hw); +s32 txgbe_start_hw(struct txgbe_hw *hw); +s32 txgbe_stop_hw(struct txgbe_hw *hw); +s32 txgbe_start_hw_gen2(struct txgbe_hw *hw); s32 txgbe_get_mac_addr(struct txgbe_hw *hw, u8 *mac_addr); void txgbe_set_lan_id_multi_port(struct txgbe_hw *hw); @@ -30,10 +33,13 @@ s32 txgbe_check_mac_link(struct txgbe_hw *hw, u32 *speed, bool *link_up, bool link_up_wait_to_complete); +s32 txgbe_get_device_caps(struct txgbe_hw *hw, u16 *device_caps); void txgbe_clear_tx_pending(struct txgbe_hw *hw); s32 txgbe_reset_pipeline_raptor(struct txgbe_hw *hw); +void txgbe_disable_rx(struct txgbe_hw *hw); +void txgbe_enable_rx(struct txgbe_hw *hw); s32 txgbe_setup_mac_link_multispeed_fiber(struct txgbe_hw *hw, u32 speed, bool autoneg_wait_to_complete); @@ -43,6 +49,7 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw); s32 txgbe_init_ops_pf(struct txgbe_hw *hw); s32 txgbe_get_link_capabilities_raptor(struct txgbe_hw *hw, u32 *speed, bool *autoneg); +u32 txgbe_get_media_type_raptor(struct txgbe_hw *hw); void txgbe_disable_tx_laser_multispeed_fiber(struct txgbe_hw *hw); void txgbe_enable_tx_laser_multispeed_fiber(struct txgbe_hw *hw); void txgbe_flap_tx_laser_multispeed_fiber(struct txgbe_hw *hw); @@ -55,8 +62,10 @@ s32 txgbe_start_mac_link_raptor(struct txgbe_hw *hw, bool autoneg_wait_to_complete); s32 txgbe_setup_mac_link(struct txgbe_hw *hw, u32 speed, bool autoneg_wait_to_complete); +s32 txgbe_setup_sfp_modules(struct txgbe_hw *hw); void txgbe_init_mac_link_ops(struct txgbe_hw *hw); s32 txgbe_reset_hw(struct txgbe_hw *hw); +s32 txgbe_start_hw_raptor(struct txgbe_hw *hw); s32 txgbe_init_phy_raptor(struct txgbe_hw *hw); bool txgbe_verify_lesm_fw_enabled_raptor(struct txgbe_hw *hw); #endif /* _TXGBE_HW_H_ */ diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h index 622c5c6a3a..c777d9f757 100644 --- a/drivers/net/txgbe/base/txgbe_type.h +++ b/drivers/net/txgbe/base/txgbe_type.h @@ -360,6 +360,7 @@ struct txgbe_mac_info { bool orig_link_settings_stored; bool autotry_restart; u8 flags; + bool set_lben; u32 max_link_up_time; }; @@ -455,12 +456,14 @@ struct txgbe_hw { u16 vendor_id; u16 subsystem_device_id; u16 subsystem_vendor_id; - + bool adapter_stopped; bool allow_unsupported_sfp; bool need_crosstalk_fix; uint64_t isb_dma; void IOMEM *isb_mem; + u16 nb_rx_queues; + u16 nb_tx_queues; enum txgbe_link_status { TXGBE_LINK_STATUS_NONE = 0, TXGBE_LINK_STATUS_KX, diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c index 28bbd8237e..ddefd313d7 100644 --- a/drivers/net/txgbe/txgbe_ethdev.c +++ b/drivers/net/txgbe/txgbe_ethdev.c @@ -80,6 +80,25 @@ txgbe_is_sfp(struct txgbe_hw *hw) } } +static inline int32_t +txgbe_pf_reset_hw(struct txgbe_hw *hw) +{ + uint32_t ctrl_ext; + int32_t status; + + status = hw->mac.reset_hw(hw); + + ctrl_ext = rd32(hw, TXGBE_PORTCTL); + /* Set PF Reset Done bit so PF/VF Mail Ops can work */ + ctrl_ext |= TXGBE_PORTCTL_RSTDONE; + wr32(hw, TXGBE_PORTCTL, ctrl_ext); + txgbe_flush(hw); + + if (status == TXGBE_ERR_SFP_NOT_PRESENT) + status = 0; + return status; +} + static inline void txgbe_enable_intr(struct rte_eth_dev *dev) { @@ -541,6 +560,203 @@ txgbe_dev_phy_intr_setup(struct rte_eth_dev *dev) intr->mask_misc |= TXGBE_ICRMISC_GPIO; } +/* + * Configure device link speed and setup link. + * It returns 0 on success. + */ +static int +txgbe_dev_start(struct rte_eth_dev *dev) +{ + struct txgbe_hw *hw = TXGBE_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 = 0; + uint32_t speed = 0; + uint32_t allowed_speeds = 0; + int status; + uint32_t *link_speeds; + + PMD_INIT_FUNC_TRACE(); + + /* TXGBE devices don't support: + * - half duplex (checked afterwards for valid speeds) + * - fixed speed: TODO implement + */ + if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) { + PMD_INIT_LOG(ERR, + "Invalid link_speeds for port %u, fix speed not supported", + dev->data->port_id); + return -EINVAL; + } + + /* Stop the link setup handler before resetting the HW. */ + rte_eal_alarm_cancel(txgbe_dev_setup_link_alarm_handler, dev); + + /* disable uio/vfio intr/eventfd mapping */ + rte_intr_disable(intr_handle); + + /* stop adapter */ + hw->adapter_stopped = 0; + txgbe_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 = txgbe_pf_reset_hw(hw); + if (status != 0) + return -1; + hw->mac.start_hw(hw); + hw->mac.get_link_status = true; + + txgbe_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) { + 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 msix for sleep until rx interrupt */ + txgbe_configure_msix(dev); + + /* initialize transmission unit */ + txgbe_dev_tx_init(dev); + + /* This can fail when allocating mbufs for descriptor rings */ + err = txgbe_dev_rx_init(dev); + if (err) { + PMD_INIT_LOG(ERR, "Unable to initialize RX hardware"); + goto error; + } + + err = txgbe_dev_rxtx_start(dev); + if (err < 0) { + PMD_INIT_LOG(ERR, "Unable to start rxtx queues"); + goto error; + } + + /* Skip link setup if loopback mode is enabled. */ + if (hw->mac.type == txgbe_mac_raptor && + dev->data->dev_conf.lpbk_mode) + goto skip_link_setup; + + if (txgbe_is_sfp(hw) && hw->phy.multispeed_fiber) { + err = hw->mac.setup_sfp(hw); + if (err) + goto error; + } + + if (hw->phy.media_type == txgbe_media_type_copper) { + /* Turn on the copper */ + hw->phy.set_phy_power(hw, true); + } else { + /* Turn on the laser */ + hw->mac.enable_tx_laser(hw); + } + + err = hw->mac.check_link(hw, &speed, &link_up, 0); + if (err) + goto error; + dev->data->dev_link.link_status = link_up; + + err = hw->mac.get_link_capabilities(hw, &speed, &negotiate); + if (err) + goto error; + + allowed_speeds = ETH_LINK_SPEED_100M | ETH_LINK_SPEED_1G | + ETH_LINK_SPEED_10G; + + link_speeds = &dev->data->dev_conf.link_speeds; + if (*link_speeds & ~allowed_speeds) { + PMD_INIT_LOG(ERR, "Invalid link setting"); + goto error; + } + + speed = 0x0; + if (*link_speeds == ETH_LINK_SPEED_AUTONEG) { + speed = (TXGBE_LINK_SPEED_100M_FULL | + TXGBE_LINK_SPEED_1GB_FULL | + TXGBE_LINK_SPEED_10GB_FULL); + } else { + if (*link_speeds & ETH_LINK_SPEED_10G) + speed |= TXGBE_LINK_SPEED_10GB_FULL; + if (*link_speeds & ETH_LINK_SPEED_5G) + speed |= TXGBE_LINK_SPEED_5GB_FULL; + if (*link_speeds & ETH_LINK_SPEED_2_5G) + speed |= TXGBE_LINK_SPEED_2_5GB_FULL; + if (*link_speeds & ETH_LINK_SPEED_1G) + speed |= TXGBE_LINK_SPEED_1GB_FULL; + if (*link_speeds & ETH_LINK_SPEED_100M) + speed |= TXGBE_LINK_SPEED_100M_FULL; + } + + err = hw->mac.setup_link(hw, speed, link_up); + if (err) + goto error; + +skip_link_setup: + + if (rte_intr_allow_others(intr_handle)) { + /* check if lsc interrupt is enabled */ + if (dev->data->dev_conf.intr_conf.lsc != 0) + txgbe_dev_lsc_interrupt_setup(dev, TRUE); + else + txgbe_dev_lsc_interrupt_setup(dev, FALSE); + txgbe_dev_macsec_interrupt_setup(dev); + txgbe_set_ivar_map(hw, -1, 1, TXGBE_MISC_VEC_ID); + } else { + rte_intr_callback_unregister(intr_handle, + txgbe_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)) + txgbe_dev_rxq_interrupt_setup(dev); + + /* enable uio/vfio intr/eventfd mapping */ + rte_intr_enable(intr_handle); + + /* resume enabled intr since hw reset */ + txgbe_enable_intr(dev); + + /* + * Update link status right before return, because it may + * start link configuration process in a separate thread. + */ + txgbe_dev_link_update(dev, 0); + + wr32m(hw, TXGBE_LEDCTL, 0xFFFFFFFF, TXGBE_LEDCTL_ORD_MASK); + + return 0; + +error: + PMD_INIT_LOG(ERR, "failure in dev start: %d", err); + txgbe_dev_clear_queues(dev); + return -EIO; +} + /* * Set device link up: enable tx. */ @@ -1360,6 +1576,7 @@ txgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev, static const struct eth_dev_ops txgbe_eth_dev_ops = { .dev_configure = txgbe_dev_configure, .dev_infos_get = txgbe_dev_info_get, + .dev_start = txgbe_dev_start, .dev_set_link_up = txgbe_dev_set_link_up, .dev_set_link_down = txgbe_dev_set_link_down, .dev_supported_ptypes_get = txgbe_dev_supported_ptypes_get, diff --git a/drivers/net/txgbe/txgbe_ethdev.h b/drivers/net/txgbe/txgbe_ethdev.h index c01f31295b..f47c64ca60 100644 --- a/drivers/net/txgbe/txgbe_ethdev.h +++ b/drivers/net/txgbe/txgbe_ethdev.h @@ -81,6 +81,8 @@ struct txgbe_adapter { /* * RX/TX function prototypes */ +void txgbe_dev_clear_queues(struct rte_eth_dev *dev); + void txgbe_dev_free_queues(struct rte_eth_dev *dev); void txgbe_dev_rx_queue_release(void *rxq); @@ -100,6 +102,8 @@ int txgbe_dev_rx_init(struct rte_eth_dev *dev); void txgbe_dev_tx_init(struct rte_eth_dev *dev); +int txgbe_dev_rxtx_start(struct rte_eth_dev *dev); + void txgbe_dev_save_rx_queue(struct txgbe_hw *hw, uint16_t rx_queue_id); void txgbe_dev_store_rx_queue(struct txgbe_hw *hw, uint16_t rx_queue_id); void txgbe_dev_save_tx_queue(struct txgbe_hw *hw, uint16_t tx_queue_id); diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c index 82d0104199..1af70e7329 100644 --- a/drivers/net/txgbe/txgbe_rxtx.c +++ b/drivers/net/txgbe/txgbe_rxtx.c @@ -2461,6 +2461,33 @@ txgbe_dev_rx_queue_setup(struct rte_eth_dev *dev, return 0; } +void __rte_cold +txgbe_dev_clear_queues(struct rte_eth_dev *dev) +{ + unsigned int i; + struct txgbe_adapter *adapter = TXGBE_DEV_ADAPTER(dev); + + PMD_INIT_FUNC_TRACE(); + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + struct txgbe_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 txgbe_rx_queue *rxq = dev->data->rx_queues[i]; + + if (rxq != NULL) { + txgbe_rx_queue_release_mbufs(rxq); + txgbe_reset_rx_queue(adapter, rxq); + } + } +} + void txgbe_dev_free_queues(struct rte_eth_dev *dev) { @@ -2908,6 +2935,81 @@ txgbe_dev_tx_init(struct rte_eth_dev *dev) } } +/* + * Set up link loopback mode Tx->Rx. + */ +static inline void __rte_cold +txgbe_setup_loopback_link_raptor(struct txgbe_hw *hw) +{ + PMD_INIT_FUNC_TRACE(); + + wr32m(hw, TXGBE_MACRXCFG, TXGBE_MACRXCFG_LB, TXGBE_MACRXCFG_LB); + + msec_delay(50); +} + +/* + * Start Transmit and Receive Units. + */ +int __rte_cold +txgbe_dev_rxtx_start(struct rte_eth_dev *dev) +{ + struct txgbe_hw *hw; + struct txgbe_tx_queue *txq; + struct txgbe_rx_queue *rxq; + uint32_t dmatxctl; + uint32_t rxctrl; + uint16_t i; + int ret = 0; + + PMD_INIT_FUNC_TRACE(); + hw = TXGBE_DEV_HW(dev); + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + txq = dev->data->tx_queues[i]; + /* Setup Transmit Threshold Registers */ + wr32m(hw, TXGBE_TXCFG(txq->reg_idx), + TXGBE_TXCFG_HTHRESH_MASK | + TXGBE_TXCFG_WTHRESH_MASK, + TXGBE_TXCFG_HTHRESH(txq->hthresh) | + TXGBE_TXCFG_WTHRESH(txq->wthresh)); + } + + dmatxctl = rd32(hw, TXGBE_DMATXCTRL); + dmatxctl |= TXGBE_DMATXCTRL_ENA; + wr32(hw, TXGBE_DMATXCTRL, dmatxctl); + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + txq = dev->data->tx_queues[i]; + if (!txq->tx_deferred_start) { + ret = txgbe_dev_tx_queue_start(dev, i); + if (ret < 0) + return ret; + } + } + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + rxq = dev->data->rx_queues[i]; + if (!rxq->rx_deferred_start) { + ret = txgbe_dev_rx_queue_start(dev, i); + if (ret < 0) + return ret; + } + } + + /* Enable Receive engine */ + rxctrl = rd32(hw, TXGBE_PBRXCTL); + rxctrl |= TXGBE_PBRXCTL_ENA; + hw->mac.enable_rx_dma(hw, rxctrl); + + /* If loopback mode is enabled, set up the link accordingly */ + if (hw->mac.type == txgbe_mac_raptor && + dev->data->dev_conf.lpbk_mode) + txgbe_setup_loopback_link_raptor(hw); + + return 0; +} + void txgbe_dev_save_rx_queue(struct txgbe_hw *hw, uint16_t rx_queue_id) {