+static int
+ice_fdir_counter_pool_add(__rte_unused struct ice_pf *pf,
+ struct ice_fdir_counter_pool_container *container,
+ uint32_t index_start,
+ uint32_t len)
+{
+ struct ice_fdir_counter_pool *pool;
+ uint32_t i;
+ int ret = 0;
+
+ pool = rte_zmalloc("ice_fdir_counter_pool",
+ sizeof(*pool) +
+ sizeof(struct ice_fdir_counter) * len,
+ 0);
+ if (!pool) {
+ PMD_INIT_LOG(ERR,
+ "Failed to allocate memory for fdir counter pool");
+ return -ENOMEM;
+ }
+
+ TAILQ_INIT(&pool->counter_list);
+ TAILQ_INSERT_TAIL(&container->pool_list, pool, next);
+
+ for (i = 0; i < len; i++) {
+ struct ice_fdir_counter *counter = &pool->counters[i];
+
+ counter->hw_index = index_start + i;
+ TAILQ_INSERT_TAIL(&pool->counter_list, counter, next);
+ }
+
+ if (container->index_free == ICE_FDIR_COUNTER_MAX_POOL_SIZE) {
+ PMD_INIT_LOG(ERR, "FDIR counter pool is full");
+ ret = -EINVAL;
+ goto free_pool;
+ }
+
+ container->pools[container->index_free++] = pool;
+ return 0;
+
+free_pool:
+ rte_free(pool);
+ return ret;
+}
+
+static int
+ice_fdir_counter_init(struct ice_pf *pf)
+{
+ struct ice_hw *hw = ICE_PF_TO_HW(pf);
+ struct ice_fdir_info *fdir_info = &pf->fdir;
+ struct ice_fdir_counter_pool_container *container =
+ &fdir_info->counter;
+ uint32_t cnt_index, len;
+ int ret;
+
+ TAILQ_INIT(&container->pool_list);
+
+ cnt_index = ICE_FDIR_COUNTER_INDEX(hw->fd_ctr_base);
+ len = ICE_FDIR_COUNTERS_PER_BLOCK;
+
+ ret = ice_fdir_counter_pool_add(pf, container, cnt_index, len);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to add fdir pool to container");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+ice_fdir_counter_release(struct ice_pf *pf)
+{
+ struct ice_fdir_info *fdir_info = &pf->fdir;
+ struct ice_fdir_counter_pool_container *container =
+ &fdir_info->counter;
+ uint8_t i;
+
+ for (i = 0; i < container->index_free; i++) {
+ rte_free(container->pools[i]);
+ container->pools[i] = NULL;
+ }
+
+ TAILQ_INIT(&container->pool_list);
+ container->index_free = 0;
+
+ return 0;
+}
+
+static struct ice_fdir_counter *
+ice_fdir_counter_shared_search(struct ice_fdir_counter_pool_container
+ *container,
+ uint32_t id)
+{
+ struct ice_fdir_counter_pool *pool;
+ struct ice_fdir_counter *counter;
+ int i;
+
+ TAILQ_FOREACH(pool, &container->pool_list, next) {
+ for (i = 0; i < ICE_FDIR_COUNTERS_PER_BLOCK; i++) {
+ counter = &pool->counters[i];
+
+ if (counter->shared &&
+ counter->ref_cnt &&
+ counter->id == id)
+ return counter;
+ }
+ }
+
+ return NULL;
+}
+
+static struct ice_fdir_counter *
+ice_fdir_counter_alloc(struct ice_pf *pf, uint32_t shared, uint32_t id)
+{
+ struct ice_hw *hw = ICE_PF_TO_HW(pf);
+ struct ice_fdir_info *fdir_info = &pf->fdir;
+ struct ice_fdir_counter_pool_container *container =
+ &fdir_info->counter;
+ struct ice_fdir_counter_pool *pool = NULL;
+ struct ice_fdir_counter *counter_free = NULL;
+
+ if (shared) {
+ counter_free = ice_fdir_counter_shared_search(container, id);
+ if (counter_free) {
+ if (counter_free->ref_cnt + 1 == 0) {
+ rte_errno = E2BIG;
+ return NULL;
+ }
+ counter_free->ref_cnt++;
+ return counter_free;
+ }
+ }
+
+ TAILQ_FOREACH(pool, &container->pool_list, next) {
+ counter_free = TAILQ_FIRST(&pool->counter_list);
+ if (counter_free)
+ break;
+ counter_free = NULL;
+ }
+
+ if (!counter_free) {
+ PMD_DRV_LOG(ERR, "No free counter found\n");
+ return NULL;
+ }
+
+ counter_free->shared = shared;
+ counter_free->id = id;
+ counter_free->ref_cnt = 1;
+ counter_free->pool = pool;
+
+ /* reset statistic counter value */
+ ICE_WRITE_REG(hw, GLSTAT_FD_CNT0H(counter_free->hw_index), 0);
+ ICE_WRITE_REG(hw, GLSTAT_FD_CNT0L(counter_free->hw_index), 0);
+
+ TAILQ_REMOVE(&pool->counter_list, counter_free, next);
+ if (TAILQ_EMPTY(&pool->counter_list)) {
+ TAILQ_REMOVE(&container->pool_list, pool, next);
+ TAILQ_INSERT_TAIL(&container->pool_list, pool, next);
+ }
+
+ return counter_free;
+}
+
+static void
+ice_fdir_counter_free(__rte_unused struct ice_pf *pf,
+ struct ice_fdir_counter *counter)
+{
+ if (!counter)
+ return;
+
+ if (--counter->ref_cnt == 0) {
+ struct ice_fdir_counter_pool *pool = counter->pool;
+
+ TAILQ_INSERT_TAIL(&pool->counter_list, counter, next);
+ }
+}
+
+static int
+ice_fdir_init_filter_list(struct ice_pf *pf)
+{
+ struct rte_eth_dev *dev = pf->adapter->eth_dev;
+ struct ice_fdir_info *fdir_info = &pf->fdir;
+ char fdir_hash_name[RTE_HASH_NAMESIZE];
+ int ret;
+
+ struct rte_hash_parameters fdir_hash_params = {
+ .name = fdir_hash_name,
+ .entries = ICE_MAX_FDIR_FILTER_NUM,
+ .key_len = sizeof(struct ice_fdir_fltr_pattern),
+ .hash_func = rte_hash_crc,
+ .hash_func_init_val = 0,
+ .socket_id = rte_socket_id(),
+ .extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE,
+ };
+
+ /* Initialize hash */
+ snprintf(fdir_hash_name, RTE_HASH_NAMESIZE,
+ "fdir_%s", dev->device->name);
+ fdir_info->hash_table = rte_hash_create(&fdir_hash_params);
+ if (!fdir_info->hash_table) {
+ PMD_INIT_LOG(ERR, "Failed to create fdir hash table!");
+ return -EINVAL;
+ }
+ fdir_info->hash_map = rte_zmalloc("ice_fdir_hash_map",
+ sizeof(*fdir_info->hash_map) *
+ ICE_MAX_FDIR_FILTER_NUM,
+ 0);
+ if (!fdir_info->hash_map) {
+ PMD_INIT_LOG(ERR,
+ "Failed to allocate memory for fdir hash map!");
+ ret = -ENOMEM;
+ goto err_fdir_hash_map_alloc;
+ }
+ return 0;
+
+err_fdir_hash_map_alloc:
+ rte_hash_free(fdir_info->hash_table);
+
+ return ret;
+}
+
+static void
+ice_fdir_release_filter_list(struct ice_pf *pf)
+{
+ struct ice_fdir_info *fdir_info = &pf->fdir;
+
+ if (fdir_info->hash_map)
+ rte_free(fdir_info->hash_map);
+ if (fdir_info->hash_table)
+ rte_hash_free(fdir_info->hash_table);
+
+ fdir_info->hash_map = NULL;
+ fdir_info->hash_table = NULL;
+}
+