1 // SPDX-License-Identifier: GPL-2.0-only
3 * Huawei HiNIC PCI Express Linux driver
4 * Copyright(c) 2017 Huawei Technologies Co., Ltd
7 #include <linux/kernel.h>
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/pci.h>
11 #include <linux/device.h>
12 #include <linux/semaphore.h>
13 #include <linux/completion.h>
14 #include <linux/slab.h>
15 #include <asm/barrier.h>
17 #include "hinic_hw_if.h"
18 #include "hinic_hw_eqs.h"
19 #include "hinic_hw_api_cmd.h"
20 #include "hinic_hw_mgmt.h"
21 #include "hinic_hw_dev.h"
23 #define SYNC_MSG_ID_MASK 0x1FF
25 #define SYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->sync_msg_id)
27 #define SYNC_MSG_ID_INC(pf_to_mgmt) (SYNC_MSG_ID(pf_to_mgmt) = \
28 ((SYNC_MSG_ID(pf_to_mgmt) + 1) & \
31 #define MSG_SZ_IS_VALID(in_size) ((in_size) <= MAX_MSG_LEN)
33 #define MGMT_MSG_LEN_MIN 20
34 #define MGMT_MSG_LEN_STEP 16
35 #define MGMT_MSG_RSVD_FOR_DEV 8
37 #define SEGMENT_LEN 48
39 #define MAX_PF_MGMT_BUF_SIZE 2048
41 /* Data should be SEG LEN size aligned */
42 #define MAX_MSG_LEN 2016
44 #define MSG_NOT_RESP 0xFFFF
46 #define MGMT_MSG_TIMEOUT 5000
48 #define SET_FUNC_PORT_MGMT_TIMEOUT 25000
50 #define mgmt_to_pfhwdev(pf_mgmt) \
51 container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
53 enum msg_segment_type
{
58 enum mgmt_direction_type
{
69 * hinic_register_mgmt_msg_cb - register msg handler for a msg from a module
70 * @pf_to_mgmt: PF to MGMT channel
71 * @mod: module in the chip that this handler will handle its messages
72 * @handle: private data for the callback
73 * @callback: the handler that will handle messages
75 void hinic_register_mgmt_msg_cb(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
76 enum hinic_mod_type mod
,
78 void (*callback
)(void *handle
,
80 u16 in_size
, void *buf_out
,
83 struct hinic_mgmt_cb
*mgmt_cb
= &pf_to_mgmt
->mgmt_cb
[mod
];
85 mgmt_cb
->cb
= callback
;
86 mgmt_cb
->handle
= handle
;
87 mgmt_cb
->state
= HINIC_MGMT_CB_ENABLED
;
91 * hinic_unregister_mgmt_msg_cb - unregister msg handler for a msg from a module
92 * @pf_to_mgmt: PF to MGMT channel
93 * @mod: module in the chip that this handler handles its messages
95 void hinic_unregister_mgmt_msg_cb(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
96 enum hinic_mod_type mod
)
98 struct hinic_mgmt_cb
*mgmt_cb
= &pf_to_mgmt
->mgmt_cb
[mod
];
100 mgmt_cb
->state
&= ~HINIC_MGMT_CB_ENABLED
;
102 while (mgmt_cb
->state
& HINIC_MGMT_CB_RUNNING
)
109 * prepare_header - prepare the header of the message
110 * @pf_to_mgmt: PF to MGMT channel
111 * @msg_len: the length of the message
112 * @mod: module in the chip that will get the message
113 * @ack_type: ask for response
114 * @direction: the direction of the message
115 * @cmd: command of the message
116 * @msg_id: message id
118 * Return the prepared header value
120 static u64
prepare_header(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
121 u16 msg_len
, enum hinic_mod_type mod
,
122 enum msg_ack_type ack_type
,
123 enum mgmt_direction_type direction
,
126 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
128 return HINIC_MSG_HEADER_SET(msg_len
, MSG_LEN
) |
129 HINIC_MSG_HEADER_SET(mod
, MODULE
) |
130 HINIC_MSG_HEADER_SET(SEGMENT_LEN
, SEG_LEN
) |
131 HINIC_MSG_HEADER_SET(ack_type
, NO_ACK
) |
132 HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF
) |
133 HINIC_MSG_HEADER_SET(0, SEQID
) |
134 HINIC_MSG_HEADER_SET(LAST_SEGMENT
, LAST
) |
135 HINIC_MSG_HEADER_SET(direction
, DIRECTION
) |
136 HINIC_MSG_HEADER_SET(cmd
, CMD
) |
137 HINIC_MSG_HEADER_SET(HINIC_HWIF_PCI_INTF(hwif
), PCI_INTF
) |
138 HINIC_MSG_HEADER_SET(HINIC_HWIF_PF_IDX(hwif
), PF_IDX
) |
139 HINIC_MSG_HEADER_SET(msg_id
, MSG_ID
);
143 * prepare_mgmt_cmd - prepare the mgmt command
144 * @mgmt_cmd: pointer to the command to prepare
145 * @header: pointer of the header for the message
146 * @msg: the data of the message
147 * @msg_len: the length of the message
149 static void prepare_mgmt_cmd(u8
*mgmt_cmd
, u64
*header
, u8
*msg
, u16 msg_len
)
151 memset(mgmt_cmd
, 0, MGMT_MSG_RSVD_FOR_DEV
);
153 mgmt_cmd
+= MGMT_MSG_RSVD_FOR_DEV
;
154 memcpy(mgmt_cmd
, header
, sizeof(*header
));
156 mgmt_cmd
+= sizeof(*header
);
157 memcpy(mgmt_cmd
, msg
, msg_len
);
161 * mgmt_msg_len - calculate the total message length
162 * @msg_data_len: the length of the message data
164 * Return the total message length
166 static u16
mgmt_msg_len(u16 msg_data_len
)
168 /* RSVD + HEADER_SIZE + DATA_LEN */
169 u16 msg_len
= MGMT_MSG_RSVD_FOR_DEV
+ sizeof(u64
) + msg_data_len
;
171 if (msg_len
> MGMT_MSG_LEN_MIN
)
172 msg_len
= MGMT_MSG_LEN_MIN
+
173 ALIGN((msg_len
- MGMT_MSG_LEN_MIN
),
176 msg_len
= MGMT_MSG_LEN_MIN
;
182 * send_msg_to_mgmt - send message to mgmt by API CMD
183 * @pf_to_mgmt: PF to MGMT channel
184 * @mod: module in the chip that will get the message
185 * @cmd: command of the message
186 * @data: the msg data
187 * @data_len: the msg data length
188 * @ack_type: ask for response
189 * @direction: the direction of the original message
190 * @resp_msg_id: msg id to response for
192 * Return 0 - Success, negative - Failure
194 static int send_msg_to_mgmt(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
195 enum hinic_mod_type mod
, u8 cmd
,
196 u8
*data
, u16 data_len
,
197 enum msg_ack_type ack_type
,
198 enum mgmt_direction_type direction
,
201 struct hinic_api_cmd_chain
*chain
;
205 msg_id
= SYNC_MSG_ID(pf_to_mgmt
);
207 if (direction
== MGMT_RESP
) {
208 header
= prepare_header(pf_to_mgmt
, data_len
, mod
, ack_type
,
209 direction
, cmd
, resp_msg_id
);
211 SYNC_MSG_ID_INC(pf_to_mgmt
);
212 header
= prepare_header(pf_to_mgmt
, data_len
, mod
, ack_type
,
213 direction
, cmd
, msg_id
);
216 prepare_mgmt_cmd(pf_to_mgmt
->sync_msg_buf
, &header
, data
, data_len
);
218 chain
= pf_to_mgmt
->cmd_chain
[HINIC_API_CMD_WRITE_TO_MGMT_CPU
];
219 return hinic_api_cmd_write(chain
, HINIC_NODE_ID_MGMT
,
220 pf_to_mgmt
->sync_msg_buf
,
221 mgmt_msg_len(data_len
));
225 * msg_to_mgmt_sync - send sync message to mgmt
226 * @pf_to_mgmt: PF to MGMT channel
227 * @mod: module in the chip that will get the message
228 * @cmd: command of the message
229 * @buf_in: the msg data
230 * @in_size: the msg data length
232 * @out_size: response length
233 * @direction: the direction of the original message
234 * @resp_msg_id: msg id to response for
236 * Return 0 - Success, negative - Failure
238 static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
239 enum hinic_mod_type mod
, u8 cmd
,
240 u8
*buf_in
, u16 in_size
,
241 u8
*buf_out
, u16
*out_size
,
242 enum mgmt_direction_type direction
,
243 u16 resp_msg_id
, u32 timeout
)
245 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
246 struct pci_dev
*pdev
= hwif
->pdev
;
247 struct hinic_recv_msg
*recv_msg
;
248 struct completion
*recv_done
;
253 /* Lock the sync_msg_buf */
254 down(&pf_to_mgmt
->sync_msg_lock
);
256 recv_msg
= &pf_to_mgmt
->recv_resp_msg_from_mgmt
;
257 recv_done
= &recv_msg
->recv_done
;
259 if (resp_msg_id
== MSG_NOT_RESP
)
260 msg_id
= SYNC_MSG_ID(pf_to_mgmt
);
262 msg_id
= resp_msg_id
;
264 init_completion(recv_done
);
266 err
= send_msg_to_mgmt(pf_to_mgmt
, mod
, cmd
, buf_in
, in_size
,
267 MSG_ACK
, direction
, resp_msg_id
);
269 dev_err(&pdev
->dev
, "Failed to send sync msg to mgmt\n");
270 goto unlock_sync_msg
;
273 timeo
= msecs_to_jiffies(timeout
? timeout
: MGMT_MSG_TIMEOUT
);
275 if (!wait_for_completion_timeout(recv_done
, timeo
)) {
276 dev_err(&pdev
->dev
, "MGMT timeout, MSG id = %d\n", msg_id
);
278 goto unlock_sync_msg
;
281 smp_rmb(); /* verify reading after completion */
283 if (recv_msg
->msg_id
!= msg_id
) {
284 dev_err(&pdev
->dev
, "incorrect MSG for id = %d\n", msg_id
);
286 goto unlock_sync_msg
;
289 if ((buf_out
) && (recv_msg
->msg_len
<= MAX_PF_MGMT_BUF_SIZE
)) {
290 memcpy(buf_out
, recv_msg
->msg
, recv_msg
->msg_len
);
291 *out_size
= recv_msg
->msg_len
;
295 up(&pf_to_mgmt
->sync_msg_lock
);
300 * msg_to_mgmt_async - send message to mgmt without response
301 * @pf_to_mgmt: PF to MGMT channel
302 * @mod: module in the chip that will get the message
303 * @cmd: command of the message
304 * @buf_in: the msg data
305 * @in_size: the msg data length
306 * @direction: the direction of the original message
307 * @resp_msg_id: msg id to response for
309 * Return 0 - Success, negative - Failure
311 static int msg_to_mgmt_async(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
312 enum hinic_mod_type mod
, u8 cmd
,
313 u8
*buf_in
, u16 in_size
,
314 enum mgmt_direction_type direction
,
319 /* Lock the sync_msg_buf */
320 down(&pf_to_mgmt
->sync_msg_lock
);
322 err
= send_msg_to_mgmt(pf_to_mgmt
, mod
, cmd
, buf_in
, in_size
,
323 MSG_NO_ACK
, direction
, resp_msg_id
);
325 up(&pf_to_mgmt
->sync_msg_lock
);
330 * hinic_msg_to_mgmt - send message to mgmt
331 * @pf_to_mgmt: PF to MGMT channel
332 * @mod: module in the chip that will get the message
333 * @cmd: command of the message
334 * @buf_in: the msg data
335 * @in_size: the msg data length
337 * @out_size: returned response length
338 * @sync: sync msg or async msg
340 * Return 0 - Success, negative - Failure
342 int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
343 enum hinic_mod_type mod
, u8 cmd
,
344 void *buf_in
, u16 in_size
, void *buf_out
, u16
*out_size
,
345 enum hinic_mgmt_msg_type sync
)
347 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
348 struct pci_dev
*pdev
= hwif
->pdev
;
351 if (sync
!= HINIC_MGMT_MSG_SYNC
) {
352 dev_err(&pdev
->dev
, "Invalid MGMT msg type\n");
356 if (!MSG_SZ_IS_VALID(in_size
)) {
357 dev_err(&pdev
->dev
, "Invalid MGMT msg buffer size\n");
361 if (cmd
== HINIC_PORT_CMD_SET_FUNC_STATE
)
362 timeout
= SET_FUNC_PORT_MGMT_TIMEOUT
;
364 return msg_to_mgmt_sync(pf_to_mgmt
, mod
, cmd
, buf_in
, in_size
,
365 buf_out
, out_size
, MGMT_DIRECT_SEND
,
366 MSG_NOT_RESP
, timeout
);
370 * mgmt_recv_msg_handler - handler for message from mgmt cpu
371 * @pf_to_mgmt: PF to MGMT channel
372 * @recv_msg: received message details
374 static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
375 struct hinic_recv_msg
*recv_msg
)
377 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
378 struct pci_dev
*pdev
= hwif
->pdev
;
379 u8
*buf_out
= recv_msg
->buf_out
;
380 struct hinic_mgmt_cb
*mgmt_cb
;
381 unsigned long cb_state
;
384 if (recv_msg
->mod
>= HINIC_MOD_MAX
) {
385 dev_err(&pdev
->dev
, "Unknown MGMT MSG module = %d\n",
390 mgmt_cb
= &pf_to_mgmt
->mgmt_cb
[recv_msg
->mod
];
392 cb_state
= cmpxchg(&mgmt_cb
->state
,
393 HINIC_MGMT_CB_ENABLED
,
394 HINIC_MGMT_CB_ENABLED
| HINIC_MGMT_CB_RUNNING
);
396 if ((cb_state
== HINIC_MGMT_CB_ENABLED
) && (mgmt_cb
->cb
))
397 mgmt_cb
->cb(mgmt_cb
->handle
, recv_msg
->cmd
,
398 recv_msg
->msg
, recv_msg
->msg_len
,
401 dev_err(&pdev
->dev
, "No MGMT msg handler, mod = %d\n",
404 mgmt_cb
->state
&= ~HINIC_MGMT_CB_RUNNING
;
406 if (!recv_msg
->async_mgmt_to_pf
)
407 /* MGMT sent sync msg, send the response */
408 msg_to_mgmt_async(pf_to_mgmt
, recv_msg
->mod
, recv_msg
->cmd
,
409 buf_out
, out_size
, MGMT_RESP
,
414 * mgmt_resp_msg_handler - handler for a response message from mgmt cpu
415 * @pf_to_mgmt: PF to MGMT channel
416 * @recv_msg: received message details
418 static void mgmt_resp_msg_handler(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
419 struct hinic_recv_msg
*recv_msg
)
421 wmb(); /* verify writing all, before reading */
423 complete(&recv_msg
->recv_done
);
427 * recv_mgmt_msg_handler - handler for a message from mgmt cpu
428 * @pf_to_mgmt: PF to MGMT channel
429 * @header: the header of the message
430 * @recv_msg: received message details
432 static void recv_mgmt_msg_handler(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
433 u64
*header
, struct hinic_recv_msg
*recv_msg
)
435 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
436 struct pci_dev
*pdev
= hwif
->pdev
;
440 seq_id
= HINIC_MSG_HEADER_GET(*header
, SEQID
);
441 seg_len
= HINIC_MSG_HEADER_GET(*header
, SEG_LEN
);
443 if (seq_id
>= (MAX_MSG_LEN
/ SEGMENT_LEN
)) {
444 dev_err(&pdev
->dev
, "recv big mgmt msg\n");
448 msg_body
= (u8
*)header
+ sizeof(*header
);
449 memcpy(recv_msg
->msg
+ seq_id
* SEGMENT_LEN
, msg_body
, seg_len
);
451 if (!HINIC_MSG_HEADER_GET(*header
, LAST
))
454 recv_msg
->cmd
= HINIC_MSG_HEADER_GET(*header
, CMD
);
455 recv_msg
->mod
= HINIC_MSG_HEADER_GET(*header
, MODULE
);
456 recv_msg
->async_mgmt_to_pf
= HINIC_MSG_HEADER_GET(*header
,
458 recv_msg
->msg_len
= HINIC_MSG_HEADER_GET(*header
, MSG_LEN
);
459 recv_msg
->msg_id
= HINIC_MSG_HEADER_GET(*header
, MSG_ID
);
461 if (HINIC_MSG_HEADER_GET(*header
, DIRECTION
) == MGMT_RESP
)
462 mgmt_resp_msg_handler(pf_to_mgmt
, recv_msg
);
464 mgmt_recv_msg_handler(pf_to_mgmt
, recv_msg
);
468 * mgmt_msg_aeqe_handler - handler for a mgmt message event
469 * @handle: PF to MGMT channel
470 * @data: the header of the message
473 static void mgmt_msg_aeqe_handler(void *handle
, void *data
, u8 size
)
475 struct hinic_pf_to_mgmt
*pf_to_mgmt
= handle
;
476 struct hinic_recv_msg
*recv_msg
;
477 u64
*header
= (u64
*)data
;
479 recv_msg
= HINIC_MSG_HEADER_GET(*header
, DIRECTION
) ==
481 &pf_to_mgmt
->recv_msg_from_mgmt
:
482 &pf_to_mgmt
->recv_resp_msg_from_mgmt
;
484 recv_mgmt_msg_handler(pf_to_mgmt
, header
, recv_msg
);
488 * alloc_recv_msg - allocate receive message memory
489 * @pf_to_mgmt: PF to MGMT channel
490 * @recv_msg: pointer that will hold the allocated data
492 * Return 0 - Success, negative - Failure
494 static int alloc_recv_msg(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
495 struct hinic_recv_msg
*recv_msg
)
497 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
498 struct pci_dev
*pdev
= hwif
->pdev
;
500 recv_msg
->msg
= devm_kzalloc(&pdev
->dev
, MAX_PF_MGMT_BUF_SIZE
,
505 recv_msg
->buf_out
= devm_kzalloc(&pdev
->dev
, MAX_PF_MGMT_BUF_SIZE
,
507 if (!recv_msg
->buf_out
)
514 * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
515 * @pf_to_mgmt: PF to MGMT channel
517 * Return 0 - Success, negative - Failure
519 static int alloc_msg_buf(struct hinic_pf_to_mgmt
*pf_to_mgmt
)
521 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
522 struct pci_dev
*pdev
= hwif
->pdev
;
525 err
= alloc_recv_msg(pf_to_mgmt
,
526 &pf_to_mgmt
->recv_msg_from_mgmt
);
528 dev_err(&pdev
->dev
, "Failed to allocate recv msg\n");
532 err
= alloc_recv_msg(pf_to_mgmt
,
533 &pf_to_mgmt
->recv_resp_msg_from_mgmt
);
535 dev_err(&pdev
->dev
, "Failed to allocate resp recv msg\n");
539 pf_to_mgmt
->sync_msg_buf
= devm_kzalloc(&pdev
->dev
,
540 MAX_PF_MGMT_BUF_SIZE
,
542 if (!pf_to_mgmt
->sync_msg_buf
)
549 * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
550 * @pf_to_mgmt: PF to MGMT channel
551 * @hwif: HW interface the PF to MGMT will use for accessing HW
553 * Return 0 - Success, negative - Failure
555 int hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
556 struct hinic_hwif
*hwif
)
558 struct hinic_pfhwdev
*pfhwdev
= mgmt_to_pfhwdev(pf_to_mgmt
);
559 struct hinic_hwdev
*hwdev
= &pfhwdev
->hwdev
;
560 struct pci_dev
*pdev
= hwif
->pdev
;
563 pf_to_mgmt
->hwif
= hwif
;
565 sema_init(&pf_to_mgmt
->sync_msg_lock
, 1);
566 pf_to_mgmt
->sync_msg_id
= 0;
568 err
= alloc_msg_buf(pf_to_mgmt
);
570 dev_err(&pdev
->dev
, "Failed to allocate msg buffers\n");
574 err
= hinic_api_cmd_init(pf_to_mgmt
->cmd_chain
, hwif
);
576 dev_err(&pdev
->dev
, "Failed to initialize cmd chains\n");
580 hinic_aeq_register_hw_cb(&hwdev
->aeqs
, HINIC_MSG_FROM_MGMT_CPU
,
582 mgmt_msg_aeqe_handler
);
587 * hinic_pf_to_mgmt_free - free PF to MGMT channel
588 * @pf_to_mgmt: PF to MGMT channel
590 void hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt
*pf_to_mgmt
)
592 struct hinic_pfhwdev
*pfhwdev
= mgmt_to_pfhwdev(pf_to_mgmt
);
593 struct hinic_hwdev
*hwdev
= &pfhwdev
->hwdev
;
595 hinic_aeq_unregister_hw_cb(&hwdev
->aeqs
, HINIC_MSG_FROM_MGMT_CPU
);
596 hinic_api_cmd_free(pf_to_mgmt
->cmd_chain
);