+ int rc;
+ struct tf_session *tfs;
+ struct tf_dev_info *dev;
+ struct tf_rm_is_allocated_parms aparms;
+ struct tf_rm_free_parms fparms;
+ struct tf_rm_get_hcapi_parms hparms;
+ uint16_t num_slice_per_row = 1;
+ int allocated = 0;
+ struct tf_shadow_tcam_remove_parms shparms;
+
+ TF_CHECK_PARMS2(tfp, parms);
+
+ if (!init) {
+ TFP_DRV_LOG(ERR,
+ "%s: No TCAM DBs created\n",
+ tf_dir_2_str(parms->dir));
+ return -EINVAL;
+ }
+
+ /* Retrieve the session information */
+ rc = tf_session_get_session_internal(tfp, &tfs);
+ if (rc)
+ return rc;
+
+ /* Retrieve the device information */
+ rc = tf_session_get_device(tfs, &dev);
+ if (rc)
+ return rc;
+
+ if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
+ rc = -EOPNOTSUPP;
+ TFP_DRV_LOG(ERR,
+ "%s: Operation not supported, rc:%s\n",
+ tf_dir_2_str(parms->dir),
+ strerror(-rc));
+ return rc;
+ }
+
+ /* Need to retrieve row size etc */
+ rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
+ parms->type,
+ 0,
+ &num_slice_per_row);
+ if (rc)
+ return rc;
+
+ /* Check if element is in use */
+ memset(&aparms, 0, sizeof(aparms));
+
+ aparms.rm_db = tcam_db[parms->dir];
+ aparms.db_index = parms->type;
+ aparms.index = parms->idx / num_slice_per_row;
+ aparms.allocated = &allocated;
+ rc = tf_rm_is_allocated(&aparms);
+ if (rc)
+ return rc;
+
+ if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
+ TFP_DRV_LOG(ERR,
+ "%s: Entry already free, type:%d, index:%d\n",
+ tf_dir_2_str(parms->dir),
+ parms->type,
+ parms->idx);
+ return -EINVAL;
+ }
+
+ /*
+ * The Shadow mgmt, if enabled, determines if the entry needs
+ * to be deleted.
+ */
+ if (shadow_init) {
+ shparms.shadow_db = shadow_tcam_db[parms->dir];
+ shparms.fparms = parms;
+ rc = tf_shadow_tcam_remove(&shparms);
+ if (rc) {
+ /*
+ * Should not get here, log it and let the entry be
+ * deleted.
+ */
+ TFP_DRV_LOG(ERR, "%s: Shadow free fail, "
+ "type:%d index:%d deleting the entry.\n",
+ tf_dir_2_str(parms->dir),
+ parms->type,
+ parms->idx);
+ } else {
+ /*
+ * If the entry still has references, just return the
+ * ref count to the caller. No need to remove entry
+ * from rm or hw
+ */
+ if (parms->ref_cnt >= 1)
+ return rc;
+ }
+ }
+
+ /* Free requested element */
+ memset(&fparms, 0, sizeof(fparms));
+ fparms.rm_db = tcam_db[parms->dir];
+ fparms.db_index = parms->type;
+ fparms.index = parms->idx / num_slice_per_row;
+ rc = tf_rm_free(&fparms);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "%s: Free failed, type:%d, index:%d\n",
+ tf_dir_2_str(parms->dir),
+ parms->type,
+ parms->idx);
+ return rc;
+ }
+
+ if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM) {
+ int i;
+
+ for (i = -1; i < 3; i += 3) {
+ aparms.index += i;
+ rc = tf_rm_is_allocated(&aparms);
+ if (rc)
+ return rc;
+
+ if (allocated == TF_RM_ALLOCATED_ENTRY_IN_USE) {
+ /* Free requested element */
+ fparms.index = aparms.index;
+ rc = tf_rm_free(&fparms);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "%s: Free failed, type:%d, "
+ "index:%d\n",
+ tf_dir_2_str(parms->dir),
+ parms->type,
+ fparms.index);
+ return rc;
+ }
+ }
+ }
+ }
+
+ /* Convert TF type to HCAPI RM type */
+ memset(&hparms, 0, sizeof(hparms));
+
+ hparms.rm_db = tcam_db[parms->dir];
+ hparms.db_index = parms->type;
+ hparms.hcapi_type = &parms->hcapi_type;
+
+ rc = tf_rm_get_hcapi_type(&hparms);
+ if (rc)
+ return rc;
+
+ rc = tf_msg_tcam_entry_free(tfp, parms);
+ if (rc) {
+ /* Log error */
+ TFP_DRV_LOG(ERR,
+ "%s: %s: Entry %d free failed, rc:%s\n",
+ tf_dir_2_str(parms->dir),
+ tf_tcam_tbl_2_str(parms->type),
+ parms->idx,
+ strerror(-rc));
+ return rc;
+ }
+