net/bnxt: update multi device design
[dpdk.git] / drivers / net / bnxt / tf_core / tf_rm_new.c
index 51bb9ba..7cadb23 100644 (file)
@@ -3,20 +3,18 @@
  * All rights reserved.
  */
 
+#include <string.h>
+
 #include <rte_common.h>
 
-#include "tf_rm_new.h"
+#include <cfa_resource_types.h>
 
-/**
- * Resource query single entry. Used when accessing HCAPI RM on the
- * firmware.
- */
-struct tf_rm_query_entry {
-       /** Minimum guaranteed number of elements */
-       uint16_t min;
-       /** Maximum non-guaranteed number of elements */
-       uint16_t max;
-};
+#include "tf_rm_new.h"
+#include "tf_util.h"
+#include "tf_session.h"
+#include "tf_device.h"
+#include "tfp.h"
+#include "tf_msg.h"
 
 /**
  * Generic RM Element data type that an RM DB is build upon.
@@ -27,7 +25,7 @@ struct tf_rm_element {
         * hcapi_type can be ignored. If Null then the element is not
         * valid for the device.
         */
-       enum tf_rm_elem_cfg_type type;
+       enum tf_rm_elem_cfg_type cfg_type;
 
        /**
         * HCAPI RM Type for the element.
@@ -50,53 +48,435 @@ struct tf_rm_element {
 /**
  * TF RM DB definition
  */
