Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / ethernet / cavium / thunder / nic_main.c
index 85cc782..2bbf4cb 100644 (file)
 #define DRV_NAME       "thunder-nic"
 #define DRV_VERSION    "1.0"
 
+struct hw_info {
+       u8              bgx_cnt;
+       u8              chans_per_lmac;
+       u8              chans_per_bgx; /* Rx/Tx chans */
+       u8              chans_per_rgx;
+       u8              chans_per_lbk;
+       u16             cpi_cnt;
+       u16             rssi_cnt;
+       u16             rss_ind_tbl_size;
+       u16             tl4_cnt;
+       u16             tl3_cnt;
+       u8              tl2_cnt;
+       u8              tl1_cnt;
+       bool            tl1_per_bgx; /* TL1 per BGX or per LMAC */
+};
+
 struct nicpf {
        struct pci_dev          *pdev;
+       struct hw_info          *hw;
        u8                      node;
        unsigned int            flags;
        u8                      num_vf_en;      /* No of VF enabled */
@@ -36,22 +53,22 @@ struct nicpf {
 #define        NIC_SET_VF_LMAC_MAP(bgx, lmac)  (((bgx & 0xF) << 4) | (lmac & 0xF))
 #define        NIC_GET_BGX_FROM_VF_LMAC_MAP(map)       ((map >> 4) & 0xF)
 #define        NIC_GET_LMAC_FROM_VF_LMAC_MAP(map)      (map & 0xF)
-       u8                      vf_lmac_map[MAX_LMAC];
+       u8                      *vf_lmac_map;
        struct delayed_work     dwork;
        struct workqueue_struct *check_link;
-       u8                      link[MAX_LMAC];
-       u8                      duplex[MAX_LMAC];
-       u32                     speed[MAX_LMAC];
+       u8                      *link;
+       u8                      *duplex;
+       u32                     *speed;
        u16                     cpi_base[MAX_NUM_VFS_SUPPORTED];
        u16                     rssi_base[MAX_NUM_VFS_SUPPORTED];
-       u16                     rss_ind_tbl_size;
        bool                    mbx_lock[MAX_NUM_VFS_SUPPORTED];
 
        /* MSI-X */
        bool                    msix_enabled;
        u8                      num_vec;
-       struct msix_entry       msix_entries[NIC_PF_MSIX_VECTORS];
+       struct msix_entry       *msix_entries;
        bool                    irq_allocated[NIC_PF_MSIX_VECTORS];
+       char                    irq_name[NIC_PF_MSIX_VECTORS][20];
 };
 
 /* Supported devices */
@@ -89,9 +106,22 @@ static u64 nic_reg_read(struct nicpf *nic, u64 offset)
 /* PF -> VF mailbox communication APIs */
 static void nic_enable_mbx_intr(struct nicpf *nic)
 {
-       /* Enable mailbox interrupt for all 128 VFs */
-       nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0ull);
-       nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), ~0ull);
+       int vf_cnt = pci_sriov_get_totalvfs(nic->pdev);
+
+#define INTR_MASK(vfs) ((vfs < 64) ? (BIT_ULL(vfs) - 1) : (~0ull))
+
+       /* Clear it, to avoid spurious interrupts (if any) */
+       nic_reg_write(nic, NIC_PF_MAILBOX_INT, INTR_MASK(vf_cnt));
+
+       /* Enable mailbox interrupt for all VFs */
+       nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, INTR_MASK(vf_cnt));
+       /* One mailbox intr enable reg per 64 VFs */
+       if (vf_cnt > 64) {
+               nic_reg_write(nic, NIC_PF_MAILBOX_INT + sizeof(u64),
+                             INTR_MASK(vf_cnt - 64));
+               nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64),
+                             INTR_MASK(vf_cnt - 64));
+       }
 }
 
 static void nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg)
@@ -144,7 +174,7 @@ static void nic_mbx_send_ready(struct nicpf *nic, int vf)
 
        mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE;
 
