7eb4b86cae3e59e095461adf24b888c60107302a
[deb_dpdk.git] / drivers / net / sfc / sfc_intr.c
1 /*-
2  *   BSD LICENSE
3  *
4  * Copyright (c) 2016-2017 Solarflare Communications Inc.
5  * All rights reserved.
6  *
7  * This software was jointly developed between OKTET Labs (under contract
8  * for Solarflare) and Solarflare Communications, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 /*
33  * At the momemt of writing DPDK v16.07 has notion of two types of
34  * interrupts: LSC (link status change) and RXQ (receive indication).
35  * It allows to register interrupt callback for entire device which is
36  * not intended to be used for receive indication (i.e. link status
37  * change indication only). The handler has no information which HW
38  * interrupt has triggered it, so we don't know which event queue should
39  * be polled/reprimed (except qmask in the case of legacy line interrupt).
40  */
41
42 #include <rte_common.h>
43 #include <rte_interrupts.h>
44
45 #include "efx.h"
46
47 #include "sfc.h"
48 #include "sfc_log.h"
49 #include "sfc_ev.h"
50
51 static void
52 sfc_intr_handle_mgmt_evq(struct sfc_adapter *sa)
53 {
54         struct sfc_evq *evq;
55
56         rte_spinlock_lock(&sa->mgmt_evq_lock);
57
58         evq = sa->mgmt_evq;
59
60         if (evq->init_state != SFC_EVQ_STARTED) {
61                 sfc_log_init(sa, "interrupt on stopped EVQ %u", evq->evq_index);
62         } else {
63                 sfc_ev_qpoll(evq);
64
65                 if (sfc_ev_qprime(evq) != 0)
66                         sfc_err(sa, "cannot prime EVQ %u", evq->evq_index);
67         }
68
69         rte_spinlock_unlock(&sa->mgmt_evq_lock);
70 }
71
72 static void
73 sfc_intr_line_handler(void *cb_arg)
74 {
75         struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg;
76         efx_nic_t *enp = sa->nic;
77         boolean_t fatal;
78         uint32_t qmask;
79         unsigned int lsc_seq = sa->port.lsc_seq;
80         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
81
82         sfc_log_init(sa, "entry");
83
84         if (sa->state != SFC_ADAPTER_STARTED &&
85             sa->state != SFC_ADAPTER_STARTING &&
86             sa->state != SFC_ADAPTER_STOPPING) {
87                 sfc_log_init(sa,
88                              "interrupt on stopped adapter, don't reenable");
89                 goto exit;
90         }
91
92         efx_intr_status_line(enp, &fatal, &qmask);
93         if (fatal) {
94                 (void)efx_intr_disable(enp);
95                 (void)efx_intr_fatal(enp);
96                 sfc_err(sa, "fatal, interrupts disabled");
97                 goto exit;
98         }
99
100         if (qmask & (1 << sa->mgmt_evq_index))
101                 sfc_intr_handle_mgmt_evq(sa);
102
103         if (rte_intr_enable(&pci_dev->intr_handle) != 0)
104                 sfc_err(sa, "cannot reenable interrupts");
105
106         sfc_log_init(sa, "done");
107
108 exit:
109         if (lsc_seq != sa->port.lsc_seq) {
110                 sfc_info(sa, "link status change event: link %s",
111                          sa->eth_dev->data->dev_link.link_status ?
112                          "UP" : "DOWN");
113                 _rte_eth_dev_callback_process(sa->eth_dev,
114                                               RTE_ETH_EVENT_INTR_LSC, NULL);
115         }
116 }
117
118 static void
119 sfc_intr_message_handler(void *cb_arg)
120 {
121         struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg;
122         efx_nic_t *enp = sa->nic;
123         boolean_t fatal;
124         unsigned int lsc_seq = sa->port.lsc_seq;
125         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
126
127         sfc_log_init(sa, "entry");
128
129         if (sa->state != SFC_ADAPTER_STARTED &&
130             sa->state != SFC_ADAPTER_STARTING &&
131             sa->state != SFC_ADAPTER_STOPPING) {
132                 sfc_log_init(sa, "adapter not-started, don't reenable");
133                 goto exit;
134         }
135
136         efx_intr_status_message(enp, sa->mgmt_evq_index, &fatal);
137         if (fatal) {
138                 (void)efx_intr_disable(enp);
139                 (void)efx_intr_fatal(enp);
140                 sfc_err(sa, "fatal, interrupts disabled");
141                 goto exit;
142         }
143
144         sfc_intr_handle_mgmt_evq(sa);
145
146         if (rte_intr_enable(&pci_dev->intr_handle) != 0)
147                 sfc_err(sa, "cannot reenable interrupts");
148
149         sfc_log_init(sa, "done");
150
151 exit:
152         if (lsc_seq != sa->port.lsc_seq) {
153                 sfc_info(sa, "link status change event");
154                 _rte_eth_dev_callback_process(sa->eth_dev,
155                                               RTE_ETH_EVENT_INTR_LSC, NULL);
156         }
157 }
158
159 int
160 sfc_intr_start(struct sfc_adapter *sa)
161 {
162         struct sfc_intr *intr = &sa->intr;
163         struct rte_intr_handle *intr_handle;
164         struct rte_pci_device *pci_dev;
165         int rc;
166
167         sfc_log_init(sa, "entry");
168
169         /*
170          * The EFX common code event queue module depends on the interrupt
171          * module. Ensure that the interrupt module is always initialized
172          * (even if interrupts are not used).  Status memory is required
173          * for Siena only and may be NULL for EF10.
174          */
175         sfc_log_init(sa, "efx_intr_init");
176         rc = efx_intr_init(sa->nic, intr->type, NULL);
177         if (rc != 0)
178                 goto fail_intr_init;
179
180         pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
181         intr_handle = &pci_dev->intr_handle;
182
183         if (intr->handler != NULL) {
184                 sfc_log_init(sa, "rte_intr_callback_register");
185                 rc = rte_intr_callback_register(intr_handle, intr->handler,
186                                                 (void *)sa);
187                 if (rc != 0) {
188                         sfc_err(sa,
189                                 "cannot register interrupt handler (rc=%d)",
190                                 rc);
191                         /*
192                          * Convert error code from negative returned by RTE API
193                          * to positive used in the driver.
194                          */
195                         rc = -rc;
196                         goto fail_rte_intr_cb_reg;
197                 }
198
199                 sfc_log_init(sa, "rte_intr_enable");
200                 rc = rte_intr_enable(intr_handle);
201                 if (rc != 0) {
202                         sfc_err(sa, "cannot enable interrupts (rc=%d)", rc);
203                         /*
204                          * Convert error code from negative returned by RTE API
205                          * to positive used in the driver.
206                          */
207                         rc = -rc;
208                         goto fail_rte_intr_enable;
209                 }
210
211                 sfc_log_init(sa, "efx_intr_enable");
212                 efx_intr_enable(sa->nic);
213         }
214
215         sfc_log_init(sa, "done type=%u max_intr=%d nb_efd=%u vec=%p",
216                      intr_handle->type, intr_handle->max_intr,
217                      intr_handle->nb_efd, intr_handle->intr_vec);
218         return 0;
219
220 fail_rte_intr_enable:
221         rte_intr_callback_unregister(intr_handle, intr->handler, (void *)sa);
222
223 fail_rte_intr_cb_reg:
224         efx_intr_fini(sa->nic);
225
226 fail_intr_init:
227         sfc_log_init(sa, "failed %d", rc);
228         return rc;
229 }
230
231 void
232 sfc_intr_stop(struct sfc_adapter *sa)
233 {
234         struct sfc_intr *intr = &sa->intr;
235         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
236
237         sfc_log_init(sa, "entry");
238
239         if (intr->handler != NULL) {
240                 struct rte_intr_handle *intr_handle;
241                 int rc;
242
243                 efx_intr_disable(sa->nic);
244
245                 intr_handle = &pci_dev->intr_handle;
246                 if (rte_intr_disable(intr_handle) != 0)
247                         sfc_err(sa, "cannot disable interrupts");
248
249                 while ((rc = rte_intr_callback_unregister(intr_handle,
250                                 intr->handler, (void *)sa)) == -EAGAIN)
251                         ;
252                 if (rc != 1)
253                         sfc_err(sa,
254                                 "cannot unregister interrupt handler %d",
255                                 rc);
256         }
257
258         efx_intr_fini(sa->nic);
259
260         sfc_log_init(sa, "done");
261 }
262
263 int
264 sfc_intr_configure(struct sfc_adapter *sa)
265 {
266         struct sfc_intr *intr = &sa->intr;
267
268         sfc_log_init(sa, "entry");
269
270         intr->handler = NULL;
271         intr->lsc_intr = (sa->eth_dev->data->dev_conf.intr_conf.lsc != 0);
272         if (!intr->lsc_intr) {
273                 sfc_info(sa, "LSC tracking using interrupts is disabled");
274                 goto done;
275         }
276
277         switch (intr->type) {
278         case EFX_INTR_MESSAGE:
279                 intr->handler = sfc_intr_message_handler;
280                 break;
281         case EFX_INTR_LINE:
282                 intr->handler = sfc_intr_line_handler;
283                 break;
284         case EFX_INTR_INVALID:
285                 sfc_warn(sa, "interrupts are not supported");
286                 break;
287         default:
288                 sfc_panic(sa, "unexpected EFX interrupt type %u\n", intr->type);
289                 break;
290         }
291
292 done:
293         sfc_log_init(sa, "done");
294         return 0;
295 }
296
297 void
298 sfc_intr_close(struct sfc_adapter *sa)
299 {
300         sfc_log_init(sa, "entry");
301
302         sfc_log_init(sa, "done");
303 }
304
305 int
306 sfc_intr_attach(struct sfc_adapter *sa)
307 {
308         struct sfc_intr *intr = &sa->intr;
309         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
310
311         sfc_log_init(sa, "entry");
312
313         switch (pci_dev->intr_handle.type) {
314 #ifdef RTE_EXEC_ENV_LINUXAPP
315         case RTE_INTR_HANDLE_UIO_INTX:
316         case RTE_INTR_HANDLE_VFIO_LEGACY:
317                 intr->type = EFX_INTR_LINE;
318                 break;
319         case RTE_INTR_HANDLE_UIO:
320         case RTE_INTR_HANDLE_VFIO_MSI:
321         case RTE_INTR_HANDLE_VFIO_MSIX:
322                 intr->type = EFX_INTR_MESSAGE;
323                 break;
324 #endif
325         default:
326                 intr->type = EFX_INTR_INVALID;
327                 break;
328         }
329
330         sfc_log_init(sa, "done");
331         return 0;
332 }
333
334 void
335 sfc_intr_detach(struct sfc_adapter *sa)
336 {
337         sfc_log_init(sa, "entry");
338
339         sa->intr.type = EFX_INTR_INVALID;
340
341         sfc_log_init(sa, "done");
342 }