New upstream version 18.02
[deb_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                 if (fs_lock(dev, 1) != 0)
117                         goto reinstall;
118                 ret = failsafe_eth_dev_state_sync(dev);
119                 fs_unlock(dev, 1);
120                 if (ret)
121                         ERROR("Unable to synchronize sub_device state");
122         }
123         failsafe_dev_remove(dev);
124 reinstall:
125         ret = failsafe_hotplug_alarm_install(dev);
126         if (ret)
127                 ERROR("Unable to set up next alarm");
128 }
129
130 static int
131 fs_mutex_init(struct fs_priv *priv)
132 {
133         int ret;
134         pthread_mutexattr_t attr;
135
136         ret = pthread_mutexattr_init(&attr);
137         if (ret) {
138                 ERROR("Cannot initiate mutex attributes - %s", strerror(ret));
139                 return ret;
140         }
141         /* Allow mutex relocks for the thread holding the mutex. */
142         ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
143         if (ret) {
144                 ERROR("Cannot set mutex type - %s", strerror(ret));
145                 return ret;
146         }
147         ret = pthread_mutex_init(&priv->hotplug_mutex, &attr);
148         if (ret) {
149                 ERROR("Cannot initiate mutex - %s", strerror(ret));
150                 return ret;
151         }
152         return 0;
153 }
154
155 static int
156 fs_eth_dev_create(struct rte_vdev_device *vdev)
157 {
158         struct rte_eth_dev *dev;
159         struct ether_addr *mac;
160         struct fs_priv *priv;
161         struct sub_device *sdev;
162         const char *params;
163         unsigned int socket_id;
164         uint8_t i;
165         int ret;
166
167         dev = NULL;
168         priv = NULL;
169         socket_id = rte_socket_id();
170         INFO("Creating fail-safe device on NUMA socket %u", socket_id);
171         params = rte_vdev_device_args(vdev);
172         if (params == NULL) {
173                 ERROR("This PMD requires sub-devices, none provided");
174                 return -1;
175         }
176         dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
177         if (dev == NULL) {
178                 ERROR("Unable to allocate rte_eth_dev");
179                 return -1;
180         }
181         priv = PRIV(dev);
182         priv->dev = dev;
183         dev->dev_ops = &failsafe_ops;
184         dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
185         dev->data->dev_link = eth_link;
186         PRIV(dev)->nb_mac_addr = 1;
187         TAILQ_INIT(&PRIV(dev)->flow_list);
188         dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
189         dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
190         ret = fs_sub_device_alloc(dev, params);
191         if (ret) {
192                 ERROR("Could not allocate sub_devices");
193                 goto free_dev;
194         }
195         ret = failsafe_args_parse(dev, params);
196         if (ret)
197                 goto free_subs;
198         ret = rte_eth_dev_owner_new(&priv->my_owner.id);
199         if (ret) {
200                 ERROR("Failed to get unique owner identifier");
201                 goto free_args;
202         }
203         snprintf(priv->my_owner.name, sizeof(priv->my_owner.name),
204                  FAILSAFE_OWNER_NAME);
205         ret = failsafe_eal_init(dev);
206         if (ret)
207                 goto free_args;
208         ret = fs_mutex_init(priv);
209         if (ret)
210                 goto free_args;
211         ret = failsafe_hotplug_alarm_install(dev);
212         if (ret) {
213                 ERROR("Could not set up plug-in event detection");
214                 goto free_args;
215         }
216         mac = &dev->data->mac_addrs[0];
217         if (mac_from_arg) {
218                 /*
219                  * If MAC address was provided as a parameter,
220                  * apply to all probed slaves.
221                  */
222                 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
223                         ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
224                                                                mac);
225                         if (ret) {
226                                 ERROR("Failed to set default MAC address");
227                                 goto free_args;
228                         }
229                 }
230         } else {
231                 /*
232                  * Use the ether_addr from first probed
233                  * device, either preferred or fallback.
234                  */
235                 FOREACH_SUBDEV(sdev, i, dev)
236                         if (sdev->state >= DEV_PROBED) {
237                                 ether_addr_copy(&ETH(sdev)->data->mac_addrs[0],
238                                                 mac);
239                                 break;
240                         }
241                 /*
242                  * If no device has been probed and no ether_addr
243                  * has been provided on the command line, use a random
244                  * valid one.
245                  * It will be applied during future slave state syncs to
246                  * probed slaves.
247                  */
248                 if (i == priv->subs_tail)
249                         eth_random_addr(&mac->addr_bytes[0]);
250         }
251         INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
252                 mac->addr_bytes[0], mac->addr_bytes[1],
253                 mac->addr_bytes[2], mac->addr_bytes[3],
254                 mac->addr_bytes[4], mac->addr_bytes[5]);
255         dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
256         PRIV(dev)->intr_handle = (struct rte_intr_handle){
257                 .fd = -1,
258                 .type = RTE_INTR_HANDLE_EXT,
259         };
260         return 0;
261 free_args:
262         failsafe_args_free(dev);
263 free_subs:
264         fs_sub_device_free(dev);
265 free_dev:
266         rte_free(PRIV(dev));
267         rte_eth_dev_release_port(dev);
268         return -1;
269 }
270
271 static int
272 fs_rte_eth_free(const char *name)
273 {
274         struct rte_eth_dev *dev;
275         int ret;
276
277         dev = rte_eth_dev_allocated(name);
278         if (dev == NULL)
279                 return -ENODEV;
280         ret = failsafe_eal_uninit(dev);
281         if (ret)
282                 ERROR("Error while uninitializing sub-EAL");
283         failsafe_args_free(dev);
284         fs_sub_device_free(dev);
285         ret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex);
286         if (ret)
287                 ERROR("Error while destroying hotplug mutex");
288         rte_free(PRIV(dev));
289         rte_eth_dev_release_port(dev);
290         return ret;
291 }
292
293 static int
294 rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
295 {
296         const char *name;
297
298         name = rte_vdev_device_name(vdev);
299         INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
300                         name);
301         return fs_eth_dev_create(vdev);
302 }
303
304 static int
305 rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
306 {
307         const char *name;
308
309         name = rte_vdev_device_name(vdev);
310         INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
311         return fs_rte_eth_free(name);
312 }
313
314 static struct rte_vdev_driver failsafe_drv = {
315         .probe = rte_pmd_failsafe_probe,
316         .remove = rte_pmd_failsafe_remove,
317 };
318
319 RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
320 RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);