crypto: qat - Move driver to drivers/crypto/intel/qat
[linux-2.6-microblaze.git] / drivers / crypto / intel / qat / qat_common / adf_gen4_pfvf.c
1 // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
2 /* Copyright(c) 2021 Intel Corporation */
3 #include <linux/iopoll.h>
4 #include <linux/mutex.h>
5 #include <linux/types.h>
6 #include "adf_accel_devices.h"
7 #include "adf_common_drv.h"
8 #include "adf_gen4_pfvf.h"
9 #include "adf_pfvf_pf_proto.h"
10 #include "adf_pfvf_utils.h"
11
12 #define ADF_4XXX_PF2VM_OFFSET(i)        (0x40B010 + ((i) * 0x20))
13 #define ADF_4XXX_VM2PF_OFFSET(i)        (0x40B014 + ((i) * 0x20))
14
15 /* VF2PF interrupt source registers */
16 #define ADF_4XXX_VM2PF_SOU              0x41A180
17 #define ADF_4XXX_VM2PF_MSK              0x41A1C0
18 #define ADF_GEN4_VF_MSK                 0xFFFF
19
20 #define ADF_PFVF_GEN4_MSGTYPE_SHIFT     2
21 #define ADF_PFVF_GEN4_MSGTYPE_MASK      0x3F
22 #define ADF_PFVF_GEN4_MSGDATA_SHIFT     8
23 #define ADF_PFVF_GEN4_MSGDATA_MASK      0xFFFFFF
24
25 static const struct pfvf_csr_format csr_gen4_fmt = {
26         { ADF_PFVF_GEN4_MSGTYPE_SHIFT, ADF_PFVF_GEN4_MSGTYPE_MASK },
27         { ADF_PFVF_GEN4_MSGDATA_SHIFT, ADF_PFVF_GEN4_MSGDATA_MASK },
28 };
29
30 static u32 adf_gen4_pf_get_pf2vf_offset(u32 i)
31 {
32         return ADF_4XXX_PF2VM_OFFSET(i);
33 }
34
35 static u32 adf_gen4_pf_get_vf2pf_offset(u32 i)
36 {
37         return ADF_4XXX_VM2PF_OFFSET(i);
38 }
39
40 static void adf_gen4_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask)
41 {
42         u32 val;
43
44         val = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK) & ~vf_mask;
45         ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, val);
46 }
47
48 static void adf_gen4_disable_all_vf2pf_interrupts(void __iomem *pmisc_addr)
49 {
50         ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, ADF_GEN4_VF_MSK);
51 }
52
53 static u32 adf_gen4_disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr)
54 {
55         u32 sources, disabled, pending;
56
57         /* Get the interrupt sources triggered by VFs */
58         sources = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_SOU);
59         if (!sources)
60                 return 0;
61
62         /* Get the already disabled interrupts */
63         disabled = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK);
64
65         pending = sources & ~disabled;
66         if (!pending)
67                 return 0;
68
69         /* Due to HW limitations, when disabling the interrupts, we can't
70          * just disable the requested sources, as this would lead to missed
71          * interrupts if VM2PF_SOU changes just before writing to VM2PF_MSK.
72          * To work around it, disable all and re-enable only the sources that
73          * are not in vf_mask and were not already disabled. Re-enabling will
74          * trigger a new interrupt for the sources that have changed in the
75          * meantime, if any.
76          */
77         ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, ADF_GEN4_VF_MSK);
78         ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, disabled | sources);
79
80         /* Return the sources of the (new) interrupt(s) */
81         return pending;
82 }
83
84 static int adf_gen4_pfvf_send(struct adf_accel_dev *accel_dev,
85                               struct pfvf_message msg, u32 pfvf_offset,
86                               struct mutex *csr_lock)
87 {
88         void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
89         u32 csr_val;
90         int ret;
91
92         csr_val = adf_pfvf_csr_msg_of(accel_dev, msg, &csr_gen4_fmt);
93         if (unlikely(!csr_val))
94                 return -EINVAL;
95
96         mutex_lock(csr_lock);
97
98         ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val | ADF_PFVF_INT);
99
100         /* Wait for confirmation from remote that it received the message */
101         ret = read_poll_timeout(ADF_CSR_RD, csr_val, !(csr_val & ADF_PFVF_INT),
102                                 ADF_PFVF_MSG_ACK_DELAY_US,
103                                 ADF_PFVF_MSG_ACK_MAX_DELAY_US,
104                                 true, pmisc_addr, pfvf_offset);
105         if (ret < 0)
106                 dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n");
107
108         mutex_unlock(csr_lock);
109         return ret;
110 }
111
112 static struct pfvf_message adf_gen4_pfvf_recv(struct adf_accel_dev *accel_dev,
113                                               u32 pfvf_offset, u8 compat_ver)
114 {
115         void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
116         struct pfvf_message msg = { 0 };
117         u32 csr_val;
118
119         /* Read message from the CSR */
120         csr_val = ADF_CSR_RD(pmisc_addr, pfvf_offset);
121         if (!(csr_val & ADF_PFVF_INT)) {
122                 dev_info(&GET_DEV(accel_dev),
123                          "Spurious PFVF interrupt, msg 0x%.8x. Ignored\n", csr_val);
124                 return msg;
125         }
126
127         /* We can now acknowledge the message reception by clearing the
128          * interrupt bit
129          */
130         ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val & ~ADF_PFVF_INT);
131
132         /* Return the pfvf_message format */
133         return adf_pfvf_message_of(accel_dev, csr_val, &csr_gen4_fmt);
134 }
135
136 void adf_gen4_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops)
137 {
138         pfvf_ops->enable_comms = adf_enable_pf2vf_comms;
139         pfvf_ops->get_pf2vf_offset = adf_gen4_pf_get_pf2vf_offset;
140         pfvf_ops->get_vf2pf_offset = adf_gen4_pf_get_vf2pf_offset;
141         pfvf_ops->enable_vf2pf_interrupts = adf_gen4_enable_vf2pf_interrupts;
142         pfvf_ops->disable_all_vf2pf_interrupts = adf_gen4_disable_all_vf2pf_interrupts;
143         pfvf_ops->disable_pending_vf2pf_interrupts = adf_gen4_disable_pending_vf2pf_interrupts;
144         pfvf_ops->send_msg = adf_gen4_pfvf_send;
145         pfvf_ops->recv_msg = adf_gen4_pfvf_recv;
146 }
147 EXPORT_SYMBOL_GPL(adf_gen4_init_pf_pfvf_ops);