net/bnxt: support WC TCAM management
[dpdk.git] / drivers / net / bnxt / tf_core / tf_device.c
index 4c46cad..498e668 100644 (file)
@@ -1,16 +1,64 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2019-2020 Broadcom
+ * Copyright(c) 2019-2021 Broadcom
  * All rights reserved.
  */
 
 #include "tf_device.h"
 #include "tf_device_p4.h"
+#include "tf_device_p58.h"
 #include "tfp.h"
+#include "tf_em.h"
+#include "tf_rm.h"
+#ifdef TF_TCAM_SHARED
+#include "tf_tcam_shared.h"
+#endif /* TF_TCAM_SHARED */
 
 struct tf;
 
 /* Forward declarations */
-static int dev_unbind_p4(struct tf *tfp);
+static int tf_dev_unbind_p4(struct tf *tfp);
+static int tf_dev_unbind_p58(struct tf *tfp);
+
+/**
+ * Resource Reservation Check function
+ *
+ * [in] count
+ *   Number of module subtypes
+ *
+ * [in] cfg
+ *   Pointer to rm element config
+ *
+ * [in] reservations
+ *   Pointer to resource reservation array
+ *
+ * Returns
+ *   - (n) number of tables in module that have non-zero reservation count.
+ */
+static int
+tf_dev_reservation_check(uint16_t count,
+                        struct tf_rm_element_cfg *cfg,
+                        uint16_t *reservations)
+{
+       uint16_t cnt = 0;
+       uint16_t *rm_num;
+       int i, j;
+
+       for (i = 0; i < TF_DIR_MAX; i++) {
+               rm_num = (uint16_t *)reservations + i * count;
+               for (j = 0; j < count; j++) {
+                       if ((cfg[j].cfg_type == TF_RM_ELEM_CFG_HCAPI ||
+                            cfg[j].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA ||
+                            cfg[j].cfg_type ==
+                               TF_RM_ELEM_CFG_HCAPI_BA_PARENT ||
+                            cfg[j].cfg_type ==
+                               TF_RM_ELEM_CFG_HCAPI_BA_CHILD) &&
+                            rm_num[j] > 0)
+                               cnt++;
+               }
+       }
+
+       return cnt;
+}
 
 /**
  * Device specific bind function, WH+
@@ -32,60 +80,438 @@ static int dev_unbind_p4(struct tf *tfp);
  *   - (-EINVAL) on parameter or internal failure.
  */
 static int
