All of lore.kernel.org
 help / color / mirror / Atom feed
From: alvinx.zhang@intel.com
To: dev@dpdk.org
Cc: xiaolong.ye@intel.com
Subject: [dpdk-dev] [PATCH v4 03/11] net/igc: implement device base ops
Date: Wed, 15 Apr 2020 16:48:02 +0800	[thread overview]
Message-ID: <20200415084810.20816-4-alvinx.zhang@intel.com> (raw)
In-Reply-To: <20200415084810.20816-1-alvinx.zhang@intel.com>

From: Alvin Zhang <alvinx.zhang@intel.com>

Bellow ops are implemented:
dev_configure
dev_start
dev_stop
dev_close
dev_reset
dev_set_link_up
dev_set_link_down
link_update
fw_version_get
dev_led_on
dev_led_off

Signed-off-by: Alvin Zhang <alvinx.zhang@intel.com>

V2: Modify codes according to comments.
V3: Modify codes according to comments.
V4: Modify codes according to comments.
---
 doc/guides/nics/features/igc.ini |   5 +
 drivers/net/igc/igc_ethdev.c     | 644 ++++++++++++++++++++++++++++++++++++++-
 drivers/net/igc/igc_ethdev.h     |  35 +++
 3 files changed, 674 insertions(+), 10 deletions(-)

diff --git a/doc/guides/nics/features/igc.ini b/doc/guides/nics/features/igc.ini
index ad75cc4..0fbdf7c 100644
--- a/doc/guides/nics/features/igc.ini
+++ b/doc/guides/nics/features/igc.ini
@@ -3,6 +3,11 @@
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Speed capabilities   = Y
+Link status          = Y
+Link status event    = Y
+FW version           = Y
+LED                  = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index f23543e..2a9ff9c 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -3,6 +3,7 @@
  */
 
 #include <stdint.h>
+#include <string.h>
 
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
@@ -15,7 +16,34 @@
 
 #define IGC_INTEL_VENDOR_ID		0x8086
 
+/*
+ * The overhead from MTU to max frame size.
+ * Considering VLAN so tag needs to be counted.
+ */
+#define IGC_ETH_OVERHEAD		(RTE_ETHER_HDR_LEN + \
+					RTE_ETHER_CRC_LEN + VLAN_TAG_SIZE)
+
 #define IGC_FC_PAUSE_TIME		0x0680