-struct tf_rm_db {
+struct tf_rm_new_db {
+       /**
+        * Number of elements in the DB
+        */
+       uint16_t num_entries;
+
+       /**
+        * Direction this DB controls.
+        */
+       enum tf_dir dir;
+
        /**
         * The DB consists of an array of elements
         */
        struct tf_rm_element *db;
 };
 
+
+/**
+ * Resource Manager Adjust of base index definitions.
+ */
+enum tf_rm_adjust_type {
+       TF_RM_ADJUST_ADD_BASE, /**< Adds base to the index */
+       TF_RM_ADJUST_RM_BASE   /**< Removes base from the index */
+};
+
+/**
+ * Adjust an index according to the allocation information.
+ *
+ * All resources are controlled in a 0 based pool. Some resources, by
+ * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
+ * need to be adjusted before they are handed out.
+ *
+ * [in] db
+ *   Pointer to the db, used for the lookup
+ *
+ * [in] action
+ *   Adjust action
+ *
+ * [in] db_index
+ *   DB index for the element type
+ *
+ * [in] index
+ *   Index to convert
+ *
+ * [out] adj_index
+ *   Adjusted index
+ *
+ * Returns:
+ *     0          - Success
+ *   - EOPNOTSUPP - Operation not supported
+ */
+static int
+tf_rm_adjust_index(struct tf_rm_element *db,
+                  enum tf_rm_adjust_type action,
+                  uint32_t db_index,
+                  uint32_t index,
+                  uint32_t *adj_index)
+{
+       int rc = 0;
+       uint32_t base_index;
+
+       base_index = db[db_index].alloc.entry.start;
+
+       switch (action) {
+       case TF_RM_ADJUST_RM_BASE:
+               *adj_index = index - base_index;
+               break;
+       case TF_RM_ADJUST_ADD_BASE:
+               *adj_index = index + base_index;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return rc;
+}
+
 int
-tf_rm_create_db(struct tf *tfp __rte_unused,
-               struct tf_rm_create_db_parms *parms __rte_unused)
+tf_rm_create_db(struct tf *tfp,
+               struct tf_rm_create_db_parms *parms)
 {
+       int rc;
+       int i;
+       struct tf_session *tfs;
+       struct tf_dev_info *dev;
+       uint16_t max_types;
+       struct tfp_calloc_parms cparms;
+       struct tf_rm_resc_req_entry *query;
+       enum tf_rm_resc_resv_strategy resv_strategy;
+       struct tf_rm_resc_req_entry *req;
+       struct tf_rm_resc_entry *resv;
+       struct tf_rm_new_db *rm_db;
+       struct tf_rm_element *db;
+       uint32_t pool_size;
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* Retrieve device information */
+       rc = tf_session_get_device(tfs, &dev);
+       if (rc)
+               return rc;
+
+       /* Need device max number of elements for the RM QCAPS */
+       rc = dev->ops->tf_dev_get_max_types(tfp, &max_types);
+       if (rc)
+               return rc;
+
+       cparms.nitems = max_types;
+       cparms.size = sizeof(struct tf_rm_resc_req_entry);
+       cparms.alignment = 0;
+       rc = tfp_calloc(&cparms);
+       if (rc)
+               return rc;
+
+       query = (struct tf_rm_resc_req_entry *)cparms.mem_va;
+
+       /* Get Firmware Capabilities */
+       rc = tf_msg_session_resc_qcaps(tfp,
+                                      parms->dir,
+                                      max_types,
+                                      query,
+                                      &resv_strategy);
+       if (rc)
+               return rc;
+
+       /* Process capabilities against db requirements */
+
+       /* Alloc request, alignment already set */
+       cparms.nitems = parms->num_elements;
+       cparms.size = sizeof(struct tf_rm_resc_req_entry);
+       rc = tfp_calloc(&cparms);
+       if (rc)
+               return rc;
+       req = (struct tf_rm_resc_req_entry *)cparms.mem_va;
+
+       /* Alloc reservation, alignment and nitems already set */
+       cparms.size = sizeof(struct tf_rm_resc_entry);
+       rc = tfp_calloc(&cparms);
+       if (rc)
+               return rc;
+       resv = (struct tf_rm_resc_entry *)cparms.mem_va;
+
+       /* Build the request */
+       for (i = 0; i < parms->num_elements; i++) {
+               /* Skip any non HCAPI cfg elements */
+               if (parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI) {
+                       req[i].type = parms->cfg[i].hcapi_type;
+                       /* Check that we can get the full amount allocated */
+                       if (parms->alloc_num[i] <=
+                           query[parms->cfg[i].hcapi_type].max) {
+                               req[i].min = parms->alloc_num[i];
+                               req[i].max = parms->alloc_num[i];
+                       } else {
+                               TFP_DRV_LOG(ERR,
+                                           "%s: Resource failure, type:%d\n",
+                                           tf_dir_2_str(parms->dir),
+                                           parms->cfg[i].hcapi_type);
+                               TFP_DRV_LOG(ERR,
+                                       "req:%d, avail:%d\n",
+                                       parms->alloc_num[i],
+                                       query[parms->cfg[i].hcapi_type].max);
+                               return -EINVAL;
+                       }
+               } else {
+                       /* Skip the element */
+                       req[i].type = CFA_RESOURCE_TYPE_INVALID;
+               }
+       }
+
+       rc = tf_msg_session_resc_alloc(tfp,
+                                      parms->dir,
+                                      parms->num_elements,
+                                      req,
+                                      resv);
+       if (rc)
+               return rc;
+
+       /* Build the RM DB per the request */
+       cparms.nitems = 1;
+       cparms.size = sizeof(struct tf_rm_new_db);
+       rc = tfp_calloc(&cparms);
+       if (rc)
+               return rc;
+       rm_db = (void *)cparms.mem_va;
+
+       /* Build the DB within RM DB */
+       cparms.nitems = parms->num_elements;
+       cparms.size = sizeof(struct tf_rm_element);
+       rc = tfp_calloc(&cparms);
+       if (rc)
+               return rc;
+       rm_db->db = (struct tf_rm_element *)cparms.mem_va;
+
+       db = rm_db->db;
+       for (i = 0; i < parms->num_elements; i++) {
+               /* If allocation failed for a single entry the DB
+                * creation is considered a failure.
+                */
+               if (parms->alloc_num[i] != resv[i].stride) {
+                       TFP_DRV_LOG(ERR,
+                                   "%s: Alloc failed, type:%d\n",
+                                   tf_dir_2_str(parms->dir),
+                                   i);
+                       TFP_DRV_LOG(ERR,
+                                   "req:%d, alloc:%d\n",
+                                   parms->alloc_num[i],
+                                   resv[i].stride);
+                       goto fail;
+               }
+
+               db[i].cfg_type = parms->cfg[i].cfg_type;
+               db[i].hcapi_type = parms->cfg[i].hcapi_type;
+               db[i].alloc.entry.start = resv[i].start;
+               db[i].alloc.entry.stride = resv[i].stride;
+
+               /* Create pool */
+               pool_size = (BITALLOC_SIZEOF(resv[i].stride) /
+                            sizeof(struct bitalloc));
+               /* Alloc request, alignment already set */
+               cparms.nitems = pool_size;
+               cparms.size = sizeof(struct bitalloc);
+               rc = tfp_calloc(&cparms);
+               if (rc)
+                       return rc;
+               db[i].pool = (struct bitalloc *)cparms.mem_va;
+       }
+
+       rm_db->num_entries = i;
+       rm_db->dir = parms->dir;
+       parms->rm_db = (void *)rm_db;
+
+       tfp_free((void *)req);
+       tfp_free((void *)resv);
+
        return 0;
+
+ fail:
+       tfp_free((void *)req);
+       tfp_free((void *)resv);
+       tfp_free((void *)db->pool);
+       tfp_free((void *)db);
+       tfp_free((void *)rm_db);
+       parms->rm_db = NULL;
+
+       return -EINVAL;
 }
 
 int
 tf_rm_free_db(struct tf *tfp __rte_unused,
-             struct tf_rm_free_db_parms *parms __rte_unused)
+             struct tf_rm_free_db_parms *parms)
 {
-       return 0;
+       int rc = 0;
+       int i;
+       struct tf_rm_new_db *rm_db;
+
+       /* Traverse the DB and clear each pool.
+        * NOTE:
+        *   Firmware is not cleared. It will be cleared on close only.
+        */
+       rm_db = (struct tf_rm_new_db *)parms->rm_db;
+       for (i = 0; i < rm_db->num_entries; i++)
+               tfp_free((void *)rm_db->db->pool);
+
+       tfp_free((void *)parms->rm_db);
+
+       return rc;
 }
 
 int
-tf_rm_allocate(struct tf_rm_allocate_parms *parms __rte_unused)
+tf_rm_allocate(struct tf_rm_allocate_parms *parms)
 {
-       return 0;
+       int rc = 0;
+       int id;
+       struct tf_rm_new_db *rm_db;
+       enum tf_rm_elem_cfg_type cfg_type;
+
+       if (parms == NULL || parms->rm_db == NULL)
+               return -EINVAL;
+
+       rm_db = (struct tf_rm_new_db *)parms->rm_db;
+       cfg_type = rm_db->db[parms->db_index].cfg_type;
+
+       /* Bail out if not controlled by RM */
+       if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
+           cfg_type != TF_RM_ELEM_CFG_PRIVATE)
+               return -ENOTSUP;
+
+       id = ba_alloc(rm_db->db[parms->db_index].pool);
+       if (id == BA_FAIL) {
+               TFP_DRV_LOG(ERR,
+                           "%s: Allocation failed, rc:%s\n",
+                           tf_dir_2_str(rm_db->dir),
+                           strerror(-rc));
+               return -ENOMEM;
+       }
+
+       /* Adjust for any non zero start value */
+       rc = tf_rm_adjust_index(rm_db->db,
+                               TF_RM_ADJUST_ADD_BASE,
+                               parms->db_index,
+                               id,
+                               parms->index);
+       if (rc) {
+               TFP_DRV_LOG(ERR,
+                           "%s: Alloc adjust of base index failed, rc:%s\n",
+                           tf_dir_2_str(rm_db->dir),
+                           strerror(-rc));
+               return -1;
+       }
+
+       return rc;
 }
 
 int
