1771fa900SAdrien Mazarguil /*- 2771fa900SAdrien Mazarguil * BSD LICENSE 3771fa900SAdrien Mazarguil * 4771fa900SAdrien Mazarguil * Copyright 2015 6WIND S.A. 5771fa900SAdrien Mazarguil * Copyright 2015 Mellanox. 6771fa900SAdrien Mazarguil * 7771fa900SAdrien Mazarguil * Redistribution and use in source and binary forms, with or without 8771fa900SAdrien Mazarguil * modification, are permitted provided that the following conditions 9771fa900SAdrien Mazarguil * are met: 10771fa900SAdrien Mazarguil * 11771fa900SAdrien Mazarguil * * Redistributions of source code must retain the above copyright 12771fa900SAdrien Mazarguil * notice, this list of conditions and the following disclaimer. 13771fa900SAdrien Mazarguil * * Redistributions in binary form must reproduce the above copyright 14771fa900SAdrien Mazarguil * notice, this list of conditions and the following disclaimer in 15771fa900SAdrien Mazarguil * the documentation and/or other materials provided with the 16771fa900SAdrien Mazarguil * distribution. 17771fa900SAdrien Mazarguil * * Neither the name of 6WIND S.A. nor the names of its 18771fa900SAdrien Mazarguil * contributors may be used to endorse or promote products derived 19771fa900SAdrien Mazarguil * from this software without specific prior written permission. 20771fa900SAdrien Mazarguil * 21771fa900SAdrien Mazarguil * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22771fa900SAdrien Mazarguil * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23771fa900SAdrien Mazarguil * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24771fa900SAdrien Mazarguil * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25771fa900SAdrien Mazarguil * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26771fa900SAdrien Mazarguil * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27771fa900SAdrien Mazarguil * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28771fa900SAdrien Mazarguil * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29771fa900SAdrien Mazarguil * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30771fa900SAdrien Mazarguil * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31771fa900SAdrien Mazarguil * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32771fa900SAdrien Mazarguil */ 33771fa900SAdrien Mazarguil 34771fa900SAdrien Mazarguil #include <stddef.h> 35e60fbd5bSAdrien Mazarguil #include <assert.h> 36771fa900SAdrien Mazarguil #include <unistd.h> 37771fa900SAdrien Mazarguil #include <stdint.h> 38771fa900SAdrien Mazarguil #include <stdio.h> 39771fa900SAdrien Mazarguil #include <string.h> 40771fa900SAdrien Mazarguil #include <stdlib.h> 41771fa900SAdrien Mazarguil #include <errno.h> 42771fa900SAdrien Mazarguil #include <dirent.h> 43771fa900SAdrien Mazarguil #include <net/if.h> 44771fa900SAdrien Mazarguil #include <sys/ioctl.h> 45771fa900SAdrien Mazarguil #include <sys/socket.h> 46771fa900SAdrien Mazarguil #include <netinet/in.h> 47771fa900SAdrien Mazarguil #include <linux/if.h> 48771fa900SAdrien Mazarguil 49771fa900SAdrien Mazarguil /* DPDK headers don't like -pedantic. */ 50771fa900SAdrien Mazarguil #ifdef PEDANTIC 51771fa900SAdrien Mazarguil #pragma GCC diagnostic ignored "-pedantic" 52771fa900SAdrien Mazarguil #endif 53771fa900SAdrien Mazarguil #include <rte_atomic.h> 54771fa900SAdrien Mazarguil #include <rte_ethdev.h> 55771fa900SAdrien Mazarguil #include <rte_mbuf.h> 56771fa900SAdrien Mazarguil #include <rte_common.h> 57771fa900SAdrien Mazarguil #ifdef PEDANTIC 58771fa900SAdrien Mazarguil #pragma GCC diagnostic error "-pedantic" 59771fa900SAdrien Mazarguil #endif 60771fa900SAdrien Mazarguil 61771fa900SAdrien Mazarguil #include "mlx5.h" 62e60fbd5bSAdrien Mazarguil #include "mlx5_rxtx.h" 63771fa900SAdrien Mazarguil #include "mlx5_utils.h" 64771fa900SAdrien Mazarguil 65771fa900SAdrien Mazarguil /** 66771fa900SAdrien Mazarguil * Get interface name from private structure. 67771fa900SAdrien Mazarguil * 68771fa900SAdrien Mazarguil * @param[in] priv 69771fa900SAdrien Mazarguil * Pointer to private structure. 70771fa900SAdrien Mazarguil * @param[out] ifname 71771fa900SAdrien Mazarguil * Interface name output buffer. 72771fa900SAdrien Mazarguil * 73771fa900SAdrien Mazarguil * @return 74771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 75771fa900SAdrien Mazarguil */ 76771fa900SAdrien Mazarguil int 77771fa900SAdrien Mazarguil priv_get_ifname(const struct priv *priv, char (*ifname)[IF_NAMESIZE]) 78771fa900SAdrien Mazarguil { 79771fa900SAdrien Mazarguil DIR *dir; 80771fa900SAdrien Mazarguil struct dirent *dent; 81771fa900SAdrien Mazarguil unsigned int dev_type = 0; 82771fa900SAdrien Mazarguil unsigned int dev_port_prev = ~0u; 83771fa900SAdrien Mazarguil char match[IF_NAMESIZE] = ""; 84771fa900SAdrien Mazarguil 85771fa900SAdrien Mazarguil { 86771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net", priv->ctx->device->ibdev_path); 87771fa900SAdrien Mazarguil 88771fa900SAdrien Mazarguil dir = opendir(path); 89771fa900SAdrien Mazarguil if (dir == NULL) 90771fa900SAdrien Mazarguil return -1; 91771fa900SAdrien Mazarguil } 92771fa900SAdrien Mazarguil while ((dent = readdir(dir)) != NULL) { 93771fa900SAdrien Mazarguil char *name = dent->d_name; 94771fa900SAdrien Mazarguil FILE *file; 95771fa900SAdrien Mazarguil unsigned int dev_port; 96771fa900SAdrien Mazarguil int r; 97771fa900SAdrien Mazarguil 98771fa900SAdrien Mazarguil if ((name[0] == '.') && 99771fa900SAdrien Mazarguil ((name[1] == '\0') || 100771fa900SAdrien Mazarguil ((name[1] == '.') && (name[2] == '\0')))) 101771fa900SAdrien Mazarguil continue; 102771fa900SAdrien Mazarguil 103771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net/%s/%s", 104771fa900SAdrien Mazarguil priv->ctx->device->ibdev_path, name, 105771fa900SAdrien Mazarguil (dev_type ? "dev_id" : "dev_port")); 106771fa900SAdrien Mazarguil 107771fa900SAdrien Mazarguil file = fopen(path, "rb"); 108771fa900SAdrien Mazarguil if (file == NULL) { 109771fa900SAdrien Mazarguil if (errno != ENOENT) 110771fa900SAdrien Mazarguil continue; 111771fa900SAdrien Mazarguil /* 112771fa900SAdrien Mazarguil * Switch to dev_id when dev_port does not exist as 113771fa900SAdrien Mazarguil * is the case with Linux kernel versions < 3.15. 114771fa900SAdrien Mazarguil */ 115771fa900SAdrien Mazarguil try_dev_id: 116771fa900SAdrien Mazarguil match[0] = '\0'; 117771fa900SAdrien Mazarguil if (dev_type) 118771fa900SAdrien Mazarguil break; 119771fa900SAdrien Mazarguil dev_type = 1; 120771fa900SAdrien Mazarguil dev_port_prev = ~0u; 121771fa900SAdrien Mazarguil rewinddir(dir); 122771fa900SAdrien Mazarguil continue; 123771fa900SAdrien Mazarguil } 124771fa900SAdrien Mazarguil r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port); 125771fa900SAdrien Mazarguil fclose(file); 126771fa900SAdrien Mazarguil if (r != 1) 127771fa900SAdrien Mazarguil continue; 128771fa900SAdrien Mazarguil /* 129771fa900SAdrien Mazarguil * Switch to dev_id when dev_port returns the same value for 130771fa900SAdrien Mazarguil * all ports. May happen when using a MOFED release older than 131771fa900SAdrien Mazarguil * 3.0 with a Linux kernel >= 3.15. 132771fa900SAdrien Mazarguil */ 133771fa900SAdrien Mazarguil if (dev_port == dev_port_prev) 134771fa900SAdrien Mazarguil goto try_dev_id; 135771fa900SAdrien Mazarguil dev_port_prev = dev_port; 136771fa900SAdrien Mazarguil if (dev_port == (priv->port - 1u)) 137771fa900SAdrien Mazarguil snprintf(match, sizeof(match), "%s", name); 138771fa900SAdrien Mazarguil } 139771fa900SAdrien Mazarguil closedir(dir); 140771fa900SAdrien Mazarguil if (match[0] == '\0') 141771fa900SAdrien Mazarguil return -1; 142771fa900SAdrien Mazarguil strncpy(*ifname, match, sizeof(*ifname)); 143771fa900SAdrien Mazarguil return 0; 144771fa900SAdrien Mazarguil } 145771fa900SAdrien Mazarguil 146771fa900SAdrien Mazarguil /** 147771fa900SAdrien Mazarguil * Read from sysfs entry. 148771fa900SAdrien Mazarguil * 149771fa900SAdrien Mazarguil * @param[in] priv 150771fa900SAdrien Mazarguil * Pointer to private structure. 151771fa900SAdrien Mazarguil * @param[in] entry 152771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 153771fa900SAdrien Mazarguil * @param[out] buf 154771fa900SAdrien Mazarguil * Data output buffer. 155771fa900SAdrien Mazarguil * @param size 156771fa900SAdrien Mazarguil * Buffer size. 157771fa900SAdrien Mazarguil * 158771fa900SAdrien Mazarguil * @return 159771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 160771fa900SAdrien Mazarguil */ 161771fa900SAdrien Mazarguil static int 162771fa900SAdrien Mazarguil priv_sysfs_read(const struct priv *priv, const char *entry, 163771fa900SAdrien Mazarguil char *buf, size_t size) 164771fa900SAdrien Mazarguil { 165771fa900SAdrien Mazarguil char ifname[IF_NAMESIZE]; 166771fa900SAdrien Mazarguil FILE *file; 167771fa900SAdrien Mazarguil int ret; 168771fa900SAdrien Mazarguil int err; 169771fa900SAdrien Mazarguil 170771fa900SAdrien Mazarguil if (priv_get_ifname(priv, &ifname)) 171771fa900SAdrien Mazarguil return -1; 172771fa900SAdrien Mazarguil 173771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path, 174771fa900SAdrien Mazarguil ifname, entry); 175771fa900SAdrien Mazarguil 176771fa900SAdrien Mazarguil file = fopen(path, "rb"); 177771fa900SAdrien Mazarguil if (file == NULL) 178771fa900SAdrien Mazarguil return -1; 179771fa900SAdrien Mazarguil ret = fread(buf, 1, size, file); 180771fa900SAdrien Mazarguil err = errno; 181771fa900SAdrien Mazarguil if (((size_t)ret < size) && (ferror(file))) 182771fa900SAdrien Mazarguil ret = -1; 183771fa900SAdrien Mazarguil else 184771fa900SAdrien Mazarguil ret = size; 185771fa900SAdrien Mazarguil fclose(file); 186771fa900SAdrien Mazarguil errno = err; 187771fa900SAdrien Mazarguil return ret; 188771fa900SAdrien Mazarguil } 189771fa900SAdrien Mazarguil 190771fa900SAdrien Mazarguil /** 191771fa900SAdrien Mazarguil * Write to sysfs entry. 192771fa900SAdrien Mazarguil * 193771fa900SAdrien Mazarguil * @param[in] priv 194771fa900SAdrien Mazarguil * Pointer to private structure. 195771fa900SAdrien Mazarguil * @param[in] entry 196771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 197771fa900SAdrien Mazarguil * @param[in] buf 198771fa900SAdrien Mazarguil * Data buffer. 199771fa900SAdrien Mazarguil * @param size 200771fa900SAdrien Mazarguil * Buffer size. 201771fa900SAdrien Mazarguil * 202771fa900SAdrien Mazarguil * @return 203771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 204771fa900SAdrien Mazarguil */ 205771fa900SAdrien Mazarguil static int 206771fa900SAdrien Mazarguil priv_sysfs_write(const struct priv *priv, const char *entry, 207771fa900SAdrien Mazarguil char *buf, size_t size) 208771fa900SAdrien Mazarguil { 209771fa900SAdrien Mazarguil char ifname[IF_NAMESIZE]; 210771fa900SAdrien Mazarguil FILE *file; 211771fa900SAdrien Mazarguil int ret; 212771fa900SAdrien Mazarguil int err; 213771fa900SAdrien Mazarguil 214771fa900SAdrien Mazarguil if (priv_get_ifname(priv, &ifname)) 215771fa900SAdrien Mazarguil return -1; 216771fa900SAdrien Mazarguil 217771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path, 218771fa900SAdrien Mazarguil ifname, entry); 219771fa900SAdrien Mazarguil 220771fa900SAdrien Mazarguil file = fopen(path, "wb"); 221771fa900SAdrien Mazarguil if (file == NULL) 222771fa900SAdrien Mazarguil return -1; 223771fa900SAdrien Mazarguil ret = fwrite(buf, 1, size, file); 224771fa900SAdrien Mazarguil err = errno; 225771fa900SAdrien Mazarguil if (((size_t)ret < size) || (ferror(file))) 226771fa900SAdrien Mazarguil ret = -1; 227771fa900SAdrien Mazarguil else 228771fa900SAdrien Mazarguil ret = size; 229771fa900SAdrien Mazarguil fclose(file); 230771fa900SAdrien Mazarguil errno = err; 231771fa900SAdrien Mazarguil return ret; 232771fa900SAdrien Mazarguil } 233771fa900SAdrien Mazarguil 234771fa900SAdrien Mazarguil /** 235771fa900SAdrien Mazarguil * Get unsigned long sysfs property. 236771fa900SAdrien Mazarguil * 237771fa900SAdrien Mazarguil * @param priv 238771fa900SAdrien Mazarguil * Pointer to private structure. 239771fa900SAdrien Mazarguil * @param[in] name 240771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 241771fa900SAdrien Mazarguil * @param[out] value 242771fa900SAdrien Mazarguil * Value output buffer. 243771fa900SAdrien Mazarguil * 244771fa900SAdrien Mazarguil * @return 245771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 246771fa900SAdrien Mazarguil */ 247771fa900SAdrien Mazarguil static int 248771fa900SAdrien Mazarguil priv_get_sysfs_ulong(struct priv *priv, const char *name, unsigned long *value) 249771fa900SAdrien Mazarguil { 250771fa900SAdrien Mazarguil int ret; 251771fa900SAdrien Mazarguil unsigned long value_ret; 252771fa900SAdrien Mazarguil char value_str[32]; 253771fa900SAdrien Mazarguil 254771fa900SAdrien Mazarguil ret = priv_sysfs_read(priv, name, value_str, (sizeof(value_str) - 1)); 255771fa900SAdrien Mazarguil if (ret == -1) { 256771fa900SAdrien Mazarguil DEBUG("cannot read %s value from sysfs: %s", 257771fa900SAdrien Mazarguil name, strerror(errno)); 258771fa900SAdrien Mazarguil return -1; 259771fa900SAdrien Mazarguil } 260771fa900SAdrien Mazarguil value_str[ret] = '\0'; 261771fa900SAdrien Mazarguil errno = 0; 262771fa900SAdrien Mazarguil value_ret = strtoul(value_str, NULL, 0); 263771fa900SAdrien Mazarguil if (errno) { 264771fa900SAdrien Mazarguil DEBUG("invalid %s value `%s': %s", name, value_str, 265771fa900SAdrien Mazarguil strerror(errno)); 266771fa900SAdrien Mazarguil return -1; 267771fa900SAdrien Mazarguil } 268771fa900SAdrien Mazarguil *value = value_ret; 269771fa900SAdrien Mazarguil return 0; 270771fa900SAdrien Mazarguil } 271771fa900SAdrien Mazarguil 272771fa900SAdrien Mazarguil /** 273771fa900SAdrien Mazarguil * Set unsigned long sysfs property. 274771fa900SAdrien Mazarguil * 275771fa900SAdrien Mazarguil * @param priv 276771fa900SAdrien Mazarguil * Pointer to private structure. 277771fa900SAdrien Mazarguil * @param[in] name 278771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 279771fa900SAdrien Mazarguil * @param value 280771fa900SAdrien Mazarguil * Value to set. 281771fa900SAdrien Mazarguil * 282771fa900SAdrien Mazarguil * @return 283771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 284771fa900SAdrien Mazarguil */ 285771fa900SAdrien Mazarguil static int 286771fa900SAdrien Mazarguil priv_set_sysfs_ulong(struct priv *priv, const char *name, unsigned long value) 287771fa900SAdrien Mazarguil { 288771fa900SAdrien Mazarguil int ret; 289771fa900SAdrien Mazarguil MKSTR(value_str, "%lu", value); 290771fa900SAdrien Mazarguil 291771fa900SAdrien Mazarguil ret = priv_sysfs_write(priv, name, value_str, (sizeof(value_str) - 1)); 292771fa900SAdrien Mazarguil if (ret == -1) { 293771fa900SAdrien Mazarguil DEBUG("cannot write %s `%s' (%lu) to sysfs: %s", 294771fa900SAdrien Mazarguil name, value_str, value, strerror(errno)); 295771fa900SAdrien Mazarguil return -1; 296771fa900SAdrien Mazarguil } 297771fa900SAdrien Mazarguil return 0; 298771fa900SAdrien Mazarguil } 299771fa900SAdrien Mazarguil 300771fa900SAdrien Mazarguil /** 301771fa900SAdrien Mazarguil * Perform ifreq ioctl() on associated Ethernet device. 302771fa900SAdrien Mazarguil * 303771fa900SAdrien Mazarguil * @param[in] priv 304771fa900SAdrien Mazarguil * Pointer to private structure. 305771fa900SAdrien Mazarguil * @param req 306771fa900SAdrien Mazarguil * Request number to pass to ioctl(). 307771fa900SAdrien Mazarguil * @param[out] ifr 308771fa900SAdrien Mazarguil * Interface request structure output buffer. 309771fa900SAdrien Mazarguil * 310771fa900SAdrien Mazarguil * @return 311771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 312771fa900SAdrien Mazarguil */ 313771fa900SAdrien Mazarguil int 314771fa900SAdrien Mazarguil priv_ifreq(const struct priv *priv, int req, struct ifreq *ifr) 315771fa900SAdrien Mazarguil { 316771fa900SAdrien Mazarguil int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 317771fa900SAdrien Mazarguil int ret = -1; 318771fa900SAdrien Mazarguil 319771fa900SAdrien Mazarguil if (sock == -1) 320771fa900SAdrien Mazarguil return ret; 321771fa900SAdrien Mazarguil if (priv_get_ifname(priv, &ifr->ifr_name) == 0) 322771fa900SAdrien Mazarguil ret = ioctl(sock, req, ifr); 323771fa900SAdrien Mazarguil close(sock); 324771fa900SAdrien Mazarguil return ret; 325771fa900SAdrien Mazarguil } 326771fa900SAdrien Mazarguil 327771fa900SAdrien Mazarguil /** 328771fa900SAdrien Mazarguil * Get device MTU. 329771fa900SAdrien Mazarguil * 330771fa900SAdrien Mazarguil * @param priv 331771fa900SAdrien Mazarguil * Pointer to private structure. 332771fa900SAdrien Mazarguil * @param[out] mtu 333771fa900SAdrien Mazarguil * MTU value output buffer. 334771fa900SAdrien Mazarguil * 335771fa900SAdrien Mazarguil * @return 336771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 337771fa900SAdrien Mazarguil */ 338771fa900SAdrien Mazarguil int 339771fa900SAdrien Mazarguil priv_get_mtu(struct priv *priv, uint16_t *mtu) 340771fa900SAdrien Mazarguil { 341771fa900SAdrien Mazarguil unsigned long ulong_mtu; 342771fa900SAdrien Mazarguil 343771fa900SAdrien Mazarguil if (priv_get_sysfs_ulong(priv, "mtu", &ulong_mtu) == -1) 344771fa900SAdrien Mazarguil return -1; 345771fa900SAdrien Mazarguil *mtu = ulong_mtu; 346771fa900SAdrien Mazarguil return 0; 347771fa900SAdrien Mazarguil } 348771fa900SAdrien Mazarguil 349771fa900SAdrien Mazarguil /** 350cf37ca95SAdrien Mazarguil * Set device MTU. 351cf37ca95SAdrien Mazarguil * 352cf37ca95SAdrien Mazarguil * @param priv 353cf37ca95SAdrien Mazarguil * Pointer to private structure. 354cf37ca95SAdrien Mazarguil * @param mtu 355cf37ca95SAdrien Mazarguil * MTU value to set. 356cf37ca95SAdrien Mazarguil * 357cf37ca95SAdrien Mazarguil * @return 358cf37ca95SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 359cf37ca95SAdrien Mazarguil */ 360cf37ca95SAdrien Mazarguil static int 361cf37ca95SAdrien Mazarguil priv_set_mtu(struct priv *priv, uint16_t mtu) 362cf37ca95SAdrien Mazarguil { 363cf37ca95SAdrien Mazarguil return priv_set_sysfs_ulong(priv, "mtu", mtu); 364cf37ca95SAdrien Mazarguil } 365cf37ca95SAdrien Mazarguil 366cf37ca95SAdrien Mazarguil /** 367771fa900SAdrien Mazarguil * Set device flags. 368771fa900SAdrien Mazarguil * 369771fa900SAdrien Mazarguil * @param priv 370771fa900SAdrien Mazarguil * Pointer to private structure. 371771fa900SAdrien Mazarguil * @param keep 372771fa900SAdrien Mazarguil * Bitmask for flags that must remain untouched. 373771fa900SAdrien Mazarguil * @param flags 374771fa900SAdrien Mazarguil * Bitmask for flags to modify. 375771fa900SAdrien Mazarguil * 376771fa900SAdrien Mazarguil * @return 377771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 378771fa900SAdrien Mazarguil */ 379771fa900SAdrien Mazarguil int 380771fa900SAdrien Mazarguil priv_set_flags(struct priv *priv, unsigned int keep, unsigned int flags) 381771fa900SAdrien Mazarguil { 382771fa900SAdrien Mazarguil unsigned long tmp; 383771fa900SAdrien Mazarguil 384771fa900SAdrien Mazarguil if (priv_get_sysfs_ulong(priv, "flags", &tmp) == -1) 385771fa900SAdrien Mazarguil return -1; 386771fa900SAdrien Mazarguil tmp &= keep; 387771fa900SAdrien Mazarguil tmp |= flags; 388771fa900SAdrien Mazarguil return priv_set_sysfs_ulong(priv, "flags", tmp); 389771fa900SAdrien Mazarguil } 390771fa900SAdrien Mazarguil 391771fa900SAdrien Mazarguil /** 392e60fbd5bSAdrien Mazarguil * Ethernet device configuration. 393e60fbd5bSAdrien Mazarguil * 394e60fbd5bSAdrien Mazarguil * Prepare the driver for a given number of TX and RX queues. 395e60fbd5bSAdrien Mazarguil * Allocate parent RSS queue when several RX queues are requested. 396e60fbd5bSAdrien Mazarguil * 397e60fbd5bSAdrien Mazarguil * @param dev 398e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 399e60fbd5bSAdrien Mazarguil * 400e60fbd5bSAdrien Mazarguil * @return 401e60fbd5bSAdrien Mazarguil * 0 on success, errno value on failure. 402e60fbd5bSAdrien Mazarguil */ 403e60fbd5bSAdrien Mazarguil static int 404e60fbd5bSAdrien Mazarguil dev_configure(struct rte_eth_dev *dev) 405e60fbd5bSAdrien Mazarguil { 406e60fbd5bSAdrien Mazarguil struct priv *priv = dev->data->dev_private; 407e60fbd5bSAdrien Mazarguil unsigned int rxqs_n = dev->data->nb_rx_queues; 408e60fbd5bSAdrien Mazarguil unsigned int txqs_n = dev->data->nb_tx_queues; 409e60fbd5bSAdrien Mazarguil unsigned int tmp; 410e60fbd5bSAdrien Mazarguil int ret; 411e60fbd5bSAdrien Mazarguil 412e60fbd5bSAdrien Mazarguil priv->rxqs = (void *)dev->data->rx_queues; 413e60fbd5bSAdrien Mazarguil priv->txqs = (void *)dev->data->tx_queues; 414e60fbd5bSAdrien Mazarguil if (txqs_n != priv->txqs_n) { 415e60fbd5bSAdrien Mazarguil INFO("%p: TX queues number update: %u -> %u", 416e60fbd5bSAdrien Mazarguil (void *)dev, priv->txqs_n, txqs_n); 417e60fbd5bSAdrien Mazarguil priv->txqs_n = txqs_n; 418e60fbd5bSAdrien Mazarguil } 419e60fbd5bSAdrien Mazarguil if (rxqs_n == priv->rxqs_n) 420e60fbd5bSAdrien Mazarguil return 0; 421e60fbd5bSAdrien Mazarguil INFO("%p: RX queues number update: %u -> %u", 422e60fbd5bSAdrien Mazarguil (void *)dev, priv->rxqs_n, rxqs_n); 423e60fbd5bSAdrien Mazarguil /* If RSS is enabled, disable it first. */ 424e60fbd5bSAdrien Mazarguil if (priv->rss) { 425e60fbd5bSAdrien Mazarguil unsigned int i; 426e60fbd5bSAdrien Mazarguil 427e60fbd5bSAdrien Mazarguil /* Only if there are no remaining child RX queues. */ 428e60fbd5bSAdrien Mazarguil for (i = 0; (i != priv->rxqs_n); ++i) 429e60fbd5bSAdrien Mazarguil if ((*priv->rxqs)[i] != NULL) 430e60fbd5bSAdrien Mazarguil return EINVAL; 431e60fbd5bSAdrien Mazarguil rxq_cleanup(&priv->rxq_parent); 432e60fbd5bSAdrien Mazarguil priv->rss = 0; 433e60fbd5bSAdrien Mazarguil priv->rxqs_n = 0; 434e60fbd5bSAdrien Mazarguil } 435e60fbd5bSAdrien Mazarguil if (rxqs_n <= 1) { 436e60fbd5bSAdrien Mazarguil /* Nothing else to do. */ 437e60fbd5bSAdrien Mazarguil priv->rxqs_n = rxqs_n; 438e60fbd5bSAdrien Mazarguil return 0; 439e60fbd5bSAdrien Mazarguil } 440e60fbd5bSAdrien Mazarguil /* Allocate a new RSS parent queue if supported by hardware. */ 441e60fbd5bSAdrien Mazarguil if (!priv->hw_rss) { 442e60fbd5bSAdrien Mazarguil ERROR("%p: only a single RX queue can be configured when" 443e60fbd5bSAdrien Mazarguil " hardware doesn't support RSS", 444e60fbd5bSAdrien Mazarguil (void *)dev); 445e60fbd5bSAdrien Mazarguil return EINVAL; 446e60fbd5bSAdrien Mazarguil } 447e60fbd5bSAdrien Mazarguil /* Fail if hardware doesn't support that many RSS queues. */ 448e60fbd5bSAdrien Mazarguil if (rxqs_n >= priv->max_rss_tbl_sz) { 449e60fbd5bSAdrien Mazarguil ERROR("%p: only %u RX queues can be configured for RSS", 450e60fbd5bSAdrien Mazarguil (void *)dev, priv->max_rss_tbl_sz); 451e60fbd5bSAdrien Mazarguil return EINVAL; 452e60fbd5bSAdrien Mazarguil } 453e60fbd5bSAdrien Mazarguil priv->rss = 1; 454e60fbd5bSAdrien Mazarguil tmp = priv->rxqs_n; 455e60fbd5bSAdrien Mazarguil priv->rxqs_n = rxqs_n; 456e60fbd5bSAdrien Mazarguil ret = rxq_setup(dev, &priv->rxq_parent, 0, 0, NULL, NULL); 457e60fbd5bSAdrien Mazarguil if (!ret) 458e60fbd5bSAdrien Mazarguil return 0; 459e60fbd5bSAdrien Mazarguil /* Failure, rollback. */ 460e60fbd5bSAdrien Mazarguil priv->rss = 0; 461e60fbd5bSAdrien Mazarguil priv->rxqs_n = tmp; 462e60fbd5bSAdrien Mazarguil assert(ret > 0); 463e60fbd5bSAdrien Mazarguil return ret; 464e60fbd5bSAdrien Mazarguil } 465e60fbd5bSAdrien Mazarguil 466e60fbd5bSAdrien Mazarguil /** 467e60fbd5bSAdrien Mazarguil * DPDK callback for Ethernet device configuration. 468e60fbd5bSAdrien Mazarguil * 469e60fbd5bSAdrien Mazarguil * @param dev 470e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 471e60fbd5bSAdrien Mazarguil * 472e60fbd5bSAdrien Mazarguil * @return 473e60fbd5bSAdrien Mazarguil * 0 on success, negative errno value on failure. 474e60fbd5bSAdrien Mazarguil */ 475e60fbd5bSAdrien Mazarguil int 476e60fbd5bSAdrien Mazarguil mlx5_dev_configure(struct rte_eth_dev *dev) 477e60fbd5bSAdrien Mazarguil { 478e60fbd5bSAdrien Mazarguil struct priv *priv = dev->data->dev_private; 479e60fbd5bSAdrien Mazarguil int ret; 480e60fbd5bSAdrien Mazarguil 481e60fbd5bSAdrien Mazarguil priv_lock(priv); 482e60fbd5bSAdrien Mazarguil ret = dev_configure(dev); 483e60fbd5bSAdrien Mazarguil assert(ret >= 0); 484e60fbd5bSAdrien Mazarguil priv_unlock(priv); 485e60fbd5bSAdrien Mazarguil return -ret; 486e60fbd5bSAdrien Mazarguil } 487e60fbd5bSAdrien Mazarguil 488e60fbd5bSAdrien Mazarguil /** 489e60fbd5bSAdrien Mazarguil * DPDK callback to get information about the device. 490e60fbd5bSAdrien Mazarguil * 491e60fbd5bSAdrien Mazarguil * @param dev 492e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 493e60fbd5bSAdrien Mazarguil * @param[out] info 494e60fbd5bSAdrien Mazarguil * Info structure output buffer. 495e60fbd5bSAdrien Mazarguil */ 496e60fbd5bSAdrien Mazarguil void 497e60fbd5bSAdrien Mazarguil mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) 498e60fbd5bSAdrien Mazarguil { 499e60fbd5bSAdrien Mazarguil struct priv *priv = dev->data->dev_private; 500e60fbd5bSAdrien Mazarguil unsigned int max; 501e60fbd5bSAdrien Mazarguil char ifname[IF_NAMESIZE]; 502e60fbd5bSAdrien Mazarguil 503e60fbd5bSAdrien Mazarguil priv_lock(priv); 504e60fbd5bSAdrien Mazarguil /* FIXME: we should ask the device for these values. */ 505e60fbd5bSAdrien Mazarguil info->min_rx_bufsize = 32; 506e60fbd5bSAdrien Mazarguil info->max_rx_pktlen = 65536; 507e60fbd5bSAdrien Mazarguil /* 508e60fbd5bSAdrien Mazarguil * Since we need one CQ per QP, the limit is the minimum number 509e60fbd5bSAdrien Mazarguil * between the two values. 510e60fbd5bSAdrien Mazarguil */ 511e60fbd5bSAdrien Mazarguil max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ? 512e60fbd5bSAdrien Mazarguil priv->device_attr.max_qp : priv->device_attr.max_cq); 513e60fbd5bSAdrien Mazarguil /* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */ 514e60fbd5bSAdrien Mazarguil if (max >= 65535) 515e60fbd5bSAdrien Mazarguil max = 65535; 516e60fbd5bSAdrien Mazarguil info->max_rx_queues = max; 517e60fbd5bSAdrien Mazarguil info->max_tx_queues = max; 518e60fbd5bSAdrien Mazarguil /* Last array entry is reserved for broadcast. */ 519e60fbd5bSAdrien Mazarguil info->max_mac_addrs = (RTE_DIM(priv->mac) - 1); 520e60fbd5bSAdrien Mazarguil info->rx_offload_capa = 521e60fbd5bSAdrien Mazarguil (priv->hw_csum ? 522e60fbd5bSAdrien Mazarguil (DEV_RX_OFFLOAD_IPV4_CKSUM | 523e60fbd5bSAdrien Mazarguil DEV_RX_OFFLOAD_UDP_CKSUM | 524e60fbd5bSAdrien Mazarguil DEV_RX_OFFLOAD_TCP_CKSUM) : 525e60fbd5bSAdrien Mazarguil 0); 526e60fbd5bSAdrien Mazarguil info->tx_offload_capa = 527e60fbd5bSAdrien Mazarguil (priv->hw_csum ? 528e60fbd5bSAdrien Mazarguil (DEV_TX_OFFLOAD_IPV4_CKSUM | 529e60fbd5bSAdrien Mazarguil DEV_TX_OFFLOAD_UDP_CKSUM | 530e60fbd5bSAdrien Mazarguil DEV_TX_OFFLOAD_TCP_CKSUM) : 531e60fbd5bSAdrien Mazarguil 0); 532e60fbd5bSAdrien Mazarguil if (priv_get_ifname(priv, &ifname) == 0) 533e60fbd5bSAdrien Mazarguil info->if_index = if_nametoindex(ifname); 534e60fbd5bSAdrien Mazarguil priv_unlock(priv); 535e60fbd5bSAdrien Mazarguil } 536e60fbd5bSAdrien Mazarguil 537e60fbd5bSAdrien Mazarguil /** 538cf37ca95SAdrien Mazarguil * DPDK callback to change the MTU. 539cf37ca95SAdrien Mazarguil * 540cf37ca95SAdrien Mazarguil * Setting the MTU affects hardware MRU (packets larger than the MTU cannot be 541cf37ca95SAdrien Mazarguil * received). Use this as a hint to enable/disable scattered packets support 542cf37ca95SAdrien Mazarguil * and improve performance when not needed. 543cf37ca95SAdrien Mazarguil * Since failure is not an option, reconfiguring queues on the fly is not 544cf37ca95SAdrien Mazarguil * recommended. 545cf37ca95SAdrien Mazarguil * 546cf37ca95SAdrien Mazarguil * @param dev 547cf37ca95SAdrien Mazarguil * Pointer to Ethernet device structure. 548cf37ca95SAdrien Mazarguil * @param in_mtu 549cf37ca95SAdrien Mazarguil * New MTU. 550cf37ca95SAdrien Mazarguil * 551cf37ca95SAdrien Mazarguil * @return 552cf37ca95SAdrien Mazarguil * 0 on success, negative errno value on failure. 553cf37ca95SAdrien Mazarguil */ 554cf37ca95SAdrien Mazarguil int 555cf37ca95SAdrien Mazarguil mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu) 556cf37ca95SAdrien Mazarguil { 557cf37ca95SAdrien Mazarguil struct priv *priv = dev->data->dev_private; 558cf37ca95SAdrien Mazarguil int ret = 0; 559cf37ca95SAdrien Mazarguil unsigned int i; 560cf37ca95SAdrien Mazarguil uint16_t (*rx_func)(void *, struct rte_mbuf **, uint16_t) = 561cf37ca95SAdrien Mazarguil mlx5_rx_burst; 562cf37ca95SAdrien Mazarguil 563cf37ca95SAdrien Mazarguil priv_lock(priv); 564cf37ca95SAdrien Mazarguil /* Set kernel interface MTU first. */ 565cf37ca95SAdrien Mazarguil if (priv_set_mtu(priv, mtu)) { 566cf37ca95SAdrien Mazarguil ret = errno; 567cf37ca95SAdrien Mazarguil WARN("cannot set port %u MTU to %u: %s", priv->port, mtu, 568cf37ca95SAdrien Mazarguil strerror(ret)); 569cf37ca95SAdrien Mazarguil goto out; 570cf37ca95SAdrien Mazarguil } else 571cf37ca95SAdrien Mazarguil DEBUG("adapter port %u MTU set to %u", priv->port, mtu); 572cf37ca95SAdrien Mazarguil priv->mtu = mtu; 573cf37ca95SAdrien Mazarguil /* Temporarily replace RX handler with a fake one, assuming it has not 574cf37ca95SAdrien Mazarguil * been copied elsewhere. */ 575cf37ca95SAdrien Mazarguil dev->rx_pkt_burst = removed_rx_burst; 576cf37ca95SAdrien Mazarguil /* Make sure everyone has left mlx5_rx_burst() and uses 577cf37ca95SAdrien Mazarguil * removed_rx_burst() instead. */ 578cf37ca95SAdrien Mazarguil rte_wmb(); 579cf37ca95SAdrien Mazarguil usleep(1000); 580cf37ca95SAdrien Mazarguil /* Reconfigure each RX queue. */ 581cf37ca95SAdrien Mazarguil for (i = 0; (i != priv->rxqs_n); ++i) { 582cf37ca95SAdrien Mazarguil struct rxq *rxq = (*priv->rxqs)[i]; 583cf37ca95SAdrien Mazarguil unsigned int max_frame_len; 584cf37ca95SAdrien Mazarguil int sp; 585cf37ca95SAdrien Mazarguil 586cf37ca95SAdrien Mazarguil if (rxq == NULL) 587cf37ca95SAdrien Mazarguil continue; 588cf37ca95SAdrien Mazarguil /* Calculate new maximum frame length according to MTU and 589cf37ca95SAdrien Mazarguil * toggle scattered support (sp) if necessary. */ 590cf37ca95SAdrien Mazarguil max_frame_len = (priv->mtu + ETHER_HDR_LEN + 591cf37ca95SAdrien Mazarguil (ETHER_MAX_VLAN_FRAME_LEN - ETHER_MAX_LEN)); 592cf37ca95SAdrien Mazarguil sp = (max_frame_len > (rxq->mb_len - RTE_PKTMBUF_HEADROOM)); 593cf37ca95SAdrien Mazarguil /* Provide new values to rxq_setup(). */ 594cf37ca95SAdrien Mazarguil dev->data->dev_conf.rxmode.jumbo_frame = sp; 595cf37ca95SAdrien Mazarguil dev->data->dev_conf.rxmode.max_rx_pkt_len = max_frame_len; 596cf37ca95SAdrien Mazarguil ret = rxq_rehash(dev, rxq); 597cf37ca95SAdrien Mazarguil if (ret) { 598cf37ca95SAdrien Mazarguil /* Force SP RX if that queue requires it and abort. */ 599cf37ca95SAdrien Mazarguil if (rxq->sp) 600cf37ca95SAdrien Mazarguil rx_func = mlx5_rx_burst_sp; 601cf37ca95SAdrien Mazarguil break; 602cf37ca95SAdrien Mazarguil } 603cf37ca95SAdrien Mazarguil /* Reenable non-RSS queue attributes. No need to check 604cf37ca95SAdrien Mazarguil * for errors at this stage. */ 605cf37ca95SAdrien Mazarguil if (!priv->rss) { 606cf37ca95SAdrien Mazarguil if (priv->started) 607cf37ca95SAdrien Mazarguil rxq_mac_addrs_add(rxq); 608*1bdbe1afSAdrien Mazarguil if (priv->started && priv->promisc_req) 609*1bdbe1afSAdrien Mazarguil rxq_promiscuous_enable(rxq); 610*1bdbe1afSAdrien Mazarguil if (priv->started && priv->allmulti_req) 611*1bdbe1afSAdrien Mazarguil rxq_allmulticast_enable(rxq); 612cf37ca95SAdrien Mazarguil } 613cf37ca95SAdrien Mazarguil /* Scattered burst function takes priority. */ 614cf37ca95SAdrien Mazarguil if (rxq->sp) 615cf37ca95SAdrien Mazarguil rx_func = mlx5_rx_burst_sp; 616cf37ca95SAdrien Mazarguil } 617cf37ca95SAdrien Mazarguil /* Burst functions can now be called again. */ 618cf37ca95SAdrien Mazarguil rte_wmb(); 619cf37ca95SAdrien Mazarguil dev->rx_pkt_burst = rx_func; 620cf37ca95SAdrien Mazarguil out: 621cf37ca95SAdrien Mazarguil priv_unlock(priv); 622cf37ca95SAdrien Mazarguil assert(ret >= 0); 623cf37ca95SAdrien Mazarguil return -ret; 624cf37ca95SAdrien Mazarguil } 625cf37ca95SAdrien Mazarguil 626cf37ca95SAdrien Mazarguil /** 627771fa900SAdrien Mazarguil * Get PCI information from struct ibv_device. 628771fa900SAdrien Mazarguil * 629771fa900SAdrien Mazarguil * @param device 630771fa900SAdrien Mazarguil * Pointer to Ethernet device structure. 631771fa900SAdrien Mazarguil * @param[out] pci_addr 632771fa900SAdrien Mazarguil * PCI bus address output buffer. 633771fa900SAdrien Mazarguil * 634771fa900SAdrien Mazarguil * @return 635771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 636771fa900SAdrien Mazarguil */ 637771fa900SAdrien Mazarguil int 638771fa900SAdrien Mazarguil mlx5_ibv_device_to_pci_addr(const struct ibv_device *device, 639771fa900SAdrien Mazarguil struct rte_pci_addr *pci_addr) 640771fa900SAdrien Mazarguil { 641771fa900SAdrien Mazarguil FILE *file; 642771fa900SAdrien Mazarguil char line[32]; 643771fa900SAdrien Mazarguil MKSTR(path, "%s/device/uevent", device->ibdev_path); 644771fa900SAdrien Mazarguil 645771fa900SAdrien Mazarguil file = fopen(path, "rb"); 646771fa900SAdrien Mazarguil if (file == NULL) 647771fa900SAdrien Mazarguil return -1; 648771fa900SAdrien Mazarguil while (fgets(line, sizeof(line), file) == line) { 649771fa900SAdrien Mazarguil size_t len = strlen(line); 650771fa900SAdrien Mazarguil int ret; 651771fa900SAdrien Mazarguil 652771fa900SAdrien Mazarguil /* Truncate long lines. */ 653771fa900SAdrien Mazarguil if (len == (sizeof(line) - 1)) 654771fa900SAdrien Mazarguil while (line[(len - 1)] != '\n') { 655771fa900SAdrien Mazarguil ret = fgetc(file); 656771fa900SAdrien Mazarguil if (ret == EOF) 657771fa900SAdrien Mazarguil break; 658771fa900SAdrien Mazarguil line[(len - 1)] = ret; 659771fa900SAdrien Mazarguil } 660771fa900SAdrien Mazarguil /* Extract information. */ 661771fa900SAdrien Mazarguil if (sscanf(line, 662771fa900SAdrien Mazarguil "PCI_SLOT_NAME=" 663771fa900SAdrien Mazarguil "%" SCNx16 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n", 664771fa900SAdrien Mazarguil &pci_addr->domain, 665771fa900SAdrien Mazarguil &pci_addr->bus, 666771fa900SAdrien Mazarguil &pci_addr->devid, 667771fa900SAdrien Mazarguil &pci_addr->function) == 4) { 668771fa900SAdrien Mazarguil ret = 0; 669771fa900SAdrien Mazarguil break; 670771fa900SAdrien Mazarguil } 671771fa900SAdrien Mazarguil } 672771fa900SAdrien Mazarguil fclose(file); 673771fa900SAdrien Mazarguil return 0; 674771fa900SAdrien Mazarguil } 675