+#define IGC_LINK_UPDATE_CHECK_TIMEOUT	90  /* 9s */
+#define IGC_LINK_UPDATE_CHECK_INTERVAL	100 /* ms */
+
+#define IGC_MISC_VEC_ID			RTE_INTR_VEC_ZERO_OFFSET
+#define IGC_RX_VEC_START		RTE_INTR_VEC_RXTX_OFFSET
+#define IGC_MSIX_OTHER_INTR_VEC		0   /* MSI-X other interrupt vector */
+#define IGC_FLAG_NEED_LINK_UPDATE	(1u << 0)	/* need update link */
+
+#define IGC_DEFAULT_RX_FREE_THRESH	32
+
+#define IGC_DEFAULT_RX_PTHRESH		8
+#define IGC_DEFAULT_RX_HTHRESH		8
+#define IGC_DEFAULT_RX_WTHRESH		4
+
+#define IGC_DEFAULT_TX_PTHRESH		8
+#define IGC_DEFAULT_TX_HTHRESH		1
+#define IGC_DEFAULT_TX_WTHRESH		16
+
+/* MSI-X other interrupt vector */
+#define IGC_MSIX_OTHER_INTR_VEC		0
 
 static const struct rte_pci_id pci_id_igc_map[] = {
 	{ RTE_PCI_DEVICE(IGC_INTEL_VENDOR_ID, IGC_DEV_ID_I225_LM) },
@@ -29,12 +57,20 @@
 static int eth_igc_link_update(struct rte_eth_dev *dev, int wait_to_complete);
 static void eth_igc_stop(struct rte_eth_dev *dev);
 static int eth_igc_start(struct rte_eth_dev *dev);
+static int eth_igc_set_link_up(struct rte_eth_dev *dev);
+static int eth_igc_set_link_down(struct rte_eth_dev *dev);
 static void eth_igc_close(struct rte_eth_dev *dev);
 static int eth_igc_reset(struct rte_eth_dev *dev);
 static int eth_igc_promiscuous_enable(struct rte_eth_dev *dev);
 static int eth_igc_promiscuous_disable(struct rte_eth_dev *dev);
+static int eth_igc_fw_version_get(struct rte_eth_dev *dev,
+				char *fw_version, size_t fw_size);
 static int eth_igc_infos_get(struct rte_eth_dev *dev,
 			struct rte_eth_dev_info *dev_info);
+static int eth_igc_led_on(struct rte_eth_dev *dev);
+static int eth_igc_led_off(struct rte_eth_dev *dev);
+static void eth_igc_tx_queue_release(void *txq);
+static void eth_igc_rx_queue_release(void *rxq);
 static int
 eth_igc_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 		uint16_t nb_rx_desc, unsigned int socket_id,
@@ -52,35 +88,394 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 	.dev_start		= eth_igc_start,
 	.dev_close		= eth_igc_close,
 	.dev_reset		= eth_igc_reset,
+	.dev_set_link_up	= eth_igc_set_link_up,
+	.dev_set_link_down	= eth_igc_set_link_down,
 	.promiscuous_enable	= eth_igc_promiscuous_enable,
 	.promiscuous_disable	= eth_igc_promiscuous_disable,
+
+	.fw_version_get		= eth_igc_fw_version_get,
 	.dev_infos_get		= eth_igc_infos_get,
+	.dev_led_on		= eth_igc_led_on,
+	.dev_led_off		= eth_igc_led_off,
+
 	.rx_queue_setup		= eth_igc_rx_queue_setup,
+	.rx_queue_release	= eth_igc_rx_queue_release,
 	.tx_queue_setup		= eth_igc_tx_queue_setup,
+	.tx_queue_release	= eth_igc_tx_queue_release,
 };
 
+/*
+ * multipe queue mode checking
+ */
+static int
+igc_check_mq_mode(struct rte_eth_dev *dev)
+{
+	enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;
+	enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;
+
+	if (RTE_ETH_DEV_SRIOV(dev).active != 0) {
+		PMD_INIT_LOG(ERR, "SRIOV is not supported.");
+		return -EINVAL;
+	}
+
+	if (rx_mq_mode != ETH_MQ_RX_NONE &&
+		rx_mq_mode != ETH_MQ_RX_RSS) {
+		/* RSS together with VMDq not supported*/
+		PMD_INIT_LOG(ERR, "RX mode %d is not supported.",
+				rx_mq_mode);
+		return -EINVAL;
+	}
+
+	/* To no break software that set invalid mode, only display
+	 * warning if invalid mode is used.
+	 */
+	if (tx_mq_mode != ETH_MQ_TX_NONE)
+		PMD_INIT_LOG(WARNING,
+			"TX mode %d is not supported. Due to meaningless in this driver, just ignore",
+			tx_mq_mode);
+
+	return 0;
+}
+
 static int
 eth_igc_configure(struct rte_eth_dev *dev)
 {
+	struct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);
+	int ret;
+
 	PMD_INIT_FUNC_TRACE();
-	RTE_SET_USED(dev);
+
+	ret  = igc_check_mq_mode(dev);
+	if (ret != 0)
+		return ret;
+
+	intr->flags |= IGC_FLAG_NEED_LINK_UPDATE;
 	return 0;
 }
 
 static int
