GNU Linux-libre 4.14.266-gnu1
[releases.git] / drivers / crypto / qat / qat_common / adf_isr.c
1 /*
2   This file is provided under a dual BSD/GPLv2 license.  When using or
3   redistributing this file, you may do so under either license.
4
5   GPL LICENSE SUMMARY
6   Copyright(c) 2014 Intel Corporation.
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of version 2 of the GNU General Public License as
9   published by the Free Software Foundation.
10
11   This program is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   General Public License for more details.
15
16   Contact Information:
17   qat-linux@intel.com
18
19   BSD LICENSE
20   Copyright(c) 2014 Intel Corporation.
21   Redistribution and use in source and binary forms, with or without
22   modification, are permitted provided that the following conditions
23   are met:
24
25     * Redistributions of source code must retain the above copyright
26       notice, this list of conditions and the following disclaimer.
27     * Redistributions in binary form must reproduce the above copyright
28       notice, this list of conditions and the following disclaimer in
29       the documentation and/or other materials provided with the
30       distribution.
31     * Neither the name of Intel Corporation nor the names of its
32       contributors may be used to endorse or promote products derived
33       from this software without specific prior written permission.
34
35   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 */
47 #include <linux/kernel.h>
48 #include <linux/init.h>
49 #include <linux/types.h>
50 #include <linux/pci.h>
51 #include <linux/slab.h>
52 #include <linux/errno.h>
53 #include <linux/interrupt.h>
54 #include "adf_accel_devices.h"
55 #include "adf_common_drv.h"
56 #include "adf_cfg.h"
57 #include "adf_cfg_strings.h"
58 #include "adf_cfg_common.h"
59 #include "adf_transport_access_macros.h"
60 #include "adf_transport_internal.h"
61
62 #define ADF_MAX_NUM_VFS 32
63
64 static int adf_enable_msix(struct adf_accel_dev *accel_dev)
65 {
66         struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
67         struct adf_hw_device_data *hw_data = accel_dev->hw_device;
68         u32 msix_num_entries = 1;
69
70         /* If SR-IOV is disabled, add entries for each bank */
71         if (!accel_dev->pf.vf_info) {
72                 int i;
73
74                 msix_num_entries += hw_data->num_banks;
75                 for (i = 0; i < msix_num_entries; i++)
76                         pci_dev_info->msix_entries.entries[i].entry = i;
77         } else {
78                 pci_dev_info->msix_entries.entries[0].entry =
79                         hw_data->num_banks;
80         }
81
82         if (pci_enable_msix_exact(pci_dev_info->pci_dev,
83                                   pci_dev_info->msix_entries.entries,
84                                   msix_num_entries)) {
85                 dev_err(&GET_DEV(accel_dev), "Failed to enable MSI-X IRQ(s)\n");
86                 return -EFAULT;
87         }
88         return 0;
89 }
90
91 static void adf_disable_msix(struct adf_accel_pci *pci_dev_info)
92 {
93         pci_disable_msix(pci_dev_info->pci_dev);
94 }
95
96 static irqreturn_t adf_msix_isr_bundle(int irq, void *bank_ptr)
97 {
98         struct adf_etr_bank_data *bank = bank_ptr;
99
100         WRITE_CSR_INT_FLAG_AND_COL(bank->csr_addr, bank->bank_number, 0);
101         tasklet_hi_schedule(&bank->resp_handler);
102         return IRQ_HANDLED;
103 }
104
105 static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
106 {
107         struct adf_accel_dev *accel_dev = dev_ptr;
108
109 #ifdef CONFIG_PCI_IOV
110         /* If SR-IOV is enabled (vf_info is non-NULL), check for VF->PF ints */
111         if (accel_dev->pf.vf_info) {
112                 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
113                 struct adf_bar *pmisc =
114                         &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
115                 void __iomem *pmisc_bar_addr = pmisc->virt_addr;
116                 unsigned long vf_mask;
117
118                 /* Get the interrupt sources triggered by VFs */
119                 vf_mask = ((ADF_CSR_RD(pmisc_bar_addr, ADF_ERRSOU5) &
120                             0x0000FFFF) << 16) |
121                           ((ADF_CSR_RD(pmisc_bar_addr, ADF_ERRSOU3) &
122                             0x01FFFE00) >> 9);
123
124                 if (vf_mask) {
125                         struct adf_accel_vf_info *vf_info;
126                         bool irq_handled = false;
127                         int i;
128
129                         /* Disable VF2PF interrupts for VFs with pending ints */
130                         adf_disable_vf2pf_interrupts(accel_dev, vf_mask);
131
132                         /*
133                          * Schedule tasklets to handle VF2PF interrupt BHs
134                          * unless the VF is malicious and is attempting to
135                          * flood the host OS with VF2PF interrupts.
136                          */
137                         for_each_set_bit(i, &vf_mask, ADF_MAX_NUM_VFS) {
138                                 vf_info = accel_dev->pf.vf_info + i;
139
140                                 if (!__ratelimit(&vf_info->vf2pf_ratelimit)) {
141                                         dev_info(&GET_DEV(accel_dev),
142                                                  "Too many ints from VF%d\n",
143                                                   vf_info->vf_nr + 1);
144                                         continue;
145                                 }
146
147                                 /* Tasklet will re-enable ints from this VF */
148                                 tasklet_hi_schedule(&vf_info->vf2pf_bh_tasklet);
149                                 irq_handled = true;
150                         }
151
152                         if (irq_handled)
153                                 return IRQ_HANDLED;
154                 }
155         }
156 #endif /* CONFIG_PCI_IOV */
157
158         dev_dbg(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n",
159                 accel_dev->accel_id);
160
161         return IRQ_NONE;
162 }
163
164 static int adf_request_irqs(struct adf_accel_dev *accel_dev)
165 {
166         struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
167         struct adf_hw_device_data *hw_data = accel_dev->hw_device;
168         struct msix_entry *msixe = pci_dev_info->msix_entries.entries;
169         struct adf_etr_data *etr_data = accel_dev->transport;
170         int ret, i = 0;
171         char *name;
172
173         /* Request msix irq for all banks unless SR-IOV enabled */
174         if (!accel_dev->pf.vf_info) {
175                 for (i = 0; i < hw_data->num_banks; i++) {
176                         struct adf_etr_bank_data *bank = &etr_data->banks[i];
177                         unsigned int cpu, cpus = num_online_cpus();
178
179                         name = *(pci_dev_info->msix_entries.names + i);
180                         snprintf(name, ADF_MAX_MSIX_VECTOR_NAME,
181                                  "qat%d-bundle%d", accel_dev->accel_id, i);
182                         ret = request_irq(msixe[i].vector,
183                                           adf_msix_isr_bundle, 0, name, bank);
184                         if (ret) {
185                                 dev_err(&GET_DEV(accel_dev),
186                                         "failed to enable irq %d for %s\n",
187                                         msixe[i].vector, name);
188                                 return ret;
189                         }
190
191                         cpu = ((accel_dev->accel_id * hw_data->num_banks) +
192                                i) % cpus;
193                         irq_set_affinity_hint(msixe[i].vector,
194                                               get_cpu_mask(cpu));
195                 }
196         }
197
198         /* Request msix irq for AE */
199         name = *(pci_dev_info->msix_entries.names + i);
200         snprintf(name, ADF_MAX_MSIX_VECTOR_NAME,
201                  "qat%d-ae-cluster", accel_dev->accel_id);
202         ret = request_irq(msixe[i].vector, adf_msix_isr_ae, 0, name, accel_dev);
203         if (ret) {
204                 dev_err(&GET_DEV(accel_dev),
205                         "failed to enable irq %d, for %s\n",
206                         msixe[i].vector, name);
207                 return ret;
208         }
209         return ret;
210 }
211
212 static void adf_free_irqs(struct adf_accel_dev *accel_dev)
213 {
214         struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
215         struct adf_hw_device_data *hw_data = accel_dev->hw_device;
216         struct msix_entry *msixe = pci_dev_info->msix_entries.entries;
217         struct adf_etr_data *etr_data = accel_dev->transport;
218         int i = 0;
219
220         if (pci_dev_info->msix_entries.num_entries > 1) {
221                 for (i = 0; i < hw_data->num_banks; i++) {
222                         irq_set_affinity_hint(msixe[i].vector, NULL);
223                         free_irq(msixe[i].vector, &etr_data->banks[i]);
224                 }
225         }
226         irq_set_affinity_hint(msixe[i].vector, NULL);
227         free_irq(msixe[i].vector, accel_dev);
228 }
229
230 static int adf_isr_alloc_msix_entry_table(struct adf_accel_dev *accel_dev)
231 {
232         int i;
233         char **names;
234         struct msix_entry *entries;
235         struct adf_hw_device_data *hw_data = accel_dev->hw_device;
236         u32 msix_num_entries = 1;
237
238         /* If SR-IOV is disabled (vf_info is NULL), add entries for each bank */
239         if (!accel_dev->pf.vf_info)
240                 msix_num_entries += hw_data->num_banks;
241
242         entries = kzalloc_node(msix_num_entries * sizeof(*entries),
243                                GFP_KERNEL, dev_to_node(&GET_DEV(accel_dev)));
244         if (!entries)
245                 return -ENOMEM;
246
247         names = kcalloc(msix_num_entries, sizeof(char *), GFP_KERNEL);
248         if (!names) {
249                 kfree(entries);
250                 return -ENOMEM;
251         }
252         for (i = 0; i < msix_num_entries; i++) {
253                 *(names + i) = kzalloc(ADF_MAX_MSIX_VECTOR_NAME, GFP_KERNEL);
254                 if (!(*(names + i)))
255                         goto err;
256         }
257         accel_dev->accel_pci_dev.msix_entries.num_entries = msix_num_entries;
258         accel_dev->accel_pci_dev.msix_entries.entries = entries;
259         accel_dev->accel_pci_dev.msix_entries.names = names;
260         return 0;
261 err:
262         for (i = 0; i < msix_num_entries; i++)
263                 kfree(*(names + i));
264         kfree(entries);
265         kfree(names);
266         return -ENOMEM;
267 }
268
269 static void adf_isr_free_msix_entry_table(struct adf_accel_dev *accel_dev)
270 {
271         char **names = accel_dev->accel_pci_dev.msix_entries.names;
272         int i;
273
274         kfree(accel_dev->accel_pci_dev.msix_entries.entries);
275         for (i = 0; i < accel_dev->accel_pci_dev.msix_entries.num_entries; i++)
276                 kfree(*(names + i));
277         kfree(names);
278 }
279
280 static int adf_setup_bh(struct adf_accel_dev *accel_dev)
281 {
282         struct adf_etr_data *priv_data = accel_dev->transport;
283         struct adf_hw_device_data *hw_data = accel_dev->hw_device;
284         int i;
285
286         for (i = 0; i < hw_data->num_banks; i++)
287                 tasklet_init(&priv_data->banks[i].resp_handler,
288                              adf_response_handler,
289                              (unsigned long)&priv_data->banks[i]);
290         return 0;
291 }
292
293 static void adf_cleanup_bh(struct adf_accel_dev *accel_dev)
294 {
295         struct adf_etr_data *priv_data = accel_dev->transport;
296         struct adf_hw_device_data *hw_data = accel_dev->hw_device;
297         int i;
298
299         for (i = 0; i < hw_data->num_banks; i++) {
300                 tasklet_disable(&priv_data->banks[i].resp_handler);
301                 tasklet_kill(&priv_data->banks[i].resp_handler);
302         }
303 }
304
305 /**
306  * adf_isr_resource_free() - Free IRQ for acceleration device
307  * @accel_dev:  Pointer to acceleration device.
308  *
309  * Function frees interrupts for acceleration device.
310  */
311 void adf_isr_resource_free(struct adf_accel_dev *accel_dev)
312 {
313         adf_free_irqs(accel_dev);
314         adf_cleanup_bh(accel_dev);
315         adf_disable_msix(&accel_dev->accel_pci_dev);
316         adf_isr_free_msix_entry_table(accel_dev);
317 }
318 EXPORT_SYMBOL_GPL(adf_isr_resource_free);
319
320 /**
321  * adf_isr_resource_alloc() - Allocate IRQ for acceleration device
322  * @accel_dev:  Pointer to acceleration device.
323  *
324  * Function allocates interrupts for acceleration device.
325  *
326  * Return: 0 on success, error code otherwise.
327  */
328 int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev)
329 {
330         int ret;
331
332         ret = adf_isr_alloc_msix_entry_table(accel_dev);
333         if (ret)
334                 goto err_out;
335
336         ret = adf_enable_msix(accel_dev);
337         if (ret)
338                 goto err_free_msix_table;
339
340         ret = adf_setup_bh(accel_dev);
341         if (ret)
342                 goto err_disable_msix;
343
344         ret = adf_request_irqs(accel_dev);
345         if (ret)
346                 goto err_cleanup_bh;
347
348         return 0;
349
350 err_cleanup_bh:
351         adf_cleanup_bh(accel_dev);
352
353 err_disable_msix:
354         adf_disable_msix(&accel_dev->accel_pci_dev);
355
356 err_free_msix_table:
357         adf_isr_free_msix_entry_table(accel_dev);
358
359 err_out:
360         return ret;
361 }
362 EXPORT_SYMBOL_GPL(adf_isr_resource_alloc);