]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/net/ethernet/qlogic/qed/qed_dev.c
qed: Add Light L2 support
[linux-beck.git] / drivers / net / ethernet / qlogic / qed / qed_dev.c
index 5ae27f2d2fa57ec9766cdb25fa3ddff5c2a32a11..9a8e153df841beef200540f148d04a6628ab8416 100644 (file)
@@ -29,6 +29,7 @@
 #include "qed_hw.h"
 #include "qed_init_ops.h"
 #include "qed_int.h"
+#include "qed_ll2.h"
 #include "qed_mcp.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
@@ -147,6 +148,9 @@ void qed_resc_free(struct qed_dev *cdev)
                qed_eq_free(p_hwfn, p_hwfn->p_eq);
                qed_consq_free(p_hwfn, p_hwfn->p_consq);
                qed_int_free(p_hwfn);
+#ifdef CONFIG_QED_LL2
+               qed_ll2_free(p_hwfn, p_hwfn->p_ll2_info);
+#endif
                qed_iov_free(p_hwfn);
                qed_dmae_info_free(p_hwfn);
                qed_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info);
@@ -340,7 +344,6 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable)
        return 0;
 
 alloc_err:
-       DP_NOTICE(p_hwfn, "Failed to allocate memory for QM params\n");
        qed_qm_info_free(p_hwfn);
        return -ENOMEM;
 }
@@ -404,6 +407,9 @@ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 
 int qed_resc_alloc(struct qed_dev *cdev)
 {
+#ifdef CONFIG_QED_LL2
+       struct qed_ll2_info *p_ll2_info;
+#endif
        struct qed_consq *p_consq;
        struct qed_eq *p_eq;
        int i, rc = 0;
@@ -424,18 +430,12 @@ int qed_resc_alloc(struct qed_dev *cdev)
                                     RESC_NUM(p_hwfn, QED_L2_QUEUE);
 
                p_hwfn->p_tx_cids = kzalloc(tx_size, GFP_KERNEL);
-               if (!p_hwfn->p_tx_cids) {
-                       DP_NOTICE(p_hwfn,
-                                 "Failed to allocate memory for Tx Cids\n");
+               if (!p_hwfn->p_tx_cids)
                        goto alloc_no_mem;
-               }
 
                p_hwfn->p_rx_cids = kzalloc(rx_size, GFP_KERNEL);
-               if (!p_hwfn->p_rx_cids) {
-                       DP_NOTICE(p_hwfn,
-                                 "Failed to allocate memory for Rx Cids\n");
+               if (!p_hwfn->p_rx_cids)
                        goto alloc_no_mem;
-               }
        }
 
        for_each_hwfn(cdev, i) {
@@ -520,28 +520,29 @@ int qed_resc_alloc(struct qed_dev *cdev)
                        goto alloc_no_mem;
                p_hwfn->p_consq = p_consq;
 
+#ifdef CONFIG_QED_LL2
+               if (p_hwfn->using_ll2) {
+                       p_ll2_info = qed_ll2_alloc(p_hwfn);
+                       if (!p_ll2_info)
+                               goto alloc_no_mem;
+                       p_hwfn->p_ll2_info = p_ll2_info;
+               }
+#endif
+
                /* DMA info initialization */
                rc = qed_dmae_info_alloc(p_hwfn);
-               if (rc) {
-                       DP_NOTICE(p_hwfn,
-                                 "Failed to allocate memory for dmae_info structure\n");
+               if (rc)
                        goto alloc_err;
-               }
 
                /* DCBX initialization */
                rc = qed_dcbx_info_alloc(p_hwfn);
-               if (rc) {
-                       DP_NOTICE(p_hwfn,
-                                 "Failed to allocate memory for dcbx structure\n");
+               if (rc)
                        goto alloc_err;
-               }
        }
 
        cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
-       if (!cdev->reset_stats) {
-               DP_NOTICE(cdev, "Failed to allocate reset statistics\n");
+       if (!cdev->reset_stats)
                goto alloc_no_mem;
-       }
 
        return 0;
 
@@ -576,6 +577,10 @@ void qed_resc_setup(struct qed_dev *cdev)
                qed_int_setup(p_hwfn, p_hwfn->p_main_ptt);
 
                qed_iov_setup(p_hwfn, p_hwfn->p_main_ptt);
+#ifdef CONFIG_QED_LL2
+               if (p_hwfn->using_ll2)
+                       qed_ll2_setup(p_hwfn, p_hwfn->p_ll2_info);
+#endif
        }
 }
 