-eth_igc_link_update(struct rte_eth_dev *dev, int wait_to_complete)
+eth_igc_set_link_up(struct rte_eth_dev *dev)
 {
-	PMD_INIT_FUNC_TRACE();
-	RTE_SET_USED(dev);
-	RTE_SET_USED(wait_to_complete);
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
+	if (hw->phy.media_type == igc_media_type_copper)
+		igc_power_up_phy(hw);
+	else
+		igc_power_up_fiber_serdes_link(hw);
+	return 0;
+}
+
+static int
+eth_igc_set_link_down(struct rte_eth_dev *dev)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
+	if (hw->phy.media_type == igc_media_type_copper)
+		igc_power_down_phy(hw);
+	else
+		igc_shutdown_fiber_serdes_link(hw);
 	return 0;
 }
 
+/*
+ * disable other interrupt
+ */
+static void
+igc_intr_other_disable(struct rte_eth_dev *dev)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_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 (rte_intr_allow_others(intr_handle) &&
+		dev->data->dev_conf.intr_conf.lsc) {
+		IGC_WRITE_REG(hw, IGC_EIMC, 1u << IGC_MSIX_OTHER_INTR_VEC);
+	}
+
+	IGC_WRITE_REG(hw, IGC_IMC, ~0);
+	IGC_WRITE_FLUSH(hw);
+}
+
+/*
+ * enable other interrupt
+ */
+static inline void
+igc_intr_other_enable(struct rte_eth_dev *dev)
+{
+	struct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);
+	struct igc_hw *hw = IGC_DEV_PRIVATE_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 (rte_intr_allow_others(intr_handle) &&
+		dev->data->dev_conf.intr_conf.lsc) {
+		IGC_WRITE_REG(hw, IGC_EIMS, 1u << IGC_MSIX_OTHER_INTR_VEC);
+	}
+
+	IGC_WRITE_REG(hw, IGC_IMS, intr->mask);
+	IGC_WRITE_FLUSH(hw);
+}
+
+/*
+ * It reads ICR and gets interrupt causes, check it and set a bit flag
+ * to update link status.
+ */
+static void
+eth_igc_interrupt_get_status(struct rte_eth_dev *dev)
+{
+	uint32_t icr;
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);
+
+	/* read-on-clear nic registers here */
+	icr = IGC_READ_REG(hw, IGC_ICR);
+
+	intr->flags = 0;
+	if (icr & IGC_ICR_LSC)
+		intr->flags |= IGC_FLAG_NEED_LINK_UPDATE;
+}
+
+/* return 0 means link status changed, -1 means not changed */
+static int
+eth_igc_link_update(struct rte_eth_dev *dev, int wait_to_complete)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct rte_eth_link link;
+	int link_check, count;
+
+	link_check = 0;
+	hw->mac.get_link_status = 1;
+
+	/* possible wait-to-complete in up to 9 seconds */
+	for (count = 0; count < IGC_LINK_UPDATE_CHECK_TIMEOUT; count++) {
+		/* Read the real link status */
+		switch (hw->phy.media_type) {
+		case igc_media_type_copper:
+			/* Do the work to read phy */
+			igc_check_for_link(hw);
+			link_check = !hw->mac.get_link_status;
+			break;
+
+		case igc_media_type_fiber:
+			igc_check_for_link(hw);
+			link_check = (IGC_READ_REG(hw, IGC_STATUS) &
+				      IGC_STATUS_LU);
+			break;
+
+		case igc_media_type_internal_serdes:
+			igc_check_for_link(hw);
+			link_check = hw->mac.serdes_has_link;
+			break;
+
+		default:
+			break;
+		}
+		if (link_check || wait_to_complete == 0)
+			break;
+		rte_delay_ms(IGC_LINK_UPDATE_CHECK_INTERVAL);
+	}
+	memset(&link, 0, sizeof(link));
+
+	/* Now we check if a transition has happened */
+	if (link_check) {
+		uint16_t duplex, speed;
+		hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+		link.link_duplex = (duplex == FULL_DUPLEX) ?
+				ETH_LINK_FULL_DUPLEX :
+				ETH_LINK_HALF_DUPLEX;
+		link.link_speed = speed;
+		link.link_status = ETH_LINK_UP;
+		link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+				ETH_LINK_SPEED_FIXED);
+
+		if (speed == SPEED_2500) {
+			uint32_t tipg = IGC_READ_REG(hw, IGC_TIPG);
+			if ((tipg & IGC_TIPG_IPGT_MASK) != 0x0b) {
+				tipg &= ~IGC_TIPG_IPGT_MASK;
+				tipg |= 0x0b;
+				IGC_WRITE_REG(hw, IGC_TIPG, tipg);
+			}
+		}
+	} else {
+		link.link_speed = 0;
+		link.link_duplex = ETH_LINK_HALF_DUPLEX;
+		link.link_status = ETH_LINK_DOWN;
+		link.link_autoneg = ETH_LINK_FIXED;
+	}
+
+	return rte_eth_linkstatus_set(dev, &link);
+}
+
+/*
+ * It executes link_update after knowing an interrupt is present.
+ */
+static void
+eth_igc_interrupt_action(struct rte_eth_dev *dev)
+{
+	struct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_eth_link link;
+	int ret;
+
+	if (intr->flags & IGC_FLAG_NEED_LINK_UPDATE) {
+		intr->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;
+
+		/* set get_link_status to check register later */
+		ret = eth_igc_link_update(dev, 0);
+
+		/* check if link has changed */
+		if (ret < 0)
+			return;
+
+		rte_eth_linkstatus_get(dev, &link);
+		if (link.link_status)
+			PMD_DRV_LOG(INFO,
+				" Port %d: Link Up - speed %u Mbps - %s",
+				dev->data->port_id,
+				(unsigned int)link.link_speed,
+				link.link_duplex == ETH_LINK_FULL_DUPLEX ?
+				"full-duplex" : "half-duplex");
+		else
+			PMD_DRV_LOG(INFO, " Port %d: Link Down",
+				dev->data->port_id);
+
+		PMD_DRV_LOG(DEBUG, "PCI Address: " PCI_PRI_FMT,
+				pci_dev->addr.domain,
+				pci_dev->addr.bus,
+				pci_dev->addr.devid,
+				pci_dev->addr.function);
+		_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
+				NULL);
+	}
+}
+
+/*
+ * Interrupt handler which shall be registered at first.
+ *
+ * @handle
+ *  Pointer to interrupt handle.
+ * @param
+ *  The address of parameter (struct rte_eth_dev *) regsitered before.
+ */
+static void
+eth_igc_interrupt_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+
+	eth_igc_interrupt_get_status(dev);
+	eth_igc_interrupt_action(dev);
+}
+
+/*
+ *  This routine disables all traffic on the adapter by issuing a
+ *  global reset on the MAC.
+ */
 static void
 eth_igc_stop(struct rte_eth_dev *dev)
 {
-	PMD_INIT_FUNC_TRACE();
-	RTE_SET_USED(dev);
+	struct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+	struct rte_eth_link link;
+
+	adapter->stopped = 1;
+
+	/* disable all MSI-X interrupts */
+	IGC_WRITE_REG(hw, IGC_EIMC, 0x1f);
+	IGC_WRITE_FLUSH(hw);
+
+	/* clear all MSI-X interrupts */
+	IGC_WRITE_REG(hw, IGC_EICR, 0x1f);
+
+	igc_intr_other_disable(dev);
+
+	/* disable intr eventfd mapping */
+	rte_intr_disable(intr_handle);
+
+	igc_reset_hw(hw);
+
+	/* disable all wake up */
+	IGC_WRITE_REG(hw, IGC_WUC, 0);
+
+	/* Set bit for Go Link disconnect */
+	igc_read_reg_check_set_bits(hw, IGC_82580_PHY_POWER_MGMT,
+			IGC_82580_PM_GO_LINKD);
+
+	/* Power down the phy. Needed to make the link go Down */
+	eth_igc_set_link_down(dev);
+
+	/* clear the 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,
+					   eth_igc_interrupt_handler,
+					   (void *)dev);
+
+	/* Clean datapath event and queue/vec mapping */
+	rte_intr_efd_disable(intr_handle);
+}
+
+/* Sets up the hardware to generate MSI-X interrupts properly
+ * @hw
+ *  board private structure
+ */
+static void
+igc_configure_msix_intr(struct rte_eth_dev *dev)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_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_mask;
+
+	/* won't configure msix register if no mapping is done
+	 * between intr vector and event fd
+	 */
+	if (!rte_intr_dp_is_en(intr_handle) ||
+		!dev->data->dev_conf.intr_conf.lsc)
+		return;
+
+	/* turn on MSI-X capability first */
+	IGC_WRITE_REG(hw, IGC_GPIE, IGC_GPIE_MSIX_MODE |
+				IGC_GPIE_PBA | IGC_GPIE_EIAME |
+				IGC_GPIE_NSICR);
+
+	intr_mask = (1u << IGC_MSIX_OTHER_INTR_VEC);
+
+	/* enable msix auto-clear */
+	igc_read_reg_check_set_bits(hw, IGC_EIAC, intr_mask);
+
+	/* set other cause interrupt vector */
+	igc_read_reg_check_set_bits(hw, IGC_IVAR_MISC,
+		(uint32_t)(IGC_MSIX_OTHER_INTR_VEC | IGC_IVAR_VALID) << 8);
+
+	/* enable auto-mask */
+	igc_read_reg_check_set_bits(hw, IGC_EIAM, intr_mask);
+
+	IGC_WRITE_FLUSH(hw);
+}
+
+/**
+ * It enables the interrupt mask and then enable the interrupt.
+ *
+ * @dev
+ *  Pointer to struct rte_eth_dev.
+ * @on
+ *  Enable or Disable
+ */
+static void
+igc_lsc_interrupt_setup(struct rte_eth_dev *dev, uint8_t on)
+{
+	struct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);
+
+	if (on)
+		intr->mask |= IGC_ICR_LSC;
+	else
+		intr->mask &= ~IGC_ICR_LSC;
 }
 
 /*
@@ -170,9 +565,134 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 static int
 eth_igc_start(struct rte_eth_dev *dev)
 {
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct igc_adapter *adapter = IGC_DEV_PRIVATE(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 *speeds;
+	int num_speeds;
+	bool autoneg;
+
 	PMD_INIT_FUNC_TRACE();
-	RTE_SET_USED(dev);
+
+	/* disable all MSI-X interrupts */
+	IGC_WRITE_REG(hw, IGC_EIMC, 0x1f);
+	IGC_WRITE_FLUSH(hw);
+
+	/* clear all MSI-X interrupts */
+	IGC_WRITE_REG(hw, IGC_EICR, 0x1f);
+
+	/* disable uio/vfio intr/eventfd mapping */
+	if (!adapter->stopped)
+		rte_intr_disable(intr_handle);
+
+	/* Power up the phy. Needed to make the link go Up */
+	eth_igc_set_link_up(dev);
+
+	/* Put the address into the Receive Address Array */
+	igc_rar_set(hw, hw->mac.addr, 0);
+
+	/* Initialize the hardware */
+	if (igc_hardware_init(hw)) {
+		PMD_DRV_LOG(ERR, "Unable to initialize the hardware");
+		return -EIO;
+	}
+	adapter->stopped = 0;
+
+	/* confiugre msix for rx interrupt */
+	igc_configure_msix_intr(dev);
+
+	igc_clear_hw_cntrs_base_generic(hw);
+
+	/* Setup link speed and duplex */
+	speeds = &dev->data->dev_conf.link_speeds;
+	if (*speeds == ETH_LINK_SPEED_AUTONEG) {
+		hw->phy.autoneg_advertised = IGC_ALL_SPEED_DUPLEX_2500;
+		hw->mac.autoneg = 1;
+	} else {
+		num_speeds = 0;
+		autoneg = (*speeds & ETH_LINK_SPEED_FIXED) == 0;
+
+		/* Reset */
+		hw->phy.autoneg_advertised = 0;
+
+		if (*speeds & ~(ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M |
+				ETH_LINK_SPEED_100M_HD | ETH_LINK_SPEED_100M |
+				ETH_LINK_SPEED_1G | ETH_LINK_SPEED_2_5G |
+				ETH_LINK_SPEED_FIXED)) {
+			num_speeds = -1;
+			goto error_invalid_config;
+		}
+		if (*speeds & ETH_LINK_SPEED_10M_HD) {
+			hw->phy.autoneg_advertised |= ADVERTISE_10_HALF;
+			num_speeds++;
+		}
+		if (*speeds & ETH_LINK_SPEED_10M) {
+			hw->phy.autoneg_advertised |= ADVERTISE_10_FULL;
+			num_speeds++;
+		}
+		if (*speeds & ETH_LINK_SPEED_100M_HD) {
+			hw->phy.autoneg_advertised |= ADVERTISE_100_HALF;
+			num_speeds++;
+		}
+		if (*speeds & ETH_LINK_SPEED_100M) {
+			hw->phy.autoneg_advertised |= ADVERTISE_100_FULL;
+			num_speeds++;
+		}
+		if (*speeds & ETH_LINK_SPEED_1G) {
+			hw->phy.autoneg_advertised |= ADVERTISE_1000_FULL;
+			num_speeds++;
+		}
+		if (*speeds & ETH_LINK_SPEED_2_5G) {
+			hw->phy.autoneg_advertised |= ADVERTISE_2500_FULL;
+			num_speeds++;
+		}
+		if (num_speeds == 0 || (!autoneg && num_speeds > 1))
+			goto error_invalid_config;
+
+		/* Set/reset the mac.autoneg based on the link speed,
+		 * fixed or not
+		 */
+		if (!autoneg) {
+			hw->mac.autoneg = 0;
+			hw->mac.forced_speed_duplex =
+					hw->phy.autoneg_advertised;
+		} else {
+			hw->mac.autoneg = 1;
+		}
+	}
+
+	igc_setup_link(hw);
+
+	if (rte_intr_allow_others(intr_handle)) {
+		/* check if lsc interrupt is enabled */
+		if (dev->data->dev_conf.intr_conf.lsc)
+			igc_lsc_interrupt_setup(dev, 1);
+		else
+			igc_lsc_interrupt_setup(dev, 0);
+	} else {
+		rte_intr_callback_unregister(intr_handle,
+					     eth_igc_interrupt_handler,
+					     (void *)dev);
+		if (dev->data->dev_conf.intr_conf.lsc)
+			PMD_DRV_LOG(INFO,
+				"LSC won't enable because of no intr multiplex");
+	}
+
+	/* enable uio/vfio intr/eventfd mapping */
+	rte_intr_enable(intr_handle);
+
+	/* resume enabled intr since hw reset */
+	igc_intr_other_enable(dev);
+
+	eth_igc_link_update(dev, 0);
+
 	return 0;
