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