@@ -1319,6 +1324,7 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn)
        resc_num[QED_VLAN] = (ETH_NUM_VLAN_FILTERS - 1 /*For vlan0*/) /
                             num_funcs;
        resc_num[QED_ILT] = PXP_NUM_ILT_RECORDS_BB / num_funcs;
+       resc_num[QED_LL2_QUEUE] = MAX_NUM_LL2_RX_QUEUES / num_funcs;
 
        for (i = 0; i < QED_MAX_RESC; i++)
                resc_start[i] = resc_num[i] * enabled_func_idx;
@@ -1342,7 +1348,8 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn)
                   "RL = %d start = %d\n"
                   "MAC = %d start = %d\n"
                   "VLAN = %d start = %d\n"
-                  "ILT = %d start = %d\n",
+                  "ILT = %d start = %d\n"
+                  "LL2_QUEUE = %d start = %d\n",
                   p_hwfn->hw_info.resc_num[QED_SB],
                   p_hwfn->hw_info.resc_start[QED_SB],
                   p_hwfn->hw_info.resc_num[QED_L2_QUEUE],
@@ -1358,7 +1365,9 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn)
                   p_hwfn->hw_info.resc_num[QED_VLAN],
                   p_hwfn->hw_info.resc_start[QED_VLAN],
                   p_hwfn->hw_info.resc_num[QED_ILT],
-                  p_hwfn->hw_info.resc_start[QED_ILT]);
+                  p_hwfn->hw_info.resc_start[QED_ILT],
+                  RESC_NUM(p_hwfn, QED_LL2_QUEUE),
+                  RESC_START(p_hwfn, QED_LL2_QUEUE));
 
        return 0;
 }
@@ -1713,10 +1722,8 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
 
        /* Allocate PTT pool */
        rc = qed_ptt_pool_alloc(p_hwfn);
-       if (rc) {
-               DP_NOTICE(p_hwfn, "Failed to prepare hwfn's hw\n");
+       if (rc)
                goto err0;
-       }
 
        /* Allocate the main PTT */
        p_hwfn->p_main_ptt = qed_get_reserved_ptt(p_hwfn, RESERVED_PTT_MAIN);
@@ -1746,10 +1753,8 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
 
        /* Allocate the init RT array and initialize the init-ops engine */
        rc = qed_init_alloc(p_hwfn);
-       if (rc) {
-               DP_NOTICE(p_hwfn, "Failed to allocate the init array\n");
+       if (rc)
                goto err2;
-       }
 
        return rc;
 err2:
@@ -1957,10 +1962,8 @@ qed_chain_alloc_next_ptr(struct qed_dev *cdev, struct qed_chain *p_chain)
                p_virt = dma_alloc_coherent(&cdev->pdev->dev,
                                            QED_CHAIN_PAGE_SIZE,
                                            &p_phys, GFP_KERNEL);
