From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 72786A04AC; Tue, 1 Sep 2020 13:53:24 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id DBC6A1C133; Tue, 1 Sep 2020 13:51:25 +0200 (CEST) Received: from smtpbgsg2.qq.com (smtpbgsg2.qq.com [54.254.200.128]) by dpdk.org (Postfix) with ESMTP id 92CD41C0CD for ; Tue, 1 Sep 2020 13:51:20 +0200 (CEST) X-QQ-mid: bizesmtp5t1598961076toaq0d3xn Received: from localhost.localdomain.com (unknown [183.129.236.74]) by esmtp6.qq.com (ESMTP) with id ; Tue, 01 Sep 2020 19:51:15 +0800 (CST) X-QQ-SSF: 01400000000000B0C000000A0000000 X-QQ-FEAT: LQSB3YBfzTB/9PihqRREmT8m3mrQqItORalQLxmw2IoauXh7hGKt2z/hAt+rI 98jN9GiIGFWo+RQC0TMXFl6RzLe97WkndDqqszJ9GA1KzVbhu27elFmv+7eB4lcYFTqnzHb 6m5qJkQ9id39O93ju6Yk8vKTxZVBb/xIhQzh0o7YLA6pO6Wi/75KluX48wdXRPJw7jrFLAb UcSbUhFsda4YlCfgjPpnSqGg+k6RqPlt3q2Z7a3XpWKnw/CAQENhlcV0tRPO/HVlqBDMMKn RgWTIy8V+xrq7PFFg1Ct2hkW0dGWf8up7hMPhg14eXzXgJGezdpUGFSP4pbZyZeNsg7wJBC cKmJDn4yuo8xIpDuzMggKnWPig1QA== X-QQ-GoodBg: 2 From: Jiawen Wu To: dev@dpdk.org Cc: Jiawen Wu Date: Tue, 1 Sep 2020 19:50:43 +0800 Message-Id: <20200901115113.1529675-12-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.18.4 In-Reply-To: <20200901115113.1529675-1-jiawenwu@trustnetic.com> References: <20200901115113.1529675-1-jiawenwu@trustnetic.com> X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybgforeign:qybgforeign6 X-QQ-Bgrelay: 1 Subject: [dpdk-dev] [PATCH v1 12/42] net/txgbe: add device start and stop X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add device start and stop operations. Signed-off-by: Jiawen Wu --- drivers/net/txgbe/base/txgbe_eeprom.h | 1 + drivers/net/txgbe/base/txgbe_hw.c | 197 ++++++++++++++++- drivers/net/txgbe/base/txgbe_hw.h | 3 + drivers/net/txgbe/base/txgbe_type.h | 8 +- drivers/net/txgbe/txgbe_ethdev.c | 302 +++++++++++++++++++++++++- drivers/net/txgbe/txgbe_ethdev.h | 6 + drivers/net/txgbe/txgbe_rxtx.c | 35 ++- 7 files changed, 541 insertions(+), 11 deletions(-) diff --git a/drivers/net/txgbe/base/txgbe_eeprom.h b/drivers/net/txgbe/base/txgbe_eeprom.h index 29973e624..47b6a2f2b 100644 --- a/drivers/net/txgbe/base/txgbe_eeprom.h +++ b/drivers/net/txgbe/base/txgbe_eeprom.h @@ -24,6 +24,7 @@ #define TXGBE_ISCSI_BOOT_CONFIG 0x07 #define TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 +#define TXGBE_DEVICE_CAPS_NO_CROSSTALK_WR (1 << 7) s32 txgbe_init_eeprom_params(struct txgbe_hw *hw); s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw); diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index 21745905d..215900895 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -20,7 +20,32 @@ **/ s32 txgbe_start_hw(struct txgbe_hw *hw) { - RTE_SET_USED(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; } @@ -34,7 +59,17 @@ s32 txgbe_start_hw(struct txgbe_hw *hw) **/ s32 txgbe_start_hw_gen2(struct txgbe_hw *hw) { - RTE_SET_USED(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; } @@ -71,6 +106,56 @@ s32 txgbe_init_hw(struct txgbe_hw *hw) return status; } +/** + * 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; + + /* 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. @@ -143,6 +228,24 @@ s32 txgbe_set_rar(struct txgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, 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 @@ -248,21 +351,26 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw) switch (hw->device_id) { case TXGBE_DEV_ID_RAPTOR_KR_KX_KX4: + hw->phy.media_type = txgbe_media_type_backplane; hw->mac.type = txgbe_mac_raptor; break; case TXGBE_DEV_ID_RAPTOR_XAUI: case TXGBE_DEV_ID_RAPTOR_SGMII: + hw->phy.media_type = txgbe_media_type_copper; hw->mac.type = txgbe_mac_raptor; break; case TXGBE_DEV_ID_RAPTOR_SFP: case TXGBE_DEV_ID_WX1820_SFP: + hw->phy.media_type = txgbe_media_type_fiber; hw->mac.type = txgbe_mac_raptor; break; case TXGBE_DEV_ID_RAPTOR_QSFP: + hw->phy.media_type = txgbe_media_type_fiber_qsfp; hw->mac.type = txgbe_mac_raptor; break; case TXGBE_DEV_ID_RAPTOR_VF: case TXGBE_DEV_ID_RAPTOR_VF_HV: + hw->phy.media_type = txgbe_media_type_virtual; hw->mac.type = txgbe_mac_raptor_vf; break; default: @@ -271,8 +379,8 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw) break; } - DEBUGOUT("txgbe_set_mac_type found mac: %d, returns: %d\n", - hw->mac.type, err); + DEBUGOUT("txgbe_set_mac_type found mac: %d media: %d, returns: %d\n", + hw->mac.type, hw->phy.media_type, err); return err; } @@ -325,6 +433,38 @@ s32 txgbe_init_phy_raptor(struct txgbe_hw *hw) 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 @@ -339,6 +479,7 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) struct txgbe_rom_info *rom = &hw->rom; /* 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; @@ -356,6 +497,8 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) mac->start_hw = txgbe_start_hw_raptor; mac->reset_hw = txgbe_reset_hw; + mac->get_device_caps = txgbe_get_device_caps; + /* EEPROM */ rom->init_params = txgbe_init_eeprom_params; rom->read16 = txgbe_ee_read16; @@ -373,6 +516,52 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) return 0; } + +/** + * 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; +} static int txgbe_check_flash_load(struct txgbe_hw *hw, u32 check_bit) { diff --git a/drivers/net/txgbe/base/txgbe_hw.h b/drivers/net/txgbe/base/txgbe_hw.h index a70b0340a..884d24124 100644 --- a/drivers/net/txgbe/base/txgbe_hw.h +++ b/drivers/net/txgbe/base/txgbe_hw.h @@ -17,10 +17,13 @@ s32 txgbe_set_rar(struct txgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr); s32 txgbe_validate_mac_addr(u8 *mac_addr); +s32 txgbe_get_device_caps(struct txgbe_hw *hw, u16 *device_caps); void txgbe_clear_tx_pending(struct txgbe_hw *hw); s32 txgbe_init_shared_code(struct txgbe_hw *hw); s32 txgbe_set_mac_type(struct txgbe_hw *hw); s32 txgbe_init_ops_pf(struct txgbe_hw *hw); +u32 txgbe_get_media_type_raptor(struct txgbe_hw *hw); +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); diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h index f4c861497..7eff5c05b 100644 --- a/drivers/net/txgbe/base/txgbe_type.h +++ b/drivers/net/txgbe/base/txgbe_type.h @@ -323,8 +323,11 @@ struct txgbe_mac_info { u16 wwpn_prefix; u32 num_rar_entries; + u32 max_tx_queues; + u32 max_rx_queues; u8 san_mac_rar_index; + bool get_link_status; u64 orig_autoc; /* cached value of AUTOC */ bool orig_link_settings_stored; bool autotry_restart; @@ -401,11 +404,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_reset_type { TXGBE_LAN_RESET = 0, TXGBE_SW_RESET, diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c index 921a75f25..f29bd2112 100644 --- a/drivers/net/txgbe/txgbe_ethdev.c +++ b/drivers/net/txgbe/txgbe_ethdev.c @@ -36,6 +36,8 @@ #include "txgbe_rxtx.h" static void txgbe_dev_close(struct rte_eth_dev *dev); +static int txgbe_dev_link_update(struct rte_eth_dev *dev, + int wait_to_complete); static int txgbe_dev_stats_reset(struct rte_eth_dev *dev); /* @@ -52,8 +54,17 @@ static const struct eth_dev_ops txgbe_eth_dev_ops; static inline int txgbe_is_sfp(struct txgbe_hw *hw) { - RTE_SET_USED(hw); - return 0; + switch (hw->phy.type) { + case txgbe_phy_sfp_avago: + case txgbe_phy_sfp_ftl: + case txgbe_phy_sfp_intel: + case txgbe_phy_sfp_unknown: + case txgbe_phy_sfp_tyco_passive: + case txgbe_phy_sfp_unknown_passive: + return 1; + default: + return 0; + } } static inline int32_t @@ -153,6 +164,38 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) err = hw->mac.init_hw(hw); + /* + * Devices with copper phys will fail to initialise if txgbe_init_hw() + * is called too soon after the kernel driver unbinding/binding occurs. + * The failure occurs in txgbe_identify_phy() for all devices, + * but for non-copper devies, txgbe_identify_sfp_module() is + * also called. See txgbe_identify_phy(). The reason for the + * failure is not known, and only occuts when virtualisation features + * are disabled in the bios. A delay of 200ms was found to be enough by + * trial-and-error, and is doubled to be safe. + */ + if (err && (hw->phy.media_type == txgbe_media_type_copper)) { + rte_delay_ms(200); + err = hw->mac.init_hw(hw); + } + + if (err == TXGBE_ERR_SFP_NOT_PRESENT) + err = 0; + + if (err == TXGBE_ERR_EEPROM_VERSION) { + PMD_INIT_LOG(ERR, "This device is a pre-production adapter/" + "LOM. Please be aware there may be issues associated " + "with your hardware."); + PMD_INIT_LOG(ERR, "If you are experiencing problems " + "please contact your hardware representative " + "who provided you with this hardware."); + } else if (err == TXGBE_ERR_SFP_NOT_SUPPORTED) + PMD_INIT_LOG(ERR, "Unsupported SFP+ Module"); + if (err) { + PMD_INIT_LOG(ERR, "Hardware Initialization Failure: %d", err); + return -EIO; + } + /* Reset the hw statistics */ txgbe_dev_stats_reset(eth_dev); @@ -318,17 +361,227 @@ static struct rte_pci_driver rte_txgbe_pmd = { .remove = eth_txgbe_pci_remove, }; + +/* + * Configure device link speed and setup link. + * It returns 0 on success. + */ static int txgbe_dev_start(struct rte_eth_dev *dev) { - RTE_SET_USED(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; + + /* 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; + } + } + + /* 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: + + /* 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); + return 0; + +error: + PMD_INIT_LOG(ERR, "failure in txgbe_dev_start(): %d", err); + return -EIO; } +/* + * Stop device: disable rx and tx functions to allow for reconfiguring. + */ static void txgbe_dev_stop(struct rte_eth_dev *dev) { - RTE_SET_USED(dev); + struct rte_eth_link link; + 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; + + if (hw->adapter_stopped) + return; + + PMD_INIT_FUNC_TRACE(); + + rte_eal_alarm_cancel(txgbe_dev_setup_link_alarm_handler, dev); + + /* disable interrupts */ + txgbe_disable_intr(hw); + + /* reset the NIC */ + txgbe_pf_reset_hw(hw); + hw->adapter_stopped = 0; + + /* stop adapter */ + txgbe_stop_hw(hw); + + if (hw->phy.media_type == txgbe_media_type_copper) { + /* Turn off the copper */ + hw->phy.set_phy_power(hw, false); + } else { + /* Turn off the laser */ + hw->mac.disable_tx_laser(hw); + } + + /* Clear stored conf */ + dev->data->scattered_rx = 0; + dev->data->lro = 0; + + /* Clear recorded link status */ + memset(&link, 0, sizeof(link)); + rte_eth_linkstatus_set(dev, &link); + + /* 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; } /* @@ -367,6 +620,31 @@ txgbe_dev_close(struct rte_eth_dev *dev) dev->data->hash_mac_addrs = NULL; } +/* + * Reset PF device. + */ +static int +txgbe_dev_reset(struct rte_eth_dev *dev) +{ + int ret; + + /* When a DPDK PMD PF begin to reset PF port, it should notify all + * its VF to make them align with it. The detailed notification + * mechanism is PMD specific. As to txgbe PF, it is rather complex. + * To avoid unexpected behavior in VF, currently reset of PF with + * SR-IOV activation is not supported. It might be supported later. + */ + if (dev->data->sriov.active) + return -ENOTSUP; + + ret = eth_txgbe_dev_uninit(dev); + if (ret) + return ret; + + ret = eth_txgbe_dev_init(dev, NULL); + + return ret; +} static int txgbe_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) { @@ -390,10 +668,26 @@ txgbe_dev_stats_reset(struct rte_eth_dev *dev) return 0; } +void +txgbe_dev_setup_link_alarm_handler(void *param) +{ + RTE_SET_USED(param); +} + +static int +txgbe_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete) +{ + RTE_SET_USED(dev); + RTE_SET_USED(wait_to_complete); + return 0; +} + static const struct eth_dev_ops txgbe_eth_dev_ops = { .dev_start = txgbe_dev_start, .dev_stop = txgbe_dev_stop, .dev_close = txgbe_dev_close, + .dev_reset = txgbe_dev_reset, + .link_update = txgbe_dev_link_update, .stats_get = txgbe_dev_stats_get, .stats_reset = txgbe_dev_stats_reset, }; diff --git a/drivers/net/txgbe/txgbe_ethdev.h b/drivers/net/txgbe/txgbe_ethdev.h index e6d533141..eb9f29b97 100644 --- a/drivers/net/txgbe/txgbe_ethdev.h +++ b/drivers/net/txgbe/txgbe_ethdev.h @@ -53,6 +53,11 @@ int txgbe_vf_representor_uninit(struct rte_eth_dev *ethdev); */ void txgbe_dev_free_queues(struct rte_eth_dev *dev); +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); /* * misc function prototypes */ @@ -61,4 +66,5 @@ void txgbe_pf_host_init(struct rte_eth_dev *eth_dev); void txgbe_pf_host_uninit(struct rte_eth_dev *eth_dev); #define TXGBE_VMDQ_NUM_UC_MAC 4096 /* Maximum nb. of UC MAC addr. */ +void txgbe_dev_setup_link_alarm_handler(void *param); #endif /* _TXGBE_ETHDEV_H_ */ diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c index 8236807d1..cb067d4f4 100644 --- a/drivers/net/txgbe/txgbe_rxtx.c +++ b/drivers/net/txgbe/txgbe_rxtx.c @@ -31,15 +31,46 @@ txgbe_set_tx_function(struct rte_eth_dev *dev, struct txgbe_tx_queue *txq) RTE_SET_USED(txq); } + +void +txgbe_dev_free_queues(struct rte_eth_dev *dev) +{ + RTE_SET_USED(dev); +} + void __rte_cold txgbe_set_rx_function(struct rte_eth_dev *dev) { RTE_SET_USED(dev); } -void -txgbe_dev_free_queues(struct rte_eth_dev *dev) +/* + * Initializes Receive Unit. + */ +int __rte_cold +txgbe_dev_rx_init(struct rte_eth_dev *dev) +{ + RTE_SET_USED(dev); + + return 0; +} + +/* + * Initializes Transmit Unit. + */ +void __rte_cold +txgbe_dev_tx_init(struct rte_eth_dev *dev) +{ + RTE_SET_USED(dev); +} + +/* + * Start Transmit and Receive Units. + */ +int __rte_cold +txgbe_dev_rxtx_start(struct rte_eth_dev *dev) { RTE_SET_USED(dev); + return 0; } -- 2.18.4