1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright (c) 2023 Advanced Micro Devices, Inc. 4 */ 5 6 #include "efx.h" 7 #include "efx_impl.h" 8 9 /* List of HW tables that have support in efx */ 10 static const efx_table_id_t efx_supported_table_ids[] = { 11 EFX_TABLE_ID_CONNTRACK, 12 }; 13 14 __checkReturn efx_rc_t 15 efx_table_list( 16 __in efx_nic_t *enp, 17 __in uint32_t entry_ofst, 18 __out_opt unsigned int *total_n_tablesp, 19 __out_ecount_opt(n_table_ids) efx_table_id_t *table_ids, 20 __in unsigned int n_table_ids, 21 __out_opt unsigned int *n_table_ids_writtenp) 22 { 23 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 24 unsigned int n_entries; 25 efx_mcdi_req_t req; 26 unsigned int i; 27 efx_rc_t rc; 28 EFX_MCDI_DECLARE_BUF(payload, 29 MC_CMD_TABLE_LIST_IN_LEN, 30 MC_CMD_TABLE_LIST_OUT_LENMAX_MCDI2); 31 32 /* Ensure EFX and MCDI use same values for table IDs */ 33 EFX_STATIC_ASSERT(EFX_TABLE_ID_CONNTRACK == TABLE_ID_CONNTRACK_TABLE); 34 35 if (encp->enc_table_api_supported == B_FALSE) { 36 rc = ENOTSUP; 37 goto fail1; 38 } 39 40 if ((n_table_ids != 0) && 41 ((table_ids == NULL) || (n_table_ids_writtenp == NULL))) { 42 rc = EINVAL; 43 goto fail2; 44 } 45 46 req.emr_cmd = MC_CMD_TABLE_LIST; 47 req.emr_in_buf = payload; 48 req.emr_in_length = MC_CMD_TABLE_LIST_IN_LEN; 49 req.emr_out_buf = payload; 50 req.emr_out_length = MC_CMD_TABLE_LIST_OUT_LENMAX_MCDI2; 51 52 MCDI_IN_SET_DWORD(req, TABLE_LIST_IN_FIRST_TABLE_ID_INDEX, entry_ofst); 53 54 efx_mcdi_execute(enp, &req); 55 56 if (req.emr_rc != 0) { 57 rc = req.emr_rc; 58 goto fail3; 59 } 60 61 if (req.emr_out_length_used < MC_CMD_TABLE_LIST_OUT_LENMIN) { 62 rc = EMSGSIZE; 63 goto fail4; 64 } 65 66 if (total_n_tablesp != NULL) 67 *total_n_tablesp = MCDI_OUT_DWORD(req, TABLE_LIST_OUT_N_TABLES); 68 69 n_entries = MC_CMD_TABLE_LIST_OUT_TABLE_ID_NUM(req.emr_out_length_used); 70 71 if (table_ids != NULL) { 72 if (n_entries > n_table_ids) { 73 rc = ENOMEM; 74 goto fail5; 75 } 76 77 for (i = 0; i < n_entries; i++) { 78 table_ids[i] = MCDI_OUT_INDEXED_DWORD(req, 79 TABLE_LIST_OUT_TABLE_ID, i); 80 } 81 } 82 83 if (n_table_ids_writtenp != NULL) 84 *n_table_ids_writtenp = n_entries; 85 86 return (0); 87 88 fail5: 89 EFSYS_PROBE(fail5); 90 fail4: 91 EFSYS_PROBE(fail4); 92 fail3: 93 EFSYS_PROBE(fail3); 94 fail2: 95 EFSYS_PROBE(fail2); 96 fail1: 97 EFSYS_PROBE1(fail1, efx_rc_t, rc); 98 return (rc); 99 } 100 101 __checkReturn size_t 102 efx_table_supported_num_get( 103 __in void) 104 { 105 return (EFX_ARRAY_SIZE(efx_supported_table_ids)); 106 } 107 108 __checkReturn boolean_t 109 efx_table_is_supported( 110 __in efx_table_id_t table_id) 111 { 112 size_t i; 113 114 for (i = 0; i < efx_table_supported_num_get(); i++) { 115 if (efx_supported_table_ids[i] == table_id) 116 return (B_TRUE); 117 } 118 119 return (B_FALSE); 120 } 121 122 static __checkReturn efx_rc_t 123 efx_table_ct_desc_fields_check( 124 __in_ecount(n_fields_descs) efx_table_field_descriptor_t *fields_descsp, 125 __in unsigned int n_fields_descs) 126 { 127 unsigned int i; 128 efx_rc_t rc; 129 130 for (i = 0; i < n_fields_descs; i++) { 131 switch (fields_descsp[i].field_id) { 132 case EFX_TABLE_FIELD_ID_ETHER_TYPE: 133 case EFX_TABLE_FIELD_ID_SRC_IP: 134 case EFX_TABLE_FIELD_ID_DST_IP: 135 case EFX_TABLE_FIELD_ID_IP_PROTO: 136 case EFX_TABLE_FIELD_ID_SRC_PORT: 137 case EFX_TABLE_FIELD_ID_DST_PORT: 138 if (fields_descsp[i].mask_type != EFX_TABLE_FIELD_MASK_EXACT) { 139 rc = EINVAL; 140 goto fail1; 141 } 142 break; 143 /* 144 * TODO: 145 * All fields in the CT table have EXACT mask. 146 * All the response field descriptors must have the EXACT mask. 147 * In the current implementation, only the Ethertype, source and 148 * destination IP address, IP protocol, and source and destination IP 149 * are used for the lookup by the key. 150 * FW could use the NEVER mask for the fields in the key that are not 151 * used for the lookup. 152 * As an alternative, a new mask could be added for these fields, 153 * like EXACT_NOT_USED. 154 */ 155 default: 156 if ((fields_descsp[i].mask_type != EFX_TABLE_FIELD_MASK_NEVER) && 157 (fields_descsp[i].mask_type != EFX_TABLE_FIELD_MASK_EXACT)) { 158 rc = EINVAL; 159 goto fail2; 160 } 161 break; 162 } 163 } 164 165 return (0); 166 167 fail2: 168 EFSYS_PROBE(fail2); 169 fail1: 170 EFSYS_PROBE1(fail1, efx_rc_t, rc); 171 return (rc); 172 } 173 174 static __checkReturn efx_rc_t 175 efx_table_desc_fields_check( 176 __in efx_table_id_t table_id, 177 __in_ecount(n_fields_descs) efx_table_field_descriptor_t *fields_descsp, 178 __in unsigned int n_fields_descs) 179 { 180 efx_rc_t rc; 181 182 switch (table_id) { 183 case EFX_TABLE_ID_CONNTRACK: 184 rc = efx_table_ct_desc_fields_check(fields_descsp, n_fields_descs); 185 if (rc != 0) 186 goto fail1; 187 break; 188 default: 189 break; 190 } 191 192 return (0); 193 194 fail1: 195 EFSYS_PROBE1(fail1, efx_rc_t, rc); 196 return (rc); 197 } 198 199 static void 200 efx_table_desc_fields_get( 201 __in const efx_mcdi_req_t *req, 202 __out_ecount(n_fields_descs) efx_table_field_descriptor_t *fields_descsp, 203 __in unsigned int n_fields_descs) 204 { 205 unsigned int i; 206 207 for (i = 0; i < n_fields_descs; i++) { 208 fields_descsp[i].field_id = (efx_table_field_id_t) 209 MCDI_OUT_INDEXED_QWORD_FIELD(*req, 210 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_FIELD_ID); 211 212 fields_descsp[i].lbn = 213 MCDI_OUT_INDEXED_QWORD_FIELD(*req, 214 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_LBN); 215 216 fields_descsp[i].width = 217 MCDI_OUT_INDEXED_QWORD_FIELD(*req, 218 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_WIDTH); 219 220 fields_descsp[i].mask_type = (efx_table_field_mask_type_t) 221 MCDI_OUT_INDEXED_QWORD_FIELD(*req, 222 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_MASK_TYPE); 223 224 fields_descsp[i].scheme = 225 MCDI_OUT_INDEXED_QWORD_FIELD(*req, 226 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_SCHEME); 227 } 228 } 229 230 __checkReturn efx_rc_t 231 efx_table_describe( 232 __in efx_nic_t *enp, 233 __in efx_table_id_t table_id, 234 __in uint32_t field_offset, 235 __out_opt efx_table_descriptor_t *table_descp, 236 __out_ecount_opt(n_field_descs) efx_table_field_descriptor_t *fields_descs, 237 __in unsigned int n_field_descs, 238 __out_opt unsigned int *n_field_descs_writtenp) 239 { 240 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 241 unsigned int n_entries; 242 efx_mcdi_req_t req; 243 unsigned int i; 244 efx_rc_t rc; 245 EFX_MCDI_DECLARE_BUF(payload, 246 MC_CMD_TABLE_DESCRIPTOR_IN_LEN, 247 MC_CMD_TABLE_DESCRIPTOR_OUT_LENMAX_MCDI2); 248 249 /* Ensure EFX and MCDI use same values for table types */ 250 EFX_STATIC_ASSERT(EFX_TABLE_TYPE_BCAM == MC_CMD_TABLE_DESCRIPTOR_OUT_TYPE_BCAM); 251 252 /* Ensure EFX and MCDI use same values for table fields */ 253 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_UNUSED == TABLE_FIELD_ID_UNUSED); 254 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_COUNTER_ID == TABLE_FIELD_ID_COUNTER_ID); 255 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_ETHER_TYPE == TABLE_FIELD_ID_ETHER_TYPE); 256 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_SRC_IP == TABLE_FIELD_ID_SRC_IP); 257 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_DST_IP == TABLE_FIELD_ID_DST_IP); 258 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_IP_PROTO == TABLE_FIELD_ID_IP_PROTO); 259 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_SRC_PORT == TABLE_FIELD_ID_SRC_PORT); 260 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_DST_PORT == TABLE_FIELD_ID_DST_PORT); 261 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_NAT_PORT == TABLE_FIELD_ID_NAT_PORT); 262 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_NAT_IP == TABLE_FIELD_ID_NAT_IP); 263 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_NAT_DIR == TABLE_FIELD_ID_NAT_DIR); 264 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_CT_MARK == TABLE_FIELD_ID_CT_MARK); 265 266 if (encp->enc_table_api_supported == B_FALSE) { 267 rc = ENOTSUP; 268 goto fail1; 269 } 270 271 if (!efx_table_is_supported(table_id)) { 272 rc = ENOTSUP; 273 goto fail2; 274 } 275 276 if ((n_field_descs != 0) && 277 ((fields_descs == NULL) || (n_field_descs_writtenp == NULL))) { 278 rc = EINVAL; 279 goto fail3; 280 } 281 282 req.emr_cmd = MC_CMD_TABLE_DESCRIPTOR; 283 req.emr_in_buf = payload; 284 req.emr_in_length = MC_CMD_TABLE_DESCRIPTOR_IN_LEN; 285 req.emr_out_buf = payload; 286 req.emr_out_length = MC_CMD_TABLE_DESCRIPTOR_OUT_LENMAX_MCDI2; 287 288 MCDI_IN_SET_DWORD(req, TABLE_DESCRIPTOR_IN_TABLE_ID, (uint32_t)table_id); 289 MCDI_IN_SET_DWORD(req, TABLE_DESCRIPTOR_IN_FIRST_FIELDS_INDEX, field_offset); 290 291 efx_mcdi_execute(enp, &req); 292 293 if (req.emr_rc != 0) { 294 rc = req.emr_rc; 295 goto fail4; 296 } 297 298 if (req.emr_out_length_used < MC_CMD_TABLE_DESCRIPTOR_OUT_LENMIN) { 299 rc = EMSGSIZE; 300 goto fail5; 301 } 302 303 if (table_descp != NULL) { 304 table_descp->type = (efx_table_type_t)MCDI_OUT_WORD( 305 req, TABLE_DESCRIPTOR_OUT_TYPE); 306 table_descp->key_width = MCDI_OUT_WORD( 307 req, TABLE_DESCRIPTOR_OUT_KEY_WIDTH); 308 table_descp->resp_width = MCDI_OUT_WORD( 309 req, TABLE_DESCRIPTOR_OUT_RESP_WIDTH); 310 table_descp->n_key_fields = MCDI_OUT_WORD( 311 req, TABLE_DESCRIPTOR_OUT_N_KEY_FIELDS); 312 table_descp->n_resp_fields = MCDI_OUT_WORD( 313 req, TABLE_DESCRIPTOR_OUT_N_RESP_FIELDS); 314 } 315 316 n_entries = MC_CMD_TABLE_DESCRIPTOR_OUT_FIELDS_NUM(req.emr_out_length_used); 317 318 if (fields_descs != NULL) { 319 if (n_entries > n_field_descs) { 320 rc = ENOMEM; 321 goto fail6; 322 } 323 324 efx_table_desc_fields_get(&req, fields_descs, n_entries); 325 rc = efx_table_desc_fields_check(table_id, fields_descs, n_entries); 326 if (rc != 0) 327 goto fail7; 328 } 329 330 if (n_field_descs_writtenp != NULL) 331 *n_field_descs_writtenp = n_entries; 332 333 return (0); 334 335 fail7: 336 EFSYS_PROBE(fail7); 337 fail6: 338 EFSYS_PROBE(fail6); 339 fail5: 340 EFSYS_PROBE(fail5); 341 fail4: 342 EFSYS_PROBE(fail4); 343 fail3: 344 EFSYS_PROBE(fail3); 345 fail2: 346 EFSYS_PROBE(fail2); 347 fail1: 348 EFSYS_PROBE1(fail1, efx_rc_t, rc); 349 return (rc); 350 } 351 352 __checkReturn efx_rc_t 353 efx_table_entry_insert( 354 __in efx_nic_t *enp, 355 __in efx_table_id_t table_id, 356 __in uint16_t priority, 357 __in uint16_t mask_id, 358 __in uint16_t key_width, 359 __in uint16_t mask_width, 360 __in uint16_t resp_width, 361 __in_bcount(data_size) uint8_t *entry_datap, 362 __in unsigned int data_size) 363 { 364 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 365 unsigned int n_dwords; 366 efx_mcdi_req_t req; 367 efx_rc_t rc; 368 EFX_MCDI_DECLARE_BUF(payload, 369 MC_CMD_TABLE_INSERT_IN_LENMAX_MCDI2, 370 MC_CMD_TABLE_INSERT_OUT_LEN); 371 372 /* 373 * Ensure MCDI number of 32bit units matches EFX maximum possible 374 * data in bytes. 375 */ 376 EFX_STATIC_ASSERT((MC_CMD_TABLE_INSERT_IN_LENMAX * sizeof(uint32_t)) == 377 EFX_TABLE_ENTRY_LENGTH_MAX); 378 379 if (encp->enc_table_api_supported == B_FALSE) { 380 rc = ENOTSUP; 381 goto fail1; 382 } 383 384 if ((data_size % sizeof(uint32_t)) != 0) { 385 rc = EINVAL; 386 goto fail2; 387 } 388 389 if ((data_size == 0) || (data_size > EFX_TABLE_ENTRY_LENGTH_MAX)) { 390 rc = EINVAL; 391 goto fail3; 392 } 393 394 n_dwords = data_size / sizeof(uint32_t); 395 396 req.emr_cmd = MC_CMD_TABLE_INSERT; 397 req.emr_in_buf = payload; 398 req.emr_in_length = MC_CMD_TABLE_INSERT_IN_LEN(n_dwords); 399 req.emr_out_buf = payload; 400 req.emr_out_length = MC_CMD_TABLE_INSERT_OUT_LEN; 401 402 MCDI_IN_SET_DWORD(req, TABLE_INSERT_IN_TABLE_ID, (uint32_t)table_id); 403 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_PRIORITY, priority); 404 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_MASK_ID, mask_id); 405 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_KEY_WIDTH, key_width); 406 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_MASK_WIDTH, mask_width); 407 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_RESP_WIDTH, resp_width); 408 409 memcpy(MCDI_IN2(req, uint8_t, TABLE_INSERT_IN_DATA), entry_datap, data_size); 410 411 efx_mcdi_execute(enp, &req); 412 413 if (req.emr_rc != 0) { 414 rc = req.emr_rc; 415 goto fail4; 416 } 417 418 return (0); 419 420 fail4: 421 EFSYS_PROBE(fail4); 422 fail3: 423 EFSYS_PROBE(fail3); 424 fail2: 425 EFSYS_PROBE(fail2); 426 fail1: 427 EFSYS_PROBE1(fail1, efx_rc_t, rc); 428 return (rc); 429 } 430 431 __checkReturn efx_rc_t 432 efx_table_entry_delete( 433 __in efx_nic_t *enp, 434 __in efx_table_id_t table_id, 435 __in uint16_t mask_id, 436 __in uint16_t key_width, 437 __in uint16_t mask_width, 438 __in_bcount(data_size) uint8_t *entry_datap, 439 __in unsigned int data_size) 440 { 441 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 442 unsigned int n_dwords; 443 efx_mcdi_req_t req; 444 efx_rc_t rc; 445 EFX_MCDI_DECLARE_BUF(payload, 446 MC_CMD_TABLE_DELETE_IN_LENMAX_MCDI2, 447 MC_CMD_TABLE_DELETE_OUT_LEN); 448 449 /* 450 * Ensure MCDI number of 32bit units matches EFX maximum possible 451 * data in bytes. 452 */ 453 EFX_STATIC_ASSERT((MC_CMD_TABLE_DELETE_IN_LENMAX * sizeof(uint32_t)) == 454 EFX_TABLE_ENTRY_LENGTH_MAX); 455 456 if (encp->enc_table_api_supported == B_FALSE) { 457 rc = ENOTSUP; 458 goto fail1; 459 } 460 461 if ((data_size % sizeof(uint32_t)) != 0) { 462 rc = EINVAL; 463 goto fail2; 464 } 465 466 if ((data_size == 0) || (data_size > EFX_TABLE_ENTRY_LENGTH_MAX)) { 467 rc = EINVAL; 468 goto fail3; 469 } 470 471 n_dwords = data_size / sizeof(uint32_t); 472 473 req.emr_cmd = MC_CMD_TABLE_DELETE; 474 req.emr_in_buf = payload; 475 req.emr_in_length = MC_CMD_TABLE_DELETE_IN_LEN(n_dwords); 476 req.emr_out_buf = payload; 477 req.emr_out_length = MC_CMD_TABLE_DELETE_OUT_LEN; 478 479 MCDI_IN_SET_DWORD(req, TABLE_DELETE_IN_TABLE_ID, (uint32_t)table_id); 480 MCDI_IN_SET_WORD(req, TABLE_DELETE_IN_MASK_ID, mask_id); 481 MCDI_IN_SET_WORD(req, TABLE_DELETE_IN_KEY_WIDTH, key_width); 482 MCDI_IN_SET_WORD(req, TABLE_DELETE_IN_MASK_WIDTH, mask_width); 483 484 485 memcpy(MCDI_IN2(req, uint8_t, TABLE_DELETE_IN_DATA), entry_datap, data_size); 486 487 efx_mcdi_execute(enp, &req); 488 489 if (req.emr_rc != 0) { 490 rc = req.emr_rc; 491 goto fail4; 492 } 493 494 return (0); 495 496 fail4: 497 EFSYS_PROBE(fail4); 498 499 fail3: 500 EFSYS_PROBE(fail3); 501 fail2: 502 EFSYS_PROBE(fail2); 503 fail1: 504 EFSYS_PROBE1(fail1, efx_rc_t, rc); 505 return (rc); 506 } 507