fm10k: add vector Tx
[dpdk.git] / drivers / net / fm10k / fm10k_ethdev.c
index 76c050a..247edd5 100644 (file)
@@ -67,6 +67,7 @@ static void fm10k_MAC_filter_set(struct rte_eth_dev *dev,
        const u8 *mac, bool add, uint32_t pool);
 static void fm10k_tx_queue_release(void *queue);
 static void fm10k_rx_queue_release(void *queue);
+static void fm10k_set_rx_function(struct rte_eth_dev *dev);
 
 static void
 fm10k_mbx_initlock(struct fm10k_hw *hw)
@@ -121,6 +122,9 @@ rx_queue_reset(struct fm10k_rx_queue *q)
        q->next_alloc = 0;
        q->next_trigger = q->alloc_thresh - 1;
        FM10K_PCI_REG_WRITE(q->tail_ptr, q->nb_desc - 1);
+       q->rxrearm_start = 0;
+       q->rxrearm_nb = 0;
+
        return 0;
 }
 
@@ -139,6 +143,12 @@ rx_queue_clean(struct fm10k_rx_queue *q)
        for (i = 0; i < q->nb_desc; ++i)
                q->hw_ring[i] = zero;
 
+       /* vPMD driver has a different way of releasing mbufs. */
+       if (q->rx_using_sse) {
+               fm10k_rx_queue_release_mbufs_vec(q);
+               return;
+       }
+
        /* free software buffers */
        for (i = 0; i < q->nb_desc; ++i) {
                if (q->sw_ring[i]) {
@@ -337,8 +347,41 @@ fm10k_dev_configure(struct rte_eth_dev *dev)
        return 0;
 }
 
+/* fls = find last set bit = 32 minus the number of leading zeros */
+#ifndef fls
+#define fls(x) (((x) == 0) ? 0 : (32 - __builtin_clz((x))))
+#endif
+
 static void
-fm10k_dev_mq_rx_configure(struct rte_eth_dev *dev)
+fm10k_dev_vmdq_rx_configure(struct rte_eth_dev *dev)
+{
+       struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_eth_vmdq_rx_conf *vmdq_conf;
+       uint32_t i;
+
+       vmdq_conf = &dev->data->dev_conf.rx_adv_conf.vmdq_rx_conf;
+
+       for (i = 0; i < vmdq_conf->nb_pool_maps; i++) {
+               if (!vmdq_conf->pool_map[i].pools)
+                       continue;
+               fm10k_mbx_lock(hw);
+               fm10k_update_vlan(hw, vmdq_conf->pool_map[i].vlan_id, 0, true);
+               fm10k_mbx_unlock(hw);
+       }
+}
+
+static void
+fm10k_dev_pf_main_vsi_reset(struct rte_eth_dev *dev)
+{
+       struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /* Add default mac address */
+       fm10k_MAC_filter_set(dev, hw->mac.addr, true,
+               MAIN_VSI_POOL_NUMBER);
+}
+
+static void
+fm10k_dev_rss_configure(struct rte_eth_dev *dev)
 {
        struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
@@ -409,6 +452,78 @@ fm10k_dev_mq_rx_configure(struct rte_eth_dev *dev)
        FM10K_WRITE_REG(hw, FM10K_MRQC(0), mrqc);
 }
 
+static void
+fm10k_dev_logic_port_update(struct rte_eth_dev *dev,
+       uint16_t nb_lport_old, uint16_t nb_lport_new)
+{
+       struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t i;
+
+       fm10k_mbx_lock(hw);
+       /* Disable previous logic ports */
+       if (nb_lport_old)
+               hw->mac.ops.update_lport_state(hw, hw->mac.dglort_map,
+                       nb_lport_old, false);
+       /* Enable new logic ports */
+       hw->mac.ops.update_lport_state(hw, hw->mac.dglort_map,
+               nb_lport_new, true);
+       fm10k_mbx_unlock(hw);
+
+       for (i = 0; i < nb_lport_new; i++) {
+               /* Set unicast mode by default. App can change
+                * to other mode in other API func.
+                */
+               fm10k_mbx_lock(hw);
+               hw->mac.ops.update_xcast_mode(hw, hw->mac.dglort_map + i,
+                       FM10K_XCAST_MODE_NONE);
+               fm10k_mbx_unlock(hw);
+       }
+}
+
+static void
+fm10k_dev_mq_rx_configure(struct rte_eth_dev *dev)
+{
+       struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_eth_vmdq_rx_conf *vmdq_conf;
+       struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+       struct fm10k_macvlan_filter_info *macvlan;
+       uint16_t nb_queue_pools = 0; /* pool number in configuration */
+       uint16_t nb_lport_new, nb_lport_old;
+
+       macvlan = FM10K_DEV_PRIVATE_TO_MACVLAN(dev->data->dev_private);
+       vmdq_conf = &dev->data->dev_conf.rx_adv_conf.vmdq_rx_conf;
+
+       fm10k_dev_rss_configure(dev);
+
+       /* only PF supports VMDQ */
+       if (hw->mac.type != fm10k_mac_pf)
+               return;
+
+       if (dev_conf->rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
+               nb_queue_pools = vmdq_conf->nb_queue_pools;
+
+       /* no pool number change, no need to update logic port and VLAN/MAC */
+       if (macvlan->nb_queue_pools == nb_queue_pools)
+               return;
+
+       nb_lport_old = macvlan->nb_queue_pools ? macvlan->nb_queue_pools : 1;
+       nb_lport_new = nb_queue_pools ? nb_queue_pools : 1;
+       fm10k_dev_logic_port_update(dev, nb_lport_old, nb_lport_new);
+
+       /* reset MAC/VLAN as it's based on VMDQ or PF main VSI */
+       memset(dev->data->mac_addrs, 0,
+               ETHER_ADDR_LEN * FM10K_MAX_MACADDR_NUM);
+       ether_addr_copy((const struct ether_addr *)hw->mac.addr,
+               &dev->data->mac_addrs[0]);
+       memset(macvlan, 0, sizeof(*macvlan));
+       macvlan->nb_queue_pools = nb_queue_pools;
+
+       if (nb_queue_pools)
+               fm10k_dev_vmdq_rx_configure(dev);
+       else
+               fm10k_dev_pf_main_vsi_reset(dev);
+}
+
 static int
 fm10k_dev_tx_init(struct rte_eth_dev *dev)
 {
@@ -503,7 +618,6 @@ fm10k_dev_rx_init(struct rte_eth_dev *dev)
                        dev->data->dev_conf.rxmode.enable_scatter) {
                        uint32_t reg;
                        dev->data->scattered_rx = 1;
-                       dev->rx_pkt_burst = fm10k_recv_scattered_pkts;
                        reg = FM10K_READ_REG(hw, FM10K_SRRCTL(i));
                        reg |= FM10K_SRRCTL_BUFFER_CHAINING_EN;
                        FM10K_WRITE_REG(hw, FM10K_SRRCTL(i), reg);
@@ -517,8 +631,12 @@ fm10k_dev_rx_init(struct rte_eth_dev *dev)
                FM10K_WRITE_FLUSH(hw);
        }
 
-       /* Configure RSS if applicable */
+       /* Configure VMDQ/RSS if applicable */
        fm10k_dev_mq_rx_configure(dev);
+
+       /* Decide the best RX function */
+       fm10k_set_rx_function(dev);
+
        return 0;
 }
 
@@ -747,10 +865,32 @@ fm10k_dev_allmulticast_disable(struct rte_eth_dev *dev)
                PMD_INIT_LOG(ERR, "Failed to disable allmulticast mode");
 }
 
