• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <adf_pf2vf_msg.h>
62 #include "adf_drv.h"
63 #include "adf_dh895xccvf_hw_data.h"
64 
adf_enable_msi(struct adf_accel_dev * accel_dev)65 static int adf_enable_msi(struct adf_accel_dev *accel_dev)
66 {
67 	struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
68 	int stat = pci_enable_msi(pci_dev_info->pci_dev);
69 
70 	if (stat) {
71 		dev_err(&GET_DEV(accel_dev),
72 			"Failed to enable MSI interrupts\n");
73 		return stat;
74 	}
75 
76 	accel_dev->vf.irq_name = kzalloc(ADF_MAX_MSIX_VECTOR_NAME, GFP_KERNEL);
77 	if (!accel_dev->vf.irq_name)
78 		return -ENOMEM;
79 
80 	return stat;
81 }
82 
adf_disable_msi(struct adf_accel_dev * accel_dev)83 static void adf_disable_msi(struct adf_accel_dev *accel_dev)
84 {
85 	struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
86 
87 	kfree(accel_dev->vf.irq_name);
88 	pci_disable_msi(pdev);
89 }
90 
adf_pf2vf_bh_handler(void * data)91 static void adf_pf2vf_bh_handler(void *data)
92 {
93 	struct adf_accel_dev *accel_dev = data;
94 	void __iomem *pmisc_bar_addr =
95 		(&GET_BARS(accel_dev)[ADF_DH895XCCIOV_PMISC_BAR])->virt_addr;
96 	u32 msg;
97 
98 	/* Read the message from PF */
99 	msg = ADF_CSR_RD(pmisc_bar_addr, ADF_DH895XCCIOV_PF2VF_OFFSET);
100 
101 	if (!(msg & ADF_PF2VF_MSGORIGIN_SYSTEM))
102 		/* Ignore legacy non-system (non-kernel) PF2VF messages */
103 		goto err;
104 
105 	switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) {
106 	case ADF_PF2VF_MSGTYPE_RESTARTING:
107 		dev_dbg(&GET_DEV(accel_dev),
108 			"Restarting msg received from PF 0x%x\n", msg);
109 		adf_dev_stop(accel_dev);
110 		break;
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);
121 		break;
122 	default:
123 		goto err;
124 	}
125 
126 	/* To ack, clear the PF2VFINT bit */
127 	msg &= ~ADF_DH895XCC_PF2VF_PF2VFINT;
128 	ADF_CSR_WR(pmisc_bar_addr, ADF_DH895XCCIOV_PF2VF_OFFSET, msg);
129 
130 	/* Re-enable PF2VF interrupts */
131 	adf_enable_pf2vf_interrupts(accel_dev);
132 	return;
133 err:
134 	dev_err(&GET_DEV(accel_dev),
135 		"Unknown message from PF (0x%x); leaving PF2VF ints disabled\n",
136 		msg);
137 }
138 
adf_setup_pf2vf_bh(struct adf_accel_dev * accel_dev)139 static int adf_setup_pf2vf_bh(struct adf_accel_dev *accel_dev)
140 {
141 	tasklet_init(&accel_dev->vf.pf2vf_bh_tasklet,
142 		     (void *)adf_pf2vf_bh_handler, (unsigned long)accel_dev);
143 
144 	mutex_init(&accel_dev->vf.vf2pf_lock);
145 	return 0;
146 }
147 
adf_cleanup_pf2vf_bh(struct adf_accel_dev * accel_dev)148 static void adf_cleanup_pf2vf_bh(struct adf_accel_dev *accel_dev)
149 {
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);
153 }
154 
adf_isr(int irq,void * privdata)155 static irqreturn_t adf_isr(int irq, void *privdata)
156 {
157 	struct adf_accel_dev *accel_dev = privdata;
158 	void __iomem *pmisc_bar_addr =
159 		(&GET_BARS(accel_dev)[ADF_DH895XCCIOV_PMISC_BAR])->virt_addr;
160 	u32 v_int;
161 
162 	/* Read VF INT source CSR to determine the source of VF interrupt */
163 	v_int = ADF_CSR_RD(pmisc_bar_addr, ADF_DH895XCCIOV_VINTSOU_OFFSET);
164 
165 	/* Check for PF2VF interrupt */
166 	if (v_int & ADF_DH895XCC_VINTSOU_PF2VF) {
167 		/* Disable PF to VF interrupt */
168 		adf_disable_pf2vf_interrupts(accel_dev);
169 
170 		/* Schedule tasklet to handle interrupt BH */
171 		tasklet_hi_schedule(&accel_dev->vf.pf2vf_bh_tasklet);
172 		return IRQ_HANDLED;
173 	}
174 
175 	/* Check bundle interrupt */
176 	if (v_int & ADF_DH895XCC_VINTSOU_BUN) {
177 		struct adf_etr_data *etr_data = accel_dev->transport;
178 		struct adf_etr_bank_data *bank = &etr_data->banks[0];
179 
180 		/* Disable Flag and Coalesce Ring Interrupts */
181 		WRITE_CSR_INT_FLAG_AND_COL(bank->csr_addr, bank->bank_number,
182 					   0);
183 		tasklet_hi_schedule(&bank->resp_handler);
184 		return IRQ_HANDLED;
185 	}
186 
187 	return IRQ_NONE;
188 }
189 
adf_request_msi_irq(struct adf_accel_dev * accel_dev)190 static int adf_request_msi_irq(struct adf_accel_dev *accel_dev)
191 {
192 	struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
193 	unsigned int cpu;
194 	int ret;
195 
196 	snprintf(accel_dev->vf.irq_name, ADF_MAX_MSIX_VECTOR_NAME,
197 		 "qat_%02x:%02d.%02d", pdev->bus->number, PCI_SLOT(pdev->devfn),
198 		 PCI_FUNC(pdev->devfn));
199 	ret = request_irq(pdev->irq, adf_isr, 0, accel_dev->vf.irq_name,
200 			  (void *)accel_dev);
201 	if (ret) {
202 		dev_err(&GET_DEV(accel_dev), "failed to enable irq for %s\n",
203 			accel_dev->vf.irq_name);
204 		return ret;
205 	}
206 	cpu = accel_dev->accel_id % num_online_cpus();
207 	irq_set_affinity_hint(pdev->irq, get_cpu_mask(cpu));
208 
209 	return ret;
210 }
211 
adf_setup_bh(struct adf_accel_dev * accel_dev)212 static int adf_setup_bh(struct adf_accel_dev *accel_dev)
213 {
214 	struct adf_etr_data *priv_data = accel_dev->transport;
215 
216 	tasklet_init(&priv_data->banks[0].resp_handler, adf_response_handler,
217 		     (unsigned long)priv_data->banks);
218 	return 0;
219 }
220 
adf_cleanup_bh(struct adf_accel_dev * accel_dev)221 static void adf_cleanup_bh(struct adf_accel_dev *accel_dev)
222 {
223 	struct adf_etr_data *priv_data = accel_dev->transport;
224 
225 	tasklet_disable(&priv_data->banks[0].resp_handler);
226 	tasklet_kill(&priv_data->banks[0].resp_handler);
227 }
228 
adf_vf_isr_resource_free(struct adf_accel_dev * accel_dev)229 void adf_vf_isr_resource_free(struct adf_accel_dev *accel_dev)
230 {
231 	struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
232 
233 	irq_set_affinity_hint(pdev->irq, NULL);
234 	free_irq(pdev->irq, (void *)accel_dev);
235 	adf_cleanup_bh(accel_dev);
236 	adf_cleanup_pf2vf_bh(accel_dev);
237 	adf_disable_msi(accel_dev);
238 }
239 
adf_vf_isr_resource_alloc(struct adf_accel_dev * accel_dev)240 int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev)
241 {
242 	if (adf_enable_msi(accel_dev))
243 		goto err_out;
244 
245 	if (adf_setup_pf2vf_bh(accel_dev))
246 		goto err_disable_msi;
247 
248 	if (adf_setup_bh(accel_dev))
249 		goto err_cleanup_pf2vf_bh;
250 
251 	if (adf_request_msi_irq(accel_dev))
252 		goto err_cleanup_bh;
253 
254 	return 0;
255 
256 err_cleanup_bh:
257 	adf_cleanup_bh(accel_dev);
258 
259 err_cleanup_pf2vf_bh:
260 	adf_cleanup_pf2vf_bh(accel_dev);
261 
262 err_disable_msi:
263 	adf_disable_msi(accel_dev);
264 
265 err_out:
266 	return -EFAULT;
267 }
268