-       if (vf < MAX_LMAC) {
+       if (vf < nic->num_vf_en) {
                bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
                lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
 
@@ -155,7 +185,7 @@ static void nic_mbx_send_ready(struct nicpf *nic, int vf)
        mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false;
        mbx.nic_cfg.node_id = nic->node;
 
-       mbx.nic_cfg.loopback_supported = vf < MAX_LMAC;
+       mbx.nic_cfg.loopback_supported = vf < nic->num_vf_en;
 
        nic_send_msg_to_vf(nic, vf, &mbx);
 }
@@ -248,7 +278,8 @@ static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf)
 /* Set minimum transmit packet size */
 static void nic_set_tx_pkt_pad(struct nicpf *nic, int size)
 {
-       int lmac;
+       int lmac, max_lmac;
+       u16 sdevid;
        u64 lmac_cfg;
 
        /* There is a issue in HW where-in while sending GSO sized
@@ -260,7 +291,14 @@ static void nic_set_tx_pkt_pad(struct nicpf *nic, int size)
        if (size > 52)
                size = 52;
 
-       for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) {
+       pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid);
+       /* 81xx's RGX has only one LMAC */
+       if (sdevid == PCI_SUBSYS_DEVID_81XX_NIC_PF)
+               max_lmac = ((nic->hw->bgx_cnt - 1) * MAX_LMAC_PER_BGX) + 1;
+       else
+               max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX;
+
+       for (lmac = 0; lmac < max_lmac; lmac++) {
                lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3));
                lmac_cfg &= ~(0xF << 2);
                lmac_cfg |= ((size / 4) << 2);
@@ -280,7 +318,7 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic)
 
        nic->num_vf_en = 0;
 
-       for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) {
+       for (bgx = 0; bgx < nic->hw->bgx_cnt; bgx++) {
                if (!(bgx_map & (1 << bgx)))
                        continue;
                lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
@@ -300,28 +338,125 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic)
                        nic_reg_write(nic,
                                      NIC_PF_LMAC_0_7_CREDIT + (lmac * 8),
                                      lmac_credit);
+
+               /* On CN81XX there are only 8 VFs but max possible no of
+                * interfaces are 9.
+                */
+               if (nic->num_vf_en >= pci_sriov_get_totalvfs(nic->pdev)) {
+                       nic->num_vf_en = pci_sriov_get_totalvfs(nic->pdev);
+                       break;
+               }
        }
 }
 
+static void nic_free_lmacmem(struct nicpf *nic)
+{
+       kfree(nic->vf_lmac_map);
+       kfree(nic->link);
+       kfree(nic->duplex);
+       kfree(nic->speed);
+}
+
+static int nic_get_hw_info(struct nicpf *nic)
+{
+       u8 max_lmac;
+       u16 sdevid;
+       struct hw_info *hw = nic->hw;
+
+       pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid);
+
+       switch (sdevid) {
+       case PCI_SUBSYS_DEVID_88XX_NIC_PF:
+               hw->bgx_cnt = MAX_BGX_PER_CN88XX;
+               hw->chans_per_lmac = 16;
+               hw->chans_per_bgx = 128;
+               hw->cpi_cnt = 2048;
+               hw->rssi_cnt = 4096;
+               hw->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
+               hw->tl3_cnt = 256;
+               hw->tl2_cnt = 64;
+               hw->tl1_cnt = 2;
+               hw->tl1_per_bgx = true;
+               break;
+       case PCI_SUBSYS_DEVID_81XX_NIC_PF:
+               hw->bgx_cnt = MAX_BGX_PER_CN81XX;
+               hw->chans_per_lmac = 8;
+               hw->chans_per_bgx = 32;
+               hw->chans_per_rgx = 8;
+               hw->chans_per_lbk = 24;
+               hw->cpi_cnt = 512;
+               hw->rssi_cnt = 256;
+               hw->rss_ind_tbl_size = 32; /* Max RSSI / Max interfaces */
+               hw->tl3_cnt = 64;
+               hw->tl2_cnt = 16;
+               hw->tl1_cnt = 10;
+               hw->tl1_per_bgx = false;
+               break;
+       case PCI_SUBSYS_DEVID_83XX_NIC_PF:
+               hw->bgx_cnt = MAX_BGX_PER_CN83XX;
+               hw->chans_per_lmac = 8;
+               hw->chans_per_bgx = 32;
+               hw->chans_per_lbk = 64;
+               hw->cpi_cnt = 2048;
+               hw->rssi_cnt = 1024;
+               hw->rss_ind_tbl_size = 64; /* Max RSSI / Max interfaces */
+               hw->tl3_cnt = 256;
+               hw->tl2_cnt = 64;
+               hw->tl1_cnt = 18;
+               hw->tl1_per_bgx = false;
+               break;
+       }
+       hw->tl4_cnt = MAX_QUEUES_PER_QSET * pci_sriov_get_totalvfs(nic->pdev);
+
+       /* Allocate memory for LMAC tracking elements */
+       max_lmac = hw->bgx_cnt * MAX_LMAC_PER_BGX;
+       nic->vf_lmac_map = kmalloc_array(max_lmac, sizeof(u8), GFP_KERNEL);
+       if (!nic->vf_lmac_map)
+               goto error;
+       nic->link = kmalloc_array(max_lmac, sizeof(u8), GFP_KERNEL);
+       if (!nic->link)
+               goto error;
+       nic->duplex = kmalloc_array(max_lmac, sizeof(u8), GFP_KERNEL);
+       if (!nic->duplex)
+               goto error;
+       nic->speed = kmalloc_array(max_lmac, sizeof(u32), GFP_KERNEL);
+       if (!nic->speed)
+               goto error;
+       return 0;
+
+error:
+       nic_free_lmacmem(nic);
+       return -ENOMEM;
+}
+
 #define BGX0_BLOCK 8
 #define BGX1_BLOCK 9
 
