1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 2a46f8d58SGaetan Rivet * Copyright 2017 6WIND S.A. 35feecc57SShahaf Shuler * Copyright 2017 Mellanox Technologies, Ltd 4a46f8d58SGaetan Rivet */ 5a46f8d58SGaetan Rivet 6a04322f6SDavid Marchand #include <bus_driver.h> 76723c0fcSBruce Richardson #include <rte_string_fns.h> 8a46f8d58SGaetan Rivet #include <rte_malloc.h> 9a46f8d58SGaetan Rivet 10a46f8d58SGaetan Rivet #include "failsafe_private.h" 11a46f8d58SGaetan Rivet 12a46f8d58SGaetan Rivet static int 1353a2d53fSMatan Azrad fs_ethdev_portid_get(const char *name, uint16_t *port_id) 1453a2d53fSMatan Azrad { 1553a2d53fSMatan Azrad uint16_t pid; 1653a2d53fSMatan Azrad size_t len; 1753a2d53fSMatan Azrad 1853a2d53fSMatan Azrad if (name == NULL) { 19*f665790aSDavid Marchand DEBUG("Null pointer is specified"); 2053a2d53fSMatan Azrad return -EINVAL; 2153a2d53fSMatan Azrad } 2253a2d53fSMatan Azrad len = strlen(name); 237fda13d3SMatan Azrad for (pid = 0; pid < RTE_MAX_ETHPORTS; pid++) { 247fda13d3SMatan Azrad if (rte_eth_dev_is_valid_port(pid) && 257fda13d3SMatan Azrad !strncmp(name, rte_eth_devices[pid].device->name, len)) { 2653a2d53fSMatan Azrad *port_id = pid; 2753a2d53fSMatan Azrad return 0; 2853a2d53fSMatan Azrad } 2953a2d53fSMatan Azrad } 3053a2d53fSMatan Azrad return -ENODEV; 3153a2d53fSMatan Azrad } 3253a2d53fSMatan Azrad 3353a2d53fSMatan Azrad static int 34a46f8d58SGaetan Rivet fs_bus_init(struct rte_eth_dev *dev) 35a46f8d58SGaetan Rivet { 36a46f8d58SGaetan Rivet struct sub_device *sdev; 37a46f8d58SGaetan Rivet struct rte_devargs *da; 38a46f8d58SGaetan Rivet uint8_t i; 3953a2d53fSMatan Azrad uint16_t pid; 40a46f8d58SGaetan Rivet int ret; 41a46f8d58SGaetan Rivet 42a46f8d58SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 43a46f8d58SGaetan Rivet if (sdev->state != DEV_PARSED) 44a46f8d58SGaetan Rivet continue; 45a46f8d58SGaetan Rivet da = &sdev->devargs; 4653a2d53fSMatan Azrad if (fs_ethdev_portid_get(da->name, &pid) != 0) { 477fda13d3SMatan Azrad struct rte_eth_dev_owner pid_owner; 487fda13d3SMatan Azrad 49a46f8d58SGaetan Rivet ret = rte_eal_hotplug_add(da->bus->name, 50a46f8d58SGaetan Rivet da->name, 51a46f8d58SGaetan Rivet da->args); 5275b66decSIlya Maximets if (ret < 0) { 53a46f8d58SGaetan Rivet ERROR("sub_device %d probe failed %s%s%s", i, 54a46f8d58SGaetan Rivet rte_errno ? "(" : "", 55a46f8d58SGaetan Rivet rte_errno ? strerror(rte_errno) : "", 56a46f8d58SGaetan Rivet rte_errno ? ")" : ""); 57a46f8d58SGaetan Rivet continue; 58a46f8d58SGaetan Rivet } 5953a2d53fSMatan Azrad if (fs_ethdev_portid_get(da->name, &pid) != 0) { 60a46f8d58SGaetan Rivet ERROR("sub_device %d init went wrong", i); 61a46f8d58SGaetan Rivet return -ENODEV; 62a46f8d58SGaetan Rivet } 637fda13d3SMatan Azrad /* 647fda13d3SMatan Azrad * The NEW callback tried to take ownership, check 657fda13d3SMatan Azrad * whether it succeed or didn't. 667fda13d3SMatan Azrad */ 677fda13d3SMatan Azrad rte_eth_dev_owner_get(pid, &pid_owner); 687fda13d3SMatan Azrad if (pid_owner.id != PRIV(dev)->my_owner.id) { 697fda13d3SMatan Azrad INFO("sub_device %d owner(%s_%016"PRIX64") is not my," 707fda13d3SMatan Azrad " owner(%s_%016"PRIX64"), will try again later", 717fda13d3SMatan Azrad i, pid_owner.name, pid_owner.id, 727fda13d3SMatan Azrad PRIV(dev)->my_owner.name, 737fda13d3SMatan Azrad PRIV(dev)->my_owner.id); 747fda13d3SMatan Azrad continue; 757fda13d3SMatan Azrad } 7653a2d53fSMatan Azrad } else { 777fda13d3SMatan Azrad /* The sub-device port was found. */ 7853a2d53fSMatan Azrad char devstr[DEVARGS_MAXLEN] = ""; 7953a2d53fSMatan Azrad struct rte_devargs *probed_da = 8053a2d53fSMatan Azrad rte_eth_devices[pid].device->devargs; 8153a2d53fSMatan Azrad 827fda13d3SMatan Azrad /* Take control of probed device. */ 8364051bb1SXueming Li rte_devargs_reset(da); 8453a2d53fSMatan Azrad memset(da, 0, sizeof(*da)); 8553a2d53fSMatan Azrad if (probed_da != NULL) 8653a2d53fSMatan Azrad snprintf(devstr, sizeof(devstr), "%s,%s", 8753a2d53fSMatan Azrad probed_da->name, probed_da->args); 8853a2d53fSMatan Azrad else 896723c0fcSBruce Richardson strlcpy(devstr, 906723c0fcSBruce Richardson rte_eth_devices[pid].device->name, 916723c0fcSBruce Richardson sizeof(devstr)); 92a23bc2c4SGaetan Rivet ret = rte_devargs_parse(da, devstr); 9353a2d53fSMatan Azrad if (ret) { 9453a2d53fSMatan Azrad ERROR("Probed devargs parsing failed with code" 9553a2d53fSMatan Azrad " %d", ret); 9653a2d53fSMatan Azrad return ret; 9753a2d53fSMatan Azrad } 9853a2d53fSMatan Azrad INFO("Taking control of a probed sub device" 9953a2d53fSMatan Azrad " %d named %s", i, da->name); 100dcd0c9c3SMatan Azrad ret = rte_eth_dev_owner_set(pid, &PRIV(dev)->my_owner); 1019df324adSGaetan Rivet if (ret < 0) { 102dcd0c9c3SMatan Azrad INFO("sub_device %d owner set failed (%s), " 1039df324adSGaetan Rivet "will try again later", i, strerror(-ret)); 104dcd0c9c3SMatan Azrad continue; 1057fda13d3SMatan Azrad } else if (strncmp(rte_eth_devices[pid].device->name, 1067fda13d3SMatan Azrad da->name, strlen(da->name)) != 0) { 107dcd0c9c3SMatan Azrad /* 1087fda13d3SMatan Azrad * The device probably was removed and its port 1097fda13d3SMatan Azrad * id was reallocated before ownership set. 110dcd0c9c3SMatan Azrad */ 1117fda13d3SMatan Azrad rte_eth_dev_owner_unset(pid, 1127fda13d3SMatan Azrad PRIV(dev)->my_owner.id); 1137fda13d3SMatan Azrad INFO("sub_device %d was removed before taking" 114dcd0c9c3SMatan Azrad " ownership, will try again later", i); 115dcd0c9c3SMatan Azrad continue; 116dcd0c9c3SMatan Azrad } 1177fda13d3SMatan Azrad } 1182f4b9983SRaslan Darawsheh sdev->sdev_port_id = pid; 119b737a1eeSGaetan Rivet SUB_ID(sdev) = i; 120fa7bb47aSRaslan Darawsheh sdev->fs_port_id = dev->data->port_id; 121a46f8d58SGaetan Rivet sdev->dev = ETH(sdev)->device; 122a46f8d58SGaetan Rivet sdev->state = DEV_PROBED; 123a46f8d58SGaetan Rivet } 124a46f8d58SGaetan Rivet return 0; 125a46f8d58SGaetan Rivet } 126a46f8d58SGaetan Rivet 127a46f8d58SGaetan Rivet int 128a46f8d58SGaetan Rivet failsafe_eal_init(struct rte_eth_dev *dev) 129a46f8d58SGaetan Rivet { 130a46f8d58SGaetan Rivet int ret; 131a46f8d58SGaetan Rivet 132a46f8d58SGaetan Rivet ret = fs_bus_init(dev); 133a46f8d58SGaetan Rivet if (ret) 134a46f8d58SGaetan Rivet return ret; 135ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_PROBED) 136ebea83f8SGaetan Rivet PRIV(dev)->state = DEV_PROBED; 137598fb8aeSGaetan Rivet fs_switch_dev(dev, NULL); 138a46f8d58SGaetan Rivet return 0; 139a46f8d58SGaetan Rivet } 140a46f8d58SGaetan Rivet 141a46f8d58SGaetan Rivet static int 142a46f8d58SGaetan Rivet fs_bus_uninit(struct rte_eth_dev *dev) 143a46f8d58SGaetan Rivet { 144a46f8d58SGaetan Rivet struct sub_device *sdev = NULL; 145a46f8d58SGaetan Rivet uint8_t i; 1466969a22bSRaslan Darawsheh int sdev_ret; 1476969a22bSRaslan Darawsheh int ret = 0; 148a46f8d58SGaetan Rivet 149a46f8d58SGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) { 150911462ebSThomas Monjalon sdev_ret = rte_dev_remove(sdev->dev); 15175b66decSIlya Maximets if (sdev_ret < 0) { 1526969a22bSRaslan Darawsheh ERROR("Failed to remove requested device %s (err: %d)", 1536969a22bSRaslan Darawsheh sdev->dev->name, sdev_ret); 154a46f8d58SGaetan Rivet continue; 155a46f8d58SGaetan Rivet } 156a46f8d58SGaetan Rivet sdev->state = DEV_PROBED - 1; 157a46f8d58SGaetan Rivet } 1586969a22bSRaslan Darawsheh return ret; 159a46f8d58SGaetan Rivet } 160a46f8d58SGaetan Rivet 161a46f8d58SGaetan Rivet int 162a46f8d58SGaetan Rivet failsafe_eal_uninit(struct rte_eth_dev *dev) 163a46f8d58SGaetan Rivet { 164a46f8d58SGaetan Rivet int ret; 165a46f8d58SGaetan Rivet 166a46f8d58SGaetan Rivet ret = fs_bus_uninit(dev); 167ebea83f8SGaetan Rivet PRIV(dev)->state = DEV_PROBED - 1; 1686969a22bSRaslan Darawsheh return ret; 169a46f8d58SGaetan Rivet } 170