net/axgbe: support unicast hash table for MAC address
[dpdk.git] / drivers / net / axgbe / axgbe_ethdev.c
index 750a768..9e2e8cb 100644 (file)
@@ -7,6 +7,7 @@
 #include "axgbe_ethdev.h"
 #include "axgbe_common.h"
 #include "axgbe_phy.h"
+#include "axgbe_regs.h"
 
 static int eth_axgbe_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_axgbe_dev_uninit(struct rte_eth_dev *eth_dev);
@@ -19,8 +20,25 @@ static int axgbe_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static int axgbe_dev_promiscuous_disable(struct rte_eth_dev *dev);
 static int axgbe_dev_allmulticast_enable(struct rte_eth_dev *dev);
 static int axgbe_dev_allmulticast_disable(struct rte_eth_dev *dev);
+static int axgbe_dev_mac_addr_set(struct rte_eth_dev *dev,
+                                 struct rte_ether_addr *mac_addr);
+static int axgbe_dev_mac_addr_add(struct rte_eth_dev *dev,
+                                 struct rte_ether_addr *mac_addr,
+                                 uint32_t index,
+                                 uint32_t vmdq);
+static void axgbe_dev_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index);
+static int axgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
+                                     struct rte_ether_addr *mc_addr_set,
+                                     uint32_t nb_mc_addr);
+static int axgbe_dev_uc_hash_table_set(struct rte_eth_dev *dev,
+                                      struct rte_ether_addr *mac_addr,
+                                      uint8_t add);
+static int axgbe_dev_uc_all_hash_table_set(struct rte_eth_dev *dev,
+                                          uint8_t add);
 static int axgbe_dev_link_update(struct rte_eth_dev *dev,
                                 int wait_to_complete);
+static int axgbe_dev_get_regs(struct rte_eth_dev *dev,
+                             struct rte_dev_reg_info *regs);
 static int axgbe_dev_stats_get(struct rte_eth_dev *dev,
                                struct rte_eth_stats *stats);
 static int axgbe_dev_stats_reset(struct rte_eth_dev *dev);
