net/failsafe: fix hotplug alarm cancel
[dpdk.git] / drivers / net / failsafe / failsafe.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017 6WIND S.A.
3  * Copyright 2017 Mellanox.
4  */
5
6 #include <rte_alarm.h>
7 #include <rte_malloc.h>
8 #include <rte_ethdev_driver.h>
9 #include <rte_ethdev_vdev.h>
10 #include <rte_devargs.h>
11 #include <rte_kvargs.h>
12 #include <rte_bus_vdev.h>
13
14 #include "failsafe_private.h"
15
16 const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME;
17 static const struct rte_eth_link eth_link = {
18         .link_speed = ETH_SPEED_NUM_10G,
19         .link_duplex = ETH_LINK_FULL_DUPLEX,
20         .link_status = ETH_LINK_UP,
21         .link_autoneg = ETH_LINK_AUTONEG,
22 };
23
24 static int
25 fs_sub_device_alloc(struct rte_eth_dev *dev,
26                 const char *params)
27 {
28         uint8_t nb_subs;
29         int ret;
30         int i;
31
32         ret = failsafe_args_count_subdevice(dev, params);
33         if (ret)
34                 return ret;
35         if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) {
36                 ERROR("Cannot allocate more than %d ports",
37                         FAILSAFE_MAX_ETHPORTS);
38                 return -ENOSPC;
39         }
40         nb_subs = PRIV(dev)->subs_tail;
41         PRIV(dev)->subs = rte_zmalloc(NULL,
42                         sizeof(struct sub_device) * nb_subs,
43                         RTE_CACHE_LINE_SIZE);
44         if (PRIV(dev)->subs == NULL) {
45                 ERROR("Could not allocate sub_devices");
46                 return -ENOMEM;
47         }
48         /* Initiate static sub devices linked list. */
49         for (i = 1; i < nb_subs; i++)
50                 PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i;
51         PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs;
52         return 0;
53 }
54
55 static void
56 fs_sub_device_free(struct rte_eth_dev *dev)
57 {
58         rte_free(PRIV(dev)->subs);
59 }
60
61 static void fs_hotplug_alarm(void *arg);
62
63 int
64 failsafe_hotplug_alarm_install(struct rte_eth_dev *dev)
65 {
66         int ret;
67
68         if (dev == NULL)
69                 return -EINVAL;
70         if (PRIV(dev)->pending_alarm)
71                 return 0;
72         ret = rte_eal_alarm_set(hotplug_poll * 1000,
73                                 fs_hotplug_alarm,
74                                 dev);
75         if (ret) {
76                 ERROR("Could not set up plug-in event detection");
77                 return ret;
78         }
79         PRIV(dev)->pending_alarm = 1;
80         return 0;
81 }
82
83 int
84 failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev)
85 {
86         int ret = 0;
87
88         rte_errno = 0;
89         rte_eal_alarm_cancel(fs_hotplug_alarm, dev);
90         if (rte_errno) {
91                 ERROR("rte_eal_alarm_cancel failed (errno: %s)",
92                       strerror(rte_errno));
93                 ret = -rte_errno;
94         } else {
95                 PRIV(dev)->pending_alarm = 0;
96         }
97         return ret;
98 }
99
100 static void
101 fs_hotplug_alarm(void *arg)
102 {
103         struct rte_eth_dev *dev = arg;
104         struct sub_device *sdev;
105         int ret;
106         uint8_t i;
107
108         if (!PRIV(dev)->pending_alarm)
109                 return;
110         PRIV(dev)->pending_alarm = 0;
111         FOREACH_SUBDEV(sdev, i, dev)
112                 if (sdev->state != PRIV(dev)->state)
113                         break;
114         /* if we have non-probed device */
115         if (i != PRIV(dev)->subs_tail) {
116                 ret = failsafe_eth_dev_state_sync(dev);
117                 if (ret)
118                         ERROR("Unable to synchronize sub_device state");
119         }
120         failsafe_dev_remove(dev);
121         ret = failsafe_hotplug_alarm_install(dev);
122         if (ret)
123                 ERROR("Unable to set up next alarm");
124 }
125
126 static int
127 fs_eth_dev_create(struct rte_vdev_device *vdev)
128 {
129         struct rte_eth_dev *dev;
130         struct ether_addr *mac;
131         struct fs_priv *priv;
132         struct sub_device *sdev;
133         const char *params;
134         unsigned int socket_id;
135         uint8_t i;
136         int ret;
137
138         dev = NULL;
139         priv = NULL;
140         socket_id = rte_socket_id();
141         INFO("Creating fail-safe device on NUMA socket %u", socket_id);
142         params = rte_vdev_device_args(vdev);
143         if (params == NULL) {
144                 ERROR("This PMD requires sub-devices, none provided");
145                 return -1;
146         }
147         dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
148         if (dev == NULL) {
149                 ERROR("Unable to allocate rte_eth_dev");
150                 return -1;
151         }
152         priv = PRIV(dev);
153         priv->dev = dev;
154         dev->dev_ops = &failsafe_ops;
155         dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
156         dev->data->dev_link = eth_link;
157         PRIV(dev)->nb_mac_addr = 1;
158         TAILQ_INIT(&PRIV(dev)->flow_list);
159         dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
160         dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
161         ret = fs_sub_device_alloc(dev, params);
162         if (ret) {
163                 ERROR("Could not allocate sub_devices");
164                 goto free_dev;
165         }
166         ret = failsafe_args_parse(dev, params);
167         if (ret)
168                 goto free_subs;
169         ret = rte_eth_dev_owner_new(&priv->my_owner.id);
170         if (ret) {
171                 ERROR("Failed to get unique owner identifier");
172                 goto free_args;
173         }
174         snprintf(priv->my_owner.name, sizeof(priv->my_owner.name),
175                  FAILSAFE_OWNER_NAME);
176         ret = failsafe_eal_init(dev);
177         if (ret)
178                 goto free_args;
179         ret = failsafe_hotplug_alarm_install(dev);
180         if (ret) {
181                 ERROR("Could not set up plug-in event detection");
182                 goto free_args;
183         }
184         mac = &dev->data->mac_addrs[0];
185         if (mac_from_arg) {
186                 /*
187                  * If MAC address was provided as a parameter,
188                  * apply to all probed slaves.
189                  */
190                 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
191                         ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
192                                                                mac);
193                         if (ret) {
194                                 ERROR("Failed to set default MAC address");
195                                 goto free_args;
196                         }
197                 }
198         } else {
199                 /*
200                  * Use the ether_addr from first probed
201                  * device, either preferred or fallback.
202                  */
203                 FOREACH_SUBDEV(sdev, i, dev)
204                         if (sdev->state >= DEV_PROBED) {
205                                 ether_addr_copy(&ETH(sdev)->data->mac_addrs[0],
206                                                 mac);
207                                 break;
208                         }
209                 /*
210                  * If no device has been probed and no ether_addr
211                  * has been provided on the command line, use a random
212                  * valid one.
213                  * It will be applied during future slave state syncs to
214                  * probed slaves.
215                  */
216                 if (i == priv->subs_tail)
217                         eth_random_addr(&mac->addr_bytes[0]);
218         }
219         INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
220                 mac->addr_bytes[0], mac->addr_bytes[1],
221                 mac->addr_bytes[2], mac->addr_bytes[3],
222                 mac->addr_bytes[4], mac->addr_bytes[5]);
223         dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
224         PRIV(dev)->intr_handle = (struct rte_intr_handle){
225                 .fd = -1,
226                 .type = RTE_INTR_HANDLE_EXT,
227         };
228         return 0;
229 free_args:
230         failsafe_args_free(dev);
231 free_subs:
232         fs_sub_device_free(dev);
233 free_dev:
234         rte_free(PRIV(dev));
235         rte_eth_dev_release_port(dev);
236         return -1;
237 }
238
239 static int
240 fs_rte_eth_free(const char *name)
241 {
242         struct rte_eth_dev *dev;
243         int ret;
244
245         dev = rte_eth_dev_allocated(name);
246         if (dev == NULL)
247                 return -ENODEV;
248         ret = failsafe_eal_uninit(dev);
249         if (ret)
250                 ERROR("Error while uninitializing sub-EAL");
251         failsafe_args_free(dev);
252         fs_sub_device_free(dev);
253         rte_free(PRIV(dev));
254         rte_eth_dev_release_port(dev);
255         return ret;
256 }
257
258 static int
259 rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
260 {
261         const char *name;
262
263         name = rte_vdev_device_name(vdev);
264         INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
265                         name);
266         return fs_eth_dev_create(vdev);
267 }
268
269 static int
270 rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
271 {
272         const char *name;
273
274         name = rte_vdev_device_name(vdev);
275         INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
276         return fs_rte_eth_free(name);
277 }
278
279 static struct rte_vdev_driver failsafe_drv = {
280         .probe = rte_pmd_failsafe_probe,
281         .remove = rte_pmd_failsafe_remove,
282 };
283
284 RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
285 RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);