net/failsafe: register slaves Rx interrupts
[dpdk.git] / drivers / net / failsafe / failsafe_intr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 Mellanox Technologies, Ltd.
3  */
4
5 /**
6  * @file
7  * Interrupts handling for failsafe driver.
8  */
9
10 #if defined(LINUX)
11 #include <sys/epoll.h>
12 #endif
13 #include <unistd.h>
14
15 #include "failsafe_private.h"
16
17 #define NUM_RX_PROXIES (FAILSAFE_MAX_ETHPORTS * RTE_MAX_RXTX_INTR_VEC_ID)
18
19
20 /**
21  * Open an epoll file descriptor.
22  *
23  * @param flags
24  *   Flags for defining epoll behavior.
25  * @return
26  *   0 on success, negative errno value otherwise.
27  */
28 static int
29 fs_epoll_create1(int flags)
30 {
31 #if defined(LINUX)
32         return epoll_create1(flags);
33 #elif defined(BSD)
34         RTE_SET_USED(flags);
35         return -ENOTSUP;
36 #endif
37 }
38
39 /**
40  * Install failsafe Rx event proxy subsystem.
41  * This is the way the failsafe PMD generates Rx events on behalf of its
42  * subdevices.
43  *
44  * @param priv
45  *   Pointer to failsafe private structure.
46  * @return
47  *   0 on success, negative errno value otherwise and rte_errno is set.
48  */
49 static int
50 fs_rx_event_proxy_install(struct fs_priv *priv)
51 {
52         int rc = 0;
53
54         /*
55          * Create the epoll fd and event vector for the proxy service to
56          * wait on for Rx events generated by the subdevices.
57          */
58         priv->rxp.efd = fs_epoll_create1(0);
59         if (priv->rxp.efd < 0) {
60                 rte_errno = errno;
61                 ERROR("Failed to create epoll,"
62                       " Rx interrupts will not be supported");
63                 return -rte_errno;
64         }
65         priv->rxp.evec = calloc(NUM_RX_PROXIES, sizeof(*priv->rxp.evec));
66         if (priv->rxp.evec == NULL) {
67                 ERROR("Failed to allocate memory for event vectors,"
68                       " Rx interrupts will not be supported");
69                 rc = -ENOMEM;
70                 goto error;
71         }
72         return 0;
73 error:
74         if (priv->rxp.efd >= 0) {
75                 close(priv->rxp.efd);
76                 priv->rxp.efd = -1;
77         }
78         if (priv->rxp.evec != NULL) {
79                 free(priv->rxp.evec);
80                 priv->rxp.evec = NULL;
81         }
82         rte_errno = -rc;
83         return rc;
84 }
85
86 /**
87  * RX Interrupt control per subdevice.
88  *
89  * @param sdev
90  *   Pointer to sub-device structure.
91  * @param op
92  *   The operation be performed for the vector.
93  *   Operation type of {RTE_INTR_EVENT_ADD, RTE_INTR_EVENT_DEL}.
94  * @return
95  *   - On success, zero.
96  *   - On failure, a negative value.
97  */
98 static int
99 failsafe_eth_rx_intr_ctl_subdevice(struct sub_device *sdev, int op)
100 {
101         struct rte_eth_dev *dev;
102         struct rte_eth_dev *fsdev;
103         int epfd;
104         uint16_t pid;
105         uint16_t qid;
106         struct rxq *fsrxq;
107         int rc;
108         int ret = 0;
109
110         if (sdev == NULL || (ETH(sdev) == NULL) ||
111             sdev->fs_dev == NULL || (PRIV(sdev->fs_dev) == NULL)) {
112                 ERROR("Called with invalid arguments");
113                 return -EINVAL;
114         }
115         dev = ETH(sdev);
116         fsdev = sdev->fs_dev;
117         epfd = PRIV(sdev->fs_dev)->rxp.efd;
118         pid = PORT_ID(sdev);
119
120         if (epfd <= 0) {
121                 if (op == RTE_INTR_EVENT_ADD) {
122                         ERROR("Proxy events are not initialized");
123                         return -EBADF;
124                 } else {
125                         return 0;
126                 }
127         }
128         if (dev->data->nb_rx_queues > fsdev->data->nb_rx_queues) {
129                 ERROR("subdevice has too many queues,"
130                       " Interrupts will not be enabled");
131                         return -E2BIG;
132         }
133         for (qid = 0; qid < dev->data->nb_rx_queues; qid++) {
134                 fsrxq = fsdev->data->rx_queues[qid];
135                 rc = rte_eth_dev_rx_intr_ctl_q(pid, qid, epfd,
136                                                op, (void *)fsrxq);
137                 if (rc) {
138                         ERROR("rte_eth_dev_rx_intr_ctl_q failed for "
139                               "port %d  queue %d, epfd %d, error %d",
140                               pid, qid, epfd, rc);
141                         ret = rc;
142                 }
143         }
144         return ret;
145 }
146
147 /**
148  * Install Rx interrupts subsystem for a subdevice.
149  * This is a support for dynamically adding subdevices.
150  *
151  * @param sdev
152  *   Pointer to subdevice structure.
153  *
154  * @return
155  *   0 on success, negative errno value otherwise and rte_errno is set.
156  */
157 int failsafe_rx_intr_install_subdevice(struct sub_device *sdev)
158 {
159         int rc;
160         int qid;
161         struct rte_eth_dev *fsdev;
162         struct rxq **rxq;
163         const struct rte_intr_conf *const intr_conf =
164                                 &ETH(sdev)->data->dev_conf.intr_conf;
165
166         fsdev = sdev->fs_dev;
167         rxq = (struct rxq **)fsdev->data->rx_queues;
168         if (intr_conf->rxq == 0)
169                 return 0;
170         rc = failsafe_eth_rx_intr_ctl_subdevice(sdev, RTE_INTR_EVENT_ADD);
171         if (rc)
172                 return rc;
173         /* enable interrupts on already-enabled queues */
174         for (qid = 0; qid < ETH(sdev)->data->nb_rx_queues; qid++) {
175                 if (rxq[qid]->enable_events) {
176                         int ret = rte_eth_dev_rx_intr_enable(PORT_ID(sdev),
177                                                              qid);
178                         if (ret && (ret != -ENOTSUP)) {
179                                 ERROR("Failed to enable interrupts on "
180                                       "port %d queue %d", PORT_ID(sdev), qid);
181                                 rc = ret;
182                         }
183                 }
184         }
185         return rc;
186 }
187
188 /**
189  * Uninstall Rx interrupts subsystem for a subdevice.
190  * This is a support for dynamically removing subdevices.
191  *
192  * @param sdev
193  *   Pointer to subdevice structure.
194  *
195  * @return
196  *   0 on success, negative errno value otherwise and rte_errno is set.
197  */
198 void failsafe_rx_intr_uninstall_subdevice(struct sub_device *sdev)
199 {
200         int qid;
201         struct rte_eth_dev *fsdev;
202         struct rxq *fsrxq;
203
204         fsdev = sdev->fs_dev;
205         for (qid = 0; qid < ETH(sdev)->data->nb_rx_queues; qid++) {
206                 if (qid < fsdev->data->nb_rx_queues) {
207                         fsrxq = fsdev->data->rx_queues[qid];
208                         if (fsrxq->enable_events)
209                                 rte_eth_dev_rx_intr_disable(PORT_ID(sdev),
210                                                             qid);
211                 }
212         }
213         failsafe_eth_rx_intr_ctl_subdevice(sdev, RTE_INTR_EVENT_DEL);
214 }
215
216 /**
217  * Uninstall failsafe Rx event proxy.
218  *
219  * @param priv
220  *   Pointer to failsafe private structure.
221  */
222 static void
223 fs_rx_event_proxy_uninstall(struct fs_priv *priv)
224 {
225         if (priv->rxp.evec != NULL) {
226                 free(priv->rxp.evec);
227                 priv->rxp.evec = NULL;
228         }
229         if (priv->rxp.efd > 0) {
230                 close(priv->rxp.efd);
231                 priv->rxp.efd = -1;
232         }
233 }
234
235 /**
236  * Uninstall failsafe interrupt vector.
237  *
238  * @param priv
239  *   Pointer to failsafe private structure.
240  */
241 static void
242 fs_rx_intr_vec_uninstall(struct fs_priv *priv)
243 {
244         struct rte_intr_handle *intr_handle;
245
246         intr_handle = &priv->intr_handle;
247         if (intr_handle->intr_vec != NULL) {
248                 free(intr_handle->intr_vec);
249                 intr_handle->intr_vec = NULL;
250         }
251         intr_handle->nb_efd = 0;
252 }
253
254 /**
255  * Installs failsafe interrupt vector to be registered with EAL later on.
256  *
257  * @param priv
258  *   Pointer to failsafe private structure.
259  *
260  * @return
261  *   0 on success, negative errno value otherwise and rte_errno is set.
262  */
263 static int
264 fs_rx_intr_vec_install(struct fs_priv *priv)
265 {
266         unsigned int i;
267         unsigned int rxqs_n;
268         unsigned int n;
269         unsigned int count;
270         struct rte_intr_handle *intr_handle;
271
272         rxqs_n = priv->dev->data->nb_rx_queues;
273         n = RTE_MIN(rxqs_n, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);
274         count = 0;
275         intr_handle = &priv->intr_handle;
276         RTE_ASSERT(intr_handle->intr_vec == NULL);
277         /* Allocate the interrupt vector of the failsafe Rx proxy interrupts */
278         intr_handle->intr_vec = malloc(n * sizeof(intr_handle->intr_vec[0]));
279         if (intr_handle->intr_vec == NULL) {
280                 fs_rx_intr_vec_uninstall(priv);
281                 rte_errno = ENOMEM;
282                 ERROR("Failed to allocate memory for interrupt vector,"
283                       " Rx interrupts will not be supported");
284                 return -rte_errno;
285         }
286         for (i = 0; i < n; i++) {
287                 struct rxq *rxq = priv->dev->data->rx_queues[i];
288
289                 /* Skip queues that cannot request interrupts. */
290                 if (rxq == NULL || rxq->event_fd < 0) {
291                         /* Use invalid intr_vec[] index to disable entry. */
292                         intr_handle->intr_vec[i] =
293                                 RTE_INTR_VEC_RXTX_OFFSET +
294                                 RTE_MAX_RXTX_INTR_VEC_ID;
295                         continue;
296                 }
297                 if (count >= RTE_MAX_RXTX_INTR_VEC_ID) {
298                         rte_errno = E2BIG;
299                         ERROR("Too many Rx queues for interrupt vector size"
300                               " (%d), Rx interrupts cannot be enabled",
301                               RTE_MAX_RXTX_INTR_VEC_ID);
302                         fs_rx_intr_vec_uninstall(priv);
303                         return -rte_errno;
304                 }
305                 intr_handle->intr_vec[i] = RTE_INTR_VEC_RXTX_OFFSET + count;
306                 intr_handle->efds[count] = rxq->event_fd;
307                 count++;
308         }
309         if (count == 0) {
310                 fs_rx_intr_vec_uninstall(priv);
311         } else {
312                 intr_handle->nb_efd = count;
313                 intr_handle->efd_counter_size = sizeof(uint64_t);
314         }
315         return 0;
316 }
317
318
319 /**
320  * Uninstall failsafe Rx interrupts subsystem.
321  *
322  * @param priv
323  *   Pointer to private structure.
324  *
325  * @return
326  *   0 on success, negative errno value otherwise and rte_errno is set.
327  */
328 void
329 failsafe_rx_intr_uninstall(struct rte_eth_dev *dev)
330 {
331         struct fs_priv *priv;
332         struct rte_intr_handle *intr_handle;
333
334         priv = PRIV(dev);
335         intr_handle = &priv->intr_handle;
336         rte_intr_free_epoll_fd(intr_handle);
337         fs_rx_event_proxy_uninstall(priv);
338         fs_rx_intr_vec_uninstall(priv);
339         dev->intr_handle = NULL;
340 }
341
342 /**
343  * Install failsafe Rx interrupts subsystem.
344  *
345  * @param priv
346  *   Pointer to private structure.
347  *
348  * @return
349  *   0 on success, negative errno value otherwise and rte_errno is set.
350  */
351 int
352 failsafe_rx_intr_install(struct rte_eth_dev *dev)
353 {
354         struct fs_priv *priv = PRIV(dev);
355         const struct rte_intr_conf *const intr_conf =
356                         &priv->dev->data->dev_conf.intr_conf;
357
358         if (intr_conf->rxq == 0)
359                 return 0;
360         if (fs_rx_intr_vec_install(priv) < 0)
361                 return -rte_errno;
362         if (fs_rx_event_proxy_install(priv) < 0) {
363                 fs_rx_intr_vec_uninstall(priv);
364                 return -rte_errno;
365         }
366         dev->intr_handle = &priv->intr_handle;
367         return 0;
368 }