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