+
+error_invalid_config:
+	PMD_DRV_LOG(ERR, "Invalid advertised speeds (%u) for port %u",
+		     dev->data->dev_conf.link_speeds, dev->data->port_id);
+	return -EINVAL;
 }
 
 static int
@@ -232,10 +752,28 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 static void
 eth_igc_close(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 igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);
+	int retry = 0;
 
 	PMD_INIT_FUNC_TRACE();
 
+	if (!adapter->stopped)
+		eth_igc_stop(dev);
+
+	igc_intr_other_disable(dev);
+	do {
+		int ret = rte_intr_callback_unregister(intr_handle,
+				eth_igc_interrupt_handler, dev);
+		if (ret >= 0 || ret == -ENOENT || ret == -EINVAL)
+			break;
+
+		PMD_DRV_LOG(ERR, "intr callback unregister failed: %d", ret);
+		DELAY(200 * 1000); /* delay 200ms */
+	} while (retry++ < 5);
+
 	igc_phy_hw_reset(hw);
 	igc_hw_control_release(hw);
 
@@ -258,6 +796,7 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 eth_igc_dev_init(struct rte_eth_dev *dev)
 {
 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
 	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
 	int error = 0;
 
@@ -364,6 +903,7 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 	dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
 
 	hw->mac.get_link_status = 1;
+	igc->stopped = 0;
 
 	/* Indicate SOL/IDER usage */
 	if (igc_check_reset_block(hw) < 0)
@@ -374,6 +914,15 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 			dev->data->port_id, pci_dev->id.vendor_id,
 			pci_dev->id.device_id);
 
