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
27 static 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
32 static u32
adf_gen4_vf_get_pfvf_offset(u32 i)33 adf_gen4_vf_get_pfvf_offset(u32 i)
34 {
35 return ADF_4XXXIOV_PF2VM_OFFSET;
36 }
37
38 static u32
adf_gen4_vf_get_vfpf_offset(u32 i)39 adf_gen4_vf_get_vfpf_offset(u32 i)
40 {
41 return ADF_4XXXIOV_VM2PF_OFFSET;
42 }
43
44 static int
adf_gen4_pfvf_send(struct adf_accel_dev * accel_dev,struct pfvf_message msg,u32 pfvf_offset,struct mutex * csr_lock)45 adf_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
78 static int
adf_gen4_vf2pf_send(struct adf_accel_dev * accel_dev,struct pfvf_message msg,u32 pfvf_offset,struct mutex * csr_lock)79 adf_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
87 static struct pfvf_message
adf_gen4_pfvf_recv(struct adf_accel_dev * accel_dev,u32 pfvf_offset,u8 compat_ver)88 adf_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
114 static struct pfvf_message
adf_gen4_pf2vf_recv(struct adf_accel_dev * accel_dev,u32 pfvf_offset,u8 compat_ver)115 adf_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
122 void
adf_gen4_init_vf_pfvf_ops(struct adf_pfvf_ops * pfvf_ops)123 adf_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