1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
22bfe3f2eSlogwang * Copyright 2017 6WIND S.A.
3d30ea906Sjfb8856606 * Copyright 2017 Mellanox Technologies, Ltd
42bfe3f2eSlogwang */
52bfe3f2eSlogwang
62bfe3f2eSlogwang /**
72bfe3f2eSlogwang * @file
82bfe3f2eSlogwang * Miscellaneous control operations for mlx4 driver.
92bfe3f2eSlogwang */
102bfe3f2eSlogwang
112bfe3f2eSlogwang #include <dirent.h>
122bfe3f2eSlogwang #include <errno.h>
132bfe3f2eSlogwang #include <linux/ethtool.h>
142bfe3f2eSlogwang #include <linux/sockios.h>
152bfe3f2eSlogwang #include <net/if.h>
162bfe3f2eSlogwang #include <netinet/ip.h>
172bfe3f2eSlogwang #include <stddef.h>
182bfe3f2eSlogwang #include <stdint.h>
192bfe3f2eSlogwang #include <stdio.h>
202bfe3f2eSlogwang #include <stdlib.h>
212bfe3f2eSlogwang #include <string.h>
222bfe3f2eSlogwang #include <sys/ioctl.h>
232bfe3f2eSlogwang #include <sys/socket.h>
242bfe3f2eSlogwang #include <unistd.h>
252bfe3f2eSlogwang
262bfe3f2eSlogwang /* Verbs headers do not support -pedantic. */
272bfe3f2eSlogwang #ifdef PEDANTIC
282bfe3f2eSlogwang #pragma GCC diagnostic ignored "-Wpedantic"
292bfe3f2eSlogwang #endif
302bfe3f2eSlogwang #include <infiniband/verbs.h>
312bfe3f2eSlogwang #ifdef PEDANTIC
322bfe3f2eSlogwang #pragma GCC diagnostic error "-Wpedantic"
332bfe3f2eSlogwang #endif
342bfe3f2eSlogwang
352bfe3f2eSlogwang #include <rte_bus_pci.h>
362bfe3f2eSlogwang #include <rte_errno.h>
37d30ea906Sjfb8856606 #include <rte_ethdev_driver.h>
382bfe3f2eSlogwang #include <rte_ether.h>
392bfe3f2eSlogwang #include <rte_flow.h>
402bfe3f2eSlogwang #include <rte_pci.h>
41d30ea906Sjfb8856606 #include <rte_string_fns.h>
422bfe3f2eSlogwang
432bfe3f2eSlogwang #include "mlx4.h"
442bfe3f2eSlogwang #include "mlx4_flow.h"
45d30ea906Sjfb8856606 #include "mlx4_glue.h"
462bfe3f2eSlogwang #include "mlx4_rxtx.h"
472bfe3f2eSlogwang #include "mlx4_utils.h"
482bfe3f2eSlogwang
492bfe3f2eSlogwang /**
502bfe3f2eSlogwang * Get interface name from private structure.
512bfe3f2eSlogwang *
522bfe3f2eSlogwang * @param[in] priv
532bfe3f2eSlogwang * Pointer to private structure.
542bfe3f2eSlogwang * @param[out] ifname
552bfe3f2eSlogwang * Interface name output buffer.
562bfe3f2eSlogwang *
572bfe3f2eSlogwang * @return
582bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
592bfe3f2eSlogwang */
602bfe3f2eSlogwang int
mlx4_get_ifname(const struct mlx4_priv * priv,char (* ifname)[IF_NAMESIZE])611646932aSjfb8856606 mlx4_get_ifname(const struct mlx4_priv *priv, char (*ifname)[IF_NAMESIZE])
622bfe3f2eSlogwang {
632bfe3f2eSlogwang DIR *dir;
642bfe3f2eSlogwang struct dirent *dent;
652bfe3f2eSlogwang unsigned int dev_type = 0;
662bfe3f2eSlogwang unsigned int dev_port_prev = ~0u;
672bfe3f2eSlogwang char match[IF_NAMESIZE] = "";
682bfe3f2eSlogwang
692bfe3f2eSlogwang {
702bfe3f2eSlogwang MKSTR(path, "%s/device/net", priv->ctx->device->ibdev_path);
712bfe3f2eSlogwang
722bfe3f2eSlogwang dir = opendir(path);
732bfe3f2eSlogwang if (dir == NULL) {
742bfe3f2eSlogwang rte_errno = errno;
752bfe3f2eSlogwang return -rte_errno;
762bfe3f2eSlogwang }
772bfe3f2eSlogwang }
782bfe3f2eSlogwang while ((dent = readdir(dir)) != NULL) {
792bfe3f2eSlogwang char *name = dent->d_name;
802bfe3f2eSlogwang FILE *file;
812bfe3f2eSlogwang unsigned int dev_port;
822bfe3f2eSlogwang int r;
832bfe3f2eSlogwang
842bfe3f2eSlogwang if ((name[0] == '.') &&
852bfe3f2eSlogwang ((name[1] == '\0') ||
862bfe3f2eSlogwang ((name[1] == '.') && (name[2] == '\0'))))
872bfe3f2eSlogwang continue;
882bfe3f2eSlogwang
892bfe3f2eSlogwang MKSTR(path, "%s/device/net/%s/%s",
902bfe3f2eSlogwang priv->ctx->device->ibdev_path, name,
912bfe3f2eSlogwang (dev_type ? "dev_id" : "dev_port"));
922bfe3f2eSlogwang
932bfe3f2eSlogwang file = fopen(path, "rb");
942bfe3f2eSlogwang if (file == NULL) {
952bfe3f2eSlogwang if (errno != ENOENT)
962bfe3f2eSlogwang continue;
972bfe3f2eSlogwang /*
982bfe3f2eSlogwang * Switch to dev_id when dev_port does not exist as
992bfe3f2eSlogwang * is the case with Linux kernel versions < 3.15.
1002bfe3f2eSlogwang */
1012bfe3f2eSlogwang try_dev_id:
1022bfe3f2eSlogwang match[0] = '\0';
1032bfe3f2eSlogwang if (dev_type)
1042bfe3f2eSlogwang break;
1052bfe3f2eSlogwang dev_type = 1;
1062bfe3f2eSlogwang dev_port_prev = ~0u;
1072bfe3f2eSlogwang rewinddir(dir);
1082bfe3f2eSlogwang continue;
1092bfe3f2eSlogwang }
1102bfe3f2eSlogwang r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port);
1112bfe3f2eSlogwang fclose(file);
1122bfe3f2eSlogwang if (r != 1)
1132bfe3f2eSlogwang continue;
1142bfe3f2eSlogwang /*
1152bfe3f2eSlogwang * Switch to dev_id when dev_port returns the same value for
1162bfe3f2eSlogwang * all ports. May happen when using a MOFED release older than
1172bfe3f2eSlogwang * 3.0 with a Linux kernel >= 3.15.
1182bfe3f2eSlogwang */
1192bfe3f2eSlogwang if (dev_port == dev_port_prev)
1202bfe3f2eSlogwang goto try_dev_id;
1212bfe3f2eSlogwang dev_port_prev = dev_port;
1222bfe3f2eSlogwang if (dev_port == (priv->port - 1u))
123d30ea906Sjfb8856606 strlcpy(match, name, sizeof(match));
1242bfe3f2eSlogwang }
1252bfe3f2eSlogwang closedir(dir);
1262bfe3f2eSlogwang if (match[0] == '\0') {
1272bfe3f2eSlogwang rte_errno = ENODEV;
1282bfe3f2eSlogwang return -rte_errno;
1292bfe3f2eSlogwang }
1302bfe3f2eSlogwang strncpy(*ifname, match, sizeof(*ifname));
1312bfe3f2eSlogwang return 0;
1322bfe3f2eSlogwang }
1332bfe3f2eSlogwang
1342bfe3f2eSlogwang /**
1352bfe3f2eSlogwang * Perform ifreq ioctl() on associated Ethernet device.
1362bfe3f2eSlogwang *
1372bfe3f2eSlogwang * @param[in] priv
1382bfe3f2eSlogwang * Pointer to private structure.
1392bfe3f2eSlogwang * @param req
1402bfe3f2eSlogwang * Request number to pass to ioctl().
1412bfe3f2eSlogwang * @param[out] ifr
1422bfe3f2eSlogwang * Interface request structure output buffer.
1432bfe3f2eSlogwang *
1442bfe3f2eSlogwang * @return
1452bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
1462bfe3f2eSlogwang */
1472bfe3f2eSlogwang static int
mlx4_ifreq(const struct mlx4_priv * priv,int req,struct ifreq * ifr)1481646932aSjfb8856606 mlx4_ifreq(const struct mlx4_priv *priv, int req, struct ifreq *ifr)
1492bfe3f2eSlogwang {
1502bfe3f2eSlogwang int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
1512bfe3f2eSlogwang int ret;
1522bfe3f2eSlogwang
1532bfe3f2eSlogwang if (sock == -1) {
1542bfe3f2eSlogwang rte_errno = errno;
1552bfe3f2eSlogwang return -rte_errno;
1562bfe3f2eSlogwang }
1572bfe3f2eSlogwang ret = mlx4_get_ifname(priv, &ifr->ifr_name);
1582bfe3f2eSlogwang if (!ret && ioctl(sock, req, ifr) == -1) {
1592bfe3f2eSlogwang rte_errno = errno;
1602bfe3f2eSlogwang ret = -rte_errno;
1612bfe3f2eSlogwang }
1622bfe3f2eSlogwang close(sock);
1632bfe3f2eSlogwang return ret;
1642bfe3f2eSlogwang }
1652bfe3f2eSlogwang
1662bfe3f2eSlogwang /**
1672bfe3f2eSlogwang * Get MAC address by querying netdevice.
1682bfe3f2eSlogwang *
1692bfe3f2eSlogwang * @param[in] priv
1702bfe3f2eSlogwang * Pointer to private structure.
1712bfe3f2eSlogwang * @param[out] mac
1722bfe3f2eSlogwang * MAC address output buffer.
1732bfe3f2eSlogwang *
1742bfe3f2eSlogwang * @return
1752bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
1762bfe3f2eSlogwang */
1772bfe3f2eSlogwang int
mlx4_get_mac(struct mlx4_priv * priv,uint8_t (* mac)[RTE_ETHER_ADDR_LEN])1784418919fSjohnjiang mlx4_get_mac(struct mlx4_priv *priv, uint8_t (*mac)[RTE_ETHER_ADDR_LEN])
1792bfe3f2eSlogwang {
1802bfe3f2eSlogwang struct ifreq request;
1812bfe3f2eSlogwang int ret = mlx4_ifreq(priv, SIOCGIFHWADDR, &request);
1822bfe3f2eSlogwang
1832bfe3f2eSlogwang if (ret)
1842bfe3f2eSlogwang return ret;
1854418919fSjohnjiang memcpy(mac, request.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
1862bfe3f2eSlogwang return 0;
1872bfe3f2eSlogwang }
1882bfe3f2eSlogwang
1892bfe3f2eSlogwang /**
1902bfe3f2eSlogwang * Get device MTU.
1912bfe3f2eSlogwang *
1922bfe3f2eSlogwang * @param priv
1932bfe3f2eSlogwang * Pointer to private structure.
1942bfe3f2eSlogwang * @param[out] mtu
1952bfe3f2eSlogwang * MTU value output buffer.
1962bfe3f2eSlogwang *
1972bfe3f2eSlogwang * @return
1982bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
1992bfe3f2eSlogwang */
2002bfe3f2eSlogwang int
mlx4_mtu_get(struct mlx4_priv * priv,uint16_t * mtu)2011646932aSjfb8856606 mlx4_mtu_get(struct mlx4_priv *priv, uint16_t *mtu)
2022bfe3f2eSlogwang {
203579bf1e2Sjfb8856606 struct ifreq request;
204579bf1e2Sjfb8856606 int ret = mlx4_ifreq(priv, SIOCGIFMTU, &request);
2052bfe3f2eSlogwang
2062bfe3f2eSlogwang if (ret)
2072bfe3f2eSlogwang return ret;
208579bf1e2Sjfb8856606 *mtu = request.ifr_mtu;
2092bfe3f2eSlogwang return 0;
2102bfe3f2eSlogwang }
2112bfe3f2eSlogwang
2122bfe3f2eSlogwang /**
2132bfe3f2eSlogwang * DPDK callback to change the MTU.
2142bfe3f2eSlogwang *
2152bfe3f2eSlogwang * @param priv
2162bfe3f2eSlogwang * Pointer to Ethernet device structure.
2172bfe3f2eSlogwang * @param mtu
2182bfe3f2eSlogwang * MTU value to set.
2192bfe3f2eSlogwang *
2202bfe3f2eSlogwang * @return
2212bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
2222bfe3f2eSlogwang */
2232bfe3f2eSlogwang int
mlx4_mtu_set(struct rte_eth_dev * dev,uint16_t mtu)2242bfe3f2eSlogwang mlx4_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
2252bfe3f2eSlogwang {
2261646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
227579bf1e2Sjfb8856606 struct ifreq request = { .ifr_mtu = mtu, };
228579bf1e2Sjfb8856606 int ret = mlx4_ifreq(priv, SIOCSIFMTU, &request);
2292bfe3f2eSlogwang
2302bfe3f2eSlogwang if (ret)
2312bfe3f2eSlogwang return ret;
2322bfe3f2eSlogwang priv->mtu = mtu;
2332bfe3f2eSlogwang return 0;
2342bfe3f2eSlogwang }
2352bfe3f2eSlogwang
2362bfe3f2eSlogwang /**
2372bfe3f2eSlogwang * Set device flags.
2382bfe3f2eSlogwang *
2392bfe3f2eSlogwang * @param priv
2402bfe3f2eSlogwang * Pointer to private structure.
2412bfe3f2eSlogwang * @param keep
2422bfe3f2eSlogwang * Bitmask for flags that must remain untouched.
2432bfe3f2eSlogwang * @param flags
2442bfe3f2eSlogwang * Bitmask for flags to modify.
2452bfe3f2eSlogwang *
2462bfe3f2eSlogwang * @return
2472bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
2482bfe3f2eSlogwang */
2492bfe3f2eSlogwang static int
mlx4_set_flags(struct mlx4_priv * priv,unsigned int keep,unsigned int flags)2501646932aSjfb8856606 mlx4_set_flags(struct mlx4_priv *priv, unsigned int keep, unsigned int flags)
2512bfe3f2eSlogwang {
252579bf1e2Sjfb8856606 struct ifreq request;
253579bf1e2Sjfb8856606 int ret = mlx4_ifreq(priv, SIOCGIFFLAGS, &request);
2542bfe3f2eSlogwang
2552bfe3f2eSlogwang if (ret)
2562bfe3f2eSlogwang return ret;
257579bf1e2Sjfb8856606 request.ifr_flags &= keep;
258579bf1e2Sjfb8856606 request.ifr_flags |= flags & ~keep;
259579bf1e2Sjfb8856606 return mlx4_ifreq(priv, SIOCSIFFLAGS, &request);
2602bfe3f2eSlogwang }
2612bfe3f2eSlogwang
2622bfe3f2eSlogwang /**
2632bfe3f2eSlogwang * Change the link state (UP / DOWN).
2642bfe3f2eSlogwang *
2652bfe3f2eSlogwang * @param priv
2662bfe3f2eSlogwang * Pointer to Ethernet device private data.
2672bfe3f2eSlogwang * @param up
2682bfe3f2eSlogwang * Nonzero for link up, otherwise link down.
2692bfe3f2eSlogwang *
2702bfe3f2eSlogwang * @return
2712bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
2722bfe3f2eSlogwang */
2732bfe3f2eSlogwang static int
mlx4_dev_set_link(struct mlx4_priv * priv,int up)2741646932aSjfb8856606 mlx4_dev_set_link(struct mlx4_priv *priv, int up)
2752bfe3f2eSlogwang {
2762bfe3f2eSlogwang int err;
2772bfe3f2eSlogwang
2782bfe3f2eSlogwang if (up) {
2792bfe3f2eSlogwang err = mlx4_set_flags(priv, ~IFF_UP, IFF_UP);
2802bfe3f2eSlogwang if (err)
2812bfe3f2eSlogwang return err;
2822bfe3f2eSlogwang } else {
2832bfe3f2eSlogwang err = mlx4_set_flags(priv, ~IFF_UP, ~IFF_UP);
2842bfe3f2eSlogwang if (err)
2852bfe3f2eSlogwang return err;
2862bfe3f2eSlogwang }
2872bfe3f2eSlogwang return 0;
2882bfe3f2eSlogwang }
2892bfe3f2eSlogwang
2902bfe3f2eSlogwang /**
2912bfe3f2eSlogwang * DPDK callback to bring the link DOWN.
2922bfe3f2eSlogwang *
2932bfe3f2eSlogwang * @param dev
2942bfe3f2eSlogwang * Pointer to Ethernet device structure.
2952bfe3f2eSlogwang *
2962bfe3f2eSlogwang * @return
2972bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
2982bfe3f2eSlogwang */
2992bfe3f2eSlogwang int
mlx4_dev_set_link_down(struct rte_eth_dev * dev)3002bfe3f2eSlogwang mlx4_dev_set_link_down(struct rte_eth_dev *dev)
3012bfe3f2eSlogwang {
3021646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
3032bfe3f2eSlogwang
3042bfe3f2eSlogwang return mlx4_dev_set_link(priv, 0);
3052bfe3f2eSlogwang }
3062bfe3f2eSlogwang
3072bfe3f2eSlogwang /**
3082bfe3f2eSlogwang * DPDK callback to bring the link UP.
3092bfe3f2eSlogwang *
3102bfe3f2eSlogwang * @param dev
3112bfe3f2eSlogwang * Pointer to Ethernet device structure.
3122bfe3f2eSlogwang *
3132bfe3f2eSlogwang * @return
3142bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
3152bfe3f2eSlogwang */
3162bfe3f2eSlogwang int
mlx4_dev_set_link_up(struct rte_eth_dev * dev)3172bfe3f2eSlogwang mlx4_dev_set_link_up(struct rte_eth_dev *dev)
3182bfe3f2eSlogwang {
3191646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
3202bfe3f2eSlogwang
3212bfe3f2eSlogwang return mlx4_dev_set_link(priv, 1);
3222bfe3f2eSlogwang }
3232bfe3f2eSlogwang
3242bfe3f2eSlogwang /**
3252bfe3f2eSlogwang * Supported Rx mode toggles.
3262bfe3f2eSlogwang *
3272bfe3f2eSlogwang * Even and odd values respectively stand for off and on.
3282bfe3f2eSlogwang */
3292bfe3f2eSlogwang enum rxmode_toggle {
3302bfe3f2eSlogwang RXMODE_TOGGLE_PROMISC_OFF,
3312bfe3f2eSlogwang RXMODE_TOGGLE_PROMISC_ON,
3322bfe3f2eSlogwang RXMODE_TOGGLE_ALLMULTI_OFF,
3332bfe3f2eSlogwang RXMODE_TOGGLE_ALLMULTI_ON,
3342bfe3f2eSlogwang };
3352bfe3f2eSlogwang
3362bfe3f2eSlogwang /**
3372bfe3f2eSlogwang * Helper function to toggle promiscuous and all multicast modes.
3382bfe3f2eSlogwang *
3392bfe3f2eSlogwang * @param dev
3402bfe3f2eSlogwang * Pointer to Ethernet device structure.
3412bfe3f2eSlogwang * @param toggle
3422bfe3f2eSlogwang * Toggle to set.
3434418919fSjohnjiang *
3444418919fSjohnjiang * @return
3454418919fSjohnjiang * 0 on success, a negative errno value otherwise and rte_errno is set.
3462bfe3f2eSlogwang */
3474418919fSjohnjiang static int
mlx4_rxmode_toggle(struct rte_eth_dev * dev,enum rxmode_toggle toggle)3482bfe3f2eSlogwang mlx4_rxmode_toggle(struct rte_eth_dev *dev, enum rxmode_toggle toggle)
3492bfe3f2eSlogwang {
3501646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
3512bfe3f2eSlogwang const char *mode;
3522bfe3f2eSlogwang struct rte_flow_error error;
3534418919fSjohnjiang int ret;
3542bfe3f2eSlogwang
3552bfe3f2eSlogwang switch (toggle) {
3562bfe3f2eSlogwang case RXMODE_TOGGLE_PROMISC_OFF:
3572bfe3f2eSlogwang case RXMODE_TOGGLE_PROMISC_ON:
3582bfe3f2eSlogwang mode = "promiscuous";
3592bfe3f2eSlogwang dev->data->promiscuous = toggle & 1;
3602bfe3f2eSlogwang break;
3612bfe3f2eSlogwang case RXMODE_TOGGLE_ALLMULTI_OFF:
3622bfe3f2eSlogwang case RXMODE_TOGGLE_ALLMULTI_ON:
3632bfe3f2eSlogwang mode = "all multicast";
3642bfe3f2eSlogwang dev->data->all_multicast = toggle & 1;
3652bfe3f2eSlogwang break;
366d30ea906Sjfb8856606 default:
367d30ea906Sjfb8856606 mode = "undefined";
3682bfe3f2eSlogwang }
3694418919fSjohnjiang
3704418919fSjohnjiang ret = mlx4_flow_sync(priv, &error);
3714418919fSjohnjiang if (!ret)
3724418919fSjohnjiang return 0;
3734418919fSjohnjiang
3742bfe3f2eSlogwang ERROR("cannot toggle %s mode (code %d, \"%s\"),"
3752bfe3f2eSlogwang " flow error type %d, cause %p, message: %s",
3762bfe3f2eSlogwang mode, rte_errno, strerror(rte_errno), error.type, error.cause,
3772bfe3f2eSlogwang error.message ? error.message : "(unspecified)");
3784418919fSjohnjiang return ret;
3792bfe3f2eSlogwang }
3802bfe3f2eSlogwang
3812bfe3f2eSlogwang /**
3822bfe3f2eSlogwang * DPDK callback to enable promiscuous mode.
3832bfe3f2eSlogwang *
3842bfe3f2eSlogwang * @param dev
3852bfe3f2eSlogwang * Pointer to Ethernet device structure.
3864418919fSjohnjiang *
3874418919fSjohnjiang * @return
3884418919fSjohnjiang * 0 on success, a negative errno value otherwise and rte_errno is set.
3892bfe3f2eSlogwang */
3904418919fSjohnjiang int
mlx4_promiscuous_enable(struct rte_eth_dev * dev)3912bfe3f2eSlogwang mlx4_promiscuous_enable(struct rte_eth_dev *dev)
3922bfe3f2eSlogwang {
3934418919fSjohnjiang return mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_ON);
3942bfe3f2eSlogwang }
3952bfe3f2eSlogwang
3962bfe3f2eSlogwang /**
3972bfe3f2eSlogwang * DPDK callback to disable promiscuous mode.
3982bfe3f2eSlogwang *
3992bfe3f2eSlogwang * @param dev
4002bfe3f2eSlogwang * Pointer to Ethernet device structure.
4014418919fSjohnjiang *
4024418919fSjohnjiang * @return
4034418919fSjohnjiang * 0 on success, a negative errno value otherwise and rte_errno is set.
4042bfe3f2eSlogwang */
4054418919fSjohnjiang int
mlx4_promiscuous_disable(struct rte_eth_dev * dev)4062bfe3f2eSlogwang mlx4_promiscuous_disable(struct rte_eth_dev *dev)
4072bfe3f2eSlogwang {
4084418919fSjohnjiang return mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_OFF);
4092bfe3f2eSlogwang }
4102bfe3f2eSlogwang
4112bfe3f2eSlogwang /**
4122bfe3f2eSlogwang * DPDK callback to enable all multicast mode.
4132bfe3f2eSlogwang *
4142bfe3f2eSlogwang * @param dev
4152bfe3f2eSlogwang * Pointer to Ethernet device structure.
4164418919fSjohnjiang *
4174418919fSjohnjiang * @return
4184418919fSjohnjiang * 0 on success, a negative errno value otherwise and rte_errno is set.
4192bfe3f2eSlogwang */
4204418919fSjohnjiang int
mlx4_allmulticast_enable(struct rte_eth_dev * dev)4212bfe3f2eSlogwang mlx4_allmulticast_enable(struct rte_eth_dev *dev)
4222bfe3f2eSlogwang {
4234418919fSjohnjiang return mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_ON);
4242bfe3f2eSlogwang }
4252bfe3f2eSlogwang
4262bfe3f2eSlogwang /**
4272bfe3f2eSlogwang * DPDK callback to disable all multicast mode.
4282bfe3f2eSlogwang *
4292bfe3f2eSlogwang * @param dev
4302bfe3f2eSlogwang * Pointer to Ethernet device structure.
4314418919fSjohnjiang *
4324418919fSjohnjiang * @return
4334418919fSjohnjiang * 0 on success, a negative errno value otherwise and rte_errno is set.
4342bfe3f2eSlogwang */
4354418919fSjohnjiang int
mlx4_allmulticast_disable(struct rte_eth_dev * dev)4362bfe3f2eSlogwang mlx4_allmulticast_disable(struct rte_eth_dev *dev)
4372bfe3f2eSlogwang {
4384418919fSjohnjiang return mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_OFF);
4392bfe3f2eSlogwang }
4402bfe3f2eSlogwang
4412bfe3f2eSlogwang /**
4422bfe3f2eSlogwang * DPDK callback to remove a MAC address.
4432bfe3f2eSlogwang *
4442bfe3f2eSlogwang * @param dev
4452bfe3f2eSlogwang * Pointer to Ethernet device structure.
4462bfe3f2eSlogwang * @param index
4472bfe3f2eSlogwang * MAC address index.
4482bfe3f2eSlogwang */
4492bfe3f2eSlogwang void
mlx4_mac_addr_remove(struct rte_eth_dev * dev,uint32_t index)4502bfe3f2eSlogwang mlx4_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
4512bfe3f2eSlogwang {
4521646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
4532bfe3f2eSlogwang struct rte_flow_error error;
4542bfe3f2eSlogwang
4554418919fSjohnjiang if (index >= RTE_DIM(priv->mac) - priv->mac_mc) {
4562bfe3f2eSlogwang rte_errno = EINVAL;
4572bfe3f2eSlogwang return;
4582bfe3f2eSlogwang }
4592bfe3f2eSlogwang memset(&priv->mac[index], 0, sizeof(priv->mac[index]));
4602bfe3f2eSlogwang if (!mlx4_flow_sync(priv, &error))
4612bfe3f2eSlogwang return;
4622bfe3f2eSlogwang ERROR("failed to synchronize flow rules after removing MAC address"
4632bfe3f2eSlogwang " at index %d (code %d, \"%s\"),"
4642bfe3f2eSlogwang " flow error type %d, cause %p, message: %s",
4652bfe3f2eSlogwang index, rte_errno, strerror(rte_errno), error.type, error.cause,
4662bfe3f2eSlogwang error.message ? error.message : "(unspecified)");
4672bfe3f2eSlogwang }
4682bfe3f2eSlogwang
4692bfe3f2eSlogwang /**
4702bfe3f2eSlogwang * DPDK callback to add a MAC address.
4712bfe3f2eSlogwang *
4722bfe3f2eSlogwang * @param dev
4732bfe3f2eSlogwang * Pointer to Ethernet device structure.
4742bfe3f2eSlogwang * @param mac_addr
4752bfe3f2eSlogwang * MAC address to register.
4762bfe3f2eSlogwang * @param index
4772bfe3f2eSlogwang * MAC address index.
4782bfe3f2eSlogwang * @param vmdq
4792bfe3f2eSlogwang * VMDq pool index to associate address with (ignored).
4802bfe3f2eSlogwang *
4812bfe3f2eSlogwang * @return
4822bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
4832bfe3f2eSlogwang */
4842bfe3f2eSlogwang int
mlx4_mac_addr_add(struct rte_eth_dev * dev,struct rte_ether_addr * mac_addr,uint32_t index,uint32_t vmdq)4854418919fSjohnjiang mlx4_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
4862bfe3f2eSlogwang uint32_t index, uint32_t vmdq)
4872bfe3f2eSlogwang {
4881646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
4892bfe3f2eSlogwang struct rte_flow_error error;
4902bfe3f2eSlogwang int ret;
4912bfe3f2eSlogwang
4922bfe3f2eSlogwang (void)vmdq;
4934418919fSjohnjiang if (index >= RTE_DIM(priv->mac) - priv->mac_mc) {
4942bfe3f2eSlogwang rte_errno = EINVAL;
4952bfe3f2eSlogwang return -rte_errno;
4962bfe3f2eSlogwang }
4972bfe3f2eSlogwang memcpy(&priv->mac[index], mac_addr, sizeof(priv->mac[index]));
4982bfe3f2eSlogwang ret = mlx4_flow_sync(priv, &error);
4992bfe3f2eSlogwang if (!ret)
5002bfe3f2eSlogwang return 0;
5012bfe3f2eSlogwang ERROR("failed to synchronize flow rules after adding MAC address"
5022bfe3f2eSlogwang " at index %d (code %d, \"%s\"),"
5032bfe3f2eSlogwang " flow error type %d, cause %p, message: %s",
5042bfe3f2eSlogwang index, rte_errno, strerror(rte_errno), error.type, error.cause,
5052bfe3f2eSlogwang error.message ? error.message : "(unspecified)");
5062bfe3f2eSlogwang return ret;
5072bfe3f2eSlogwang }
5082bfe3f2eSlogwang
5092bfe3f2eSlogwang /**
5104418919fSjohnjiang * DPDK callback to configure multicast addresses.
5114418919fSjohnjiang *
5124418919fSjohnjiang * @param dev
5134418919fSjohnjiang * Pointer to Ethernet device structure.
5144418919fSjohnjiang * @param list
5154418919fSjohnjiang * List of MAC addresses to register.
5164418919fSjohnjiang * @param num
5174418919fSjohnjiang * Number of entries in list.
5184418919fSjohnjiang *
5194418919fSjohnjiang * @return
5204418919fSjohnjiang * 0 on success, negative errno value otherwise and rte_errno is set.
5214418919fSjohnjiang */
5224418919fSjohnjiang int
mlx4_set_mc_addr_list(struct rte_eth_dev * dev,struct rte_ether_addr * list,uint32_t num)5234418919fSjohnjiang mlx4_set_mc_addr_list(struct rte_eth_dev *dev, struct rte_ether_addr *list,
5244418919fSjohnjiang uint32_t num)
5254418919fSjohnjiang {
5264418919fSjohnjiang struct mlx4_priv *priv = dev->data->dev_private;
5274418919fSjohnjiang struct rte_flow_error error;
5284418919fSjohnjiang int ret;
5294418919fSjohnjiang
5304418919fSjohnjiang if (num > RTE_DIM(priv->mac)) {
5314418919fSjohnjiang rte_errno = EINVAL;
5324418919fSjohnjiang return -rte_errno;
5334418919fSjohnjiang }
5344418919fSjohnjiang /*
5354418919fSjohnjiang * Make sure there is enough room to increase the number of
5364418919fSjohnjiang * multicast entries without overwriting standard entries.
5374418919fSjohnjiang */
5384418919fSjohnjiang if (num > priv->mac_mc) {
5394418919fSjohnjiang unsigned int i;
5404418919fSjohnjiang
5414418919fSjohnjiang for (i = RTE_DIM(priv->mac) - num;
5424418919fSjohnjiang i != RTE_DIM(priv->mac) - priv->mac_mc;
5434418919fSjohnjiang ++i)
5444418919fSjohnjiang if (!rte_is_zero_ether_addr(&priv->mac[i])) {
5454418919fSjohnjiang rte_errno = EBUSY;
5464418919fSjohnjiang return -rte_errno;
5474418919fSjohnjiang }
5484418919fSjohnjiang } else if (num < priv->mac_mc) {
5494418919fSjohnjiang /* Clear unused entries. */
5504418919fSjohnjiang memset(priv->mac + RTE_DIM(priv->mac) - priv->mac_mc,
5514418919fSjohnjiang 0,
5524418919fSjohnjiang sizeof(priv->mac[0]) * (priv->mac_mc - num));
5534418919fSjohnjiang }
5544418919fSjohnjiang memcpy(priv->mac + RTE_DIM(priv->mac) - num, list, sizeof(*list) * num);
5554418919fSjohnjiang priv->mac_mc = num;
5564418919fSjohnjiang ret = mlx4_flow_sync(priv, &error);
5574418919fSjohnjiang if (!ret)
5584418919fSjohnjiang return 0;
5594418919fSjohnjiang ERROR("failed to synchronize flow rules after modifying MC list,"
5604418919fSjohnjiang " (code %d, \"%s\"), flow error type %d, cause %p, message: %s",
5614418919fSjohnjiang rte_errno, strerror(rte_errno), error.type, error.cause,
5624418919fSjohnjiang error.message ? error.message : "(unspecified)");
5634418919fSjohnjiang return ret;
5644418919fSjohnjiang }
5654418919fSjohnjiang
5664418919fSjohnjiang /**
5672bfe3f2eSlogwang * DPDK callback to configure a VLAN filter.
5682bfe3f2eSlogwang *
5692bfe3f2eSlogwang * @param dev
5702bfe3f2eSlogwang * Pointer to Ethernet device structure.
5712bfe3f2eSlogwang * @param vlan_id
5722bfe3f2eSlogwang * VLAN ID to filter.
5732bfe3f2eSlogwang * @param on
5742bfe3f2eSlogwang * Toggle filter.
5752bfe3f2eSlogwang *
5762bfe3f2eSlogwang * @return
5772bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
5782bfe3f2eSlogwang */
5792bfe3f2eSlogwang int
mlx4_vlan_filter_set(struct rte_eth_dev * dev,uint16_t vlan_id,int on)5802bfe3f2eSlogwang mlx4_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
5812bfe3f2eSlogwang {
5821646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
5832bfe3f2eSlogwang struct rte_flow_error error;
5842bfe3f2eSlogwang unsigned int vidx = vlan_id / 64;
5852bfe3f2eSlogwang unsigned int vbit = vlan_id % 64;
5862bfe3f2eSlogwang uint64_t *v;
5872bfe3f2eSlogwang int ret;
5882bfe3f2eSlogwang
5892bfe3f2eSlogwang if (vidx >= RTE_DIM(dev->data->vlan_filter_conf.ids)) {
5902bfe3f2eSlogwang rte_errno = EINVAL;
5912bfe3f2eSlogwang return -rte_errno;
5922bfe3f2eSlogwang }
5932bfe3f2eSlogwang v = &dev->data->vlan_filter_conf.ids[vidx];
5942bfe3f2eSlogwang *v &= ~(UINT64_C(1) << vbit);
5952bfe3f2eSlogwang *v |= (uint64_t)!!on << vbit;
5962bfe3f2eSlogwang ret = mlx4_flow_sync(priv, &error);
5972bfe3f2eSlogwang if (!ret)
5982bfe3f2eSlogwang return 0;
5992bfe3f2eSlogwang ERROR("failed to synchronize flow rules after %s VLAN filter on ID %u"
6002bfe3f2eSlogwang " (code %d, \"%s\"), "
6012bfe3f2eSlogwang " flow error type %d, cause %p, message: %s",
6022bfe3f2eSlogwang on ? "enabling" : "disabling", vlan_id,
6032bfe3f2eSlogwang rte_errno, strerror(rte_errno), error.type, error.cause,
6042bfe3f2eSlogwang error.message ? error.message : "(unspecified)");
6052bfe3f2eSlogwang return ret;
6062bfe3f2eSlogwang }
6072bfe3f2eSlogwang
6082bfe3f2eSlogwang /**
6092bfe3f2eSlogwang * DPDK callback to set the primary MAC address.
6102bfe3f2eSlogwang *
6112bfe3f2eSlogwang * @param dev
6122bfe3f2eSlogwang * Pointer to Ethernet device structure.
6132bfe3f2eSlogwang * @param mac_addr
6142bfe3f2eSlogwang * MAC address to register.
615d30ea906Sjfb8856606 *
616d30ea906Sjfb8856606 * @return
617d30ea906Sjfb8856606 * 0 on success, negative errno value otherwise and rte_errno is set.
6182bfe3f2eSlogwang */
619d30ea906Sjfb8856606 int
mlx4_mac_addr_set(struct rte_eth_dev * dev,struct rte_ether_addr * mac_addr)6204418919fSjohnjiang mlx4_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
6212bfe3f2eSlogwang {
622d30ea906Sjfb8856606 return mlx4_mac_addr_add(dev, mac_addr, 0, 0);
6232bfe3f2eSlogwang }
6242bfe3f2eSlogwang
6252bfe3f2eSlogwang /**
6262bfe3f2eSlogwang * DPDK callback to get information about the device.
6272bfe3f2eSlogwang *
6282bfe3f2eSlogwang * @param dev
6292bfe3f2eSlogwang * Pointer to Ethernet device structure.
6302bfe3f2eSlogwang * @param[out] info
6312bfe3f2eSlogwang * Info structure output buffer.
6322bfe3f2eSlogwang */
6334418919fSjohnjiang int
mlx4_dev_infos_get(struct rte_eth_dev * dev,struct rte_eth_dev_info * info)6342bfe3f2eSlogwang mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
6352bfe3f2eSlogwang {
6361646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
6372bfe3f2eSlogwang unsigned int max;
6382bfe3f2eSlogwang
6392bfe3f2eSlogwang /* FIXME: we should ask the device for these values. */
6402bfe3f2eSlogwang info->min_rx_bufsize = 32;
6412bfe3f2eSlogwang info->max_rx_pktlen = 65536;
6422bfe3f2eSlogwang /*
6432bfe3f2eSlogwang * Since we need one CQ per QP, the limit is the minimum number
6442bfe3f2eSlogwang * between the two values.
6452bfe3f2eSlogwang */
6462bfe3f2eSlogwang max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ?
6472bfe3f2eSlogwang priv->device_attr.max_qp : priv->device_attr.max_cq);
648*2d9fd380Sjfb8856606 /* max_rx_queues is uint16_t. */
649*2d9fd380Sjfb8856606 max = RTE_MIN(max, (unsigned int)UINT16_MAX);
6502bfe3f2eSlogwang info->max_rx_queues = max;
6512bfe3f2eSlogwang info->max_tx_queues = max;
6522bfe3f2eSlogwang info->max_mac_addrs = RTE_DIM(priv->mac);
653d30ea906Sjfb8856606 info->tx_offload_capa = mlx4_get_tx_port_offloads(priv);
654d30ea906Sjfb8856606 info->rx_queue_offload_capa = mlx4_get_rx_queue_offloads(priv);
655d30ea906Sjfb8856606 info->rx_offload_capa = (mlx4_get_rx_port_offloads(priv) |
656d30ea906Sjfb8856606 info->rx_queue_offload_capa);
6574b05018fSfengbojiang info->if_index = priv->if_index;
6582bfe3f2eSlogwang info->hash_key_size = MLX4_RSS_HASH_KEY_SIZE;
6592bfe3f2eSlogwang info->speed_capa =
6602bfe3f2eSlogwang ETH_LINK_SPEED_1G |
6612bfe3f2eSlogwang ETH_LINK_SPEED_10G |
6622bfe3f2eSlogwang ETH_LINK_SPEED_20G |
6632bfe3f2eSlogwang ETH_LINK_SPEED_40G |
6642bfe3f2eSlogwang ETH_LINK_SPEED_56G;
665d30ea906Sjfb8856606 info->flow_type_rss_offloads = mlx4_conv_rss_types(priv, 0, 1);
6664418919fSjohnjiang
6674418919fSjohnjiang return 0;
6684418919fSjohnjiang }
6694418919fSjohnjiang
6704418919fSjohnjiang /**
6714418919fSjohnjiang * Get firmware version of a device.
6724418919fSjohnjiang *
6734418919fSjohnjiang * @param dev
6744418919fSjohnjiang * Ethernet device port.
6754418919fSjohnjiang * @param fw_ver
6764418919fSjohnjiang * String output allocated by caller.
6774418919fSjohnjiang * @param fw_size
6784418919fSjohnjiang * Size of the output string, including terminating null byte.
6794418919fSjohnjiang *
6804418919fSjohnjiang * @return
6814418919fSjohnjiang * 0 on success, or the size of the non truncated string if too big.
6824418919fSjohnjiang */
mlx4_fw_version_get(struct rte_eth_dev * dev,char * fw_ver,size_t fw_size)6834418919fSjohnjiang int mlx4_fw_version_get(struct rte_eth_dev *dev, char *fw_ver, size_t fw_size)
6844418919fSjohnjiang {
6854418919fSjohnjiang struct mlx4_priv *priv = dev->data->dev_private;
6864418919fSjohnjiang struct ibv_device_attr *attr = &priv->device_attr;
6874418919fSjohnjiang size_t size = strnlen(attr->fw_ver, sizeof(attr->fw_ver)) + 1;
6884418919fSjohnjiang
6894418919fSjohnjiang if (fw_size < size)
6904418919fSjohnjiang return size;
6914418919fSjohnjiang if (fw_ver != NULL)
6924418919fSjohnjiang strlcpy(fw_ver, attr->fw_ver, fw_size);
6934418919fSjohnjiang return 0;
6942bfe3f2eSlogwang }
6952bfe3f2eSlogwang
6962bfe3f2eSlogwang /**
6972bfe3f2eSlogwang * DPDK callback to get device statistics.
6982bfe3f2eSlogwang *
6992bfe3f2eSlogwang * @param dev
7002bfe3f2eSlogwang * Pointer to Ethernet device structure.
7012bfe3f2eSlogwang * @param[out] stats
7022bfe3f2eSlogwang * Stats structure output buffer.
7032bfe3f2eSlogwang */
7042bfe3f2eSlogwang int
mlx4_stats_get(struct rte_eth_dev * dev,struct rte_eth_stats * stats)7052bfe3f2eSlogwang mlx4_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
7062bfe3f2eSlogwang {
7072bfe3f2eSlogwang struct rte_eth_stats tmp;
7082bfe3f2eSlogwang unsigned int i;
7092bfe3f2eSlogwang unsigned int idx;
7102bfe3f2eSlogwang
7112bfe3f2eSlogwang memset(&tmp, 0, sizeof(tmp));
7122bfe3f2eSlogwang /* Add software counters. */
7132bfe3f2eSlogwang for (i = 0; i != dev->data->nb_rx_queues; ++i) {
7142bfe3f2eSlogwang struct rxq *rxq = dev->data->rx_queues[i];
7152bfe3f2eSlogwang
7162bfe3f2eSlogwang if (rxq == NULL)
7172bfe3f2eSlogwang continue;
7182bfe3f2eSlogwang idx = rxq->stats.idx;
7192bfe3f2eSlogwang if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
7202bfe3f2eSlogwang tmp.q_ipackets[idx] += rxq->stats.ipackets;
7212bfe3f2eSlogwang tmp.q_ibytes[idx] += rxq->stats.ibytes;
7222bfe3f2eSlogwang tmp.q_errors[idx] += (rxq->stats.idropped +
7232bfe3f2eSlogwang rxq->stats.rx_nombuf);
7242bfe3f2eSlogwang }
7252bfe3f2eSlogwang tmp.ipackets += rxq->stats.ipackets;
7262bfe3f2eSlogwang tmp.ibytes += rxq->stats.ibytes;
7272bfe3f2eSlogwang tmp.ierrors += rxq->stats.idropped;
7282bfe3f2eSlogwang tmp.rx_nombuf += rxq->stats.rx_nombuf;
7292bfe3f2eSlogwang }
7302bfe3f2eSlogwang for (i = 0; i != dev->data->nb_tx_queues; ++i) {
7312bfe3f2eSlogwang struct txq *txq = dev->data->tx_queues[i];
7322bfe3f2eSlogwang
7332bfe3f2eSlogwang if (txq == NULL)
7342bfe3f2eSlogwang continue;
7352bfe3f2eSlogwang idx = txq->stats.idx;
7362bfe3f2eSlogwang if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
7372bfe3f2eSlogwang tmp.q_opackets[idx] += txq->stats.opackets;
7382bfe3f2eSlogwang tmp.q_obytes[idx] += txq->stats.obytes;
7392bfe3f2eSlogwang }
7402bfe3f2eSlogwang tmp.opackets += txq->stats.opackets;
7412bfe3f2eSlogwang tmp.obytes += txq->stats.obytes;
7422bfe3f2eSlogwang tmp.oerrors += txq->stats.odropped;
7432bfe3f2eSlogwang }
7442bfe3f2eSlogwang *stats = tmp;
7452bfe3f2eSlogwang return 0;
7462bfe3f2eSlogwang }
7472bfe3f2eSlogwang
7482bfe3f2eSlogwang /**
7492bfe3f2eSlogwang * DPDK callback to clear device statistics.
7502bfe3f2eSlogwang *
7512bfe3f2eSlogwang * @param dev
7522bfe3f2eSlogwang * Pointer to Ethernet device structure.
7534418919fSjohnjiang *
7544418919fSjohnjiang * @return
7554418919fSjohnjiang * alwasy 0 on success
7562bfe3f2eSlogwang */
7574418919fSjohnjiang int
mlx4_stats_reset(struct rte_eth_dev * dev)7582bfe3f2eSlogwang mlx4_stats_reset(struct rte_eth_dev *dev)
7592bfe3f2eSlogwang {
7602bfe3f2eSlogwang unsigned int i;
7612bfe3f2eSlogwang
7622bfe3f2eSlogwang for (i = 0; i != dev->data->nb_rx_queues; ++i) {
7632bfe3f2eSlogwang struct rxq *rxq = dev->data->rx_queues[i];
7642bfe3f2eSlogwang
7652bfe3f2eSlogwang if (rxq)
7662bfe3f2eSlogwang rxq->stats = (struct mlx4_rxq_stats){
7672bfe3f2eSlogwang .idx = rxq->stats.idx,
7682bfe3f2eSlogwang };
7692bfe3f2eSlogwang }
7702bfe3f2eSlogwang for (i = 0; i != dev->data->nb_tx_queues; ++i) {
7712bfe3f2eSlogwang struct txq *txq = dev->data->tx_queues[i];
7722bfe3f2eSlogwang
7732bfe3f2eSlogwang if (txq)
7742bfe3f2eSlogwang txq->stats = (struct mlx4_txq_stats){
7752bfe3f2eSlogwang .idx = txq->stats.idx,
7762bfe3f2eSlogwang };
7772bfe3f2eSlogwang }
7784418919fSjohnjiang
7794418919fSjohnjiang return 0;
7802bfe3f2eSlogwang }
7812bfe3f2eSlogwang
7822bfe3f2eSlogwang /**
7832bfe3f2eSlogwang * DPDK callback to retrieve physical link information.
7842bfe3f2eSlogwang *
7852bfe3f2eSlogwang * @param dev
7862bfe3f2eSlogwang * Pointer to Ethernet device structure.
7872bfe3f2eSlogwang * @param wait_to_complete
7882bfe3f2eSlogwang * Wait for request completion (ignored).
7892bfe3f2eSlogwang *
7902bfe3f2eSlogwang * @return
7912bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
7922bfe3f2eSlogwang */
7932bfe3f2eSlogwang int
mlx4_link_update(struct rte_eth_dev * dev,int wait_to_complete)7942bfe3f2eSlogwang mlx4_link_update(struct rte_eth_dev *dev, int wait_to_complete)
7952bfe3f2eSlogwang {
7961646932aSjfb8856606 const struct mlx4_priv *priv = dev->data->dev_private;
7972bfe3f2eSlogwang struct ethtool_cmd edata = {
7982bfe3f2eSlogwang .cmd = ETHTOOL_GSET,
7992bfe3f2eSlogwang };
8002bfe3f2eSlogwang struct ifreq ifr;
8012bfe3f2eSlogwang struct rte_eth_link dev_link;
8022bfe3f2eSlogwang int link_speed = 0;
8032bfe3f2eSlogwang
8042bfe3f2eSlogwang if (priv == NULL) {
8052bfe3f2eSlogwang rte_errno = EINVAL;
8062bfe3f2eSlogwang return -rte_errno;
8072bfe3f2eSlogwang }
8082bfe3f2eSlogwang (void)wait_to_complete;
8092bfe3f2eSlogwang if (mlx4_ifreq(priv, SIOCGIFFLAGS, &ifr)) {
8102bfe3f2eSlogwang WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(rte_errno));
8112bfe3f2eSlogwang return -rte_errno;
8122bfe3f2eSlogwang }
8132bfe3f2eSlogwang memset(&dev_link, 0, sizeof(dev_link));
8142bfe3f2eSlogwang dev_link.link_status = ((ifr.ifr_flags & IFF_UP) &&
8152bfe3f2eSlogwang (ifr.ifr_flags & IFF_RUNNING));
8162bfe3f2eSlogwang ifr.ifr_data = (void *)&edata;
8172bfe3f2eSlogwang if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) {
8182bfe3f2eSlogwang WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s",
8192bfe3f2eSlogwang strerror(rte_errno));
8202bfe3f2eSlogwang return -rte_errno;
8212bfe3f2eSlogwang }
8222bfe3f2eSlogwang link_speed = ethtool_cmd_speed(&edata);
8232bfe3f2eSlogwang if (link_speed == -1)
824d30ea906Sjfb8856606 dev_link.link_speed = ETH_SPEED_NUM_NONE;
8252bfe3f2eSlogwang else
8262bfe3f2eSlogwang dev_link.link_speed = link_speed;
8272bfe3f2eSlogwang dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ?
8282bfe3f2eSlogwang ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX);
8292bfe3f2eSlogwang dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
8302bfe3f2eSlogwang ETH_LINK_SPEED_FIXED);
8312bfe3f2eSlogwang dev->data->dev_link = dev_link;
8322bfe3f2eSlogwang return 0;
8332bfe3f2eSlogwang }
8342bfe3f2eSlogwang
8352bfe3f2eSlogwang /**
8362bfe3f2eSlogwang * DPDK callback to get flow control status.
8372bfe3f2eSlogwang *
8382bfe3f2eSlogwang * @param dev
8392bfe3f2eSlogwang * Pointer to Ethernet device structure.
8402bfe3f2eSlogwang * @param[out] fc_conf
8412bfe3f2eSlogwang * Flow control output buffer.
8422bfe3f2eSlogwang *
8432bfe3f2eSlogwang * @return
8442bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
8452bfe3f2eSlogwang */
8462bfe3f2eSlogwang int
mlx4_flow_ctrl_get(struct rte_eth_dev * dev,struct rte_eth_fc_conf * fc_conf)8472bfe3f2eSlogwang mlx4_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
8482bfe3f2eSlogwang {
8491646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
8502bfe3f2eSlogwang struct ifreq ifr;
8512bfe3f2eSlogwang struct ethtool_pauseparam ethpause = {
8522bfe3f2eSlogwang .cmd = ETHTOOL_GPAUSEPARAM,
8532bfe3f2eSlogwang };
8542bfe3f2eSlogwang int ret;
8552bfe3f2eSlogwang
8562bfe3f2eSlogwang ifr.ifr_data = (void *)ðpause;
8572bfe3f2eSlogwang if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) {
8582bfe3f2eSlogwang ret = rte_errno;
8592bfe3f2eSlogwang WARN("ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM)"
8602bfe3f2eSlogwang " failed: %s",
8612bfe3f2eSlogwang strerror(rte_errno));
8622bfe3f2eSlogwang goto out;
8632bfe3f2eSlogwang }
8642bfe3f2eSlogwang fc_conf->autoneg = ethpause.autoneg;
8652bfe3f2eSlogwang if (ethpause.rx_pause && ethpause.tx_pause)
8662bfe3f2eSlogwang fc_conf->mode = RTE_FC_FULL;
8672bfe3f2eSlogwang else if (ethpause.rx_pause)
8682bfe3f2eSlogwang fc_conf->mode = RTE_FC_RX_PAUSE;
8692bfe3f2eSlogwang else if (ethpause.tx_pause)
8702bfe3f2eSlogwang fc_conf->mode = RTE_FC_TX_PAUSE;
8712bfe3f2eSlogwang else
8722bfe3f2eSlogwang fc_conf->mode = RTE_FC_NONE;
8732bfe3f2eSlogwang ret = 0;
8742bfe3f2eSlogwang out:
875*2d9fd380Sjfb8856606 MLX4_ASSERT(ret >= 0);
8762bfe3f2eSlogwang return -ret;
8772bfe3f2eSlogwang }
8782bfe3f2eSlogwang
8792bfe3f2eSlogwang /**
8802bfe3f2eSlogwang * DPDK callback to modify flow control parameters.
8812bfe3f2eSlogwang *
8822bfe3f2eSlogwang * @param dev
8832bfe3f2eSlogwang * Pointer to Ethernet device structure.
8842bfe3f2eSlogwang * @param[in] fc_conf
8852bfe3f2eSlogwang * Flow control parameters.
8862bfe3f2eSlogwang *
8872bfe3f2eSlogwang * @return
8882bfe3f2eSlogwang * 0 on success, negative errno value otherwise and rte_errno is set.
8892bfe3f2eSlogwang */
8902bfe3f2eSlogwang int
mlx4_flow_ctrl_set(struct rte_eth_dev * dev,struct rte_eth_fc_conf * fc_conf)8912bfe3f2eSlogwang mlx4_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
8922bfe3f2eSlogwang {
8931646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
8942bfe3f2eSlogwang struct ifreq ifr;
8952bfe3f2eSlogwang struct ethtool_pauseparam ethpause = {
8962bfe3f2eSlogwang .cmd = ETHTOOL_SPAUSEPARAM,
8972bfe3f2eSlogwang };
8982bfe3f2eSlogwang int ret;
8992bfe3f2eSlogwang
9002bfe3f2eSlogwang ifr.ifr_data = (void *)ðpause;
9012bfe3f2eSlogwang ethpause.autoneg = fc_conf->autoneg;
9022bfe3f2eSlogwang if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
9032bfe3f2eSlogwang (fc_conf->mode & RTE_FC_RX_PAUSE))
9042bfe3f2eSlogwang ethpause.rx_pause = 1;
9052bfe3f2eSlogwang else
9062bfe3f2eSlogwang ethpause.rx_pause = 0;
9072bfe3f2eSlogwang if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
9082bfe3f2eSlogwang (fc_conf->mode & RTE_FC_TX_PAUSE))
9092bfe3f2eSlogwang ethpause.tx_pause = 1;
9102bfe3f2eSlogwang else
9112bfe3f2eSlogwang ethpause.tx_pause = 0;
9122bfe3f2eSlogwang if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) {
9132bfe3f2eSlogwang ret = rte_errno;
9142bfe3f2eSlogwang WARN("ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)"
9152bfe3f2eSlogwang " failed: %s",
9162bfe3f2eSlogwang strerror(rte_errno));
9172bfe3f2eSlogwang goto out;
9182bfe3f2eSlogwang }
9192bfe3f2eSlogwang ret = 0;
9202bfe3f2eSlogwang out:
921*2d9fd380Sjfb8856606 MLX4_ASSERT(ret >= 0);
9222bfe3f2eSlogwang return -ret;
9232bfe3f2eSlogwang }
9242bfe3f2eSlogwang
9252bfe3f2eSlogwang /**
9262bfe3f2eSlogwang * DPDK callback to retrieve the received packet types that are recognized
9272bfe3f2eSlogwang * by the device.
9282bfe3f2eSlogwang *
9292bfe3f2eSlogwang * @param dev
9302bfe3f2eSlogwang * Pointer to Ethernet device structure.
9312bfe3f2eSlogwang *
9322bfe3f2eSlogwang * @return
9332bfe3f2eSlogwang * Pointer to an array of recognized packet types if in Rx burst mode,
9342bfe3f2eSlogwang * NULL otherwise.
9352bfe3f2eSlogwang */
9362bfe3f2eSlogwang const uint32_t *
mlx4_dev_supported_ptypes_get(struct rte_eth_dev * dev)9372bfe3f2eSlogwang mlx4_dev_supported_ptypes_get(struct rte_eth_dev *dev)
9382bfe3f2eSlogwang {
9392bfe3f2eSlogwang static const uint32_t ptypes[] = {
9402bfe3f2eSlogwang /* refers to rxq_cq_to_pkt_type() */
9412bfe3f2eSlogwang RTE_PTYPE_L2_ETHER,
9422bfe3f2eSlogwang RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
9432bfe3f2eSlogwang RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
9442bfe3f2eSlogwang RTE_PTYPE_L4_FRAG,
9452bfe3f2eSlogwang RTE_PTYPE_L4_TCP,
9462bfe3f2eSlogwang RTE_PTYPE_L4_UDP,
9472bfe3f2eSlogwang RTE_PTYPE_UNKNOWN
9482bfe3f2eSlogwang };
9492bfe3f2eSlogwang static const uint32_t ptypes_l2tun[] = {
9502bfe3f2eSlogwang /* refers to rxq_cq_to_pkt_type() */
9512bfe3f2eSlogwang RTE_PTYPE_L2_ETHER,
9522bfe3f2eSlogwang RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
9532bfe3f2eSlogwang RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
9542bfe3f2eSlogwang RTE_PTYPE_L4_FRAG,
9552bfe3f2eSlogwang RTE_PTYPE_L4_TCP,
9562bfe3f2eSlogwang RTE_PTYPE_L4_UDP,
9572bfe3f2eSlogwang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
9582bfe3f2eSlogwang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
9592bfe3f2eSlogwang RTE_PTYPE_UNKNOWN
9602bfe3f2eSlogwang };
9611646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
9622bfe3f2eSlogwang
9632bfe3f2eSlogwang if (dev->rx_pkt_burst == mlx4_rx_burst) {
9642bfe3f2eSlogwang if (priv->hw_csum_l2tun)
9652bfe3f2eSlogwang return ptypes_l2tun;
9662bfe3f2eSlogwang else
9672bfe3f2eSlogwang return ptypes;
9682bfe3f2eSlogwang }
9692bfe3f2eSlogwang return NULL;
9702bfe3f2eSlogwang }
971d30ea906Sjfb8856606
972d30ea906Sjfb8856606 /**
973d30ea906Sjfb8856606 * Check if mlx4 device was removed.
974d30ea906Sjfb8856606 *
975d30ea906Sjfb8856606 * @param dev
976d30ea906Sjfb8856606 * Pointer to Ethernet device structure.
977d30ea906Sjfb8856606 *
978d30ea906Sjfb8856606 * @return
979d30ea906Sjfb8856606 * 1 when device is removed, otherwise 0.
980d30ea906Sjfb8856606 */
981d30ea906Sjfb8856606 int
mlx4_is_removed(struct rte_eth_dev * dev)982d30ea906Sjfb8856606 mlx4_is_removed(struct rte_eth_dev *dev)
983d30ea906Sjfb8856606 {
984d30ea906Sjfb8856606 struct ibv_device_attr device_attr;
9851646932aSjfb8856606 struct mlx4_priv *priv = dev->data->dev_private;
986d30ea906Sjfb8856606
987d30ea906Sjfb8856606 if (mlx4_glue->query_device(priv->ctx, &device_attr) == EIO)
988d30ea906Sjfb8856606 return 1;
989d30ea906Sjfb8856606 return 0;
990d30ea906Sjfb8856606 }
991