+/**
+ * This function allocates new empty Three-level table.
+ *
+ * @param type
+ * The l3t can set as word, double word, quad word or pointer with index.
+ *
+ * @return
+ * - Pointer to the allocated l3t.
+ * - NULL on error. Not enough memory, or invalid arguments.
+ */
+struct mlx5_l3t_tbl *mlx5_l3t_create(enum mlx5_l3t_type type);
+
+/**
+ * This function destroys Three-level table.
+ *
+ * @param tbl
+ * Pointer to the l3t.
+ */
+void mlx5_l3t_destroy(struct mlx5_l3t_tbl *tbl);
+
+/**
+ * This function gets the index entry from Three-level table.
+ *
+ * @param tbl
+ * Pointer to the l3t.
+ * @param idx
+ * Index to the entry.
+ * @param data
+ * Pointer to the memory which saves the entry data.
+ * When function call returns 0, data contains the entry data get from
+ * l3t.
+ * When function call returns -1, data is not modified.
+ *
+ * @return
+ * 0 if success, -1 on error.
+ */
+
+int32_t mlx5_l3t_get_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
+ union mlx5_l3t_data *data);
+
+/**
+ * This function gets the index entry from Three-level table.
+ *
+ * If the index entry is not available, allocate new one by callback
+ * function and fill in the entry.
+ *
+ * @param tbl
+ * Pointer to the l3t.
+ * @param idx
+ * Index to the entry.
+ * @param data
+ * Pointer to the memory which saves the entry data.
+ * When function call returns 0, data contains the entry data get from
+ * l3t.
+ * When function call returns -1, data is not modified.
+ * @param cb
+ * Callback function to allocate new data.
+ * @param ctx
+ * Context for callback function.
+ *
+ * @return
+ * 0 if success, -1 on error.
+ */
+
+int32_t mlx5_l3t_prepare_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
+ union mlx5_l3t_data *data,
+ mlx5_l3t_alloc_callback_fn cb, void *ctx);
+
+/**
+ * This function decreases and clear index entry if reference
+ * counter is 0 from Three-level table.
+ *
+ * @param tbl
+ * Pointer to the l3t.
+ * @param idx
+ * Index to the entry.
+ *
+ * @return
+ * The remaining reference count, 0 means entry be cleared, -1 on error.
+ */
+int32_t mlx5_l3t_clear_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx);
+
+/**
+ * This function sets the index entry to Three-level table.
+ * If the entry is already set, the EEXIST errno will be given, and
+ * the set data will be filled to the data.
+ *
+ * @param tbl[in]
+ * Pointer to the l3t.
+ * @param idx[in]
+ * Index to the entry.
+ * @param data[in/out]
+ * Pointer to the memory which contains the entry data save to l3t.
+ * If the entry is already set, the set data will be filled.
+ *
+ * @return
+ * 0 if success, -1 on error.
+ */
+int32_t mlx5_l3t_set_entry(struct mlx5_l3t_tbl *tbl, uint32_t idx,
+ union mlx5_l3t_data *data);
+
+static inline void *
+mlx5_l3t_get_next(struct mlx5_l3t_tbl *tbl, uint32_t *pos)
+{
+ struct mlx5_l3t_level_tbl *g_tbl, *m_tbl;
+ uint32_t i, j, k, g_start, m_start, e_start;
+ uint32_t idx = *pos;
+ void *e_tbl;
+ struct mlx5_l3t_entry_word *w_e_tbl;
+ struct mlx5_l3t_entry_dword *dw_e_tbl;
+ struct mlx5_l3t_entry_qword *qw_e_tbl;
+ struct mlx5_l3t_entry_ptr *ptr_e_tbl;
+
+ if (!tbl)
+ return NULL;
+ g_tbl = tbl->tbl;
+ if (!g_tbl)
+ return NULL;
+ g_start = (idx >> MLX5_L3T_GT_OFFSET) & MLX5_L3T_GT_MASK;
+ m_start = (idx >> MLX5_L3T_MT_OFFSET) & MLX5_L3T_MT_MASK;
+ e_start = idx & MLX5_L3T_ET_MASK;
+ for (i = g_start; i < MLX5_L3T_GT_SIZE; i++) {
+ m_tbl = g_tbl->tbl[i];
+ if (!m_tbl) {
+ /* Jump to new table, reset the sub table start. */
+ m_start = 0;
+ e_start = 0;
+ continue;
+ }
+ for (j = m_start; j < MLX5_L3T_MT_SIZE; j++) {
+ if (!m_tbl->tbl[j]) {
+ /*
+ * Jump to new table, reset the sub table
+ * start.
+ */
+ e_start = 0;
+ continue;
+ }
+ e_tbl = m_tbl->tbl[j];
+ switch (tbl->type) {
+ case MLX5_L3T_TYPE_WORD:
+ w_e_tbl = (struct mlx5_l3t_entry_word *)e_tbl;
+ for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
+ if (!w_e_tbl->entry[k].data)
+ continue;
+ *pos = (i << MLX5_L3T_GT_OFFSET) |
+ (j << MLX5_L3T_MT_OFFSET) | k;
+ return (void *)&w_e_tbl->entry[k].data;
+ }
+ break;
+ case MLX5_L3T_TYPE_DWORD:
+ dw_e_tbl = (struct mlx5_l3t_entry_dword *)e_tbl;
+ for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
+ if (!dw_e_tbl->entry[k].data)
+ continue;
+ *pos = (i << MLX5_L3T_GT_OFFSET) |
+ (j << MLX5_L3T_MT_OFFSET) | k;
+ return (void *)&dw_e_tbl->entry[k].data;
+ }
+ break;
+ case MLX5_L3T_TYPE_QWORD:
+ qw_e_tbl = (struct mlx5_l3t_entry_qword *)e_tbl;
+ for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
+ if (!qw_e_tbl->entry[k].data)
+ continue;
+ *pos = (i << MLX5_L3T_GT_OFFSET) |
+ (j << MLX5_L3T_MT_OFFSET) | k;
+ return (void *)&qw_e_tbl->entry[k].data;
+ }
+ break;
+ default:
+ ptr_e_tbl = (struct mlx5_l3t_entry_ptr *)e_tbl;
+ for (k = e_start; k < MLX5_L3T_ET_SIZE; k++) {
+ if (!ptr_e_tbl->entry[k].data)
+ continue;
+ *pos = (i << MLX5_L3T_GT_OFFSET) |
+ (j << MLX5_L3T_MT_OFFSET) | k;
+ return ptr_e_tbl->entry[k].data;
+ }
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+