@@ -99,6 +117,7 @@ static const struct axgbe_xstats axgbe_xstats_strings[] = {
 
 /* The set of PCI devices this driver supports */
 #define AMD_PCI_VENDOR_ID       0x1022
+#define AMD_PCI_RV_ROOT_COMPLEX_ID     0x15d0
 #define AMD_PCI_AXGBE_DEVICE_V2A 0x1458
 #define AMD_PCI_AXGBE_DEVICE_V2B 0x1459
 
@@ -156,7 +175,14 @@ static const struct eth_dev_ops axgbe_eth_dev_ops = {
        .promiscuous_disable  = axgbe_dev_promiscuous_disable,
        .allmulticast_enable  = axgbe_dev_allmulticast_enable,
        .allmulticast_disable = axgbe_dev_allmulticast_disable,
+       .mac_addr_set         = axgbe_dev_mac_addr_set,
+       .mac_addr_add         = axgbe_dev_mac_addr_add,
+       .mac_addr_remove      = axgbe_dev_mac_addr_remove,
+       .set_mc_addr_list     = axgbe_dev_set_mc_addr_list,
+       .uc_hash_table_set    = axgbe_dev_uc_hash_table_set,
+       .uc_all_hash_table_set = axgbe_dev_uc_all_hash_table_set,
        .link_update          = axgbe_dev_link_update,
+       .get_reg              = axgbe_dev_get_regs,
        .stats_get            = axgbe_dev_stats_get,
        .stats_reset          = axgbe_dev_stats_reset,
        .xstats_get           = axgbe_dev_xstats_get,
@@ -200,12 +226,14 @@ axgbe_dev_interrupt_handler(void *param)
        pdata->phy_if.an_isr(pdata);
        /*DMA related interrupts*/
        dma_isr = AXGMAC_IOREAD(pdata, DMA_ISR);
+       PMD_DRV_LOG(DEBUG, "DMA_ISR=%#010x\n", dma_isr);
        if (dma_isr) {
                if (dma_isr & 1) {
                        dma_ch_isr =
                                AXGMAC_DMA_IOREAD((struct axgbe_rx_queue *)
                                                  pdata->rx_queues[0],
                                                  DMA_CH_SR);
+                       PMD_DRV_LOG(DEBUG, "DMA_CH0_ISR=%#010x\n", dma_ch_isr);
                        AXGMAC_DMA_IOWRITE((struct axgbe_rx_queue *)
                                           pdata->rx_queues[0],
                                           DMA_CH_SR, dma_ch_isr);
@@ -248,6 +276,10 @@ axgbe_dev_start(struct rte_eth_dev *dev)
 {
        struct axgbe_port *pdata = dev->data->dev_private;
        int ret;
+       struct rte_eth_dev_data *dev_data = dev->data;
+       uint16_t max_pkt_len = dev_data->dev_conf.rxmode.max_rx_pkt_len;
+
+       dev->dev_ops = &axgbe_eth_dev_ops;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -278,6 +310,16 @@ axgbe_dev_start(struct rte_eth_dev *dev)
 
        axgbe_clear_bit(AXGBE_STOPPED, &pdata->dev_state);
        axgbe_clear_bit(AXGBE_DOWN, &pdata->dev_state);
+       if ((dev_data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_SCATTER) ||
+                               max_pkt_len > pdata->rx_buf_size)
+               dev_data->scattered_rx = 1;
+
+       /*  Scatter Rx handling */
+       if (dev_data->scattered_rx)
+               dev->rx_pkt_burst = &eth_axgbe_recv_scattered_pkts;
+       else
+               dev->rx_pkt_burst = &axgbe_recv_pkts;
+
        return 0;
 }
 
@@ -363,6 +405,133 @@ axgbe_dev_allmulticast_disable(struct rte_eth_dev *dev)
        return 0;
 }
 
+static int
+axgbe_dev_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
+{
+       struct axgbe_port *pdata = dev->data->dev_private;
+
+       /* Set Default MAC Addr */
+       axgbe_set_mac_addn_addr(pdata, (u8 *)mac_addr, 0);
+
+       return 0;
+}
+
+static int
+axgbe_dev_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+                             uint32_t index, uint32_t pool __rte_unused)
+{
+       struct axgbe_port *pdata = dev->data->dev_private;
+       struct axgbe_hw_features *hw_feat = &pdata->hw_feat;
+
+       if (index > hw_feat->addn_mac) {
+               PMD_DRV_LOG(ERR, "Invalid Index %d\n", index);
+               return -EINVAL;
+       }
+       axgbe_set_mac_addn_addr(pdata, (u8 *)mac_addr, index);
+       return 0;
+}
+
+static void
+axgbe_dev_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+       struct axgbe_port *pdata = dev->data->dev_private;
+       struct axgbe_hw_features *hw_feat = &pdata->hw_feat;
+
+       if (index > hw_feat->addn_mac) {
+               PMD_DRV_LOG(ERR, "Invalid Index %d\n", index);
+               return;
+       }
+       axgbe_set_mac_addn_addr(pdata, NULL, index);
+}
+
+static int
+axgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
+                                     struct rte_ether_addr *mc_addr_set,
+                                     uint32_t nb_mc_addr)
+{
+       struct axgbe_port *pdata = dev->data->dev_private;
+       struct axgbe_hw_features *hw_feat = &pdata->hw_feat;
+       uint32_t index = 1; /* 0 is always default mac */
+       uint32_t i;
+
+       if (nb_mc_addr > hw_feat->addn_mac) {
+               PMD_DRV_LOG(ERR, "Invalid Index %d\n", nb_mc_addr);
+               return -EINVAL;
+       }
+
+       /* clear unicast addresses */
+       for (i = 1; i < hw_feat->addn_mac; i++) {
+               if (rte_is_zero_ether_addr(&dev->data->mac_addrs[i]))
+                       continue;
+               memset(&dev->data->mac_addrs[i], 0,
+                      sizeof(struct rte_ether_addr));
+       }
+
+       while (nb_mc_addr--)
+               axgbe_set_mac_addn_addr(pdata, (u8 *)mc_addr_set++, index++);
+
+       return 0;
+}
+
+static int
+axgbe_dev_uc_hash_table_set(struct rte_eth_dev *dev,
+                           struct rte_ether_addr *mac_addr, uint8_t add)
+{
+       struct axgbe_port *pdata = dev->data->dev_private;
+       struct axgbe_hw_features *hw_feat = &pdata->hw_feat;
+
+       if (!hw_feat->hash_table_size) {
+               PMD_DRV_LOG(ERR, "MAC Hash Table not supported\n");
+               return -ENOTSUP;
+       }
+
+       axgbe_set_mac_hash_table(pdata, (u8 *)mac_addr, add);
+
+       if (pdata->uc_hash_mac_addr > 0) {
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1);
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 1);
+       } else {
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 0);
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 0);
+       }
+       return 0;
+}
+
+static int
+axgbe_dev_uc_all_hash_table_set(struct rte_eth_dev *dev, uint8_t add)
+{
+       struct axgbe_port *pdata = dev->data->dev_private;
+       struct axgbe_hw_features *hw_feat = &pdata->hw_feat;
+       uint32_t index;
+
+       if (!hw_feat->hash_table_size) {
+               PMD_DRV_LOG(ERR, "MAC Hash Table not supported\n");
+               return -ENOTSUP;
+       }
+
+       for (index = 0; index < pdata->hash_table_count; index++) {
+               if (add)
+                       pdata->uc_hash_table[index] = ~0;
+               else
+                       pdata->uc_hash_table[index] = 0;
+
+               PMD_DRV_LOG(DEBUG, "%s MAC hash table at Index %#x\n",
+                           add ? "set" : "clear", index);
+
+               AXGMAC_IOWRITE(pdata, MAC_HTR(index),
+                              pdata->uc_hash_table[index]);
+       }
+
+       if (add) {
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1);
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 1);
+       } else {
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 0);
+               AXGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 0);
+       }
+       return 0;
+}
+
 /* return 0 means link status changed, -1 means not changed */
 static int
 axgbe_dev_link_update(struct rte_eth_dev *dev,
@@ -390,6 +559,27 @@ axgbe_dev_link_update(struct rte_eth_dev *dev,
        return ret;
 }
 
+static int
+axgbe_dev_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs)
+{
+       struct axgbe_port *pdata = dev->data->dev_private;
+
+       if (regs->data == NULL) {
+               regs->length = axgbe_regs_get_count(pdata);
+               regs->width = sizeof(uint32_t);
+               return 0;
+       }
+
+       /* Only full register dump is supported */
+       if (regs->length &&
+           regs->length != (uint32_t)axgbe_regs_get_count(pdata))
+               return -ENOTSUP;
+
+       regs->version = pdata->pci_dev->id.vendor_id << 16 |
+                       pdata->pci_dev->id.device_id;
+       axgbe_regs_dump(pdata, regs->data);
+       return 0;
+}
 static void axgbe_read_mmc_stats(struct axgbe_port *pdata)
 {
        struct axgbe_mmc_stats *stats = &pdata->mmc_stats;
@@ -781,13 +971,16 @@ axgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->max_tx_queues = pdata->tx_ring_count;
        dev_info->min_rx_bufsize = AXGBE_RX_MIN_BUF_SIZE;
        dev_info->max_rx_pktlen = AXGBE_RX_MAX_BUF_SIZE;
-       dev_info->max_mac_addrs = AXGBE_MAX_MAC_ADDRS;
+       dev_info->max_mac_addrs = pdata->hw_feat.addn_mac + 1;
+       dev_info->max_hash_mac_addrs = pdata->hw_feat.hash_table_size;
        dev_info->speed_capa =  ETH_LINK_SPEED_10G;
 
        dev_info->rx_offload_capa =
                DEV_RX_OFFLOAD_IPV4_CKSUM |
                DEV_RX_OFFLOAD_UDP_CKSUM  |
                DEV_RX_OFFLOAD_TCP_CKSUM  |
+               DEV_RX_OFFLOAD_JUMBO_FRAME      |
+               DEV_RX_OFFLOAD_SCATTER    |
                DEV_RX_OFFLOAD_KEEP_CRC;
 
        dev_info->tx_offload_capa =
@@ -982,6 +1175,30 @@ static void axgbe_default_config(struct axgbe_port *pdata)
        pdata->power_down = 0;
 }
 