+	rte_intr_callback_register(&pci_dev->intr_handle,
+			eth_igc_interrupt_handler, (void *)dev);
+
+	/* enable uio/vfio intr/eventfd mapping */
+	rte_intr_enable(&pci_dev->intr_handle);
+
+	/* enable support intr */
+	igc_intr_other_enable(dev);
+
 	return 0;
 
 err_late:
@@ -424,16 +973,81 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 }
 
 static int
+eth_igc_fw_version_get(struct rte_eth_dev *dev, char *fw_version,
+		       size_t fw_size)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct igc_fw_version fw;
+	int ret;
+
+	igc_get_fw_version(hw, &fw);
+
+	/* if option rom is valid, display its version too */
+	if (fw.or_valid) {
+		ret = snprintf(fw_version, fw_size,
+			 "%d.%d, 0x%08x, %d.%d.%d",
+			 fw.eep_major, fw.eep_minor, fw.etrack_id,
+			 fw.or_major, fw.or_build, fw.or_patch);
+	/* no option rom */
+	} else {
+		if (fw.etrack_id != 0X0000) {
+			ret = snprintf(fw_version, fw_size,
+				 "%d.%d, 0x%08x",
+				 fw.eep_major, fw.eep_minor,
+				 fw.etrack_id);
+		} else {
+			ret = snprintf(fw_version, fw_size,
+				 "%d.%d.%d",
+				 fw.eep_major, fw.eep_minor,
+				 fw.eep_build);
+		}
+	}
+
+	ret += 1; /* add the size of '\0' */
+	if (fw_size < (u32)ret)
+		return ret;
+	else
+		return 0;
+}
+
+static int
 eth_igc_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