-static void nic_init_hw(struct nicpf *nic)
+static int nic_init_hw(struct nicpf *nic)
 {
-       int i;
+       int i, err;
        u64 cqm_cfg;
 
+       /* Get HW capability info */
+       err = nic_get_hw_info(nic);
+       if (err)
+               return err;
+
        /* Enable NIC HW block */
        nic_reg_write(nic, NIC_PF_CFG, 0x3);
 
        /* Enable backpressure */
        nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03);
 
-       /* Disable TNS mode on both interfaces */
-       nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
-                     (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK);
-       nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
-                     (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK);
+       /* TNS and TNS bypass modes are present only on 88xx */
+       if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) {
+               /* Disable TNS mode on both interfaces */
+               nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
+                             (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK);
+               nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
+                             (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK);
+       }
+
        nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG,
                      (1ULL << 63) | BGX0_BLOCK);
        nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
@@ -351,11 +486,14 @@ static void nic_init_hw(struct nicpf *nic)
        cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG);
        if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL)
                nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL);
+
+       return 0;
 }
 
 /* Channel parse index configuration */
 static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg)
 {
+       struct hw_info *hw = nic->hw;
        u32 vnic, bgx, lmac, chan;
        u32 padd, cpi_count = 0;
        u64 cpi_base, cpi, rssi_base, rssi;
@@ -365,9 +503,9 @@ static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg)
        bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
        lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
 
-       chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
-       cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX);
-       rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX);
+       chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx);
+       cpi_base = vnic * NIC_MAX_CPI_PER_LMAC;
+       rssi_base = vnic * hw->rss_ind_tbl_size;
 
        /* Rx channel configuration */
        nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3),
@@ -439,7 +577,7 @@ static void nic_send_rss_size(struct nicpf *nic, int vf)
        msg = (u64 *)&mbx;
 
        mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE;
-       mbx.rss_size.ind_tbl_size = nic->rss_ind_tbl_size;
+       mbx.rss_size.ind_tbl_size = nic->hw->rss_ind_tbl_size;
        nic_send_msg_to_vf(nic, vf, &mbx);
 }
 
@@ -486,7 +624,7 @@ static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg)
 /* 4 level transmit side scheduler configutation
  * for TNS bypass mode
  *
- * Sample configuration for SQ0
+ * Sample configuration for SQ0 on 88xx
  * VNIC0-SQ0 -> TL4(0)   -> TL3[0]   -> TL2[0]  -> TL1[0] -> BGX0
  * VNIC1-SQ0 -> TL4(8)   -> TL3[2]   -> TL2[0]  -> TL1[0] -> BGX0
  * VNIC2-SQ0 -> TL4(16)  -> TL3[4]   -> TL2[1]  -> TL1[0] -> BGX0
@@ -499,6 +637,7 @@ static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg)
 static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
                               struct sq_cfg_msg *sq)
 {
+       struct hw_info *hw = nic->hw;
        u32 bgx, lmac, chan;
        u32 tl2, tl3, tl4;
        u32 rr_quantum;
@@ -517,21 +656,28 @@ static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
        /* 24 bytes for FCS, IPG and preamble */
        rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4);
 
