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
|
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2022 - 2025 Mucse Corporation. */
#include <linux/errno.h>
#include <linux/bitfield.h>
#include <linux/iopoll.h>
#include "rnpgbe_mbx.h"
/**
* mbx_data_rd32 - Reads reg with base mbx->fwpf_shm_base
* @mbx: pointer to the MBX structure
* @reg: register offset
*
* Return: register value
**/
static u32 mbx_data_rd32(struct mucse_mbx_info *mbx, u32 reg)
{
struct mucse_hw *hw = container_of(mbx, struct mucse_hw, mbx);
return readl(hw->hw_addr + mbx->fwpf_shm_base + reg);
}
/**
* mbx_data_wr32 - Writes value to reg with base mbx->fwpf_shm_base
* @mbx: pointer to the MBX structure
* @reg: register offset
* @value: value to be written
*
**/
static void mbx_data_wr32(struct mucse_mbx_info *mbx, u32 reg, u32 value)
{
struct mucse_hw *hw = container_of(mbx, struct mucse_hw, mbx);
writel(value, hw->hw_addr + mbx->fwpf_shm_base + reg);
}
/**
* mbx_ctrl_rd32 - Reads reg with base mbx->fwpf_ctrl_base
* @mbx: pointer to the MBX structure
* @reg: register offset
*
* Return: register value
**/
static u32 mbx_ctrl_rd32(struct mucse_mbx_info *mbx, u32 reg)
{
struct mucse_hw *hw = container_of(mbx, struct mucse_hw, mbx);
return readl(hw->hw_addr + mbx->fwpf_ctrl_base + reg);
}
/**
* mbx_ctrl_wr32 - Writes value to reg with base mbx->fwpf_ctrl_base
* @mbx: pointer to the MBX structure
* @reg: register offset
* @value: value to be written
*
**/
static void mbx_ctrl_wr32(struct mucse_mbx_info *mbx, u32 reg, u32 value)
{
struct mucse_hw *hw = container_of(mbx, struct mucse_hw, mbx);
writel(value, hw->hw_addr + mbx->fwpf_ctrl_base + reg);
}
/**
* mucse_mbx_get_lock_pf - Write ctrl and read back lock status
* @hw: pointer to the HW structure
*
* Return: register value after write
**/
static u32 mucse_mbx_get_lock_pf(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u32 reg = MUCSE_MBX_PF2FW_CTRL(mbx);
mbx_ctrl_wr32(mbx, reg, MUCSE_MBX_PFU);
return mbx_ctrl_rd32(mbx, reg);
}
/**
* mucse_obtain_mbx_lock_pf - Obtain mailbox lock
* @hw: pointer to the HW structure
*
* Pair with mucse_release_mbx_lock_pf()
* This function maybe used in an irq handler.
*
* Return: 0 on success, negative errno on failure
**/
static int mucse_obtain_mbx_lock_pf(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u32 val;
return read_poll_timeout_atomic(mucse_mbx_get_lock_pf,
val, val & MUCSE_MBX_PFU,
mbx->delay_us,
mbx->timeout_us,
false, hw);
}
/**
* mucse_release_mbx_lock_pf - Release mailbox lock
* @hw: pointer to the HW structure
* @req: send a request or not
*
* Pair with mucse_obtain_mbx_lock_pf():
* - Releases the mailbox lock by clearing MUCSE_MBX_PFU bit
* - Simultaneously sends the request by setting MUCSE_MBX_REQ bit
* if req is true
* (Both bits are in the same mailbox control register,
* so operations are combined)
**/
static void mucse_release_mbx_lock_pf(struct mucse_hw *hw, bool req)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u32 reg = MUCSE_MBX_PF2FW_CTRL(mbx);
mbx_ctrl_wr32(mbx, reg, req ? MUCSE_MBX_REQ : 0);
}
/**
* mucse_mbx_get_fwreq - Read fw req from reg
* @mbx: pointer to the mbx structure
*
* Return: the fwreq value
**/
static u16 mucse_mbx_get_fwreq(struct mucse_mbx_info *mbx)
{
u32 val = mbx_data_rd32(mbx, MUCSE_MBX_FW2PF_CNT);
return FIELD_GET(GENMASK_U32(15, 0), val);
}
/**
* mucse_mbx_inc_pf_ack - Increase ack
* @hw: pointer to the HW structure
*
* mucse_mbx_inc_pf_ack reads pf_ack from hw, then writes
* new value back after increase
**/
static void mucse_mbx_inc_pf_ack(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u16 ack;
u32 val;
val = mbx_data_rd32(mbx, MUCSE_MBX_PF2FW_CNT);
ack = FIELD_GET(GENMASK_U32(31, 16), val);
ack++;
val &= ~GENMASK_U32(31, 16);
val |= FIELD_PREP(GENMASK_U32(31, 16), ack);
mbx_data_wr32(mbx, MUCSE_MBX_PF2FW_CNT, val);
}
/**
* mucse_read_mbx_pf - Read a message from the mailbox
* @hw: pointer to the HW structure
* @msg: the message buffer
* @size: length of buffer
*
* mucse_read_mbx_pf copies a message from the mbx buffer to the caller's
* memory buffer. The presumption is that the caller knows that there was
* a message due to a fw request so no polling for message is needed.
*
* Return: 0 on success, negative errno on failure
**/
static int mucse_read_mbx_pf(struct mucse_hw *hw, u32 *msg, u16 size)
{
const int size_in_words = size / sizeof(u32);
struct mucse_mbx_info *mbx = &hw->mbx;
int err;
err = mucse_obtain_mbx_lock_pf(hw);
if (err)
return err;
for (int i = 0; i < size_in_words; i++)
msg[i] = mbx_data_rd32(mbx, MUCSE_MBX_FWPF_SHM + 4 * i);
/* Hw needs write data_reg at last */
mbx_data_wr32(mbx, MUCSE_MBX_FWPF_SHM, 0);
/* flush reqs as we have read this request data */
hw->mbx.fw_req = mucse_mbx_get_fwreq(mbx);
mucse_mbx_inc_pf_ack(hw);
mucse_release_mbx_lock_pf(hw, false);
return 0;
}
/**
* mucse_check_for_msg_pf - Check to see if the fw has sent mail
* @hw: pointer to the HW structure
*
* Return: 0 if the fw has set the Status bit or else -EIO
**/
static int mucse_check_for_msg_pf(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u16 fw_req;
fw_req = mucse_mbx_get_fwreq(mbx);
/* chip's register is reset to 0 when rc send reset
* mbx command. Return -EIO if in this state, others
* fw == hw->mbx.fw_req means no new msg.
**/
if (fw_req == 0 || fw_req == hw->mbx.fw_req)
return -EIO;
return 0;
}
/**
* mucse_poll_for_msg - Wait for message notification
* @hw: pointer to the HW structure
*
* Return: 0 on success, negative errno on failure
**/
static int mucse_poll_for_msg(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
int val;
return read_poll_timeout(mucse_check_for_msg_pf,
val, !val, mbx->delay_us,
mbx->timeout_us,
false, hw);
}
/**
* mucse_poll_and_read_mbx - Wait for message notification and receive message
* @hw: pointer to the HW structure
* @msg: the message buffer
* @size: length of buffer
*
* Return: 0 if it successfully received a message notification and
* copied it into the receive buffer, negative errno on failure
**/
int mucse_poll_and_read_mbx(struct mucse_hw *hw, u32 *msg, u16 size)
{
int err;
err = mucse_poll_for_msg(hw);
if (err)
return err;
return mucse_read_mbx_pf(hw, msg, size);
}
/**
* mucse_mbx_get_fwack - Read fw ack from reg
* @mbx: pointer to the MBX structure
*
* Return: the fwack value
**/
static u16 mucse_mbx_get_fwack(struct mucse_mbx_info *mbx)
{
u32 val = mbx_data_rd32(mbx, MUCSE_MBX_FW2PF_CNT);
return FIELD_GET(GENMASK_U32(31, 16), val);
}
/**
* mucse_mbx_inc_pf_req - Increase req
* @hw: pointer to the HW structure
*
* mucse_mbx_inc_pf_req reads pf_req from hw, then writes
* new value back after increase
**/
static void mucse_mbx_inc_pf_req(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u16 req;
u32 val;
val = mbx_data_rd32(mbx, MUCSE_MBX_PF2FW_CNT);
req = FIELD_GET(GENMASK_U32(15, 0), val);
req++;
val &= ~GENMASK_U32(15, 0);
val |= FIELD_PREP(GENMASK_U32(15, 0), req);
mbx_data_wr32(mbx, MUCSE_MBX_PF2FW_CNT, val);
}
/**
* mucse_write_mbx_pf - Place a message in the mailbox
* @hw: pointer to the HW structure
* @msg: the message buffer
* @size: length of buffer
*
* Return: 0 if it successfully copied message into the buffer,
* negative errno on failure
**/
static int mucse_write_mbx_pf(struct mucse_hw *hw, u32 *msg, u16 size)
{
const int size_in_words = size / sizeof(u32);
struct mucse_mbx_info *mbx = &hw->mbx;
int err;
err = mucse_obtain_mbx_lock_pf(hw);
if (err)
return err;
for (int i = 0; i < size_in_words; i++)
mbx_data_wr32(mbx, MUCSE_MBX_FWPF_SHM + i * 4, msg[i]);
/* flush acks as we are overwriting the message buffer */
hw->mbx.fw_ack = mucse_mbx_get_fwack(mbx);
mucse_mbx_inc_pf_req(hw);
mucse_release_mbx_lock_pf(hw, true);
return 0;
}
/**
* mucse_check_for_ack_pf - Check to see if the fw has ACKed
* @hw: pointer to the HW structure
*
* Return: 0 if the fw has set the Status bit or else -EIO
**/
static int mucse_check_for_ack_pf(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u16 fw_ack;
fw_ack = mucse_mbx_get_fwack(mbx);
/* chip's register is reset to 0 when rc send reset
* mbx command. Return -EIO if in this state, others
* fw_ack == hw->mbx.fw_ack means no new ack.
**/
if (fw_ack == 0 || fw_ack == hw->mbx.fw_ack)
return -EIO;
return 0;
}
/**
* mucse_poll_for_ack - Wait for message acknowledgment
* @hw: pointer to the HW structure
*
* Return: 0 if it successfully received a message acknowledgment,
* else negative errno
**/
static int mucse_poll_for_ack(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
int val;
return read_poll_timeout(mucse_check_for_ack_pf,
val, !val, mbx->delay_us,
mbx->timeout_us,
false, hw);
}
/**
* mucse_write_and_wait_ack_mbx - Write a message to the mailbox, wait for ack
* @hw: pointer to the HW structure
* @msg: the message buffer
* @size: length of buffer
*
* Return: 0 if it successfully copied message into the buffer and
* received an ack to that message within delay * timeout_cnt period
**/
int mucse_write_and_wait_ack_mbx(struct mucse_hw *hw, u32 *msg, u16 size)
{
int err;
err = mucse_write_mbx_pf(hw, msg, size);
if (err)
return err;
return mucse_poll_for_ack(hw);
}
/**
* mucse_mbx_reset - Reset mbx info, sync info from regs
* @hw: pointer to the HW structure
*
* mucse_mbx_reset resets all mbx variables to default.
**/
static void mucse_mbx_reset(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
u32 val;
val = mbx_data_rd32(mbx, MUCSE_MBX_FW2PF_CNT);
hw->mbx.fw_req = FIELD_GET(GENMASK_U32(15, 0), val);
hw->mbx.fw_ack = FIELD_GET(GENMASK_U32(31, 16), val);
mbx_ctrl_wr32(mbx, MUCSE_MBX_PF2FW_CTRL(mbx), 0);
mbx_ctrl_wr32(mbx, MUCSE_MBX_FWPF_MASK(mbx), GENMASK_U32(31, 16));
}
/**
* mucse_init_mbx_params_pf - Set initial values for pf mailbox
* @hw: pointer to the HW structure
*
* Initializes the hw->mbx struct to correct values for pf mailbox
*/
void mucse_init_mbx_params_pf(struct mucse_hw *hw)
{
struct mucse_mbx_info *mbx = &hw->mbx;
mbx->delay_us = 100;
mbx->timeout_us = 4 * USEC_PER_SEC;
mutex_init(&mbx->lock);
mucse_mbx_reset(hw);
}
|