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