@@ -112,6 +112,167 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
112112 return 0 ;
113113}
114114
115+ static int efx_mae_get_basic_caps (struct efx_nic * efx , struct mae_caps * caps )
116+ {
117+ MCDI_DECLARE_BUF (outbuf , MC_CMD_MAE_GET_CAPS_OUT_LEN );
118+ size_t outlen ;
119+ int rc ;
120+
121+ BUILD_BUG_ON (MC_CMD_MAE_GET_CAPS_IN_LEN );
122+
123+ rc = efx_mcdi_rpc (efx , MC_CMD_MAE_GET_CAPS , NULL , 0 , outbuf ,
124+ sizeof (outbuf ), & outlen );
125+ if (rc )
126+ return rc ;
127+ if (outlen < sizeof (outbuf ))
128+ return - EIO ;
129+ caps -> match_field_count = MCDI_DWORD (outbuf , MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT );
130+ caps -> action_prios = MCDI_DWORD (outbuf , MAE_GET_CAPS_OUT_ACTION_PRIOS );
131+ return 0 ;
132+ }
133+
134+ static int efx_mae_get_rule_fields (struct efx_nic * efx , u32 cmd ,
135+ u8 * field_support )
136+ {
137+ MCDI_DECLARE_BUF (outbuf , MC_CMD_MAE_GET_AR_CAPS_OUT_LEN (MAE_NUM_FIELDS ));
138+ MCDI_DECLARE_STRUCT_PTR (caps );
139+ unsigned int count ;
140+ size_t outlen ;
141+ int rc , i ;
142+
143+ BUILD_BUG_ON (MC_CMD_MAE_GET_AR_CAPS_IN_LEN );
144+
145+ rc = efx_mcdi_rpc (efx , cmd , NULL , 0 , outbuf , sizeof (outbuf ), & outlen );
146+ if (rc )
147+ return rc ;
148+ count = MCDI_DWORD (outbuf , MAE_GET_AR_CAPS_OUT_COUNT );
149+ memset (field_support , MAE_FIELD_UNSUPPORTED , MAE_NUM_FIELDS );
150+ caps = _MCDI_DWORD (outbuf , MAE_GET_AR_CAPS_OUT_FIELD_FLAGS );
151+ /* We're only interested in the support status enum, not any other
152+ * flags, so just extract that from each entry.
153+ */
154+ for (i = 0 ; i < count ; i ++ )
155+ if (i * sizeof (* outbuf ) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen )
156+ field_support [i ] = EFX_DWORD_FIELD (caps [i ], MAE_FIELD_FLAGS_SUPPORT_STATUS );
157+ return 0 ;
158+ }
159+
160+ int efx_mae_get_caps (struct efx_nic * efx , struct mae_caps * caps )
161+ {
162+ int rc ;
163+
164+ rc = efx_mae_get_basic_caps (efx , caps );
165+ if (rc )
166+ return rc ;
167+ return efx_mae_get_rule_fields (efx , MC_CMD_MAE_GET_AR_CAPS ,
168+ caps -> action_rule_fields );
169+ }
170+
171+ /* Bit twiddling:
172+ * Prefix: 1...110...0
173+ * ~: 0...001...1
174+ * + 1: 0...010...0 is power of two
175+ * so (~x) & ((~x) + 1) == 0. Converse holds also.
176+ */
177+ #define is_prefix_byte (_x ) !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1))
178+
179+ enum mask_type { MASK_ONES , MASK_ZEROES , MASK_PREFIX , MASK_OTHER };
180+
181+ static const char * mask_type_name (enum mask_type typ )
182+ {
183+ switch (typ ) {
184+ case MASK_ONES :
185+ return "all-1s" ;
186+ case MASK_ZEROES :
187+ return "all-0s" ;
188+ case MASK_PREFIX :
189+ return "prefix" ;
190+ case MASK_OTHER :
191+ return "arbitrary" ;
192+ default : /* can't happen */
193+ return "unknown" ;
194+ }
195+ }
196+
197+ /* Checks a (big-endian) bytestring is a bit prefix */
198+ static enum mask_type classify_mask (const u8 * mask , size_t len )
199+ {
200+ bool zeroes = true; /* All bits seen so far are zeroes */
201+ bool ones = true; /* All bits seen so far are ones */
202+ bool prefix = true; /* Valid prefix so far */
203+ size_t i ;
204+
205+ for (i = 0 ; i < len ; i ++ ) {
206+ if (ones ) {
207+ if (!is_prefix_byte (mask [i ]))
208+ prefix = false;
209+ } else if (mask [i ]) {
210+ prefix = false;
211+ }
212+ if (mask [i ] != 0xff )
213+ ones = false;
214+ if (mask [i ])
215+ zeroes = false;
216+ }
217+ if (ones )
218+ return MASK_ONES ;
219+ if (zeroes )
220+ return MASK_ZEROES ;
221+ if (prefix )
222+ return MASK_PREFIX ;
223+ return MASK_OTHER ;
224+ }
225+
226+ static int efx_mae_match_check_cap_typ (u8 support , enum mask_type typ )
227+ {
228+ switch (support ) {
229+ case MAE_FIELD_UNSUPPORTED :
230+ case MAE_FIELD_SUPPORTED_MATCH_NEVER :
231+ if (typ == MASK_ZEROES )
232+ return 0 ;
233+ return - EOPNOTSUPP ;
234+ case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL :
235+ if (typ == MASK_ZEROES )
236+ return 0 ;
237+ fallthrough ;
238+ case MAE_FIELD_SUPPORTED_MATCH_ALWAYS :
239+ if (typ == MASK_ONES )
240+ return 0 ;
241+ return - EINVAL ;
242+ case MAE_FIELD_SUPPORTED_MATCH_PREFIX :
243+ if (typ == MASK_OTHER )
244+ return - EOPNOTSUPP ;
245+ return 0 ;
246+ case MAE_FIELD_SUPPORTED_MATCH_MASK :
247+ return 0 ;
248+ default :
249+ return - EIO ;
250+ }
251+ }
252+
253+ int efx_mae_match_check_caps (struct efx_nic * efx ,
254+ const struct efx_tc_match_fields * mask ,
255+ struct netlink_ext_ack * extack )
256+ {
257+ const u8 * supported_fields = efx -> tc -> caps -> action_rule_fields ;
258+ __be32 ingress_port = cpu_to_be32 (mask -> ingress_port );
259+ enum mask_type ingress_port_mask_type ;
260+ int rc ;
261+
262+ /* Check for _PREFIX assumes big-endian, so we need to convert */
263+ ingress_port_mask_type = classify_mask ((const u8 * )& ingress_port ,
264+ sizeof (ingress_port ));
265+ rc = efx_mae_match_check_cap_typ (supported_fields [MAE_FIELD_INGRESS_PORT ],
266+ ingress_port_mask_type );
267+ if (rc ) {
268+ efx_tc_err (efx , "No support for %s mask in field ingress_port\n" ,
269+ mask_type_name (ingress_port_mask_type ));
270+ NL_SET_ERR_MSG_MOD (extack , "Unsupported mask type for ingress_port" );
271+ return rc ;
272+ }
273+ return 0 ;
274+ }
275+
115276static bool efx_mae_asl_id (u32 id )
116277{
117278 return !!(id & BIT (31 ));
@@ -279,6 +440,10 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
279440 }
280441 MCDI_STRUCT_SET_DWORD (match_crit , MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK ,
281442 match -> mask .ingress_port );
443+ MCDI_STRUCT_SET_BYTE (match_crit , MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID ,
444+ match -> value .recirc_id );
445+ MCDI_STRUCT_SET_BYTE (match_crit , MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK ,
446+ match -> mask .recirc_id );
282447 return 0 ;
283448}
284449
0 commit comments