-dev_bind_p4(struct tf *tfp,
-           bool shadow_copy,
-           struct tf_session_resources *resources,
-           struct tf_dev_info *dev_handle)
+tf_dev_bind_p4(struct tf *tfp,
+              bool shadow_copy,
+              struct tf_session_resources *resources,
+              struct tf_dev_info *dev_handle)
 {
        int rc;
        int frc;
+       int rsv_cnt;
+       bool no_rsv_flag = true;
        struct tf_ident_cfg_parms ident_cfg;
        struct tf_tbl_cfg_parms tbl_cfg;
        struct tf_tcam_cfg_parms tcam_cfg;
+       struct tf_em_cfg_parms em_cfg;
+       struct tf_if_tbl_cfg_parms if_tbl_cfg;
+       struct tf_global_cfg_cfg_parms global_cfg;
+       struct tf_session *tfs;
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* Initial function initialization */
+       dev_handle->ops = &tf_dev_ops_p4_init;
 
        /* Initialize the modules */
 
-       ident_cfg.num_elements = TF_IDENT_TYPE_MAX;
-       ident_cfg.cfg = tf_ident_p4;
-       ident_cfg.shadow_copy = shadow_copy;
-       ident_cfg.resources = resources;
-       rc = tf_ident_bind(tfp, &ident_cfg);
+       rsv_cnt = tf_dev_reservation_check(TF_IDENT_TYPE_MAX,
+                                          tf_ident_p4,
+                                          (uint16_t *)resources->ident_cnt);
+       if (rsv_cnt) {
+               ident_cfg.num_elements = TF_IDENT_TYPE_MAX;
+               ident_cfg.cfg = tf_ident_p4;
+               ident_cfg.shadow_copy = shadow_copy;
+               ident_cfg.resources = resources;
+               rc = tf_ident_bind(tfp, &ident_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Identifier initialization failure\n");
+                       goto fail;
+               }
+
+               no_rsv_flag = false;
+       }
+
+       rsv_cnt = tf_dev_reservation_check(TF_TBL_TYPE_MAX,
+                                          tf_tbl_p4,
+                                          (uint16_t *)resources->tbl_cnt);
+       if (rsv_cnt) {
+               tbl_cfg.num_elements = TF_TBL_TYPE_MAX;
+               tbl_cfg.cfg = tf_tbl_p4;
+               tbl_cfg.shadow_copy = shadow_copy;
+               tbl_cfg.resources = resources;
+               rc = tf_tbl_bind(tfp, &tbl_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Table initialization failure\n");
+                       goto fail;
+               }
+
+               no_rsv_flag = false;
+       }
+
+       rsv_cnt = tf_dev_reservation_check(TF_TCAM_TBL_TYPE_MAX,
+                                          tf_tcam_p4,
+                                          (uint16_t *)resources->tcam_cnt);
+       if (rsv_cnt) {
+               tcam_cfg.num_elements = TF_TCAM_TBL_TYPE_MAX;
+               tcam_cfg.cfg = tf_tcam_p4;
+               tcam_cfg.shadow_copy = shadow_copy;
+               tcam_cfg.resources = resources;
+#ifdef TF_TCAM_SHARED
+               rc = tf_tcam_shared_bind(tfp, &tcam_cfg);
+#else /* !TF_TCAM_SHARED */
+               rc = tf_tcam_bind(tfp, &tcam_cfg);
+#endif
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "TCAM initialization failure\n");
+                       goto fail;
+               }
+               no_rsv_flag = false;
+       }
+
+       /*
+        * EEM
+        */
+
+       em_cfg.cfg = tf_em_ext_p4;
+       rsv_cnt = tf_dev_reservation_check(TF_EM_TBL_TYPE_MAX,
+                                          em_cfg.cfg,
+                                          (uint16_t *)resources->em_cnt);
+       if (rsv_cnt) {
+               em_cfg.num_elements = TF_EM_TBL_TYPE_MAX;
+               em_cfg.resources = resources;
+               em_cfg.mem_type = TF_EEM_MEM_TYPE_HOST;
+               rc = tf_em_ext_common_bind(tfp, &em_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "EEM initialization failure\n");
+                       goto fail;
+               }
+               no_rsv_flag = false;
+       }
+
+       /*
+        * EM
+        */
+       rsv_cnt = tf_dev_reservation_check(TF_EM_TBL_TYPE_MAX,
+                                          tf_em_int_p4,
+                                          (uint16_t *)resources->em_cnt);
+       if (rsv_cnt) {
+               em_cfg.num_elements = TF_EM_TBL_TYPE_MAX;
+               em_cfg.cfg = tf_em_int_p4;
+               em_cfg.resources = resources;
+               em_cfg.mem_type = 0; /* Not used by EM */
+
+               rc = tf_em_int_bind(tfp, &em_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "EM initialization failure\n");
+                       goto fail;
+               }
+               no_rsv_flag = false;
+       }
+
+       /*
+        * There is no rm reserved for any tables
+        *
+        */
+       if (no_rsv_flag) {
+               TFP_DRV_LOG(ERR,
+                           "No rm reserved for any tables\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * IF_TBL
+        */
+       if_tbl_cfg.num_elements = TF_IF_TBL_TYPE_MAX;
+       if_tbl_cfg.cfg = tf_if_tbl_p4;
+       if_tbl_cfg.shadow_copy = shadow_copy;
+       rc = tf_if_tbl_bind(tfp, &if_tbl_cfg);
        if (rc) {
                TFP_DRV_LOG(ERR,
-                           "Identifier initialization failure\n");
+                           "IF Table initialization failure\n");
                goto fail;
        }
 
-       tbl_cfg.num_elements = TF_TBL_TYPE_MAX;
-       tbl_cfg.cfg = tf_tbl_p4;
-       tbl_cfg.shadow_copy = shadow_copy;
-       tbl_cfg.resources = resources;
-       rc = tf_tbl_bind(tfp, &tbl_cfg);
+       if (!tf_session_is_shared_session(tfs)) {
+               /*
+                * GLOBAL_CFG
+                */
+               global_cfg.num_elements = TF_GLOBAL_CFG_TYPE_MAX;
+               global_cfg.cfg = tf_global_cfg_p4;
+               rc = tf_global_cfg_bind(tfp, &global_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Global Cfg initialization failure\n");
+                       goto fail;
+               }
+       }
+       /* Final function initialization */
+       dev_handle->ops = &tf_dev_ops_p4;
+
+       return 0;
+
+ fail:
+       /* Cleanup of already created modules */
+       frc = tf_dev_unbind_p4(tfp);
+       if (frc)
+               return frc;
+
+       return rc;
+}
+
+/**
+ * Device specific unbind function, WH+
+ *
+ * [in] tfp
+ *   Pointer to TF handle
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on failure.
+ */
+static int
+tf_dev_unbind_p4(struct tf *tfp)
+{
+       int rc = 0;
+       bool fail = false;
+       struct tf_session *tfs;
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* Unbind all the support modules. As this is only done on
+        * close we only report errors as everything has to be cleaned
+        * up regardless.
+        *
+        * In case of residuals TCAMs are cleaned up first as to
+        * invalidate the pipeline in a clean manner.
+        */
+#ifdef TF_TCAM_SHARED
+       rc = tf_tcam_shared_unbind(tfp);
+#else /* !TF_TCAM_SHARED */
+       rc = tf_tcam_unbind(tfp);
+#endif /* TF_TCAM_SHARED */
+       if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Device unbind failed, TCAM\n");
+               fail = true;
+       }
+
+       rc = tf_ident_unbind(tfp);
        if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Device unbind failed, Identifier\n");
