X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmvneta%2Fmvneta_ethdev.c;h=865ad61aed1c51f4becfe87bae5831eb242f7f02;hb=23d4b61fee5dc75ced7938169dc87a6174a093aa;hp=8b9e262532783b2f4bad27d378baefda4d435e65;hpb=4ccc8d770d3b70b038facf880694744ee0acb521;p=dpdk.git diff --git a/drivers/net/mvneta/mvneta_ethdev.c b/drivers/net/mvneta/mvneta_ethdev.c index 8b9e262532..865ad61aed 100644 --- a/drivers/net/mvneta/mvneta_ethdev.c +++ b/drivers/net/mvneta/mvneta_ethdev.c @@ -4,10 +4,9 @@ * All rights reserved. */ +#include #include #include -#include -#include #include #include @@ -23,20 +22,11 @@ #include -#include "mvneta_ethdev.h" +#include "mvneta_rxtx.h" #define MVNETA_IFACE_NAME_ARG "iface" -#define MVNETA_RX_OFFLOADS (DEV_RX_OFFLOAD_JUMBO_FRAME | \ - DEV_RX_OFFLOAD_CHECKSUM) - -/** Port Tx offloads capabilities */ -#define MVNETA_TX_OFFLOADS (DEV_TX_OFFLOAD_IPV4_CKSUM | \ - DEV_TX_OFFLOAD_UDP_CKSUM | \ - DEV_TX_OFFLOAD_TCP_CKSUM | \ - DEV_TX_OFFLOAD_MULTI_SEGS) - #define MVNETA_PKT_SIZE_MAX (16382 - MV_MH_SIZE) /* 9700B */ #define MVNETA_DEFAULT_MTU 1500 @@ -58,6 +48,10 @@ struct mvneta_ifnames { static int mvneta_dev_num; +static int mvneta_stats_reset(struct rte_eth_dev *dev); +static int rte_pmd_mvneta_remove(struct rte_vdev_device *vdev); + + /** * Deinitialize packet processor. */ @@ -159,7 +153,7 @@ mvneta_dev_configure(struct rte_eth_dev *dev) * @param info * Info structure output buffer. */ -static void +static int mvneta_dev_infos_get(struct rte_eth_dev *dev __rte_unused, struct rte_eth_dev_info *info) { @@ -193,6 +187,8 @@ mvneta_dev_infos_get(struct rte_eth_dev *dev __rte_unused, info->default_txconf.offloads = 0; info->max_rx_pktlen = MVNETA_PKT_SIZE_MAX; + + return 0; } /** @@ -219,6 +215,77 @@ mvneta_dev_supported_ptypes_get(struct rte_eth_dev *dev __rte_unused) return ptypes; } +/** + * DPDK callback to change the MTU. + * + * Setting the MTU affects hardware MRU (packets larger than the MRU + * will be dropped). + * + * @param dev + * Pointer to Ethernet device structure. + * @param mtu + * New MTU. + * + * @return + * 0 on success, negative error value otherwise. + */ +static int +mvneta_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) +{ + struct mvneta_priv *priv = dev->data->dev_private; + uint16_t mbuf_data_size = 0; /* SW buffer size */ + uint16_t mru; + int ret; + + mru = MRVL_NETA_MTU_TO_MRU(mtu); + /* + * min_rx_buf_size is equal to mbuf data size + * if pmd didn't set it differently + */ + mbuf_data_size = dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM; + /* Prevent PMD from: + * - setting mru greater than the mbuf size resulting in + * hw and sw buffer size mismatch + * - setting mtu that requires the support of scattered packets + * when this feature has not been enabled/supported so far. + */ + if (!dev->data->scattered_rx && + (mru + MRVL_NETA_PKT_OFFS > mbuf_data_size)) { + mru = mbuf_data_size - MRVL_NETA_PKT_OFFS; + mtu = MRVL_NETA_MRU_TO_MTU(mru); + MVNETA_LOG(WARNING, "MTU too big, max MTU possible limitted by" + " current mbuf size: %u. Set MTU to %u, MRU to %u", + mbuf_data_size, mtu, mru); + } + + if (mtu < RTE_ETHER_MIN_MTU || mru > MVNETA_PKT_SIZE_MAX) { + MVNETA_LOG(ERR, "Invalid MTU [%u] or MRU [%u]", mtu, mru); + return -EINVAL; + } + + dev->data->mtu = mtu; + dev->data->dev_conf.rxmode.max_rx_pkt_len = mru - MV_MH_SIZE; + + if (!priv->ppio) + /* It is OK. New MTU will be set later on mvneta_dev_start */ + return 0; + + ret = neta_ppio_set_mru(priv->ppio, mru); + if (ret) { + MVNETA_LOG(ERR, "Failed to change MRU"); + return ret; + } + + ret = neta_ppio_set_mtu(priv->ppio, mtu); + if (ret) { + MVNETA_LOG(ERR, "Failed to change MTU"); + return ret; + } + MVNETA_LOG(INFO, "MTU changed to %u, MRU = %u", mtu, mru); + + return 0; +} + /** * DPDK callback to bring the link up. * @@ -278,7 +345,7 @@ mvneta_dev_start(struct rte_eth_dev *dev) if (priv->ppio) return mvneta_dev_set_link_up(dev); - snprintf(match, sizeof(match), "%s", dev->data->name); + strlcpy(match, dev->data->name, sizeof(match)); priv->ppio_params.match = match; priv->ppio_params.inqs_params.mtu = dev->data->mtu; @@ -289,6 +356,8 @@ mvneta_dev_start(struct rte_eth_dev *dev) } priv->ppio_id = priv->ppio->port_id; + mvneta_stats_reset(dev); + /* * In case there are some some stale uc/mc mac addresses flush them * here. It cannot be done during mvneta_dev_close() as port information @@ -305,6 +374,16 @@ mvneta_dev_start(struct rte_eth_dev *dev) priv->uc_mc_flushed = 1; } + ret = mvneta_alloc_rx_bufs(dev); + if (ret) + goto out; + + ret = mvneta_mtu_set(dev, dev->data->mtu); + if (ret) { + MVNETA_LOG(ERR, "Failed to set MTU %d", dev->data->mtu); + goto out; + } + ret = mvneta_dev_set_link_up(dev); if (ret) { MVNETA_LOG(ERR, "Failed to set link up"); @@ -315,6 +394,8 @@ mvneta_dev_start(struct rte_eth_dev *dev) for (i = 0; i < dev->data->nb_tx_queues; i++) dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED; + mvneta_set_tx_function(dev); + return 0; out: @@ -338,7 +419,7 @@ mvneta_dev_stop(struct rte_eth_dev *dev) return; mvneta_dev_set_link_down(dev); - + mvneta_flush_queues(dev); neta_ppio_deinit(priv->ppio); priv->ppio = NULL; @@ -354,9 +435,227 @@ static void mvneta_dev_close(struct rte_eth_dev *dev) { struct mvneta_priv *priv = dev->data->dev_private; + int i; if (priv->ppio) mvneta_dev_stop(dev); + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + mvneta_rx_queue_release(dev->data->rx_queues[i]); + dev->data->rx_queues[i] = NULL; + } + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + mvneta_tx_queue_release(dev->data->tx_queues[i]); + dev->data->tx_queues[i] = NULL; + } + + mvneta_dev_num--; + + if (mvneta_dev_num == 0) { + MVNETA_LOG(INFO, "Perform MUSDK deinit"); + mvneta_neta_deinit(); + rte_mvep_deinit(MVEP_MOD_T_NETA); + } +} + +/** + * DPDK callback to retrieve physical link information. + * + * @param dev + * Pointer to Ethernet device structure. + * @param wait_to_complete + * Wait for request completion (ignored). + * + * @return + * 0 on success, negative error value otherwise. + */ +static int +mvneta_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused) +{ + /* + * TODO + * once MUSDK provides necessary API use it here + */ + struct mvneta_priv *priv = dev->data->dev_private; + struct ethtool_cmd edata; + struct ifreq req; + int ret, fd, link_up; + + if (!priv->ppio) + return -EPERM; + + edata.cmd = ETHTOOL_GSET; + + strcpy(req.ifr_name, dev->data->name); + req.ifr_data = (void *)&edata; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) + return -EFAULT; + ret = ioctl(fd, SIOCETHTOOL, &req); + if (ret == -1) { + close(fd); + return -EFAULT; + } + + close(fd); + + switch (ethtool_cmd_speed(&edata)) { + case SPEED_10: + dev->data->dev_link.link_speed = ETH_SPEED_NUM_10M; + break; + case SPEED_100: + dev->data->dev_link.link_speed = ETH_SPEED_NUM_100M; + break; + case SPEED_1000: + dev->data->dev_link.link_speed = ETH_SPEED_NUM_1G; + break; + case SPEED_2500: + dev->data->dev_link.link_speed = ETH_SPEED_NUM_2_5G; + break; + default: + dev->data->dev_link.link_speed = ETH_SPEED_NUM_NONE; + } + + dev->data->dev_link.link_duplex = edata.duplex ? ETH_LINK_FULL_DUPLEX : + ETH_LINK_HALF_DUPLEX; + dev->data->dev_link.link_autoneg = edata.autoneg ? ETH_LINK_AUTONEG : + ETH_LINK_FIXED; + + neta_ppio_get_link_state(priv->ppio, &link_up); + dev->data->dev_link.link_status = link_up ? ETH_LINK_UP : ETH_LINK_DOWN; + + return 0; +} + +/** + * DPDK callback to enable promiscuous mode. + * + * @param dev + * Pointer to Ethernet device structure. + * + * @return + * always 0 + */ +static int +mvneta_promiscuous_enable(struct rte_eth_dev *dev) +{ + struct mvneta_priv *priv = dev->data->dev_private; + int ret, en; + + if (!priv->ppio) + return 0; + + neta_ppio_get_promisc(priv->ppio, &en); + if (en) { + MVNETA_LOG(INFO, "Promiscuous already enabled"); + return 0; + } + + ret = neta_ppio_set_promisc(priv->ppio, 1); + if (ret) + MVNETA_LOG(ERR, "Failed to enable promiscuous mode"); + + return 0; +} + +/** + * DPDK callback to disable allmulticast mode. + * + * @param dev + * Pointer to Ethernet device structure. + * + * @return + * always 0 + */ +static int +mvneta_promiscuous_disable(struct rte_eth_dev *dev) +{ + struct mvneta_priv *priv = dev->data->dev_private; + int ret, en; + + if (!priv->ppio) + return 0; + + neta_ppio_get_promisc(priv->ppio, &en); + if (!en) { + MVNETA_LOG(INFO, "Promiscuous already disabled"); + return 0; + } + + ret = neta_ppio_set_promisc(priv->ppio, 0); + if (ret) + MVNETA_LOG(ERR, "Failed to disable promiscuous mode"); + + return 0; +} + +/** + * DPDK callback to remove a MAC address. + * + * @param dev + * Pointer to Ethernet device structure. + * @param index + * MAC address index. + */ +static void +mvneta_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) +{ + struct mvneta_priv *priv = dev->data->dev_private; + char buf[RTE_ETHER_ADDR_FMT_SIZE]; + int ret; + + if (!priv->ppio) + return; + + ret = neta_ppio_remove_mac_addr(priv->ppio, + dev->data->mac_addrs[index].addr_bytes); + if (ret) { + rte_ether_format_addr(buf, sizeof(buf), + &dev->data->mac_addrs[index]); + MVNETA_LOG(ERR, "Failed to remove mac %s", buf); + } +} + +/** + * DPDK callback to add a MAC address. + * + * @param dev + * Pointer to Ethernet device structure. + * @param mac_addr + * MAC address to register. + * @param index + * MAC address index. + * @param vmdq + * VMDq pool index to associate address with (unused). + * + * @return + * 0 on success, negative error value otherwise. + */ +static int +mvneta_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr, + uint32_t index, uint32_t vmdq __rte_unused) +{ + struct mvneta_priv *priv = dev->data->dev_private; + char buf[RTE_ETHER_ADDR_FMT_SIZE]; + int ret; + + if (index == 0) + /* For setting index 0, mrvl_mac_addr_set() should be used.*/ + return -1; + + if (!priv->ppio) + return 0; + + ret = neta_ppio_add_mac_addr(priv->ppio, mac_addr->addr_bytes); + if (ret) { + rte_ether_format_addr(buf, sizeof(buf), mac_addr); + MVNETA_LOG(ERR, "Failed to add mac %s", buf); + return -1; + } + + return 0; } /** @@ -368,7 +667,7 @@ mvneta_dev_close(struct rte_eth_dev *dev) * MAC address to register. */ static int -mvneta_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr) +mvneta_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr) { struct mvneta_priv *priv = dev->data->dev_private; int ret; @@ -378,13 +677,86 @@ mvneta_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr) ret = neta_ppio_set_mac_addr(priv->ppio, mac_addr->addr_bytes); if (ret) { - char buf[ETHER_ADDR_FMT_SIZE]; - ether_format_addr(buf, sizeof(buf), mac_addr); + char buf[RTE_ETHER_ADDR_FMT_SIZE]; + rte_ether_format_addr(buf, sizeof(buf), mac_addr); MVNETA_LOG(ERR, "Failed to set mac to %s", buf); } return 0; } +/** + * DPDK callback to get device statistics. + * + * @param dev + * Pointer to Ethernet device structure. + * @param stats + * Stats structure output buffer. + * + * @return + * 0 on success, negative error value otherwise. + */ +static int +mvneta_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) +{ + struct mvneta_priv *priv = dev->data->dev_private; + struct neta_ppio_statistics ppio_stats; + unsigned int ret; + + if (!priv->ppio) + return -EPERM; + + ret = neta_ppio_get_statistics(priv->ppio, &ppio_stats); + if (unlikely(ret)) { + MVNETA_LOG(ERR, "Failed to update port statistics"); + return ret; + } + + stats->ipackets += ppio_stats.rx_packets + + ppio_stats.rx_broadcast_packets + + ppio_stats.rx_multicast_packets - + priv->prev_stats.ipackets; + stats->opackets += ppio_stats.tx_packets + + ppio_stats.tx_broadcast_packets + + ppio_stats.tx_multicast_packets - + priv->prev_stats.opackets; + stats->ibytes += ppio_stats.rx_bytes - priv->prev_stats.ibytes; + stats->obytes += ppio_stats.tx_bytes - priv->prev_stats.obytes; + stats->imissed += ppio_stats.rx_discard + + ppio_stats.rx_overrun - + priv->prev_stats.imissed; + stats->ierrors = ppio_stats.rx_packets_err - + priv->prev_stats.ierrors; + stats->oerrors = ppio_stats.tx_errors - priv->prev_stats.oerrors; + + return 0; +} + +/** + * DPDK callback to clear device statistics. + * + * @param dev + * Pointer to Ethernet device structure. + * + * @return + * 0 on success, negative error value otherwise. + */ +static int +mvneta_stats_reset(struct rte_eth_dev *dev) +{ + struct mvneta_priv *priv = dev->data->dev_private; + unsigned int ret; + + if (!priv->ppio) + return 0; + + ret = mvneta_stats_get(dev, &priv->prev_stats); + if (unlikely(ret)) + RTE_LOG(ERR, PMD, "Failed to reset port statistics"); + + return ret; +} + + static const struct eth_dev_ops mvneta_ops = { .dev_configure = mvneta_dev_configure, .dev_start = mvneta_dev_start, @@ -392,9 +764,23 @@ static const struct eth_dev_ops mvneta_ops = { .dev_set_link_up = mvneta_dev_set_link_up, .dev_set_link_down = mvneta_dev_set_link_down, .dev_close = mvneta_dev_close, + .link_update = mvneta_link_update, + .promiscuous_enable = mvneta_promiscuous_enable, + .promiscuous_disable = mvneta_promiscuous_disable, + .mac_addr_remove = mvneta_mac_addr_remove, + .mac_addr_add = mvneta_mac_addr_add, .mac_addr_set = mvneta_mac_addr_set, + .mtu_set = mvneta_mtu_set, + .stats_get = mvneta_stats_get, + .stats_reset = mvneta_stats_reset, .dev_infos_get = mvneta_dev_infos_get, .dev_supported_ptypes_get = mvneta_dev_supported_ptypes_get, + .rxq_info_get = mvneta_rxq_info_get, + .txq_info_get = mvneta_txq_info_get, + .rx_queue_setup = mvneta_rx_queue_setup, + .rx_queue_release = mvneta_rx_queue_release, + .tx_queue_setup = mvneta_tx_queue_setup, + .tx_queue_release = mvneta_tx_queue_release, }; /** @@ -421,39 +807,40 @@ mvneta_eth_dev_create(struct rte_vdev_device *vdev, const char *name) priv = rte_zmalloc_socket(name, sizeof(*priv), 0, rte_socket_id()); if (!priv) { ret = -ENOMEM; - goto out_free_dev; + goto out_free; } + eth_dev->data->dev_private = priv; eth_dev->data->mac_addrs = rte_zmalloc("mac_addrs", - ETHER_ADDR_LEN * MVNETA_MAC_ADDRS_MAX, 0); + RTE_ETHER_ADDR_LEN * MVNETA_MAC_ADDRS_MAX, 0); if (!eth_dev->data->mac_addrs) { MVNETA_LOG(ERR, "Failed to allocate space for eth addrs"); ret = -ENOMEM; - goto out_free_priv; + goto out_free; } memset(&req, 0, sizeof(req)); strcpy(req.ifr_name, name); ret = ioctl(fd, SIOCGIFHWADDR, &req); if (ret) - goto out_free_mac; + goto out_free; memcpy(eth_dev->data->mac_addrs[0].addr_bytes, - req.ifr_addr.sa_data, ETHER_ADDR_LEN); + req.ifr_addr.sa_data, RTE_ETHER_ADDR_LEN); eth_dev->data->kdrv = RTE_KDRV_NONE; - eth_dev->data->dev_private = priv; eth_dev->device = &vdev->device; + eth_dev->rx_pkt_burst = mvneta_rx_pkt_burst; + mvneta_set_tx_function(eth_dev); eth_dev->dev_ops = &mvneta_ops; + /* Flag to call rte_eth_dev_release_port() in rte_eth_dev_close(). */ + eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE; + rte_eth_dev_probing_finish(eth_dev); return 0; -out_free_mac: - rte_free(eth_dev->data->mac_addrs); -out_free_priv: - rte_free(priv); -out_free_dev: +out_free: rte_eth_dev_release_port(eth_dev); return ret; @@ -468,8 +855,6 @@ out_free_dev: static void mvneta_eth_dev_destroy(struct rte_eth_dev *eth_dev) { - rte_free(eth_dev->data->dev_private); - rte_free(eth_dev->data->mac_addrs); rte_eth_dev_release_port(eth_dev); } @@ -551,20 +936,16 @@ init_devices: ret = mvneta_eth_dev_create(vdev, ifnames.names[i]); if (ret) goto out_cleanup; + + mvneta_dev_num++; } - mvneta_dev_num += ifnum; rte_kvargs_free(kvlist); return 0; out_cleanup: - for (; i > 0; i--) - mvneta_eth_dev_destroy_name(ifnames.names[i]); + rte_pmd_mvneta_remove(vdev); - if (mvneta_dev_num == 0) { - mvneta_neta_deinit(); - rte_mvep_deinit(MVEP_MOD_T_NETA); - } out_free_kvlist: rte_kvargs_free(kvlist); @@ -583,27 +964,12 @@ out_free_kvlist: static int rte_pmd_mvneta_remove(struct rte_vdev_device *vdev) { - int i; - const char *name; - - name = rte_vdev_device_name(vdev); - if (!name) - return -EINVAL; - - MVNETA_LOG(INFO, "Removing %s", name); + uint16_t port_id; - RTE_ETH_FOREACH_DEV(i) { - if (rte_eth_devices[i].device != &vdev->device) + RTE_ETH_FOREACH_DEV(port_id) { + if (rte_eth_devices[port_id].device != &vdev->device) continue; - - mvneta_eth_dev_destroy(&rte_eth_devices[i]); - mvneta_dev_num--; - } - - if (mvneta_dev_num == 0) { - MVNETA_LOG(INFO, "Perform MUSDK deinit"); - mvneta_neta_deinit(); - rte_mvep_deinit(MVEP_MOD_T_NETA); + rte_eth_dev_close(port_id); } return 0;