1*bc712f1cSDenis Pryazhennikov /* SPDX-License-Identifier: BSD-3-Clause
2*bc712f1cSDenis Pryazhennikov *
3*bc712f1cSDenis Pryazhennikov * Copyright (c) 2023 Advanced Micro Devices, Inc.
4*bc712f1cSDenis Pryazhennikov */
5*bc712f1cSDenis Pryazhennikov
6*bc712f1cSDenis Pryazhennikov #include <rte_malloc.h>
7*bc712f1cSDenis Pryazhennikov #include <rte_jhash.h>
8*bc712f1cSDenis Pryazhennikov
9*bc712f1cSDenis Pryazhennikov #include "sfc_tbl_meta_cache.h"
10*bc712f1cSDenis Pryazhennikov #include "sfc_debug.h"
11*bc712f1cSDenis Pryazhennikov
12*bc712f1cSDenis Pryazhennikov /* The minimal size of the table meta cache */
13*bc712f1cSDenis Pryazhennikov #define SFC_TBL_META_CACHE_SIZE_MIN 8
14*bc712f1cSDenis Pryazhennikov
15*bc712f1cSDenis Pryazhennikov int
sfc_tbl_meta_cache_ctor(struct rte_hash ** ref_cache)16*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_cache_ctor(struct rte_hash **ref_cache)
17*bc712f1cSDenis Pryazhennikov {
18*bc712f1cSDenis Pryazhennikov size_t cache_size = RTE_MAX((unsigned int)SFC_TBL_META_CACHE_SIZE_MIN,
19*bc712f1cSDenis Pryazhennikov efx_table_supported_num_get());
20*bc712f1cSDenis Pryazhennikov struct rte_hash *cache = NULL;
21*bc712f1cSDenis Pryazhennikov const struct rte_hash_parameters hash_params = {
22*bc712f1cSDenis Pryazhennikov .name = "meta_hash_table",
23*bc712f1cSDenis Pryazhennikov .hash_func = rte_jhash,
24*bc712f1cSDenis Pryazhennikov .entries = cache_size,
25*bc712f1cSDenis Pryazhennikov .socket_id = rte_socket_id(),
26*bc712f1cSDenis Pryazhennikov .key_len = sizeof(efx_table_id_t),
27*bc712f1cSDenis Pryazhennikov };
28*bc712f1cSDenis Pryazhennikov
29*bc712f1cSDenis Pryazhennikov cache = rte_hash_create(&hash_params);
30*bc712f1cSDenis Pryazhennikov if (cache == NULL)
31*bc712f1cSDenis Pryazhennikov return -ENOMEM;
32*bc712f1cSDenis Pryazhennikov
33*bc712f1cSDenis Pryazhennikov *ref_cache = cache;
34*bc712f1cSDenis Pryazhennikov
35*bc712f1cSDenis Pryazhennikov return 0;
36*bc712f1cSDenis Pryazhennikov }
37*bc712f1cSDenis Pryazhennikov
38*bc712f1cSDenis Pryazhennikov static void
sfc_tbl_meta_cache_free(struct sfc_tbl_meta * meta)39*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_cache_free(struct sfc_tbl_meta *meta)
40*bc712f1cSDenis Pryazhennikov {
41*bc712f1cSDenis Pryazhennikov SFC_ASSERT(meta != NULL);
42*bc712f1cSDenis Pryazhennikov
43*bc712f1cSDenis Pryazhennikov rte_free(meta->keys);
44*bc712f1cSDenis Pryazhennikov rte_free(meta->responses);
45*bc712f1cSDenis Pryazhennikov rte_free(meta);
46*bc712f1cSDenis Pryazhennikov }
47*bc712f1cSDenis Pryazhennikov
48*bc712f1cSDenis Pryazhennikov void
sfc_tbl_meta_cache_dtor(struct rte_hash ** ref_cache)49*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_cache_dtor(struct rte_hash **ref_cache)
50*bc712f1cSDenis Pryazhennikov {
51*bc712f1cSDenis Pryazhennikov struct rte_hash *cache = *ref_cache;
52*bc712f1cSDenis Pryazhennikov const void *next_key;
53*bc712f1cSDenis Pryazhennikov uint32_t iter = 0;
54*bc712f1cSDenis Pryazhennikov void *next_meta;
55*bc712f1cSDenis Pryazhennikov
56*bc712f1cSDenis Pryazhennikov if (cache == NULL)
57*bc712f1cSDenis Pryazhennikov return;
58*bc712f1cSDenis Pryazhennikov
59*bc712f1cSDenis Pryazhennikov while (rte_hash_iterate(cache, &next_key, &next_meta, &iter) >= 0)
60*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_cache_free((struct sfc_tbl_meta *)next_meta);
61*bc712f1cSDenis Pryazhennikov
62*bc712f1cSDenis Pryazhennikov rte_hash_free(cache);
63*bc712f1cSDenis Pryazhennikov
64*bc712f1cSDenis Pryazhennikov *ref_cache = NULL;
65*bc712f1cSDenis Pryazhennikov }
66*bc712f1cSDenis Pryazhennikov
67*bc712f1cSDenis Pryazhennikov /**
68*bc712f1cSDenis Pryazhennikov * Table descriptor contains information about the table's
69*bc712f1cSDenis Pryazhennikov * fields that can be associated with both the key and the response.
70*bc712f1cSDenis Pryazhennikov * Save these fields by separating the key from the response in
71*bc712f1cSDenis Pryazhennikov * appropriate places based on their lengths.
72*bc712f1cSDenis Pryazhennikov */
73*bc712f1cSDenis Pryazhennikov static int
sfc_tbl_meta_desc_fields_copy(struct sfc_tbl_meta * meta,efx_nic_t * enp,efx_table_field_descriptor_t * fields,unsigned int total_n_fields)74*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_desc_fields_copy(struct sfc_tbl_meta *meta, efx_nic_t *enp,
75*bc712f1cSDenis Pryazhennikov efx_table_field_descriptor_t *fields,
76*bc712f1cSDenis Pryazhennikov unsigned int total_n_fields)
77*bc712f1cSDenis Pryazhennikov {
78*bc712f1cSDenis Pryazhennikov uint16_t n_key_fields = meta->descriptor.n_key_fields;
79*bc712f1cSDenis Pryazhennikov size_t field_size = sizeof(*fields);
80*bc712f1cSDenis Pryazhennikov unsigned int n_field_descs_written;
81*bc712f1cSDenis Pryazhennikov uint32_t field_offset;
82*bc712f1cSDenis Pryazhennikov int rc;
83*bc712f1cSDenis Pryazhennikov
84*bc712f1cSDenis Pryazhennikov for (n_field_descs_written = 0, field_offset = 0;
85*bc712f1cSDenis Pryazhennikov field_offset < total_n_fields;
86*bc712f1cSDenis Pryazhennikov field_offset += n_field_descs_written) {
87*bc712f1cSDenis Pryazhennikov rc = efx_table_describe(enp, meta->table_id, field_offset, NULL,
88*bc712f1cSDenis Pryazhennikov fields, total_n_fields, &n_field_descs_written);
89*bc712f1cSDenis Pryazhennikov if (rc != 0)
90*bc712f1cSDenis Pryazhennikov return rc;
91*bc712f1cSDenis Pryazhennikov
92*bc712f1cSDenis Pryazhennikov if (field_offset + n_field_descs_written > total_n_fields)
93*bc712f1cSDenis Pryazhennikov return -EINVAL;
94*bc712f1cSDenis Pryazhennikov
95*bc712f1cSDenis Pryazhennikov if (field_offset < n_key_fields &&
96*bc712f1cSDenis Pryazhennikov field_offset + n_field_descs_written > n_key_fields) {
97*bc712f1cSDenis Pryazhennikov /*
98*bc712f1cSDenis Pryazhennikov * Some of the descriptors belong to key,
99*bc712f1cSDenis Pryazhennikov * the other to response.
100*bc712f1cSDenis Pryazhennikov */
101*bc712f1cSDenis Pryazhennikov rte_memcpy(RTE_PTR_ADD(meta->keys, field_offset * field_size),
102*bc712f1cSDenis Pryazhennikov fields, (n_key_fields - field_offset) * field_size);
103*bc712f1cSDenis Pryazhennikov rte_memcpy(meta->responses,
104*bc712f1cSDenis Pryazhennikov RTE_PTR_ADD(fields,
105*bc712f1cSDenis Pryazhennikov (n_key_fields - field_offset) * field_size),
106*bc712f1cSDenis Pryazhennikov (field_offset + n_field_descs_written - n_key_fields) *
107*bc712f1cSDenis Pryazhennikov field_size);
108*bc712f1cSDenis Pryazhennikov } else if (field_offset < n_key_fields) {
109*bc712f1cSDenis Pryazhennikov /* All fields belong to the key */
110*bc712f1cSDenis Pryazhennikov rte_memcpy(RTE_PTR_ADD(meta->keys, field_offset * field_size),
111*bc712f1cSDenis Pryazhennikov fields, n_field_descs_written * field_size);
112*bc712f1cSDenis Pryazhennikov } else {
113*bc712f1cSDenis Pryazhennikov /* All fields belong to the response */
114*bc712f1cSDenis Pryazhennikov rte_memcpy(RTE_PTR_ADD(meta->responses,
115*bc712f1cSDenis Pryazhennikov (field_offset - n_key_fields) * field_size),
116*bc712f1cSDenis Pryazhennikov fields, n_field_descs_written * field_size);
117*bc712f1cSDenis Pryazhennikov }
118*bc712f1cSDenis Pryazhennikov }
119*bc712f1cSDenis Pryazhennikov
120*bc712f1cSDenis Pryazhennikov return 0;
121*bc712f1cSDenis Pryazhennikov }
122*bc712f1cSDenis Pryazhennikov
123*bc712f1cSDenis Pryazhennikov static int
sfc_tbl_meta_desc_read(struct sfc_tbl_meta * meta,efx_nic_t * enp,efx_table_id_t table_id)124*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_desc_read(struct sfc_tbl_meta *meta, efx_nic_t *enp,
125*bc712f1cSDenis Pryazhennikov efx_table_id_t table_id)
126*bc712f1cSDenis Pryazhennikov {
127*bc712f1cSDenis Pryazhennikov efx_table_field_descriptor_t *fields;
128*bc712f1cSDenis Pryazhennikov unsigned int total_n_fields;
129*bc712f1cSDenis Pryazhennikov int rc;
130*bc712f1cSDenis Pryazhennikov
131*bc712f1cSDenis Pryazhennikov rc = efx_table_describe(enp, table_id, 0, &meta->descriptor, NULL, 0, NULL);
132*bc712f1cSDenis Pryazhennikov if (rc != 0)
133*bc712f1cSDenis Pryazhennikov return rc;
134*bc712f1cSDenis Pryazhennikov
135*bc712f1cSDenis Pryazhennikov total_n_fields = meta->descriptor.n_key_fields + meta->descriptor.n_resp_fields;
136*bc712f1cSDenis Pryazhennikov
137*bc712f1cSDenis Pryazhennikov fields = rte_calloc(NULL, total_n_fields, sizeof(*fields), 0);
138*bc712f1cSDenis Pryazhennikov if (fields == NULL)
139*bc712f1cSDenis Pryazhennikov return -ENOMEM;
140*bc712f1cSDenis Pryazhennikov
141*bc712f1cSDenis Pryazhennikov meta->table_id = table_id;
142*bc712f1cSDenis Pryazhennikov
143*bc712f1cSDenis Pryazhennikov meta->keys = rte_calloc("efx_table_key_field_descs",
144*bc712f1cSDenis Pryazhennikov meta->descriptor.n_key_fields,
145*bc712f1cSDenis Pryazhennikov sizeof(*meta->keys), 0);
146*bc712f1cSDenis Pryazhennikov if (meta->keys == NULL) {
147*bc712f1cSDenis Pryazhennikov rc = -ENOMEM;
148*bc712f1cSDenis Pryazhennikov goto fail_alloc_keys;
149*bc712f1cSDenis Pryazhennikov }
150*bc712f1cSDenis Pryazhennikov
151*bc712f1cSDenis Pryazhennikov meta->responses = rte_calloc("efx_table_response_field_descs",
152*bc712f1cSDenis Pryazhennikov meta->descriptor.n_resp_fields,
153*bc712f1cSDenis Pryazhennikov sizeof(*meta->responses), 0);
154*bc712f1cSDenis Pryazhennikov if (meta->responses == NULL) {
155*bc712f1cSDenis Pryazhennikov rc = -ENOMEM;
156*bc712f1cSDenis Pryazhennikov goto fail_alloc_responses;
157*bc712f1cSDenis Pryazhennikov }
158*bc712f1cSDenis Pryazhennikov
159*bc712f1cSDenis Pryazhennikov rc = sfc_tbl_meta_desc_fields_copy(meta, enp, fields, total_n_fields);
160*bc712f1cSDenis Pryazhennikov if (rc != 0)
161*bc712f1cSDenis Pryazhennikov goto fail_copy_fields;
162*bc712f1cSDenis Pryazhennikov
163*bc712f1cSDenis Pryazhennikov return 0;
164*bc712f1cSDenis Pryazhennikov
165*bc712f1cSDenis Pryazhennikov fail_copy_fields:
166*bc712f1cSDenis Pryazhennikov rte_free(meta->responses);
167*bc712f1cSDenis Pryazhennikov fail_alloc_responses:
168*bc712f1cSDenis Pryazhennikov rte_free(meta->keys);
169*bc712f1cSDenis Pryazhennikov fail_alloc_keys:
170*bc712f1cSDenis Pryazhennikov rte_free(fields);
171*bc712f1cSDenis Pryazhennikov
172*bc712f1cSDenis Pryazhennikov return rc;
173*bc712f1cSDenis Pryazhennikov }
174*bc712f1cSDenis Pryazhennikov
175*bc712f1cSDenis Pryazhennikov static int
sfc_tbl_meta_cache_add(struct rte_hash * cache,efx_nic_t * enp,efx_table_id_t table_id)176*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_cache_add(struct rte_hash *cache, efx_nic_t *enp,
177*bc712f1cSDenis Pryazhennikov efx_table_id_t table_id)
178*bc712f1cSDenis Pryazhennikov {
179*bc712f1cSDenis Pryazhennikov struct sfc_tbl_meta *meta = NULL;
180*bc712f1cSDenis Pryazhennikov int rc;
181*bc712f1cSDenis Pryazhennikov
182*bc712f1cSDenis Pryazhennikov meta = rte_zmalloc("sfc_tbl_meta", sizeof(*meta), 0);
183*bc712f1cSDenis Pryazhennikov if (meta == NULL)
184*bc712f1cSDenis Pryazhennikov return -ENOMEM;
185*bc712f1cSDenis Pryazhennikov
186*bc712f1cSDenis Pryazhennikov rc = sfc_tbl_meta_desc_read(meta, enp, table_id);
187*bc712f1cSDenis Pryazhennikov if (rc != 0)
188*bc712f1cSDenis Pryazhennikov goto fail_read_meta;
189*bc712f1cSDenis Pryazhennikov
190*bc712f1cSDenis Pryazhennikov rc = rte_hash_add_key_data(cache, &table_id, meta);
191*bc712f1cSDenis Pryazhennikov if (rc != 0)
192*bc712f1cSDenis Pryazhennikov goto fail_add_key;
193*bc712f1cSDenis Pryazhennikov
194*bc712f1cSDenis Pryazhennikov return 0;
195*bc712f1cSDenis Pryazhennikov
196*bc712f1cSDenis Pryazhennikov fail_add_key:
197*bc712f1cSDenis Pryazhennikov rte_free(meta->keys);
198*bc712f1cSDenis Pryazhennikov rte_free(meta->responses);
199*bc712f1cSDenis Pryazhennikov fail_read_meta:
200*bc712f1cSDenis Pryazhennikov rte_free(meta);
201*bc712f1cSDenis Pryazhennikov
202*bc712f1cSDenis Pryazhennikov return rc;
203*bc712f1cSDenis Pryazhennikov }
204*bc712f1cSDenis Pryazhennikov
205*bc712f1cSDenis Pryazhennikov int
sfc_tbl_meta_cache_update(struct rte_hash * cache,efx_nic_t * enp)206*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_cache_update(struct rte_hash *cache, efx_nic_t *enp)
207*bc712f1cSDenis Pryazhennikov {
208*bc712f1cSDenis Pryazhennikov efx_table_id_t *table_ids = NULL;
209*bc712f1cSDenis Pryazhennikov unsigned int n_table_ids_written;
210*bc712f1cSDenis Pryazhennikov unsigned int total_n_tables;
211*bc712f1cSDenis Pryazhennikov unsigned int n_table_ids;
212*bc712f1cSDenis Pryazhennikov uint32_t table_index;
213*bc712f1cSDenis Pryazhennikov unsigned int i;
214*bc712f1cSDenis Pryazhennikov int rc = 0;
215*bc712f1cSDenis Pryazhennikov
216*bc712f1cSDenis Pryazhennikov rc = efx_table_list(enp, 0, &total_n_tables, NULL, 0, NULL);
217*bc712f1cSDenis Pryazhennikov if (rc != 0)
218*bc712f1cSDenis Pryazhennikov return rc;
219*bc712f1cSDenis Pryazhennikov
220*bc712f1cSDenis Pryazhennikov table_ids = rte_calloc(NULL, total_n_tables, sizeof(*table_ids), 0);
221*bc712f1cSDenis Pryazhennikov if (table_ids == NULL)
222*bc712f1cSDenis Pryazhennikov return -ENOMEM;
223*bc712f1cSDenis Pryazhennikov
224*bc712f1cSDenis Pryazhennikov n_table_ids = total_n_tables;
225*bc712f1cSDenis Pryazhennikov
226*bc712f1cSDenis Pryazhennikov for (table_index = 0, n_table_ids_written = 0;
227*bc712f1cSDenis Pryazhennikov table_index < total_n_tables;
228*bc712f1cSDenis Pryazhennikov table_index += n_table_ids_written) {
229*bc712f1cSDenis Pryazhennikov rc = efx_table_list(enp, table_index, NULL,
230*bc712f1cSDenis Pryazhennikov table_ids, n_table_ids, &n_table_ids_written);
231*bc712f1cSDenis Pryazhennikov if (rc != 0)
232*bc712f1cSDenis Pryazhennikov goto out;
233*bc712f1cSDenis Pryazhennikov
234*bc712f1cSDenis Pryazhennikov if (table_index + n_table_ids_written > total_n_tables) {
235*bc712f1cSDenis Pryazhennikov rc = -EINVAL;
236*bc712f1cSDenis Pryazhennikov goto out;
237*bc712f1cSDenis Pryazhennikov }
238*bc712f1cSDenis Pryazhennikov
239*bc712f1cSDenis Pryazhennikov for (i = 0; i < n_table_ids_written; i++, table_index++) {
240*bc712f1cSDenis Pryazhennikov if (!efx_table_is_supported(table_ids[i]))
241*bc712f1cSDenis Pryazhennikov continue;
242*bc712f1cSDenis Pryazhennikov
243*bc712f1cSDenis Pryazhennikov rc = sfc_tbl_meta_cache_add(cache, enp, table_ids[i]);
244*bc712f1cSDenis Pryazhennikov if (rc != 0)
245*bc712f1cSDenis Pryazhennikov goto out;
246*bc712f1cSDenis Pryazhennikov }
247*bc712f1cSDenis Pryazhennikov }
248*bc712f1cSDenis Pryazhennikov
249*bc712f1cSDenis Pryazhennikov out:
250*bc712f1cSDenis Pryazhennikov rte_free(table_ids);
251*bc712f1cSDenis Pryazhennikov
252*bc712f1cSDenis Pryazhennikov return rc;
253*bc712f1cSDenis Pryazhennikov }
254