-       if (!sq->sqs_mode) {
-               tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX);
-       } else {
-               for (svf = 0; svf < MAX_SQS_PER_VF; svf++) {
-                       if (nic->vf_sqs[pqs_vnic][svf] == vnic)
-                               break;
+       /* For 88xx 0-511 TL4 transmits via BGX0 and
+        * 512-1023 TL4s transmit via BGX1.
+        */
+       if (hw->tl1_per_bgx) {
+               tl4 = bgx * (hw->tl4_cnt / hw->bgx_cnt);
+               if (!sq->sqs_mode) {
+                       tl4 += (lmac * MAX_QUEUES_PER_QSET);
+               } else {
+                       for (svf = 0; svf < MAX_SQS_PER_VF; svf++) {
+                               if (nic->vf_sqs[pqs_vnic][svf] == vnic)
+                                       break;
+                       }
+                       tl4 += (MAX_LMAC_PER_BGX * MAX_QUEUES_PER_QSET);
+                       tl4 += (lmac * MAX_QUEUES_PER_QSET * MAX_SQS_PER_VF);
+                       tl4 += (svf * MAX_QUEUES_PER_QSET);
                }
-               tl4 = (MAX_LMAC_PER_BGX * NIC_TL4_PER_LMAC);
-               tl4 += (lmac * NIC_TL4_PER_LMAC * MAX_SQS_PER_VF);
-               tl4 += (svf * NIC_TL4_PER_LMAC);
-               tl4 += (bgx * NIC_TL4_PER_BGX);
+       } else {
+               tl4 = (vnic * MAX_QUEUES_PER_QSET);
        }
        tl4 += sq_idx;
 
-       tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3);
+       tl3 = tl4 / (hw->tl4_cnt / hw->tl3_cnt);
        nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 |
                      ((u64)vnic << NIC_QS_ID_SHIFT) |
                      ((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4);
@@ -539,8 +685,19 @@ static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
                      ((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum);
 
        nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum);
-       chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
-       nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan);
+
+       /* On 88xx 0-127 channels are for BGX0 and
+        * 127-255 channels for BGX1.
+        *
+        * On 81xx/83xx TL3_CHAN reg should be configured with channel
+        * within LMAC i.e 0-7 and not the actual channel number like on 88xx
+        */
+       chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx);
+       if (hw->tl1_per_bgx)
+               nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan);
+       else
+               nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), 0);
+
        /* Enable backpressure on the channel */
        nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1);
 
@@ -549,6 +706,16 @@ static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic,
        nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum);
        /* No priorities as of now */
        nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00);
+
+       /* Unlike 88xx where TL2s 0-31 transmits to TL1 '0' and rest to TL1 '1'
+        * on 81xx/83xx TL2 needs to be configured to transmit to one of the
+        * possible LMACs.
+        *
+        * This register doesn't exist on 88xx.
+        */
+       if (!hw->tl1_per_bgx)
+               nic_reg_write(nic, NIC_PF_TL2_LMAC | (tl2 << 3),
+                             lmac + (bgx * MAX_LMAC_PER_BGX));
 }
 
 /* Send primary nicvf pointer to secondary QS's VF */
@@ -620,7 +787,7 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
 {
        int bgx_idx, lmac_idx;
 
-       if (lbk->vf_id > MAX_LMAC)
+       if (lbk->vf_id >= nic->num_vf_en)
                return -1;
 
        bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
@@ -631,6 +798,67 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
        return 0;
 }
 
