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> 48*cb8faed7SAdrien Mazarguil #include <linux/ethtool.h> 49*cb8faed7SAdrien Mazarguil #include <linux/sockios.h> 50771fa900SAdrien Mazarguil 51771fa900SAdrien Mazarguil /* DPDK headers don't like -pedantic. */ 52771fa900SAdrien Mazarguil #ifdef PEDANTIC 53771fa900SAdrien Mazarguil #pragma GCC diagnostic ignored "-pedantic" 54771fa900SAdrien Mazarguil #endif 55771fa900SAdrien Mazarguil #include <rte_atomic.h> 56771fa900SAdrien Mazarguil #include <rte_ethdev.h> 57771fa900SAdrien Mazarguil #include <rte_mbuf.h> 58771fa900SAdrien Mazarguil #include <rte_common.h> 59771fa900SAdrien Mazarguil #ifdef PEDANTIC 60771fa900SAdrien Mazarguil #pragma GCC diagnostic error "-pedantic" 61771fa900SAdrien Mazarguil #endif 62771fa900SAdrien Mazarguil 63771fa900SAdrien Mazarguil #include "mlx5.h" 64e60fbd5bSAdrien Mazarguil #include "mlx5_rxtx.h" 65771fa900SAdrien Mazarguil #include "mlx5_utils.h" 66771fa900SAdrien Mazarguil 67771fa900SAdrien Mazarguil /** 68771fa900SAdrien Mazarguil * Get interface name from private structure. 69771fa900SAdrien Mazarguil * 70771fa900SAdrien Mazarguil * @param[in] priv 71771fa900SAdrien Mazarguil * Pointer to private structure. 72771fa900SAdrien Mazarguil * @param[out] ifname 73771fa900SAdrien Mazarguil * Interface name output buffer. 74771fa900SAdrien Mazarguil * 75771fa900SAdrien Mazarguil * @return 76771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 77771fa900SAdrien Mazarguil */ 78771fa900SAdrien Mazarguil int 79771fa900SAdrien Mazarguil priv_get_ifname(const struct priv *priv, char (*ifname)[IF_NAMESIZE]) 80771fa900SAdrien Mazarguil { 81771fa900SAdrien Mazarguil DIR *dir; 82771fa900SAdrien Mazarguil struct dirent *dent; 83771fa900SAdrien Mazarguil unsigned int dev_type = 0; 84771fa900SAdrien Mazarguil unsigned int dev_port_prev = ~0u; 85771fa900SAdrien Mazarguil char match[IF_NAMESIZE] = ""; 86771fa900SAdrien Mazarguil 87771fa900SAdrien Mazarguil { 88771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net", priv->ctx->device->ibdev_path); 89771fa900SAdrien Mazarguil 90771fa900SAdrien Mazarguil dir = opendir(path); 91771fa900SAdrien Mazarguil if (dir == NULL) 92771fa900SAdrien Mazarguil return -1; 93771fa900SAdrien Mazarguil } 94771fa900SAdrien Mazarguil while ((dent = readdir(dir)) != NULL) { 95771fa900SAdrien Mazarguil char *name = dent->d_name; 96771fa900SAdrien Mazarguil FILE *file; 97771fa900SAdrien Mazarguil unsigned int dev_port; 98771fa900SAdrien Mazarguil int r; 99771fa900SAdrien Mazarguil 100771fa900SAdrien Mazarguil if ((name[0] == '.') && 101771fa900SAdrien Mazarguil ((name[1] == '\0') || 102771fa900SAdrien Mazarguil ((name[1] == '.') && (name[2] == '\0')))) 103771fa900SAdrien Mazarguil continue; 104771fa900SAdrien Mazarguil 105771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net/%s/%s", 106771fa900SAdrien Mazarguil priv->ctx->device->ibdev_path, name, 107771fa900SAdrien Mazarguil (dev_type ? "dev_id" : "dev_port")); 108771fa900SAdrien Mazarguil 109771fa900SAdrien Mazarguil file = fopen(path, "rb"); 110771fa900SAdrien Mazarguil if (file == NULL) { 111771fa900SAdrien Mazarguil if (errno != ENOENT) 112771fa900SAdrien Mazarguil continue; 113771fa900SAdrien Mazarguil /* 114771fa900SAdrien Mazarguil * Switch to dev_id when dev_port does not exist as 115771fa900SAdrien Mazarguil * is the case with Linux kernel versions < 3.15. 116771fa900SAdrien Mazarguil */ 117771fa900SAdrien Mazarguil try_dev_id: 118771fa900SAdrien Mazarguil match[0] = '\0'; 119771fa900SAdrien Mazarguil if (dev_type) 120771fa900SAdrien Mazarguil break; 121771fa900SAdrien Mazarguil dev_type = 1; 122771fa900SAdrien Mazarguil dev_port_prev = ~0u; 123771fa900SAdrien Mazarguil rewinddir(dir); 124771fa900SAdrien Mazarguil continue; 125771fa900SAdrien Mazarguil } 126771fa900SAdrien Mazarguil r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port); 127771fa900SAdrien Mazarguil fclose(file); 128771fa900SAdrien Mazarguil if (r != 1) 129771fa900SAdrien Mazarguil continue; 130771fa900SAdrien Mazarguil /* 131771fa900SAdrien Mazarguil * Switch to dev_id when dev_port returns the same value for 132771fa900SAdrien Mazarguil * all ports. May happen when using a MOFED release older than 133771fa900SAdrien Mazarguil * 3.0 with a Linux kernel >= 3.15. 134771fa900SAdrien Mazarguil */ 135771fa900SAdrien Mazarguil if (dev_port == dev_port_prev) 136771fa900SAdrien Mazarguil goto try_dev_id; 137771fa900SAdrien Mazarguil dev_port_prev = dev_port; 138771fa900SAdrien Mazarguil if (dev_port == (priv->port - 1u)) 139771fa900SAdrien Mazarguil snprintf(match, sizeof(match), "%s", name); 140771fa900SAdrien Mazarguil } 141771fa900SAdrien Mazarguil closedir(dir); 142771fa900SAdrien Mazarguil if (match[0] == '\0') 143771fa900SAdrien Mazarguil return -1; 144771fa900SAdrien Mazarguil strncpy(*ifname, match, sizeof(*ifname)); 145771fa900SAdrien Mazarguil return 0; 146771fa900SAdrien Mazarguil } 147771fa900SAdrien Mazarguil 148771fa900SAdrien Mazarguil /** 149771fa900SAdrien Mazarguil * Read from sysfs entry. 150771fa900SAdrien Mazarguil * 151771fa900SAdrien Mazarguil * @param[in] priv 152771fa900SAdrien Mazarguil * Pointer to private structure. 153771fa900SAdrien Mazarguil * @param[in] entry 154771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 155771fa900SAdrien Mazarguil * @param[out] buf 156771fa900SAdrien Mazarguil * Data output buffer. 157771fa900SAdrien Mazarguil * @param size 158771fa900SAdrien Mazarguil * Buffer size. 159771fa900SAdrien Mazarguil * 160771fa900SAdrien Mazarguil * @return 161771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 162771fa900SAdrien Mazarguil */ 163771fa900SAdrien Mazarguil static int 164771fa900SAdrien Mazarguil priv_sysfs_read(const struct priv *priv, const char *entry, 165771fa900SAdrien Mazarguil char *buf, size_t size) 166771fa900SAdrien Mazarguil { 167771fa900SAdrien Mazarguil char ifname[IF_NAMESIZE]; 168771fa900SAdrien Mazarguil FILE *file; 169771fa900SAdrien Mazarguil int ret; 170771fa900SAdrien Mazarguil int err; 171771fa900SAdrien Mazarguil 172771fa900SAdrien Mazarguil if (priv_get_ifname(priv, &ifname)) 173771fa900SAdrien Mazarguil return -1; 174771fa900SAdrien Mazarguil 175771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path, 176771fa900SAdrien Mazarguil ifname, entry); 177771fa900SAdrien Mazarguil 178771fa900SAdrien Mazarguil file = fopen(path, "rb"); 179771fa900SAdrien Mazarguil if (file == NULL) 180771fa900SAdrien Mazarguil return -1; 181771fa900SAdrien Mazarguil ret = fread(buf, 1, size, file); 182771fa900SAdrien Mazarguil err = errno; 183771fa900SAdrien Mazarguil if (((size_t)ret < size) && (ferror(file))) 184771fa900SAdrien Mazarguil ret = -1; 185771fa900SAdrien Mazarguil else 186771fa900SAdrien Mazarguil ret = size; 187771fa900SAdrien Mazarguil fclose(file); 188771fa900SAdrien Mazarguil errno = err; 189771fa900SAdrien Mazarguil return ret; 190771fa900SAdrien Mazarguil } 191771fa900SAdrien Mazarguil 192771fa900SAdrien Mazarguil /** 193771fa900SAdrien Mazarguil * Write to sysfs entry. 194771fa900SAdrien Mazarguil * 195771fa900SAdrien Mazarguil * @param[in] priv 196771fa900SAdrien Mazarguil * Pointer to private structure. 197771fa900SAdrien Mazarguil * @param[in] entry 198771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 199771fa900SAdrien Mazarguil * @param[in] buf 200771fa900SAdrien Mazarguil * Data buffer. 201771fa900SAdrien Mazarguil * @param size 202771fa900SAdrien Mazarguil * Buffer size. 203771fa900SAdrien Mazarguil * 204771fa900SAdrien Mazarguil * @return 205771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 206771fa900SAdrien Mazarguil */ 207771fa900SAdrien Mazarguil static int 208771fa900SAdrien Mazarguil priv_sysfs_write(const struct priv *priv, const char *entry, 209771fa900SAdrien Mazarguil char *buf, size_t size) 210771fa900SAdrien Mazarguil { 211771fa900SAdrien Mazarguil char ifname[IF_NAMESIZE]; 212771fa900SAdrien Mazarguil FILE *file; 213771fa900SAdrien Mazarguil int ret; 214771fa900SAdrien Mazarguil int err; 215771fa900SAdrien Mazarguil 216771fa900SAdrien Mazarguil if (priv_get_ifname(priv, &ifname)) 217771fa900SAdrien Mazarguil return -1; 218771fa900SAdrien Mazarguil 219771fa900SAdrien Mazarguil MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path, 220771fa900SAdrien Mazarguil ifname, entry); 221771fa900SAdrien Mazarguil 222771fa900SAdrien Mazarguil file = fopen(path, "wb"); 223771fa900SAdrien Mazarguil if (file == NULL) 224771fa900SAdrien Mazarguil return -1; 225771fa900SAdrien Mazarguil ret = fwrite(buf, 1, size, file); 226771fa900SAdrien Mazarguil err = errno; 227771fa900SAdrien Mazarguil if (((size_t)ret < size) || (ferror(file))) 228771fa900SAdrien Mazarguil ret = -1; 229771fa900SAdrien Mazarguil else 230771fa900SAdrien Mazarguil ret = size; 231771fa900SAdrien Mazarguil fclose(file); 232771fa900SAdrien Mazarguil errno = err; 233771fa900SAdrien Mazarguil return ret; 234771fa900SAdrien Mazarguil } 235771fa900SAdrien Mazarguil 236771fa900SAdrien Mazarguil /** 237771fa900SAdrien Mazarguil * Get unsigned long sysfs property. 238771fa900SAdrien Mazarguil * 239771fa900SAdrien Mazarguil * @param priv 240771fa900SAdrien Mazarguil * Pointer to private structure. 241771fa900SAdrien Mazarguil * @param[in] name 242771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 243771fa900SAdrien Mazarguil * @param[out] value 244771fa900SAdrien Mazarguil * Value output buffer. 245771fa900SAdrien Mazarguil * 246771fa900SAdrien Mazarguil * @return 247771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 248771fa900SAdrien Mazarguil */ 249771fa900SAdrien Mazarguil static int 250771fa900SAdrien Mazarguil priv_get_sysfs_ulong(struct priv *priv, const char *name, unsigned long *value) 251771fa900SAdrien Mazarguil { 252771fa900SAdrien Mazarguil int ret; 253771fa900SAdrien Mazarguil unsigned long value_ret; 254771fa900SAdrien Mazarguil char value_str[32]; 255771fa900SAdrien Mazarguil 256771fa900SAdrien Mazarguil ret = priv_sysfs_read(priv, name, value_str, (sizeof(value_str) - 1)); 257771fa900SAdrien Mazarguil if (ret == -1) { 258771fa900SAdrien Mazarguil DEBUG("cannot read %s value from sysfs: %s", 259771fa900SAdrien Mazarguil name, strerror(errno)); 260771fa900SAdrien Mazarguil return -1; 261771fa900SAdrien Mazarguil } 262771fa900SAdrien Mazarguil value_str[ret] = '\0'; 263771fa900SAdrien Mazarguil errno = 0; 264771fa900SAdrien Mazarguil value_ret = strtoul(value_str, NULL, 0); 265771fa900SAdrien Mazarguil if (errno) { 266771fa900SAdrien Mazarguil DEBUG("invalid %s value `%s': %s", name, value_str, 267771fa900SAdrien Mazarguil strerror(errno)); 268771fa900SAdrien Mazarguil return -1; 269771fa900SAdrien Mazarguil } 270771fa900SAdrien Mazarguil *value = value_ret; 271771fa900SAdrien Mazarguil return 0; 272771fa900SAdrien Mazarguil } 273771fa900SAdrien Mazarguil 274771fa900SAdrien Mazarguil /** 275771fa900SAdrien Mazarguil * Set unsigned long sysfs property. 276771fa900SAdrien Mazarguil * 277771fa900SAdrien Mazarguil * @param priv 278771fa900SAdrien Mazarguil * Pointer to private structure. 279771fa900SAdrien Mazarguil * @param[in] name 280771fa900SAdrien Mazarguil * Entry name relative to sysfs path. 281771fa900SAdrien Mazarguil * @param value 282771fa900SAdrien Mazarguil * Value to set. 283771fa900SAdrien Mazarguil * 284771fa900SAdrien Mazarguil * @return 285771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 286771fa900SAdrien Mazarguil */ 287771fa900SAdrien Mazarguil static int 288771fa900SAdrien Mazarguil priv_set_sysfs_ulong(struct priv *priv, const char *name, unsigned long value) 289771fa900SAdrien Mazarguil { 290771fa900SAdrien Mazarguil int ret; 291771fa900SAdrien Mazarguil MKSTR(value_str, "%lu", value); 292771fa900SAdrien Mazarguil 293771fa900SAdrien Mazarguil ret = priv_sysfs_write(priv, name, value_str, (sizeof(value_str) - 1)); 294771fa900SAdrien Mazarguil if (ret == -1) { 295771fa900SAdrien Mazarguil DEBUG("cannot write %s `%s' (%lu) to sysfs: %s", 296771fa900SAdrien Mazarguil name, value_str, value, strerror(errno)); 297771fa900SAdrien Mazarguil return -1; 298771fa900SAdrien Mazarguil } 299771fa900SAdrien Mazarguil return 0; 300771fa900SAdrien Mazarguil } 301771fa900SAdrien Mazarguil 302771fa900SAdrien Mazarguil /** 303771fa900SAdrien Mazarguil * Perform ifreq ioctl() on associated Ethernet device. 304771fa900SAdrien Mazarguil * 305771fa900SAdrien Mazarguil * @param[in] priv 306771fa900SAdrien Mazarguil * Pointer to private structure. 307771fa900SAdrien Mazarguil * @param req 308771fa900SAdrien Mazarguil * Request number to pass to ioctl(). 309771fa900SAdrien Mazarguil * @param[out] ifr 310771fa900SAdrien Mazarguil * Interface request structure output buffer. 311771fa900SAdrien Mazarguil * 312771fa900SAdrien Mazarguil * @return 313771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 314771fa900SAdrien Mazarguil */ 315771fa900SAdrien Mazarguil int 316771fa900SAdrien Mazarguil priv_ifreq(const struct priv *priv, int req, struct ifreq *ifr) 317771fa900SAdrien Mazarguil { 318771fa900SAdrien Mazarguil int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 319771fa900SAdrien Mazarguil int ret = -1; 320771fa900SAdrien Mazarguil 321771fa900SAdrien Mazarguil if (sock == -1) 322771fa900SAdrien Mazarguil return ret; 323771fa900SAdrien Mazarguil if (priv_get_ifname(priv, &ifr->ifr_name) == 0) 324771fa900SAdrien Mazarguil ret = ioctl(sock, req, ifr); 325771fa900SAdrien Mazarguil close(sock); 326771fa900SAdrien Mazarguil return ret; 327771fa900SAdrien Mazarguil } 328771fa900SAdrien Mazarguil 329771fa900SAdrien Mazarguil /** 330771fa900SAdrien Mazarguil * Get device MTU. 331771fa900SAdrien Mazarguil * 332771fa900SAdrien Mazarguil * @param priv 333771fa900SAdrien Mazarguil * Pointer to private structure. 334771fa900SAdrien Mazarguil * @param[out] mtu 335771fa900SAdrien Mazarguil * MTU value output buffer. 336771fa900SAdrien Mazarguil * 337771fa900SAdrien Mazarguil * @return 338771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 339771fa900SAdrien Mazarguil */ 340771fa900SAdrien Mazarguil int 341771fa900SAdrien Mazarguil priv_get_mtu(struct priv *priv, uint16_t *mtu) 342771fa900SAdrien Mazarguil { 343771fa900SAdrien Mazarguil unsigned long ulong_mtu; 344771fa900SAdrien Mazarguil 345771fa900SAdrien Mazarguil if (priv_get_sysfs_ulong(priv, "mtu", &ulong_mtu) == -1) 346771fa900SAdrien Mazarguil return -1; 347771fa900SAdrien Mazarguil *mtu = ulong_mtu; 348771fa900SAdrien Mazarguil return 0; 349771fa900SAdrien Mazarguil } 350771fa900SAdrien Mazarguil 351771fa900SAdrien Mazarguil /** 352cf37ca95SAdrien Mazarguil * Set device MTU. 353cf37ca95SAdrien Mazarguil * 354cf37ca95SAdrien Mazarguil * @param priv 355cf37ca95SAdrien Mazarguil * Pointer to private structure. 356cf37ca95SAdrien Mazarguil * @param mtu 357cf37ca95SAdrien Mazarguil * MTU value to set. 358cf37ca95SAdrien Mazarguil * 359cf37ca95SAdrien Mazarguil * @return 360cf37ca95SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 361cf37ca95SAdrien Mazarguil */ 362cf37ca95SAdrien Mazarguil static int 363cf37ca95SAdrien Mazarguil priv_set_mtu(struct priv *priv, uint16_t mtu) 364cf37ca95SAdrien Mazarguil { 365cf37ca95SAdrien Mazarguil return priv_set_sysfs_ulong(priv, "mtu", mtu); 366cf37ca95SAdrien Mazarguil } 367cf37ca95SAdrien Mazarguil 368cf37ca95SAdrien Mazarguil /** 369771fa900SAdrien Mazarguil * Set device flags. 370771fa900SAdrien Mazarguil * 371771fa900SAdrien Mazarguil * @param priv 372771fa900SAdrien Mazarguil * Pointer to private structure. 373771fa900SAdrien Mazarguil * @param keep 374771fa900SAdrien Mazarguil * Bitmask for flags that must remain untouched. 375771fa900SAdrien Mazarguil * @param flags 376771fa900SAdrien Mazarguil * Bitmask for flags to modify. 377771fa900SAdrien Mazarguil * 378771fa900SAdrien Mazarguil * @return 379771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 380771fa900SAdrien Mazarguil */ 381771fa900SAdrien Mazarguil int 382771fa900SAdrien Mazarguil priv_set_flags(struct priv *priv, unsigned int keep, unsigned int flags) 383771fa900SAdrien Mazarguil { 384771fa900SAdrien Mazarguil unsigned long tmp; 385771fa900SAdrien Mazarguil 386771fa900SAdrien Mazarguil if (priv_get_sysfs_ulong(priv, "flags", &tmp) == -1) 387771fa900SAdrien Mazarguil return -1; 388771fa900SAdrien Mazarguil tmp &= keep; 389771fa900SAdrien Mazarguil tmp |= flags; 390771fa900SAdrien Mazarguil return priv_set_sysfs_ulong(priv, "flags", tmp); 391771fa900SAdrien Mazarguil } 392771fa900SAdrien Mazarguil 393771fa900SAdrien Mazarguil /** 394e60fbd5bSAdrien Mazarguil * Ethernet device configuration. 395e60fbd5bSAdrien Mazarguil * 396e60fbd5bSAdrien Mazarguil * Prepare the driver for a given number of TX and RX queues. 397e60fbd5bSAdrien Mazarguil * Allocate parent RSS queue when several RX queues are requested. 398e60fbd5bSAdrien Mazarguil * 399e60fbd5bSAdrien Mazarguil * @param dev 400e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 401e60fbd5bSAdrien Mazarguil * 402e60fbd5bSAdrien Mazarguil * @return 403e60fbd5bSAdrien Mazarguil * 0 on success, errno value on failure. 404e60fbd5bSAdrien Mazarguil */ 405e60fbd5bSAdrien Mazarguil static int 406e60fbd5bSAdrien Mazarguil dev_configure(struct rte_eth_dev *dev) 407e60fbd5bSAdrien Mazarguil { 408e60fbd5bSAdrien Mazarguil struct priv *priv = dev->data->dev_private; 409e60fbd5bSAdrien Mazarguil unsigned int rxqs_n = dev->data->nb_rx_queues; 410e60fbd5bSAdrien Mazarguil unsigned int txqs_n = dev->data->nb_tx_queues; 411e60fbd5bSAdrien Mazarguil unsigned int tmp; 412e60fbd5bSAdrien Mazarguil int ret; 413e60fbd5bSAdrien Mazarguil 414e60fbd5bSAdrien Mazarguil priv->rxqs = (void *)dev->data->rx_queues; 415e60fbd5bSAdrien Mazarguil priv->txqs = (void *)dev->data->tx_queues; 416e60fbd5bSAdrien Mazarguil if (txqs_n != priv->txqs_n) { 417e60fbd5bSAdrien Mazarguil INFO("%p: TX queues number update: %u -> %u", 418e60fbd5bSAdrien Mazarguil (void *)dev, priv->txqs_n, txqs_n); 419e60fbd5bSAdrien Mazarguil priv->txqs_n = txqs_n; 420e60fbd5bSAdrien Mazarguil } 421e60fbd5bSAdrien Mazarguil if (rxqs_n == priv->rxqs_n) 422e60fbd5bSAdrien Mazarguil return 0; 423e60fbd5bSAdrien Mazarguil INFO("%p: RX queues number update: %u -> %u", 424e60fbd5bSAdrien Mazarguil (void *)dev, priv->rxqs_n, rxqs_n); 425e60fbd5bSAdrien Mazarguil /* If RSS is enabled, disable it first. */ 426e60fbd5bSAdrien Mazarguil if (priv->rss) { 427e60fbd5bSAdrien Mazarguil unsigned int i; 428e60fbd5bSAdrien Mazarguil 429e60fbd5bSAdrien Mazarguil /* Only if there are no remaining child RX queues. */ 430e60fbd5bSAdrien Mazarguil for (i = 0; (i != priv->rxqs_n); ++i) 431e60fbd5bSAdrien Mazarguil if ((*priv->rxqs)[i] != NULL) 432e60fbd5bSAdrien Mazarguil return EINVAL; 433e60fbd5bSAdrien Mazarguil rxq_cleanup(&priv->rxq_parent); 434e60fbd5bSAdrien Mazarguil priv->rss = 0; 435e60fbd5bSAdrien Mazarguil priv->rxqs_n = 0; 436e60fbd5bSAdrien Mazarguil } 437e60fbd5bSAdrien Mazarguil if (rxqs_n <= 1) { 438e60fbd5bSAdrien Mazarguil /* Nothing else to do. */ 439e60fbd5bSAdrien Mazarguil priv->rxqs_n = rxqs_n; 440e60fbd5bSAdrien Mazarguil return 0; 441e60fbd5bSAdrien Mazarguil } 442e60fbd5bSAdrien Mazarguil /* Allocate a new RSS parent queue if supported by hardware. */ 443e60fbd5bSAdrien Mazarguil if (!priv->hw_rss) { 444e60fbd5bSAdrien Mazarguil ERROR("%p: only a single RX queue can be configured when" 445e60fbd5bSAdrien Mazarguil " hardware doesn't support RSS", 446e60fbd5bSAdrien Mazarguil (void *)dev); 447e60fbd5bSAdrien Mazarguil return EINVAL; 448e60fbd5bSAdrien Mazarguil } 449e60fbd5bSAdrien Mazarguil /* Fail if hardware doesn't support that many RSS queues. */ 450e60fbd5bSAdrien Mazarguil if (rxqs_n >= priv->max_rss_tbl_sz) { 451e60fbd5bSAdrien Mazarguil ERROR("%p: only %u RX queues can be configured for RSS", 452e60fbd5bSAdrien Mazarguil (void *)dev, priv->max_rss_tbl_sz); 453e60fbd5bSAdrien Mazarguil return EINVAL; 454e60fbd5bSAdrien Mazarguil } 455e60fbd5bSAdrien Mazarguil priv->rss = 1; 456e60fbd5bSAdrien Mazarguil tmp = priv->rxqs_n; 457e60fbd5bSAdrien Mazarguil priv->rxqs_n = rxqs_n; 458e60fbd5bSAdrien Mazarguil ret = rxq_setup(dev, &priv->rxq_parent, 0, 0, NULL, NULL); 459e60fbd5bSAdrien Mazarguil if (!ret) 460e60fbd5bSAdrien Mazarguil return 0; 461e60fbd5bSAdrien Mazarguil /* Failure, rollback. */ 462e60fbd5bSAdrien Mazarguil priv->rss = 0; 463e60fbd5bSAdrien Mazarguil priv->rxqs_n = tmp; 464e60fbd5bSAdrien Mazarguil assert(ret > 0); 465e60fbd5bSAdrien Mazarguil return ret; 466e60fbd5bSAdrien Mazarguil } 467e60fbd5bSAdrien Mazarguil 468e60fbd5bSAdrien Mazarguil /** 469e60fbd5bSAdrien Mazarguil * DPDK callback for Ethernet device configuration. 470e60fbd5bSAdrien Mazarguil * 471e60fbd5bSAdrien Mazarguil * @param dev 472e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 473e60fbd5bSAdrien Mazarguil * 474e60fbd5bSAdrien Mazarguil * @return 475e60fbd5bSAdrien Mazarguil * 0 on success, negative errno value on failure. 476e60fbd5bSAdrien Mazarguil */ 477e60fbd5bSAdrien Mazarguil int 478e60fbd5bSAdrien Mazarguil mlx5_dev_configure(struct rte_eth_dev *dev) 479e60fbd5bSAdrien Mazarguil { 480e60fbd5bSAdrien Mazarguil struct priv *priv = dev->data->dev_private; 481e60fbd5bSAdrien Mazarguil int ret; 482e60fbd5bSAdrien Mazarguil 483e60fbd5bSAdrien Mazarguil priv_lock(priv); 484e60fbd5bSAdrien Mazarguil ret = dev_configure(dev); 485e60fbd5bSAdrien Mazarguil assert(ret >= 0); 486e60fbd5bSAdrien Mazarguil priv_unlock(priv); 487e60fbd5bSAdrien Mazarguil return -ret; 488e60fbd5bSAdrien Mazarguil } 489e60fbd5bSAdrien Mazarguil 490e60fbd5bSAdrien Mazarguil /** 491e60fbd5bSAdrien Mazarguil * DPDK callback to get information about the device. 492e60fbd5bSAdrien Mazarguil * 493e60fbd5bSAdrien Mazarguil * @param dev 494e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 495e60fbd5bSAdrien Mazarguil * @param[out] info 496e60fbd5bSAdrien Mazarguil * Info structure output buffer. 497e60fbd5bSAdrien Mazarguil */ 498e60fbd5bSAdrien Mazarguil void 499e60fbd5bSAdrien Mazarguil mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) 500e60fbd5bSAdrien Mazarguil { 501e60fbd5bSAdrien Mazarguil struct priv *priv = dev->data->dev_private; 502e60fbd5bSAdrien Mazarguil unsigned int max; 503e60fbd5bSAdrien Mazarguil char ifname[IF_NAMESIZE]; 504e60fbd5bSAdrien Mazarguil 505e60fbd5bSAdrien Mazarguil priv_lock(priv); 506e60fbd5bSAdrien Mazarguil /* FIXME: we should ask the device for these values. */ 507e60fbd5bSAdrien Mazarguil info->min_rx_bufsize = 32; 508e60fbd5bSAdrien Mazarguil info->max_rx_pktlen = 65536; 509e60fbd5bSAdrien Mazarguil /* 510e60fbd5bSAdrien Mazarguil * Since we need one CQ per QP, the limit is the minimum number 511e60fbd5bSAdrien Mazarguil * between the two values. 512e60fbd5bSAdrien Mazarguil */ 513e60fbd5bSAdrien Mazarguil max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ? 514e60fbd5bSAdrien Mazarguil priv->device_attr.max_qp : priv->device_attr.max_cq); 515e60fbd5bSAdrien Mazarguil /* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */ 516e60fbd5bSAdrien Mazarguil if (max >= 65535) 517e60fbd5bSAdrien Mazarguil max = 65535; 518e60fbd5bSAdrien Mazarguil info->max_rx_queues = max; 519e60fbd5bSAdrien Mazarguil info->max_tx_queues = max; 520e60fbd5bSAdrien Mazarguil /* Last array entry is reserved for broadcast. */ 521e60fbd5bSAdrien Mazarguil info->max_mac_addrs = (RTE_DIM(priv->mac) - 1); 522e60fbd5bSAdrien Mazarguil info->rx_offload_capa = 523e60fbd5bSAdrien Mazarguil (priv->hw_csum ? 524e60fbd5bSAdrien Mazarguil (DEV_RX_OFFLOAD_IPV4_CKSUM | 525e60fbd5bSAdrien Mazarguil DEV_RX_OFFLOAD_UDP_CKSUM | 526e60fbd5bSAdrien Mazarguil DEV_RX_OFFLOAD_TCP_CKSUM) : 527e60fbd5bSAdrien Mazarguil 0); 528e60fbd5bSAdrien Mazarguil info->tx_offload_capa = 529e60fbd5bSAdrien Mazarguil (priv->hw_csum ? 530e60fbd5bSAdrien Mazarguil (DEV_TX_OFFLOAD_IPV4_CKSUM | 531e60fbd5bSAdrien Mazarguil DEV_TX_OFFLOAD_UDP_CKSUM | 532e60fbd5bSAdrien Mazarguil DEV_TX_OFFLOAD_TCP_CKSUM) : 533e60fbd5bSAdrien Mazarguil 0); 534e60fbd5bSAdrien Mazarguil if (priv_get_ifname(priv, &ifname) == 0) 535e60fbd5bSAdrien Mazarguil info->if_index = if_nametoindex(ifname); 536e60fbd5bSAdrien Mazarguil priv_unlock(priv); 537e60fbd5bSAdrien Mazarguil } 538e60fbd5bSAdrien Mazarguil 539e60fbd5bSAdrien Mazarguil /** 540*cb8faed7SAdrien Mazarguil * DPDK callback to retrieve physical link information (unlocked version). 541*cb8faed7SAdrien Mazarguil * 542*cb8faed7SAdrien Mazarguil * @param dev 543*cb8faed7SAdrien Mazarguil * Pointer to Ethernet device structure. 544*cb8faed7SAdrien Mazarguil * @param wait_to_complete 545*cb8faed7SAdrien Mazarguil * Wait for request completion (ignored). 546*cb8faed7SAdrien Mazarguil */ 547*cb8faed7SAdrien Mazarguil static int 548*cb8faed7SAdrien Mazarguil mlx5_link_update_unlocked(struct rte_eth_dev *dev, int wait_to_complete) 549*cb8faed7SAdrien Mazarguil { 550*cb8faed7SAdrien Mazarguil struct priv *priv = dev->data->dev_private; 551*cb8faed7SAdrien Mazarguil struct ethtool_cmd edata = { 552*cb8faed7SAdrien Mazarguil .cmd = ETHTOOL_GSET 553*cb8faed7SAdrien Mazarguil }; 554*cb8faed7SAdrien Mazarguil struct ifreq ifr; 555*cb8faed7SAdrien Mazarguil struct rte_eth_link dev_link; 556*cb8faed7SAdrien Mazarguil int link_speed = 0; 557*cb8faed7SAdrien Mazarguil 558*cb8faed7SAdrien Mazarguil (void)wait_to_complete; 559*cb8faed7SAdrien Mazarguil if (priv_ifreq(priv, SIOCGIFFLAGS, &ifr)) { 560*cb8faed7SAdrien Mazarguil WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(errno)); 561*cb8faed7SAdrien Mazarguil return -1; 562*cb8faed7SAdrien Mazarguil } 563*cb8faed7SAdrien Mazarguil memset(&dev_link, 0, sizeof(dev_link)); 564*cb8faed7SAdrien Mazarguil dev_link.link_status = ((ifr.ifr_flags & IFF_UP) && 565*cb8faed7SAdrien Mazarguil (ifr.ifr_flags & IFF_RUNNING)); 566*cb8faed7SAdrien Mazarguil ifr.ifr_data = &edata; 567*cb8faed7SAdrien Mazarguil if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) { 568*cb8faed7SAdrien Mazarguil WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s", 569*cb8faed7SAdrien Mazarguil strerror(errno)); 570*cb8faed7SAdrien Mazarguil return -1; 571*cb8faed7SAdrien Mazarguil } 572*cb8faed7SAdrien Mazarguil link_speed = ethtool_cmd_speed(&edata); 573*cb8faed7SAdrien Mazarguil if (link_speed == -1) 574*cb8faed7SAdrien Mazarguil dev_link.link_speed = 0; 575*cb8faed7SAdrien Mazarguil else 576*cb8faed7SAdrien Mazarguil dev_link.link_speed = link_speed; 577*cb8faed7SAdrien Mazarguil dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ? 578*cb8faed7SAdrien Mazarguil ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX); 579*cb8faed7SAdrien Mazarguil if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) { 580*cb8faed7SAdrien Mazarguil /* Link status changed. */ 581*cb8faed7SAdrien Mazarguil dev->data->dev_link = dev_link; 582*cb8faed7SAdrien Mazarguil return 0; 583*cb8faed7SAdrien Mazarguil } 584*cb8faed7SAdrien Mazarguil /* Link status is still the same. */ 585*cb8faed7SAdrien Mazarguil return -1; 586*cb8faed7SAdrien Mazarguil } 587*cb8faed7SAdrien Mazarguil 588*cb8faed7SAdrien Mazarguil /** 589*cb8faed7SAdrien Mazarguil * DPDK callback to retrieve physical link information. 590*cb8faed7SAdrien Mazarguil * 591*cb8faed7SAdrien Mazarguil * @param dev 592*cb8faed7SAdrien Mazarguil * Pointer to Ethernet device structure. 593*cb8faed7SAdrien Mazarguil * @param wait_to_complete 594*cb8faed7SAdrien Mazarguil * Wait for request completion (ignored). 595*cb8faed7SAdrien Mazarguil */ 596*cb8faed7SAdrien Mazarguil int 597*cb8faed7SAdrien Mazarguil mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete) 598*cb8faed7SAdrien Mazarguil { 599*cb8faed7SAdrien Mazarguil struct priv *priv = dev->data->dev_private; 600*cb8faed7SAdrien Mazarguil int ret; 601*cb8faed7SAdrien Mazarguil 602*cb8faed7SAdrien Mazarguil priv_lock(priv); 603*cb8faed7SAdrien Mazarguil ret = mlx5_link_update_unlocked(dev, wait_to_complete); 604*cb8faed7SAdrien Mazarguil priv_unlock(priv); 605*cb8faed7SAdrien Mazarguil return ret; 606*cb8faed7SAdrien Mazarguil } 607*cb8faed7SAdrien Mazarguil 608*cb8faed7SAdrien Mazarguil /** 609cf37ca95SAdrien Mazarguil * DPDK callback to change the MTU. 610cf37ca95SAdrien Mazarguil * 611cf37ca95SAdrien Mazarguil * Setting the MTU affects hardware MRU (packets larger than the MTU cannot be 612cf37ca95SAdrien Mazarguil * received). Use this as a hint to enable/disable scattered packets support 613cf37ca95SAdrien Mazarguil * and improve performance when not needed. 614cf37ca95SAdrien Mazarguil * Since failure is not an option, reconfiguring queues on the fly is not 615cf37ca95SAdrien Mazarguil * recommended. 616cf37ca95SAdrien Mazarguil * 617cf37ca95SAdrien Mazarguil * @param dev 618cf37ca95SAdrien Mazarguil * Pointer to Ethernet device structure. 619cf37ca95SAdrien Mazarguil * @param in_mtu 620cf37ca95SAdrien Mazarguil * New MTU. 621cf37ca95SAdrien Mazarguil * 622cf37ca95SAdrien Mazarguil * @return 623cf37ca95SAdrien Mazarguil * 0 on success, negative errno value on failure. 624cf37ca95SAdrien Mazarguil */ 625cf37ca95SAdrien Mazarguil int 626cf37ca95SAdrien Mazarguil mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu) 627cf37ca95SAdrien Mazarguil { 628cf37ca95SAdrien Mazarguil struct priv *priv = dev->data->dev_private; 629cf37ca95SAdrien Mazarguil int ret = 0; 630cf37ca95SAdrien Mazarguil unsigned int i; 631cf37ca95SAdrien Mazarguil uint16_t (*rx_func)(void *, struct rte_mbuf **, uint16_t) = 632cf37ca95SAdrien Mazarguil mlx5_rx_burst; 633cf37ca95SAdrien Mazarguil 634cf37ca95SAdrien Mazarguil priv_lock(priv); 635cf37ca95SAdrien Mazarguil /* Set kernel interface MTU first. */ 636cf37ca95SAdrien Mazarguil if (priv_set_mtu(priv, mtu)) { 637cf37ca95SAdrien Mazarguil ret = errno; 638cf37ca95SAdrien Mazarguil WARN("cannot set port %u MTU to %u: %s", priv->port, mtu, 639cf37ca95SAdrien Mazarguil strerror(ret)); 640cf37ca95SAdrien Mazarguil goto out; 641cf37ca95SAdrien Mazarguil } else 642cf37ca95SAdrien Mazarguil DEBUG("adapter port %u MTU set to %u", priv->port, mtu); 643cf37ca95SAdrien Mazarguil priv->mtu = mtu; 644cf37ca95SAdrien Mazarguil /* Temporarily replace RX handler with a fake one, assuming it has not 645cf37ca95SAdrien Mazarguil * been copied elsewhere. */ 646cf37ca95SAdrien Mazarguil dev->rx_pkt_burst = removed_rx_burst; 647cf37ca95SAdrien Mazarguil /* Make sure everyone has left mlx5_rx_burst() and uses 648cf37ca95SAdrien Mazarguil * removed_rx_burst() instead. */ 649cf37ca95SAdrien Mazarguil rte_wmb(); 650cf37ca95SAdrien Mazarguil usleep(1000); 651cf37ca95SAdrien Mazarguil /* Reconfigure each RX queue. */ 652cf37ca95SAdrien Mazarguil for (i = 0; (i != priv->rxqs_n); ++i) { 653cf37ca95SAdrien Mazarguil struct rxq *rxq = (*priv->rxqs)[i]; 654cf37ca95SAdrien Mazarguil unsigned int max_frame_len; 655cf37ca95SAdrien Mazarguil int sp; 656cf37ca95SAdrien Mazarguil 657cf37ca95SAdrien Mazarguil if (rxq == NULL) 658cf37ca95SAdrien Mazarguil continue; 659cf37ca95SAdrien Mazarguil /* Calculate new maximum frame length according to MTU and 660cf37ca95SAdrien Mazarguil * toggle scattered support (sp) if necessary. */ 661cf37ca95SAdrien Mazarguil max_frame_len = (priv->mtu + ETHER_HDR_LEN + 662cf37ca95SAdrien Mazarguil (ETHER_MAX_VLAN_FRAME_LEN - ETHER_MAX_LEN)); 663cf37ca95SAdrien Mazarguil sp = (max_frame_len > (rxq->mb_len - RTE_PKTMBUF_HEADROOM)); 664cf37ca95SAdrien Mazarguil /* Provide new values to rxq_setup(). */ 665cf37ca95SAdrien Mazarguil dev->data->dev_conf.rxmode.jumbo_frame = sp; 666cf37ca95SAdrien Mazarguil dev->data->dev_conf.rxmode.max_rx_pkt_len = max_frame_len; 667cf37ca95SAdrien Mazarguil ret = rxq_rehash(dev, rxq); 668cf37ca95SAdrien Mazarguil if (ret) { 669cf37ca95SAdrien Mazarguil /* Force SP RX if that queue requires it and abort. */ 670cf37ca95SAdrien Mazarguil if (rxq->sp) 671cf37ca95SAdrien Mazarguil rx_func = mlx5_rx_burst_sp; 672cf37ca95SAdrien Mazarguil break; 673cf37ca95SAdrien Mazarguil } 674cf37ca95SAdrien Mazarguil /* Reenable non-RSS queue attributes. No need to check 675cf37ca95SAdrien Mazarguil * for errors at this stage. */ 676cf37ca95SAdrien Mazarguil if (!priv->rss) { 677cf37ca95SAdrien Mazarguil if (priv->started) 678cf37ca95SAdrien Mazarguil rxq_mac_addrs_add(rxq); 6791bdbe1afSAdrien Mazarguil if (priv->started && priv->promisc_req) 6801bdbe1afSAdrien Mazarguil rxq_promiscuous_enable(rxq); 6811bdbe1afSAdrien Mazarguil if (priv->started && priv->allmulti_req) 6821bdbe1afSAdrien Mazarguil rxq_allmulticast_enable(rxq); 683cf37ca95SAdrien Mazarguil } 684cf37ca95SAdrien Mazarguil /* Scattered burst function takes priority. */ 685cf37ca95SAdrien Mazarguil if (rxq->sp) 686cf37ca95SAdrien Mazarguil rx_func = mlx5_rx_burst_sp; 687cf37ca95SAdrien Mazarguil } 688cf37ca95SAdrien Mazarguil /* Burst functions can now be called again. */ 689cf37ca95SAdrien Mazarguil rte_wmb(); 690cf37ca95SAdrien Mazarguil dev->rx_pkt_burst = rx_func; 691cf37ca95SAdrien Mazarguil out: 692cf37ca95SAdrien Mazarguil priv_unlock(priv); 693cf37ca95SAdrien Mazarguil assert(ret >= 0); 694cf37ca95SAdrien Mazarguil return -ret; 695cf37ca95SAdrien Mazarguil } 696cf37ca95SAdrien Mazarguil 697cf37ca95SAdrien Mazarguil /** 698771fa900SAdrien Mazarguil * Get PCI information from struct ibv_device. 699771fa900SAdrien Mazarguil * 700771fa900SAdrien Mazarguil * @param device 701771fa900SAdrien Mazarguil * Pointer to Ethernet device structure. 702771fa900SAdrien Mazarguil * @param[out] pci_addr 703771fa900SAdrien Mazarguil * PCI bus address output buffer. 704771fa900SAdrien Mazarguil * 705771fa900SAdrien Mazarguil * @return 706771fa900SAdrien Mazarguil * 0 on success, -1 on failure and errno is set. 707771fa900SAdrien Mazarguil */ 708771fa900SAdrien Mazarguil int 709771fa900SAdrien Mazarguil mlx5_ibv_device_to_pci_addr(const struct ibv_device *device, 710771fa900SAdrien Mazarguil struct rte_pci_addr *pci_addr) 711771fa900SAdrien Mazarguil { 712771fa900SAdrien Mazarguil FILE *file; 713771fa900SAdrien Mazarguil char line[32]; 714771fa900SAdrien Mazarguil MKSTR(path, "%s/device/uevent", device->ibdev_path); 715771fa900SAdrien Mazarguil 716771fa900SAdrien Mazarguil file = fopen(path, "rb"); 717771fa900SAdrien Mazarguil if (file == NULL) 718771fa900SAdrien Mazarguil return -1; 719771fa900SAdrien Mazarguil while (fgets(line, sizeof(line), file) == line) { 720771fa900SAdrien Mazarguil size_t len = strlen(line); 721771fa900SAdrien Mazarguil int ret; 722771fa900SAdrien Mazarguil 723771fa900SAdrien Mazarguil /* Truncate long lines. */ 724771fa900SAdrien Mazarguil if (len == (sizeof(line) - 1)) 725771fa900SAdrien Mazarguil while (line[(len - 1)] != '\n') { 726771fa900SAdrien Mazarguil ret = fgetc(file); 727771fa900SAdrien Mazarguil if (ret == EOF) 728771fa900SAdrien Mazarguil break; 729771fa900SAdrien Mazarguil line[(len - 1)] = ret; 730771fa900SAdrien Mazarguil } 731771fa900SAdrien Mazarguil /* Extract information. */ 732771fa900SAdrien Mazarguil if (sscanf(line, 733771fa900SAdrien Mazarguil "PCI_SLOT_NAME=" 734771fa900SAdrien Mazarguil "%" SCNx16 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n", 735771fa900SAdrien Mazarguil &pci_addr->domain, 736771fa900SAdrien Mazarguil &pci_addr->bus, 737771fa900SAdrien Mazarguil &pci_addr->devid, 738771fa900SAdrien Mazarguil &pci_addr->function) == 4) { 739771fa900SAdrien Mazarguil ret = 0; 740771fa900SAdrien Mazarguil break; 741771fa900SAdrien Mazarguil } 742771fa900SAdrien Mazarguil } 743771fa900SAdrien Mazarguil fclose(file); 744771fa900SAdrien Mazarguil return 0; 745771fa900SAdrien Mazarguil } 746