net: provide IP-related API on any OS
[dpdk.git] / drivers / net / igc / igc_ethdev.c
index 15b63d1..31c99dc 100644 (file)
@@ -8,13 +8,15 @@
 #include <rte_string_fns.h>
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
-#include <rte_ethdev_driver.h>
-#include <rte_ethdev_pci.h>
+#include <ethdev_driver.h>
+#include <ethdev_pci.h>
 #include <rte_malloc.h>
 #include <rte_alarm.h>
 
 #include "igc_logs.h"
 #include "igc_txrx.h"
+#include "igc_filter.h"
+#include "igc_flow.h"
 
 #define IGC_INTEL_VENDOR_ID            0x8086
 
 /* External VLAN Enable bit mask */
 #define IGC_CTRL_EXT_EXT_VLAN          (1u << 26)
 
+/* Speed select */
+#define IGC_CTRL_SPEED_MASK            (7u << 8)
+#define IGC_CTRL_SPEED_2500            (6u << 8)
+
 /* External VLAN Ether Type bit mask and shift */
 #define IGC_VET_EXT                    0xFFFF0000
 #define IGC_VET_EXT_SHIFT              16
 
+/* Force EEE Auto-negotiation */
+#define IGC_EEER_EEE_FRC_AN            (1u << 28)
+
 /* Per Queue Good Packets Received Count */
 #define IGC_PQGPRC(idx)                (0x10010 + 0x100 * (idx))
 /* Per Queue Good Octets Received Count */
@@ -170,11 +179,11 @@ static const struct rte_igc_xstats_name_off rte_igc_stats_strings[] = {
 
 static int eth_igc_configure(struct rte_eth_dev *dev);
 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_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_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);
@@ -263,10 +272,6 @@ static const struct eth_dev_ops eth_igc_ops = {
 
        .rx_queue_setup         = eth_igc_rx_queue_setup,
        .rx_queue_release       = eth_igc_rx_queue_release,
-       .rx_queue_count         = eth_igc_rx_queue_count,
-       .rx_descriptor_done     = eth_igc_rx_descriptor_done,
-       .rx_descriptor_status   = eth_igc_rx_descriptor_status,
-       .tx_descriptor_status   = eth_igc_tx_descriptor_status,
        .tx_queue_setup         = eth_igc_tx_queue_setup,
        .tx_queue_release       = eth_igc_tx_queue_release,
        .tx_done_cleanup        = eth_igc_tx_done_cleanup,
@@ -292,6 +297,7 @@ static const struct eth_dev_ops eth_igc_ops = {
        .vlan_offload_set       = eth_igc_vlan_offload_set,
        .vlan_tpid_set          = eth_igc_vlan_tpid_set,
        .vlan_strip_queue_set   = eth_igc_vlan_strip_queue_set,
+       .flow_ops_get           = eth_igc_flow_ops_get,
 };
 
 /*
@@ -335,6 +341,9 @@ eth_igc_configure(struct rte_eth_dev *dev)
 
        PMD_INIT_FUNC_TRACE();
 
+       if (dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG)
+               dev->data->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_RSS_HASH;
+
        ret  = igc_check_mq_mode(dev);
        if (ret != 0)
                return ret;
@@ -534,8 +543,7 @@ eth_igc_interrupt_action(struct rte_eth_dev *dev)
                                pci_dev->addr.bus,
                                pci_dev->addr.devid,
                                pci_dev->addr.function);
-               _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
-                               NULL);
+               rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
        }
 }
 
@@ -602,7 +610,7 @@ eth_igc_rxtx_control(struct rte_eth_dev *dev, bool enable)
  *  This routine disables all traffic on the adapter by issuing a
  *  global reset on the MAC.
  */
-static void
+static int
 eth_igc_stop(struct rte_eth_dev *dev)
 {
        struct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);
@@ -611,6 +619,7 @@ eth_igc_stop(struct rte_eth_dev *dev)
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct rte_eth_link link;
 
+       dev->data->dev_started = 0;
        adapter->stopped = 1;
 
        /* disable receive and transmit */
@@ -635,6 +644,9 @@ eth_igc_stop(struct rte_eth_dev *dev)
        /* disable all wake up */
        IGC_WRITE_REG(hw, IGC_WUC, 0);
 
+       /* disable checking EEE operation in MAC loopback mode */
+       igc_read_reg_check_clear_bits(hw, IGC_EEER, IGC_EEER_EEE_FRC_AN);
+
        /* Set bit for Go Link disconnect */
        igc_read_reg_check_set_bits(hw, IGC_82580_PHY_POWER_MGMT,
                        IGC_82580_PM_GO_LINKD);
@@ -660,6 +672,8 @@ eth_igc_stop(struct rte_eth_dev *dev)
                rte_free(intr_handle->intr_vec);
                intr_handle->intr_vec = NULL;
        }
