get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/66382/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 66382,
    "url": "https://patches.dpdk.org/api/patches/66382/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1583742247-370386-4-git-send-email-alvinx.zhang@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1583742247-370386-4-git-send-email-alvinx.zhang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1583742247-370386-4-git-send-email-alvinx.zhang@intel.com",
    "date": "2020-03-09T08:23:56",
    "name": "[v1,04/15] net/igc: implement device base ops",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "5aa176f4bde183b9db921d853c164362413a7f03",
    "submitter": {
        "id": 1398,
        "url": "https://patches.dpdk.org/api/people/1398/?format=api",
        "name": "Alvin Zhang",
        "email": "alvinx.zhang@intel.com"
    },
    "delegate": {
        "id": 319,
        "url": "https://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1583742247-370386-4-git-send-email-alvinx.zhang@intel.com/mbox/",
    "series": [
        {
            "id": 8831,
            "url": "https://patches.dpdk.org/api/series/8831/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=8831",
            "date": "2020-03-09T08:23:53",
            "name": "[v1,01/15] net/igc: add igc PMD",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/8831/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/66382/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/66382/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 12AEBA052E;\n\tMon,  9 Mar 2020 09:29:06 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 8EA521C036;\n\tMon,  9 Mar 2020 09:28:56 +0100 (CET)",
            "from mga18.intel.com (mga18.intel.com [134.134.136.126])\n by dpdk.org (Postfix) with ESMTP id 911E11C01F\n for <dev@dpdk.org>; Mon,  9 Mar 2020 09:28:54 +0100 (CET)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n 09 Mar 2020 01:28:53 -0700",
            "from unknown (HELO dpdk-zhangalvin-dev.sh.intel.com)\n ([10.240.179.50])\n by orsmga002.jf.intel.com with ESMTP; 09 Mar 2020 01:28:50 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.70,518,1574150400\"; d=\"scan'208\";a=\"260350693\"",
        "From": "alvinx.zhang@intel.com",
        "To": "dev@dpdk.org",
        "Cc": "haiyue.wang@intel.com, xiaolong.ye@intel.com, qi.z.zhang@intel.com,\n beilei.xing@intel.com, Alvin Zhang <alvinx.zhang@intel.com>",
        "Date": "Mon,  9 Mar 2020 16:23:56 +0800",
        "Message-Id": "<1583742247-370386-4-git-send-email-alvinx.zhang@intel.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1583742247-370386-1-git-send-email-alvinx.zhang@intel.com>",
        "References": "<1583742247-370386-1-git-send-email-alvinx.zhang@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v1 04/15] net/igc: implement device base ops",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Alvin Zhang <alvinx.zhang@intel.com>\n\nBellow ops are implemented:\ndev_configure\ndev_start\ndev_stop\ndev_close\ndev_reset\ndev_set_link_up\ndev_set_link_down\nlink_update\nfw_version_get\ndev_led_on\ndev_led_off\n\nSigned-off-by: Alvin Zhang <alvinx.zhang@intel.com>\n---\n doc/guides/nics/features/igc.ini |   4 +\n drivers/net/igc/igc_ethdev.c     | 644 ++++++++++++++++++++++++++++++++++++++-\n drivers/net/igc/igc_ethdev.h     |  37 ++-\n 3 files changed, 674 insertions(+), 11 deletions(-)",
    "diff": "diff --git a/doc/guides/nics/features/igc.ini b/doc/guides/nics/features/igc.ini\nindex ad75cc4..b7f546e 100644\n--- a/doc/guides/nics/features/igc.ini\n+++ b/doc/guides/nics/features/igc.ini\n@@ -3,6 +3,10 @@\n ; Refer to default.ini for the full list of available PMD features.\n ;\n [Features]\n+Speed capabilities   = Y\n+Link status          = Y\n+Link status event    = Y\n+FW version           = Y\n Linux UIO            = Y\n Linux VFIO           = Y\n x86-64               = Y\ndiff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c\nindex 4d78f0e..09f19f2 100644\n--- a/drivers/net/igc/igc_ethdev.c\n+++ b/drivers/net/igc/igc_ethdev.c\n@@ -12,7 +12,34 @@\n \n #define IGC_INTEL_VENDOR_ID\t\t0x8086\n \n+/*\n+ * The overhead from MTU to max frame size.\n+ * Considering VLAN so a tag needs to be counted.\n+ */\n+#define IGC_ETH_OVERHEAD\t\t(RTE_ETHER_HDR_LEN + \\\n+\t\t\t\t\tRTE_ETHER_CRC_LEN + VLAN_TAG_SIZE)\n+\n #define IGC_FC_PAUSE_TIME\t\t0x0680\n+#define IGC_LINK_UPDATE_CHECK_TIMEOUT\t90  /* 9s */\n+#define IGC_LINK_UPDATE_CHECK_INTERVAL\t100 /* ms */\n+\n+#define IGC_MISC_VEC_ID\t\t\tRTE_INTR_VEC_ZERO_OFFSET\n+#define IGC_RX_VEC_START\t\tRTE_INTR_VEC_RXTX_OFFSET\n+#define IGC_MSIX_OTHER_INTR_VEC\t\t0   /* MSI-X other interrupt vector */\n+#define IGC_FLAG_NEED_LINK_UPDATE\t(1u << 0)\t/* need update link */\n+\n+#define IGC_DEFAULT_RX_FREE_THRESH\t32\n+\n+#define IGC_DEFAULT_RX_PTHRESH\t\t8\n+#define IGC_DEFAULT_RX_HTHRESH\t\t8\n+#define IGC_DEFAULT_RX_WTHRESH\t\t4\n+\n+#define IGC_DEFAULT_TX_PTHRESH\t\t8\n+#define IGC_DEFAULT_TX_HTHRESH\t\t1\n+#define IGC_DEFAULT_TX_WTHRESH\t\t16\n+\n+/* MSI-X other interrupt vector */\n+#define IGC_MSIX_OTHER_INTR_VEC\t\t0\n \n static const struct rte_pci_id pci_id_igc_map[] = {\n \t{ RTE_PCI_DEVICE(IGC_INTEL_VENDOR_ID, IGC_DEV_ID_I225_LM) },\n@@ -27,12 +54,20 @@\n static int eth_igc_link_update(struct rte_eth_dev *dev, int wait_to_complete);\n static void eth_igc_stop(struct rte_eth_dev *dev);\n static int eth_igc_start(struct rte_eth_dev *dev);\n+static int eth_igc_set_link_up(struct rte_eth_dev *dev);\n+static int eth_igc_set_link_down(struct rte_eth_dev *dev);\n static void eth_igc_close(struct rte_eth_dev *dev);\n static int eth_igc_reset(struct rte_eth_dev *dev);\n static int eth_igc_promiscuous_enable(struct rte_eth_dev *dev);\n static int eth_igc_promiscuous_disable(struct rte_eth_dev *dev);\n+static int eth_igc_fw_version_get(struct rte_eth_dev *dev,\n+\t\t\t\tchar *fw_version, size_t fw_size);\n static int eth_igc_infos_get(struct rte_eth_dev *dev,\n \t\t\tstruct rte_eth_dev_info *dev_info);\n+static int eth_igc_led_on(struct rte_eth_dev *dev);\n+static int eth_igc_led_off(struct rte_eth_dev *dev);\n+static void eth_igc_tx_queue_release(void *txq);\n+static void eth_igc_rx_queue_release(void *rxq);\n static int\n eth_igc_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,\n \t\tuint16_t nb_rx_desc, unsigned int socket_id,\n@@ -50,35 +85,395 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n \t.dev_start\t\t= eth_igc_start,\n \t.dev_close\t\t= eth_igc_close,\n \t.dev_reset\t\t= eth_igc_reset,\n+\t.dev_set_link_up\t= eth_igc_set_link_up,\n+\t.dev_set_link_down\t= eth_igc_set_link_down,\n \t.promiscuous_enable\t= eth_igc_promiscuous_enable,\n \t.promiscuous_disable\t= eth_igc_promiscuous_disable,\n+\n+\t.fw_version_get\t\t= eth_igc_fw_version_get,\n \t.dev_infos_get\t\t= eth_igc_infos_get,\n+\t.dev_led_on\t\t= eth_igc_led_on,\n+\t.dev_led_off\t\t= eth_igc_led_off,\n+\n \t.rx_queue_setup\t\t= eth_igc_rx_queue_setup,\n+\t.rx_queue_release\t= eth_igc_rx_queue_release,\n \t.tx_queue_setup\t\t= eth_igc_tx_queue_setup,\n+\t.tx_queue_release\t= eth_igc_tx_queue_release,\n };\n \n+/*\n+ * multipe queue mode checking\n+ */\n+static int\n+igc_check_mq_mode(struct rte_eth_dev *dev)\n+{\n+\tenum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;\n+\tenum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;\n+\n+\tif (RTE_ETH_DEV_SRIOV(dev).active != 0) {\n+\t\tPMD_INIT_LOG(ERR, \"SRIOV is not supported.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (rx_mq_mode != ETH_MQ_RX_NONE &&\n+\t\trx_mq_mode != ETH_MQ_RX_RSS) {\n+\t\t/* RSS together with VMDq not supported*/\n+\t\tPMD_INIT_LOG(ERR, \"RX mode %d is not supported.\",\n+\t\t\t\trx_mq_mode);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* To no break software that set invalid mode, only display\n+\t * warning if invalid mode is used.\n+\t */\n+\tif (tx_mq_mode != ETH_MQ_TX_NONE)\n+\t\tPMD_INIT_LOG(WARNING, \"TX mode %d is not supported.\"\n+\t\t\t\t\" Due to txmode is meaningless in this driver,\"\n+\t\t\t\t\" just ignore.\", tx_mq_mode);\n+\n+\treturn 0;\n+}\n+\n static int\n eth_igc_configure(struct rte_eth_dev *dev)\n {\n+\tstruct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);\n+\tint ret;\n+\n \tPMD_INIT_FUNC_TRACE();\n-\tRTE_SET_USED(dev);\n+\n+\tret  = igc_check_mq_mode(dev);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tintr->flags |= IGC_FLAG_NEED_LINK_UPDATE;\n \treturn 0;\n }\n \n static int\n-eth_igc_link_update(struct rte_eth_dev *dev, int wait_to_complete)\n+eth_igc_set_link_up(struct rte_eth_dev *dev)\n {\n-\tPMD_INIT_FUNC_TRACE();\n-\tRTE_SET_USED(dev);\n-\tRTE_SET_USED(wait_to_complete);\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\n+\tif (hw->phy.media_type == igc_media_type_copper)\n+\t\tigc_power_up_phy(hw);\n+\telse\n+\t\tigc_power_up_fiber_serdes_link(hw);\n+\treturn 0;\n+}\n+\n+static int\n+eth_igc_set_link_down(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\n+\tif (hw->phy.media_type == igc_media_type_copper)\n+\t\tigc_power_down_phy(hw);\n+\telse\n+\t\tigc_shutdown_fiber_serdes_link(hw);\n \treturn 0;\n }\n \n+/*\n+ * disable other interrupt\n+ */\n+static void\n+igc_intr_other_disable(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct rte_intr_handle *intr_handle = &pci_dev->intr_handle;\n+\n+\tif (rte_intr_allow_others(intr_handle) &&\n+\t\tdev->data->dev_conf.intr_conf.lsc) {\n+\t\tIGC_WRITE_REG(hw, IGC_EIMC, 1 << IGC_MSIX_OTHER_INTR_VEC);\n+\t}\n+\n+\tIGC_WRITE_REG(hw, IGC_IMC, ~0);\n+\tIGC_WRITE_FLUSH(hw);\n+}\n+\n+/*\n+ * enable other interrupt\n+ */\n+static inline void\n+igc_intr_other_enable(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct rte_intr_handle *intr_handle = &pci_dev->intr_handle;\n+\n+\tif (rte_intr_allow_others(intr_handle) &&\n+\t\tdev->data->dev_conf.intr_conf.lsc) {\n+\t\tIGC_WRITE_REG(hw, IGC_EIMS, 1 << IGC_MSIX_OTHER_INTR_VEC);\n+\t}\n+\n+\tIGC_WRITE_REG(hw, IGC_IMS, intr->mask);\n+\tIGC_WRITE_FLUSH(hw);\n+}\n+\n+/*\n+ * It reads ICR and gets interrupt causes, check it and set a bit flag\n+ * to update link status.\n+ */\n+static void\n+eth_igc_interrupt_get_status(struct rte_eth_dev *dev)\n+{\n+\tuint32_t icr;\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);\n+\n+\t/* read-on-clear nic registers here */\n+\ticr = IGC_READ_REG(hw, IGC_ICR);\n+\n+\tintr->flags = 0;\n+\tif (icr & IGC_ICR_LSC)\n+\t\tintr->flags |= IGC_FLAG_NEED_LINK_UPDATE;\n+}\n+\n+/* return 0 means link status changed, -1 means not changed */\n+static int\n+eth_igc_link_update(struct rte_eth_dev *dev, int wait_to_complete)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct rte_eth_link link;\n+\tint link_check, count;\n+\n+\tlink_check = 0;\n+\thw->mac.get_link_status = 1;\n+\n+\t/* possible wait-to-complete in up to 9 seconds */\n+\tfor (count = 0; count < IGC_LINK_UPDATE_CHECK_TIMEOUT; count++) {\n+\t\t/* Read the real link status */\n+\t\tswitch (hw->phy.media_type) {\n+\t\tcase igc_media_type_copper:\n+\t\t\t/* Do the work to read phy */\n+\t\t\tigc_check_for_link(hw);\n+\t\t\tlink_check = !hw->mac.get_link_status;\n+\t\t\tbreak;\n+\n+\t\tcase igc_media_type_fiber:\n+\t\t\tigc_check_for_link(hw);\n+\t\t\tlink_check = (IGC_READ_REG(hw, IGC_STATUS) &\n+\t\t\t\t      IGC_STATUS_LU);\n+\t\t\tbreak;\n+\n+\t\tcase igc_media_type_internal_serdes:\n+\t\t\tigc_check_for_link(hw);\n+\t\t\tlink_check = hw->mac.serdes_has_link;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (link_check || wait_to_complete == 0)\n+\t\t\tbreak;\n+\t\trte_delay_ms(IGC_LINK_UPDATE_CHECK_INTERVAL);\n+\t}\n+\tmemset(&link, 0, sizeof(link));\n+\n+\t/* Now we check if a transition has happened */\n+\tif (link_check) {\n+\t\tuint16_t duplex, speed;\n+\t\thw->mac.ops.get_link_up_info(hw, &speed, &duplex);\n+\t\tlink.link_duplex = (duplex == FULL_DUPLEX) ?\n+\t\t\t\tETH_LINK_FULL_DUPLEX :\n+\t\t\t\tETH_LINK_HALF_DUPLEX;\n+\t\tlink.link_speed = speed;\n+\t\tlink.link_status = ETH_LINK_UP;\n+\t\tlink.link_autoneg = !(dev->data->dev_conf.link_speeds &\n+\t\t\t\tETH_LINK_SPEED_FIXED);\n+\n+\t\tif (speed == SPEED_2500) {\n+\t\t\tuint32_t tipg = IGC_READ_REG(hw, IGC_TIPG);\n+\t\t\tif ((tipg & IGC_TIPG_IPGT_MASK) != 0x0b) {\n+\t\t\t\ttipg &= ~IGC_TIPG_IPGT_MASK;\n+\t\t\t\ttipg |= 0x0b;\n+\t\t\t\tIGC_WRITE_REG(hw, IGC_TIPG, tipg);\n+\t\t\t}\n+\t\t}\n+\t} else if (!link_check) {\n+\t\tlink.link_speed = 0;\n+\t\tlink.link_duplex = ETH_LINK_HALF_DUPLEX;\n+\t\tlink.link_status = ETH_LINK_DOWN;\n+\t\tlink.link_autoneg = ETH_LINK_FIXED;\n+\t}\n+\n+\treturn rte_eth_linkstatus_set(dev, &link);\n+}\n+\n+/*\n+ * It executes link_update after knowing an interrupt is present.\n+ */\n+static void\n+eth_igc_interrupt_action(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_interrupt *intr =\n+\t\tIGC_DEV_PRIVATE_INTR(dev);\n+\tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct rte_eth_link link;\n+\tint ret;\n+\n+\tif (intr->flags & IGC_FLAG_NEED_LINK_UPDATE) {\n+\t\tintr->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;\n+\n+\t\t/* set get_link_status to check register later */\n+\t\tret = eth_igc_link_update(dev, 0);\n+\n+\t\t/* check if link has changed */\n+\t\tif (ret < 0)\n+\t\t\treturn;\n+\n+\t\trte_eth_linkstatus_get(dev, &link);\n+\t\tif (link.link_status)\n+\t\t\tPMD_DRV_LOG(INFO,\n+\t\t\t\t\" Port %d: Link Up - speed %u Mbps - %s\",\n+\t\t\t\tdev->data->port_id,\n+\t\t\t\t(unsigned int)link.link_speed,\n+\t\t\t\tlink.link_duplex == ETH_LINK_FULL_DUPLEX ?\n+\t\t\t\t\"full-duplex\" : \"half-duplex\");\n+\t\telse\n+\t\t\tPMD_DRV_LOG(INFO, \" Port %d: Link Down\",\n+\t\t\t\tdev->data->port_id);\n+\n+\t\tPMD_DRV_LOG(DEBUG, \"PCI Address: %04d:%02d:%02d:%d\",\n+\t\t\t\tpci_dev->addr.domain,\n+\t\t\t\tpci_dev->addr.bus,\n+\t\t\t\tpci_dev->addr.devid,\n+\t\t\t\tpci_dev->addr.function);\n+\t\t_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,\n+\t\t\t\tNULL);\n+\t}\n+}\n+\n+/*\n+ * Interrupt handler which shall be registered at first.\n+ *\n+ * @handle\n+ *  Pointer to interrupt handle.\n+ * @param\n+ *  The address of parameter (struct rte_eth_dev *) regsitered before.\n+ */\n+static void\n+eth_igc_interrupt_handler(void *param)\n+{\n+\tstruct rte_eth_dev *dev = (struct rte_eth_dev *)param;\n+\n+\teth_igc_interrupt_get_status(dev);\n+\teth_igc_interrupt_action(dev);\n+}\n+\n+/*\n+ *  This routine disables all traffic on the adapter by issuing a\n+ *  global reset on the MAC.\n+ */\n static void\n eth_igc_stop(struct rte_eth_dev *dev)\n {\n-\tPMD_INIT_FUNC_TRACE();\n-\tRTE_SET_USED(dev);\n+\tstruct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct rte_intr_handle *intr_handle = &pci_dev->intr_handle;\n+\tstruct rte_eth_link link;\n+\n+\tadapter->stopped = 1;\n+\n+\t/* disable all MSI-X interrupts */\n+\tIGC_WRITE_REG(hw, IGC_EIMC, 0x1f);\n+\tIGC_WRITE_FLUSH(hw);\n+\n+\t/* clear all MSI-X interrupts */\n+\tIGC_WRITE_REG(hw, IGC_EICR, 0x1f);\n+\n+\tigc_intr_other_disable(dev);\n+\n+\t/* disable intr eventfd mapping */\n+\trte_intr_disable(intr_handle);\n+\n+\tigc_reset_hw(hw);\n+\n+\t/* disable all wake up */\n+\tIGC_WRITE_REG(hw, IGC_WUC, 0);\n+\n+\t/* Set bit for Go Link disconnect */\n+\tigc_read_reg_check_set_bits(hw, IGC_82580_PHY_POWER_MGMT,\n+\t\t\tIGC_82580_PM_GO_LINKD);\n+\n+\t/* Power down the phy. Needed to make the link go Down */\n+\teth_igc_set_link_down(dev);\n+\n+\t/* clear the recorded link status */\n+\tmemset(&link, 0, sizeof(link));\n+\trte_eth_linkstatus_set(dev, &link);\n+\n+\tif (!rte_intr_allow_others(intr_handle))\n+\t\t/* resume to the default handler */\n+\t\trte_intr_callback_register(intr_handle,\n+\t\t\t\t\t   eth_igc_interrupt_handler,\n+\t\t\t\t\t   (void *)dev);\n+\n+\t/* Clean datapath event and queue/vec mapping */\n+\trte_intr_efd_disable(intr_handle);\n+}\n+\n+/* Sets up the hardware to generate MSI-X interrupts properly\n+ * @hw\n+ *  board private structure\n+ */\n+static void\n+igc_configure_msix_intr(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct rte_intr_handle *intr_handle = &pci_dev->intr_handle;\n+\n+\tuint32_t intr_mask;\n+\n+\t/* won't configure msix register if no mapping is done\n+\t * between intr vector and event fd\n+\t */\n+\tif (!rte_intr_dp_is_en(intr_handle) ||\n+\t\t!dev->data->dev_conf.intr_conf.lsc)\n+\t\treturn;\n+\n+\t/* turn on MSI-X capability first */\n+\tIGC_WRITE_REG(hw, IGC_GPIE, IGC_GPIE_MSIX_MODE |\n+\t\t\t\tIGC_GPIE_PBA | IGC_GPIE_EIAME |\n+\t\t\t\tIGC_GPIE_NSICR);\n+\n+\tintr_mask = (1 << IGC_MSIX_OTHER_INTR_VEC);\n+\n+\t/* enable msix auto-clear */\n+\tigc_read_reg_check_set_bits(hw, IGC_EIAC, intr_mask);\n+\n+\t/* set other cause interrupt vector */\n+\tigc_read_reg_check_set_bits(hw, IGC_IVAR_MISC,\n+\t\t\t(IGC_MSIX_OTHER_INTR_VEC | IGC_IVAR_VALID) << 8);\n+\n+\t/* enable auto-mask */\n+\tigc_read_reg_check_set_bits(hw, IGC_EIAM, intr_mask);\n+\n+\tIGC_WRITE_FLUSH(hw);\n+}\n+\n+/**\n+ * It enables the interrupt mask and then enable the interrupt.\n+ *\n+ * @dev\n+ *  Pointer to struct rte_eth_dev.\n+ * @on\n+ *  Enable or Disable\n+ */\n+static void\n+igc_lsc_interrupt_setup(struct rte_eth_dev *dev, uint8_t on)\n+{\n+\tstruct igc_interrupt *intr = IGC_DEV_PRIVATE_INTR(dev);\n+\n+\tif (on)\n+\t\tintr->mask |= IGC_ICR_LSC;\n+\telse\n+\t\tintr->mask &= ~IGC_ICR_LSC;\n }\n \n /*\n@@ -168,9 +563,134 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n static int\n eth_igc_start(struct rte_eth_dev *dev)\n {\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);\n+\tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct rte_intr_handle *intr_handle = &pci_dev->intr_handle;\n+\tuint32_t *speeds;\n+\tint num_speeds;\n+\tbool autoneg;\n+\n \tPMD_INIT_FUNC_TRACE();\n-\tRTE_SET_USED(dev);\n+\n+\t/* disable all MSI-X interrupts */\n+\tIGC_WRITE_REG(hw, IGC_EIMC, 0x1f);\n+\tIGC_WRITE_FLUSH(hw);\n+\n+\t/* clear all MSI-X interrupts */\n+\tIGC_WRITE_REG(hw, IGC_EICR, 0x1f);\n+\n+\t/* disable uio/vfio intr/eventfd mapping */\n+\tif (!adapter->stopped)\n+\t\trte_intr_disable(intr_handle);\n+\n+\t/* Power up the phy. Needed to make the link go Up */\n+\teth_igc_set_link_up(dev);\n+\n+\t/* Put the address into the Receive Address Array */\n+\tigc_rar_set(hw, hw->mac.addr, 0);\n+\n+\t/* Initialize the hardware */\n+\tif (igc_hardware_init(hw)) {\n+\t\tPMD_DRV_LOG(ERR, \"Unable to initialize the hardware\");\n+\t\treturn -EIO;\n+\t}\n+\tadapter->stopped = 0;\n+\n+\t/* confiugre msix for rx interrupt */\n+\tigc_configure_msix_intr(dev);\n+\n+\tigc_clear_hw_cntrs_base_generic(hw);\n+\n+\t/* Setup link speed and duplex */\n+\tspeeds = &dev->data->dev_conf.link_speeds;\n+\tif (*speeds == ETH_LINK_SPEED_AUTONEG) {\n+\t\thw->phy.autoneg_advertised = IGC_ALL_SPEED_DUPLEX_2500;\n+\t\thw->mac.autoneg = 1;\n+\t} else {\n+\t\tnum_speeds = 0;\n+\t\tautoneg = (*speeds & ETH_LINK_SPEED_FIXED) == 0;\n+\n+\t\t/* Reset */\n+\t\thw->phy.autoneg_advertised = 0;\n+\n+\t\tif (*speeds & ~(ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M |\n+\t\t\t\tETH_LINK_SPEED_100M_HD | ETH_LINK_SPEED_100M |\n+\t\t\t\tETH_LINK_SPEED_1G | ETH_LINK_SPEED_2_5G |\n+\t\t\t\tETH_LINK_SPEED_FIXED)) {\n+\t\t\tnum_speeds = -1;\n+\t\t\tgoto error_invalid_config;\n+\t\t}\n+\t\tif (*speeds & ETH_LINK_SPEED_10M_HD) {\n+\t\t\thw->phy.autoneg_advertised |= ADVERTISE_10_HALF;\n+\t\t\tnum_speeds++;\n+\t\t}\n+\t\tif (*speeds & ETH_LINK_SPEED_10M) {\n+\t\t\thw->phy.autoneg_advertised |= ADVERTISE_10_FULL;\n+\t\t\tnum_speeds++;\n+\t\t}\n+\t\tif (*speeds & ETH_LINK_SPEED_100M_HD) {\n+\t\t\thw->phy.autoneg_advertised |= ADVERTISE_100_HALF;\n+\t\t\tnum_speeds++;\n+\t\t}\n+\t\tif (*speeds & ETH_LINK_SPEED_100M) {\n+\t\t\thw->phy.autoneg_advertised |= ADVERTISE_100_FULL;\n+\t\t\tnum_speeds++;\n+\t\t}\n+\t\tif (*speeds & ETH_LINK_SPEED_1G) {\n+\t\t\thw->phy.autoneg_advertised |= ADVERTISE_1000_FULL;\n+\t\t\tnum_speeds++;\n+\t\t}\n+\t\tif (*speeds & ETH_LINK_SPEED_2_5G) {\n+\t\t\thw->phy.autoneg_advertised |= ADVERTISE_2500_FULL;\n+\t\t\tnum_speeds++;\n+\t\t}\n+\t\tif (num_speeds == 0 || (!autoneg && num_speeds > 1))\n+\t\t\tgoto error_invalid_config;\n+\n+\t\t/* Set/reset the mac.autoneg based on the link speed,\n+\t\t * fixed or not\n+\t\t */\n+\t\tif (!autoneg) {\n+\t\t\thw->mac.autoneg = 0;\n+\t\t\thw->mac.forced_speed_duplex =\n+\t\t\t\t\thw->phy.autoneg_advertised;\n+\t\t} else {\n+\t\t\thw->mac.autoneg = 1;\n+\t\t}\n+\t}\n+\n+\tigc_setup_link(hw);\n+\n+\tif (rte_intr_allow_others(intr_handle)) {\n+\t\t/* check if lsc interrupt is enabled */\n+\t\tif (dev->data->dev_conf.intr_conf.lsc != 0)\n+\t\t\tigc_lsc_interrupt_setup(dev, TRUE);\n+\t\telse\n+\t\t\tigc_lsc_interrupt_setup(dev, FALSE);\n+\t} else {\n+\t\trte_intr_callback_unregister(intr_handle,\n+\t\t\t\t\t     eth_igc_interrupt_handler,\n+\t\t\t\t\t     (void *)dev);\n+\t\tif (dev->data->dev_conf.intr_conf.lsc != 0)\n+\t\t\tPMD_DRV_LOG(INFO, \"lsc won't enable because of\"\n+\t\t\t\t     \" no intr multiplex\");\n+\t}\n+\n+\t/* enable uio/vfio intr/eventfd mapping */\n+\trte_intr_enable(intr_handle);\n+\n+\t/* resume enabled intr since hw reset */\n+\tigc_intr_other_enable(dev);\n+\n+\teth_igc_link_update(dev, 0);\n+\n \treturn 0;\n+\n+error_invalid_config:\n+\tPMD_DRV_LOG(ERR, \"Invalid advertised speeds (%u) for port %u\",\n+\t\t     dev->data->dev_conf.link_speeds, dev->data->port_id);\n+\treturn -EINVAL;\n }\n \n static int\n@@ -230,10 +750,28 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n static void\n eth_igc_close(struct rte_eth_dev *dev)\n {\n+\tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct rte_intr_handle *intr_handle = &pci_dev->intr_handle;\n \tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);\n+\tint retry = 0;\n \n \tPMD_INIT_FUNC_TRACE();\n \n+\tif (!adapter->stopped)\n+\t\teth_igc_stop(dev);\n+\n+\tigc_intr_other_disable(dev);\n+\tdo {\n+\t\tint ret = rte_intr_callback_unregister(intr_handle,\n+\t\t\t\teth_igc_interrupt_handler, dev);\n+\t\tif (ret >= 0 || ret == -ENOENT || ret == -EINVAL)\n+\t\t\tbreak;\n+\n+\t\tPMD_DRV_LOG(ERR, \"intr callback unregister failed: %d\", ret);\n+\t\tDELAY(200 * 1000); /* delay 200ms */\n+\t} while (retry++ < 5);\n+\n \tigc_phy_hw_reset(hw);\n \tigc_hw_control_release(hw);\n \n@@ -257,6 +795,7 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n eth_igc_dev_init(struct rte_eth_dev *dev)\n {\n \tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct igc_adapter *igc = IGC_DEV_PRIVATE(dev);\n \tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n \tint error = 0;\n \n@@ -364,6 +903,7 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n \tdev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;\n \n \thw->mac.get_link_status = 1;\n+\tigc->stopped = 0;\n \n \t/* Indicate SOL/IDER usage */\n \tif (igc_check_reset_block(hw) < 0)\n@@ -374,6 +914,15 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n \t\t\tdev->data->port_id, pci_dev->id.vendor_id,\n \t\t\tpci_dev->id.device_id);\n \n+\trte_intr_callback_register(&pci_dev->intr_handle,\n+\t\t\teth_igc_interrupt_handler, (void *)dev);\n+\n+\t/* enable uio/vfio intr/eventfd mapping */\n+\trte_intr_enable(&pci_dev->intr_handle);\n+\n+\t/* enable support intr */\n+\tigc_intr_other_enable(dev);\n+\n \treturn 0;\n \n err_late:\n@@ -427,16 +976,81 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n }\n \n static int\n+eth_igc_fw_version_get(struct rte_eth_dev *dev, char *fw_version,\n+\t\t       size_t fw_size)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\tstruct igc_fw_version fw;\n+\tint ret;\n+\n+\tigc_get_fw_version(hw, &fw);\n+\n+\t/* if option rom is valid, display its version too */\n+\tif (fw.or_valid) {\n+\t\tret = snprintf(fw_version, fw_size,\n+\t\t\t \"%d.%d, 0x%08x, %d.%d.%d\",\n+\t\t\t fw.eep_major, fw.eep_minor, fw.etrack_id,\n+\t\t\t fw.or_major, fw.or_build, fw.or_patch);\n+\t/* no option rom */\n+\t} else {\n+\t\tif (fw.etrack_id != 0X0000) {\n+\t\t\tret = snprintf(fw_version, fw_size,\n+\t\t\t\t \"%d.%d, 0x%08x\",\n+\t\t\t\t fw.eep_major, fw.eep_minor,\n+\t\t\t\t fw.etrack_id);\n+\t\t} else {\n+\t\t\tret = snprintf(fw_version, fw_size,\n+\t\t\t\t \"%d.%d.%d\",\n+\t\t\t\t fw.eep_major, fw.eep_minor,\n+\t\t\t\t fw.eep_build);\n+\t\t}\n+\t}\n+\n+\tret += 1; /* add the size of '\\0' */\n+\tif (fw_size < (u32)ret)\n+\t\treturn ret;\n+\telse\n+\t\treturn 0;\n+}\n+\n+static int\n eth_igc_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)\n {\n-\tPMD_INIT_FUNC_TRACE();\n-\tRTE_SET_USED(dev);\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\n+\tdev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */\n+\tdev_info->max_rx_pktlen  = 0x2600; /* See RLPML register. */\n+\tdev_info->max_mac_addrs = hw->mac.rar_entry_count;\n \tdev_info->max_rx_queues = IGC_QUEUE_PAIRS_NUM;\n \tdev_info->max_tx_queues = IGC_QUEUE_PAIRS_NUM;\n+\tdev_info->max_vmdq_pools = 0;\n+\n+\tdev_info->speed_capa = ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M |\n+\t\t\tETH_LINK_SPEED_100M_HD | ETH_LINK_SPEED_100M |\n+\t\t\tETH_LINK_SPEED_1G | ETH_LINK_SPEED_2_5G;\n+\n+\tdev_info->max_mtu = dev_info->max_rx_pktlen - IGC_ETH_OVERHEAD;\n+\tdev_info->min_mtu = RTE_ETHER_MIN_MTU;\n \treturn 0;\n }\n \n static int\n+eth_igc_led_on(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\n+\treturn igc_led_on(hw) == IGC_SUCCESS ? 0 : -ENOTSUP;\n+}\n+\n+static int\n+eth_igc_led_off(struct rte_eth_dev *dev)\n+{\n+\tstruct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);\n+\n+\treturn igc_led_off(hw) == IGC_SUCCESS ? 0 : -ENOTSUP;\n+}\n+\n+static int\n eth_igc_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,\n \t\tuint16_t nb_rx_desc, unsigned int socket_id,\n \t\tconst struct rte_eth_rxconf *rx_conf,\n@@ -466,6 +1080,16 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+static void eth_igc_tx_queue_release(void *txq)\n+{\n+\tRTE_SET_USED(txq);\n+}\n+\n+static void eth_igc_rx_queue_release(void *rxq)\n+{\n+\tRTE_SET_USED(rxq);\n+}\n+\n static int\n eth_igc_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \tstruct rte_pci_device *pci_dev)\ndiff --git a/drivers/net/igc/igc_ethdev.h b/drivers/net/igc/igc_ethdev.h\nindex c5d51f6..eb38e7a 100644\n--- a/drivers/net/igc/igc_ethdev.h\n+++ b/drivers/net/igc/igc_ethdev.h\n@@ -18,11 +18,19 @@\n \n #define IGC_QUEUE_PAIRS_NUM\t\t4\n \n+/* structure for interrupt relative data */\n+struct igc_interrupt {\n+\tuint32_t flags;\n+\tuint32_t mask;\n+};\n+\n /*\n  * Structure to store private data for each driver instance (for each port).\n  */\n struct igc_adapter {\n-\tstruct igc_hw         hw;\n+\tstruct igc_hw\thw;\n+\tstruct igc_interrupt  intr;\n+\tbool\t\tstopped;\n };\n \n #define IGC_DEV_PRIVATE(_dev)\t((_dev)->data->dev_private)\n@@ -30,6 +38,33 @@ struct igc_adapter {\n #define IGC_DEV_PRIVATE_HW(_dev) \\\n \t(&((struct igc_adapter *)(_dev)->data->dev_private)->hw)\n \n+#define IGC_DEV_PRIVATE_INTR(_dev) \\\n+\t(&((struct igc_adapter *)(_dev)->data->dev_private)->intr)\n+\n+static inline void\n+igc_read_reg_check_set_bits(struct igc_hw *hw, uint32_t reg, uint32_t bits)\n+{\n+\tuint32_t reg_val = IGC_READ_REG(hw, reg);\n+\n+\tbits |= reg_val;\n+\tif (bits == reg_val)\n+\t\treturn;\t/* no need to write back */\n+\n+\tIGC_WRITE_REG(hw, reg, bits);\n+}\n+\n+static inline void\n+igc_read_reg_check_clear_bits(struct igc_hw *hw, uint32_t reg, uint32_t bits)\n+{\n+\tuint32_t reg_val = IGC_READ_REG(hw, reg);\n+\n+\tbits = reg_val & ~bits;\n+\tif (bits == reg_val)\n+\t\treturn;\t/* no need to write back */\n+\n+\tIGC_WRITE_REG(hw, reg, bits);\n+}\n+\n #ifdef __cplusplus\n }\n #endif\n",
    "prefixes": [
        "v1",
        "04/15"
    ]
}