net/txgbe: support VF MAC address
authorJiawen Wu <jiawenwu@trustnetic.com>
Thu, 25 Feb 2021 08:08:47 +0000 (16:08 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 26 Feb 2021 13:13:03 +0000 (14:13 +0100)
Generate a random MAC address if none was assigned by PF during
the initialization of VF device. And support to add and remove
MAC address.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
doc/guides/nics/features/txgbe_vf.ini
drivers/net/txgbe/base/txgbe_vf.c
drivers/net/txgbe/base/txgbe_vf.h
drivers/net/txgbe/txgbe_ethdev_vf.c

index 5035c5e..97c881d 100644 (file)
@@ -4,6 +4,7 @@
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Unicast MAC filter   = Y
 Multiprocess aware   = Y
 Linux                = Y
 ARMv8                = Y
index 5d4e101..fadecaa 100644 (file)
@@ -21,9 +21,16 @@ s32 txgbe_init_ops_vf(struct txgbe_hw *hw)
 
        /* MAC */
        mac->reset_hw = txgbe_reset_hw_vf;
+       mac->start_hw = txgbe_start_hw_vf;
+       /* Cannot clear stats on VF */
+       mac->get_mac_addr = txgbe_get_mac_addr_vf;
        mac->stop_hw = txgbe_stop_hw_vf;
        mac->negotiate_api_version = txgbevf_negotiate_api_version;
 
+       /* RAR, Multicast, VLAN */
+       mac->set_rar = txgbe_set_rar_vf;
+       mac->set_uc_addr = txgbevf_set_uc_addr_vf;
+
        mac->max_tx_queues = 1;
        mac->max_rx_queues = 1;
 
@@ -60,6 +67,23 @@ static void txgbe_virt_clr_reg(struct txgbe_hw *hw)
        txgbe_flush(hw);
 }
 