-               if (!p_virt) {
-                       DP_NOTICE(cdev, "Failed to allocate chain memory\n");
+               if (!p_virt)
                        return -ENOMEM;
-               }
 
                if (i == 0) {
                        qed_chain_init_mem(p_chain, p_virt, p_phys);
@@ -1990,10 +1993,8 @@ qed_chain_alloc_single(struct qed_dev *cdev, struct qed_chain *p_chain)
 
        p_virt = dma_alloc_coherent(&cdev->pdev->dev,
                                    QED_CHAIN_PAGE_SIZE, &p_phys, GFP_KERNEL);
-       if (!p_virt) {
-               DP_NOTICE(cdev, "Failed to allocate chain memory\n");
+       if (!p_virt)
                return -ENOMEM;
-       }
 
        qed_chain_init_mem(p_chain, p_virt, p_phys);
        qed_chain_reset(p_chain);
@@ -2010,13 +2011,9 @@ static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
        void *p_virt = NULL;
 
        size = page_cnt * sizeof(*pp_virt_addr_tbl);
-       pp_virt_addr_tbl = vmalloc(size);
-       if (!pp_virt_addr_tbl) {
-               DP_NOTICE(cdev,
-                         "Failed to allocate memory for the chain virtual addresses table\n");
+       pp_virt_addr_tbl = vzalloc(size);
+       if (!pp_virt_addr_tbl)
                return -ENOMEM;
-       }
-       memset(pp_virt_addr_tbl, 0, size);
 
        /* The allocation of the PBL table is done with its full size, since it
         * is expected to be successive.
@@ -2029,19 +2026,15 @@ static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
                                        size, &p_pbl_phys, GFP_KERNEL);
        qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys,
                               pp_virt_addr_tbl);
-       if (!p_pbl_virt) {
-               DP_NOTICE(cdev, "Failed to allocate chain pbl memory\n");
+       if (!p_pbl_virt)
                return -ENOMEM;
-       }
 
        for (i = 0; i < page_cnt; i++) {
                p_virt = dma_alloc_coherent(&cdev->pdev->dev,
                                            QED_CHAIN_PAGE_SIZE,
                                            &p_phys, GFP_KERNEL);
-               if (!p_virt) {
-                       DP_NOTICE(cdev, "Failed to allocate chain memory\n");
+               if (!p_virt)
                        return -ENOMEM;
-               }
 
                if (i == 0) {
                        qed_chain_init_mem(p_chain, p_virt, p_phys);
@@ -2076,7 +2069,8 @@ int qed_chain_alloc(struct qed_dev *cdev,
        rc = qed_chain_alloc_sanity_check(cdev, cnt_type, elem_size, page_cnt);
        if (rc) {
                DP_NOTICE(cdev,
-                         "Cannot allocate a chain with the given arguments:\n"
+                         "Cannot allocate a chain with the given arguments:\n");
+               DP_NOTICE(cdev,
                          "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu]\n",
                          intended_use, mode, cnt_type, num_elems, elem_size);
                return rc;
@@ -2163,6 +2157,98 @@ int qed_fw_rss_eng(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id)
        return 0;
 }
 
+static void qed_llh_mac_to_filter(u32 *p_high, u32 *p_low,
+                                 u8 *p_filter)
+{
+       *p_high = p_filter[1] | (p_filter[0] << 8);
+       *p_low = p_filter[5] | (p_filter[4] << 8) |
+                (p_filter[3] << 16) | (p_filter[2] << 24);
+}
+
+int qed_llh_add_mac_filter(struct qed_hwfn *p_hwfn,
+                          struct qed_ptt *p_ptt, u8 *p_filter)
+{
+       u32 high = 0, low = 0, en;
+       int i;
+
+       if (!(IS_MF_SI(p_hwfn) || IS_MF_DEFAULT(p_hwfn)))
+               return 0;
+
+       qed_llh_mac_to_filter(&high, &low, p_filter);
+
+       /* Find a free entry and utilize it */
+       for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
+               en = qed_rd(p_hwfn, p_ptt,
+                           NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32));
+               if (en)
+                       continue;
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_VALUE +
+                      2 * i * sizeof(u32), low);
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_VALUE +
+                      (2 * i + 1) * sizeof(u32), high);
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 0);
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
+                      i * sizeof(u32), 0);
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 1);
+               break;
+       }
+       if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) {
+               DP_NOTICE(p_hwfn,
+                         "Failed to find an empty LLH filter to utilize\n");
+               return -EINVAL;
+       }
+
+       DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
+                  "mac: %pM is added at %d\n",
+                  p_filter, i);
+
+       return 0;
+}
+
+void qed_llh_remove_mac_filter(struct qed_hwfn *p_hwfn,
+                              struct qed_ptt *p_ptt, u8 *p_filter)
+{
+       u32 high = 0, low = 0;
+       int i;
+
+       if (!(IS_MF_SI(p_hwfn) || IS_MF_DEFAULT(p_hwfn)))
+               return;
+
+       qed_llh_mac_to_filter(&high, &low, p_filter);
+
+       /* Find the entry and clean it */
+       for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
+               if (qed_rd(p_hwfn, p_ptt,
+                          NIG_REG_LLH_FUNC_FILTER_VALUE +
+                          2 * i * sizeof(u32)) != low)
+                       continue;
+               if (qed_rd(p_hwfn, p_ptt,
+                          NIG_REG_LLH_FUNC_FILTER_VALUE +
+                          (2 * i + 1) * sizeof(u32)) != high)
+                       continue;
+
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 0);
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * i * sizeof(u32), 0);
+               qed_wr(p_hwfn, p_ptt,
+                      NIG_REG_LLH_FUNC_FILTER_VALUE +
+                      (2 * i + 1) * sizeof(u32), 0);
+
+               DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
+                          "mac: %pM is removed from %d\n",
+                          p_filter, i);
+               break;
+       }
+       if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
+               DP_NOTICE(p_hwfn, "Tried to remove a non-configured filter\n");
+}
+
 static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
                            u32 hw_addr, void *p_eth_qzone,
                            size_t eth_qzone_size, u8 timeset)