+/* Reset statistics counters */
+static int nic_reset_stat_counters(struct nicpf *nic,
+                                  int vf, struct reset_stat_cfg *cfg)
+{
+       int i, stat, qnum;
+       u64 reg_addr;
+
+       for (i = 0; i < RX_STATS_ENUM_LAST; i++) {
+               if (cfg->rx_stat_mask & BIT(i)) {
+                       reg_addr = NIC_PF_VNIC_0_127_RX_STAT_0_13 |
+                                  (vf << NIC_QS_ID_SHIFT) |
+                                  (i << 3);
+                       nic_reg_write(nic, reg_addr, 0);
+               }
+       }
+
+       for (i = 0; i < TX_STATS_ENUM_LAST; i++) {
+               if (cfg->tx_stat_mask & BIT(i)) {
+                       reg_addr = NIC_PF_VNIC_0_127_TX_STAT_0_4 |
+                                  (vf << NIC_QS_ID_SHIFT) |
+                                  (i << 3);
+                       nic_reg_write(nic, reg_addr, 0);
+               }
+       }
+
+       for (i = 0; i <= 15; i++) {
+               qnum = i >> 1;
+               stat = i & 1 ? 1 : 0;
+               reg_addr = (vf << NIC_QS_ID_SHIFT) |
+                          (qnum << NIC_Q_NUM_SHIFT) | (stat << 3);
+               if (cfg->rq_stat_mask & BIT(i)) {
+                       reg_addr |= NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1;
+                       nic_reg_write(nic, reg_addr, 0);
+               }
+               if (cfg->sq_stat_mask & BIT(i)) {
+                       reg_addr |= NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1;
+                       nic_reg_write(nic, reg_addr, 0);
+               }
+       }
+       return 0;
+}
+
+static void nic_enable_tunnel_parsing(struct nicpf *nic, int vf)
+{
+       u64 prot_def = (IPV6_PROT << 32) | (IPV4_PROT << 16) | ET_PROT;
+       u64 vxlan_prot_def = (IPV6_PROT_DEF << 32) |
+                             (IPV4_PROT_DEF) << 16 | ET_PROT_DEF;
+
+       /* Configure tunnel parsing parameters */
+       nic_reg_write(nic, NIC_PF_RX_GENEVE_DEF,
+                     (1ULL << 63 | UDP_GENEVE_PORT_NUM));
+       nic_reg_write(nic, NIC_PF_RX_GENEVE_PROT_DEF,
+                     ((7ULL << 61) | prot_def));
+       nic_reg_write(nic, NIC_PF_RX_NVGRE_PROT_DEF,
+                     ((7ULL << 61) | prot_def));
+       nic_reg_write(nic, NIC_PF_RX_VXLAN_DEF_0_1,
+                     ((1ULL << 63) | UDP_VXLAN_PORT_NUM));
+       nic_reg_write(nic, NIC_PF_RX_VXLAN_PROT_DEF,
+                     ((0xfULL << 60) | vxlan_prot_def));
+}
+
 static void nic_enable_vf(struct nicpf *nic, int vf, bool enable)
 {
        int bgx, lmac;
@@ -669,18 +897,17 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
                mbx_addr += sizeof(u64);
        }
 
