From 039b769f7c018351fbadf240f7dd692d3b02518f Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Thu, 25 Feb 2021 16:08:47 +0800 Subject: [PATCH] net/txgbe: support VF MAC address 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 --- doc/guides/nics/features/txgbe_vf.ini | 1 + drivers/net/txgbe/base/txgbe_vf.c | 102 ++++++++++++++++ drivers/net/txgbe/base/txgbe_vf.h | 5 + drivers/net/txgbe/txgbe_ethdev_vf.c | 168 ++++++++++++++++++++++++++ 4 files changed, 276 insertions(+) diff --git a/doc/guides/nics/features/txgbe_vf.ini b/doc/guides/nics/features/txgbe_vf.ini index 5035c5eeaf..97c881d96f 100644 --- a/doc/guides/nics/features/txgbe_vf.ini +++ b/doc/guides/nics/features/txgbe_vf.ini @@ -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 diff --git a/drivers/net/txgbe/base/txgbe_vf.c b/drivers/net/txgbe/base/txgbe_vf.c index 5d4e101586..fadecaa11b 100644 --- a/drivers/net/txgbe/base/txgbe_vf.c +++ b/drivers/net/txgbe/base/txgbe_vf.c @@ -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 diff --git a/drivers/net/txgbe/base/txgbe_vf.h b/drivers/net/txgbe/base/txgbe_vf.h index 70f90c2629..f8c6532f65 100644 --- a/drivers/net/txgbe/base/txgbe_vf.h +++ b/drivers/net/txgbe/base/txgbe_vf.h @@ -11,8 +11,13 @@ #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); diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c index 4fbb4f1540..86b1e2bfbd 100644 --- a/drivers/net/txgbe/txgbe_ethdev_vf.c +++ b/drivers/net/txgbe/txgbe_ethdev_vf.c @@ -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, ð_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); -- 2.20.1