-/* fls = find last set bit = 32 minus the number of leading zeros */
-#ifndef fls
-#define fls(x) (((x) == 0) ? 0 : (32 - __builtin_clz((x))))
-#endif
+static void
+fm10k_dev_dglort_map_configure(struct rte_eth_dev *dev)
+{
+       struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t dglortdec, pool_len, rss_len, i;
+       uint16_t nb_queue_pools;
+       struct fm10k_macvlan_filter_info *macvlan;
+
+       macvlan = FM10K_DEV_PRIVATE_TO_MACVLAN(dev->data->dev_private);
+       nb_queue_pools = macvlan->nb_queue_pools;
+       pool_len = nb_queue_pools ? fls(nb_queue_pools - 1) : 0;
+       rss_len = fls(dev->data->nb_rx_queues - 1) - pool_len;
+       dglortdec = (rss_len << FM10K_DGLORTDEC_RSSLENGTH_SHIFT) | pool_len;
+
+       /* Establish only MAP 0 as valid */
+       FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(0), FM10K_DGLORTMAP_ANY);
+
+       /* Configure VMDQ/RSS DGlort Decoder */
+       FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(0), dglortdec);
+
+       /* Invalidate all other GLORT entries */
+       for (i = 1; i < FM10K_DGLORT_COUNT; i++)
+               FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(i),
+                               FM10K_DGLORTMAP_NONE);
+}
+
 #define BSIZEPKT_ROUNDUP ((1 << FM10K_SRRCTL_BSIZEPKT_SHIFT) - 1)
 static int
 fm10k_dev_start(struct rte_eth_dev *dev)