-tf_rm_free(struct tf_rm_free_parms *parms __rte_unused)
+tf_rm_free(struct tf_rm_free_parms *parms)
 {
-       return 0;
+       int rc = 0;
+       uint32_t adj_index;
+       struct tf_rm_new_db *rm_db;
+       enum tf_rm_elem_cfg_type cfg_type;
+
+       if (parms == NULL || parms->rm_db == NULL)
+               return -EINVAL;
+
+       rm_db = (struct tf_rm_new_db *)parms->rm_db;
+       cfg_type = rm_db->db[parms->db_index].cfg_type;
+
+       /* Bail out if not controlled by RM */
+       if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
+           cfg_type != TF_RM_ELEM_CFG_PRIVATE)
+               return -ENOTSUP;
+
+       /* Adjust for any non zero start value */
+       rc = tf_rm_adjust_index(rm_db->db,
+                               TF_RM_ADJUST_RM_BASE,
+                               parms->db_index,
+                               parms->index,
+                               &adj_index);
+       if (rc)
+               return rc;
+
+       rc = ba_free(rm_db->db[parms->db_index].pool, adj_index);
+       /* No logging direction matters and that is not available here */
+       if (rc)
+               return rc;
+
+       return rc;
 }
 
 int
-tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms __rte_unused)
+tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)
 {
-       return 0;
+       int rc = 0;
+       uint32_t adj_index;
+       struct tf_rm_new_db *rm_db;
+       enum tf_rm_elem_cfg_type cfg_type;
+
+       if (parms == NULL || parms->rm_db == NULL)
+               return -EINVAL;
+
+       rm_db = (struct tf_rm_new_db *)parms->rm_db;
+       cfg_type = rm_db->db[parms->db_index].cfg_type;
+
+       /* Bail out if not controlled by RM */
+       if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
+           cfg_type != TF_RM_ELEM_CFG_PRIVATE)
+               return -ENOTSUP;
+
+       /* Adjust for any non zero start value */
+       rc = tf_rm_adjust_index(rm_db->db,
+                               TF_RM_ADJUST_RM_BASE,
+                               parms->db_index,
+                               parms->index,
+                               &adj_index);
+       if (rc)
+               return rc;
+
+       *parms->allocated = ba_inuse(rm_db->db[parms->db_index].pool,
+                                    adj_index);
+
+       return rc;
 }
 
 int
-tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms __rte_unused)
+tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)
 {
-       return 0;
+       int rc = 0;
+       struct tf_rm_new_db *rm_db;
+       enum tf_rm_elem_cfg_type cfg_type;
+
+       if (parms == NULL || parms->rm_db == NULL)
+               return -EINVAL;
+
+       rm_db = (struct tf_rm_new_db *)parms->rm_db;
+       cfg_type = rm_db->db[parms->db_index].cfg_type;
+
+       /* Bail out if not controlled by RM */
+       if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
+           cfg_type != TF_RM_ELEM_CFG_PRIVATE)
+               return -ENOTSUP;
+
+       parms->info = &rm_db->db[parms->db_index].alloc;
+
+       return rc;
 }
 
 int
-tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms __rte_unused)
+tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)
 {
-       return 0;
+       int rc = 0;
+       struct tf_rm_new_db *rm_db;
+       enum tf_rm_elem_cfg_type cfg_type;
+
+       if (parms == NULL || parms->rm_db == NULL)
+               return -EINVAL;
+
+       rm_db = (struct tf_rm_new_db *)parms->rm_db;
+       cfg_type = rm_db->db[parms->db_index].cfg_type;
+
+       /* Bail out if not controlled by RM */
+       if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
+           cfg_type != TF_RM_ELEM_CFG_PRIVATE)
+               return -ENOTSUP;
+
+       *parms->hcapi_type = rm_db->db[parms->db_index].hcapi_type;
+
+       return rc;
 }