ethdev: allow to set RSS hash computation flags and/or key
[dpdk.git] / lib / librte_pmd_ixgbe / ixgbe_ethdev.c
index 9291a8e..0b81f2b 100644 (file)
@@ -58,6 +58,7 @@
 #include <rte_ethdev.h>
 #include <rte_atomic.h>
 #include <rte_malloc.h>
+#include <rte_random.h>
 #include <rte_dev.h>
 
 #include "ixgbe_logs.h"
@@ -306,6 +307,7 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = {
        .bypass_ver_show      = ixgbe_bypass_ver_show,
        .bypass_wd_reset      = ixgbe_bypass_wd_reset,
 #endif /* RTE_NIC_BYPASS */
+       .rss_hash_update = ixgbe_dev_rss_hash_update,
 };
 
 /*
@@ -842,6 +844,22 @@ ixgbevf_negotiate_api(struct ixgbe_hw *hw)
                ;
 }
 
+static void
+generate_random_mac_addr(struct ether_addr *mac_addr)
+{
+       uint64_t random;
+
+       /* Set Organizationally Unique Identifier (OUI) prefix. */
+       mac_addr->addr_bytes[0] = 0x00;
+       mac_addr->addr_bytes[1] = 0x09;
+       mac_addr->addr_bytes[2] = 0xC0;
+       /* Force indication of locally assigned MAC address. */
+       mac_addr->addr_bytes[0] |= ETHER_LOCAL_ADMIN_ADDR;
+       /* Generate the last 3 bytes of the MAC address with a random number. */
+       random = rte_rand();
+       memcpy(&mac_addr->addr_bytes[3], &random, 3);
+}
+
 /*
  * Virtual Function device init
  */
@@ -858,6 +876,7 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
                IXGBE_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private);
        struct ixgbe_hwstrip *hwstrip = 
                IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(eth_dev->data->dev_private);
+       struct ether_addr *perm_addr = (struct ether_addr *) hw->mac.perm_addr;
 
        PMD_INIT_LOG(DEBUG, "eth_ixgbevf_dev_init");
 
@@ -902,13 +921,13 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        hw->mac.num_rar_entries = 128; /* The MAX of the underlying PF */
        diag = hw->mac.ops.reset_hw(hw);
 
-       if (diag != IXGBE_SUCCESS) {
+       /*
+        * The VF reset operation returns the IXGBE_ERR_INVALID_MAC_ADDR when
+        * the underlying PF driver has not assigned a MAC address to the VF.
+        * In this case, assign a random MAC address.
+        */
+       if ((diag != IXGBE_SUCCESS) && (diag != IXGBE_ERR_INVALID_MAC_ADDR)) {
                PMD_INIT_LOG(ERR, "VF Initialization Failure: %d", diag);
-                       RTE_LOG(ERR, PMD, "\tThe MAC address is not valid.\n"
-                                       "\tThe most likely cause of this error is that the VM host\n"
-                                       "\thas not assigned a valid MAC address to this VF device.\n"
-                                       "\tPlease consult the DPDK Release Notes (FAQ section) for\n"
-                                       "\ta possible solution to this problem.\n");
                return (diag);
        }
 
@@ -929,9 +948,29 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
                return -ENOMEM;
        }
 
+       /* Generate a random MAC address, if none was assigned by PF. */
+       if (is_zero_ether_addr(perm_addr)) {
+               generate_random_mac_addr(perm_addr);
+               diag = ixgbe_set_rar_vf(hw, 1, perm_addr->addr_bytes, 0, 1);
+               if (diag) {
+                       rte_free(eth_dev->data->mac_addrs);
+                       eth_dev->data->mac_addrs = NULL;
+                       return diag;
+               }
+               RTE_LOG(INFO, PMD,
+                       "\tVF MAC address not assigned by Host PF\n"
+                       "\tAssign randomly generated MAC address "
+                       "%02x:%02x:%02x:%02x:%02x:%02x\n",
+                       perm_addr->addr_bytes[0],
+                       perm_addr->addr_bytes[1],
+                       perm_addr->addr_bytes[2],
+                       perm_addr->addr_bytes[3],
+                       perm_addr->addr_bytes[4],
+                       perm_addr->addr_bytes[5]);
+       }
+
        /* Copy the permanent MAC address */
-       ether_addr_copy((struct ether_addr *) hw->mac.perm_addr,
-                       &eth_dev->data->mac_addrs[0]);
+       ether_addr_copy(perm_addr, &eth_dev->data->mac_addrs[0]);
 
        /* reset the hardware with the new settings */
        diag = hw->mac.ops.start_hw(hw);
@@ -3096,6 +3135,13 @@ ixgbevf_add_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        int diag;
 
+       /*
+        * On a 82599 VF, adding again the same MAC addr is not an idempotent
+        * operation. Trap this case to avoid exhausting the [very limited]
+        * set of PF resources used to store VF MAC addresses.
+        */
+       if (memcmp(hw->mac.perm_addr, mac_addr, sizeof(struct ether_addr)) == 0)
+               return;
        diag = ixgbevf_set_uc_addr_vf(hw, 2, mac_addr->addr_bytes);
        if (diag == 0)
                return;
@@ -3106,7 +3152,8 @@ static void
 ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 {
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct ether_addr *dev_mac_addrs;
+       struct ether_addr *perm_addr = (struct ether_addr *) hw->mac.perm_addr;
+       struct ether_addr *mac_addr;
        uint32_t i;
        int diag;
 
@@ -3114,20 +3161,37 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
         * The IXGBE_VF_SET_MACVLAN command of the ixgbe-pf driver does
         * not support the deletion of a given MAC address.
         * Instead, it imposes to delete all MAC addresses, then to add again
-        * all MAC address with the exception of the one to be deleted.
+        * all MAC addresses with the exception of the one to be deleted.
         */
        (void) ixgbevf_set_uc_addr_vf(hw, 0, NULL);
 
-       /* Add again all MAC addresses, excepted the deleted one. */
-       dev_mac_addrs = dev->data->mac_addrs;
-       for (i = 0; i < hw->mac.num_rar_entries; i++) {
+       /*
+        * Add again all MAC addresses, with the exception of the deleted one
+        * and of the permanent MAC address.
+        */
+       for (i = 0, mac_addr = dev->data->mac_addrs;
+            i < hw->mac.num_rar_entries; i++, mac_addr++) {
                /* Skip the deleted MAC address */
                if (i == index)
                        continue;
-               diag = ixgbevf_set_uc_addr_vf(hw, 2,
-                                             dev_mac_addrs[i].addr_bytes);
+               /* Skip NULL MAC addresses */
+               if (is_zero_ether_addr(mac_addr))
+                       continue;
+               /* Skip the permanent MAC address */
+               if (memcmp(perm_addr, mac_addr, sizeof(struct ether_addr)) == 0)
+                       continue;
+               diag = ixgbevf_set_uc_addr_vf(hw, 2, mac_addr->addr_bytes);
                if (diag != 0)
-                       PMD_DRV_LOG(ERR, "Adding MAC address failed diag=%d",
+                       PMD_DRV_LOG(ERR,
+                                   "Adding again MAC address "
+                                   "%02x:%02x:%02x:%02x:%02x:%02x failed "
+                                   "diag=%d",
+                                   mac_addr->addr_bytes[0],
+                                   mac_addr->addr_bytes[1],
+                                   mac_addr->addr_bytes[2],
+                                   mac_addr->addr_bytes[3],
+                                   mac_addr->addr_bytes[4],
+                                   mac_addr->addr_bytes[5],
                                    diag);
        }
 }