1 // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
2 /* Copyright(c) 2015 - 2020 Intel Corporation */
3 #include <linux/delay.h>
4 #include "adf_accel_devices.h"
5 #include "adf_common_drv.h"
6 #include "adf_pf2vf_msg.h"
7
8 #define ADF_DH895XCC_EP_OFFSET 0x3A000
9 #define ADF_DH895XCC_ERRMSK3 (ADF_DH895XCC_EP_OFFSET + 0x1C)
10 #define ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask) ((vf_mask & 0xFFFF) << 9)
11 #define ADF_DH895XCC_ERRMSK5 (ADF_DH895XCC_EP_OFFSET + 0xDC)
12 #define ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask) (vf_mask >> 16)
13
__adf_enable_vf2pf_interrupts(struct adf_accel_dev * accel_dev,u32 vf_mask)14 static void __adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,
15 u32 vf_mask)
16 {
17 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
18 struct adf_bar *pmisc =
19 &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
20 void __iomem *pmisc_addr = pmisc->virt_addr;
21 u32 reg;
22
23 /* Enable VF2PF Messaging Ints - VFs 1 through 16 per vf_mask[15:0] */
24 if (vf_mask & 0xFFFF) {
25 reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3);
26 reg &= ~ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask);
27 ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg);
28 }
29
30 /* Enable VF2PF Messaging Ints - VFs 17 through 32 per vf_mask[31:16] */
31 if (vf_mask >> 16) {
32 reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5);
33 reg &= ~ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask);
34 ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg);
35 }
36 }
37
adf_enable_vf2pf_interrupts(struct adf_accel_dev * accel_dev,u32 vf_mask)38 void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
39 {
40 unsigned long flags;
41
42 spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
43 __adf_enable_vf2pf_interrupts(accel_dev, vf_mask);
44 spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
45 }
46
__adf_disable_vf2pf_interrupts(struct adf_accel_dev * accel_dev,u32 vf_mask)47 static void __adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,
48 u32 vf_mask)
49 {
50 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
51 struct adf_bar *pmisc =
52 &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
53 void __iomem *pmisc_addr = pmisc->virt_addr;
54 u32 reg;
55
56 /* Disable VF2PF interrupts for VFs 1 through 16 per vf_mask[15:0] */
57 if (vf_mask & 0xFFFF) {
58 reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3) |
59 ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask);
60 ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg);
61 }
62
63 /* Disable VF2PF interrupts for VFs 17 through 32 per vf_mask[31:16] */
64 if (vf_mask >> 16) {
65 reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5) |
66 ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask);
67 ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg);
68 }
69 }
70
adf_disable_vf2pf_interrupts(struct adf_accel_dev * accel_dev,u32 vf_mask)71 void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
72 {
73 unsigned long flags;
74
75 spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
76 __adf_disable_vf2pf_interrupts(accel_dev, vf_mask);
77 spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
78 }
79
adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev * accel_dev,u32 vf_mask)80 void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, u32 vf_mask)
81 {
82 spin_lock(&accel_dev->pf.vf2pf_ints_lock);
83 __adf_disable_vf2pf_interrupts(accel_dev, vf_mask);
84 spin_unlock(&accel_dev->pf.vf2pf_ints_lock);
85 }
86
__adf_iov_putmsg(struct adf_accel_dev * accel_dev,u32 msg,u8 vf_nr)87 static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr)
88 {
89 struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev;
90 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
91 void __iomem *pmisc_bar_addr =
92 pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr;
93 u32 val, pf2vf_offset, count = 0;
94 u32 local_in_use_mask, local_in_use_pattern;
95 u32 remote_in_use_mask, remote_in_use_pattern;
96 struct mutex *lock; /* lock preventing concurrent acces of CSR */
97 u32 int_bit;
98 int ret = 0;
99
100 if (accel_dev->is_vf) {
101 pf2vf_offset = hw_data->get_pf2vf_offset(0);
102 lock = &accel_dev->vf.vf2pf_lock;
103 local_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK;
104 local_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF;
105 remote_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK;
106 remote_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF;
107 int_bit = ADF_VF2PF_INT;
108 } else {
109 pf2vf_offset = hw_data->get_pf2vf_offset(vf_nr);
110 lock = &accel_dev->pf.vf_info[vf_nr].pf2vf_lock;
111 local_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK;
112 local_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF;
113 remote_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK;
114 remote_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF;
115 int_bit = ADF_PF2VF_INT;
116 }
117
118 mutex_lock(lock);
119
120 /* Check if the PFVF CSR is in use by remote function */
121 val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset);
122 if ((val & remote_in_use_mask) == remote_in_use_pattern) {
123 dev_dbg(&GET_DEV(accel_dev),
124 "PFVF CSR in use by remote function\n");
125 ret = -EBUSY;
126 goto out;
127 }
128
129 msg &= ~local_in_use_mask;
130 msg |= local_in_use_pattern;
131
132 /* Attempt to get ownership of the PFVF CSR */
133 ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, msg | int_bit);
134
135 /* Wait for confirmation from remote func it received the message */
136 do {
137 msleep(ADF_IOV_MSG_ACK_DELAY);
138 val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset);
139 } while ((val & int_bit) && (count++ < ADF_IOV_MSG_ACK_MAX_RETRY));
140
141 if (val & int_bit) {
142 dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n");
143 val &= ~int_bit;
144 ret = -EIO;
145 }
146
147 if (val != msg) {
148 dev_dbg(&GET_DEV(accel_dev),
149 "Collision - PFVF CSR overwritten by remote function\n");
150 ret = -EIO;
151 goto out;
152 }
153
154 /* Finished with the PFVF CSR; relinquish it and leave msg in CSR */
155 ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, val & ~local_in_use_mask);
156 out:
157 mutex_unlock(lock);
158 return ret;
159 }
160
161 /**
162 * adf_iov_putmsg() - send PFVF message
163 * @accel_dev: Pointer to acceleration device.
164 * @msg: Message to send
165 * @vf_nr: VF number to which the message will be sent if on PF, ignored
166 * otherwise
167 *
168 * Function sends a message through the PFVF channel
169 *
170 * Return: 0 on success, error code otherwise.
171 */
adf_iov_putmsg(struct adf_accel_dev * accel_dev,u32 msg,u8 vf_nr)172 int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr)
173 {
174 u32 count = 0;
175 int ret;
176
177 do {
178 ret = __adf_iov_putmsg(accel_dev, msg, vf_nr);
179 if (ret)
180 msleep(ADF_IOV_MSG_RETRY_DELAY);
181 } while (ret && (count++ < ADF_IOV_MSG_MAX_RETRIES));
182
183 return ret;
184 }
185
adf_vf2pf_req_hndl(struct adf_accel_vf_info * vf_info)186 void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info)
187 {
188 struct adf_accel_dev *accel_dev = vf_info->accel_dev;
189 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
190 int bar_id = hw_data->get_misc_bar_id(hw_data);
191 struct adf_bar *pmisc = &GET_BARS(accel_dev)[bar_id];
192 void __iomem *pmisc_addr = pmisc->virt_addr;
193 u32 msg, resp = 0, vf_nr = vf_info->vf_nr;
194
195 /* Read message from the VF */
196 msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr));
197 if (!(msg & ADF_VF2PF_INT)) {
198 dev_info(&GET_DEV(accel_dev),
199 "Spurious VF2PF interrupt, msg %X. Ignored\n", msg);
200 goto out;
201 }
202
203 /* To ACK, clear the VF2PFINT bit */
204 msg &= ~ADF_VF2PF_INT;
205 ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr), msg);
206
207 if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM))
208 /* Ignore legacy non-system (non-kernel) VF2PF messages */
209 goto err;
210
211 switch ((msg & ADF_VF2PF_MSGTYPE_MASK) >> ADF_VF2PF_MSGTYPE_SHIFT) {
212 case ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ:
213 {
214 u8 vf_compat_ver = msg >> ADF_VF2PF_COMPAT_VER_REQ_SHIFT;
215
216 resp = (ADF_PF2VF_MSGORIGIN_SYSTEM |
217 (ADF_PF2VF_MSGTYPE_VERSION_RESP <<
218 ADF_PF2VF_MSGTYPE_SHIFT) |
219 (ADF_PFVF_COMPAT_THIS_VERSION <<
220 ADF_PF2VF_VERSION_RESP_VERS_SHIFT));
221
222 dev_dbg(&GET_DEV(accel_dev),
223 "Compatibility Version Request from VF%d vers=%u\n",
224 vf_nr + 1, vf_compat_ver);
225
226 if (vf_compat_ver < hw_data->min_iov_compat_ver) {
227 dev_err(&GET_DEV(accel_dev),
228 "VF (vers %d) incompatible with PF (vers %d)\n",
229 vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION);
230 resp |= ADF_PF2VF_VF_INCOMPATIBLE <<
231 ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;
232 } else if (vf_compat_ver > ADF_PFVF_COMPAT_THIS_VERSION) {
233 dev_err(&GET_DEV(accel_dev),
234 "VF (vers %d) compat with PF (vers %d) unkn.\n",
235 vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION);
236 resp |= ADF_PF2VF_VF_COMPAT_UNKNOWN <<
237 ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;
238 } else {
239 dev_dbg(&GET_DEV(accel_dev),
240 "VF (vers %d) compatible with PF (vers %d)\n",
241 vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION);
242 resp |= ADF_PF2VF_VF_COMPATIBLE <<
243 ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;
244 }
245 }
246 break;
247 case ADF_VF2PF_MSGTYPE_VERSION_REQ:
248 dev_dbg(&GET_DEV(accel_dev),
249 "Legacy VersionRequest received from VF%d 0x%x\n",
250 vf_nr + 1, msg);
251 resp = (ADF_PF2VF_MSGORIGIN_SYSTEM |
252 (ADF_PF2VF_MSGTYPE_VERSION_RESP <<
253 ADF_PF2VF_MSGTYPE_SHIFT) |
254 (ADF_PFVF_COMPAT_THIS_VERSION <<
255 ADF_PF2VF_VERSION_RESP_VERS_SHIFT));
256 resp |= ADF_PF2VF_VF_COMPATIBLE <<
257 ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;
258 /* Set legacy major and minor version num */
259 resp |= 1 << ADF_PF2VF_MAJORVERSION_SHIFT |
260 1 << ADF_PF2VF_MINORVERSION_SHIFT;
261 break;
262 case ADF_VF2PF_MSGTYPE_INIT:
263 {
264 dev_dbg(&GET_DEV(accel_dev),
265 "Init message received from VF%d 0x%x\n",
266 vf_nr + 1, msg);
267 vf_info->init = true;
268 }
269 break;
270 case ADF_VF2PF_MSGTYPE_SHUTDOWN:
271 {
272 dev_dbg(&GET_DEV(accel_dev),
273 "Shutdown message received from VF%d 0x%x\n",
274 vf_nr + 1, msg);
275 vf_info->init = false;
276 }
277 break;
278 default:
279 goto err;
280 }
281
282 if (resp && adf_iov_putmsg(accel_dev, resp, vf_nr))
283 dev_err(&GET_DEV(accel_dev), "Failed to send response to VF\n");
284
285 out:
286 /* re-enable interrupt on PF from this VF */
287 adf_enable_vf2pf_interrupts(accel_dev, (1 << vf_nr));
288
289 return;
290 err:
291 dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x);\n",
292 vf_nr + 1, msg);
293 }
294
adf_pf2vf_notify_restarting(struct adf_accel_dev * accel_dev)295 void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev)
296 {
297 struct adf_accel_vf_info *vf;
298 u32 msg = (ADF_PF2VF_MSGORIGIN_SYSTEM |
299 (ADF_PF2VF_MSGTYPE_RESTARTING << ADF_PF2VF_MSGTYPE_SHIFT));
300 int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev));
301
302 for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) {
303 if (vf->init && adf_iov_putmsg(accel_dev, msg, i))
304 dev_err(&GET_DEV(accel_dev),
305 "Failed to send restarting msg to VF%d\n", i);
306 }
307 }
308
adf_vf2pf_request_version(struct adf_accel_dev * accel_dev)309 static int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev)
310 {
311 unsigned long timeout = msecs_to_jiffies(ADF_IOV_MSG_RESP_TIMEOUT);
312 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
313 u32 msg = 0;
314 int ret;
315
316 msg = ADF_VF2PF_MSGORIGIN_SYSTEM;
317 msg |= ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ << ADF_VF2PF_MSGTYPE_SHIFT;
318 msg |= ADF_PFVF_COMPAT_THIS_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT;
319 BUILD_BUG_ON(ADF_PFVF_COMPAT_THIS_VERSION > 255);
320
321 reinit_completion(&accel_dev->vf.iov_msg_completion);
322
323 /* Send request from VF to PF */
324 ret = adf_iov_putmsg(accel_dev, msg, 0);
325 if (ret) {
326 dev_err(&GET_DEV(accel_dev),
327 "Failed to send Compatibility Version Request.\n");
328 return ret;
329 }
330
331 /* Wait for response */
332 if (!wait_for_completion_timeout(&accel_dev->vf.iov_msg_completion,
333 timeout)) {
334 dev_err(&GET_DEV(accel_dev),
335 "IOV request/response message timeout expired\n");
336 return -EIO;
337 }
338
339 /* Response from PF received, check compatibility */
340 switch (accel_dev->vf.compatible) {
341 case ADF_PF2VF_VF_COMPATIBLE:
342 break;
343 case ADF_PF2VF_VF_COMPAT_UNKNOWN:
344 /* VF is newer than PF and decides whether it is compatible */
345 if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver) {
346 accel_dev->vf.compatible = ADF_PF2VF_VF_COMPATIBLE;
347 break;
348 }
349 fallthrough;
350 case ADF_PF2VF_VF_INCOMPATIBLE:
351 dev_err(&GET_DEV(accel_dev),
352 "PF (vers %d) and VF (vers %d) are not compatible\n",
353 accel_dev->vf.pf_version,
354 ADF_PFVF_COMPAT_THIS_VERSION);
355 return -EINVAL;
356 default:
357 dev_err(&GET_DEV(accel_dev),
358 "Invalid response from PF; assume not compatible\n");
359 return -EINVAL;
360 }
361 return ret;
362 }
363
364 /**
365 * adf_enable_vf2pf_comms() - Function enables communication from vf to pf
366 *
367 * @accel_dev: Pointer to acceleration device virtual function.
368 *
369 * Return: 0 on success, error code otherwise.
370 */
adf_enable_vf2pf_comms(struct adf_accel_dev * accel_dev)371 int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev)
372 {
373 adf_enable_pf2vf_interrupts(accel_dev);
374 return adf_vf2pf_request_version(accel_dev);
375 }
376 EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms);
377