net: add rte prefix to ether structures
[dpdk.git] / drivers / net / mvneta / mvneta_ethdev.c
index 8b9e262..d539ba6 100644 (file)
@@ -4,10 +4,9 @@
  * All rights reserved.
  */
 
+#include <rte_string_fns.h>
 #include <rte_ethdev_driver.h>
 #include <rte_kvargs.h>
-#include <rte_log.h>
-#include <rte_malloc.h>
 #include <rte_bus_vdev.h>
 
 #include <stdio.h>
@@ -23,7 +22,7 @@
 
 #include <rte_mvep_common.h>
 
-#include "mvneta_ethdev.h"
+#include "mvneta_rxtx.h"
 
 
 #define MVNETA_IFACE_NAME_ARG "iface"
@@ -219,6 +218,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 < 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 +348,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;
 
@@ -305,6 +375,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 +395,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 +420,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 +436,209 @@ 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;
+       }
+}
+
+/**
+ * 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.
+ */
+static void
+mvneta_promiscuous_enable(struct rte_eth_dev *dev)
+{
+       struct mvneta_priv *priv = dev->data->dev_private;
+       int ret, en;
+
+       if (!priv->ppio)
+               return;
+
+       neta_ppio_get_promisc(priv->ppio, &en);
+       if (en) {
+               MVNETA_LOG(INFO, "Promiscuous already enabled");
+               return;
+       }
+
+       ret = neta_ppio_set_promisc(priv->ppio, 1);
+       if (ret)
+               MVNETA_LOG(ERR, "Failed to enable promiscuous mode");
+}
+
+/**
+ * DPDK callback to disable allmulticast mode.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mvneta_promiscuous_disable(struct rte_eth_dev *dev)
+{
+       struct mvneta_priv *priv = dev->data->dev_private;
+       int ret, en;
+
+       if (!priv->ppio)
+               return;
+
+       neta_ppio_get_promisc(priv->ppio, &en);
+       if (!en) {
+               MVNETA_LOG(INFO, "Promiscuous already disabled");
+               return;
+       }
+
+       ret = neta_ppio_set_promisc(priv->ppio, 0);
+       if (ret)
+               MVNETA_LOG(ERR, "Failed to disable promiscuous mode");
+}
+
+/**
+ * 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[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) {
+               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[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) {
+               ether_format_addr(buf, sizeof(buf), mac_addr);
+               MVNETA_LOG(ERR, "Failed to add mac %s", buf);
+               return -1;
+       }
+
+       return 0;
 }
 
 /**
@@ -368,7 +650,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;
@@ -385,6 +667,77 @@ mvneta_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
        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 +
+                       ppio_stats.rx_errors +
+                       ppio_stats.rx_crc_error -
+                       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.
+ */
+static void
+mvneta_stats_reset(struct rte_eth_dev *dev)
+{
+       struct mvneta_priv *priv = dev->data->dev_private;
+       unsigned int ret;
+
+       if (!priv->ppio)
+               return;
+
+       ret = mvneta_stats_get(dev, &priv->prev_stats);
+       if (unlikely(ret))
+               RTE_LOG(ERR, PMD, "Failed to reset port statistics");
+}
+
+
 static const struct eth_dev_ops mvneta_ops = {
        .dev_configure = mvneta_dev_configure,
        .dev_start = mvneta_dev_start,
@@ -392,9 +745,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,8 +788,9 @@ 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",
@@ -430,30 +798,27 @@ mvneta_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
        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);
 
        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;
 
        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 +833,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);
 }