net/nfp: use link status helper functions
[dpdk.git] / drivers / net / nfp / nfp_net.c
index 9a7b0b2..8591c7d 100644 (file)
@@ -43,7 +43,7 @@
 #include <rte_common.h>
 #include <rte_log.h>
 #include <rte_debug.h>
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
 #include <rte_ethdev_pci.h>
 #include <rte_dev.h>
 #include <rte_ether.h>
@@ -95,6 +95,15 @@ static void nfp_net_stop(struct rte_eth_dev *dev);
 static uint16_t nfp_net_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                                  uint16_t nb_pkts);
 
+static int nfp_net_rss_config_default(struct rte_eth_dev *dev);
+static int nfp_net_rss_hash_update(struct rte_eth_dev *dev,
+                                  struct rte_eth_rss_conf *rss_conf);
+static int nfp_net_rss_reta_write(struct rte_eth_dev *dev,
+                   struct rte_eth_rss_reta_entry64 *reta_conf,
+                   uint16_t reta_size);
+static int nfp_net_rss_hash_write(struct rte_eth_dev *dev,
+                       struct rte_eth_rss_conf *rss_conf);
+
 /*
  * The offset of the queue controller queues in the PCIe Target. These
  * happen to be at the same offset on the NFP6000 and the NFP3200 so
@@ -204,57 +213,6 @@ nn_cfg_writeq(struct nfp_net_hw *hw, int off, uint64_t val)
        nn_writeq(rte_cpu_to_le_64(val), hw->ctrl_bar + off);
 }
 
-/*
- * Atomically reads link status information from global structure rte_eth_dev.
- *
- * @param dev
- *   - Pointer to the structure rte_eth_dev to read from.
- *   - Pointer to the buffer to be saved with the link status.
- *
- * @return
- *   - On success, zero.
- *   - On failure, negative value.
- */
-static inline int
-nfp_net_dev_atomic_read_link_status(struct rte_eth_dev *dev,
-                                   struct rte_eth_link *link)
-{
-       struct rte_eth_link *dst = link;
-       struct rte_eth_link *src = &dev->data->dev_link;
-
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                               *(uint64_t *)src) == 0)
-               return -1;
-
-       return 0;
-}
-
-/*
- * Atomically writes the link status information into global
- * structure rte_eth_dev.
- *
- * @param dev
- *   - Pointer to the structure rte_eth_dev to read from.
- *   - Pointer to the buffer to be saved with the link status.
- *
- * @return
- *   - On success, zero.
- *   - On failure, negative value.
- */
-static inline int
-nfp_net_dev_atomic_write_link_status(struct rte_eth_dev *dev,
-                                    struct rte_eth_link *link)
-{
-       struct rte_eth_link *dst = &dev->data->dev_link;
-       struct rte_eth_link *src = link;
-
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                               *(uint64_t *)src) == 0)
-               return -1;
-
-       return 0;
-}
-
 static void
 nfp_net_rx_queue_release_mbufs(struct nfp_net_rxq *rxq)
 {
@@ -489,12 +447,10 @@ nfp_net_configure(struct rte_eth_dev *dev)
        }
 
        if (rxmode->jumbo_frame)
-               /* this is handled in rte_eth_dev_configure */
+               hw->mtu = rxmode->max_rx_pkt_len;
 