@@ -791,20 +931,8 @@ fm10k_dev_start(struct rte_eth_dev *dev)
                return diag;
        }
 
-       if (hw->mac.type == fm10k_mac_pf) {
-               /* Establish only VSI 0 as valid */
-               FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(0), FM10K_DGLORTMAP_ANY);
-
-               /* Configure RSS bits used in RETA table */
-               FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(0),
-                               fls(dev->data->nb_rx_queues - 1) <<
-                               FM10K_DGLORTDEC_RSSLENGTH_SHIFT);
-
-               /* Invalidate all other GLORT entries */
-               for (i = 1; i < FM10K_DGLORT_COUNT; i++)
-                       FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(i),
-                                       FM10K_DGLORTMAP_NONE);
-       }
+       if (hw->mac.type == fm10k_mac_pf)
+               fm10k_dev_dglort_map_configure(dev);
 
        for (i = 0; i < dev->data->nb_rx_queues; i++) {
                struct fm10k_rx_queue *rxq;
@@ -838,8 +966,8 @@ fm10k_dev_start(struct rte_eth_dev *dev)
                }
        }
 
-       /* Update default vlan */
-       if (hw->mac.default_vid && hw->mac.default_vid <= ETHER_MAX_VLAN_ID)
+       /* Update default vlan when not in VMDQ mode */
+       if (!(dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG))
                fm10k_vlan_filter_set(dev, hw->mac.default_vid, true);
 
        return 0;
@@ -978,7 +1106,10 @@ fm10k_dev_infos_get(struct rte_eth_dev *dev,
        dev_info->max_mac_addrs      = FM10K_MAX_MACADDR_NUM;
        dev_info->max_hash_mac_addrs = 0;
        dev_info->max_vfs            = dev->pci_dev->max_vfs;
-       dev_info->max_vmdq_pools     = ETH_64_POOLS;
+       dev_info->vmdq_pool_base     = 0;
+       dev_info->vmdq_queue_base    = 0;
+       dev_info->max_vmdq_pools     = ETH_32_POOLS;
+       dev_info->vmdq_queue_num     = FM10K_MAX_QUEUES_PF;
        dev_info->rx_offload_capa =
                DEV_RX_OFFLOAD_VLAN_STRIP |
                DEV_RX_OFFLOAD_IPV4_CKSUM |
@@ -1016,6 +1147,17 @@ fm10k_dev_infos_get(struct rte_eth_dev *dev,
                                ETH_TXQ_FLAGS_NOOFFLOADS,
        };
 
+       dev_info->rx_desc_lim = (struct rte_eth_desc_lim) {
+               .nb_max = FM10K_MAX_RX_DESC,
+               .nb_min = FM10K_MIN_RX_DESC,
+               .nb_align = FM10K_MULT_RX_DESC,
+       };
+
+       dev_info->tx_desc_lim = (struct rte_eth_desc_lim) {
+               .nb_max = FM10K_MAX_TX_DESC,
+               .nb_min = FM10K_MIN_TX_DESC,
+               .nb_align = FM10K_MULT_TX_DESC,
+       };
 }
 
 static int
@@ -1337,6 +1479,7 @@ fm10k_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id,
        const struct rte_eth_rxconf *conf, struct rte_mempool *mp)
 {
        struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct fm10k_dev_info *dev_info = FM10K_DEV_PRIVATE_TO_INFO(dev);
        struct fm10k_rx_queue *q;
        const struct rte_memzone *mz;
 
@@ -1419,6 +1562,16 @@ fm10k_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id,
        q->hw_ring_phys_addr = mz->phys_addr;
 #endif
 
+       /* Check if number of descs satisfied Vector requirement */
+       if (!rte_is_power_of_2(nb_desc)) {
+               PMD_INIT_LOG(DEBUG, "queue[%d] doesn't meet Vector Rx "
+                                   "preconditions - canceling the feature for "
+                                   "the whole port[%d]",
+                            q->queue_id, q->port_id);
+               dev_info->rx_vec_allowed = false;
+       } else
+               fm10k_rxq_vec_setup(q);
+
        dev->data->rx_queues[queue_id] = q;
        return 0;
 }