+/**
+ *  txgbe_start_hw_vf - Prepare hardware for Tx/Rx
+ *  @hw: pointer to hardware structure
+ *
+ *  Starts the hardware by filling the bus info structure and media type, clears
+ *  all on chip counters, initializes receive address registers, multicast
+ *  table, VLAN filter table, calls routine to set up link and flow control
+ *  settings, and leaves transmit and receive units disabled and uninitialized
+ **/
+s32 txgbe_start_hw_vf(struct txgbe_hw *hw)
+{
+       /* Clear adapter stopped flag */
+       hw->adapter_stopped = false;
+
+       return 0;
+}
+
 /**
  *  txgbe_reset_hw_vf - Performs hardware reset
  *  @hw: pointer to hardware structure
@@ -195,6 +219,84 @@ STATIC s32 txgbevf_write_msg_read_ack(struct txgbe_hw *hw, u32 *msg,
        return mbx->read_posted(hw, retmsg, size, 0);
 }
 
+/**
+ *  txgbe_set_rar_vf - set device MAC address
+ *  @hw: pointer to hardware structure
+ *  @index: Receive address register to write
+ *  @addr: Address to put into receive address register
+ *  @vmdq: VMDq "set" or "pool" index
+ *  @enable_addr: set flag that address is active
+ **/
+s32 txgbe_set_rar_vf(struct txgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
+                    u32 enable_addr)
+{
+       u32 msgbuf[3];
+       u8 *msg_addr = (u8 *)(&msgbuf[1]);
+       s32 ret_val;
+       UNREFERENCED_PARAMETER(vmdq, enable_addr, index);
+
+       memset(msgbuf, 0, 12);
+       msgbuf[0] = TXGBE_VF_SET_MAC_ADDR;
+       memcpy(msg_addr, addr, 6);
+       ret_val = txgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 3);
+
+       msgbuf[0] &= ~TXGBE_VT_MSGTYPE_CTS;
+
+       /* if nacked the address was rejected, use "perm_addr" */
+       if (!ret_val &&
+           (msgbuf[0] == (TXGBE_VF_SET_MAC_ADDR | TXGBE_VT_MSGTYPE_NACK))) {
+               txgbe_get_mac_addr_vf(hw, hw->mac.addr);
+               return TXGBE_ERR_MBX;
+       }
+
+       return ret_val;
+}
+
+/**
+ * txgbe_get_mac_addr_vf - Read device MAC address
+ * @hw: pointer to the HW structure
+ * @mac_addr: the MAC address
+ **/
+s32 txgbe_get_mac_addr_vf(struct txgbe_hw *hw, u8 *mac_addr)
+{
+       int i;
+
+       for (i = 0; i < ETH_ADDR_LEN; i++)
+               mac_addr[i] = hw->mac.perm_addr[i];
+
+       return 0;
+}
+
+s32 txgbevf_set_uc_addr_vf(struct txgbe_hw *hw, u32 index, u8 *addr)
+{
+       u32 msgbuf[3], msgbuf_chk;
+       u8 *msg_addr = (u8 *)(&msgbuf[1]);
+       s32 ret_val;
+
+       memset(msgbuf, 0, sizeof(msgbuf));
+       /*
+        * If index is one then this is the start of a new list and needs
+        * indication to the PF so it can do it's own list management.
+        * If it is zero then that tells the PF to just clear all of
+        * this VF's macvlans and there is no new list.
+        */
+       msgbuf[0] |= index << TXGBE_VT_MSGINFO_SHIFT;
+       msgbuf[0] |= TXGBE_VF_SET_MACVLAN;
+       msgbuf_chk = msgbuf[0];
+       if (addr)
+               memcpy(msg_addr, addr, 6);
+
+       ret_val = txgbevf_write_msg_read_ack(hw, msgbuf, msgbuf, 3);
+       if (!ret_val) {
+               msgbuf[0] &= ~TXGBE_VT_MSGTYPE_CTS;
+
+               if (msgbuf[0] == (msgbuf_chk | TXGBE_VT_MSGTYPE_NACK))
+                       return TXGBE_ERR_OUT_OF_MEM;
+       }
+
+       return ret_val;
+}
+
 /**
  *  txgbevf_negotiate_api_version - Negotiate supported API version
  *  @hw: pointer to the HW structure
index 70f90c2..f8c6532 100644 (file)
 #define TXGBE_VF_MAX_RX_QUEUES 8
 
 s32 txgbe_init_ops_vf(struct txgbe_hw *hw);
+s32 txgbe_start_hw_vf(struct txgbe_hw *hw);
 s32 txgbe_reset_hw_vf(struct txgbe_hw *hw);
 s32 txgbe_stop_hw_vf(struct txgbe_hw *hw);
+s32 txgbe_get_mac_addr_vf(struct txgbe_hw *hw, u8 *mac_addr);
+s32 txgbe_set_rar_vf(struct txgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
+                    u32 enable_addr);
+s32 txgbevf_set_uc_addr_vf(struct txgbe_hw *hw, u32 index, u8 *addr);
 int txgbevf_negotiate_api_version(struct txgbe_hw *hw, int api);
 int txgbevf_get_queues(struct txgbe_hw *hw, unsigned int *num_tcs,
                       unsigned int *default_tc);
index 4fbb4f1..86b1e2b 100644 (file)
@@ -18,6 +18,7 @@
 static int txgbevf_dev_close(struct rte_eth_dev *dev);
 static void txgbevf_intr_disable(struct rte_eth_dev *dev);
 static void txgbevf_intr_enable(struct rte_eth_dev *dev);
+static void txgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
 
 /*
  * The set of PCI devices this driver supports (for VF)
@@ -56,6 +57,22 @@ txgbevf_negotiate_api(struct txgbe_hw *hw)
        }
 }
 
+static void
+generate_random_mac_addr(struct rte_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] |= RTE_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
  */
@@ -66,6 +83,8 @@ eth_txgbevf_dev_init(struct rte_eth_dev *eth_dev)
        uint32_t tc, tcs;
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        struct txgbe_hw *hw = TXGBE_DEV_HW(eth_dev);
+       struct rte_ether_addr *perm_addr =
+                       (struct rte_ether_addr *)hw->mac.perm_addr;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -141,8 +160,53 @@ eth_txgbevf_dev_init(struct rte_eth_dev *eth_dev)
        /* Get Rx/Tx queue count via mailbox, which is ready after reset_hw */
        txgbevf_get_queues(hw, &tcs, &tc);
 