-	PMD_INIT_FUNC_TRACE();
-	RTE_SET_USED(dev);
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
+	dev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */
+	dev_info->max_rx_pktlen = MAX_RX_JUMBO_FRAME_SIZE;
+	dev_info->max_mac_addrs = hw->mac.rar_entry_count;
 	dev_info->max_rx_queues = IGC_QUEUE_PAIRS_NUM;
 	dev_info->max_tx_queues = IGC_QUEUE_PAIRS_NUM;
+	dev_info->max_vmdq_pools = 0;
+
+	dev_info->speed_capa = ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M |
+			ETH_LINK_SPEED_100M_HD | ETH_LINK_SPEED_100M |
+			ETH_LINK_SPEED_1G | ETH_LINK_SPEED_2_5G;
+
+	dev_info->max_mtu = dev_info->max_rx_pktlen - IGC_ETH_OVERHEAD;
+	dev_info->min_mtu = RTE_ETHER_MIN_MTU;
 	return 0;
 }
 
 static int
+eth_igc_led_on(struct rte_eth_dev *dev)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
+	return igc_led_on(hw) == IGC_SUCCESS ? 0 : -ENOTSUP;
+}
+
+static int
+eth_igc_led_off(struct rte_eth_dev *dev)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
+	return igc_led_off(hw) == IGC_SUCCESS ? 0 : -ENOTSUP;
+}
+
+static int
 eth_igc_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 		uint16_t nb_rx_desc, unsigned int socket_id,
 		const struct rte_eth_rxconf *rx_conf,