-       if (rxmode->hw_strip_crc) {
-               PMD_INIT_LOG(INFO, "strip CRC not supported");
-               return -EINVAL;
-       }
+       if (!rxmode->hw_strip_crc)
+               PMD_INIT_LOG(INFO, "HW does strip CRC and it is not configurable");
 
        if (rxmode->enable_scatter) {
                PMD_INIT_LOG(INFO, "Scatter not supported");
@@ -737,6 +693,8 @@ nfp_net_start(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 rte_eth_conf *dev_conf;
+       struct rte_eth_rxmode *rxmode;
        uint32_t new_ctrl, update = 0;
        struct nfp_net_hw *hw;
        uint32_t intr_vector;
@@ -786,6 +744,19 @@ nfp_net_start(struct rte_eth_dev *dev)
 
        rte_intr_enable(intr_handle);
 
+       dev_conf = &dev->data->dev_conf;
+       rxmode = &dev_conf->rxmode;
+
+       /* Checking RX mode */
+       if (rxmode->mq_mode & ETH_MQ_RX_RSS) {
+               if (hw->cap & NFP_NET_CFG_CTRL_RSS) {
+                       if (!nfp_net_rss_config_default(dev))
+                               update |= NFP_NET_CFG_UPDATE_RSS;
+               } else {
+                       PMD_INIT_LOG(INFO, "RSS not supported");
+                       return -EINVAL;
+               }
+       }
        /* Enable device */
        new_ctrl = hw->ctrl | NFP_NET_CFG_CTRL_ENABLE;
 
@@ -977,8 +948,9 @@ static int
 nfp_net_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
 {
        struct nfp_net_hw *hw;
-       struct rte_eth_link link, old;
+       struct rte_eth_link link;
        uint32_t nn_link_status;
+       int ret;
 
        static const uint32_t ls_to_ethtool[] = {
                [NFP_NET_CFG_STS_LINK_RATE_UNSUPPORTED] = ETH_SPEED_NUM_NONE,
@@ -995,9 +967,6 @@ nfp_net_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
 
        hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       memset(&old, 0, sizeof(old));
-       nfp_net_dev_atomic_read_link_status(dev, &old);
-
        nn_link_status = nn_cfg_readl(hw, NFP_NET_CFG_STS);
 
        memset(&link, 0, sizeof(struct rte_eth_link));
@@ -1015,16 +984,14 @@ nfp_net_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
        else
                link.link_speed = ls_to_ethtool[nn_link_status];
 
-       if (old.link_status != link.link_status) {
-               nfp_net_dev_atomic_write_link_status(dev, &link);
+       ret = rte_eth_linkstatus_set(dev, &link);
+       if (ret == 0) {
                if (link.link_status)
                        PMD_DRV_LOG(INFO, "NIC Link is Up\n");
                else
                        PMD_DRV_LOG(INFO, "NIC Link is Down\n");
-               return 0;
        }
-
-       return -1;
+       return ret;
 }
 
 static int
@@ -1246,9 +1213,9 @@ nfp_net_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->reta_size = NFP_NET_CFG_RSS_ITBL_SZ;
        dev_info->hash_key_size = NFP_NET_CFG_RSS_KEY_SZ;
 
-       dev_info->speed_capa = ETH_SPEED_NUM_1G | ETH_LINK_SPEED_10G |
-                              ETH_SPEED_NUM_25G | ETH_SPEED_NUM_40G |
-                              ETH_SPEED_NUM_50G | ETH_LINK_SPEED_100G;
+       dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G |
+                              ETH_LINK_SPEED_25G | ETH_LINK_SPEED_40G |
+                              ETH_LINK_SPEED_50G | ETH_LINK_SPEED_100G;
 
        if (hw->cap & NFP_NET_CFG_CTRL_LSO)
                dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;
@@ -1354,8 +1321,7 @@ nfp_net_dev_link_status_print(struct rte_eth_dev *dev)
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_eth_link link;
 
-       memset(&link, 0, sizeof(link));
-       nfp_net_dev_atomic_read_link_status(dev, &link);
+       rte_eth_linkstatus_get(dev, &link);
        if (link.link_status)
                RTE_LOG(INFO, PMD, "Port %d: Link Up - speed %u Mbps - %s\n",
                        dev->data->port_id, link.link_speed,
@@ -1408,9 +1374,7 @@ nfp_net_dev_interrupt_handler(void *param)
 
        PMD_DRV_LOG(DEBUG, "We got a LSC interrupt!!!\n");
 
-       /* get the link status */
-       memset(&link, 0, sizeof(link));
-       nfp_net_dev_atomic_read_link_status(dev, &link);
+       rte_eth_linkstatus_get(dev, &link);
 
        nfp_net_link_update(dev, 0);
 
@@ -1450,7 +1414,7 @@ nfp_net_dev_interrupt_delayed_handler(void *param)
        struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 
        nfp_net_link_update(dev, 0);
-       _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL, NULL);
+       _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
 
        nfp_net_dev_link_status_print(dev);
 
@@ -1469,6 +1433,13 @@ nfp_net_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
        if ((mtu < ETHER_MIN_MTU) || ((uint32_t)mtu > hw->max_mtu))
                return -EINVAL;
 
+       /* mtu setting is forbidden if port is started */
+       if (dev->data->dev_started) {
+               PMD_DRV_LOG(ERR, "port %d must be stopped before configuration",
+                           dev->data->port_id);
+               return -EBUSY;
+       }
+
        /* switch to jumbo mode if needed */
        if ((uint32_t)mtu > ETHER_MAX_LEN)
                dev->data->dev_conf.rxmode.jumbo_frame = 1;
@@ -1990,16 +1961,16 @@ nfp_net_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
                        break;
                }
 
+               rxds = &rxq->rxds[rxq->rd_p];
+               if ((rxds->rxd.meta_len_dd & PCIE_DESC_RX_DD) == 0)
+                       break;
+
                /*
                 * Memory barrier to ensure that we won't do other
                 * reads before the DD bit.
                 */
                rte_rmb();
 
-               rxds = &rxq->rxds[rxq->rd_p];
-               if ((rxds->rxd.meta_len_dd & PCIE_DESC_RX_DD) == 0)
-                       break;
-
                /*
                 * We got a packet. Let's alloc a new mbuff for refilling the
                 * free descriptor ring as soon as possible
@@ -2060,6 +2031,8 @@ nfp_net_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
                mb->nb_segs = 1;
                mb->next = NULL;
 
+               mb->port = rxq->port_id;
+
                /* Checking the RSS flag */
                nfp_net_set_hash(rxq, rxds, mb);
 
@@ -2345,22 +2318,17 @@ nfp_net_vlan_offload_set(struct rte_eth_dev *dev, int mask)
        return ret;
 }
 
-/* Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device */
 static int
-nfp_net_reta_update(struct rte_eth_dev *dev,
+nfp_net_rss_reta_write(struct rte_eth_dev *dev,
                    struct rte_eth_rss_reta_entry64 *reta_conf,
                    uint16_t reta_size)
 {
        uint32_t reta, mask;
        int i, j;
        int idx, shift;
-       uint32_t update;
        struct nfp_net_hw *hw =
                NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       if (!(hw->ctrl & NFP_NET_CFG_CTRL_RSS))
-               return -EINVAL;
-
        if (reta_size != NFP_NET_CFG_RSS_ITBL_SZ) {
                RTE_LOG(ERR, PMD, "The size of hash lookup table configured "
                        "(%d) doesn't match the number hardware can supported "
@@ -2397,6 +2365,26 @@ nfp_net_reta_update(struct rte_eth_dev *dev,
                nn_cfg_writel(hw, NFP_NET_CFG_RSS_ITBL + (idx * 64) + shift,
                              reta);
        }
+       return 0;
+}
+
+/* Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device */
+static int
+nfp_net_reta_update(struct rte_eth_dev *dev,
+                   struct rte_eth_rss_reta_entry64 *reta_conf,
+                   uint16_t reta_size)
+{
+       struct nfp_net_hw *hw =
+               NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t update;
+       int ret;
+
+       if (!(hw->ctrl & NFP_NET_CFG_CTRL_RSS))
+               return -EINVAL;
+
+       ret = nfp_net_rss_reta_write(dev, reta_conf, reta_size);
+       if (ret != 0)
+               return ret;
 
        update = NFP_NET_CFG_UPDATE_RSS;
 
@@ -2455,33 +2443,24 @@ nfp_net_reta_query(struct rte_eth_dev *dev,
 }
 
 static int
-nfp_net_rss_hash_update(struct rte_eth_dev *dev,
+nfp_net_rss_hash_write(struct rte_eth_dev *dev,
                        struct rte_eth_rss_conf *rss_conf)
 {
-       uint32_t update;
+       struct nfp_net_hw *hw;
+       uint64_t rss_hf;
        uint32_t cfg_rss_ctrl = 0;
        uint8_t key;
-       uint64_t rss_hf;
        int i;
-       struct nfp_net_hw *hw;
 
        hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       rss_hf = rss_conf->rss_hf;
-
-       /* Checking if RSS is enabled */
-       if (!(hw->ctrl & NFP_NET_CFG_CTRL_RSS)) {
-               if (rss_hf != 0) { /* Enable RSS? */
-                       RTE_LOG(ERR, PMD, "RSS unsupported\n");
-                       return -EINVAL;
-               }
-               return 0; /* Nothing to do */
+       /* Writing the key byte a byte */
+       for (i = 0; i < rss_conf->rss_key_len; i++) {
+               memcpy(&key, &rss_conf->rss_key[i], 1);
+               nn_cfg_writeb(hw, NFP_NET_CFG_RSS_KEY + i, key);
        }
 
-       if (rss_conf->rss_key_len > NFP_NET_CFG_RSS_KEY_SZ) {
-               RTE_LOG(ERR, PMD, "hash key too long\n");
-               return -EINVAL;
-       }
+       rss_hf = rss_conf->rss_hf;
 
        if (rss_hf & ETH_RSS_IPV4)
                cfg_rss_ctrl |= NFP_NET_CFG_RSS_IPV4 |
@@ -2499,15 +2478,40 @@ nfp_net_rss_hash_update(struct rte_eth_dev *dev,
        /* configuring where to apply the RSS hash */
        nn_cfg_writel(hw, NFP_NET_CFG_RSS_CTRL, cfg_rss_ctrl);
 
-       /* Writing the key byte a byte */
-       for (i = 0; i < rss_conf->rss_key_len; i++) {
-               memcpy(&key, &rss_conf->rss_key[i], 1);
-               nn_cfg_writeb(hw, NFP_NET_CFG_RSS_KEY + i, key);
-       }
-
        /* Writing the key size */
        nn_cfg_writeb(hw, NFP_NET_CFG_RSS_KEY_SZ, rss_conf->rss_key_len);
 
+       return 0;
+}
+
+static int
+nfp_net_rss_hash_update(struct rte_eth_dev *dev,
+                       struct rte_eth_rss_conf *rss_conf)
+{
+       uint32_t update;
+       uint64_t rss_hf;
+       struct nfp_net_hw *hw;
+
+       hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       rss_hf = rss_conf->rss_hf;
+
+       /* Checking if RSS is enabled */
+       if (!(hw->ctrl & NFP_NET_CFG_CTRL_RSS)) {
+               if (rss_hf != 0) { /* Enable RSS? */
+                       RTE_LOG(ERR, PMD, "RSS unsupported\n");
+                       return -EINVAL;
+               }
+               return 0; /* Nothing to do */
+       }
+
+       if (rss_conf->rss_key_len > NFP_NET_CFG_RSS_KEY_SZ) {
+               RTE_LOG(ERR, PMD, "hash key too long\n");
+               return -EINVAL;
+       }
+
+       nfp_net_rss_hash_write(dev, rss_conf);
+
        update = NFP_NET_CFG_UPDATE_RSS;
 
        if (nfp_net_reconfig(hw, hw->ctrl, update) < 0)
@@ -2564,6 +2568,47 @@ nfp_net_rss_hash_conf_get(struct rte_eth_dev *dev,
        return 0;
 }
 
+static int
+nfp_net_rss_config_default(struct rte_eth_dev *dev)
+{
+       struct rte_eth_conf *dev_conf;
+       struct rte_eth_rss_conf rss_conf;
+       struct rte_eth_rss_reta_entry64 nfp_reta_conf[2];
+       uint16_t rx_queues = dev->data->nb_rx_queues;
+       uint16_t queue;
+       int i, j, ret;
+
+       RTE_LOG(INFO, PMD, "setting default RSS conf for %u queues\n",
+               rx_queues);
+
+       nfp_reta_conf[0].mask = ~0x0;
+       nfp_reta_conf[1].mask = ~0x0;
+
+       queue = 0;
+       for (i = 0; i < 0x40; i += 8) {
+               for (j = i; j < (i + 8); j++) {
+                       nfp_reta_conf[0].reta[j] = queue;
+                       nfp_reta_conf[1].reta[j] = queue++;
+                       queue %= rx_queues;
+               }
+       }
+       ret = nfp_net_rss_reta_write(dev, nfp_reta_conf, 0x80);
+       if (ret != 0)
+               return ret;
+
+       dev_conf = &dev->data->dev_conf;
+       if (!dev_conf) {
+               RTE_LOG(INFO, PMD, "wrong rss conf");
+               return -EINVAL;
+       }
+       rss_conf = dev_conf->rx_adv_conf.rss_conf;
+
+       ret = nfp_net_rss_hash_write(dev, &rss_conf);
+
+       return ret;
+}
+
+
 /* Initialise and register driver with DPDK Application */
 static const struct eth_dev_ops nfp_net_eth_dev_ops = {
        .dev_configure          = nfp_net_configure,
@@ -2984,6 +3029,9 @@ nfpu_error:
        return ret;
 }
 
+int nfp_logtype_init;
+int nfp_logtype_driver;
+
 static const struct rte_pci_id pci_id_nfp_pf_net_map[] = {
        {
                RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
@@ -3057,6 +3105,17 @@ RTE_PMD_REGISTER_PCI_TABLE(net_nfp_vf, pci_id_nfp_vf_net_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_nfp_pf, "* igb_uio | uio_pci_generic | vfio");
 RTE_PMD_REGISTER_KMOD_DEP(net_nfp_vf, "* igb_uio | uio_pci_generic | vfio");
 
+RTE_INIT(nfp_init_log);
+static void
+nfp_init_log(void)
+{
+       nfp_logtype_init = rte_log_register("pmd.net.nfp.init");
+       if (nfp_logtype_init >= 0)
+               rte_log_set_level(nfp_logtype_init, RTE_LOG_NOTICE);
+       nfp_logtype_driver = rte_log_register("pmd.net.nfp.driver");
+       if (nfp_logtype_driver >= 0)
+               rte_log_set_level(nfp_logtype_driver, RTE_LOG_NOTICE);
+}
 /*
  * Local variables:
  * c-file-style: "Linux"