+static int
+pci_device_cmp(const struct rte_device *dev, const void *_pci_id)
+{
+       const struct rte_pci_device *pdev = RTE_DEV_TO_PCI_CONST(dev);
+       const struct rte_pci_id *pcid = _pci_id;
+
+       if (pdev->id.vendor_id == AMD_PCI_VENDOR_ID &&
+                       pdev->id.device_id == pcid->device_id)
+               return 0;
+       return 1;
+}
+
+static bool
+pci_search_device(int device_id)
+{
+       struct rte_bus *pci_bus;
+       struct rte_pci_id dev_id;
+
+       dev_id.device_id = device_id;
+       pci_bus = rte_bus_find_by_name("pci");
+       return (pci_bus != NULL) &&
+               (pci_bus->find_device(NULL, pci_device_cmp, &dev_id) != NULL);
+}
+
 /*
  * It returns 0 on success.
  */
@@ -992,10 +1209,10 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
        struct axgbe_port *pdata;
        struct rte_pci_device *pci_dev;
        uint32_t reg, mac_lo, mac_hi;
+       uint32_t len;
        int ret;
 
        eth_dev->dev_ops = &axgbe_eth_dev_ops;
-       eth_dev->rx_pkt_burst = &axgbe_recv_pkts;
 
        /*
         * For secondary processes, we don't initialise any further as primary
@@ -1013,6 +1230,17 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
        pci_dev = RTE_DEV_TO_PCI(eth_dev->device);
        pdata->pci_dev = pci_dev;
 
+       /*
+        * Use root complex device ID to differentiate RV AXGBE vs SNOWY AXGBE
+        */
+       if (pci_search_device(AMD_PCI_RV_ROOT_COMPLEX_ID)) {
+               pdata->xpcs_window_def_reg = PCS_V2_RV_WINDOW_DEF;
+               pdata->xpcs_window_sel_reg = PCS_V2_RV_WINDOW_SELECT;
+       } else {
+               pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF;
+               pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT;
+       }
+
        pdata->xgmac_regs =
                (void *)pci_dev->mem_resource[AXGBE_AXGMAC_BAR].addr;
        pdata->xprop_regs = (void *)((uint8_t *)pdata->xgmac_regs
@@ -1028,14 +1256,13 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
                pdata->vdata = &axgbe_v2b;
 
        /* Configure the PCS indirect addressing support */
-       reg = XPCS32_IOREAD(pdata, PCS_V2_WINDOW_DEF);
+       reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg);
        pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET);
        pdata->xpcs_window <<= 6;
        pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, SIZE);
        pdata->xpcs_window_size = 1 << (pdata->xpcs_window_size + 7);
        pdata->xpcs_window_mask = pdata->xpcs_window_size - 1;
