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 if (HINIC_IS_VF(hwif))
365 return hinic_mbox_to_pf(pf_to_mgmt->hwdev, mod, cmd, buf_in,
366 in_size, buf_out, out_size, 0);
368 return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
369 buf_out, out_size, MGMT_DIRECT_SEND,
370 MSG_NOT_RESP, timeout);
373 static void recv_mgmt_msg_work_handler(struct work_struct *work)
375 struct hinic_mgmt_msg_handle_work *mgmt_work =
376 container_of(work, struct hinic_mgmt_msg_handle_work, work);
377 struct hinic_pf_to_mgmt *pf_to_mgmt = mgmt_work->pf_to_mgmt;
378 struct pci_dev *pdev = pf_to_mgmt->hwif->pdev;
379 u8 *buf_out = pf_to_mgmt->mgmt_ack_buf;
380 struct hinic_mgmt_cb *mgmt_cb;
381 unsigned long cb_state;
384 memset(buf_out, 0, MAX_PF_MGMT_BUF_SIZE);
386 if (mgmt_work->mod >= HINIC_MOD_MAX) {
387 dev_err(&pdev->dev, "Unknown MGMT MSG module = %d\n",
389 kfree(mgmt_work->msg);
394 mgmt_cb = &pf_to_mgmt->mgmt_cb[mgmt_work->mod];
396 cb_state = cmpxchg(&mgmt_cb->state,
397 HINIC_MGMT_CB_ENABLED,
398 HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING);
400 if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb))
401 mgmt_cb->cb(mgmt_cb->handle, mgmt_work->cmd,
402 mgmt_work->msg, mgmt_work->msg_len,
405 dev_err(&pdev->dev, "No MGMT msg handler, mod: %d, cmd: %d\n",
406 mgmt_work->mod, mgmt_work->cmd);
408 mgmt_cb->state &= ~HINIC_MGMT_CB_RUNNING;
410 if (!mgmt_work->async_mgmt_to_pf)
411 /* MGMT sent sync msg, send the response */
412 msg_to_mgmt_async(pf_to_mgmt, mgmt_work->mod, mgmt_work->cmd,
413 buf_out, out_size, MGMT_RESP,
416 kfree(mgmt_work->msg);
421 * mgmt_recv_msg_handler - handler for message from mgmt cpu
422 * @pf_to_mgmt: PF to MGMT channel
423 * @recv_msg: received message details
425 static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
426 struct hinic_recv_msg *recv_msg)
428 struct hinic_mgmt_msg_handle_work *mgmt_work = NULL;
429 struct pci_dev *pdev = pf_to_mgmt->hwif->pdev;
431 mgmt_work = kzalloc(sizeof(*mgmt_work), GFP_KERNEL);
433 dev_err(&pdev->dev, "Allocate mgmt work memory failed\n");
437 if (recv_msg->msg_len) {
438 mgmt_work->msg = kzalloc(recv_msg->msg_len, GFP_KERNEL);
439 if (!mgmt_work->msg) {
440 dev_err(&pdev->dev, "Allocate mgmt msg memory failed\n");
446 mgmt_work->pf_to_mgmt = pf_to_mgmt;
447 mgmt_work->msg_len = recv_msg->msg_len;
448 memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len);
449 mgmt_work->msg_id = recv_msg->msg_id;
450 mgmt_work->mod = recv_msg->mod;
451 mgmt_work->cmd = recv_msg->cmd;
452 mgmt_work->async_mgmt_to_pf = recv_msg->async_mgmt_to_pf;
454 INIT_WORK(&mgmt_work->work, recv_mgmt_msg_work_handler);
455 queue_work(pf_to_mgmt->workq, &mgmt_work->work);
459 * mgmt_resp_msg_handler - handler for a response message from mgmt cpu
460 * @pf_to_mgmt: PF to MGMT channel
461 * @recv_msg: received message details
463 static void mgmt_resp_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
464 struct hinic_recv_msg *recv_msg)
466 wmb(); /* verify writing all, before reading */
468 complete(&recv_msg->recv_done);
472 * recv_mgmt_msg_handler - handler for a message from mgmt cpu
473 * @pf_to_mgmt: PF to MGMT channel
474 * @header: the header of the message
475 * @recv_msg: received message details
477 static void recv_mgmt_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
478 u64 *header, struct hinic_recv_msg *recv_msg)
480 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
481 struct pci_dev *pdev = hwif->pdev;
485 seq_id = HINIC_MSG_HEADER_GET(*header, SEQID);
486 seg_len = HINIC_MSG_HEADER_GET(*header, SEG_LEN);
488 if (seq_id >= (MAX_MSG_LEN / SEGMENT_LEN)) {
489 dev_err(&pdev->dev, "recv big mgmt msg\n");
493 msg_body = (u8 *)header + sizeof(*header);
494 memcpy(recv_msg->msg + seq_id * SEGMENT_LEN, msg_body, seg_len);
496 if (!HINIC_MSG_HEADER_GET(*header, LAST))
499 recv_msg->cmd = HINIC_MSG_HEADER_GET(*header, CMD);
500 recv_msg->mod = HINIC_MSG_HEADER_GET(*header, MODULE);
501 recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(*header,
503 recv_msg->msg_len = HINIC_MSG_HEADER_GET(*header, MSG_LEN);
504 recv_msg->msg_id = HINIC_MSG_HEADER_GET(*header, MSG_ID);
506 if (HINIC_MSG_HEADER_GET(*header, DIRECTION) == MGMT_RESP)
507 mgmt_resp_msg_handler(pf_to_mgmt, recv_msg);
509 mgmt_recv_msg_handler(pf_to_mgmt, recv_msg);
513 * mgmt_msg_aeqe_handler - handler for a mgmt message event
514 * @handle: PF to MGMT channel
515 * @data: the header of the message
518 static void mgmt_msg_aeqe_handler(void *handle, void *data, u8 size)
520 struct hinic_pf_to_mgmt *pf_to_mgmt = handle;
521 struct hinic_recv_msg *recv_msg;
522 u64 *header = (u64 *)data;
524 recv_msg = HINIC_MSG_HEADER_GET(*header, DIRECTION) ==
526 &pf_to_mgmt->recv_msg_from_mgmt :
527 &pf_to_mgmt->recv_resp_msg_from_mgmt;
529 recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg);
533 * alloc_recv_msg - allocate receive message memory
534 * @pf_to_mgmt: PF to MGMT channel
535 * @recv_msg: pointer that will hold the allocated data
537 * Return 0 - Success, negative - Failure
539 static int alloc_recv_msg(struct hinic_pf_to_mgmt *pf_to_mgmt,
540 struct hinic_recv_msg *recv_msg)
542 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
543 struct pci_dev *pdev = hwif->pdev;
545 recv_msg->msg = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
550 recv_msg->buf_out = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
552 if (!recv_msg->buf_out)
559 * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
560 * @pf_to_mgmt: PF to MGMT channel
562 * Return 0 - Success, negative - Failure
564 static int alloc_msg_buf(struct hinic_pf_to_mgmt *pf_to_mgmt)
566 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
567 struct pci_dev *pdev = hwif->pdev;
570 err = alloc_recv_msg(pf_to_mgmt,
571 &pf_to_mgmt->recv_msg_from_mgmt);
573 dev_err(&pdev->dev, "Failed to allocate recv msg\n");
577 err = alloc_recv_msg(pf_to_mgmt,
578 &pf_to_mgmt->recv_resp_msg_from_mgmt);
580 dev_err(&pdev->dev, "Failed to allocate resp recv msg\n");
584 pf_to_mgmt->sync_msg_buf = devm_kzalloc(&pdev->dev,
585 MAX_PF_MGMT_BUF_SIZE,
587 if (!pf_to_mgmt->sync_msg_buf)
590 pf_to_mgmt->mgmt_ack_buf = devm_kzalloc(&pdev->dev,
591 MAX_PF_MGMT_BUF_SIZE,
593 if (!pf_to_mgmt->mgmt_ack_buf)
600 * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
601 * @pf_to_mgmt: PF to MGMT channel
602 * @hwif: HW interface the PF to MGMT will use for accessing HW
604 * Return 0 - Success, negative - Failure
606 int hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt *pf_to_mgmt,
607 struct hinic_hwif *hwif)
609 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
610 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
611 struct pci_dev *pdev = hwif->pdev;
614 pf_to_mgmt->hwif = hwif;
615 pf_to_mgmt->hwdev = hwdev;
617 if (HINIC_IS_VF(hwif))
620 sema_init(&pf_to_mgmt->sync_msg_lock, 1);
621 pf_to_mgmt->workq = create_singlethread_workqueue("hinic_mgmt");
622 if (!pf_to_mgmt->workq) {
623 dev_err(&pdev->dev, "Failed to initialize MGMT workqueue\n");
626 pf_to_mgmt->sync_msg_id = 0;
628 err = alloc_msg_buf(pf_to_mgmt);
630 dev_err(&pdev->dev, "Failed to allocate msg buffers\n");
634 err = hinic_api_cmd_init(pf_to_mgmt->cmd_chain, hwif);
636 dev_err(&pdev->dev, "Failed to initialize cmd chains\n");
640 hinic_aeq_register_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU,
642 mgmt_msg_aeqe_handler);
647 * hinic_pf_to_mgmt_free - free PF to MGMT channel
648 * @pf_to_mgmt: PF to MGMT channel
650 void hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt *pf_to_mgmt)
652 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
653 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
655 if (HINIC_IS_VF(hwdev->hwif))
658 hinic_aeq_unregister_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU);
659 hinic_api_cmd_free(pf_to_mgmt->cmd_chain);
660 destroy_workqueue(pf_to_mgmt->workq);