@@ -463,6 +1077,16 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void eth_igc_tx_queue_release(void *txq)
+{
+	RTE_SET_USED(txq);
+}
+
+static void eth_igc_rx_queue_release(void *rxq)
+{
+	RTE_SET_USED(rxq);
+}
+
 static int
 eth_igc_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 	struct rte_pci_device *pci_dev)
diff --git a/drivers/net/igc/igc_ethdev.h b/drivers/net/igc/igc_ethdev.h
index 4cff0e3..c1e3217 100644
--- a/drivers/net/igc/igc_ethdev.h
+++ b/drivers/net/igc/igc_ethdev.h
@@ -18,11 +18,19 @@
 
 #define IGC_QUEUE_PAIRS_NUM		4
 
+/* structure for interrupt relative data */
+struct igc_interrupt {
+	uint32_t flags;
+	uint32_t mask;
+};
+
 /*
  * Structure to store private data for each driver instance (for each port).
  */
 struct igc_adapter {
 	struct igc_hw		hw;
+	struct igc_interrupt	intr;
+	bool		stopped;
 };
 
 #define IGC_DEV_PRIVATE(_dev)	((_dev)->data->dev_private)
@@ -30,6 +38,33 @@ struct igc_adapter {
 #define IGC_DEV_PRIVATE_HW(_dev) \
 	(&((struct igc_adapter *)(_dev)->data->dev_private)->hw)
 
+#define IGC_DEV_PRIVATE_INTR(_dev) \
+	(&((struct igc_adapter *)(_dev)->data->dev_private)->intr)
+
+static inline void
+igc_read_reg_check_set_bits(struct igc_hw *hw, uint32_t reg, uint32_t bits)
+{
+	uint32_t reg_val = IGC_READ_REG(hw, reg);
+
+	bits |= reg_val;
+	if (bits == reg_val)
+		return;	/* no need to write back */
+
+	IGC_WRITE_REG(hw, reg, bits);
+}
+
+static inline void
+igc_read_reg_check_clear_bits(struct igc_hw *hw, uint32_t reg, uint32_t bits)
+{
+	uint32_t reg_val = IGC_READ_REG(hw, reg);
+
+	bits = reg_val & ~bits;
+	if (bits == reg_val)
+		return;	/* no need to write back */
+
+	IGC_WRITE_REG(hw, reg, bits);
+}
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.3.1


  parent reply	other threads:[~2020-04-15  8:49 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-13  6:30 [dpdk-dev] [PATCH v3 00/11] igc pmd alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 01/11] net/igc: add igc PMD alvinx.zhang
2020-04-13 15:19   ` Stephen Hemminger
2020-04-15  8:47   ` [dpdk-dev] [PATCH v4 00/11] " alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 01/11] net/igc: add " alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 02/11] net/igc: support device initialization alvinx.zhang
2020-04-15  8:48     ` alvinx.zhang [this message]
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 04/11] net/igc: support reception and transmission of packets alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 05/11] net/igc: enable statistics alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 06/11] net/igc: enable Rx queue interrupts alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 07/11] net/igc: implement flow control ops alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 08/11] net/igc: implement RSS API alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 09/11] net/igc: implement feature of VLAN alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 10/11] net/igc: implement MAC-loopback mode alvinx.zhang
2020-04-15  8:48     ` [dpdk-dev] [PATCH v4 11/11] net/igc: implement flow API alvinx.zhang
2020-04-15 11:14     ` [dpdk-dev] [PATCH v4 00/11] igc PMD Ferruh Yigit
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 02/11] net/igc: support device initialization alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 03/11] net/igc: implement device base ops alvinx.zhang
2020-04-13 15:23   ` Stephen Hemminger
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 04/11] net/igc: support reception and transmission of packets alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 05/11] net/igc: enable statistics alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 06/11] net/igc: enable Rx queue interrupts alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 07/11] net/igc: implement flow control ops alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 08/11] net/igc: implement RSS API alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 09/11] net/igc: implement feature of VLAN alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 10/11] net/igc: implement MAC-loopback mode alvinx.zhang
2020-04-13  6:30 ` [dpdk-dev] [PATCH v3 11/11] net/igc: implement flow API alvinx.zhang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200415084810.20816-4-alvinx.zhang@intel.com \
    --to=alvinx.zhang@intel.com \
    --cc=dev@dpdk.org \
    --cc=xiaolong.ye@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.