-       pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF;
-       pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT;
+
        PMD_INIT_LOG(DEBUG,
                     "xpcs window :%x, size :%x, mask :%x ", pdata->xpcs_window,
                     pdata->xpcs_window_size, pdata->xpcs_window_mask);
@@ -1051,12 +1278,25 @@ eth_axgbe_dev_init(struct rte_eth_dev *eth_dev)
        pdata->mac_addr.addr_bytes[4] = mac_hi & 0xff;
        pdata->mac_addr.addr_bytes[5] = (mac_hi >> 8)  &  0xff;
 
-       eth_dev->data->mac_addrs = rte_zmalloc("axgbe_mac_addr",
-                                              RTE_ETHER_ADDR_LEN, 0);
+       len = RTE_ETHER_ADDR_LEN * AXGBE_MAX_MAC_ADDRS;
+       eth_dev->data->mac_addrs = rte_zmalloc("axgbe_mac_addr", len, 0);
+
        if (!eth_dev->data->mac_addrs) {
                PMD_INIT_LOG(ERR,
-                            "Failed to alloc %u bytes needed to store MAC addr tbl",
-                            RTE_ETHER_ADDR_LEN);
+                            "Failed to alloc %u bytes needed to "
+                            "store MAC addresses", len);
+               return -ENOMEM;
+       }
+
+       /* Allocate memory for storing hash filter MAC addresses */
+       len = RTE_ETHER_ADDR_LEN * AXGBE_MAX_HASH_MAC_ADDRS;
+       eth_dev->data->hash_mac_addrs = rte_zmalloc("axgbe_hash_mac_addr",
+                                                   len, 0);
+
+       if (eth_dev->data->hash_mac_addrs == NULL) {
+               PMD_INIT_LOG(ERR,
+                            "Failed to allocate %d bytes needed to "
+                            "store MAC addresses", len);
                return -ENOMEM;
        }