-       dev_dbg(&nic->pdev->dev, "%s: Mailbox msg %d from VF%d\n",
+       dev_dbg(&nic->pdev->dev, "%s: Mailbox msg 0x%02x from VF%d\n",
                __func__, mbx.msg.msg, vf);
        switch (mbx.msg.msg) {
        case NIC_MBOX_MSG_READY:
                nic_mbx_send_ready(nic, vf);
-               if (vf < MAX_LMAC) {
+               if (vf < nic->num_vf_en) {
                        nic->link[vf] = 0;
                        nic->duplex[vf] = 0;
                        nic->speed[vf] = 0;
                }
-               ret = 1;
-               break;
+               goto unlock;
        case NIC_MBOX_MSG_QS_CFG:
                reg_addr = NIC_PF_QSET_0_127_CFG |
                           (mbx.qs.num << NIC_QS_ID_SHIFT);
@@ -698,6 +925,15 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
                           (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
                           (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
                nic_reg_write(nic, reg_addr, mbx.rq.cfg);
+               /* Enable CQE_RX2_S extension in CQE_RX descriptor.
+                * This gets appended by default on 81xx/83xx chips,
+                * for consistency enabling the same on 88xx pass2
+                * where this is introduced.
+                */
+               if (pass2_silicon(nic->pdev))
+                       nic_reg_write(nic, NIC_PF_RX_CFG, 0x01);
+               if (!pass1_silicon(nic->pdev))
+                       nic_enable_tunnel_parsing(nic, vf);
                break;
        case NIC_MBOX_MSG_RQ_BP_CFG:
                reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG |
@@ -722,8 +958,10 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
                nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq);
                break;
        case NIC_MBOX_MSG_SET_MAC:
-               if (vf >= nic->num_vf_en)
+               if (vf >= nic->num_vf_en) {
+                       ret = -1; /* NACK */
                        break;
+               }
                lmac = mbx.mac.vf_id;
                bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
                lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
@@ -772,25 +1010,38 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
        case NIC_MBOX_MSG_LOOPBACK:
                ret = nic_config_loopback(nic, &mbx.lbk);
                break;
+       case NIC_MBOX_MSG_RESET_STAT_COUNTER:
+               ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat);
+               break;
        default:
                dev_err(&nic->pdev->dev,
                        "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
                break;
        }
 
-       if (!ret)
+       if (!ret) {
                nic_mbx_send_ack(nic, vf);
-       else if (mbx.msg.msg != NIC_MBOX_MSG_READY)
+       } else if (mbx.msg.msg != NIC_MBOX_MSG_READY) {
+               dev_err(&nic->pdev->dev, "NACK for MBOX 0x%02x from VF %d\n",
+                       mbx.msg.msg, vf);
                nic_mbx_send_nack(nic, vf);
+       }
 unlock:
        nic->mbx_lock[vf] = false;
 }
 
-static void nic_mbx_intr_handler (struct nicpf *nic, int mbx)
+static irqreturn_t nic_mbx_intr_handler(int irq, void *nic_irq)
 {
+       struct nicpf *nic = (struct nicpf *)nic_irq;
+       int mbx;
        u64 intr;
        u8  vf, vf_per_mbx_reg = 64;
 
+       if (irq == nic->msix_entries[NIC_PF_INTR_ID_MBOX0].vector)
+               mbx = 0;
+       else
+               mbx = 1;
+
        intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3));
        dev_dbg(&nic->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr);
        for (vf = 0; vf < vf_per_mbx_reg; vf++) {
@@ -802,23 +1053,6 @@ static void nic_mbx_intr_handler (struct nicpf *nic, int mbx)
                        nic_clear_mbx_intr(nic, vf, mbx);
                }
        }