+               fail = true;
+       }
+
+       rc = tf_tbl_unbind(tfp);
+       if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Device unbind failed, Table Type\n");
+               fail = true;
+       }
+
+       rc = tf_em_ext_common_unbind(tfp);
+       if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Device unbind failed, EEM\n");
+               fail = true;
+       }
+
+       rc = tf_em_int_unbind(tfp);
+       if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Device unbind failed, EM\n");
+               fail = true;
+       }
+
+       if (!tf_session_is_shared_session(tfs)) {
+               rc = tf_if_tbl_unbind(tfp);
+               if (rc) {
+                       TFP_DRV_LOG(INFO,
+                                   "Device unbind failed, IF Table Type\n");
+                       fail = true;
+               }
+
+               rc = tf_global_cfg_unbind(tfp);
+               if (rc) {
+                       TFP_DRV_LOG(INFO,
+                                   "Device unbind failed, Global Cfg Type\n");
+                       fail = true;
+               }
+       }
+
+       if (fail)
+               return -1;
+
+       return rc;
+}
+
+/**
+ * Device specific bind function, THOR
+ *
+ * [in] tfp
+ *   Pointer to TF handle
+ *
+ * [in] shadow_copy
+ *   Flag controlling shadow copy DB creation
+ *
+ * [in] resources
+ *   Pointer to resource allocation information
+ *
+ * [out] dev_handle
+ *   Device handle
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on parameter or internal failure.
+ */
+static int
+tf_dev_bind_p58(struct tf *tfp,
+               bool shadow_copy,
+               struct tf_session_resources *resources,
+               struct tf_dev_info *dev_handle)
+{
+       int rc;
+       int frc;
+       int rsv_cnt;
+       bool no_rsv_flag = true;
+       struct tf_ident_cfg_parms ident_cfg;
+       struct tf_tbl_cfg_parms tbl_cfg;
+       struct tf_tcam_cfg_parms tcam_cfg;
+       struct tf_em_cfg_parms em_cfg;
+       struct tf_if_tbl_cfg_parms if_tbl_cfg;
+       struct tf_global_cfg_cfg_parms global_cfg;
+       struct tf_session *tfs;
+
+       /* Initial function initialization */
+       dev_handle->ops = &tf_dev_ops_p58_init;
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       rsv_cnt = tf_dev_reservation_check(TF_IDENT_TYPE_MAX,
+                                          tf_ident_p58,
+                                          (uint16_t *)resources->ident_cnt);
+       if (rsv_cnt) {
+               ident_cfg.num_elements = TF_IDENT_TYPE_MAX;
+               ident_cfg.cfg = tf_ident_p58;
+               ident_cfg.shadow_copy = shadow_copy;
+               ident_cfg.resources = resources;
+               rc = tf_ident_bind(tfp, &ident_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Identifier initialization failure\n");
+                       goto fail;
+               }
+               no_rsv_flag = false;
+       }
+
+       rsv_cnt = tf_dev_reservation_check(TF_TBL_TYPE_MAX,
+                                          tf_tbl_p58,
+                                          (uint16_t *)resources->tbl_cnt);
+       if (rsv_cnt) {
+               tbl_cfg.num_elements = TF_TBL_TYPE_MAX;
+               tbl_cfg.cfg = tf_tbl_p58;
+               tbl_cfg.shadow_copy = shadow_copy;
+               tbl_cfg.resources = resources;
+               rc = tf_tbl_bind(tfp, &tbl_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Table initialization failure\n");
+                       goto fail;
+               }
+               no_rsv_flag = false;
+       }
+
+       rsv_cnt = tf_dev_reservation_check(TF_TCAM_TBL_TYPE_MAX,
+                                          tf_tcam_p58,
+                                          (uint16_t *)resources->tcam_cnt);
+       if (rsv_cnt) {
+               tcam_cfg.num_elements = TF_TCAM_TBL_TYPE_MAX;
+               tcam_cfg.cfg = tf_tcam_p58;
+               tcam_cfg.shadow_copy = shadow_copy;
+               tcam_cfg.resources = resources;
+#ifdef TF_TCAM_SHARED
+               rc = tf_tcam_shared_bind(tfp, &tcam_cfg);
+#else /* !TF_TCAM_SHARED */
+               rc = tf_tcam_bind(tfp, &tcam_cfg);
+#endif
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "TCAM initialization failure\n");
+                       goto fail;
+               }
+               no_rsv_flag = false;
+       }
+
+       /*
+        * EM
+        */
+       rsv_cnt = tf_dev_reservation_check(TF_EM_TBL_TYPE_MAX,
+                                          tf_em_int_p58,
+                                          (uint16_t *)resources->em_cnt);
+       if (rsv_cnt) {
+               em_cfg.num_elements = TF_EM_TBL_TYPE_MAX;
+               em_cfg.cfg = tf_em_int_p58;
+               em_cfg.resources = resources;
+               em_cfg.mem_type = 0; /* Not used by EM */
+
+               rc = tf_em_int_bind(tfp, &em_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "EM initialization failure\n");
+                       goto fail;
+               }
+               no_rsv_flag = false;
+       }
+
+       /*
+        * There is no rm reserved for any tables
+        *
+        */
+       if (no_rsv_flag) {
                TFP_DRV_LOG(ERR,
-                           "Table initialization failure\n");
-               goto fail;
+                           "No rm reserved for any tables\n");
+               return -ENOMEM;
        }
 
