1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Marvell RVU Admin Function driver |
3 | * |
4 | * Copyright (C) 2022 Marvell. |
5 | * |
6 | */ |
7 | |
8 | #include <linux/bitfield.h> |
9 | #include <linux/module.h> |
10 | #include <linux/pci.h> |
11 | #include <linux/firmware.h> |
12 | #include <linux/stddef.h> |
13 | #include <linux/debugfs.h> |
14 | |
15 | #include "rvu_struct.h" |
16 | #include "rvu_reg.h" |
17 | #include "rvu.h" |
18 | #include "npc.h" |
19 | #include "cgx.h" |
20 | #include "rvu_npc_fs.h" |
21 | #include "rvu_npc_hash.h" |
22 | |
23 | static u64 (const u64 input[], size_t start_bit, |
24 | size_t width_bits) |
25 | { |
26 | const u64 mask = ~(u64)((~(__uint128_t)0) << width_bits); |
27 | const size_t msb = start_bit + width_bits - 1; |
28 | const size_t lword = start_bit >> 6; |
29 | const size_t uword = msb >> 6; |
30 | size_t lbits; |
31 | u64 hi, lo; |
32 | |
33 | if (lword == uword) |
34 | return (input[lword] >> (start_bit & 63)) & mask; |
35 | |
36 | lbits = 64 - (start_bit & 63); |
37 | hi = input[uword]; |
38 | lo = (input[lword] >> (start_bit & 63)); |
39 | return ((hi << lbits) | lo) & mask; |
40 | } |
41 | |
42 | static void rvu_npc_lshift_key(u64 *key, size_t key_bit_len) |
43 | { |
44 | u64 prev_orig_word = 0; |
45 | u64 cur_orig_word = 0; |
46 | size_t = key_bit_len % 64; |
47 | size_t max_idx = key_bit_len / 64; |
48 | size_t i; |
49 | |
50 | if (extra) |
51 | max_idx++; |
52 | |
53 | for (i = 0; i < max_idx; i++) { |
54 | cur_orig_word = key[i]; |
55 | key[i] = key[i] << 1; |
56 | key[i] |= ((prev_orig_word >> 63) & 0x1); |
57 | prev_orig_word = cur_orig_word; |
58 | } |
59 | } |
60 | |
61 | static u32 rvu_npc_toeplitz_hash(const u64 *data, u64 *key, size_t data_bit_len, |
62 | size_t key_bit_len) |
63 | { |
64 | u32 hash_out = 0; |
65 | u64 temp_data = 0; |
66 | int i; |
67 | |
68 | for (i = data_bit_len - 1; i >= 0; i--) { |
69 | temp_data = (data[i / 64]); |
70 | temp_data = temp_data >> (i % 64); |
71 | temp_data &= 0x1; |
72 | if (temp_data) |
73 | hash_out ^= (u32)(rvu_npc_wide_extract(input: key, start_bit: key_bit_len - 32, width_bits: 32)); |
74 | |
75 | rvu_npc_lshift_key(key, key_bit_len); |
76 | } |
77 | |
78 | return hash_out; |
79 | } |
80 | |
81 | u32 npc_field_hash_calc(u64 *ldata, struct npc_get_field_hash_info_rsp rsp, |
82 | u8 intf, u8 hash_idx) |
83 | { |
84 | u64 hash_key[3]; |
85 | u64 data_padded[2]; |
86 | u32 field_hash; |
87 | |
88 | hash_key[0] = rsp.secret_key[1] << 31; |
89 | hash_key[0] |= rsp.secret_key[2]; |
90 | hash_key[1] = rsp.secret_key[1] >> 33; |
91 | hash_key[1] |= rsp.secret_key[0] << 31; |
92 | hash_key[2] = rsp.secret_key[0] >> 33; |
93 | |
94 | data_padded[0] = rsp.hash_mask[intf][hash_idx][0] & ldata[0]; |
95 | data_padded[1] = rsp.hash_mask[intf][hash_idx][1] & ldata[1]; |
96 | field_hash = rvu_npc_toeplitz_hash(data: data_padded, key: hash_key, data_bit_len: 128, key_bit_len: 159); |
97 | |
98 | field_hash &= FIELD_GET(GENMASK(63, 32), rsp.hash_ctrl[intf][hash_idx]); |
99 | field_hash += FIELD_GET(GENMASK(31, 0), rsp.hash_ctrl[intf][hash_idx]); |
100 | return field_hash; |
101 | } |
102 | |
103 | static u64 npc_update_use_hash(struct rvu *rvu, int blkaddr, |
104 | u8 intf, int lid, int lt, int ld) |
105 | { |
106 | u8 hdr, key; |
107 | u64 cfg; |
108 | |
109 | cfg = rvu_read64(rvu, block: blkaddr, NPC_AF_INTFX_LIDX_LTX_LDX_CFG(intf, lid, lt, ld)); |
110 | hdr = FIELD_GET(NPC_HDR_OFFSET, cfg); |
111 | key = FIELD_GET(NPC_KEY_OFFSET, cfg); |
112 | |
113 | /* Update use_hash(bit-20) to 'true' and |
114 | * bytesm1(bit-16:19) to '0x3' in KEX_LD_CFG |
115 | */ |
116 | cfg = KEX_LD_CFG_USE_HASH(0x1, 0x03, |
117 | hdr, 0x1, 0x0, key); |
118 | |
119 | return cfg; |
120 | } |
121 | |
122 | static void npc_program_mkex_hash_rx(struct rvu *rvu, int blkaddr, |
123 | u8 intf) |
124 | { |
125 | struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash; |
126 | int lid, lt, ld, hash_cnt = 0; |
127 | |
128 | if (is_npc_intf_tx(intf)) |
129 | return; |
130 | |
131 | /* Program HASH_CFG */ |
132 | for (lid = 0; lid < NPC_MAX_LID; lid++) { |
133 | for (lt = 0; lt < NPC_MAX_LT; lt++) { |
134 | for (ld = 0; ld < NPC_MAX_LD; ld++) { |
135 | if (mkex_hash->lid_lt_ld_hash_en[intf][lid][lt][ld]) { |
136 | u64 cfg; |
137 | |
138 | if (hash_cnt == NPC_MAX_HASH) |
139 | return; |
140 | |
141 | cfg = npc_update_use_hash(rvu, blkaddr, |
142 | intf, lid, lt, ld); |
143 | /* Set updated KEX configuration */ |
144 | SET_KEX_LD(intf, lid, lt, ld, cfg); |
145 | /* Set HASH configuration */ |
146 | SET_KEX_LD_HASH(intf, ld, |
147 | mkex_hash->hash[intf][ld]); |
148 | SET_KEX_LD_HASH_MASK(intf, ld, 0, |
149 | mkex_hash->hash_mask[intf][ld][0]); |
150 | SET_KEX_LD_HASH_MASK(intf, ld, 1, |
151 | mkex_hash->hash_mask[intf][ld][1]); |
152 | SET_KEX_LD_HASH_CTRL(intf, ld, |
153 | mkex_hash->hash_ctrl[intf][ld]); |
154 | |
155 | hash_cnt++; |
156 | } |
157 | } |
158 | } |
159 | } |
160 | } |
161 | |
162 | static void npc_program_mkex_hash_tx(struct rvu *rvu, int blkaddr, |
163 | u8 intf) |
164 | { |
165 | struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash; |
166 | int lid, lt, ld, hash_cnt = 0; |
167 | |
168 | if (is_npc_intf_rx(intf)) |
169 | return; |
170 | |
171 | /* Program HASH_CFG */ |
172 | for (lid = 0; lid < NPC_MAX_LID; lid++) { |
173 | for (lt = 0; lt < NPC_MAX_LT; lt++) { |
174 | for (ld = 0; ld < NPC_MAX_LD; ld++) |
175 | if (mkex_hash->lid_lt_ld_hash_en[intf][lid][lt][ld]) { |
176 | u64 cfg; |
177 | |
178 | if (hash_cnt == NPC_MAX_HASH) |
179 | return; |
180 | |
181 | cfg = npc_update_use_hash(rvu, blkaddr, |
182 | intf, lid, lt, ld); |
183 | /* Set updated KEX configuration */ |
184 | SET_KEX_LD(intf, lid, lt, ld, cfg); |
185 | /* Set HASH configuration */ |
186 | SET_KEX_LD_HASH(intf, ld, |
187 | mkex_hash->hash[intf][ld]); |
188 | SET_KEX_LD_HASH_MASK(intf, ld, 0, |
189 | mkex_hash->hash_mask[intf][ld][0]); |
190 | SET_KEX_LD_HASH_MASK(intf, ld, 1, |
191 | mkex_hash->hash_mask[intf][ld][1]); |
192 | SET_KEX_LD_HASH_CTRL(intf, ld, |
193 | mkex_hash->hash_ctrl[intf][ld]); |
194 | hash_cnt++; |
195 | } |
196 | } |
197 | } |
198 | } |
199 | |
200 | void npc_config_secret_key(struct rvu *rvu, int blkaddr) |
201 | { |
202 | struct hw_cap *hwcap = &rvu->hw->cap; |
203 | struct rvu_hwinfo *hw = rvu->hw; |
204 | u8 intf; |
205 | |
206 | if (!hwcap->npc_hash_extract) |
207 | return; |
208 | |
209 | for (intf = 0; intf < hw->npc_intfs; intf++) { |
210 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_SECRET_KEY0(intf), |
211 | RVU_NPC_HASH_SECRET_KEY0); |
212 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_SECRET_KEY1(intf), |
213 | RVU_NPC_HASH_SECRET_KEY1); |
214 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_SECRET_KEY2(intf), |
215 | RVU_NPC_HASH_SECRET_KEY2); |
216 | } |
217 | } |
218 | |
219 | void npc_program_mkex_hash(struct rvu *rvu, int blkaddr) |
220 | { |
221 | struct npc_mcam_kex_hash *mh = rvu->kpu.mkex_hash; |
222 | struct hw_cap *hwcap = &rvu->hw->cap; |
223 | u8 intf, ld, hdr_offset, byte_len; |
224 | struct rvu_hwinfo *hw = rvu->hw; |
225 | u64 cfg; |
226 | |
227 | /* Check if hardware supports hash extraction */ |
228 | if (!hwcap->npc_hash_extract) |
229 | return; |
230 | |
231 | /* Check if IPv6 source/destination address |
232 | * should be hash enabled. |
233 | * Hashing reduces 128bit SIP/DIP fields to 32bit |
234 | * so that 224 bit X2 key can be used for IPv6 based filters as well, |
235 | * which in turn results in more number of MCAM entries available for |
236 | * use. |
237 | * |
238 | * Hashing of IPV6 SIP/DIP is enabled in below scenarios |
239 | * 1. If the silicon variant supports hashing feature |
240 | * 2. If the number of bytes of IP addr being extracted is 4 bytes ie |
241 | * 32bit. The assumption here is that if user wants 8bytes of LSB of |
242 | * IP addr or full 16 bytes then his intention is not to use 32bit |
243 | * hash. |
244 | */ |
245 | for (intf = 0; intf < hw->npc_intfs; intf++) { |
246 | for (ld = 0; ld < NPC_MAX_LD; ld++) { |
247 | cfg = rvu_read64(rvu, block: blkaddr, |
248 | NPC_AF_INTFX_LIDX_LTX_LDX_CFG(intf, |
249 | NPC_LID_LC, |
250 | NPC_LT_LC_IP6, |
251 | ld)); |
252 | hdr_offset = FIELD_GET(NPC_HDR_OFFSET, cfg); |
253 | byte_len = FIELD_GET(NPC_BYTESM, cfg); |
254 | /* Hashing of IPv6 source/destination address should be |
255 | * enabled if, |
256 | * hdr_offset == 8 (offset of source IPv6 address) or |
257 | * hdr_offset == 24 (offset of destination IPv6) |
258 | * address) and the number of byte to be |
259 | * extracted is 4. As per hardware configuration |
260 | * byte_len should be == actual byte_len - 1. |
261 | * Hence byte_len is checked against 3 but nor 4. |
262 | */ |
263 | if ((hdr_offset == 8 || hdr_offset == 24) && byte_len == 3) |
264 | mh->lid_lt_ld_hash_en[intf][NPC_LID_LC][NPC_LT_LC_IP6][ld] = true; |
265 | } |
266 | } |
267 | |
268 | /* Update hash configuration if the field is hash enabled */ |
269 | for (intf = 0; intf < hw->npc_intfs; intf++) { |
270 | npc_program_mkex_hash_rx(rvu, blkaddr, intf); |
271 | npc_program_mkex_hash_tx(rvu, blkaddr, intf); |
272 | } |
273 | } |
274 | |
275 | void npc_update_field_hash(struct rvu *rvu, u8 intf, |
276 | struct mcam_entry *entry, |
277 | int blkaddr, |
278 | u64 features, |
279 | struct flow_msg *pkt, |
280 | struct flow_msg *mask, |
281 | struct flow_msg *opkt, |
282 | struct flow_msg *omask) |
283 | { |
284 | struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash; |
285 | struct npc_get_field_hash_info_req req; |
286 | struct npc_get_field_hash_info_rsp rsp; |
287 | u64 ldata[2], cfg; |
288 | u32 field_hash; |
289 | u8 hash_idx; |
290 | |
291 | if (!rvu->hw->cap.npc_hash_extract) { |
292 | dev_dbg(rvu->dev, "%s: Field hash extract feature is not supported\n" , __func__); |
293 | return; |
294 | } |
295 | |
296 | req.intf = intf; |
297 | rvu_mbox_handler_npc_get_field_hash_info(rvu, &req, &rsp); |
298 | |
299 | for (hash_idx = 0; hash_idx < NPC_MAX_HASH; hash_idx++) { |
300 | cfg = rvu_read64(rvu, block: blkaddr, NPC_AF_INTFX_HASHX_CFG(intf, hash_idx)); |
301 | if ((cfg & BIT_ULL(11)) && (cfg & BIT_ULL(12))) { |
302 | u8 lid = (cfg & GENMASK_ULL(10, 8)) >> 8; |
303 | u8 ltype = (cfg & GENMASK_ULL(7, 4)) >> 4; |
304 | u8 ltype_mask = cfg & GENMASK_ULL(3, 0); |
305 | |
306 | if (mkex_hash->lid_lt_ld_hash_en[intf][lid][ltype][hash_idx]) { |
307 | switch (ltype & ltype_mask) { |
308 | /* If hash extract enabled is supported for IPv6 then |
309 | * 128 bit IPv6 source and destination addressed |
310 | * is hashed to 32 bit value. |
311 | */ |
312 | case NPC_LT_LC_IP6: |
313 | /* ld[0] == hash_idx[0] == Source IPv6 |
314 | * ld[1] == hash_idx[1] == Destination IPv6 |
315 | */ |
316 | if ((features & BIT_ULL(NPC_SIP_IPV6)) && !hash_idx) { |
317 | u32 src_ip[IPV6_WORDS]; |
318 | |
319 | be32_to_cpu_array(dst: src_ip, src: pkt->ip6src, IPV6_WORDS); |
320 | ldata[1] = (u64)src_ip[0] << 32 | src_ip[1]; |
321 | ldata[0] = (u64)src_ip[2] << 32 | src_ip[3]; |
322 | field_hash = npc_field_hash_calc(ldata, |
323 | rsp, |
324 | intf, |
325 | hash_idx); |
326 | npc_update_entry(rvu, type: NPC_SIP_IPV6, entry, |
327 | val_lo: field_hash, val_hi: 0, |
328 | GENMASK(31, 0), mask_hi: 0, intf); |
329 | memcpy(&opkt->ip6src, &pkt->ip6src, |
330 | sizeof(pkt->ip6src)); |
331 | memcpy(&omask->ip6src, &mask->ip6src, |
332 | sizeof(mask->ip6src)); |
333 | } else if ((features & BIT_ULL(NPC_DIP_IPV6)) && hash_idx) { |
334 | u32 dst_ip[IPV6_WORDS]; |
335 | |
336 | be32_to_cpu_array(dst: dst_ip, src: pkt->ip6dst, IPV6_WORDS); |
337 | ldata[1] = (u64)dst_ip[0] << 32 | dst_ip[1]; |
338 | ldata[0] = (u64)dst_ip[2] << 32 | dst_ip[3]; |
339 | field_hash = npc_field_hash_calc(ldata, |
340 | rsp, |
341 | intf, |
342 | hash_idx); |
343 | npc_update_entry(rvu, type: NPC_DIP_IPV6, entry, |
344 | val_lo: field_hash, val_hi: 0, |
345 | GENMASK(31, 0), mask_hi: 0, intf); |
346 | memcpy(&opkt->ip6dst, &pkt->ip6dst, |
347 | sizeof(pkt->ip6dst)); |
348 | memcpy(&omask->ip6dst, &mask->ip6dst, |
349 | sizeof(mask->ip6dst)); |
350 | } |
351 | |
352 | break; |
353 | } |
354 | } |
355 | } |
356 | } |
357 | } |
358 | |
359 | int rvu_mbox_handler_npc_get_field_hash_info(struct rvu *rvu, |
360 | struct npc_get_field_hash_info_req *req, |
361 | struct npc_get_field_hash_info_rsp *rsp) |
362 | { |
363 | u64 *secret_key = rsp->secret_key; |
364 | u8 intf = req->intf; |
365 | int i, j, blkaddr; |
366 | |
367 | blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
368 | if (blkaddr < 0) { |
369 | dev_err(rvu->dev, "%s: NPC block not implemented\n" , __func__); |
370 | return -EINVAL; |
371 | } |
372 | |
373 | secret_key[0] = rvu_read64(rvu, block: blkaddr, NPC_AF_INTFX_SECRET_KEY0(intf)); |
374 | secret_key[1] = rvu_read64(rvu, block: blkaddr, NPC_AF_INTFX_SECRET_KEY1(intf)); |
375 | secret_key[2] = rvu_read64(rvu, block: blkaddr, NPC_AF_INTFX_SECRET_KEY2(intf)); |
376 | |
377 | for (i = 0; i < NPC_MAX_HASH; i++) { |
378 | for (j = 0; j < NPC_MAX_HASH_MASK; j++) { |
379 | rsp->hash_mask[NIX_INTF_RX][i][j] = |
380 | GET_KEX_LD_HASH_MASK(NIX_INTF_RX, i, j); |
381 | rsp->hash_mask[NIX_INTF_TX][i][j] = |
382 | GET_KEX_LD_HASH_MASK(NIX_INTF_TX, i, j); |
383 | } |
384 | } |
385 | |
386 | for (i = 0; i < NPC_MAX_INTF; i++) |
387 | for (j = 0; j < NPC_MAX_HASH; j++) |
388 | rsp->hash_ctrl[i][j] = GET_KEX_LD_HASH_CTRL(i, j); |
389 | |
390 | return 0; |
391 | } |
392 | |
393 | /** |
394 | * rvu_exact_prepare_mdata - Make mdata for mcam entry |
395 | * @mac: MAC address |
396 | * @chan: Channel number. |
397 | * @ctype: Channel Type. |
398 | * @mask: LDATA mask. |
399 | * Return: Meta data |
400 | */ |
401 | static u64 rvu_exact_prepare_mdata(u8 *mac, u16 chan, u16 ctype, u64 mask) |
402 | { |
403 | u64 ldata = ether_addr_to_u64(addr: mac); |
404 | |
405 | /* Please note that mask is 48bit which excludes chan and ctype. |
406 | * Increase mask bits if we need to include them as well. |
407 | */ |
408 | ldata |= ((u64)chan << 48); |
409 | ldata |= ((u64)ctype << 60); |
410 | ldata &= mask; |
411 | ldata = ldata << 2; |
412 | |
413 | return ldata; |
414 | } |
415 | |
416 | /** |
417 | * rvu_exact_calculate_hash - calculate hash index to mem table. |
418 | * @rvu: resource virtualization unit. |
419 | * @chan: Channel number |
420 | * @ctype: Channel type. |
421 | * @mac: MAC address |
422 | * @mask: HASH mask. |
423 | * @table_depth: Depth of table. |
424 | * Return: Hash value |
425 | */ |
426 | static u32 rvu_exact_calculate_hash(struct rvu *rvu, u16 chan, u16 ctype, u8 *mac, |
427 | u64 mask, u32 table_depth) |
428 | { |
429 | struct npc_exact_table *table = rvu->hw->table; |
430 | u64 hash_key[2]; |
431 | u64 key_in[2]; |
432 | u64 ldata; |
433 | u32 hash; |
434 | |
435 | key_in[0] = RVU_NPC_HASH_SECRET_KEY0; |
436 | key_in[1] = RVU_NPC_HASH_SECRET_KEY2; |
437 | |
438 | hash_key[0] = key_in[0] << 31; |
439 | hash_key[0] |= key_in[1]; |
440 | hash_key[1] = key_in[0] >> 33; |
441 | |
442 | ldata = rvu_exact_prepare_mdata(mac, chan, ctype, mask); |
443 | |
444 | dev_dbg(rvu->dev, "%s: ldata=0x%llx hash_key0=0x%llx hash_key2=0x%llx\n" , __func__, |
445 | ldata, hash_key[1], hash_key[0]); |
446 | hash = rvu_npc_toeplitz_hash(data: &ldata, key: (u64 *)hash_key, data_bit_len: 64, key_bit_len: 95); |
447 | |
448 | hash &= table->mem_table.hash_mask; |
449 | hash += table->mem_table.hash_offset; |
450 | dev_dbg(rvu->dev, "%s: hash=%x\n" , __func__, hash); |
451 | |
452 | return hash; |
453 | } |
454 | |
455 | /** |
456 | * rvu_npc_exact_alloc_mem_table_entry - find free entry in 4 way table. |
457 | * @rvu: resource virtualization unit. |
458 | * @way: Indicate way to table. |
459 | * @index: Hash index to 4 way table. |
460 | * @hash: Hash value. |
461 | * |
462 | * Searches 4 way table using hash index. Returns 0 on success. |
463 | * Return: 0 upon success. |
464 | */ |
465 | static int rvu_npc_exact_alloc_mem_table_entry(struct rvu *rvu, u8 *way, |
466 | u32 *index, unsigned int hash) |
467 | { |
468 | struct npc_exact_table *table; |
469 | int depth, i; |
470 | |
471 | table = rvu->hw->table; |
472 | depth = table->mem_table.depth; |
473 | |
474 | /* Check all the 4 ways for a free slot. */ |
475 | mutex_lock(&table->lock); |
476 | for (i = 0; i < table->mem_table.ways; i++) { |
477 | if (test_bit(hash + i * depth, table->mem_table.bmap)) |
478 | continue; |
479 | |
480 | set_bit(nr: hash + i * depth, addr: table->mem_table.bmap); |
481 | mutex_unlock(lock: &table->lock); |
482 | |
483 | dev_dbg(rvu->dev, "%s: mem table entry alloc success (way=%d index=%d)\n" , |
484 | __func__, i, hash); |
485 | |
486 | *way = i; |
487 | *index = hash; |
488 | return 0; |
489 | } |
490 | mutex_unlock(lock: &table->lock); |
491 | |
492 | dev_dbg(rvu->dev, "%s: No space in 4 way exact way, weight=%u\n" , __func__, |
493 | bitmap_weight(table->mem_table.bmap, table->mem_table.depth)); |
494 | return -ENOSPC; |
495 | } |
496 | |
497 | /** |
498 | * rvu_npc_exact_free_id - Free seq id from bitmat. |
499 | * @rvu: Resource virtualization unit. |
500 | * @seq_id: Sequence identifier to be freed. |
501 | */ |
502 | static void rvu_npc_exact_free_id(struct rvu *rvu, u32 seq_id) |
503 | { |
504 | struct npc_exact_table *table; |
505 | |
506 | table = rvu->hw->table; |
507 | mutex_lock(&table->lock); |
508 | clear_bit(nr: seq_id, addr: table->id_bmap); |
509 | mutex_unlock(lock: &table->lock); |
510 | dev_dbg(rvu->dev, "%s: freed id %d\n" , __func__, seq_id); |
511 | } |
512 | |
513 | /** |
514 | * rvu_npc_exact_alloc_id - Alloc seq id from bitmap. |
515 | * @rvu: Resource virtualization unit. |
516 | * @seq_id: Sequence identifier. |
517 | * Return: True or false. |
518 | */ |
519 | static bool rvu_npc_exact_alloc_id(struct rvu *rvu, u32 *seq_id) |
520 | { |
521 | struct npc_exact_table *table; |
522 | u32 idx; |
523 | |
524 | table = rvu->hw->table; |
525 | |
526 | mutex_lock(&table->lock); |
527 | idx = find_first_zero_bit(addr: table->id_bmap, size: table->tot_ids); |
528 | if (idx == table->tot_ids) { |
529 | mutex_unlock(lock: &table->lock); |
530 | dev_err(rvu->dev, "%s: No space in id bitmap (%d)\n" , |
531 | __func__, table->tot_ids); |
532 | |
533 | return false; |
534 | } |
535 | |
536 | /* Mark bit map to indicate that slot is used.*/ |
537 | set_bit(nr: idx, addr: table->id_bmap); |
538 | mutex_unlock(lock: &table->lock); |
539 | |
540 | *seq_id = idx; |
541 | dev_dbg(rvu->dev, "%s: Allocated id (%d)\n" , __func__, *seq_id); |
542 | |
543 | return true; |
544 | } |
545 | |
546 | /** |
547 | * rvu_npc_exact_alloc_cam_table_entry - find free slot in fully associative table. |
548 | * @rvu: resource virtualization unit. |
549 | * @index: Index to exact CAM table. |
550 | * Return: 0 upon success; else error number. |
551 | */ |
552 | static int rvu_npc_exact_alloc_cam_table_entry(struct rvu *rvu, int *index) |
553 | { |
554 | struct npc_exact_table *table; |
555 | u32 idx; |
556 | |
557 | table = rvu->hw->table; |
558 | |
559 | mutex_lock(&table->lock); |
560 | idx = find_first_zero_bit(addr: table->cam_table.bmap, size: table->cam_table.depth); |
561 | if (idx == table->cam_table.depth) { |
562 | mutex_unlock(lock: &table->lock); |
563 | dev_info(rvu->dev, "%s: No space in exact cam table, weight=%u\n" , __func__, |
564 | bitmap_weight(table->cam_table.bmap, table->cam_table.depth)); |
565 | return -ENOSPC; |
566 | } |
567 | |
568 | /* Mark bit map to indicate that slot is used.*/ |
569 | set_bit(nr: idx, addr: table->cam_table.bmap); |
570 | mutex_unlock(lock: &table->lock); |
571 | |
572 | *index = idx; |
573 | dev_dbg(rvu->dev, "%s: cam table entry alloc success (index=%d)\n" , |
574 | __func__, idx); |
575 | return 0; |
576 | } |
577 | |
578 | /** |
579 | * rvu_exact_prepare_table_entry - Data for exact match table entry. |
580 | * @rvu: Resource virtualization unit. |
581 | * @enable: Enable/Disable entry |
582 | * @ctype: Software defined channel type. Currently set as 0. |
583 | * @chan: Channel number. |
584 | * @mac_addr: Destination mac address. |
585 | * Return: mdata for exact match table. |
586 | */ |
587 | static u64 rvu_exact_prepare_table_entry(struct rvu *rvu, bool enable, |
588 | u8 ctype, u16 chan, u8 *mac_addr) |
589 | |
590 | { |
591 | u64 ldata = ether_addr_to_u64(addr: mac_addr); |
592 | |
593 | /* Enable or disable */ |
594 | u64 mdata = FIELD_PREP(GENMASK_ULL(63, 63), enable ? 1 : 0); |
595 | |
596 | /* Set Ctype */ |
597 | mdata |= FIELD_PREP(GENMASK_ULL(61, 60), ctype); |
598 | |
599 | /* Set chan */ |
600 | mdata |= FIELD_PREP(GENMASK_ULL(59, 48), chan); |
601 | |
602 | /* MAC address */ |
603 | mdata |= FIELD_PREP(GENMASK_ULL(47, 0), ldata); |
604 | |
605 | return mdata; |
606 | } |
607 | |
608 | /** |
609 | * rvu_exact_config_secret_key - Configure secret key. |
610 | * @rvu: Resource virtualization unit. |
611 | */ |
612 | static void rvu_exact_config_secret_key(struct rvu *rvu) |
613 | { |
614 | int blkaddr; |
615 | |
616 | blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
617 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_EXACT_SECRET0(NIX_INTF_RX), |
618 | RVU_NPC_HASH_SECRET_KEY0); |
619 | |
620 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_EXACT_SECRET1(NIX_INTF_RX), |
621 | RVU_NPC_HASH_SECRET_KEY1); |
622 | |
623 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_EXACT_SECRET2(NIX_INTF_RX), |
624 | RVU_NPC_HASH_SECRET_KEY2); |
625 | } |
626 | |
627 | /** |
628 | * rvu_exact_config_search_key - Configure search key |
629 | * @rvu: Resource virtualization unit. |
630 | */ |
631 | static void rvu_exact_config_search_key(struct rvu *rvu) |
632 | { |
633 | int blkaddr; |
634 | u64 reg_val; |
635 | |
636 | blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
637 | |
638 | /* HDR offset */ |
639 | reg_val = FIELD_PREP(GENMASK_ULL(39, 32), 0); |
640 | |
641 | /* BYTESM1, number of bytes - 1 */ |
642 | reg_val |= FIELD_PREP(GENMASK_ULL(18, 16), ETH_ALEN - 1); |
643 | |
644 | /* Enable LID and set LID to NPC_LID_LA */ |
645 | reg_val |= FIELD_PREP(GENMASK_ULL(11, 11), 1); |
646 | reg_val |= FIELD_PREP(GENMASK_ULL(10, 8), NPC_LID_LA); |
647 | |
648 | /* Clear layer type based extraction */ |
649 | |
650 | /* Disable LT_EN */ |
651 | reg_val |= FIELD_PREP(GENMASK_ULL(12, 12), 0); |
652 | |
653 | /* Set LTYPE_MATCH to 0 */ |
654 | reg_val |= FIELD_PREP(GENMASK_ULL(7, 4), 0); |
655 | |
656 | /* Set LTYPE_MASK to 0 */ |
657 | reg_val |= FIELD_PREP(GENMASK_ULL(3, 0), 0); |
658 | |
659 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_EXACT_CFG(NIX_INTF_RX), val: reg_val); |
660 | } |
661 | |
662 | /** |
663 | * rvu_exact_config_result_ctrl - Set exact table hash control |
664 | * @rvu: Resource virtualization unit. |
665 | * @depth: Depth of Exact match table. |
666 | * |
667 | * Sets mask and offset for hash for mem table. |
668 | */ |
669 | static void rvu_exact_config_result_ctrl(struct rvu *rvu, uint32_t depth) |
670 | { |
671 | int blkaddr; |
672 | u64 reg = 0; |
673 | |
674 | blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
675 | |
676 | /* Set mask. Note that depth is a power of 2 */ |
677 | rvu->hw->table->mem_table.hash_mask = (depth - 1); |
678 | reg |= FIELD_PREP(GENMASK_ULL(42, 32), (depth - 1)); |
679 | |
680 | /* Set offset as 0 */ |
681 | rvu->hw->table->mem_table.hash_offset = 0; |
682 | reg |= FIELD_PREP(GENMASK_ULL(10, 0), 0); |
683 | |
684 | /* Set reg for RX */ |
685 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_EXACT_RESULT_CTL(NIX_INTF_RX), val: reg); |
686 | /* Store hash mask and offset for s/w algorithm */ |
687 | } |
688 | |
689 | /** |
690 | * rvu_exact_config_table_mask - Set exact table mask. |
691 | * @rvu: Resource virtualization unit. |
692 | */ |
693 | static void rvu_exact_config_table_mask(struct rvu *rvu) |
694 | { |
695 | int blkaddr; |
696 | u64 mask = 0; |
697 | |
698 | blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
699 | |
700 | /* Don't use Ctype */ |
701 | mask |= FIELD_PREP(GENMASK_ULL(61, 60), 0); |
702 | |
703 | /* Set chan */ |
704 | mask |= GENMASK_ULL(59, 48); |
705 | |
706 | /* Full ldata */ |
707 | mask |= GENMASK_ULL(47, 0); |
708 | |
709 | /* Store mask for s/w hash calcualtion */ |
710 | rvu->hw->table->mem_table.mask = mask; |
711 | |
712 | /* Set mask for RX.*/ |
713 | rvu_write64(rvu, block: blkaddr, NPC_AF_INTFX_EXACT_MASK(NIX_INTF_RX), val: mask); |
714 | } |
715 | |
716 | /** |
717 | * rvu_npc_exact_get_max_entries - Get total number of entries in table. |
718 | * @rvu: resource virtualization unit. |
719 | * Return: Maximum table entries possible. |
720 | */ |
721 | u32 rvu_npc_exact_get_max_entries(struct rvu *rvu) |
722 | { |
723 | struct npc_exact_table *table; |
724 | |
725 | table = rvu->hw->table; |
726 | return table->tot_ids; |
727 | } |
728 | |
729 | /** |
730 | * rvu_npc_exact_has_match_table - Checks support for exact match. |
731 | * @rvu: resource virtualization unit. |
732 | * Return: True if exact match table is supported/enabled. |
733 | */ |
734 | bool rvu_npc_exact_has_match_table(struct rvu *rvu) |
735 | { |
736 | return rvu->hw->cap.npc_exact_match_enabled; |
737 | } |
738 | |
739 | /** |
740 | * __rvu_npc_exact_find_entry_by_seq_id - find entry by id |
741 | * @rvu: resource virtualization unit. |
742 | * @seq_id: Sequence identifier. |
743 | * |
744 | * Caller should acquire the lock. |
745 | * Return: Pointer to table entry. |
746 | */ |
747 | static struct npc_exact_table_entry * |
748 | __rvu_npc_exact_find_entry_by_seq_id(struct rvu *rvu, u32 seq_id) |
749 | { |
750 | struct npc_exact_table *table = rvu->hw->table; |
751 | struct npc_exact_table_entry *entry = NULL; |
752 | struct list_head *lhead; |
753 | |
754 | lhead = &table->lhead_gbl; |
755 | |
756 | /* traverse to find the matching entry */ |
757 | list_for_each_entry(entry, lhead, glist) { |
758 | if (entry->seq_id != seq_id) |
759 | continue; |
760 | |
761 | return entry; |
762 | } |
763 | |
764 | return NULL; |
765 | } |
766 | |
767 | /** |
768 | * rvu_npc_exact_add_to_list - Add entry to list |
769 | * @rvu: resource virtualization unit. |
770 | * @opc_type: OPCODE to select MEM/CAM table. |
771 | * @ways: MEM table ways. |
772 | * @index: Index in MEM/CAM table. |
773 | * @cgx_id: CGX identifier. |
774 | * @lmac_id: LMAC identifier. |
775 | * @mac_addr: MAC address. |
776 | * @chan: Channel number. |
777 | * @ctype: Channel Type. |
778 | * @seq_id: Sequence identifier |
779 | * @cmd: True if function is called by ethtool cmd |
780 | * @mcam_idx: NPC mcam index of DMAC entry in NPC mcam. |
781 | * @pcifunc: pci function |
782 | * Return: 0 upon success. |
783 | */ |
784 | static int rvu_npc_exact_add_to_list(struct rvu *rvu, enum npc_exact_opc_type opc_type, u8 ways, |
785 | u32 index, u8 cgx_id, u8 lmac_id, u8 *mac_addr, u16 chan, |
786 | u8 ctype, u32 *seq_id, bool cmd, u32 mcam_idx, u16 pcifunc) |
787 | { |
788 | struct npc_exact_table_entry *entry, *tmp, *iter; |
789 | struct npc_exact_table *table = rvu->hw->table; |
790 | struct list_head *lhead, *pprev; |
791 | |
792 | WARN_ON(ways >= NPC_EXACT_TBL_MAX_WAYS); |
793 | |
794 | if (!rvu_npc_exact_alloc_id(rvu, seq_id)) { |
795 | dev_err(rvu->dev, "%s: Generate seq id failed\n" , __func__); |
796 | return -EFAULT; |
797 | } |
798 | |
799 | entry = kmalloc(size: sizeof(*entry), GFP_KERNEL); |
800 | if (!entry) { |
801 | rvu_npc_exact_free_id(rvu, seq_id: *seq_id); |
802 | dev_err(rvu->dev, "%s: Memory allocation failed\n" , __func__); |
803 | return -ENOMEM; |
804 | } |
805 | |
806 | mutex_lock(&table->lock); |
807 | switch (opc_type) { |
808 | case NPC_EXACT_OPC_CAM: |
809 | lhead = &table->lhead_cam_tbl_entry; |
810 | table->cam_tbl_entry_cnt++; |
811 | break; |
812 | |
813 | case NPC_EXACT_OPC_MEM: |
814 | lhead = &table->lhead_mem_tbl_entry[ways]; |
815 | table->mem_tbl_entry_cnt++; |
816 | break; |
817 | |
818 | default: |
819 | mutex_unlock(lock: &table->lock); |
820 | kfree(objp: entry); |
821 | rvu_npc_exact_free_id(rvu, seq_id: *seq_id); |
822 | |
823 | dev_err(rvu->dev, "%s: Unknown opc type%d\n" , __func__, opc_type); |
824 | return -EINVAL; |
825 | } |
826 | |
827 | /* Add to global list */ |
828 | INIT_LIST_HEAD(list: &entry->glist); |
829 | list_add_tail(new: &entry->glist, head: &table->lhead_gbl); |
830 | INIT_LIST_HEAD(list: &entry->list); |
831 | entry->index = index; |
832 | entry->ways = ways; |
833 | entry->opc_type = opc_type; |
834 | |
835 | entry->pcifunc = pcifunc; |
836 | |
837 | ether_addr_copy(dst: entry->mac, src: mac_addr); |
838 | entry->chan = chan; |
839 | entry->ctype = ctype; |
840 | entry->cgx_id = cgx_id; |
841 | entry->lmac_id = lmac_id; |
842 | |
843 | entry->seq_id = *seq_id; |
844 | |
845 | entry->mcam_idx = mcam_idx; |
846 | entry->cmd = cmd; |
847 | |
848 | pprev = lhead; |
849 | |
850 | /* Insert entry in ascending order of index */ |
851 | list_for_each_entry_safe(iter, tmp, lhead, list) { |
852 | if (index < iter->index) |
853 | break; |
854 | |
855 | pprev = &iter->list; |
856 | } |
857 | |
858 | /* Add to each table list */ |
859 | list_add(new: &entry->list, head: pprev); |
860 | mutex_unlock(lock: &table->lock); |
861 | return 0; |
862 | } |
863 | |
864 | /** |
865 | * rvu_npc_exact_mem_table_write - Wrapper for register write |
866 | * @rvu: resource virtualization unit. |
867 | * @blkaddr: Block address |
868 | * @ways: ways for MEM table. |
869 | * @index: Index in MEM |
870 | * @mdata: Meta data to be written to register. |
871 | */ |
872 | static void rvu_npc_exact_mem_table_write(struct rvu *rvu, int blkaddr, u8 ways, |
873 | u32 index, u64 mdata) |
874 | { |
875 | rvu_write64(rvu, block: blkaddr, NPC_AF_EXACT_MEM_ENTRY(ways, index), val: mdata); |
876 | } |
877 | |
878 | /** |
879 | * rvu_npc_exact_cam_table_write - Wrapper for register write |
880 | * @rvu: resource virtualization unit. |
881 | * @blkaddr: Block address |
882 | * @index: Index in MEM |
883 | * @mdata: Meta data to be written to register. |
884 | */ |
885 | static void rvu_npc_exact_cam_table_write(struct rvu *rvu, int blkaddr, |
886 | u32 index, u64 mdata) |
887 | { |
888 | rvu_write64(rvu, block: blkaddr, NPC_AF_EXACT_CAM_ENTRY(index), val: mdata); |
889 | } |
890 | |
891 | /** |
892 | * rvu_npc_exact_dealloc_table_entry - dealloc table entry |
893 | * @rvu: resource virtualization unit. |
894 | * @opc_type: OPCODE for selection of table(MEM or CAM) |
895 | * @ways: ways if opc_type is MEM table. |
896 | * @index: Index of MEM or CAM table. |
897 | * Return: 0 upon success. |
898 | */ |
899 | static int rvu_npc_exact_dealloc_table_entry(struct rvu *rvu, enum npc_exact_opc_type opc_type, |
900 | u8 ways, u32 index) |
901 | { |
902 | int blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
903 | struct npc_exact_table *table; |
904 | u8 null_dmac[6] = { 0 }; |
905 | int depth; |
906 | |
907 | /* Prepare entry with all fields set to zero */ |
908 | u64 null_mdata = rvu_exact_prepare_table_entry(rvu, enable: false, ctype: 0, chan: 0, mac_addr: null_dmac); |
909 | |
910 | table = rvu->hw->table; |
911 | depth = table->mem_table.depth; |
912 | |
913 | mutex_lock(&table->lock); |
914 | |
915 | switch (opc_type) { |
916 | case NPC_EXACT_OPC_CAM: |
917 | |
918 | /* Check whether entry is used already */ |
919 | if (!test_bit(index, table->cam_table.bmap)) { |
920 | mutex_unlock(lock: &table->lock); |
921 | dev_err(rvu->dev, "%s: Trying to free an unused entry ways=%d index=%d\n" , |
922 | __func__, ways, index); |
923 | return -EINVAL; |
924 | } |
925 | |
926 | rvu_npc_exact_cam_table_write(rvu, blkaddr, index, mdata: null_mdata); |
927 | clear_bit(nr: index, addr: table->cam_table.bmap); |
928 | break; |
929 | |
930 | case NPC_EXACT_OPC_MEM: |
931 | |
932 | /* Check whether entry is used already */ |
933 | if (!test_bit(index + ways * depth, table->mem_table.bmap)) { |
934 | mutex_unlock(lock: &table->lock); |
935 | dev_err(rvu->dev, "%s: Trying to free an unused entry index=%d\n" , |
936 | __func__, index); |
937 | return -EINVAL; |
938 | } |
939 | |
940 | rvu_npc_exact_mem_table_write(rvu, blkaddr, ways, index, mdata: null_mdata); |
941 | clear_bit(nr: index + ways * depth, addr: table->mem_table.bmap); |
942 | break; |
943 | |
944 | default: |
945 | mutex_unlock(lock: &table->lock); |
946 | dev_err(rvu->dev, "%s: invalid opc type %d" , __func__, opc_type); |
947 | return -ENOSPC; |
948 | } |
949 | |
950 | mutex_unlock(lock: &table->lock); |
951 | |
952 | dev_dbg(rvu->dev, "%s: Successfully deleted entry (index=%d, ways=%d opc_type=%d\n" , |
953 | __func__, index, ways, opc_type); |
954 | |
955 | return 0; |
956 | } |
957 | |
958 | /** |
959 | * rvu_npc_exact_alloc_table_entry - Allociate an entry |
960 | * @rvu: resource virtualization unit. |
961 | * @mac: MAC address. |
962 | * @chan: Channel number. |
963 | * @ctype: Channel Type. |
964 | * @index: Index of MEM table or CAM table. |
965 | * @ways: Ways. Only valid for MEM table. |
966 | * @opc_type: OPCODE to select table (MEM or CAM) |
967 | * |
968 | * Try allocating a slot from MEM table. If all 4 ways |
969 | * slot are full for a hash index, check availability in |
970 | * 32-entry CAM table for allocation. |
971 | * Return: 0 upon success. |
972 | */ |
973 | static int rvu_npc_exact_alloc_table_entry(struct rvu *rvu, char *mac, u16 chan, u8 ctype, |
974 | u32 *index, u8 *ways, enum npc_exact_opc_type *opc_type) |
975 | { |
976 | struct npc_exact_table *table; |
977 | unsigned int hash; |
978 | int err; |
979 | |
980 | table = rvu->hw->table; |
981 | |
982 | /* Check in 4-ways mem entry for free slote */ |
983 | hash = rvu_exact_calculate_hash(rvu, chan, ctype, mac, mask: table->mem_table.mask, |
984 | table_depth: table->mem_table.depth); |
985 | err = rvu_npc_exact_alloc_mem_table_entry(rvu, way: ways, index, hash); |
986 | if (!err) { |
987 | *opc_type = NPC_EXACT_OPC_MEM; |
988 | dev_dbg(rvu->dev, "%s: inserted in 4 ways hash table ways=%d, index=%d\n" , |
989 | __func__, *ways, *index); |
990 | return 0; |
991 | } |
992 | |
993 | dev_dbg(rvu->dev, "%s: failed to insert in 4 ways hash table\n" , __func__); |
994 | |
995 | /* wayss is 0 for cam table */ |
996 | *ways = 0; |
997 | err = rvu_npc_exact_alloc_cam_table_entry(rvu, index); |
998 | if (!err) { |
999 | *opc_type = NPC_EXACT_OPC_CAM; |
1000 | dev_dbg(rvu->dev, "%s: inserted in fully associative hash table index=%u\n" , |
1001 | __func__, *index); |
1002 | return 0; |
1003 | } |
1004 | |
1005 | dev_err(rvu->dev, "%s: failed to insert in fully associative hash table\n" , __func__); |
1006 | return -ENOSPC; |
1007 | } |
1008 | |
1009 | /** |
1010 | * rvu_npc_exact_save_drop_rule_chan_and_mask - Save drop rules info in data base. |
1011 | * @rvu: resource virtualization unit. |
1012 | * @drop_mcam_idx: Drop rule index in NPC mcam. |
1013 | * @chan_val: Channel value. |
1014 | * @chan_mask: Channel Mask. |
1015 | * @pcifunc: pcifunc of interface. |
1016 | * Return: True upon success. |
1017 | */ |
1018 | static bool rvu_npc_exact_save_drop_rule_chan_and_mask(struct rvu *rvu, int drop_mcam_idx, |
1019 | u64 chan_val, u64 chan_mask, u16 pcifunc) |
1020 | { |
1021 | struct npc_exact_table *table; |
1022 | int i; |
1023 | |
1024 | table = rvu->hw->table; |
1025 | |
1026 | for (i = 0; i < NPC_MCAM_DROP_RULE_MAX; i++) { |
1027 | if (!table->drop_rule_map[i].valid) |
1028 | break; |
1029 | |
1030 | if (table->drop_rule_map[i].chan_val != (u16)chan_val) |
1031 | continue; |
1032 | |
1033 | if (table->drop_rule_map[i].chan_mask != (u16)chan_mask) |
1034 | continue; |
1035 | |
1036 | return false; |
1037 | } |
1038 | |
1039 | if (i == NPC_MCAM_DROP_RULE_MAX) |
1040 | return false; |
1041 | |
1042 | table->drop_rule_map[i].drop_rule_idx = drop_mcam_idx; |
1043 | table->drop_rule_map[i].chan_val = (u16)chan_val; |
1044 | table->drop_rule_map[i].chan_mask = (u16)chan_mask; |
1045 | table->drop_rule_map[i].pcifunc = pcifunc; |
1046 | table->drop_rule_map[i].valid = true; |
1047 | return true; |
1048 | } |
1049 | |
1050 | /** |
1051 | * rvu_npc_exact_calc_drop_rule_chan_and_mask - Calculate Channel number and mask. |
1052 | * @rvu: resource virtualization unit. |
1053 | * @intf_type: Interface type (SDK, LBK or CGX) |
1054 | * @cgx_id: CGX identifier. |
1055 | * @lmac_id: LAMC identifier. |
1056 | * @val: Channel number. |
1057 | * @mask: Channel mask. |
1058 | * Return: True upon success. |
1059 | */ |
1060 | static bool rvu_npc_exact_calc_drop_rule_chan_and_mask(struct rvu *rvu, u8 intf_type, |
1061 | u8 cgx_id, u8 lmac_id, |
1062 | u64 *val, u64 *mask) |
1063 | { |
1064 | u16 chan_val, chan_mask; |
1065 | |
1066 | /* No support for SDP and LBK */ |
1067 | if (intf_type != NIX_INTF_TYPE_CGX) |
1068 | return false; |
1069 | |
1070 | chan_val = rvu_nix_chan_cgx(rvu, cgxid: cgx_id, lmacid: lmac_id, chan: 0); |
1071 | chan_mask = 0xfff; |
1072 | |
1073 | if (val) |
1074 | *val = chan_val; |
1075 | |
1076 | if (mask) |
1077 | *mask = chan_mask; |
1078 | |
1079 | return true; |
1080 | } |
1081 | |
1082 | /** |
1083 | * rvu_npc_exact_drop_rule_to_pcifunc - Retrieve pcifunc |
1084 | * @rvu: resource virtualization unit. |
1085 | * @drop_rule_idx: Drop rule index in NPC mcam. |
1086 | * |
1087 | * Debugfs (exact_drop_cnt) entry displays pcifunc for interface |
1088 | * by retrieving the pcifunc value from data base. |
1089 | * Return: Drop rule index. |
1090 | */ |
1091 | u16 rvu_npc_exact_drop_rule_to_pcifunc(struct rvu *rvu, u32 drop_rule_idx) |
1092 | { |
1093 | struct npc_exact_table *table; |
1094 | int i; |
1095 | |
1096 | table = rvu->hw->table; |
1097 | |
1098 | for (i = 0; i < NPC_MCAM_DROP_RULE_MAX; i++) { |
1099 | if (!table->drop_rule_map[i].valid) |
1100 | break; |
1101 | |
1102 | if (table->drop_rule_map[i].drop_rule_idx != drop_rule_idx) |
1103 | continue; |
1104 | |
1105 | return table->drop_rule_map[i].pcifunc; |
1106 | } |
1107 | |
1108 | dev_err(rvu->dev, "%s: drop mcam rule index (%d) >= NPC_MCAM_DROP_RULE_MAX\n" , |
1109 | __func__, drop_rule_idx); |
1110 | return -1; |
1111 | } |
1112 | |
1113 | /** |
1114 | * rvu_npc_exact_get_drop_rule_info - Get drop rule information. |
1115 | * @rvu: resource virtualization unit. |
1116 | * @intf_type: Interface type (CGX, SDP or LBK) |
1117 | * @cgx_id: CGX identifier. |
1118 | * @lmac_id: LMAC identifier. |
1119 | * @drop_mcam_idx: NPC mcam drop rule index. |
1120 | * @val: Channel value. |
1121 | * @mask: Channel mask. |
1122 | * @pcifunc: pcifunc of interface corresponding to the drop rule. |
1123 | * Return: True upon success. |
1124 | */ |
1125 | static bool rvu_npc_exact_get_drop_rule_info(struct rvu *rvu, u8 intf_type, u8 cgx_id, |
1126 | u8 lmac_id, u32 *drop_mcam_idx, u64 *val, |
1127 | u64 *mask, u16 *pcifunc) |
1128 | { |
1129 | struct npc_exact_table *table; |
1130 | u64 chan_val, chan_mask; |
1131 | bool rc; |
1132 | int i; |
1133 | |
1134 | table = rvu->hw->table; |
1135 | |
1136 | if (intf_type != NIX_INTF_TYPE_CGX) { |
1137 | dev_err(rvu->dev, "%s: No drop rule for LBK/SDP mode\n" , __func__); |
1138 | return false; |
1139 | } |
1140 | |
1141 | rc = rvu_npc_exact_calc_drop_rule_chan_and_mask(rvu, intf_type, cgx_id, |
1142 | lmac_id, val: &chan_val, mask: &chan_mask); |
1143 | if (!rc) |
1144 | return false; |
1145 | |
1146 | for (i = 0; i < NPC_MCAM_DROP_RULE_MAX; i++) { |
1147 | if (!table->drop_rule_map[i].valid) |
1148 | break; |
1149 | |
1150 | if (table->drop_rule_map[i].chan_val != (u16)chan_val) |
1151 | continue; |
1152 | |
1153 | if (val) |
1154 | *val = table->drop_rule_map[i].chan_val; |
1155 | if (mask) |
1156 | *mask = table->drop_rule_map[i].chan_mask; |
1157 | if (pcifunc) |
1158 | *pcifunc = table->drop_rule_map[i].pcifunc; |
1159 | |
1160 | *drop_mcam_idx = i; |
1161 | return true; |
1162 | } |
1163 | |
1164 | if (i == NPC_MCAM_DROP_RULE_MAX) { |
1165 | dev_err(rvu->dev, "%s: drop mcam rule index (%d) >= NPC_MCAM_DROP_RULE_MAX\n" , |
1166 | __func__, *drop_mcam_idx); |
1167 | return false; |
1168 | } |
1169 | |
1170 | dev_err(rvu->dev, "%s: Could not retrieve for cgx=%d, lmac=%d\n" , |
1171 | __func__, cgx_id, lmac_id); |
1172 | return false; |
1173 | } |
1174 | |
1175 | /** |
1176 | * __rvu_npc_exact_cmd_rules_cnt_update - Update number dmac rules against a drop rule. |
1177 | * @rvu: resource virtualization unit. |
1178 | * @drop_mcam_idx: NPC mcam drop rule index. |
1179 | * @val: +1 or -1. |
1180 | * @enable_or_disable_cam: If no exact match rules against a drop rule, disable it. |
1181 | * |
1182 | * when first exact match entry against a drop rule is added, enable_or_disable_cam |
1183 | * is set to true. When last exact match entry against a drop rule is deleted, |
1184 | * enable_or_disable_cam is set to true. |
1185 | * Return: Number of rules |
1186 | */ |
1187 | static u16 __rvu_npc_exact_cmd_rules_cnt_update(struct rvu *rvu, int drop_mcam_idx, |
1188 | int val, bool *enable_or_disable_cam) |
1189 | { |
1190 | struct npc_exact_table *table; |
1191 | u16 *cnt, old_cnt; |
1192 | bool promisc; |
1193 | |
1194 | table = rvu->hw->table; |
1195 | promisc = table->promisc_mode[drop_mcam_idx]; |
1196 | |
1197 | cnt = &table->cnt_cmd_rules[drop_mcam_idx]; |
1198 | old_cnt = *cnt; |
1199 | |
1200 | *cnt += val; |
1201 | |
1202 | if (!enable_or_disable_cam) |
1203 | goto done; |
1204 | |
1205 | *enable_or_disable_cam = false; |
1206 | |
1207 | if (promisc) |
1208 | goto done; |
1209 | |
1210 | /* If all rules are deleted and not already in promisc mode; |
1211 | * disable cam |
1212 | */ |
1213 | if (!*cnt && val < 0) { |
1214 | *enable_or_disable_cam = true; |
1215 | goto done; |
1216 | } |
1217 | |
1218 | /* If rule got added and not already in promisc mode; enable cam */ |
1219 | if (!old_cnt && val > 0) { |
1220 | *enable_or_disable_cam = true; |
1221 | goto done; |
1222 | } |
1223 | |
1224 | done: |
1225 | return *cnt; |
1226 | } |
1227 | |
1228 | /** |
1229 | * rvu_npc_exact_del_table_entry_by_id - Delete and free table entry. |
1230 | * @rvu: resource virtualization unit. |
1231 | * @seq_id: Sequence identifier of the entry. |
1232 | * |
1233 | * Deletes entry from linked lists and free up slot in HW MEM or CAM |
1234 | * table. |
1235 | * Return: 0 upon success. |
1236 | */ |
1237 | static int rvu_npc_exact_del_table_entry_by_id(struct rvu *rvu, u32 seq_id) |
1238 | { |
1239 | struct npc_exact_table_entry *entry = NULL; |
1240 | struct npc_exact_table *table; |
1241 | bool disable_cam = false; |
1242 | u32 drop_mcam_idx = -1; |
1243 | int *cnt; |
1244 | bool rc; |
1245 | |
1246 | table = rvu->hw->table; |
1247 | |
1248 | mutex_lock(&table->lock); |
1249 | |
1250 | /* Lookup for entry which needs to be updated */ |
1251 | entry = __rvu_npc_exact_find_entry_by_seq_id(rvu, seq_id); |
1252 | if (!entry) { |
1253 | dev_dbg(rvu->dev, "%s: failed to find entry for id=%d\n" , __func__, seq_id); |
1254 | mutex_unlock(lock: &table->lock); |
1255 | return -ENODATA; |
1256 | } |
1257 | |
1258 | cnt = (entry->opc_type == NPC_EXACT_OPC_CAM) ? &table->cam_tbl_entry_cnt : |
1259 | &table->mem_tbl_entry_cnt; |
1260 | |
1261 | /* delete from lists */ |
1262 | list_del_init(entry: &entry->list); |
1263 | list_del_init(entry: &entry->glist); |
1264 | |
1265 | (*cnt)--; |
1266 | |
1267 | rc = rvu_npc_exact_get_drop_rule_info(rvu, NIX_INTF_TYPE_CGX, cgx_id: entry->cgx_id, |
1268 | lmac_id: entry->lmac_id, drop_mcam_idx: &drop_mcam_idx, NULL, NULL, NULL); |
1269 | if (!rc) { |
1270 | dev_dbg(rvu->dev, "%s: failed to retrieve drop info for id=0x%x\n" , |
1271 | __func__, seq_id); |
1272 | mutex_unlock(lock: &table->lock); |
1273 | return -ENODATA; |
1274 | } |
1275 | |
1276 | if (entry->cmd) |
1277 | __rvu_npc_exact_cmd_rules_cnt_update(rvu, drop_mcam_idx, val: -1, enable_or_disable_cam: &disable_cam); |
1278 | |
1279 | /* No dmac filter rules; disable drop on hit rule */ |
1280 | if (disable_cam) { |
1281 | rvu_npc_enable_mcam_by_entry_index(rvu, entry: drop_mcam_idx, NIX_INTF_RX, enable: false); |
1282 | dev_dbg(rvu->dev, "%s: Disabling mcam idx %d\n" , |
1283 | __func__, drop_mcam_idx); |
1284 | } |
1285 | |
1286 | mutex_unlock(lock: &table->lock); |
1287 | |
1288 | rvu_npc_exact_dealloc_table_entry(rvu, opc_type: entry->opc_type, ways: entry->ways, index: entry->index); |
1289 | |
1290 | rvu_npc_exact_free_id(rvu, seq_id); |
1291 | |
1292 | dev_dbg(rvu->dev, "%s: delete entry success for id=0x%x, mca=%pM\n" , |
1293 | __func__, seq_id, entry->mac); |
1294 | kfree(objp: entry); |
1295 | |
1296 | return 0; |
1297 | } |
1298 | |
1299 | /** |
1300 | * rvu_npc_exact_add_table_entry - Adds a table entry |
1301 | * @rvu: resource virtualization unit. |
1302 | * @cgx_id: cgx identifier. |
1303 | * @lmac_id: lmac identifier. |
1304 | * @mac: MAC address. |
1305 | * @chan: Channel number. |
1306 | * @ctype: Channel Type. |
1307 | * @seq_id: Sequence number. |
1308 | * @cmd: Whether it is invoked by ethtool cmd. |
1309 | * @mcam_idx: NPC mcam index corresponding to MAC |
1310 | * @pcifunc: PCI func. |
1311 | * |
1312 | * Creates a new exact match table entry in either CAM or |
1313 | * MEM table. |
1314 | * Return: 0 upon success. |
1315 | */ |
1316 | static int rvu_npc_exact_add_table_entry(struct rvu *rvu, u8 cgx_id, u8 lmac_id, u8 *mac, |
1317 | u16 chan, u8 ctype, u32 *seq_id, bool cmd, |
1318 | u32 mcam_idx, u16 pcifunc) |
1319 | { |
1320 | int blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
1321 | enum npc_exact_opc_type opc_type; |
1322 | bool enable_cam = false; |
1323 | u32 drop_mcam_idx; |
1324 | u32 index; |
1325 | u64 mdata; |
1326 | bool rc; |
1327 | int err; |
1328 | u8 ways; |
1329 | |
1330 | ctype = 0; |
1331 | |
1332 | err = rvu_npc_exact_alloc_table_entry(rvu, mac, chan, ctype, index: &index, ways: &ways, opc_type: &opc_type); |
1333 | if (err) { |
1334 | dev_err(rvu->dev, "%s: Could not alloc in exact match table\n" , __func__); |
1335 | return err; |
1336 | } |
1337 | |
1338 | /* Write mdata to table */ |
1339 | mdata = rvu_exact_prepare_table_entry(rvu, enable: true, ctype, chan, mac_addr: mac); |
1340 | |
1341 | if (opc_type == NPC_EXACT_OPC_CAM) |
1342 | rvu_npc_exact_cam_table_write(rvu, blkaddr, index, mdata); |
1343 | else |
1344 | rvu_npc_exact_mem_table_write(rvu, blkaddr, ways, index, mdata); |
1345 | |
1346 | /* Insert entry to linked list */ |
1347 | err = rvu_npc_exact_add_to_list(rvu, opc_type, ways, index, cgx_id, lmac_id, |
1348 | mac_addr: mac, chan, ctype, seq_id, cmd, mcam_idx, pcifunc); |
1349 | if (err) { |
1350 | rvu_npc_exact_dealloc_table_entry(rvu, opc_type, ways, index); |
1351 | dev_err(rvu->dev, "%s: could not add to exact match table\n" , __func__); |
1352 | return err; |
1353 | } |
1354 | |
1355 | rc = rvu_npc_exact_get_drop_rule_info(rvu, NIX_INTF_TYPE_CGX, cgx_id, lmac_id, |
1356 | drop_mcam_idx: &drop_mcam_idx, NULL, NULL, NULL); |
1357 | if (!rc) { |
1358 | rvu_npc_exact_dealloc_table_entry(rvu, opc_type, ways, index); |
1359 | dev_dbg(rvu->dev, "%s: failed to get drop rule info cgx=%d lmac=%d\n" , |
1360 | __func__, cgx_id, lmac_id); |
1361 | return -EINVAL; |
1362 | } |
1363 | |
1364 | if (cmd) |
1365 | __rvu_npc_exact_cmd_rules_cnt_update(rvu, drop_mcam_idx, val: 1, enable_or_disable_cam: &enable_cam); |
1366 | |
1367 | /* First command rule; enable drop on hit rule */ |
1368 | if (enable_cam) { |
1369 | rvu_npc_enable_mcam_by_entry_index(rvu, entry: drop_mcam_idx, NIX_INTF_RX, enable: true); |
1370 | dev_dbg(rvu->dev, "%s: Enabling mcam idx %d\n" , |
1371 | __func__, drop_mcam_idx); |
1372 | } |
1373 | |
1374 | dev_dbg(rvu->dev, |
1375 | "%s: Successfully added entry (index=%d, dmac=%pM, ways=%d opc_type=%d\n" , |
1376 | __func__, index, mac, ways, opc_type); |
1377 | |
1378 | return 0; |
1379 | } |
1380 | |
1381 | /** |
1382 | * rvu_npc_exact_update_table_entry - Update exact match table. |
1383 | * @rvu: resource virtualization unit. |
1384 | * @cgx_id: CGX identifier. |
1385 | * @lmac_id: LMAC identifier. |
1386 | * @old_mac: Existing MAC address entry. |
1387 | * @new_mac: New MAC address entry. |
1388 | * @seq_id: Sequence identifier of the entry. |
1389 | * |
1390 | * Updates MAC address of an entry. If entry is in MEM table, new |
1391 | * hash value may not match with old one. |
1392 | * Return: 0 upon success. |
1393 | */ |
1394 | static int rvu_npc_exact_update_table_entry(struct rvu *rvu, u8 cgx_id, u8 lmac_id, |
1395 | u8 *old_mac, u8 *new_mac, u32 *seq_id) |
1396 | { |
1397 | int blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
1398 | struct npc_exact_table_entry *entry; |
1399 | struct npc_exact_table *table; |
1400 | u32 hash_index; |
1401 | u64 mdata; |
1402 | |
1403 | table = rvu->hw->table; |
1404 | |
1405 | mutex_lock(&table->lock); |
1406 | |
1407 | /* Lookup for entry which needs to be updated */ |
1408 | entry = __rvu_npc_exact_find_entry_by_seq_id(rvu, seq_id: *seq_id); |
1409 | if (!entry) { |
1410 | mutex_unlock(lock: &table->lock); |
1411 | dev_dbg(rvu->dev, |
1412 | "%s: failed to find entry for cgx_id=%d lmac_id=%d old_mac=%pM\n" , |
1413 | __func__, cgx_id, lmac_id, old_mac); |
1414 | return -ENODATA; |
1415 | } |
1416 | |
1417 | /* If entry is in mem table and new hash index is different than old |
1418 | * hash index, we cannot update the entry. Fail in these scenarios. |
1419 | */ |
1420 | if (entry->opc_type == NPC_EXACT_OPC_MEM) { |
1421 | hash_index = rvu_exact_calculate_hash(rvu, chan: entry->chan, ctype: entry->ctype, |
1422 | mac: new_mac, mask: table->mem_table.mask, |
1423 | table_depth: table->mem_table.depth); |
1424 | if (hash_index != entry->index) { |
1425 | dev_dbg(rvu->dev, |
1426 | "%s: Update failed due to index mismatch(new=0x%x, old=%x)\n" , |
1427 | __func__, hash_index, entry->index); |
1428 | mutex_unlock(lock: &table->lock); |
1429 | return -EINVAL; |
1430 | } |
1431 | } |
1432 | |
1433 | mdata = rvu_exact_prepare_table_entry(rvu, enable: true, ctype: entry->ctype, chan: entry->chan, mac_addr: new_mac); |
1434 | |
1435 | if (entry->opc_type == NPC_EXACT_OPC_MEM) |
1436 | rvu_npc_exact_mem_table_write(rvu, blkaddr, ways: entry->ways, index: entry->index, mdata); |
1437 | else |
1438 | rvu_npc_exact_cam_table_write(rvu, blkaddr, index: entry->index, mdata); |
1439 | |
1440 | /* Update entry fields */ |
1441 | ether_addr_copy(dst: entry->mac, src: new_mac); |
1442 | *seq_id = entry->seq_id; |
1443 | |
1444 | dev_dbg(rvu->dev, |
1445 | "%s: Successfully updated entry (index=%d, dmac=%pM, ways=%d opc_type=%d\n" , |
1446 | __func__, entry->index, entry->mac, entry->ways, entry->opc_type); |
1447 | |
1448 | dev_dbg(rvu->dev, "%s: Successfully updated entry (old mac=%pM new_mac=%pM\n" , |
1449 | __func__, old_mac, new_mac); |
1450 | |
1451 | mutex_unlock(lock: &table->lock); |
1452 | return 0; |
1453 | } |
1454 | |
1455 | /** |
1456 | * rvu_npc_exact_promisc_disable - Disable promiscuous mode. |
1457 | * @rvu: resource virtualization unit. |
1458 | * @pcifunc: pcifunc |
1459 | * |
1460 | * Drop rule is against each PF. We dont support DMAC filter for |
1461 | * VF. |
1462 | * Return: 0 upon success |
1463 | */ |
1464 | |
1465 | int rvu_npc_exact_promisc_disable(struct rvu *rvu, u16 pcifunc) |
1466 | { |
1467 | struct npc_exact_table *table; |
1468 | int pf = rvu_get_pf(pcifunc); |
1469 | u8 cgx_id, lmac_id; |
1470 | u32 drop_mcam_idx; |
1471 | bool *promisc; |
1472 | bool rc; |
1473 | |
1474 | table = rvu->hw->table; |
1475 | |
1476 | rvu_get_cgx_lmac_id(map: rvu->pf2cgxlmac_map[pf], cgx_id: &cgx_id, lmac_id: &lmac_id); |
1477 | rc = rvu_npc_exact_get_drop_rule_info(rvu, NIX_INTF_TYPE_CGX, cgx_id, lmac_id, |
1478 | drop_mcam_idx: &drop_mcam_idx, NULL, NULL, NULL); |
1479 | if (!rc) { |
1480 | dev_dbg(rvu->dev, "%s: failed to get drop rule info cgx=%d lmac=%d\n" , |
1481 | __func__, cgx_id, lmac_id); |
1482 | return -EINVAL; |
1483 | } |
1484 | |
1485 | mutex_lock(&table->lock); |
1486 | promisc = &table->promisc_mode[drop_mcam_idx]; |
1487 | |
1488 | if (!*promisc) { |
1489 | mutex_unlock(lock: &table->lock); |
1490 | dev_dbg(rvu->dev, "%s: Err Already promisc mode disabled (cgx=%d lmac=%d)\n" , |
1491 | __func__, cgx_id, lmac_id); |
1492 | return LMAC_AF_ERR_INVALID_PARAM; |
1493 | } |
1494 | *promisc = false; |
1495 | mutex_unlock(lock: &table->lock); |
1496 | |
1497 | /* Enable drop rule */ |
1498 | rvu_npc_enable_mcam_by_entry_index(rvu, entry: drop_mcam_idx, NIX_INTF_RX, |
1499 | enable: true); |
1500 | |
1501 | dev_dbg(rvu->dev, "%s: disabled promisc mode (cgx=%d lmac=%d)\n" , |
1502 | __func__, cgx_id, lmac_id); |
1503 | return 0; |
1504 | } |
1505 | |
1506 | /** |
1507 | * rvu_npc_exact_promisc_enable - Enable promiscuous mode. |
1508 | * @rvu: resource virtualization unit. |
1509 | * @pcifunc: pcifunc. |
1510 | * Return: 0 upon success |
1511 | */ |
1512 | int rvu_npc_exact_promisc_enable(struct rvu *rvu, u16 pcifunc) |
1513 | { |
1514 | struct npc_exact_table *table; |
1515 | int pf = rvu_get_pf(pcifunc); |
1516 | u8 cgx_id, lmac_id; |
1517 | u32 drop_mcam_idx; |
1518 | bool *promisc; |
1519 | bool rc; |
1520 | |
1521 | table = rvu->hw->table; |
1522 | |
1523 | rvu_get_cgx_lmac_id(map: rvu->pf2cgxlmac_map[pf], cgx_id: &cgx_id, lmac_id: &lmac_id); |
1524 | rc = rvu_npc_exact_get_drop_rule_info(rvu, NIX_INTF_TYPE_CGX, cgx_id, lmac_id, |
1525 | drop_mcam_idx: &drop_mcam_idx, NULL, NULL, NULL); |
1526 | if (!rc) { |
1527 | dev_dbg(rvu->dev, "%s: failed to get drop rule info cgx=%d lmac=%d\n" , |
1528 | __func__, cgx_id, lmac_id); |
1529 | return -EINVAL; |
1530 | } |
1531 | |
1532 | mutex_lock(&table->lock); |
1533 | promisc = &table->promisc_mode[drop_mcam_idx]; |
1534 | |
1535 | if (*promisc) { |
1536 | mutex_unlock(lock: &table->lock); |
1537 | dev_dbg(rvu->dev, "%s: Already in promisc mode (cgx=%d lmac=%d)\n" , |
1538 | __func__, cgx_id, lmac_id); |
1539 | return LMAC_AF_ERR_INVALID_PARAM; |
1540 | } |
1541 | *promisc = true; |
1542 | mutex_unlock(lock: &table->lock); |
1543 | |
1544 | /* disable drop rule */ |
1545 | rvu_npc_enable_mcam_by_entry_index(rvu, entry: drop_mcam_idx, NIX_INTF_RX, |
1546 | enable: false); |
1547 | |
1548 | dev_dbg(rvu->dev, "%s: Enabled promisc mode (cgx=%d lmac=%d)\n" , |
1549 | __func__, cgx_id, lmac_id); |
1550 | return 0; |
1551 | } |
1552 | |
1553 | /** |
1554 | * rvu_npc_exact_mac_addr_reset - Delete PF mac address. |
1555 | * @rvu: resource virtualization unit. |
1556 | * @req: Reset request |
1557 | * @rsp: Reset response. |
1558 | * Return: 0 upon success |
1559 | */ |
1560 | int rvu_npc_exact_mac_addr_reset(struct rvu *rvu, struct cgx_mac_addr_reset_req *req, |
1561 | struct msg_rsp *rsp) |
1562 | { |
1563 | int pf = rvu_get_pf(pcifunc: req->hdr.pcifunc); |
1564 | u32 seq_id = req->index; |
1565 | struct rvu_pfvf *pfvf; |
1566 | u8 cgx_id, lmac_id; |
1567 | int rc; |
1568 | |
1569 | rvu_get_cgx_lmac_id(map: rvu->pf2cgxlmac_map[pf], cgx_id: &cgx_id, lmac_id: &lmac_id); |
1570 | |
1571 | pfvf = rvu_get_pfvf(rvu, pcifunc: req->hdr.pcifunc); |
1572 | |
1573 | rc = rvu_npc_exact_del_table_entry_by_id(rvu, seq_id); |
1574 | if (rc) { |
1575 | /* TODO: how to handle this error case ? */ |
1576 | dev_err(rvu->dev, "%s MAC (%pM) del PF=%d failed\n" , __func__, pfvf->mac_addr, pf); |
1577 | return 0; |
1578 | } |
1579 | |
1580 | dev_dbg(rvu->dev, "%s MAC (%pM) del PF=%d success (seq_id=%u)\n" , |
1581 | __func__, pfvf->mac_addr, pf, seq_id); |
1582 | return 0; |
1583 | } |
1584 | |
1585 | /** |
1586 | * rvu_npc_exact_mac_addr_update - Update mac address field with new value. |
1587 | * @rvu: resource virtualization unit. |
1588 | * @req: Update request. |
1589 | * @rsp: Update response. |
1590 | * Return: 0 upon success |
1591 | */ |
1592 | int rvu_npc_exact_mac_addr_update(struct rvu *rvu, |
1593 | struct cgx_mac_addr_update_req *req, |
1594 | struct cgx_mac_addr_update_rsp *rsp) |
1595 | { |
1596 | int pf = rvu_get_pf(pcifunc: req->hdr.pcifunc); |
1597 | struct npc_exact_table_entry *entry; |
1598 | struct npc_exact_table *table; |
1599 | struct rvu_pfvf *pfvf; |
1600 | u32 seq_id, mcam_idx; |
1601 | u8 old_mac[ETH_ALEN]; |
1602 | u8 cgx_id, lmac_id; |
1603 | int rc; |
1604 | |
1605 | if (!is_cgx_config_permitted(rvu, pcifunc: req->hdr.pcifunc)) |
1606 | return LMAC_AF_ERR_PERM_DENIED; |
1607 | |
1608 | dev_dbg(rvu->dev, "%s: Update request for seq_id=%d, mac=%pM\n" , |
1609 | __func__, req->index, req->mac_addr); |
1610 | |
1611 | rvu_get_cgx_lmac_id(map: rvu->pf2cgxlmac_map[pf], cgx_id: &cgx_id, lmac_id: &lmac_id); |
1612 | |
1613 | pfvf = rvu_get_pfvf(rvu, pcifunc: req->hdr.pcifunc); |
1614 | |
1615 | table = rvu->hw->table; |
1616 | |
1617 | mutex_lock(&table->lock); |
1618 | |
1619 | /* Lookup for entry which needs to be updated */ |
1620 | entry = __rvu_npc_exact_find_entry_by_seq_id(rvu, seq_id: req->index); |
1621 | if (!entry) { |
1622 | dev_err(rvu->dev, "%s: failed to find entry for id=0x%x\n" , __func__, req->index); |
1623 | mutex_unlock(lock: &table->lock); |
1624 | return LMAC_AF_ERR_EXACT_MATCH_TBL_LOOK_UP_FAILED; |
1625 | } |
1626 | ether_addr_copy(dst: old_mac, src: entry->mac); |
1627 | seq_id = entry->seq_id; |
1628 | mcam_idx = entry->mcam_idx; |
1629 | mutex_unlock(lock: &table->lock); |
1630 | |
1631 | rc = rvu_npc_exact_update_table_entry(rvu, cgx_id, lmac_id, old_mac, |
1632 | new_mac: req->mac_addr, seq_id: &seq_id); |
1633 | if (!rc) { |
1634 | rsp->index = seq_id; |
1635 | dev_dbg(rvu->dev, "%s mac:%pM (pfvf:%pM default:%pM) update to PF=%d success\n" , |
1636 | __func__, req->mac_addr, pfvf->mac_addr, pfvf->default_mac, pf); |
1637 | ether_addr_copy(dst: pfvf->mac_addr, src: req->mac_addr); |
1638 | return 0; |
1639 | } |
1640 | |
1641 | /* Try deleting and adding it again */ |
1642 | rc = rvu_npc_exact_del_table_entry_by_id(rvu, seq_id: req->index); |
1643 | if (rc) { |
1644 | /* This could be a new entry */ |
1645 | dev_dbg(rvu->dev, "%s MAC (%pM) del PF=%d failed\n" , __func__, |
1646 | pfvf->mac_addr, pf); |
1647 | } |
1648 | |
1649 | rc = rvu_npc_exact_add_table_entry(rvu, cgx_id, lmac_id, mac: req->mac_addr, |
1650 | chan: pfvf->rx_chan_base, ctype: 0, seq_id: &seq_id, cmd: true, |
1651 | mcam_idx, pcifunc: req->hdr.pcifunc); |
1652 | if (rc) { |
1653 | dev_err(rvu->dev, "%s MAC (%pM) add PF=%d failed\n" , __func__, |
1654 | req->mac_addr, pf); |
1655 | return LMAC_AF_ERR_EXACT_MATCH_TBL_ADD_FAILED; |
1656 | } |
1657 | |
1658 | rsp->index = seq_id; |
1659 | dev_dbg(rvu->dev, |
1660 | "%s MAC (new:%pM, old=%pM default:%pM) del and add to PF=%d success (seq_id=%u)\n" , |
1661 | __func__, req->mac_addr, pfvf->mac_addr, pfvf->default_mac, pf, seq_id); |
1662 | |
1663 | ether_addr_copy(dst: pfvf->mac_addr, src: req->mac_addr); |
1664 | return 0; |
1665 | } |
1666 | |
1667 | /** |
1668 | * rvu_npc_exact_mac_addr_add - Adds MAC address to exact match table. |
1669 | * @rvu: resource virtualization unit. |
1670 | * @req: Add request. |
1671 | * @rsp: Add response. |
1672 | * Return: 0 upon success |
1673 | */ |
1674 | int rvu_npc_exact_mac_addr_add(struct rvu *rvu, |
1675 | struct cgx_mac_addr_add_req *req, |
1676 | struct cgx_mac_addr_add_rsp *rsp) |
1677 | { |
1678 | int pf = rvu_get_pf(pcifunc: req->hdr.pcifunc); |
1679 | struct rvu_pfvf *pfvf; |
1680 | u8 cgx_id, lmac_id; |
1681 | int rc = 0; |
1682 | u32 seq_id; |
1683 | |
1684 | rvu_get_cgx_lmac_id(map: rvu->pf2cgxlmac_map[pf], cgx_id: &cgx_id, lmac_id: &lmac_id); |
1685 | pfvf = rvu_get_pfvf(rvu, pcifunc: req->hdr.pcifunc); |
1686 | |
1687 | rc = rvu_npc_exact_add_table_entry(rvu, cgx_id, lmac_id, mac: req->mac_addr, |
1688 | chan: pfvf->rx_chan_base, ctype: 0, seq_id: &seq_id, |
1689 | cmd: true, mcam_idx: -1, pcifunc: req->hdr.pcifunc); |
1690 | |
1691 | if (!rc) { |
1692 | rsp->index = seq_id; |
1693 | dev_dbg(rvu->dev, "%s MAC (%pM) add to PF=%d success (seq_id=%u)\n" , |
1694 | __func__, req->mac_addr, pf, seq_id); |
1695 | return 0; |
1696 | } |
1697 | |
1698 | dev_err(rvu->dev, "%s MAC (%pM) add to PF=%d failed\n" , __func__, |
1699 | req->mac_addr, pf); |
1700 | return LMAC_AF_ERR_EXACT_MATCH_TBL_ADD_FAILED; |
1701 | } |
1702 | |
1703 | /** |
1704 | * rvu_npc_exact_mac_addr_del - Delete DMAC filter |
1705 | * @rvu: resource virtualization unit. |
1706 | * @req: Delete request. |
1707 | * @rsp: Delete response. |
1708 | * Return: 0 upon success |
1709 | */ |
1710 | int rvu_npc_exact_mac_addr_del(struct rvu *rvu, |
1711 | struct cgx_mac_addr_del_req *req, |
1712 | struct msg_rsp *rsp) |
1713 | { |
1714 | int pf = rvu_get_pf(pcifunc: req->hdr.pcifunc); |
1715 | int rc; |
1716 | |
1717 | rc = rvu_npc_exact_del_table_entry_by_id(rvu, seq_id: req->index); |
1718 | if (!rc) { |
1719 | dev_dbg(rvu->dev, "%s del to PF=%d success (seq_id=%u)\n" , |
1720 | __func__, pf, req->index); |
1721 | return 0; |
1722 | } |
1723 | |
1724 | dev_err(rvu->dev, "%s del to PF=%d failed (seq_id=%u)\n" , |
1725 | __func__, pf, req->index); |
1726 | return LMAC_AF_ERR_EXACT_MATCH_TBL_DEL_FAILED; |
1727 | } |
1728 | |
1729 | /** |
1730 | * rvu_npc_exact_mac_addr_set - Add PF mac address to dmac filter. |
1731 | * @rvu: resource virtualization unit. |
1732 | * @req: Set request. |
1733 | * @rsp: Set response. |
1734 | * Return: 0 upon success |
1735 | */ |
1736 | int rvu_npc_exact_mac_addr_set(struct rvu *rvu, struct cgx_mac_addr_set_or_get *req, |
1737 | struct cgx_mac_addr_set_or_get *rsp) |
1738 | { |
1739 | int pf = rvu_get_pf(pcifunc: req->hdr.pcifunc); |
1740 | u32 seq_id = req->index; |
1741 | struct rvu_pfvf *pfvf; |
1742 | u8 cgx_id, lmac_id; |
1743 | u32 mcam_idx = -1; |
1744 | int rc, nixlf; |
1745 | |
1746 | rvu_get_cgx_lmac_id(map: rvu->pf2cgxlmac_map[pf], cgx_id: &cgx_id, lmac_id: &lmac_id); |
1747 | |
1748 | pfvf = &rvu->pf[pf]; |
1749 | |
1750 | /* If table does not have an entry; both update entry and del table entry API |
1751 | * below fails. Those are not failure conditions. |
1752 | */ |
1753 | rc = rvu_npc_exact_update_table_entry(rvu, cgx_id, lmac_id, old_mac: pfvf->mac_addr, |
1754 | new_mac: req->mac_addr, seq_id: &seq_id); |
1755 | if (!rc) { |
1756 | rsp->index = seq_id; |
1757 | ether_addr_copy(dst: pfvf->mac_addr, src: req->mac_addr); |
1758 | ether_addr_copy(dst: rsp->mac_addr, src: req->mac_addr); |
1759 | dev_dbg(rvu->dev, "%s MAC (%pM) update to PF=%d success\n" , |
1760 | __func__, req->mac_addr, pf); |
1761 | return 0; |
1762 | } |
1763 | |
1764 | /* Try deleting and adding it again */ |
1765 | rc = rvu_npc_exact_del_table_entry_by_id(rvu, seq_id: req->index); |
1766 | if (rc) { |
1767 | dev_dbg(rvu->dev, "%s MAC (%pM) del PF=%d failed\n" , |
1768 | __func__, pfvf->mac_addr, pf); |
1769 | } |
1770 | |
1771 | /* find mcam entry if exist */ |
1772 | rc = nix_get_nixlf(rvu, pcifunc: req->hdr.pcifunc, nixlf: &nixlf, NULL); |
1773 | if (!rc) { |
1774 | mcam_idx = npc_get_nixlf_mcam_index(mcam: &rvu->hw->mcam, pcifunc: req->hdr.pcifunc, |
1775 | nixlf, NIXLF_UCAST_ENTRY); |
1776 | } |
1777 | |
1778 | rc = rvu_npc_exact_add_table_entry(rvu, cgx_id, lmac_id, mac: req->mac_addr, |
1779 | chan: pfvf->rx_chan_base, ctype: 0, seq_id: &seq_id, |
1780 | cmd: true, mcam_idx, pcifunc: req->hdr.pcifunc); |
1781 | if (rc) { |
1782 | dev_err(rvu->dev, "%s MAC (%pM) add PF=%d failed\n" , |
1783 | __func__, req->mac_addr, pf); |
1784 | return LMAC_AF_ERR_EXACT_MATCH_TBL_ADD_FAILED; |
1785 | } |
1786 | |
1787 | rsp->index = seq_id; |
1788 | ether_addr_copy(dst: rsp->mac_addr, src: req->mac_addr); |
1789 | ether_addr_copy(dst: pfvf->mac_addr, src: req->mac_addr); |
1790 | dev_dbg(rvu->dev, |
1791 | "%s MAC (%pM) del and add to PF=%d success (seq_id=%u)\n" , |
1792 | __func__, req->mac_addr, pf, seq_id); |
1793 | return 0; |
1794 | } |
1795 | |
1796 | /** |
1797 | * rvu_npc_exact_can_disable_feature - Check if feature can be disabled. |
1798 | * @rvu: resource virtualization unit. |
1799 | * Return: True if exact match feature is supported. |
1800 | */ |
1801 | bool rvu_npc_exact_can_disable_feature(struct rvu *rvu) |
1802 | { |
1803 | struct npc_exact_table *table = rvu->hw->table; |
1804 | bool empty; |
1805 | |
1806 | if (!rvu->hw->cap.npc_exact_match_enabled) |
1807 | return false; |
1808 | |
1809 | mutex_lock(&table->lock); |
1810 | empty = list_empty(head: &table->lhead_gbl); |
1811 | mutex_unlock(lock: &table->lock); |
1812 | |
1813 | return empty; |
1814 | } |
1815 | |
1816 | /** |
1817 | * rvu_npc_exact_disable_feature - Disable feature. |
1818 | * @rvu: resource virtualization unit. |
1819 | */ |
1820 | void rvu_npc_exact_disable_feature(struct rvu *rvu) |
1821 | { |
1822 | rvu->hw->cap.npc_exact_match_enabled = false; |
1823 | } |
1824 | |
1825 | /** |
1826 | * rvu_npc_exact_reset - Delete and free all entry which match pcifunc. |
1827 | * @rvu: resource virtualization unit. |
1828 | * @pcifunc: PCI func to match. |
1829 | */ |
1830 | void rvu_npc_exact_reset(struct rvu *rvu, u16 pcifunc) |
1831 | { |
1832 | struct npc_exact_table *table = rvu->hw->table; |
1833 | struct npc_exact_table_entry *tmp, *iter; |
1834 | u32 seq_id; |
1835 | |
1836 | mutex_lock(&table->lock); |
1837 | list_for_each_entry_safe(iter, tmp, &table->lhead_gbl, glist) { |
1838 | if (pcifunc != iter->pcifunc) |
1839 | continue; |
1840 | |
1841 | seq_id = iter->seq_id; |
1842 | dev_dbg(rvu->dev, "%s: resetting pcifun=%d seq_id=%u\n" , __func__, |
1843 | pcifunc, seq_id); |
1844 | |
1845 | mutex_unlock(lock: &table->lock); |
1846 | rvu_npc_exact_del_table_entry_by_id(rvu, seq_id); |
1847 | mutex_lock(&table->lock); |
1848 | } |
1849 | mutex_unlock(lock: &table->lock); |
1850 | } |
1851 | |
1852 | /** |
1853 | * rvu_npc_exact_init - initialize exact match table |
1854 | * @rvu: resource virtualization unit. |
1855 | * |
1856 | * Initialize HW and SW resources to manage 4way-2K table and fully |
1857 | * associative 32-entry mcam table. |
1858 | * Return: 0 upon success. |
1859 | */ |
1860 | int rvu_npc_exact_init(struct rvu *rvu) |
1861 | { |
1862 | u64 bcast_mcast_val, bcast_mcast_mask; |
1863 | struct npc_exact_table *table; |
1864 | u64 exact_val, exact_mask; |
1865 | u64 chan_val, chan_mask; |
1866 | u8 cgx_id, lmac_id; |
1867 | u32 *drop_mcam_idx; |
1868 | u16 max_lmac_cnt; |
1869 | u64 npc_const3; |
1870 | int table_size; |
1871 | int blkaddr; |
1872 | u16 pcifunc; |
1873 | int err, i; |
1874 | u64 cfg; |
1875 | bool rc; |
1876 | |
1877 | /* Read NPC_AF_CONST3 and check for have exact |
1878 | * match functionality is present |
1879 | */ |
1880 | blkaddr = rvu_get_blkaddr(rvu, blktype: BLKTYPE_NPC, pcifunc: 0); |
1881 | if (blkaddr < 0) { |
1882 | dev_err(rvu->dev, "%s: NPC block not implemented\n" , __func__); |
1883 | return -EINVAL; |
1884 | } |
1885 | |
1886 | /* Check exact match feature is supported */ |
1887 | npc_const3 = rvu_read64(rvu, block: blkaddr, NPC_AF_CONST3); |
1888 | if (!(npc_const3 & BIT_ULL(62))) |
1889 | return 0; |
1890 | |
1891 | /* Check if kex profile has enabled EXACT match nibble */ |
1892 | cfg = rvu_read64(rvu, block: blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX)); |
1893 | if (!(cfg & NPC_EXACT_NIBBLE_HIT)) |
1894 | return 0; |
1895 | |
1896 | /* Set capability to true */ |
1897 | rvu->hw->cap.npc_exact_match_enabled = true; |
1898 | |
1899 | table = kzalloc(size: sizeof(*table), GFP_KERNEL); |
1900 | if (!table) |
1901 | return -ENOMEM; |
1902 | |
1903 | dev_dbg(rvu->dev, "%s: Memory allocation for table success\n" , __func__); |
1904 | rvu->hw->table = table; |
1905 | |
1906 | /* Read table size, ways and depth */ |
1907 | table->mem_table.ways = FIELD_GET(GENMASK_ULL(19, 16), npc_const3); |
1908 | table->mem_table.depth = FIELD_GET(GENMASK_ULL(15, 0), npc_const3); |
1909 | table->cam_table.depth = FIELD_GET(GENMASK_ULL(31, 24), npc_const3); |
1910 | |
1911 | dev_dbg(rvu->dev, "%s: NPC exact match 4way_2k table(ways=%d, depth=%d)\n" , |
1912 | __func__, table->mem_table.ways, table->cam_table.depth); |
1913 | |
1914 | /* Check if depth of table is not a sequre of 2 |
1915 | * TODO: why _builtin_popcount() is not working ? |
1916 | */ |
1917 | if ((table->mem_table.depth & (table->mem_table.depth - 1)) != 0) { |
1918 | dev_err(rvu->dev, |
1919 | "%s: NPC exact match 4way_2k table depth(%d) is not square of 2\n" , |
1920 | __func__, table->mem_table.depth); |
1921 | return -EINVAL; |
1922 | } |
1923 | |
1924 | table_size = table->mem_table.depth * table->mem_table.ways; |
1925 | |
1926 | /* Allocate bitmap for 4way 2K table */ |
1927 | table->mem_table.bmap = devm_bitmap_zalloc(dev: rvu->dev, nbits: table_size, |
1928 | GFP_KERNEL); |
1929 | if (!table->mem_table.bmap) |
1930 | return -ENOMEM; |
1931 | |
1932 | dev_dbg(rvu->dev, "%s: Allocated bitmap for 4way 2K entry table\n" , __func__); |
1933 | |
1934 | /* Allocate bitmap for 32 entry mcam */ |
1935 | table->cam_table.bmap = devm_bitmap_zalloc(dev: rvu->dev, nbits: 32, GFP_KERNEL); |
1936 | |
1937 | if (!table->cam_table.bmap) |
1938 | return -ENOMEM; |
1939 | |
1940 | dev_dbg(rvu->dev, "%s: Allocated bitmap for 32 entry cam\n" , __func__); |
1941 | |
1942 | table->tot_ids = table_size + table->cam_table.depth; |
1943 | table->id_bmap = devm_bitmap_zalloc(dev: rvu->dev, nbits: table->tot_ids, |
1944 | GFP_KERNEL); |
1945 | |
1946 | if (!table->id_bmap) |
1947 | return -ENOMEM; |
1948 | |
1949 | dev_dbg(rvu->dev, "%s: Allocated bitmap for id map (total=%d)\n" , |
1950 | __func__, table->tot_ids); |
1951 | |
1952 | /* Initialize list heads for npc_exact_table entries. |
1953 | * This entry is used by debugfs to show entries in |
1954 | * exact match table. |
1955 | */ |
1956 | for (i = 0; i < NPC_EXACT_TBL_MAX_WAYS; i++) |
1957 | INIT_LIST_HEAD(list: &table->lhead_mem_tbl_entry[i]); |
1958 | |
1959 | INIT_LIST_HEAD(list: &table->lhead_cam_tbl_entry); |
1960 | INIT_LIST_HEAD(list: &table->lhead_gbl); |
1961 | |
1962 | mutex_init(&table->lock); |
1963 | |
1964 | rvu_exact_config_secret_key(rvu); |
1965 | rvu_exact_config_search_key(rvu); |
1966 | |
1967 | rvu_exact_config_table_mask(rvu); |
1968 | rvu_exact_config_result_ctrl(rvu, depth: table->mem_table.depth); |
1969 | |
1970 | /* - No drop rule for LBK |
1971 | * - Drop rules for SDP and each LMAC. |
1972 | */ |
1973 | exact_val = !NPC_EXACT_RESULT_HIT; |
1974 | exact_mask = NPC_EXACT_RESULT_HIT; |
1975 | |
1976 | /* nibble - 3 2 1 0 |
1977 | * L3B L3M L2B L2M |
1978 | */ |
1979 | bcast_mcast_val = 0b0000; |
1980 | bcast_mcast_mask = 0b0011; |
1981 | |
1982 | /* Install SDP drop rule */ |
1983 | drop_mcam_idx = &table->num_drop_rules; |
1984 | |
1985 | max_lmac_cnt = rvu->cgx_cnt_max * rvu->hw->lmac_per_cgx + |
1986 | PF_CGXMAP_BASE; |
1987 | |
1988 | for (i = PF_CGXMAP_BASE; i < max_lmac_cnt; i++) { |
1989 | if (rvu->pf2cgxlmac_map[i] == 0xFF) |
1990 | continue; |
1991 | |
1992 | rvu_get_cgx_lmac_id(map: rvu->pf2cgxlmac_map[i], cgx_id: &cgx_id, lmac_id: &lmac_id); |
1993 | |
1994 | rc = rvu_npc_exact_calc_drop_rule_chan_and_mask(rvu, NIX_INTF_TYPE_CGX, cgx_id, |
1995 | lmac_id, val: &chan_val, mask: &chan_mask); |
1996 | if (!rc) { |
1997 | dev_err(rvu->dev, |
1998 | "%s: failed, info chan_val=0x%llx chan_mask=0x%llx rule_id=%d\n" , |
1999 | __func__, chan_val, chan_mask, *drop_mcam_idx); |
2000 | return -EINVAL; |
2001 | } |
2002 | |
2003 | /* Filter rules are only for PF */ |
2004 | pcifunc = RVU_PFFUNC(i, 0); |
2005 | |
2006 | dev_dbg(rvu->dev, |
2007 | "%s:Drop rule cgx=%d lmac=%d chan(val=0x%llx, mask=0x%llx\n" , |
2008 | __func__, cgx_id, lmac_id, chan_val, chan_mask); |
2009 | |
2010 | rc = rvu_npc_exact_save_drop_rule_chan_and_mask(rvu, drop_mcam_idx: table->num_drop_rules, |
2011 | chan_val, chan_mask, pcifunc); |
2012 | if (!rc) { |
2013 | dev_err(rvu->dev, |
2014 | "%s: failed to set drop info for cgx=%d, lmac=%d, chan=%llx\n" , |
2015 | __func__, cgx_id, lmac_id, chan_val); |
2016 | return -EINVAL; |
2017 | } |
2018 | |
2019 | err = npc_install_mcam_drop_rule(rvu, mcam_idx: *drop_mcam_idx, |
2020 | counter_idx: &table->counter_idx[*drop_mcam_idx], |
2021 | chan_val, chan_mask, |
2022 | exact_val, exact_mask, |
2023 | bcast_mcast_val, bcast_mcast_mask); |
2024 | if (err) { |
2025 | dev_err(rvu->dev, |
2026 | "failed to configure drop rule (cgx=%d lmac=%d)\n" , |
2027 | cgx_id, lmac_id); |
2028 | return err; |
2029 | } |
2030 | |
2031 | (*drop_mcam_idx)++; |
2032 | } |
2033 | |
2034 | dev_info(rvu->dev, "initialized exact match table successfully\n" ); |
2035 | return 0; |
2036 | } |
2037 | |