+       /* Allocate memory for storing MAC addresses */
+       eth_dev->data->mac_addrs = rte_zmalloc("txgbevf", RTE_ETHER_ADDR_LEN *
+                                              hw->mac.num_rar_entries, 0);
+       if (eth_dev->data->mac_addrs == NULL) {
+               PMD_INIT_LOG(ERR,
+                            "Failed to allocate %u bytes needed to store "
+                            "MAC addresses",
+                            RTE_ETHER_ADDR_LEN * hw->mac.num_rar_entries);
+               return -ENOMEM;
+       }
+
+       /* Generate a random MAC address, if none was assigned by PF. */
+       if (rte_is_zero_ether_addr(perm_addr)) {
+               generate_random_mac_addr(perm_addr);
+               err = txgbe_set_rar_vf(hw, 1, perm_addr->addr_bytes, 0, 1);
+               if (err) {
+                       rte_free(eth_dev->data->mac_addrs);
+                       eth_dev->data->mac_addrs = NULL;
+                       return err;
+               }
+               PMD_INIT_LOG(INFO, "\tVF MAC address not assigned by Host PF");
+               PMD_INIT_LOG(INFO, "\tAssign randomly generated MAC address "
+                            "%02x:%02x:%02x:%02x:%02x:%02x",
+                            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 */
+       rte_ether_addr_copy(perm_addr, &eth_dev->data->mac_addrs[0]);
+
+       /* reset the hardware with the new settings */
+       err = hw->mac.start_hw(hw);
+       if (err) {
+               PMD_INIT_LOG(ERR, "VF Initialization Failure: %d", err);
+               return -EIO;
+       }
+
        txgbevf_intr_enable(eth_dev);
 
+       PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x mac.type=%s",
+                    eth_dev->data->port_id, pci_dev->id.vendor_id,
+                    pci_dev->id.device_id, "txgbe_mac_raptor_vf");
+
        return 0;
 }
 
@@ -230,9 +294,110 @@ txgbevf_dev_close(struct rte_eth_dev *dev)
 
        txgbe_dev_free_queues(dev);
 
+       /**
+        * Remove the VF MAC address ro ensure
+        * that the VF traffic goes to the PF
+        * after stop, close and detach of the VF
+        **/
+       txgbevf_remove_mac_addr(dev, 0);
+
        /* Disable the interrupts for VF */
        txgbevf_intr_disable(dev);
 
+       rte_free(dev->data->mac_addrs);
+       dev->data->mac_addrs = NULL;
+
+       return 0;
+}
+
+static int
+txgbevf_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+                    __rte_unused uint32_t index,
+                    __rte_unused uint32_t pool)
+{
+       struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+       int err;
+
+       /*
+        * On a 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 rte_ether_addr)) == 0)
+               return -1;
+       err = txgbevf_set_uc_addr_vf(hw, 2, mac_addr->addr_bytes);
+       if (err != 0)
+               PMD_DRV_LOG(ERR, "Unable to add MAC address "
+                           "%02x:%02x:%02x:%02x:%02x:%02x - err=%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],
+                           err);
+       return err;
+}
+
+static void
+txgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
+{
+       struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+       struct rte_ether_addr *perm_addr =
+                       (struct rte_ether_addr *)hw->mac.perm_addr;
+       struct rte_ether_addr *mac_addr;
+       uint32_t i;
+       int err;
+
+       /*
+        * The TXGBE_VF_SET_MACVLAN command of the txgbe-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 addresses with the exception of the one to be deleted.
+        */
+       (void)txgbevf_set_uc_addr_vf(hw, 0, NULL);
+
+       /*
+        * 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;
+               /* Skip NULL MAC addresses */
+               if (rte_is_zero_ether_addr(mac_addr))
+                       continue;
+               /* Skip the permanent MAC address */
+               if (memcmp(perm_addr, mac_addr,
+                               sizeof(struct rte_ether_addr)) == 0)
+                       continue;
+               err = txgbevf_set_uc_addr_vf(hw, 2, mac_addr->addr_bytes);
+               if (err != 0)
+                       PMD_DRV_LOG(ERR,
+                                   "Adding again MAC address "
+                                   "%02x:%02x:%02x:%02x:%02x:%02x failed "
+                                   "err=%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],
+                                   err);
+       }
+}
+
+static int
+txgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+               struct rte_ether_addr *addr)
+{
+       struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+
+       hw->mac.set_rar(hw, 0, (void *)addr, 0, 0);
+
        return 0;
 }
 
@@ -241,6 +406,9 @@ txgbevf_dev_close(struct rte_eth_dev *dev)
  * operation have been implemented
  */
 static const struct eth_dev_ops txgbevf_eth_dev_ops = {
+       .mac_addr_add         = txgbevf_add_mac_addr,
+       .mac_addr_remove      = txgbevf_remove_mac_addr,
+       .mac_addr_set         = txgbevf_set_default_mac_addr,
 };
 
 RTE_PMD_REGISTER_PCI(net_txgbe_vf, rte_txgbevf_pmd);