-       tcam_cfg.num_elements = TF_TCAM_TBL_TYPE_MAX;
-       tcam_cfg.cfg = tf_tcam_p4;
-       tcam_cfg.shadow_copy = shadow_copy;
-       tcam_cfg.resources = resources;
-       rc = tf_tcam_bind(tfp, &tcam_cfg);
+       /*
+        * IF_TBL
+        */
+       if_tbl_cfg.num_elements = TF_IF_TBL_TYPE_MAX;
+       if_tbl_cfg.cfg = tf_if_tbl_p58;
+       if_tbl_cfg.shadow_copy = shadow_copy;
+       rc = tf_if_tbl_bind(tfp, &if_tbl_cfg);
        if (rc) {
                TFP_DRV_LOG(ERR,
-                           "TCAM initialization failure\n");
+                           "IF Table initialization failure\n");
                goto fail;
        }
 
-       dev_handle->type = TF_DEVICE_TYPE_WH;
-       dev_handle->ops = &tf_dev_ops_p4;
+       if (!tf_session_is_shared_session(tfs)) {
+               /*
+                * GLOBAL_CFG
+                */
+               global_cfg.num_elements = TF_GLOBAL_CFG_TYPE_MAX;
+               global_cfg.cfg = tf_global_cfg_p58;
+               rc = tf_global_cfg_bind(tfp, &global_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Global Cfg initialization failure\n");
+                       goto fail;
+               }
+       }
+
+       /* Final function initialization */
+       dev_handle->ops = &tf_dev_ops_p58;
 
        return 0;
 
  fail:
        /* Cleanup of already created modules */
-       frc = dev_unbind_p4(tfp);
+       frc = tf_dev_unbind_p58(tfp);
        if (frc)
                return frc;
 
@@ -93,7 +519,7 @@ dev_bind_p4(struct tf *tfp,
 }
 
 /**
- * Device specific unbind function, WH+
+ * Device specific unbind function, THOR
  *
  * [in] tfp
  *   Pointer to TF handle
@@ -103,36 +529,72 @@ dev_bind_p4(struct tf *tfp,
  *   - (-EINVAL) on failure.
  */
 static int
