1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
|
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
#include <linux/pci.h>
#include "wx_type.h"
#include "wx_mbx.h"
/**
* wx_obtain_mbx_lock_pf - obtain mailbox lock
* @wx: pointer to the HW structure
* @vf: the VF index
*
* Return: return 0 on success and -EBUSY on failure
**/
static int wx_obtain_mbx_lock_pf(struct wx *wx, u16 vf)
{
int count = 5;
u32 mailbox;
while (count--) {
/* Take ownership of the buffer */
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_PFU);
/* reserve mailbox for vf use */
mailbox = rd32(wx, WX_PXMAILBOX(vf));
if (mailbox & WX_PXMAILBOX_PFU)
return 0;
else if (count)
udelay(10);
}
wx_err(wx, "Failed to obtain mailbox lock for PF%d", vf);
return -EBUSY;
}
static int wx_check_for_bit_pf(struct wx *wx, u32 mask, int index)
{
u32 mbvficr = rd32(wx, WX_MBVFICR(index));
if (!(mbvficr & mask))
return -EBUSY;
wr32(wx, WX_MBVFICR(index), mask);
return 0;
}
/**
* wx_check_for_ack_pf - checks to see if the VF has acked
* @wx: pointer to the HW structure
* @vf: the VF index
*
* Return: return 0 if the VF has set the status bit or else -EBUSY
**/
int wx_check_for_ack_pf(struct wx *wx, u16 vf)
{
u32 index = vf / 16, vf_bit = vf % 16;
return wx_check_for_bit_pf(wx,
FIELD_PREP(WX_MBVFICR_VFACK_MASK,
BIT(vf_bit)),
index);
}
/**
* wx_check_for_msg_pf - checks to see if the VF has sent mail
* @wx: pointer to the HW structure
* @vf: the VF index
*
* Return: return 0 if the VF has got req bit or else -EBUSY
**/
int wx_check_for_msg_pf(struct wx *wx, u16 vf)
{
u32 index = vf / 16, vf_bit = vf % 16;
return wx_check_for_bit_pf(wx,
FIELD_PREP(WX_MBVFICR_VFREQ_MASK,
BIT(vf_bit)),
index);
}
/**
* wx_write_mbx_pf - Places a message in the mailbox
* @wx: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
* @vf: the VF index
*
* Return: return 0 on success and -EINVAL/-EBUSY on failure
**/
int wx_write_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
{
struct wx_mbx_info *mbx = &wx->mbx;
int ret, i;
/* mbx->size is up to 15 */
if (size > mbx->size) {
wx_err(wx, "Invalid mailbox message size %d", size);
return -EINVAL;
}
/* lock the mailbox to prevent pf/vf race condition */
ret = wx_obtain_mbx_lock_pf(wx, vf);
if (ret)
return ret;
/* flush msg and acks as we are overwriting the message buffer */
wx_check_for_msg_pf(wx, vf);
wx_check_for_ack_pf(wx, vf);
/* copy the caller specified message to the mailbox memory buffer */
for (i = 0; i < size; i++)
wr32a(wx, WX_PXMBMEM(vf), i, msg[i]);
/* Interrupt VF to tell it a message has been sent and release buffer */
/* set mirrored mailbox flags */
wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_STS);
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_STS);
return 0;
}
/**
* wx_read_mbx_pf - Read a message from the mailbox
* @wx: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
* @vf: the VF index
*
* Return: return 0 on success and -EBUSY on failure
**/
int wx_read_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
{
struct wx_mbx_info *mbx = &wx->mbx;
int ret;
u16 i;
/* limit read to size of mailbox and mbx->size is up to 15 */
if (size > mbx->size)
size = mbx->size;
/* lock the mailbox to prevent pf/vf race condition */
ret = wx_obtain_mbx_lock_pf(wx, vf);
if (ret)
return ret;
for (i = 0; i < size; i++)
msg[i] = rd32a(wx, WX_PXMBMEM(vf), i);
/* Acknowledge the message and release buffer */
/* set mirrored mailbox flags */
wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_ACK);
wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_ACK);
return 0;
}
/**
* wx_check_for_rst_pf - checks to see if the VF has reset
* @wx: pointer to the HW structure
* @vf: the VF index
*
* Return: return 0 on success and -EBUSY on failure
**/
int wx_check_for_rst_pf(struct wx *wx, u16 vf)
{
u32 reg_offset = WX_VF_REG_OFFSET(vf);
u32 vf_shift = WX_VF_IND_SHIFT(vf);
u32 vflre = 0;
vflre = rd32(wx, WX_VFLRE(reg_offset));
if (!(vflre & BIT(vf_shift)))
return -EBUSY;
wr32(wx, WX_VFLREC(reg_offset), BIT(vf_shift));
return 0;
}
static u32 wx_read_v2p_mailbox(struct wx *wx)
{
u32 mailbox = rd32(wx, WX_VXMAILBOX);
mailbox |= wx->mbx.mailbox;
wx->mbx.mailbox |= mailbox & WX_VXMAILBOX_R2C_BITS;
return mailbox;
}
static u32 wx_mailbox_get_lock_vf(struct wx *wx)
{
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_VFU);
return wx_read_v2p_mailbox(wx);
}
/**
* wx_obtain_mbx_lock_vf - obtain mailbox lock
* @wx: pointer to the HW structure
*
* Return: return 0 on success and -EBUSY on failure
**/
static int wx_obtain_mbx_lock_vf(struct wx *wx)
{
int count = 5, ret;
u32 mailbox;
ret = readx_poll_timeout_atomic(wx_mailbox_get_lock_vf, wx, mailbox,
(mailbox & WX_VXMAILBOX_VFU),
1, count);
if (ret)
wx_err(wx, "Failed to obtain mailbox lock for VF.\n");
return ret;
}
static int wx_check_for_bit_vf(struct wx *wx, u32 mask)
{
u32 mailbox = wx_read_v2p_mailbox(wx);
wx->mbx.mailbox &= ~mask;
return (mailbox & mask ? 0 : -EBUSY);
}
/**
* wx_check_for_ack_vf - checks to see if the PF has ACK'd
* @wx: pointer to the HW structure
*
* Return: return 0 if the PF has set the status bit or else -EBUSY
**/
static int wx_check_for_ack_vf(struct wx *wx)
{
/* read clear the pf ack bit */
return wx_check_for_bit_vf(wx, WX_VXMAILBOX_PFACK);
}
/**
* wx_check_for_msg_vf - checks to see if the PF has sent mail
* @wx: pointer to the HW structure
*
* Return: return 0 if the PF has got req bit or else -EBUSY
**/
int wx_check_for_msg_vf(struct wx *wx)
{
/* read clear the pf sts bit */
return wx_check_for_bit_vf(wx, WX_VXMAILBOX_PFSTS);
}
/**
* wx_check_for_rst_vf - checks to see if the PF has reset
* @wx: pointer to the HW structure
*
* Return: return 0 if the PF has set the reset done and -EBUSY on failure
**/
int wx_check_for_rst_vf(struct wx *wx)
{
/* read clear the pf reset done bit */
return wx_check_for_bit_vf(wx,
WX_VXMAILBOX_RSTD |
WX_VXMAILBOX_RSTI);
}
/**
* wx_poll_for_msg - Wait for message notification
* @wx: pointer to the HW structure
*
* Return: return 0 if the VF has successfully received a message notification
**/
static int wx_poll_for_msg(struct wx *wx)
{
struct wx_mbx_info *mbx = &wx->mbx;
u32 val;
return readx_poll_timeout_atomic(wx_check_for_msg_vf, wx, val,
(val == 0), mbx->udelay, mbx->timeout);
}
/**
* wx_poll_for_ack - Wait for message acknowledgment
* @wx: pointer to the HW structure
*
* Return: return 0 if the VF has successfully received a message ack
**/
static int wx_poll_for_ack(struct wx *wx)
{
struct wx_mbx_info *mbx = &wx->mbx;
u32 val;
return readx_poll_timeout_atomic(wx_check_for_ack_vf, wx, val,
(val == 0), mbx->udelay, mbx->timeout);
}
/**
* wx_read_posted_mbx - Wait for message notification and receive message
* @wx: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
*
* Return: returns 0 if it successfully received a message notification and
* copied it into the receive buffer.
**/
int wx_read_posted_mbx(struct wx *wx, u32 *msg, u16 size)
{
int ret;
ret = wx_poll_for_msg(wx);
/* if ack received read message, otherwise we timed out */
if (ret)
return ret;
return wx_read_mbx_vf(wx, msg, size);
}
/**
* wx_write_posted_mbx - Write a message to the mailbox, wait for ack
* @wx: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
*
* Return: returns 0 if it successfully copied message into the buffer and
* received an ack to that message within delay * timeout period
**/
int wx_write_posted_mbx(struct wx *wx, u32 *msg, u16 size)
{
int ret;
/* send msg */
ret = wx_write_mbx_vf(wx, msg, size);
/* if msg sent wait until we receive an ack */
if (ret)
return ret;
return wx_poll_for_ack(wx);
}
/**
* wx_write_mbx_vf - Write a message to the mailbox
* @wx: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
*
* Return: returns 0 if it successfully copied message into the buffer
**/
int wx_write_mbx_vf(struct wx *wx, u32 *msg, u16 size)
{
struct wx_mbx_info *mbx = &wx->mbx;
int ret, i;
/* mbx->size is up to 15 */
if (size > mbx->size) {
wx_err(wx, "Invalid mailbox message size %d", size);
return -EINVAL;
}
/* lock the mailbox to prevent pf/vf race condition */
ret = wx_obtain_mbx_lock_vf(wx);
if (ret)
return ret;
/* flush msg and acks as we are overwriting the message buffer */
wx_check_for_msg_vf(wx);
wx_check_for_ack_vf(wx);
/* copy the caller specified message to the mailbox memory buffer */
for (i = 0; i < size; i++)
wr32a(wx, WX_VXMBMEM, i, msg[i]);
/* Drop VFU and interrupt the PF to tell it a message has been sent */
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_REQ);
return 0;
}
/**
* wx_read_mbx_vf - Reads a message from the inbox intended for vf
* @wx: pointer to the HW structure
* @msg: The message buffer
* @size: Length of buffer
*
* Return: returns 0 if it successfully copied message into the buffer
**/
int wx_read_mbx_vf(struct wx *wx, u32 *msg, u16 size)
{
struct wx_mbx_info *mbx = &wx->mbx;
int ret, i;
/* limit read to size of mailbox and mbx->size is up to 15 */
if (size > mbx->size)
size = mbx->size;
/* lock the mailbox to prevent pf/vf race condition */
ret = wx_obtain_mbx_lock_vf(wx);
if (ret)
return ret;
/* copy the message from the mailbox memory buffer */
for (i = 0; i < size; i++)
msg[i] = rd32a(wx, WX_VXMBMEM, i);
/* Acknowledge receipt and release mailbox, then we're done */
wr32(wx, WX_VXMAILBOX, WX_VXMAILBOX_ACK);
return 0;
}
int wx_init_mbx_params_vf(struct wx *wx)
{
wx->vfinfo = kzalloc(sizeof(struct vf_data_storage),
GFP_KERNEL);
if (!wx->vfinfo)
return -ENOMEM;
/* Initialize mailbox parameters */
wx->mbx.size = WX_VXMAILBOX_SIZE;
wx->mbx.mailbox = WX_VXMAILBOX;
wx->mbx.udelay = 10;
wx->mbx.timeout = 1000;
return 0;
}
EXPORT_SYMBOL(wx_init_mbx_params_vf);
|