1/* SPDX-License-Identifier: BSD-3-Clause */
2/* Copyright(c) 2007-2022 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_utils.h"
10#include "adf_pfvf_vf_proto.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#define ADF_4XXXIOV_PF2VM_OFFSET 0x100C
26#define ADF_4XXXIOV_VM2PF_OFFSET 0x1008
27static const struct pfvf_csr_format csr_gen4_fmt = {
28	{ ADF_PFVF_GEN4_MSGTYPE_SHIFT, ADF_PFVF_GEN4_MSGTYPE_MASK },
29	{ ADF_PFVF_GEN4_MSGDATA_SHIFT, ADF_PFVF_GEN4_MSGDATA_MASK },
30};
31
32static u32
33adf_gen4_vf_get_pfvf_offset(u32 i)
34{
35	return ADF_4XXXIOV_PF2VM_OFFSET;
36}
37
38static u32
39adf_gen4_vf_get_vfpf_offset(u32 i)
40{
41	return ADF_4XXXIOV_VM2PF_OFFSET;
42}
43
44static int
45adf_gen4_pfvf_send(struct adf_accel_dev *accel_dev,
46		   struct pfvf_message msg,
47		   u32 pfvf_offset,
48		   struct mutex *csr_lock)
49{
50	struct resource *pmisc_addr = adf_get_pmisc_base(accel_dev);
51	u32 csr_val;
52	int ret;
53	csr_val = adf_pfvf_csr_msg_of(accel_dev, msg, &csr_gen4_fmt);
54	if (unlikely(!csr_val))
55		return -EINVAL;
56
57	mutex_lock(csr_lock);
58
59	ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val | ADF_PFVF_INT);
60
61	/* Wait for confirmation from remote that it received the message */
62	ret = read_poll_timeout(ADF_CSR_RD,
63				csr_val,
64				!(csr_val & ADF_PFVF_INT),
65				ADF_PFVF_MSG_ACK_DELAY_US,
66				ADF_PFVF_MSG_ACK_MAX_DELAY_US,
67				true,
68				pmisc_addr,
69				pfvf_offset);
70	if (ret < 0)
71		device_printf(GET_DEV(accel_dev),
72			      "ACK not received from remote\n");
73
74	mutex_unlock(csr_lock);
75	return ret;
76}
77
78static int
79adf_gen4_vf2pf_send(struct adf_accel_dev *accel_dev,
80		    struct pfvf_message msg,
81		    u32 pfvf_offset,
82		    struct mutex *csr_lock)
83{
84	return adf_gen4_pfvf_send(accel_dev, msg, pfvf_offset, csr_lock);
85}
86
87static struct pfvf_message
88adf_gen4_pfvf_recv(struct adf_accel_dev *accel_dev,
89		   u32 pfvf_offset,
90		   u8 compat_ver)
91{
92	struct resource *pmisc_addr = adf_get_pmisc_base(accel_dev);
93	struct pfvf_message msg = { 0 };
94	u32 csr_val;
95
96	/* Read message from the CSR */
97	csr_val = ADF_CSR_RD(pmisc_addr, pfvf_offset);
98	if (!(csr_val & ADF_PFVF_INT)) {
99		device_printf(GET_DEV(accel_dev),
100			      "Spurious PFVF interrupt, msg 0x%.8x. Ignored\n",
101			      csr_val);
102		return msg;
103	}
104
105	/* We can now acknowledge the message reception by clearing the
106	 * interrupt bit
107	 */
108	ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val & ~ADF_PFVF_INT);
109
110	/* Return the pfvf_message format */
111	return adf_pfvf_message_of(accel_dev, csr_val, &csr_gen4_fmt);
112}
113
114static struct pfvf_message
115adf_gen4_pf2vf_recv(struct adf_accel_dev *accel_dev,
116		    u32 pfvf_offset,
117		    u8 compat_ver)
118{
119	return adf_gen4_pfvf_recv(accel_dev, pfvf_offset, compat_ver);
120}
121
122void
123adf_gen4_init_vf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops)
124{
125	pfvf_ops->enable_comms = adf_enable_vf2pf_comms;
126	pfvf_ops->get_pf2vf_offset = adf_gen4_vf_get_pfvf_offset;
127	pfvf_ops->get_vf2pf_offset = adf_gen4_vf_get_vfpf_offset;
128	pfvf_ops->send_msg = adf_gen4_vf2pf_send;
129	pfvf_ops->recv_msg = adf_gen4_pf2vf_recv;
130}
131