-dev_unbind_p4(struct tf *tfp)
+tf_dev_unbind_p58(struct tf *tfp)
 {
        int rc = 0;
        bool fail = false;
+       struct tf_session *tfs;
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
 
        /* Unbind all the support modules. As this is only done on
         * close we only report errors as everything has to be cleaned
         * up regardless.
+        *
+        * In case of residuals TCAMs are cleaned up first as to
+        * invalidate the pipeline in a clean manner.
         */
+#ifdef TF_TCAM_SHARED
+       rc = tf_tcam_shared_unbind(tfp);
+#else /* !TF_TCAM_SHARED */
+       rc = tf_tcam_unbind(tfp);
+#endif /* TF_TCAM_SHARED */
+       if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Device unbind failed, TCAM\n");
+               fail = true;
+       }
+
        rc = tf_ident_unbind(tfp);
        if (rc) {
-               TFP_DRV_LOG(ERR,
+               TFP_DRV_LOG(INFO,
                            "Device unbind failed, Identifier\n");
                fail = true;
        }
 
        rc = tf_tbl_unbind(tfp);
        if (rc) {
-               TFP_DRV_LOG(ERR,
+               TFP_DRV_LOG(INFO,
                            "Device unbind failed, Table Type\n");
                fail = true;
        }
 
-       rc = tf_tcam_unbind(tfp);
+       rc = tf_em_int_unbind(tfp);
+       if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Device unbind failed, EM\n");
+               fail = true;
+       }
+
+       rc = tf_if_tbl_unbind(tfp);
        if (rc) {
                TFP_DRV_LOG(ERR,
-                           "Device unbind failed, TCAM\n");
+                           "Device unbind failed, IF Table Type\n");
                fail = true;
        }
 
+       if (!tf_session_is_shared_session(tfs)) {
+               rc = tf_global_cfg_unbind(tfp);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Device unbind failed, Global Cfg Type\n");
+                       fail = true;
+               }
+       }
+
        if (fail)
                return -1;
 
@@ -140,18 +602,26 @@ dev_unbind_p4(struct tf *tfp)
 }
 
 int
-dev_bind(struct tf *tfp __rte_unused,
-        enum tf_device_type type,
-        bool shadow_copy,
-        struct tf_session_resources *resources,
-        struct tf_dev_info *dev_handle)
+tf_dev_bind(struct tf *tfp __rte_unused,
+           enum tf_device_type type,
+           bool shadow_copy,
+           struct tf_session_resources *resources,
+           struct tf_dev_info *dev_handle)
 {
        switch (type) {
        case TF_DEVICE_TYPE_WH:
-               return dev_bind_p4(tfp,
-                                  shadow_copy,
-                                  resources,
-                                  dev_handle);
+       case TF_DEVICE_TYPE_SR:
+               dev_handle->type = type;
+               return tf_dev_bind_p4(tfp,
+                                     shadow_copy,
+                                     resources,
+                                     dev_handle);
+       case TF_DEVICE_TYPE_THOR:
+               dev_handle->type = type;
+               return tf_dev_bind_p58(tfp,
+                                      shadow_copy,
+                                      resources,
+                                      dev_handle);
        default:
                TFP_DRV_LOG(ERR,
                            "No such device\n");
@@ -160,12 +630,36 @@ dev_bind(struct tf *tfp __rte_unused,
 }
 
 int
-dev_unbind(struct tf *tfp,
-          struct tf_dev_info *dev_handle)
+tf_dev_bind_ops(enum tf_device_type type,
+               struct tf_dev_info *dev_handle)
+{
+       switch (type) {
+       case TF_DEVICE_TYPE_WH:
+       case TF_DEVICE_TYPE_SR:
+               dev_handle->ops = &tf_dev_ops_p4_init;
+               break;
+       case TF_DEVICE_TYPE_THOR:
+               dev_handle->ops = &tf_dev_ops_p58_init;
+               break;
+       default:
+               TFP_DRV_LOG(ERR,
+                           "No such device\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+int
+tf_dev_unbind(struct tf *tfp,
+             struct tf_dev_info *dev_handle)
 {
        switch (dev_handle->type) {
        case TF_DEVICE_TYPE_WH:
-               return dev_unbind_p4(tfp);
+       case TF_DEVICE_TYPE_SR:
+               return tf_dev_unbind_p4(tfp);
+       case TF_DEVICE_TYPE_THOR:
+               return tf_dev_unbind_p58(tfp);
        default:
                TFP_DRV_LOG(ERR,
                            "No such device\n");