1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell OcteonTx2 RVU Admin Function driver
3 *
4 * Copyright (C) 2018 Marvell International Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11 #include <linux/module.h>
12 #include <linux/interrupt.h>
13 #include <linux/pci.h>
14
15 #include "rvu_reg.h"
16 #include "mbox.h"
17
18 static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
19
otx2_mbox_reset(struct otx2_mbox * mbox,int devid)20 void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
21 {
22 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
23 struct mbox_hdr *tx_hdr, *rx_hdr;
24
25 tx_hdr = mdev->mbase + mbox->tx_start;
26 rx_hdr = mdev->mbase + mbox->rx_start;
27
28 spin_lock(&mdev->mbox_lock);
29 mdev->msg_size = 0;
30 mdev->rsp_size = 0;
31 tx_hdr->num_msgs = 0;
32 rx_hdr->num_msgs = 0;
33 spin_unlock(&mdev->mbox_lock);
34 }
35 EXPORT_SYMBOL(otx2_mbox_reset);
36
otx2_mbox_destroy(struct otx2_mbox * mbox)37 void otx2_mbox_destroy(struct otx2_mbox *mbox)
38 {
39 mbox->reg_base = NULL;
40 mbox->hwbase = NULL;
41
42 kfree(mbox->dev);
43 mbox->dev = NULL;
44 }
45 EXPORT_SYMBOL(otx2_mbox_destroy);
46
otx2_mbox_init(struct otx2_mbox * mbox,void * hwbase,struct pci_dev * pdev,void * reg_base,int direction,int ndevs)47 int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev,
48 void *reg_base, int direction, int ndevs)
49 {
50 struct otx2_mbox_dev *mdev;
51 int devid;
52
53 switch (direction) {
54 case MBOX_DIR_AFPF:
55 case MBOX_DIR_PFVF:
56 mbox->tx_start = MBOX_DOWN_TX_START;
57 mbox->rx_start = MBOX_DOWN_RX_START;
58 mbox->tx_size = MBOX_DOWN_TX_SIZE;
59 mbox->rx_size = MBOX_DOWN_RX_SIZE;
60 break;
61 case MBOX_DIR_PFAF:
62 case MBOX_DIR_VFPF:
63 mbox->tx_start = MBOX_DOWN_RX_START;
64 mbox->rx_start = MBOX_DOWN_TX_START;
65 mbox->tx_size = MBOX_DOWN_RX_SIZE;
66 mbox->rx_size = MBOX_DOWN_TX_SIZE;
67 break;
68 case MBOX_DIR_AFPF_UP:
69 case MBOX_DIR_PFVF_UP:
70 mbox->tx_start = MBOX_UP_TX_START;
71 mbox->rx_start = MBOX_UP_RX_START;
72 mbox->tx_size = MBOX_UP_TX_SIZE;
73 mbox->rx_size = MBOX_UP_RX_SIZE;
74 break;
75 case MBOX_DIR_PFAF_UP:
76 case MBOX_DIR_VFPF_UP:
77 mbox->tx_start = MBOX_UP_RX_START;
78 mbox->rx_start = MBOX_UP_TX_START;
79 mbox->tx_size = MBOX_UP_RX_SIZE;
80 mbox->rx_size = MBOX_UP_TX_SIZE;
81 break;
82 default:
83 return -ENODEV;
84 }
85
86 switch (direction) {
87 case MBOX_DIR_AFPF:
88 case MBOX_DIR_AFPF_UP:
89 mbox->trigger = RVU_AF_AFPF_MBOX0;
90 mbox->tr_shift = 4;
91 break;
92 case MBOX_DIR_PFAF:
93 case MBOX_DIR_PFAF_UP:
94 mbox->trigger = RVU_PF_PFAF_MBOX1;
95 mbox->tr_shift = 0;
96 break;
97 case MBOX_DIR_PFVF:
98 case MBOX_DIR_PFVF_UP:
99 mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
100 mbox->tr_shift = 12;
101 break;
102 case MBOX_DIR_VFPF:
103 case MBOX_DIR_VFPF_UP:
104 mbox->trigger = RVU_VF_VFPF_MBOX1;
105 mbox->tr_shift = 0;
106 break;
107 default:
108 return -ENODEV;
109 }
110
111 mbox->reg_base = reg_base;
112 mbox->hwbase = hwbase;
113 mbox->pdev = pdev;
114
115 mbox->dev = kcalloc(ndevs, sizeof(struct otx2_mbox_dev), GFP_KERNEL);
116 if (!mbox->dev) {
117 otx2_mbox_destroy(mbox);
118 return -ENOMEM;
119 }
120
121 mbox->ndevs = ndevs;
122 for (devid = 0; devid < ndevs; devid++) {
123 mdev = &mbox->dev[devid];
124 mdev->mbase = mbox->hwbase + (devid * MBOX_SIZE);
125 spin_lock_init(&mdev->mbox_lock);
126 /* Init header to reset value */
127 otx2_mbox_reset(mbox, devid);
128 }
129
130 return 0;
131 }
132 EXPORT_SYMBOL(otx2_mbox_init);
133
otx2_mbox_wait_for_rsp(struct otx2_mbox * mbox,int devid)134 int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
135 {
136 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
137 int timeout = 0, sleep = 1;
138
139 while (mdev->num_msgs != mdev->msgs_acked) {
140 msleep(sleep);
141 timeout += sleep;
142 if (timeout >= MBOX_RSP_TIMEOUT)
143 return -EIO;
144 }
145 return 0;
146 }
147 EXPORT_SYMBOL(otx2_mbox_wait_for_rsp);
148
otx2_mbox_busy_poll_for_rsp(struct otx2_mbox * mbox,int devid)149 int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid)
150 {
151 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
152 unsigned long timeout = jiffies + 1 * HZ;
153
154 while (!time_after(jiffies, timeout)) {
155 if (mdev->num_msgs == mdev->msgs_acked)
156 return 0;
157 cpu_relax();
158 }
159 return -EIO;
160 }
161 EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp);
162
otx2_mbox_msg_send(struct otx2_mbox * mbox,int devid)163 void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
164 {
165 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
166 struct mbox_hdr *tx_hdr, *rx_hdr;
167
168 tx_hdr = mdev->mbase + mbox->tx_start;
169 rx_hdr = mdev->mbase + mbox->rx_start;
170
171 spin_lock(&mdev->mbox_lock);
172 /* Reset header for next messages */
173 mdev->msg_size = 0;
174 mdev->rsp_size = 0;
175 mdev->msgs_acked = 0;
176
177 /* Sync mbox data into memory */
178 smp_wmb();
179
180 /* num_msgs != 0 signals to the peer that the buffer has a number of
181 * messages. So this should be written after writing all the messages
182 * to the shared memory.
183 */
184 tx_hdr->num_msgs = mdev->num_msgs;
185 rx_hdr->num_msgs = 0;
186 spin_unlock(&mdev->mbox_lock);
187
188 /* The interrupt should be fired after num_msgs is written
189 * to the shared memory
190 */
191 writeq(1, (void __iomem *)mbox->reg_base +
192 (mbox->trigger | (devid << mbox->tr_shift)));
193 }
194 EXPORT_SYMBOL(otx2_mbox_msg_send);
195
otx2_mbox_alloc_msg_rsp(struct otx2_mbox * mbox,int devid,int size,int size_rsp)196 struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
197 int size, int size_rsp)
198 {
199 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
200 struct mbox_msghdr *msghdr = NULL;
201
202 spin_lock(&mdev->mbox_lock);
203 size = ALIGN(size, MBOX_MSG_ALIGN);
204 size_rsp = ALIGN(size_rsp, MBOX_MSG_ALIGN);
205 /* Check if there is space in mailbox */
206 if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset)
207 goto exit;
208 if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset)
209 goto exit;
210
211 if (mdev->msg_size == 0)
212 mdev->num_msgs = 0;
213 mdev->num_msgs++;
214
215 msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size;
216
217 /* Clear the whole msg region */
218 memset(msghdr, 0, sizeof(*msghdr) + size);
219 /* Init message header with reset values */
220 msghdr->ver = OTX2_MBOX_VERSION;
221 mdev->msg_size += size;
222 mdev->rsp_size += size_rsp;
223 msghdr->next_msgoff = mdev->msg_size + msgs_offset;
224 exit:
225 spin_unlock(&mdev->mbox_lock);
226
227 return msghdr;
228 }
229 EXPORT_SYMBOL(otx2_mbox_alloc_msg_rsp);
230
otx2_mbox_get_rsp(struct otx2_mbox * mbox,int devid,struct mbox_msghdr * msg)231 struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
232 struct mbox_msghdr *msg)
233 {
234 unsigned long imsg = mbox->tx_start + msgs_offset;
235 unsigned long irsp = mbox->rx_start + msgs_offset;
236 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
237 u16 msgs;
238
239 if (mdev->num_msgs != mdev->msgs_acked)
240 return ERR_PTR(-ENODEV);
241
242 for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
243 struct mbox_msghdr *pmsg = mdev->mbase + imsg;
244 struct mbox_msghdr *prsp = mdev->mbase + irsp;
245
246 if (msg == pmsg) {
247 if (pmsg->id != prsp->id)
248 return ERR_PTR(-ENODEV);
249 return prsp;
250 }
251
252 imsg = pmsg->next_msgoff;
253 irsp = prsp->next_msgoff;
254 }
255
256 return ERR_PTR(-ENODEV);
257 }
258 EXPORT_SYMBOL(otx2_mbox_get_rsp);
259
260 int
otx2_reply_invalid_msg(struct otx2_mbox * mbox,int devid,u16 pcifunc,u16 id)261 otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id)
262 {
263 struct msg_rsp *rsp;
264
265 rsp = (struct msg_rsp *)
266 otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
267 if (!rsp)
268 return -ENOMEM;
269 rsp->hdr.id = id;
270 rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
271 rsp->hdr.rc = MBOX_MSG_INVALID;
272 rsp->hdr.pcifunc = pcifunc;
273 return 0;
274 }
275 EXPORT_SYMBOL(otx2_reply_invalid_msg);
276
otx2_mbox_nonempty(struct otx2_mbox * mbox,int devid)277 bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid)
278 {
279 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
280 bool ret;
281
282 spin_lock(&mdev->mbox_lock);
283 ret = mdev->num_msgs != 0;
284 spin_unlock(&mdev->mbox_lock);
285
286 return ret;
287 }
288 EXPORT_SYMBOL(otx2_mbox_nonempty);
289
otx2_mbox_id2name(u16 id)290 const char *otx2_mbox_id2name(u16 id)
291 {
292 switch (id) {
293 #define M(_name, _id, _1, _2, _3) case _id: return # _name;
294 MBOX_MESSAGES
295 #undef M
296 default:
297 return "INVALID ID";
298 }
299 }
300 EXPORT_SYMBOL(otx2_mbox_id2name);
301
302 MODULE_AUTHOR("Marvell International Ltd.");
303 MODULE_LICENSE("GPL v2");
304