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