@@ -2141,6 +2294,55 @@ static const struct eth_dev_ops fm10k_eth_dev_ops = {
        .rss_hash_conf_get      = fm10k_rss_hash_conf_get,
 };
 
+static void __attribute__((cold))
+fm10k_set_rx_function(struct rte_eth_dev *dev)
+{
+       struct fm10k_dev_info *dev_info = FM10K_DEV_PRIVATE_TO_INFO(dev);
+       uint16_t i, rx_using_sse;
+
+       /* In order to allow Vector Rx there are a few configuration
+        * conditions to be met.
+        */
+       if (!fm10k_rx_vec_condition_check(dev) && dev_info->rx_vec_allowed) {
+               if (dev->data->scattered_rx)
+                       dev->rx_pkt_burst = fm10k_recv_scattered_pkts_vec;
+               else
+                       dev->rx_pkt_burst = fm10k_recv_pkts_vec;
+       } else if (dev->data->scattered_rx)
+               dev->rx_pkt_burst = fm10k_recv_scattered_pkts;
+
+       rx_using_sse =
+               (dev->rx_pkt_burst == fm10k_recv_scattered_pkts_vec ||
+               dev->rx_pkt_burst == fm10k_recv_pkts_vec);
+
+       for (i = 0; i < dev->data->nb_rx_queues; i++) {
+               struct fm10k_rx_queue *rxq = dev->data->rx_queues[i];
+
+               rxq->rx_using_sse = rx_using_sse;
+       }
+}
+
+static void
+fm10k_params_init(struct rte_eth_dev *dev)
+{
+       struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct fm10k_dev_info *info = FM10K_DEV_PRIVATE_TO_INFO(dev);
+
+       /* Inialize bus info. Normally we would call fm10k_get_bus_info(), but
+        * there is no way to get link status without reading BAR4.  Until this
+        * works, assume we have maximum bandwidth.
+        * @todo - fix bus info
+        */
+       hw->bus_caps.speed = fm10k_bus_speed_8000;
+       hw->bus_caps.width = fm10k_bus_width_pcie_x8;
+       hw->bus_caps.payload = fm10k_bus_payload_512;
+       hw->bus.speed = fm10k_bus_speed_8000;
+       hw->bus.width = fm10k_bus_width_pcie_x8;
+       hw->bus.payload = fm10k_bus_payload_256;
+
+       info->rx_vec_allowed = true;
+}
+
 static int
 eth_fm10k_dev_init(struct rte_eth_dev *dev)
 {
@@ -2154,9 +2356,6 @@ eth_fm10k_dev_init(struct rte_eth_dev *dev)
        dev->rx_pkt_burst = &fm10k_recv_pkts;
        dev->tx_pkt_burst = &fm10k_xmit_pkts;
 
-       if (dev->data->scattered_rx)
-               dev->rx_pkt_burst = &fm10k_recv_scattered_pkts;
-
        /* only initialize in the primary process */
        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
                return 0;
@@ -2187,18 +2386,8 @@ eth_fm10k_dev_init(struct rte_eth_dev *dev)
                return -EIO;
        }
 
-       /*
-        * Inialize bus info. Normally we would call fm10k_get_bus_info(), but
-        * there is no way to get link status without reading BAR4.  Until this
-        * works, assume we have maximum bandwidth.
-        * @todo - fix bus info
-        */
-       hw->bus_caps.speed = fm10k_bus_speed_8000;
-       hw->bus_caps.width = fm10k_bus_width_pcie_x8;
-       hw->bus_caps.payload = fm10k_bus_payload_512;
-       hw->bus.speed = fm10k_bus_speed_8000;
-       hw->bus.width = fm10k_bus_width_pcie_x8;
-       hw->bus.payload = fm10k_bus_payload_256;
+       /* Initialize parameters */
+       fm10k_params_init(dev);
 
        /* Initialize the hw */
        diag = fm10k_init_hw(hw);