1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2018-2021 NXP 3 */ 4 5 #include <sys/queue.h> 6 #include <stdio.h> 7 #include <errno.h> 8 #include <stdint.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <stdarg.h> 12 13 #include <rte_ethdev.h> 14 #include <rte_log.h> 15 #include <rte_malloc.h> 16 #include <rte_flow_driver.h> 17 #include <rte_tailq.h> 18 19 #include <bus_fslmc_driver.h> 20 #include <fsl_dpdmux.h> 21 #include <fsl_dpkg.h> 22 23 #include <dpaa2_ethdev.h> 24 #include <dpaa2_pmd_logs.h> 25 26 struct dpaa2_dpdmux_dev { 27 TAILQ_ENTRY(dpaa2_dpdmux_dev) next; 28 /**< Pointer to Next device instance */ 29 struct fsl_mc_io dpdmux; /** handle to DPDMUX portal object */ 30 uint16_t token; 31 uint32_t dpdmux_id; /*HW ID for DPDMUX object */ 32 uint8_t num_ifs; /* Number of interfaces in DPDMUX */ 33 }; 34 35 struct rte_flow { 36 struct dpdmux_rule_cfg rule; 37 }; 38 39 TAILQ_HEAD(dpdmux_dev_list, dpaa2_dpdmux_dev); 40 static struct dpdmux_dev_list dpdmux_dev_list = 41 TAILQ_HEAD_INITIALIZER(dpdmux_dev_list); /*!< DPDMUX device list */ 42 43 static struct dpaa2_dpdmux_dev *get_dpdmux_from_id(uint32_t dpdmux_id) 44 { 45 struct dpaa2_dpdmux_dev *dpdmux_dev = NULL; 46 47 /* Get DPDMUX dev handle from list using index */ 48 TAILQ_FOREACH(dpdmux_dev, &dpdmux_dev_list, next) { 49 if (dpdmux_dev->dpdmux_id == dpdmux_id) 50 break; 51 } 52 53 return dpdmux_dev; 54 } 55 56 struct rte_flow * 57 rte_pmd_dpaa2_mux_flow_create(uint32_t dpdmux_id, 58 struct rte_flow_item *pattern[], 59 struct rte_flow_action *actions[]) 60 { 61 struct dpaa2_dpdmux_dev *dpdmux_dev; 62 struct dpkg_profile_cfg kg_cfg; 63 const struct rte_flow_action_vf *vf_conf; 64 struct dpdmux_cls_action dpdmux_action; 65 struct rte_flow *flow = NULL; 66 void *key_iova, *mask_iova, *key_cfg_iova = NULL; 67 uint8_t key_size = 0; 68 int ret; 69 static int i; 70 71 if (!pattern || !actions || !pattern[0] || !actions[0]) 72 return NULL; 73 74 /* Find the DPDMUX from dpdmux_id in our list */ 75 dpdmux_dev = get_dpdmux_from_id(dpdmux_id); 76 if (!dpdmux_dev) { 77 DPAA2_PMD_ERR("Invalid dpdmux_id: %d", dpdmux_id); 78 return NULL; 79 } 80 81 key_cfg_iova = rte_zmalloc(NULL, DIST_PARAM_IOVA_SIZE, 82 RTE_CACHE_LINE_SIZE); 83 if (!key_cfg_iova) { 84 DPAA2_PMD_ERR("Unable to allocate flow-dist parameters"); 85 return NULL; 86 } 87 flow = rte_zmalloc(NULL, sizeof(struct rte_flow) + 88 (2 * DIST_PARAM_IOVA_SIZE), RTE_CACHE_LINE_SIZE); 89 if (!flow) { 90 DPAA2_PMD_ERR( 91 "Memory allocation failure for rule configuration"); 92 goto creation_error; 93 } 94 key_iova = (void *)((size_t)flow + sizeof(struct rte_flow)); 95 mask_iova = (void *)((size_t)key_iova + DIST_PARAM_IOVA_SIZE); 96 97 /* Currently taking only IP protocol as an extract type. 98 * This can be extended to other fields using pattern->type. 99 */ 100 memset(&kg_cfg, 0, sizeof(struct dpkg_profile_cfg)); 101 102 switch (pattern[0]->type) { 103 case RTE_FLOW_ITEM_TYPE_IPV4: 104 { 105 const struct rte_flow_item_ipv4 *spec; 106 107 kg_cfg.extracts[0].extract.from_hdr.prot = NET_PROT_IP; 108 kg_cfg.extracts[0].extract.from_hdr.field = NH_FLD_IP_PROTO; 109 kg_cfg.extracts[0].type = DPKG_EXTRACT_FROM_HDR; 110 kg_cfg.extracts[0].extract.from_hdr.type = DPKG_FULL_FIELD; 111 kg_cfg.num_extracts = 1; 112 113 spec = (const struct rte_flow_item_ipv4 *)pattern[0]->spec; 114 memcpy(key_iova, (const void *)(&spec->hdr.next_proto_id), 115 sizeof(uint8_t)); 116 memcpy(mask_iova, pattern[0]->mask, sizeof(uint8_t)); 117 key_size = sizeof(uint8_t); 118 } 119 break; 120 121 case RTE_FLOW_ITEM_TYPE_UDP: 122 { 123 const struct rte_flow_item_udp *spec; 124 uint16_t udp_dst_port; 125 126 kg_cfg.extracts[0].extract.from_hdr.prot = NET_PROT_UDP; 127 kg_cfg.extracts[0].extract.from_hdr.field = NH_FLD_UDP_PORT_DST; 128 kg_cfg.extracts[0].type = DPKG_EXTRACT_FROM_HDR; 129 kg_cfg.extracts[0].extract.from_hdr.type = DPKG_FULL_FIELD; 130 kg_cfg.num_extracts = 1; 131 132 spec = (const struct rte_flow_item_udp *)pattern[0]->spec; 133 udp_dst_port = rte_constant_bswap16(spec->hdr.dst_port); 134 memcpy((void *)key_iova, (const void *)&udp_dst_port, 135 sizeof(rte_be16_t)); 136 memcpy(mask_iova, pattern[0]->mask, sizeof(uint16_t)); 137 key_size = sizeof(uint16_t); 138 } 139 break; 140 141 case RTE_FLOW_ITEM_TYPE_ETH: 142 { 143 const struct rte_flow_item_eth *spec; 144 uint16_t eth_type; 145 146 kg_cfg.extracts[0].extract.from_hdr.prot = NET_PROT_ETH; 147 kg_cfg.extracts[0].extract.from_hdr.field = NH_FLD_ETH_TYPE; 148 kg_cfg.extracts[0].type = DPKG_EXTRACT_FROM_HDR; 149 kg_cfg.extracts[0].extract.from_hdr.type = DPKG_FULL_FIELD; 150 kg_cfg.num_extracts = 1; 151 152 spec = (const struct rte_flow_item_eth *)pattern[0]->spec; 153 eth_type = rte_constant_bswap16(spec->hdr.ether_type); 154 memcpy((void *)key_iova, (const void *)ð_type, 155 sizeof(rte_be16_t)); 156 memcpy(mask_iova, pattern[0]->mask, sizeof(uint16_t)); 157 key_size = sizeof(uint16_t); 158 } 159 break; 160 161 case RTE_FLOW_ITEM_TYPE_RAW: 162 { 163 const struct rte_flow_item_raw *spec; 164 165 spec = (const struct rte_flow_item_raw *)pattern[0]->spec; 166 kg_cfg.extracts[0].extract.from_data.offset = spec->offset; 167 kg_cfg.extracts[0].extract.from_data.size = spec->length; 168 kg_cfg.extracts[0].type = DPKG_EXTRACT_FROM_DATA; 169 kg_cfg.num_extracts = 1; 170 memcpy((void *)key_iova, (const void *)spec->pattern, 171 spec->length); 172 memcpy(mask_iova, pattern[0]->mask, spec->length); 173 174 key_size = spec->length; 175 } 176 break; 177 178 default: 179 DPAA2_PMD_ERR("Not supported pattern type: %d", 180 pattern[0]->type); 181 goto creation_error; 182 } 183 184 ret = dpkg_prepare_key_cfg(&kg_cfg, key_cfg_iova); 185 if (ret) { 186 DPAA2_PMD_ERR("dpkg_prepare_key_cfg failed: err(%d)", ret); 187 goto creation_error; 188 } 189 190 /* Multiple rules with same DPKG extracts (kg_cfg.extracts) like same 191 * offset and length values in raw is supported right now. Different 192 * values of kg_cfg may not work. 193 */ 194 if (i == 0) { 195 ret = dpdmux_set_custom_key(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 196 dpdmux_dev->token, 197 (uint64_t)(DPAA2_VADDR_TO_IOVA(key_cfg_iova))); 198 if (ret) { 199 DPAA2_PMD_ERR("dpdmux_set_custom_key failed: err(%d)", 200 ret); 201 goto creation_error; 202 } 203 } 204 /* As now our key extract parameters are set, let us configure 205 * the rule. 206 */ 207 flow->rule.key_iova = (uint64_t)(DPAA2_VADDR_TO_IOVA(key_iova)); 208 flow->rule.mask_iova = (uint64_t)(DPAA2_VADDR_TO_IOVA(mask_iova)); 209 flow->rule.key_size = key_size; 210 flow->rule.entry_index = i++; 211 212 vf_conf = (const struct rte_flow_action_vf *)(actions[0]->conf); 213 if (vf_conf->id == 0 || vf_conf->id > dpdmux_dev->num_ifs) { 214 DPAA2_PMD_ERR("Invalid destination id"); 215 goto creation_error; 216 } 217 dpdmux_action.dest_if = vf_conf->id; 218 219 ret = dpdmux_add_custom_cls_entry(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 220 dpdmux_dev->token, &flow->rule, 221 &dpdmux_action); 222 if (ret) { 223 DPAA2_PMD_ERR("dpdmux_add_custom_cls_entry failed: err(%d)", 224 ret); 225 goto creation_error; 226 } 227 228 return flow; 229 230 creation_error: 231 rte_free((void *)key_cfg_iova); 232 rte_free((void *)flow); 233 return NULL; 234 } 235 236 int 237 rte_pmd_dpaa2_mux_flow_l2(uint32_t dpdmux_id, 238 uint8_t mac_addr[6], uint16_t vlan_id, int dest_if) 239 { 240 struct dpaa2_dpdmux_dev *dpdmux_dev; 241 struct dpdmux_l2_rule rule; 242 int ret, i; 243 244 /* Find the DPDMUX from dpdmux_id in our list */ 245 dpdmux_dev = get_dpdmux_from_id(dpdmux_id); 246 if (!dpdmux_dev) { 247 DPAA2_PMD_ERR("Invalid dpdmux_id: %d", dpdmux_id); 248 return -ENODEV; 249 } 250 251 for (i = 0; i < 6; i++) 252 rule.mac_addr[i] = mac_addr[i]; 253 rule.vlan_id = vlan_id; 254 255 ret = dpdmux_if_add_l2_rule(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 256 dpdmux_dev->token, dest_if, &rule); 257 if (ret) { 258 DPAA2_PMD_ERR("dpdmux_if_add_l2_rule failed:err(%d)", ret); 259 return ret; 260 } 261 262 return 0; 263 } 264 265 int 266 rte_pmd_dpaa2_mux_rx_frame_len(uint32_t dpdmux_id, uint16_t max_rx_frame_len) 267 { 268 struct dpaa2_dpdmux_dev *dpdmux_dev; 269 int ret; 270 271 /* Find the DPDMUX from dpdmux_id in our list */ 272 dpdmux_dev = get_dpdmux_from_id(dpdmux_id); 273 if (!dpdmux_dev) { 274 DPAA2_PMD_ERR("Invalid dpdmux_id: %d", dpdmux_id); 275 return -1; 276 } 277 278 ret = dpdmux_set_max_frame_length(&dpdmux_dev->dpdmux, 279 CMD_PRI_LOW, dpdmux_dev->token, max_rx_frame_len); 280 if (ret) { 281 DPAA2_PMD_ERR("DPDMUX:Unable to set mtu. check config %d", ret); 282 return ret; 283 } 284 285 DPAA2_PMD_INFO("dpdmux mtu set as %u", 286 DPAA2_MAX_RX_PKT_LEN - RTE_ETHER_CRC_LEN); 287 288 return ret; 289 } 290 291 /* dump the status of the dpaa2_mux counters on the console */ 292 void 293 rte_pmd_dpaa2_mux_dump_counter(FILE *f, uint32_t dpdmux_id, int num_if) 294 { 295 struct dpaa2_dpdmux_dev *dpdmux; 296 uint64_t counter; 297 int ret; 298 int if_id; 299 300 /* Find the DPDMUX from dpdmux_id in our list */ 301 dpdmux = get_dpdmux_from_id(dpdmux_id); 302 if (!dpdmux) { 303 DPAA2_PMD_ERR("Invalid dpdmux_id: %d", dpdmux_id); 304 return; 305 } 306 307 for (if_id = 0; if_id < num_if; if_id++) { 308 fprintf(f, "dpdmux.%d\n", if_id); 309 310 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 311 dpdmux->token, if_id, DPDMUX_CNT_ING_FRAME, &counter); 312 if (!ret) 313 fprintf(f, "DPDMUX_CNT_ING_FRAME %" PRIu64 "\n", 314 counter); 315 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 316 dpdmux->token, if_id, DPDMUX_CNT_ING_BYTE, &counter); 317 if (!ret) 318 fprintf(f, "DPDMUX_CNT_ING_BYTE %" PRIu64 "\n", 319 counter); 320 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 321 dpdmux->token, if_id, DPDMUX_CNT_ING_FLTR_FRAME, 322 &counter); 323 if (!ret) 324 fprintf(f, "DPDMUX_CNT_ING_FLTR_FRAME %" PRIu64 "\n", 325 counter); 326 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 327 dpdmux->token, if_id, DPDMUX_CNT_ING_FRAME_DISCARD, 328 &counter); 329 if (!ret) 330 fprintf(f, "DPDMUX_CNT_ING_FRAME_DISCARD %" PRIu64 "\n", 331 counter); 332 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 333 dpdmux->token, if_id, DPDMUX_CNT_ING_MCAST_FRAME, 334 &counter); 335 if (!ret) 336 fprintf(f, "DPDMUX_CNT_ING_MCAST_FRAME %" PRIu64 "\n", 337 counter); 338 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 339 dpdmux->token, if_id, DPDMUX_CNT_ING_MCAST_BYTE, 340 &counter); 341 if (!ret) 342 fprintf(f, "DPDMUX_CNT_ING_MCAST_BYTE %" PRIu64 "\n", 343 counter); 344 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 345 dpdmux->token, if_id, DPDMUX_CNT_ING_BCAST_FRAME, 346 &counter); 347 if (!ret) 348 fprintf(f, "DPDMUX_CNT_ING_BCAST_FRAME %" PRIu64 "\n", 349 counter); 350 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 351 dpdmux->token, if_id, DPDMUX_CNT_ING_BCAST_BYTES, 352 &counter); 353 if (!ret) 354 fprintf(f, "DPDMUX_CNT_ING_BCAST_BYTES %" PRIu64 "\n", 355 counter); 356 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 357 dpdmux->token, if_id, DPDMUX_CNT_EGR_FRAME, &counter); 358 if (!ret) 359 fprintf(f, "DPDMUX_CNT_EGR_FRAME %" PRIu64 "\n", 360 counter); 361 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 362 dpdmux->token, if_id, DPDMUX_CNT_EGR_BYTE, &counter); 363 if (!ret) 364 fprintf(f, "DPDMUX_CNT_EGR_BYTE %" PRIu64 "\n", 365 counter); 366 ret = dpdmux_if_get_counter(&dpdmux->dpdmux, CMD_PRI_LOW, 367 dpdmux->token, if_id, DPDMUX_CNT_EGR_FRAME_DISCARD, 368 &counter); 369 if (!ret) 370 fprintf(f, "DPDMUX_CNT_EGR_FRAME_DISCARD %" PRIu64 "\n", 371 counter); 372 } 373 } 374 375 static int 376 dpaa2_create_dpdmux_device(int vdev_fd __rte_unused, 377 struct vfio_device_info *obj_info __rte_unused, 378 struct rte_dpaa2_device *obj) 379 { 380 struct dpaa2_dpdmux_dev *dpdmux_dev; 381 struct dpdmux_attr attr; 382 int ret, dpdmux_id = obj->object_id; 383 uint16_t maj_ver; 384 uint16_t min_ver; 385 uint8_t skip_reset_flags; 386 387 PMD_INIT_FUNC_TRACE(); 388 389 /* Allocate DPAA2 dpdmux handle */ 390 dpdmux_dev = rte_malloc(NULL, sizeof(struct dpaa2_dpdmux_dev), 0); 391 if (!dpdmux_dev) { 392 DPAA2_PMD_ERR("Memory allocation failed for DPDMUX Device"); 393 return -1; 394 } 395 396 /* Open the dpdmux object */ 397 dpdmux_dev->dpdmux.regs = dpaa2_get_mcp_ptr(MC_PORTAL_INDEX); 398 ret = dpdmux_open(&dpdmux_dev->dpdmux, CMD_PRI_LOW, dpdmux_id, 399 &dpdmux_dev->token); 400 if (ret) { 401 DPAA2_PMD_ERR("Unable to open dpdmux object: err(%d)", ret); 402 goto init_err; 403 } 404 405 ret = dpdmux_get_attributes(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 406 dpdmux_dev->token, &attr); 407 if (ret) { 408 DPAA2_PMD_ERR("Unable to get dpdmux attr: err(%d)", ret); 409 goto init_err; 410 } 411 412 if (attr.method != DPDMUX_METHOD_C_VLAN_MAC) { 413 ret = dpdmux_if_set_default(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 414 dpdmux_dev->token, attr.default_if); 415 if (ret) { 416 DPAA2_PMD_ERR("setting default interface failed in %s", 417 __func__); 418 goto init_err; 419 } 420 skip_reset_flags = DPDMUX_SKIP_DEFAULT_INTERFACE 421 | DPDMUX_SKIP_UNICAST_RULES | DPDMUX_SKIP_MULTICAST_RULES; 422 } else { 423 skip_reset_flags = DPDMUX_SKIP_DEFAULT_INTERFACE; 424 } 425 426 ret = dpdmux_get_api_version(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 427 &maj_ver, &min_ver); 428 if (ret) { 429 DPAA2_PMD_ERR("setting version failed in %s", 430 __func__); 431 goto init_err; 432 } 433 434 /* The new dpdmux_set/get_resetable() API are available starting with 435 * DPDMUX_VER_MAJOR==6 and DPDMUX_VER_MINOR==6 436 */ 437 if (maj_ver >= 6 && min_ver >= 6) { 438 ret = dpdmux_set_resetable(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 439 dpdmux_dev->token, skip_reset_flags); 440 if (ret) { 441 DPAA2_PMD_ERR("setting default interface failed in %s", 442 __func__); 443 goto init_err; 444 } 445 } 446 447 if (maj_ver >= 6 && min_ver >= 9) { 448 struct dpdmux_error_cfg mux_err_cfg; 449 450 memset(&mux_err_cfg, 0, sizeof(mux_err_cfg)); 451 mux_err_cfg.error_action = DPDMUX_ERROR_ACTION_CONTINUE; 452 453 if (attr.method != DPDMUX_METHOD_C_VLAN_MAC) 454 mux_err_cfg.errors = DPDMUX_ERROR_DISC; 455 else 456 mux_err_cfg.errors = DPDMUX_ALL_ERRORS; 457 458 ret = dpdmux_if_set_errors_behavior(&dpdmux_dev->dpdmux, 459 CMD_PRI_LOW, 460 dpdmux_dev->token, DPAA2_DPDMUX_DPMAC_IDX, 461 &mux_err_cfg); 462 if (ret) { 463 DPAA2_PMD_ERR("dpdmux_if_set_errors_behavior %s err %d", 464 __func__, ret); 465 goto init_err; 466 } 467 } 468 469 dpdmux_dev->dpdmux_id = dpdmux_id; 470 dpdmux_dev->num_ifs = attr.num_ifs; 471 472 TAILQ_INSERT_TAIL(&dpdmux_dev_list, dpdmux_dev, next); 473 474 return 0; 475 476 init_err: 477 rte_free(dpdmux_dev); 478 479 return -1; 480 } 481 482 static void 483 dpaa2_close_dpdmux_device(int object_id) 484 { 485 struct dpaa2_dpdmux_dev *dpdmux_dev; 486 487 dpdmux_dev = get_dpdmux_from_id((uint32_t)object_id); 488 489 if (dpdmux_dev) { 490 dpdmux_close(&dpdmux_dev->dpdmux, CMD_PRI_LOW, 491 dpdmux_dev->token); 492 TAILQ_REMOVE(&dpdmux_dev_list, dpdmux_dev, next); 493 rte_free(dpdmux_dev); 494 } 495 } 496 497 static struct rte_dpaa2_object rte_dpaa2_dpdmux_obj = { 498 .dev_type = DPAA2_MUX, 499 .create = dpaa2_create_dpdmux_device, 500 .close = dpaa2_close_dpdmux_device, 501 }; 502 503 RTE_PMD_REGISTER_DPAA2_OBJECT(dpdmux, rte_dpaa2_dpdmux_obj); 504