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