-}
-
-static irqreturn_t nic_mbx0_intr_handler (int irq, void *nic_irq)
-{
-       struct nicpf *nic = (struct nicpf *)nic_irq;
-
-       nic_mbx_intr_handler(nic, 0);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t nic_mbx1_intr_handler (int irq, void *nic_irq)
-{
-       struct nicpf *nic = (struct nicpf *)nic_irq;
-
-       nic_mbx_intr_handler(nic, 1);
-
        return IRQ_HANDLED;
 }
 
@@ -826,7 +1060,13 @@ static int nic_enable_msix(struct nicpf *nic)
 {
        int i, ret;
 
-       nic->num_vec = NIC_PF_MSIX_VECTORS;
+       nic->num_vec = pci_msix_vec_count(nic->pdev);
+
+       nic->msix_entries = kmalloc_array(nic->num_vec,
+                                         sizeof(struct msix_entry),
+                                         GFP_KERNEL);
+       if (!nic->msix_entries)
+               return -ENOMEM;
 
        for (i = 0; i < nic->num_vec; i++)
                nic->msix_entries[i].entry = i;
@@ -834,8 +1074,9 @@ static int nic_enable_msix(struct nicpf *nic)
        ret = pci_enable_msix(nic->pdev, nic->msix_entries, nic->num_vec);
        if (ret) {
                dev_err(&nic->pdev->dev,
-                       "Request for #%d msix vectors failed\n",
-                          nic->num_vec);
+                       "Request for #%d msix vectors failed, returned %d\n",
+                          nic->num_vec, ret);
+               kfree(nic->msix_entries);
                return ret;
        }
 
@@ -847,6 +1088,7 @@ static void nic_disable_msix(struct nicpf *nic)
 {
        if (nic->msix_enabled) {
                pci_disable_msix(nic->pdev);
+               kfree(nic->msix_entries);
                nic->msix_enabled = 0;
                nic->num_vec = 0;
        }
@@ -865,27 +1107,26 @@ static void nic_free_all_interrupts(struct nicpf *nic)
 
 static int nic_register_interrupts(struct nicpf *nic)
 {
-       int ret;
+       int i, ret;
 
        /* Enable MSI-X */
        ret = nic_enable_msix(nic);
        if (ret)
                return ret;
 
-       /* Register mailbox interrupt handlers */
-       ret = request_irq(nic->msix_entries[NIC_PF_INTR_ID_MBOX0].vector,
-                         nic_mbx0_intr_handler, 0, "NIC Mbox0", nic);
-       if (ret)
-               goto fail;
-
-       nic->irq_allocated[NIC_PF_INTR_ID_MBOX0] = true;
+       /* Register mailbox interrupt handler */
+       for (i = NIC_PF_INTR_ID_MBOX0; i < nic->num_vec; i++) {
+               sprintf(nic->irq_name[i],
+                       "NICPF Mbox%d", (i - NIC_PF_INTR_ID_MBOX0));
 
-       ret = request_irq(nic->msix_entries[NIC_PF_INTR_ID_MBOX1].vector,
-                         nic_mbx1_intr_handler, 0, "NIC Mbox1", nic);
-       if (ret)
-               goto fail;
+               ret = request_irq(nic->msix_entries[i].vector,
+                                 nic_mbx_intr_handler, 0,
+                                 nic->irq_name[i], nic);
+               if (ret)
+                       goto fail;
 
-       nic->irq_allocated[NIC_PF_INTR_ID_MBOX1] = true;
+               nic->irq_allocated[i] = true;
+       }
 
        /* Enable mailbox interrupt */
        nic_enable_mbx_intr(nic);
@@ -894,6 +1135,7 @@ static int nic_register_interrupts(struct nicpf *nic)
 fail:
        dev_err(&nic->pdev->dev, "Request irq failed\n");
        nic_free_all_interrupts(nic);
+       nic_disable_msix(nic);
        return ret;
 }
 
@@ -908,6 +1150,12 @@ static int nic_num_sqs_en(struct nicpf *nic, int vf_en)
        int pos, sqs_per_vf = MAX_SQS_PER_VF_SINGLE_NODE;
        u16 total_vf;
 
+       /* Secondary Qsets are needed only if CPU count is
+        * morethan MAX_QUEUES_PER_QSET.
+        */
+       if (num_online_cpus() <= MAX_QUEUES_PER_QSET)
+               return 0;
+
        /* Check if its a multi-node environment */
        if (nr_node_ids > 1)
                sqs_per_vf = MAX_SQS_PER_VF;
@@ -1013,6 +1261,12 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!nic)
                return -ENOMEM;
 
+       nic->hw = devm_kzalloc(dev, sizeof(struct hw_info), GFP_KERNEL);
+       if (!nic->hw) {
+               devm_kfree(dev, nic);
+               return -ENOMEM;
+       }
+
        pci_set_drvdata(pdev, nic);
 
        nic->pdev = pdev;
@@ -1052,13 +1306,12 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        nic->node = nic_get_node_id(pdev);
 
-       nic_set_lmac_vf_mapping(nic);
-
        /* Initialize hardware */
-       nic_init_hw(nic);
+       err = nic_init_hw(nic);
+       if (err)
+               goto err_release_regions;
 
-       /* Set RSS TBL size for each VF */
-       nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
+       nic_set_lmac_vf_mapping(nic);
 
        /* Register interrupts */
        err = nic_register_interrupts(nic);
@@ -1091,6 +1344,9 @@ err_unregister_interrupts:
 err_release_regions:
        pci_release_regions(pdev);
 err_disable_device:
+       nic_free_lmacmem(nic);
+       devm_kfree(dev, nic->hw);
+       devm_kfree(dev, nic);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
        return err;
@@ -1111,6 +1367,11 @@ static void nic_remove(struct pci_dev *pdev)
 
        nic_unregister_interrupts(nic);
        pci_release_regions(pdev);
+
+       nic_free_lmacmem(nic);
+       devm_kfree(&pdev->dev, nic->hw);
+       devm_kfree(&pdev->dev, nic);
+
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 }