1 // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
2 /* Copyright(c) 2014 - 2020 Intel Corporation */
3 #include <linux/kernel.h>
4 #include <linux/init.h>
5 #include <linux/types.h>
7 #include <linux/slab.h>
8 #include <linux/errno.h>
9 #include <linux/interrupt.h>
10 #include <linux/workqueue.h>
11 #include "adf_accel_devices.h"
12 #include "adf_common_drv.h"
14 #include "adf_cfg_strings.h"
15 #include "adf_cfg_common.h"
16 #include "adf_transport_access_macros.h"
17 #include "adf_transport_internal.h"
18 #include "adf_pf2vf_msg.h"
20 #define ADF_VINTSOU_OFFSET 0x204
21 #define ADF_VINTSOU_BUN BIT(0)
22 #define ADF_VINTSOU_PF2VF BIT(1)
24 static struct workqueue_struct
*adf_vf_stop_wq
;
26 struct adf_vf_stop_data
{
27 struct adf_accel_dev
*accel_dev
;
28 struct work_struct work
;
31 static int adf_enable_msi(struct adf_accel_dev
*accel_dev
)
33 struct adf_accel_pci
*pci_dev_info
= &accel_dev
->accel_pci_dev
;
34 int stat
= pci_enable_msi(pci_dev_info
->pci_dev
);
37 dev_err(&GET_DEV(accel_dev
),
38 "Failed to enable MSI interrupts\n");
42 accel_dev
->vf
.irq_name
= kzalloc(ADF_MAX_MSIX_VECTOR_NAME
, GFP_KERNEL
);
43 if (!accel_dev
->vf
.irq_name
)
49 static void adf_disable_msi(struct adf_accel_dev
*accel_dev
)
51 struct pci_dev
*pdev
= accel_to_pci_dev(accel_dev
);
53 kfree(accel_dev
->vf
.irq_name
);
54 pci_disable_msi(pdev
);
57 static void adf_dev_stop_async(struct work_struct
*work
)
59 struct adf_vf_stop_data
*stop_data
=
60 container_of(work
, struct adf_vf_stop_data
, work
);
61 struct adf_accel_dev
*accel_dev
= stop_data
->accel_dev
;
63 adf_dev_stop(accel_dev
);
64 adf_dev_shutdown(accel_dev
);
66 /* Re-enable PF2VF interrupts */
67 adf_enable_pf2vf_interrupts(accel_dev
);
71 static void adf_pf2vf_bh_handler(void *data
)
73 struct adf_accel_dev
*accel_dev
= data
;
74 struct adf_hw_device_data
*hw_data
= accel_dev
->hw_device
;
75 struct adf_bar
*pmisc
=
76 &GET_BARS(accel_dev
)[hw_data
->get_misc_bar_id(hw_data
)];
77 void __iomem
*pmisc_bar_addr
= pmisc
->virt_addr
;
80 /* Read the message from PF */
81 msg
= ADF_CSR_RD(pmisc_bar_addr
, hw_data
->get_pf2vf_offset(0));
83 if (!(msg
& ADF_PF2VF_MSGORIGIN_SYSTEM
))
84 /* Ignore legacy non-system (non-kernel) PF2VF messages */
87 switch ((msg
& ADF_PF2VF_MSGTYPE_MASK
) >> ADF_PF2VF_MSGTYPE_SHIFT
) {
88 case ADF_PF2VF_MSGTYPE_RESTARTING
: {
89 struct adf_vf_stop_data
*stop_data
;
91 dev_dbg(&GET_DEV(accel_dev
),
92 "Restarting msg received from PF 0x%x\n", msg
);
94 clear_bit(ADF_STATUS_PF_RUNNING
, &accel_dev
->status
);
96 stop_data
= kzalloc(sizeof(*stop_data
), GFP_ATOMIC
);
98 dev_err(&GET_DEV(accel_dev
),
99 "Couldn't schedule stop for vf_%d\n",
100 accel_dev
->accel_id
);
103 stop_data
->accel_dev
= accel_dev
;
104 INIT_WORK(&stop_data
->work
, adf_dev_stop_async
);
105 queue_work(adf_vf_stop_wq
, &stop_data
->work
);
106 /* To ack, clear the PF2VFINT bit */
107 msg
&= ~ADF_PF2VF_INT
;
108 ADF_CSR_WR(pmisc_bar_addr
, hw_data
->get_pf2vf_offset(0), msg
);
111 case ADF_PF2VF_MSGTYPE_VERSION_RESP
:
112 dev_dbg(&GET_DEV(accel_dev
),
113 "Version resp received from PF 0x%x\n", msg
);
114 accel_dev
->vf
.pf_version
=
115 (msg
& ADF_PF2VF_VERSION_RESP_VERS_MASK
) >>
116 ADF_PF2VF_VERSION_RESP_VERS_SHIFT
;
117 accel_dev
->vf
.compatible
=
118 (msg
& ADF_PF2VF_VERSION_RESP_RESULT_MASK
) >>
119 ADF_PF2VF_VERSION_RESP_RESULT_SHIFT
;
120 complete(&accel_dev
->vf
.iov_msg_completion
);
126 /* To ack, clear the PF2VFINT bit */
127 msg
&= ~ADF_PF2VF_INT
;
128 ADF_CSR_WR(pmisc_bar_addr
, hw_data
->get_pf2vf_offset(0), msg
);
130 /* Re-enable PF2VF interrupts */
131 adf_enable_pf2vf_interrupts(accel_dev
);
134 dev_err(&GET_DEV(accel_dev
),
135 "Unknown message from PF (0x%x); leaving PF2VF ints disabled\n",
139 static int adf_setup_pf2vf_bh(struct adf_accel_dev
*accel_dev
)
141 tasklet_init(&accel_dev
->vf
.pf2vf_bh_tasklet
,
142 (void *)adf_pf2vf_bh_handler
, (unsigned long)accel_dev
);
144 mutex_init(&accel_dev
->vf
.vf2pf_lock
);
148 static void adf_cleanup_pf2vf_bh(struct adf_accel_dev
*accel_dev
)
150 tasklet_disable(&accel_dev
->vf
.pf2vf_bh_tasklet
);
151 tasklet_kill(&accel_dev
->vf
.pf2vf_bh_tasklet
);
152 mutex_destroy(&accel_dev
->vf
.vf2pf_lock
);
155 static irqreturn_t
adf_isr(int irq
, void *privdata
)
157 struct adf_accel_dev
*accel_dev
= privdata
;
158 struct adf_hw_device_data
*hw_data
= accel_dev
->hw_device
;
159 struct adf_hw_csr_ops
*csr_ops
= &hw_data
->csr_ops
;
160 struct adf_bar
*pmisc
=
161 &GET_BARS(accel_dev
)[hw_data
->get_misc_bar_id(hw_data
)];
162 void __iomem
*pmisc_bar_addr
= pmisc
->virt_addr
;
165 /* Read VF INT source CSR to determine the source of VF interrupt */
166 v_int
= ADF_CSR_RD(pmisc_bar_addr
, ADF_VINTSOU_OFFSET
);
168 /* Check for PF2VF interrupt */
169 if (v_int
& ADF_VINTSOU_PF2VF
) {
170 /* Disable PF to VF interrupt */
171 adf_disable_pf2vf_interrupts(accel_dev
);
173 /* Schedule tasklet to handle interrupt BH */
174 tasklet_hi_schedule(&accel_dev
->vf
.pf2vf_bh_tasklet
);
178 /* Check bundle interrupt */
179 if (v_int
& ADF_VINTSOU_BUN
) {
180 struct adf_etr_data
*etr_data
= accel_dev
->transport
;
181 struct adf_etr_bank_data
*bank
= &etr_data
->banks
[0];
183 /* Disable Flag and Coalesce Ring Interrupts */
184 csr_ops
->write_csr_int_flag_and_col(bank
->csr_addr
,
185 bank
->bank_number
, 0);
186 tasklet_hi_schedule(&bank
->resp_handler
);
193 static int adf_request_msi_irq(struct adf_accel_dev
*accel_dev
)
195 struct pci_dev
*pdev
= accel_to_pci_dev(accel_dev
);
199 snprintf(accel_dev
->vf
.irq_name
, ADF_MAX_MSIX_VECTOR_NAME
,
200 "qat_%02x:%02d.%02d", pdev
->bus
->number
, PCI_SLOT(pdev
->devfn
),
201 PCI_FUNC(pdev
->devfn
));
202 ret
= request_irq(pdev
->irq
, adf_isr
, 0, accel_dev
->vf
.irq_name
,
205 dev_err(&GET_DEV(accel_dev
), "failed to enable irq for %s\n",
206 accel_dev
->vf
.irq_name
);
209 cpu
= accel_dev
->accel_id
% num_online_cpus();
210 irq_set_affinity_hint(pdev
->irq
, get_cpu_mask(cpu
));
215 static int adf_setup_bh(struct adf_accel_dev
*accel_dev
)
217 struct adf_etr_data
*priv_data
= accel_dev
->transport
;
219 tasklet_init(&priv_data
->banks
[0].resp_handler
, adf_response_handler
,
220 (unsigned long)priv_data
->banks
);
224 static void adf_cleanup_bh(struct adf_accel_dev
*accel_dev
)
226 struct adf_etr_data
*priv_data
= accel_dev
->transport
;
228 tasklet_disable(&priv_data
->banks
[0].resp_handler
);
229 tasklet_kill(&priv_data
->banks
[0].resp_handler
);
233 * adf_vf_isr_resource_free() - Free IRQ for acceleration device
234 * @accel_dev: Pointer to acceleration device.
236 * Function frees interrupts for acceleration device virtual function.
238 void adf_vf_isr_resource_free(struct adf_accel_dev
*accel_dev
)
240 struct pci_dev
*pdev
= accel_to_pci_dev(accel_dev
);
242 irq_set_affinity_hint(pdev
->irq
, NULL
);
243 free_irq(pdev
->irq
, (void *)accel_dev
);
244 adf_cleanup_bh(accel_dev
);
245 adf_cleanup_pf2vf_bh(accel_dev
);
246 adf_disable_msi(accel_dev
);
248 EXPORT_SYMBOL_GPL(adf_vf_isr_resource_free
);
251 * adf_vf_isr_resource_alloc() - Allocate IRQ for acceleration device
252 * @accel_dev: Pointer to acceleration device.
254 * Function allocates interrupts for acceleration device virtual function.
256 * Return: 0 on success, error code otherwise.
258 int adf_vf_isr_resource_alloc(struct adf_accel_dev
*accel_dev
)
260 if (adf_enable_msi(accel_dev
))
263 if (adf_setup_pf2vf_bh(accel_dev
))
266 if (adf_setup_bh(accel_dev
))
269 if (adf_request_msi_irq(accel_dev
))
274 adf_vf_isr_resource_free(accel_dev
);
277 EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc
);
279 int __init
adf_init_vf_wq(void)
281 adf_vf_stop_wq
= alloc_workqueue("adf_vf_stop_wq", WQ_MEM_RECLAIM
, 0);
283 return !adf_vf_stop_wq
? -EFAULT
: 0;
286 void adf_exit_vf_wq(void)
289 destroy_workqueue(adf_vf_stop_wq
);
291 adf_vf_stop_wq
= NULL
;