+
+       return 0;
 }
 
 /*
@@ -1060,6 +1074,19 @@ eth_igc_start(struct rte_eth_dev *dev)
        eth_igc_rxtx_control(dev, true);
        eth_igc_link_update(dev, 0);
 
+       /* configure MAC-loopback mode */
+       if (dev->data->dev_conf.lpbk_mode == 1) {
+               uint32_t reg_val;
+
+               reg_val = IGC_READ_REG(hw, IGC_CTRL);
+               reg_val &= ~IGC_CTRL_SPEED_MASK;
+               reg_val |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD |
+                       IGC_CTRL_FRCDPX | IGC_CTRL_FD | IGC_CTRL_SPEED_2500;
+               IGC_WRITE_REG(hw, IGC_CTRL, reg_val);
+
+               igc_read_reg_check_set_bits(hw, IGC_EEER, IGC_EEER_EEE_FRC_AN);
+       }
+
        return 0;
 
 error_invalid_config:
@@ -1144,7 +1171,7 @@ igc_dev_free_queues(struct rte_eth_dev *dev)
        dev->data->nb_tx_queues = 0;
 }
 
-static void
+static int
 eth_igc_close(struct rte_eth_dev *dev)
 {
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
@@ -1152,11 +1179,17 @@ eth_igc_close(struct rte_eth_dev *dev)
        struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
        struct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);
        int retry = 0;
+       int ret = 0;
 
        PMD_INIT_FUNC_TRACE();
+       if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+               return 0;
 
        if (!adapter->stopped)
-               eth_igc_stop(dev);
+               ret = eth_igc_stop(dev);
+
+       igc_flow_flush(dev, NULL);
+       igc_clear_all_filter(dev);
 
        igc_intr_other_disable(dev);
        do {
@@ -1175,6 +1208,8 @@ eth_igc_close(struct rte_eth_dev *dev)
 
        /* Reset any pending lock */
        igc_reset_swfw_lock(hw);
+
+       return ret;
 }
 
 static void
@@ -1198,6 +1233,10 @@ eth_igc_dev_init(struct rte_eth_dev *dev)
 
        PMD_INIT_FUNC_TRACE();
        dev->dev_ops = &eth_igc_ops;
+       dev->rx_descriptor_done = eth_igc_rx_descriptor_done;
+       dev->rx_queue_count = eth_igc_rx_queue_count;
+       dev->rx_descriptor_status = eth_igc_rx_descriptor_status;
+       dev->tx_descriptor_status = eth_igc_tx_descriptor_status;
 
        /*
         * for secondary processes, we don't initialize any further as primary
@@ -1208,6 +1247,7 @@ eth_igc_dev_init(struct rte_eth_dev *dev)
                return 0;
 
        rte_eth_copy_pci_info(dev, pci_dev);
+       dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
 
        hw->back = pci_dev;
        hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
@@ -1293,11 +1333,6 @@ eth_igc_dev_init(struct rte_eth_dev *dev)
                goto err_late;
        }
 
-       /* Pass the information to the rte_eth_dev_close() that it should also
-        * release the private port resources.
-        */
-       dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
-
        hw->mac.get_link_status = 1;
        igc->stopped = 0;
 
@@ -1325,6 +1360,8 @@ eth_igc_dev_init(struct rte_eth_dev *dev)
                igc->rxq_stats_map[i] = -1;
        }
 
+       igc_flow_init(dev);
+       igc_clear_all_filter(dev);
        return 0;
 
 err_late:
@@ -1336,10 +1373,6 @@ static int
 eth_igc_dev_uninit(__rte_unused struct rte_eth_dev *eth_dev)
 {
        PMD_INIT_FUNC_TRACE();
-
-       if (rte_eal_process_type() != RTE_PROC_PRIMARY)
-               return 0;
-
        eth_igc_close(eth_dev);
        return 0;
 }
@@ -1560,12 +1593,14 @@ eth_igc_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
                return -EINVAL;
 
        /*
-        * refuse mtu that requires the support of scattered packets when
-        * this feature has not been enabled before.
+        * If device is started, refuse mtu that requires the support of
+        * scattered packets when this feature has not been enabled before.
         */
-       if (!dev->data->scattered_rx &&
-           frame_size > dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM)
+       if (dev->data->dev_started && !dev->data->scattered_rx &&
+           frame_size > dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM) {
+               PMD_INIT_LOG(ERR, "Stop port first.");
                return -EINVAL;
+       }
 
        rctl = IGC_READ_REG(hw, IGC_RCTL);
 
@@ -1869,8 +1904,7 @@ eth_igc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
 
        /* Rx Errors */
        rte_stats->imissed = stats->mpc;
-       rte_stats->ierrors = stats->crcerrs +
-                       stats->rlec + stats->ruc + stats->roc +
+       rte_stats->ierrors = stats->crcerrs + stats->rlec +
                        stats->rxerrc + stats->algnerrc;
 
        /* Tx Errors */
@@ -2235,6 +2269,8 @@ eth_igc_rss_reta_update(struct rte_eth_dev *dev,
                return -EINVAL;
        }
 
+       RTE_BUILD_BUG_ON(ETH_RSS_RETA_SIZE_128 % IGC_RSS_RDT_REG_SIZE);
+
        /* set redirection table */
        for (i = 0; i < ETH_RSS_RETA_SIZE_128; i += IGC_RSS_RDT_REG_SIZE) {
                union igc_rss_reta_reg reta, reg;
@@ -2247,7 +2283,8 @@ eth_igc_rss_reta_update(struct rte_eth_dev *dev,
                                IGC_RSS_RDT_REG_SIZE_MASK);
 
                /* if no need to update the register */
-               if (!mask)
+               if (!mask ||
+                   shift > (RTE_RETA_GROUP_SIZE - IGC_RSS_RDT_REG_SIZE))
                        continue;
 
                /* check mask whether need to read the register value first */
@@ -2258,6 +2295,7 @@ eth_igc_rss_reta_update(struct rte_eth_dev *dev,
                                        IGC_RETA(i / IGC_RSS_RDT_REG_SIZE));
 
                /* update the register */
+               RTE_BUILD_BUG_ON(sizeof(reta.bytes) != IGC_RSS_RDT_REG_SIZE);
                for (j = 0; j < IGC_RSS_RDT_REG_SIZE; j++) {
                        if (mask & (1u << j))
                                reta.bytes[j] =
@@ -2287,6 +2325,8 @@ eth_igc_rss_reta_query(struct rte_eth_dev *dev,
                return -EINVAL;
        }
 
+       RTE_BUILD_BUG_ON(ETH_RSS_RETA_SIZE_128 % IGC_RSS_RDT_REG_SIZE);
+
        /* read redirection table */
        for (i = 0; i < ETH_RSS_RETA_SIZE_128; i += IGC_RSS_RDT_REG_SIZE) {
                union igc_rss_reta_reg reta;
@@ -2299,10 +2339,12 @@ eth_igc_rss_reta_query(struct rte_eth_dev *dev,
                                IGC_RSS_RDT_REG_SIZE_MASK);
 
                /* if no need to read register */
-               if (!mask)
+               if (!mask ||
+                   shift > (RTE_RETA_GROUP_SIZE - IGC_RSS_RDT_REG_SIZE))
                        continue;
 
                /* read register and get the queue index */
+               RTE_BUILD_BUG_ON(sizeof(reta.bytes) != IGC_RSS_RDT_REG_SIZE);
                reta.dword = IGC_READ_REG_LE_VALUE(hw,
                                IGC_RETA(i / IGC_RSS_RDT_REG_SIZE));
                for (j = 0; j < IGC_RSS_RDT_REG_SIZE; j++) {