aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/failsafe/failsafe_eal.c
blob: ce1633f1399bd061769debdded5dd3ed904e3abe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright 2017 6WIND S.A.
 * Copyright 2017 Mellanox Technologies, Ltd
 */

#include <rte_malloc.h>

#include "failsafe_private.h"

static int
fs_ethdev_portid_get(const char *name, uint16_t *port_id)
{
	uint16_t pid;
	size_t len;

	if (name == NULL) {
		DEBUG("Null pointer is specified\n");
		return -EINVAL;
	}
	len = strlen(name);
	for (pid = 0; pid < RTE_MAX_ETHPORTS; pid++) {
		if (rte_eth_dev_is_valid_port(pid) &&
		    !strncmp(name, rte_eth_devices[pid].device->name, len)) {
			*port_id = pid;
			return 0;
		}
	}
	return -ENODEV;
}

static int
fs_bus_init(struct rte_eth_dev *dev)
{
	struct sub_device *sdev;
	struct rte_devargs *da;
	uint8_t i;
	uint16_t pid;
	int ret;

	FOREACH_SUBDEV(sdev, i, dev) {
		if (sdev->state != DEV_PARSED)
			continue;
		da = &sdev->devargs;
		if (fs_ethdev_portid_get(da->name, &pid) != 0) {
			struct rte_eth_dev_owner pid_owner;

			ret = rte_eal_hotplug_add(da->bus->name,
						  da->name,
						  da->args);
			if (ret) {
				ERROR("sub_device %d probe failed %s%s%s", i,
				      rte_errno ? "(" : "",
				      rte_errno ? strerror(rte_errno) : "",
				      rte_errno ? ")" : "");
				continue;
			}
			if (fs_ethdev_portid_get(da->name, &pid) != 0) {
				ERROR("sub_device %d init went wrong", i);
				return -ENODEV;
			}
			/*
			 * The NEW callback tried to take ownership, check
			 * whether it succeed or didn't.
			 */
			rte_eth_dev_owner_get(pid, &pid_owner);
			if (pid_owner.id != PRIV(dev)->my_owner.id) {
				INFO("sub_device %d owner(%s_%016"PRIX64") is not my,"
				     " owner(%s_%016"PRIX64"), will try again later",
				     i, pid_owner.name, pid_owner.id,
				     PRIV(dev)->my_owner.name,
				     PRIV(dev)->my_owner.id);
				continue;
			}
		} else {
			/* The sub-device port was found. */
			char devstr[DEVARGS_MAXLEN] = "";
			struct rte_devargs *probed_da =
					rte_eth_devices[pid].device->devargs;

			/* Take control of probed device. */
			free(da->args);
			memset(da, 0, sizeof(*da));
			if (probed_da != NULL)
				snprintf(devstr, sizeof(devstr), "%s,%s",
					 probed_da->name, probed_da->args);
			else
				snprintf(devstr, sizeof(devstr), "%s",
					 rte_eth_devices[pid].device->name);
			ret = rte_devargs_parse(da, devstr);
			if (ret) {
				ERROR("Probed devargs parsing failed with code"
				      " %d", ret);
				return ret;
			}
			INFO("Taking control of a probed sub device"
			      " %d named %s", i, da->name);
			ret = rte_eth_dev_owner_set(pid, &PRIV(dev)->my_owner);
			if (ret < 0) {
				INFO("sub_device %d owner set failed (%s), "
				     "will try again later", i, strerror(-ret));
				continue;
			} else if (strncmp(rte_eth_devices[pid].device->name,
				   da->name, strlen(da->name)) != 0) {
				/*
				 * The device probably was removed and its port
				 * id was reallocated before ownership set.
				 */
				rte_eth_dev_owner_unset(pid,
							PRIV(dev)->my_owner.id);
				INFO("sub_device %d was removed before taking"
				     " ownership, will try again later", i);
				continue;
			}
		}
		ETH(sdev) = &rte_eth_devices[pid];
		SUB_ID(sdev) = i;
		sdev->fs_dev = dev;
		sdev->dev = ETH(sdev)->device;
		sdev->state = DEV_PROBED;
	}
	return 0;
}

int
failsafe_eal_init(struct rte_eth_dev *dev)
{
	int ret;

	ret = fs_bus_init(dev);
	if (ret)
		return ret;
	if (PRIV(dev)->state < DEV_PROBED)
		PRIV(dev)->state = DEV_PROBED;
	fs_switch_dev(dev, NULL);
	return 0;
}

static int
fs_bus_uninit(struct rte_eth_dev *dev)
{
	struct sub_device *sdev = NULL;
	uint8_t i;
	int sdev_ret;
	int ret = 0;

	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
		sdev_ret = rte_eal_hotplug_remove(sdev->bus->name,
							sdev->dev->name);
		if (sdev_ret) {
			ERROR("Failed to remove requested device %s (err: %d)",
			      sdev->dev->name, sdev_ret);
			continue;
		}
		sdev->state = DEV_PROBED - 1;
	}
	return ret;
}

int
failsafe_eal_uninit(struct rte_eth_dev *dev)
{
	int ret;

	ret = fs_bus_uninit(dev);
	PRIV(dev)->state = DEV_PROBED - 1;
	return ret;
}