xref: /dpdk/drivers/net/sfc/sfc_tbls.c (revision bc712f1c86fc9c2bb5bb41a80e12f34e224f4c6d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2023 Advanced Micro Devices, Inc.
4  */
5 
6 #include "sfc.h"
7 #include "sfc_tbls.h"
8 #include "sfc_debug.h"
9 
10 #include <rte_ip.h>
11 
12 /* Number of bits in uint32_t type */
13 #define SFC_TBLS_U32_BITS (sizeof(uint32_t) * CHAR_BIT)
14 
15 int
sfc_tbls_attach(struct sfc_adapter * sa)16 sfc_tbls_attach(struct sfc_adapter *sa)
17 {
18 	struct sfc_tbls *tables = &sa->hw_tables;
19 	const struct sfc_mae *mae = &sa->mae;
20 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
21 	int rc;
22 
23 	sfc_log_init(sa, "entry");
24 
25 	if (mae->status != SFC_MAE_STATUS_ADMIN ||
26 	    !encp->enc_table_api_supported) {
27 		tables->status = SFC_TBLS_STATUS_UNSUPPORTED;
28 		return 0;
29 	}
30 
31 	tables->status = SFC_TBLS_STATUS_SUPPORTED;
32 
33 	rc = sfc_tbl_meta_init(sa);
34 	if (rc != 0)
35 		return rc;
36 
37 	sfc_log_init(sa, "done");
38 
39 	return 0;
40 }
41 
42 void
sfc_tbls_detach(struct sfc_adapter * sa)43 sfc_tbls_detach(struct sfc_adapter *sa)
44 {
45 	struct sfc_tbls *tables = &sa->hw_tables;
46 
47 	sfc_log_init(sa, "entry");
48 
49 	if (tables->status != SFC_TBLS_STATUS_SUPPORTED)
50 		goto done;
51 
52 	sfc_tbl_meta_fini(sa);
53 
54 done:
55 	sfc_log_init(sa, "done");
56 
57 	tables->status = SFC_TBLS_STATUS_UNKNOWN;
58 }
59 
60 int
sfc_tbls_start(struct sfc_adapter * sa)61 sfc_tbls_start(struct sfc_adapter *sa)
62 {
63 	struct sfc_tbls *tables = &sa->hw_tables;
64 	int rc;
65 
66 	if (tables->status == SFC_TBLS_STATUS_UNKNOWN) {
67 		rc = sfc_tbls_attach(sa);
68 		return rc;
69 	}
70 
71 	return 0;
72 }
73 
74 static uint32_t
sfc_tbls_field_update(uint32_t in,uint16_t lbn,uint16_t width,uint32_t value)75 sfc_tbls_field_update(uint32_t in, uint16_t lbn, uint16_t width, uint32_t value)
76 {
77 	uint32_t mask;
78 
79 	SFC_ASSERT(width <= SFC_TBLS_U32_BITS);
80 
81 	if (width == SFC_TBLS_U32_BITS)
82 		return value;
83 
84 	mask = RTE_LEN2MASK(width, uint32_t);
85 	value &= mask;
86 
87 	if (lbn != 0) {
88 		mask <<= lbn;
89 		value <<= lbn;
90 	}
91 
92 	return (in & (~mask)) | value;
93 }
94 
95 void
sfc_tbls_field_set_u32(uint32_t data[],__rte_unused unsigned int data_size,uint16_t lbn,uint16_t width,uint32_t value)96 sfc_tbls_field_set_u32(uint32_t data[], __rte_unused unsigned int data_size,
97 		       uint16_t lbn, uint16_t width, uint32_t value)
98 {
99 	uint32_t data_offset = 0;
100 
101 	if (lbn >= SFC_TBLS_U32_BITS) {
102 		data_offset = lbn / SFC_TBLS_U32_BITS;
103 
104 		SFC_ASSERT(data_offset < data_size);
105 
106 		data += data_offset;
107 		lbn %= SFC_TBLS_U32_BITS;
108 	}
109 
110 	if (lbn + width <= SFC_TBLS_U32_BITS) {
111 		*data = sfc_tbls_field_update(*data, lbn, width, value);
112 	} else {
113 		*data = sfc_tbls_field_update(*data, lbn,
114 					      SFC_TBLS_U32_BITS - lbn, value);
115 		value >>= SFC_TBLS_U32_BITS - lbn;
116 
117 		data_offset++;
118 		SFC_ASSERT(data_offset < data_size);
119 
120 		data++;
121 		*data = sfc_tbls_field_update(*data, 0,
122 					      width + lbn - SFC_TBLS_U32_BITS,
123 					      value);
124 	}
125 }
126 
127 void
sfc_tbls_field_set_u16(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,uint16_t value)128 sfc_tbls_field_set_u16(uint32_t data[], unsigned int data_size, uint16_t lbn,
129 		       uint16_t width, uint16_t value)
130 {
131 	sfc_tbls_field_set_u32(data, data_size, lbn, width, value);
132 }
133 
134 void
sfc_tbls_field_set_u8(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,uint8_t value)135 sfc_tbls_field_set_u8(uint32_t data[], unsigned int data_size, uint16_t lbn,
136 		      uint16_t width, uint8_t value)
137 {
138 	sfc_tbls_field_set_u32(data, data_size, lbn, width, value);
139 }
140 
141 void
sfc_tbls_field_set_ip(uint32_t data[],unsigned int data_size,uint16_t lbn,__rte_unused uint16_t width,const uint32_t * ip)142 sfc_tbls_field_set_ip(uint32_t data[], unsigned int data_size, uint16_t lbn,
143 		      __rte_unused uint16_t width, const uint32_t *ip)
144 {
145 	unsigned int i;
146 	size_t ipv6_addr_len = RTE_SIZEOF_FIELD(struct rte_ipv6_hdr, src_addr);
147 
148 	/*
149 	 * The same 128-bit container is used to store either
150 	 * an IPv4 or an IPv6 address, with an IPv4 address
151 	 * assumed to have 12 trailing zeroes.
152 	 */
153 	SFC_ASSERT(width == ipv6_addr_len * CHAR_BIT);
154 
155 	for (i = 0; i < ipv6_addr_len / sizeof(*ip); i++) {
156 		sfc_tbls_field_set_u32(data, data_size, lbn,
157 				       SFC_TBLS_U32_BITS, ip[i]);
158 		lbn += SFC_TBLS_U32_BITS;
159 	}
160 }
161 
162 void
sfc_tbls_field_set_u64(uint32_t data[],__rte_unused unsigned int data_size,uint16_t lbn,uint16_t width,uint64_t value)163 sfc_tbls_field_set_u64(uint32_t data[], __rte_unused unsigned int data_size,
164 		       uint16_t lbn, uint16_t width, uint64_t value)
165 {
166 	uint32_t data_offset = 0;
167 
168 	if (lbn >= SFC_TBLS_U32_BITS) {
169 		data_offset = lbn / SFC_TBLS_U32_BITS;
170 
171 		SFC_ASSERT(data_offset < data_size);
172 
173 		data += data_offset;
174 		lbn %= SFC_TBLS_U32_BITS;
175 	}
176 
177 	*data = sfc_tbls_field_update(*data, lbn, SFC_TBLS_U32_BITS - lbn, value);
178 	value >>= SFC_TBLS_U32_BITS - lbn;
179 	width -= SFC_TBLS_U32_BITS - lbn;
180 
181 	data_offset++;
182 	SFC_ASSERT(data_offset < data_size);
183 
184 	data++;
185 
186 	if (width > SFC_TBLS_U32_BITS) {
187 		*data = sfc_tbls_field_update(*data, 0, SFC_TBLS_U32_BITS, value);
188 		value >>= SFC_TBLS_U32_BITS;
189 		width -= SFC_TBLS_U32_BITS;
190 
191 		data_offset++;
192 		SFC_ASSERT(data_offset < data_size);
193 
194 		data++;
195 	}
196 
197 	*data = sfc_tbls_field_update(*data, 0, width, value);
198 }
199 
200 void
sfc_tbls_field_set_bit(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,bool value)201 sfc_tbls_field_set_bit(uint32_t data[], unsigned int data_size, uint16_t lbn,
202 		       uint16_t width, bool value)
203 {
204 	SFC_ASSERT(width == 1);
205 
206 	sfc_tbls_field_set_u32(data, data_size, lbn, width, value ? 1 : 0);
207 }
208