X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fcnxk%2Fcnxk_ethdev_ops.c;h=91de6b70795f042e7bb1a883bf4b7eba6fdf1f11;hb=76dff63874e3d9dd0f2b7ffadfad94cb96a366c1;hp=fc6057698633d393a9aabba2fd639c56cbe5ff55;hpb=cbb8c8098c04b7babf0a9ae6a492b3d59f13abe3;p=dpdk.git diff --git a/drivers/net/cnxk/cnxk_ethdev_ops.c b/drivers/net/cnxk/cnxk_ethdev_ops.c index fc60576986..91de6b7079 100644 --- a/drivers/net/cnxk/cnxk_ethdev_ops.c +++ b/drivers/net/cnxk/cnxk_ethdev_ops.c @@ -71,6 +71,244 @@ cnxk_nix_info_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *devinfo) return 0; } +int +cnxk_nix_rx_burst_mode_get(struct rte_eth_dev *eth_dev, uint16_t queue_id, + struct rte_eth_burst_mode *mode) +{ + ssize_t bytes = 0, str_size = RTE_ETH_BURST_MODE_INFO_SIZE, rc; + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + const struct burst_info { + uint64_t flags; + const char *output; + } rx_offload_map[] = { + {DEV_RX_OFFLOAD_VLAN_STRIP, " VLAN Strip,"}, + {DEV_RX_OFFLOAD_IPV4_CKSUM, " Inner IPv4 Checksum,"}, + {DEV_RX_OFFLOAD_UDP_CKSUM, " UDP Checksum,"}, + {DEV_RX_OFFLOAD_TCP_CKSUM, " TCP Checksum,"}, + {DEV_RX_OFFLOAD_TCP_LRO, " TCP LRO,"}, + {DEV_RX_OFFLOAD_QINQ_STRIP, " QinQ VLAN Strip,"}, + {DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM, " Outer IPv4 Checksum,"}, + {DEV_RX_OFFLOAD_MACSEC_STRIP, " MACsec Strip,"}, + {DEV_RX_OFFLOAD_HEADER_SPLIT, " Header Split,"}, + {DEV_RX_OFFLOAD_VLAN_FILTER, " VLAN Filter,"}, + {DEV_RX_OFFLOAD_VLAN_EXTEND, " VLAN Extend,"}, + {DEV_RX_OFFLOAD_JUMBO_FRAME, " Jumbo Frame,"}, + {DEV_RX_OFFLOAD_SCATTER, " Scattered,"}, + {DEV_RX_OFFLOAD_TIMESTAMP, " Timestamp,"}, + {DEV_RX_OFFLOAD_SECURITY, " Security,"}, + {DEV_RX_OFFLOAD_KEEP_CRC, " Keep CRC,"}, + {DEV_RX_OFFLOAD_SCTP_CKSUM, " SCTP,"}, + {DEV_RX_OFFLOAD_OUTER_UDP_CKSUM, " Outer UDP Checksum,"}, + {DEV_RX_OFFLOAD_RSS_HASH, " RSS,"} + }; + static const char *const burst_mode[] = {"Vector Neon, Rx Offloads:", + "Scalar, Rx Offloads:" + }; + uint32_t i; + + PLT_SET_USED(queue_id); + + /* Update burst mode info */ + rc = rte_strscpy(mode->info + bytes, burst_mode[dev->scalar_ena], + str_size - bytes); + if (rc < 0) + goto done; + + bytes += rc; + + /* Update Rx offload info */ + for (i = 0; i < RTE_DIM(rx_offload_map); i++) { + if (dev->rx_offloads & rx_offload_map[i].flags) { + rc = rte_strscpy(mode->info + bytes, + rx_offload_map[i].output, + str_size - bytes); + if (rc < 0) + goto done; + + bytes += rc; + } + } + +done: + return 0; +} + +int +cnxk_nix_tx_burst_mode_get(struct rte_eth_dev *eth_dev, uint16_t queue_id, + struct rte_eth_burst_mode *mode) +{ + ssize_t bytes = 0, str_size = RTE_ETH_BURST_MODE_INFO_SIZE, rc; + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + const struct burst_info { + uint64_t flags; + const char *output; + } tx_offload_map[] = { + {DEV_TX_OFFLOAD_VLAN_INSERT, " VLAN Insert,"}, + {DEV_TX_OFFLOAD_IPV4_CKSUM, " Inner IPv4 Checksum,"}, + {DEV_TX_OFFLOAD_UDP_CKSUM, " UDP Checksum,"}, + {DEV_TX_OFFLOAD_TCP_CKSUM, " TCP Checksum,"}, + {DEV_TX_OFFLOAD_SCTP_CKSUM, " SCTP Checksum,"}, + {DEV_TX_OFFLOAD_TCP_TSO, " TCP TSO,"}, + {DEV_TX_OFFLOAD_UDP_TSO, " UDP TSO,"}, + {DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM, " Outer IPv4 Checksum,"}, + {DEV_TX_OFFLOAD_QINQ_INSERT, " QinQ VLAN Insert,"}, + {DEV_TX_OFFLOAD_VXLAN_TNL_TSO, " VXLAN Tunnel TSO,"}, + {DEV_TX_OFFLOAD_GRE_TNL_TSO, " GRE Tunnel TSO,"}, + {DEV_TX_OFFLOAD_IPIP_TNL_TSO, " IP-in-IP Tunnel TSO,"}, + {DEV_TX_OFFLOAD_GENEVE_TNL_TSO, " Geneve Tunnel TSO,"}, + {DEV_TX_OFFLOAD_MACSEC_INSERT, " MACsec Insert,"}, + {DEV_TX_OFFLOAD_MT_LOCKFREE, " Multi Thread Lockless Tx,"}, + {DEV_TX_OFFLOAD_MULTI_SEGS, " Scattered,"}, + {DEV_TX_OFFLOAD_MBUF_FAST_FREE, " H/W MBUF Free,"}, + {DEV_TX_OFFLOAD_SECURITY, " Security,"}, + {DEV_TX_OFFLOAD_UDP_TNL_TSO, " UDP Tunnel TSO,"}, + {DEV_TX_OFFLOAD_IP_TNL_TSO, " IP Tunnel TSO,"}, + {DEV_TX_OFFLOAD_OUTER_UDP_CKSUM, " Outer UDP Checksum,"}, + {DEV_TX_OFFLOAD_SEND_ON_TIMESTAMP, " Timestamp,"} + }; + static const char *const burst_mode[] = {"Vector Neon, Tx Offloads:", + "Scalar, Tx Offloads:" + }; + uint32_t i; + + PLT_SET_USED(queue_id); + + /* Update burst mode info */ + rc = rte_strscpy(mode->info + bytes, burst_mode[dev->scalar_ena], + str_size - bytes); + if (rc < 0) + goto done; + + bytes += rc; + + /* Update Tx offload info */ + for (i = 0; i < RTE_DIM(tx_offload_map); i++) { + if (dev->tx_offloads & tx_offload_map[i].flags) { + rc = rte_strscpy(mode->info + bytes, + tx_offload_map[i].output, + str_size - bytes); + if (rc < 0) + goto done; + + bytes += rc; + } + } + +done: + return 0; +} + +int +cnxk_nix_flow_ctrl_get(struct rte_eth_dev *eth_dev, + struct rte_eth_fc_conf *fc_conf) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + enum rte_eth_fc_mode mode_map[] = { + RTE_FC_NONE, RTE_FC_RX_PAUSE, + RTE_FC_TX_PAUSE, RTE_FC_FULL + }; + struct roc_nix *nix = &dev->nix; + int mode; + + mode = roc_nix_fc_mode_get(nix); + if (mode < 0) + return mode; + + memset(fc_conf, 0, sizeof(struct rte_eth_fc_conf)); + fc_conf->mode = mode_map[mode]; + return 0; +} + +static int +nix_fc_cq_config_set(struct cnxk_eth_dev *dev, uint16_t qid, bool enable) +{ + struct roc_nix *nix = &dev->nix; + struct roc_nix_fc_cfg fc_cfg; + struct roc_nix_cq *cq; + + memset(&fc_cfg, 0, sizeof(struct roc_nix_fc_cfg)); + cq = &dev->cqs[qid]; + fc_cfg.cq_cfg_valid = true; + fc_cfg.cq_cfg.enable = enable; + fc_cfg.cq_cfg.rq = qid; + fc_cfg.cq_cfg.cq_drop = cq->drop_thresh; + + return roc_nix_fc_config_set(nix, &fc_cfg); +} + +int +cnxk_nix_flow_ctrl_set(struct rte_eth_dev *eth_dev, + struct rte_eth_fc_conf *fc_conf) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + enum roc_nix_fc_mode mode_map[] = { + ROC_NIX_FC_NONE, ROC_NIX_FC_RX, + ROC_NIX_FC_TX, ROC_NIX_FC_FULL + }; + struct rte_eth_dev_data *data = eth_dev->data; + struct cnxk_fc_cfg *fc = &dev->fc_cfg; + struct roc_nix *nix = &dev->nix; + uint8_t rx_pause, tx_pause; + int rc, i; + + if (roc_nix_is_vf_or_sdp(nix)) { + plt_err("Flow control configuration is not allowed on VFs"); + return -ENOTSUP; + } + + if (fc_conf->high_water || fc_conf->low_water || fc_conf->pause_time || + fc_conf->mac_ctrl_frame_fwd || fc_conf->autoneg) { + plt_info("Only MODE configuration is supported"); + return -EINVAL; + } + + if (fc_conf->mode == fc->mode) + return 0; + + rx_pause = (fc_conf->mode == RTE_FC_FULL) || + (fc_conf->mode == RTE_FC_RX_PAUSE); + tx_pause = (fc_conf->mode == RTE_FC_FULL) || + (fc_conf->mode == RTE_FC_TX_PAUSE); + + /* Check if TX pause frame is already enabled or not */ + if (fc->tx_pause ^ tx_pause) { + if (roc_model_is_cn96_ax() && data->dev_started) { + /* On Ax, CQ should be in disabled state + * while setting flow control configuration. + */ + plt_info("Stop the port=%d for setting flow control", + data->port_id); + return 0; + } + + for (i = 0; i < data->nb_rx_queues; i++) { + rc = nix_fc_cq_config_set(dev, i, tx_pause); + if (rc) + return rc; + } + } + + rc = roc_nix_fc_mode_set(nix, mode_map[fc_conf->mode]); + if (rc) + return rc; + + fc->rx_pause = rx_pause; + fc->tx_pause = tx_pause; + fc->mode = fc_conf->mode; + + return rc; +} + +int +cnxk_nix_flow_ops_get(struct rte_eth_dev *eth_dev, + const struct rte_flow_ops **ops) +{ + RTE_SET_USED(eth_dev); + + *ops = &cnxk_flow_ops; + return 0; +} + int cnxk_nix_mac_addr_set(struct rte_eth_dev *eth_dev, struct rte_ether_addr *addr) { @@ -147,6 +385,8 @@ cnxk_nix_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu) int rc = -EINVAL; uint32_t buffsz; + frame_size += CNXK_NIX_TIMESYNC_RX_OFFSET * dev->ptp_en; + /* Check if MTU is within the allowed range */ if ((frame_size - RTE_ETHER_CRC_LEN) < NIX_MIN_HW_FRS) { plt_err("MTU is lesser than minimum"); @@ -267,3 +507,220 @@ cnxk_nix_promisc_disable(struct rte_eth_dev *eth_dev) dev->dmac_filter_enable = false; return 0; } + +int +cnxk_nix_allmulticast_enable(struct rte_eth_dev *eth_dev) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + + return roc_nix_npc_mcast_config(&dev->nix, true, false); +} + +int +cnxk_nix_allmulticast_disable(struct rte_eth_dev *eth_dev) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + + return roc_nix_npc_mcast_config(&dev->nix, false, + eth_dev->data->promiscuous); +} + +int +cnxk_nix_set_link_up(struct rte_eth_dev *eth_dev) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + struct roc_nix *nix = &dev->nix; + int rc, i; + + if (roc_nix_is_vf_or_sdp(nix)) + return -ENOTSUP; + + rc = roc_nix_mac_link_state_set(nix, true); + if (rc) + goto exit; + + /* Start tx queues */ + for (i = 0; i < eth_dev->data->nb_tx_queues; i++) { + rc = cnxk_nix_tx_queue_start(eth_dev, i); + if (rc) + goto exit; + } + +exit: + return rc; +} + +int +cnxk_nix_set_link_down(struct rte_eth_dev *eth_dev) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + struct roc_nix *nix = &dev->nix; + int rc, i; + + if (roc_nix_is_vf_or_sdp(nix)) + return -ENOTSUP; + + /* Stop tx queues */ + for (i = 0; i < eth_dev->data->nb_tx_queues; i++) { + rc = cnxk_nix_tx_queue_stop(eth_dev, i); + if (rc) + goto exit; + } + + rc = roc_nix_mac_link_state_set(nix, false); +exit: + return rc; +} + +int +cnxk_nix_get_module_info(struct rte_eth_dev *eth_dev, + struct rte_eth_dev_module_info *modinfo) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + struct roc_nix_eeprom_info eeprom_info = {0}; + struct roc_nix *nix = &dev->nix; + int rc; + + rc = roc_nix_eeprom_info_get(nix, &eeprom_info); + if (rc) + return rc; + + modinfo->type = eeprom_info.sff_id; + modinfo->eeprom_len = ROC_NIX_EEPROM_SIZE; + return 0; +} + +int +cnxk_nix_get_module_eeprom(struct rte_eth_dev *eth_dev, + struct rte_dev_eeprom_info *info) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + struct roc_nix_eeprom_info eeprom_info = {0}; + struct roc_nix *nix = &dev->nix; + int rc = -EINVAL; + + if (!info->data || !info->length || + (info->offset + info->length > ROC_NIX_EEPROM_SIZE)) + return rc; + + rc = roc_nix_eeprom_info_get(nix, &eeprom_info); + if (rc) + return rc; + + rte_memcpy(info->data, eeprom_info.buf + info->offset, info->length); + return 0; +} + +int +cnxk_nix_rx_queue_intr_enable(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + + roc_nix_rx_queue_intr_enable(&dev->nix, rx_queue_id); + return 0; +} + +int +cnxk_nix_rx_queue_intr_disable(struct rte_eth_dev *eth_dev, + uint16_t rx_queue_id) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + + roc_nix_rx_queue_intr_disable(&dev->nix, rx_queue_id); + return 0; +} + +int +cnxk_nix_pool_ops_supported(struct rte_eth_dev *eth_dev, const char *pool) +{ + RTE_SET_USED(eth_dev); + + if (!strcmp(pool, rte_mbuf_platform_mempool_ops())) + return 0; + + return -ENOTSUP; +} + +int +cnxk_nix_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version, + size_t fw_size) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + const char *str = roc_npc_profile_name_get(&dev->npc); + uint32_t size = strlen(str) + 1; + + if (fw_size > size) + fw_size = size; + + rte_strlcpy(fw_version, str, fw_size); + + if (fw_size < size) + return size; + + return 0; +} + +void +cnxk_nix_rxq_info_get(struct rte_eth_dev *eth_dev, uint16_t qid, + struct rte_eth_rxq_info *qinfo) +{ + void *rxq = eth_dev->data->rx_queues[qid]; + struct cnxk_eth_rxq_sp *rxq_sp = cnxk_eth_rxq_to_sp(rxq); + + memset(qinfo, 0, sizeof(*qinfo)); + + qinfo->mp = rxq_sp->qconf.mp; + qinfo->scattered_rx = eth_dev->data->scattered_rx; + qinfo->nb_desc = rxq_sp->qconf.nb_desc; + + memcpy(&qinfo->conf, &rxq_sp->qconf.conf.rx, sizeof(qinfo->conf)); +} + +void +cnxk_nix_txq_info_get(struct rte_eth_dev *eth_dev, uint16_t qid, + struct rte_eth_txq_info *qinfo) +{ + void *txq = eth_dev->data->tx_queues[qid]; + struct cnxk_eth_txq_sp *txq_sp = cnxk_eth_txq_to_sp(txq); + + memset(qinfo, 0, sizeof(*qinfo)); + + qinfo->nb_desc = txq_sp->qconf.nb_desc; + + memcpy(&qinfo->conf, &txq_sp->qconf.conf.tx, sizeof(qinfo->conf)); +} + +/* It is a NOP for cnxk as HW frees the buffer on xmit */ +int +cnxk_nix_tx_done_cleanup(void *txq, uint32_t free_cnt) +{ + RTE_SET_USED(txq); + RTE_SET_USED(free_cnt); + + return 0; +} + +int +cnxk_nix_dev_get_reg(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs) +{ + struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev); + struct roc_nix *nix = &dev->nix; + uint64_t *data = regs->data; + int rc = -ENOTSUP; + + if (data == NULL) { + rc = roc_nix_lf_get_reg_count(nix); + if (rc > 0) { + regs->length = rc; + regs->width = 8; + rc = 0; + } + return rc; + } + + if (!regs->length || + regs->length == (uint32_t)roc_nix_lf_get_reg_count(nix)) + return roc_nix_lf_reg_dump(nix, data); + + return rc; +}