X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Flinux%2Fmlx5_os.c;h=0dcf5000e91e2fce1da5f5911a2117255d6338e3;hb=ff4e52efb39517f75eccba261c87b48cb464b246;hp=1b7ee419d1e29e1a1c6982deeae8e0bf7069a2f0;hpb=a7f34989e9ade83ca14a8424e73452d0e3e018c3;p=dpdk.git diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index 1b7ee419d1..0dcf5000e9 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -785,6 +786,32 @@ mlx5_flow_counter_mode_config(struct rte_eth_dev *dev __rte_unused) #endif } +/** + * DR flow drop action support detect. + * + * @param dev + * Pointer to rte_eth_dev structure. + * + */ +static void +mlx5_flow_drop_action_config(struct rte_eth_dev *dev __rte_unused) +{ +#ifdef HAVE_MLX5DV_DR + struct mlx5_priv *priv = dev->data->dev_private; + + if (!priv->config.dv_flow_en || !priv->sh->dr_drop_action) + return; + /** + * DR supports drop action placeholder when it is supported; + * otherwise, use the queue drop action. + */ + if (mlx5_flow_discover_dr_action_support(dev)) + priv->root_drop_action = priv->drop_queue.hrxq->action; + else + priv->root_drop_action = priv->sh->dr_drop_action; +#endif +} + static void mlx5_queue_counter_id_prepare(struct rte_eth_dev *dev) { @@ -1007,8 +1034,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, err = mlx5_proc_priv_init(eth_dev); if (err) return NULL; - mp_id.port_id = eth_dev->data->port_id; - strlcpy(mp_id.name, MLX5_MP_NAME, RTE_MP_MAX_NAME_LEN); + mlx5_mp_id_init(&mp_id, eth_dev->data->port_id); /* Receive command fd from primary process */ err = mlx5_mp_req_verbs_cmd_fd(&mp_id); if (err < 0) @@ -1180,6 +1206,13 @@ err_secondary: priv->vport_meta_tag = 0; priv->vport_meta_mask = 0; priv->pf_bond = spawn->pf_bond; + + DRV_LOG(DEBUG, + "dev_port=%u bus=%s pci=%s master=%d representor=%d pf_bond=%d\n", + priv->dev_port, dpdk_dev->bus->name, + priv->pci_dev ? priv->pci_dev->name : "NONE", + priv->master, priv->representor, priv->pf_bond); + /* * If we have E-Switch we should determine the vport attributes. * E-Switch may use either source vport field or reg_c[0] metadata @@ -1252,7 +1285,7 @@ err_secondary: * Look for sibling devices in order to reuse their switch domain * if any, otherwise allocate one. */ - MLX5_ETH_FOREACH_DEV(port_id, NULL) { + MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) { const struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private; @@ -1262,6 +1295,8 @@ err_secondary: RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) continue; priv->domain_id = opriv->domain_id; + DRV_LOG(DEBUG, "dev_port-%u inherit domain_id=%u\n", + priv->dev_port, priv->domain_id); break; } if (priv->domain_id == RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) { @@ -1273,10 +1308,12 @@ err_secondary: goto error; } own_domain_id = 1; + DRV_LOG(DEBUG, "dev_port-%u new domain_id=%u\n", + priv->dev_port, priv->domain_id); } /* Override some values set by hardware configuration. */ mlx5_args(config, dpdk_dev->devargs); - err = mlx5_dev_check_sibling_config(priv, config); + err = mlx5_dev_check_sibling_config(priv, config, dpdk_dev); if (err) goto error; config->hw_csum = !!(sh->device_attr.device_cap_flags_ex & @@ -1293,6 +1330,12 @@ err_secondary: config->dv_flow_en = 0; } #endif + if (spawn->max_port > UINT8_MAX) { + /* Verbs can't support ports larger than 255 by design. */ + DRV_LOG(ERR, "can't support IB ports > UINT8_MAX"); + err = EINVAL; + goto error; + } config->ind_table_max_size = sh->device_attr.max_rwq_indirection_table_size; /* @@ -1357,6 +1400,8 @@ err_secondary: } sh->rq_ts_format = config->hca_attr.rq_ts_format; sh->sq_ts_format = config->hca_attr.sq_ts_format; + sh->steering_format_version = + config->hca_attr.steering_format_version; sh->qp_ts_format = config->hca_attr.qp_ts_format; /* Check for LRO support. */ if (config->dest_tir && config->hca_attr.lro_cap && @@ -1631,6 +1676,19 @@ err_secondary: if (priv->representor) { eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR; eth_dev->data->representor_id = priv->representor_id; + MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) { + struct mlx5_priv *opriv = + rte_eth_devices[port_id].data->dev_private; + if (opriv && + opriv->master && + opriv->domain_id == priv->domain_id && + opriv->sh == priv->sh) { + eth_dev->data->backer_port_id = port_id; + break; + } + } + if (port_id >= RTE_MAX_ETHPORTS) + eth_dev->data->backer_port_id = eth_dev->data->port_id; } priv->mp_id.port_id = eth_dev->data->port_id; strlcpy(priv->mp_id.name, MLX5_MP_NAME, RTE_MP_MAX_NAME_LEN); @@ -1656,11 +1714,8 @@ err_secondary: goto error; } DRV_LOG(INFO, - "port %u MAC address is %02x:%02x:%02x:%02x:%02x:%02x", - eth_dev->data->port_id, - mac.addr_bytes[0], mac.addr_bytes[1], - mac.addr_bytes[2], mac.addr_bytes[3], - mac.addr_bytes[4], mac.addr_bytes[5]); + "port %u MAC address is " RTE_ETHER_ADDR_PRT_FMT, + eth_dev->data->port_id, RTE_ETHER_ADDR_BYTES(&mac)); #ifdef RTE_LIBRTE_MLX5_DEBUG { char ifname[MLX5_NAMESIZE]; @@ -1769,6 +1824,21 @@ err_secondary: } else { priv->obj_ops = ibv_obj_ops; } + if (config->tx_pp && + (priv->config.dv_esw_en || + priv->obj_ops.txq_obj_new != mlx5_os_txq_obj_new)) { + /* + * HAVE_MLX5DV_DEVX_UAR_OFFSET is required to support + * packet pacing and already checked above. + * Hence, we should only make sure the SQs will be created + * with DevX, not with Verbs. + * Verbs allocates the SQ UAR on its own and it can't be shared + * with Clock Queue UAR as required for Tx scheduling. + */ + DRV_LOG(ERR, "Verbs SQs, UAR can't be shared as required for packet pacing"); + err = ENODEV; + goto error; + } priv->drop_queue.hrxq = mlx5_drop_action_create(eth_dev); if (!priv->drop_queue.hrxq) goto error; @@ -1840,6 +1910,7 @@ err_secondary: } rte_spinlock_init(&priv->shared_act_sl); mlx5_flow_counter_mode_config(eth_dev); + mlx5_flow_drop_action_config(eth_dev); if (priv->config.dv_flow_en) eth_dev->data->dev_flags |= RTE_ETH_DEV_FLOW_OPS_THREAD_SAFE; return eth_dev; @@ -2061,6 +2132,29 @@ mlx5_device_bond_pci_match(const struct ibv_device *ibv_dev, return pf; } +static void +mlx5_os_config_default(struct mlx5_dev_config *config) +{ + memset(config, 0, sizeof(*config)); + config->mps = MLX5_ARG_UNSET; + config->dbnc = MLX5_ARG_UNSET; + config->rx_vec_en = 1; + config->txq_inline_max = MLX5_ARG_UNSET; + config->txq_inline_min = MLX5_ARG_UNSET; + config->txq_inline_mpw = MLX5_ARG_UNSET; + config->txqs_inline = MLX5_ARG_UNSET; + config->vf_nl_en = 1; + config->mr_ext_memseg_en = 1; + config->mr_mempool_reg_en = 1; + config->mprq.max_memcpy_len = MLX5_MPRQ_MEMCPY_DEFAULT_LEN; + config->mprq.min_rxqs_num = MLX5_MPRQ_MIN_RXQS; + config->dv_esw_en = 1; + config->dv_flow_en = 1; + config->decap_en = 1; + config->log_hp_size = MLX5_ARG_UNSET; + config->allow_duplicate_pattern = 1; +} + /** * Register a PCI device within bonding. * @@ -2208,19 +2302,6 @@ mlx5_os_pci_probe_pf(struct rte_pci_device *pci_dev, goto exit; } } -#ifndef HAVE_MLX5DV_DR_DEVX_PORT - if (bd >= 0) { - /* - * This may happen if there is VF LAG kernel support and - * application is compiled with older rdma_core library. - */ - DRV_LOG(ERR, - "No kernel/verbs support for VF LAG bonding found."); - rte_errno = ENOTSUP; - ret = -rte_errno; - goto exit; - } -#endif /* * Now we can determine the maximal * amount of devices to be spawned. @@ -2284,10 +2365,18 @@ mlx5_os_pci_probe_pf(struct rte_pci_device *pci_dev, (list[ns].ifindex, &list[ns].info); } -#ifdef HAVE_MLX5DV_DR_DEVX_PORT if (!ret && bd >= 0) { switch (list[ns].info.name_type) { case MLX5_PHYS_PORT_NAME_TYPE_UPLINK: + if (np == 1) { + /* + * Force standalone bonding + * device for ROCE LAG + * confgiurations. + */ + list[ns].info.master = 0; + list[ns].info.representor = 0; + } if (list[ns].info.port_name == bd) ns++; break; @@ -2304,7 +2393,6 @@ mlx5_os_pci_probe_pf(struct rte_pci_device *pci_dev, } continue; } -#endif if (!ret && (list[ns].info.representor ^ list[ns].info.master)) ns++; @@ -2485,24 +2573,8 @@ mlx5_os_pci_probe_pf(struct rte_pci_device *pci_dev, uint32_t restore; /* Default configuration. */ - memset(&dev_config, 0, sizeof(struct mlx5_dev_config)); + mlx5_os_config_default(&dev_config); dev_config.vf = dev_config_vf; - dev_config.mps = MLX5_ARG_UNSET; - dev_config.dbnc = MLX5_ARG_UNSET; - dev_config.rx_vec_en = 1; - dev_config.txq_inline_max = MLX5_ARG_UNSET; - dev_config.txq_inline_min = MLX5_ARG_UNSET; - dev_config.txq_inline_mpw = MLX5_ARG_UNSET; - dev_config.txqs_inline = MLX5_ARG_UNSET; - dev_config.vf_nl_en = 1; - dev_config.mr_ext_memseg_en = 1; - dev_config.mprq.max_memcpy_len = MLX5_MPRQ_MEMCPY_DEFAULT_LEN; - dev_config.mprq.min_rxqs_num = MLX5_MPRQ_MIN_RXQS; - dev_config.dv_esw_en = 1; - dev_config.dv_flow_en = 1; - dev_config.decap_en = 1; - dev_config.log_hp_size = MLX5_ARG_UNSET; - dev_config.allow_duplicate_pattern = 1; list[i].numa_node = pci_dev->device.numa_node; list[i].eth_dev = mlx5_dev_spawn(&pci_dev->device, &list[i], @@ -2516,6 +2588,31 @@ mlx5_os_pci_probe_pf(struct rte_pci_device *pci_dev, } restore = list[i].eth_dev->data->dev_flags; rte_eth_copy_pci_info(list[i].eth_dev, pci_dev); + /** + * Each representor has a dedicated interrupts vector. + * rte_eth_copy_pci_info() assigns PF interrupts handle to + * representor eth_dev object because representor and PF + * share the same PCI address. + * Override representor device with a dedicated + * interrupts handle here. + * Representor interrupts handle is released in mlx5_dev_stop(). + */ + if (list[i].info.representor) { + struct rte_intr_handle *intr_handle; + intr_handle = mlx5_malloc(MLX5_MEM_SYS | MLX5_MEM_ZERO, + sizeof(*intr_handle), 0, + SOCKET_ID_ANY); + if (!intr_handle) { + DRV_LOG(ERR, + "port %u failed to allocate memory for interrupt handler " + "Rx interrupts will not be supported", + i); + rte_errno = ENOMEM; + ret = -rte_errno; + goto exit; + } + list[i].eth_dev->intr_handle = intr_handle; + } /* Restore non-PCI flags cleared by the above call. */ list[i].eth_dev->data->dev_flags |= restore; rte_eth_dev_probing_finish(list[i].eth_dev); @@ -2560,6 +2657,35 @@ exit: return ret; } +static int +mlx5_os_parse_eth_devargs(struct rte_device *dev, + struct rte_eth_devargs *eth_da) +{ + int ret = 0; + + if (dev->devargs == NULL) + return 0; + memset(eth_da, 0, sizeof(*eth_da)); + /* Parse representor information first from class argument. */ + if (dev->devargs->cls_str) + ret = rte_eth_devargs_parse(dev->devargs->cls_str, eth_da); + if (ret != 0) { + DRV_LOG(ERR, "failed to parse device arguments: %s", + dev->devargs->cls_str); + return -rte_errno; + } + if (eth_da->type == RTE_ETH_REPRESENTOR_NONE) { + /* Parse legacy device argument */ + ret = rte_eth_devargs_parse(dev->devargs->args, eth_da); + if (ret) { + DRV_LOG(ERR, "failed to parse device arguments: %s", + dev->devargs->args); + return -rte_errno; + } + } + return 0; +} + /** * Callback to register a PCI device. * @@ -2574,47 +2700,86 @@ exit: static int mlx5_os_pci_probe(struct rte_pci_device *pci_dev) { - struct rte_eth_devargs eth_da = { .type = RTE_ETH_REPRESENTOR_NONE }; + struct rte_eth_devargs eth_da = { .nb_ports = 0 }; int ret = 0; uint16_t p; - if (pci_dev->device.devargs) { - /* Parse representor information from device argument. */ - if (pci_dev->device.devargs->cls_str) - ret = rte_eth_devargs_parse - (pci_dev->device.devargs->cls_str, ð_da); - if (ret) { - DRV_LOG(ERR, "failed to parse device arguments: %s", - pci_dev->device.devargs->cls_str); - return -rte_errno; - } - if (eth_da.type == RTE_ETH_REPRESENTOR_NONE) { - /* Support legacy device argument */ - ret = rte_eth_devargs_parse - (pci_dev->device.devargs->args, ð_da); - if (ret) { - DRV_LOG(ERR, "failed to parse device arguments: %s", - pci_dev->device.devargs->args); - return -rte_errno; - } - } - } + ret = mlx5_os_parse_eth_devargs(&pci_dev->device, ð_da); + if (ret != 0) + return ret; if (eth_da.nb_ports > 0) { /* Iterate all port if devargs pf is range: "pf[0-1]vf[...]". */ - for (p = 0; p < eth_da.nb_ports; p++) + for (p = 0; p < eth_da.nb_ports; p++) { ret = mlx5_os_pci_probe_pf(pci_dev, ð_da, eth_da.ports[p]); + if (ret) + break; + } + if (ret) { + DRV_LOG(ERR, "Probe of PCI device " PCI_PRI_FMT " " + "aborted due to proding failure of PF %u", + pci_dev->addr.domain, pci_dev->addr.bus, + pci_dev->addr.devid, pci_dev->addr.function, + eth_da.ports[p]); + mlx5_net_remove(&pci_dev->device); + } } else { ret = mlx5_os_pci_probe_pf(pci_dev, ð_da, 0); } return ret; } +/* Probe a single SF device on auxiliary bus, no representor support. */ +static int +mlx5_os_auxiliary_probe(struct rte_device *dev) +{ + struct rte_eth_devargs eth_da = { .nb_ports = 0 }; + struct mlx5_dev_config config; + struct mlx5_dev_spawn_data spawn = { .pf_bond = -1 }; + struct rte_auxiliary_device *adev = RTE_DEV_TO_AUXILIARY(dev); + struct rte_eth_dev *eth_dev; + int ret = 0; + + /* Parse ethdev devargs. */ + ret = mlx5_os_parse_eth_devargs(dev, ð_da); + if (ret != 0) + return ret; + /* Set default config data. */ + mlx5_os_config_default(&config); + config.sf = 1; + /* Init spawn data. */ + spawn.max_port = 1; + spawn.phys_port = 1; + spawn.phys_dev = mlx5_os_get_ibv_dev(dev); + if (spawn.phys_dev == NULL) + return -rte_errno; + ret = mlx5_auxiliary_get_ifindex(dev->name); + if (ret < 0) { + DRV_LOG(ERR, "failed to get ethdev ifindex: %s", dev->name); + return ret; + } + spawn.ifindex = ret; + spawn.numa_node = dev->numa_node; + /* Spawn device. */ + eth_dev = mlx5_dev_spawn(dev, &spawn, &config, ð_da); + if (eth_dev == NULL) + return -rte_errno; + /* Post create. */ + eth_dev->intr_handle = &adev->intr_handle; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC; + eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_RMV; + eth_dev->data->numa_node = dev->numa_node; + } + rte_eth_dev_probing_finish(eth_dev); + return 0; +} + /** * Net class driver callback to probe a device. * - * This function probe PCI bus device(s). + * This function probe PCI bus device(s) or a single SF on auxiliary bus. * * @param[in] dev * Pointer to the generic device. @@ -2637,7 +2802,8 @@ mlx5_os_net_probe(struct rte_device *dev) } if (mlx5_dev_is_pci(dev)) return mlx5_os_pci_probe(RTE_DEV_TO_PCI(dev)); - return 0; + else + return mlx5_os_auxiliary_probe(dev); } static int