c57cdaefbdc70b2988894ecf2fb0d88b687ff08d
[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->evq_info[sa->mgmt_evq_index].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(struct rte_intr_handle *intr_handle, 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
81         sfc_log_init(sa, "entry");
82
83         if (sa->state != SFC_ADAPTER_STARTED &&
84             sa->state != SFC_ADAPTER_STARTING &&
85             sa->state != SFC_ADAPTER_STOPPING) {
86                 sfc_log_init(sa,
87                              "interrupt on stopped adapter, don't reenable");
88                 goto exit;
89         }
90
91         efx_intr_status_line(enp, &fatal, &qmask);
92         if (fatal) {
93                 (void)efx_intr_disable(enp);
94                 (void)efx_intr_fatal(enp);
95                 sfc_err(sa, "fatal, interrupts disabled");
96                 goto exit;
97         }
98
99         if (qmask & (1 << sa->mgmt_evq_index))
100                 sfc_intr_handle_mgmt_evq(sa);
101
102         if (rte_intr_enable(intr_handle) != 0)
103                 sfc_err(sa, "cannot reenable interrupts");
104
105         sfc_log_init(sa, "done");
106
107 exit:
108         if (lsc_seq != sa->port.lsc_seq) {
109                 sfc_info(sa, "link status change event: link %s",
110                          sa->eth_dev->data->dev_link.link_status ?
111                          "UP" : "DOWN");
112                 _rte_eth_dev_callback_process(sa->eth_dev,
113                                               RTE_ETH_EVENT_INTR_LSC, NULL);
114         }
115 }
116
117 static void
118 sfc_intr_message_handler(struct rte_intr_handle *intr_handle, void *cb_arg)
119 {
120         struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg;
121         efx_nic_t *enp = sa->nic;
122         boolean_t fatal;
123         unsigned int lsc_seq = sa->port.lsc_seq;
124
125         sfc_log_init(sa, "entry");
126
127         if (sa->state != SFC_ADAPTER_STARTED &&
128             sa->state != SFC_ADAPTER_STARTING &&
129             sa->state != SFC_ADAPTER_STOPPING) {
130                 sfc_log_init(sa, "adapter not-started, don't reenable");
131                 goto exit;
132         }
133
134         efx_intr_status_message(enp, sa->mgmt_evq_index, &fatal);
135         if (fatal) {
136                 (void)efx_intr_disable(enp);
137                 (void)efx_intr_fatal(enp);
138                 sfc_err(sa, "fatal, interrupts disabled");
139                 goto exit;
140         }
141
142         sfc_intr_handle_mgmt_evq(sa);
143
144         if (rte_intr_enable(intr_handle) != 0)
145                 sfc_err(sa, "cannot reenable interrupts");
146
147         sfc_log_init(sa, "done");
148
149 exit:
150         if (lsc_seq != sa->port.lsc_seq) {
151                 sfc_info(sa, "link status change event");
152                 _rte_eth_dev_callback_process(sa->eth_dev,
153                                               RTE_ETH_EVENT_INTR_LSC, NULL);
154         }
155 }
156
157 int
158 sfc_intr_start(struct sfc_adapter *sa)
159 {
160         struct sfc_intr *intr = &sa->intr;
161         struct rte_intr_handle *intr_handle;
162         struct rte_pci_device *pci_dev;
163         int rc;
164
165         sfc_log_init(sa, "entry");
166
167         /*
168          * The EFX common code event queue module depends on the interrupt
169          * module. Ensure that the interrupt module is always initialized
170          * (even if interrupts are not used).  Status memory is required
171          * for Siena only and may be NULL for EF10.
172          */
173         sfc_log_init(sa, "efx_intr_init");
174         rc = efx_intr_init(sa->nic, intr->type, NULL);
175         if (rc != 0)
176                 goto fail_intr_init;
177
178         pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
179         intr_handle = &pci_dev->intr_handle;
180
181         if (intr->handler != NULL) {
182                 sfc_log_init(sa, "rte_intr_callback_register");
183                 rc = rte_intr_callback_register(intr_handle, intr->handler,
184                                                 (void *)sa);
185                 if (rc != 0) {
186                         sfc_err(sa,
187                                 "cannot register interrupt handler (rc=%d)",
188                                 rc);
189                         /*
190                          * Convert error code from negative returned by RTE API
191                          * to positive used in the driver.
192                          */
193                         rc = -rc;
194                         goto fail_rte_intr_cb_reg;
195                 }
196
197                 sfc_log_init(sa, "rte_intr_enable");
198                 rc = rte_intr_enable(intr_handle);
199                 if (rc != 0) {
200                         sfc_err(sa, "cannot enable interrupts (rc=%d)", rc);
201                         /*
202                          * Convert error code from negative returned by RTE API
203                          * to positive used in the driver.
204                          */
205                         rc = -rc;
206                         goto fail_rte_intr_enable;
207                 }
208
209                 sfc_log_init(sa, "efx_intr_enable");
210                 efx_intr_enable(sa->nic);
211         }
212
213         sfc_log_init(sa, "done type=%u max_intr=%d nb_efd=%u vec=%p",
214                      intr_handle->type, intr_handle->max_intr,
215                      intr_handle->nb_efd, intr_handle->intr_vec);
216         return 0;
217
218 fail_rte_intr_enable:
219         rte_intr_callback_unregister(intr_handle, intr->handler, (void *)sa);
220
221 fail_rte_intr_cb_reg:
222         efx_intr_fini(sa->nic);
223
224 fail_intr_init:
225         sfc_log_init(sa, "failed %d", rc);
226         return rc;
227 }
228
229 void
230 sfc_intr_stop(struct sfc_adapter *sa)
231 {
232         struct sfc_intr *intr = &sa->intr;
233         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
234
235         sfc_log_init(sa, "entry");
236
237         if (intr->handler != NULL) {
238                 struct rte_intr_handle *intr_handle;
239                 int rc;
240
241                 efx_intr_disable(sa->nic);
242
243                 intr_handle = &pci_dev->intr_handle;
244                 if (rte_intr_disable(intr_handle) != 0)
245                         sfc_err(sa, "cannot disable interrupts");
246
247                 while ((rc = rte_intr_callback_unregister(intr_handle,
248                                 intr->handler, (void *)sa)) == -EAGAIN)
249                         ;
250                 if (rc != 1)
251                         sfc_err(sa,
252                                 "cannot unregister interrupt handler %d",
253                                 rc);
254         }
255
256         efx_intr_fini(sa->nic);
257
258         sfc_log_init(sa, "done");
259 }
260
261 int
262 sfc_intr_init(struct sfc_adapter *sa)
263 {
264         struct sfc_intr *intr = &sa->intr;
265
266         sfc_log_init(sa, "entry");
267
268         intr->handler = NULL;
269         intr->lsc_intr = (sa->eth_dev->data->dev_conf.intr_conf.lsc != 0);
270         if (!intr->lsc_intr) {
271                 sfc_info(sa, "LSC tracking using interrupts is disabled");
272                 goto done;
273         }
274
275         switch (intr->type) {
276         case EFX_INTR_MESSAGE:
277                 intr->handler = sfc_intr_message_handler;
278                 break;
279         case EFX_INTR_LINE:
280                 intr->handler = sfc_intr_line_handler;
281                 break;
282         case EFX_INTR_INVALID:
283                 sfc_warn(sa, "interrupts are not supported");
284                 break;
285         default:
286                 sfc_panic(sa, "unexpected EFX interrupt type %u\n", intr->type);
287                 break;
288         }
289
290 done:
291         sfc_log_init(sa, "done");
292         return 0;
293 }
294
295 void
296 sfc_intr_fini(struct sfc_adapter *sa)
297 {
298         sfc_log_init(sa, "entry");
299
300         sfc_log_init(sa, "done");
301 }
302
303 int
304 sfc_intr_attach(struct sfc_adapter *sa)
305 {
306         struct sfc_intr *intr = &sa->intr;
307         struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(sa->eth_dev);
308
309         sfc_log_init(sa, "entry");
310
311         switch (pci_dev->intr_handle.type) {
312 #ifdef RTE_EXEC_ENV_LINUXAPP
313         case RTE_INTR_HANDLE_VFIO_LEGACY:
314                 intr->type = EFX_INTR_LINE;
315                 break;
316         case RTE_INTR_HANDLE_VFIO_MSI:
317         case RTE_INTR_HANDLE_VFIO_MSIX:
318                 intr->type = EFX_INTR_MESSAGE;
319                 break;
320 #endif
321         default:
322                 intr->type = EFX_INTR_INVALID;
323                 break;
324         }
325
326         sfc_log_init(sa, "done");
327         return 0;
328 }
329
330 void
331 sfc_intr_detach(struct sfc_adapter *sa)
332 {
333         sfc_log_init(sa, "entry");
334
335         sa->intr.type = EFX_INTR_INVALID;
336
337         sfc_log_init(sa, "done");
338 }