2 * Huawei HiNIC PCI Express Linux driver
3 * Copyright(c) 2017 Huawei Technologies Co., Ltd
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include <linux/kernel.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <linux/pci.h>
20 #include <linux/device.h>
21 #include <linux/semaphore.h>
22 #include <linux/completion.h>
23 #include <linux/slab.h>
24 #include <asm/barrier.h>
26 #include "hinic_hw_if.h"
27 #include "hinic_hw_eqs.h"
28 #include "hinic_hw_api_cmd.h"
29 #include "hinic_hw_mgmt.h"
30 #include "hinic_hw_dev.h"
32 #define SYNC_MSG_ID_MASK 0x1FF
34 #define SYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->sync_msg_id)
36 #define SYNC_MSG_ID_INC(pf_to_mgmt) (SYNC_MSG_ID(pf_to_mgmt) = \
37 ((SYNC_MSG_ID(pf_to_mgmt) + 1) & \
40 #define MSG_SZ_IS_VALID(in_size) ((in_size) <= MAX_MSG_LEN)
42 #define MGMT_MSG_LEN_MIN 20
43 #define MGMT_MSG_LEN_STEP 16
44 #define MGMT_MSG_RSVD_FOR_DEV 8
46 #define SEGMENT_LEN 48
48 #define MAX_PF_MGMT_BUF_SIZE 2048
50 /* Data should be SEG LEN size aligned */
51 #define MAX_MSG_LEN 2016
53 #define MSG_NOT_RESP 0xFFFF
55 #define MGMT_MSG_TIMEOUT 5000
57 #define SET_FUNC_PORT_MGMT_TIMEOUT 25000
59 #define mgmt_to_pfhwdev(pf_mgmt) \
60 container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
62 enum msg_segment_type {
67 enum mgmt_direction_type {
78 * hinic_register_mgmt_msg_cb - register msg handler for a msg from a module
79 * @pf_to_mgmt: PF to MGMT channel
80 * @mod: module in the chip that this handler will handle its messages
81 * @handle: private data for the callback
82 * @callback: the handler that will handle messages
84 void hinic_register_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt,
85 enum hinic_mod_type mod,
87 void (*callback)(void *handle,
89 u16 in_size, void *buf_out,
92 struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod];
94 mgmt_cb->cb = callback;
95 mgmt_cb->handle = handle;
96 mgmt_cb->state = HINIC_MGMT_CB_ENABLED;
100 * hinic_unregister_mgmt_msg_cb - unregister msg handler for a msg from a module
101 * @pf_to_mgmt: PF to MGMT channel
102 * @mod: module in the chip that this handler handles its messages
104 void hinic_unregister_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt,
105 enum hinic_mod_type mod)
107 struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod];
109 mgmt_cb->state &= ~HINIC_MGMT_CB_ENABLED;
111 while (mgmt_cb->state & HINIC_MGMT_CB_RUNNING)
118 * prepare_header - prepare the header of the message
119 * @pf_to_mgmt: PF to MGMT channel
120 * @msg_len: the length of the message
121 * @mod: module in the chip that will get the message
122 * @ack_type: ask for response
123 * @direction: the direction of the message
124 * @cmd: command of the message
125 * @msg_id: message id
127 * Return the prepared header value
129 static u64 prepare_header(struct hinic_pf_to_mgmt *pf_to_mgmt,
130 u16 msg_len, enum hinic_mod_type mod,
131 enum msg_ack_type ack_type,
132 enum mgmt_direction_type direction,
135 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
137 return HINIC_MSG_HEADER_SET(msg_len, MSG_LEN) |
138 HINIC_MSG_HEADER_SET(mod, MODULE) |
139 HINIC_MSG_HEADER_SET(SEGMENT_LEN, SEG_LEN) |
140 HINIC_MSG_HEADER_SET(ack_type, NO_ACK) |
141 HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF) |
142 HINIC_MSG_HEADER_SET(0, SEQID) |
143 HINIC_MSG_HEADER_SET(LAST_SEGMENT, LAST) |
144 HINIC_MSG_HEADER_SET(direction, DIRECTION) |
145 HINIC_MSG_HEADER_SET(cmd, CMD) |
146 HINIC_MSG_HEADER_SET(HINIC_HWIF_PCI_INTF(hwif), PCI_INTF) |
147 HINIC_MSG_HEADER_SET(HINIC_HWIF_PF_IDX(hwif), PF_IDX) |
148 HINIC_MSG_HEADER_SET(msg_id, MSG_ID);
152 * prepare_mgmt_cmd - prepare the mgmt command
153 * @mgmt_cmd: pointer to the command to prepare
154 * @header: pointer of the header for the message
155 * @msg: the data of the message
156 * @msg_len: the length of the message
158 static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, u8 *msg, u16 msg_len)
160 memset(mgmt_cmd, 0, MGMT_MSG_RSVD_FOR_DEV);
162 mgmt_cmd += MGMT_MSG_RSVD_FOR_DEV;
163 memcpy(mgmt_cmd, header, sizeof(*header));
165 mgmt_cmd += sizeof(*header);
166 memcpy(mgmt_cmd, msg, msg_len);
170 * mgmt_msg_len - calculate the total message length
171 * @msg_data_len: the length of the message data
173 * Return the total message length
175 static u16 mgmt_msg_len(u16 msg_data_len)
177 /* RSVD + HEADER_SIZE + DATA_LEN */
178 u16 msg_len = MGMT_MSG_RSVD_FOR_DEV + sizeof(u64) + msg_data_len;
180 if (msg_len > MGMT_MSG_LEN_MIN)
181 msg_len = MGMT_MSG_LEN_MIN +
182 ALIGN((msg_len - MGMT_MSG_LEN_MIN),
185 msg_len = MGMT_MSG_LEN_MIN;
191 * send_msg_to_mgmt - send message to mgmt by API CMD
192 * @pf_to_mgmt: PF to MGMT channel
193 * @mod: module in the chip that will get the message
194 * @cmd: command of the message
195 * @data: the msg data
196 * @data_len: the msg data length
197 * @ack_type: ask for response
198 * @direction: the direction of the original message
199 * @resp_msg_id: msg id to response for
201 * Return 0 - Success, negative - Failure
203 static int send_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
204 enum hinic_mod_type mod, u8 cmd,
205 u8 *data, u16 data_len,
206 enum msg_ack_type ack_type,
207 enum mgmt_direction_type direction,
210 struct hinic_api_cmd_chain *chain;
214 msg_id = SYNC_MSG_ID(pf_to_mgmt);
216 if (direction == MGMT_RESP) {
217 header = prepare_header(pf_to_mgmt, data_len, mod, ack_type,
218 direction, cmd, resp_msg_id);
220 SYNC_MSG_ID_INC(pf_to_mgmt);
221 header = prepare_header(pf_to_mgmt, data_len, mod, ack_type,
222 direction, cmd, msg_id);
225 prepare_mgmt_cmd(pf_to_mgmt->sync_msg_buf, &header, data, data_len);
227 chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_WRITE_TO_MGMT_CPU];
228 return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT,
229 pf_to_mgmt->sync_msg_buf,
230 mgmt_msg_len(data_len));
234 * msg_to_mgmt_sync - send sync message to mgmt
235 * @pf_to_mgmt: PF to MGMT channel
236 * @mod: module in the chip that will get the message
237 * @cmd: command of the message
238 * @buf_in: the msg data
239 * @in_size: the msg data length
241 * @out_size: response length
242 * @direction: the direction of the original message
243 * @resp_msg_id: msg id to response for
245 * Return 0 - Success, negative - Failure
247 static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
248 enum hinic_mod_type mod, u8 cmd,
249 u8 *buf_in, u16 in_size,
250 u8 *buf_out, u16 *out_size,
251 enum mgmt_direction_type direction,
252 u16 resp_msg_id, u32 timeout)
254 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
255 struct pci_dev *pdev = hwif->pdev;
256 struct hinic_recv_msg *recv_msg;
257 struct completion *recv_done;
262 /* Lock the sync_msg_buf */
263 down(&pf_to_mgmt->sync_msg_lock);
265 recv_msg = &pf_to_mgmt->recv_resp_msg_from_mgmt;
266 recv_done = &recv_msg->recv_done;
268 if (resp_msg_id == MSG_NOT_RESP)
269 msg_id = SYNC_MSG_ID(pf_to_mgmt);
271 msg_id = resp_msg_id;
273 init_completion(recv_done);
275 err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
276 MSG_ACK, direction, resp_msg_id);
278 dev_err(&pdev->dev, "Failed to send sync msg to mgmt\n");
279 goto unlock_sync_msg;
282 timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
284 if (!wait_for_completion_timeout(recv_done, timeo)) {
285 dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
287 goto unlock_sync_msg;
290 smp_rmb(); /* verify reading after completion */
292 if (recv_msg->msg_id != msg_id) {
293 dev_err(&pdev->dev, "incorrect MSG for id = %d\n", msg_id);
295 goto unlock_sync_msg;
298 if ((buf_out) && (recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE)) {
299 memcpy(buf_out, recv_msg->msg, recv_msg->msg_len);
300 *out_size = recv_msg->msg_len;
304 up(&pf_to_mgmt->sync_msg_lock);
309 * msg_to_mgmt_async - send message to mgmt without response
310 * @pf_to_mgmt: PF to MGMT channel
311 * @mod: module in the chip that will get the message
312 * @cmd: command of the message
313 * @buf_in: the msg data
314 * @in_size: the msg data length
315 * @direction: the direction of the original message
316 * @resp_msg_id: msg id to response for
318 * Return 0 - Success, negative - Failure
320 static int msg_to_mgmt_async(struct hinic_pf_to_mgmt *pf_to_mgmt,
321 enum hinic_mod_type mod, u8 cmd,
322 u8 *buf_in, u16 in_size,
323 enum mgmt_direction_type direction,
328 /* Lock the sync_msg_buf */
329 down(&pf_to_mgmt->sync_msg_lock);
331 err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
332 MSG_NO_ACK, direction, resp_msg_id);
334 up(&pf_to_mgmt->sync_msg_lock);
339 * hinic_msg_to_mgmt - send message to mgmt
340 * @pf_to_mgmt: PF to MGMT channel
341 * @mod: module in the chip that will get the message
342 * @cmd: command of the message
343 * @buf_in: the msg data
344 * @in_size: the msg data length
346 * @out_size: returned response length
347 * @sync: sync msg or async msg
349 * Return 0 - Success, negative - Failure
351 int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
352 enum hinic_mod_type mod, u8 cmd,
353 void *buf_in, u16 in_size, void *buf_out, u16 *out_size,
354 enum hinic_mgmt_msg_type sync)
356 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
357 struct pci_dev *pdev = hwif->pdev;
360 if (sync != HINIC_MGMT_MSG_SYNC) {
361 dev_err(&pdev->dev, "Invalid MGMT msg type\n");
365 if (!MSG_SZ_IS_VALID(in_size)) {
366 dev_err(&pdev->dev, "Invalid MGMT msg buffer size\n");
370 if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
371 timeout = SET_FUNC_PORT_MGMT_TIMEOUT;
373 return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
374 buf_out, out_size, MGMT_DIRECT_SEND,
375 MSG_NOT_RESP, timeout);
379 * mgmt_recv_msg_handler - handler for message from mgmt cpu
380 * @pf_to_mgmt: PF to MGMT channel
381 * @recv_msg: received message details
383 static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
384 struct hinic_recv_msg *recv_msg)
386 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
387 struct pci_dev *pdev = hwif->pdev;
388 u8 *buf_out = recv_msg->buf_out;
389 struct hinic_mgmt_cb *mgmt_cb;
390 unsigned long cb_state;
393 if (recv_msg->mod >= HINIC_MOD_MAX) {
394 dev_err(&pdev->dev, "Unknown MGMT MSG module = %d\n",
399 mgmt_cb = &pf_to_mgmt->mgmt_cb[recv_msg->mod];
401 cb_state = cmpxchg(&mgmt_cb->state,
402 HINIC_MGMT_CB_ENABLED,
403 HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING);
405 if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb))
406 mgmt_cb->cb(mgmt_cb->handle, recv_msg->cmd,
407 recv_msg->msg, recv_msg->msg_len,
410 dev_err(&pdev->dev, "No MGMT msg handler, mod = %d\n",
413 mgmt_cb->state &= ~HINIC_MGMT_CB_RUNNING;
415 if (!recv_msg->async_mgmt_to_pf)
416 /* MGMT sent sync msg, send the response */
417 msg_to_mgmt_async(pf_to_mgmt, recv_msg->mod, recv_msg->cmd,
418 buf_out, out_size, MGMT_RESP,
423 * mgmt_resp_msg_handler - handler for a response message from mgmt cpu
424 * @pf_to_mgmt: PF to MGMT channel
425 * @recv_msg: received message details
427 static void mgmt_resp_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
428 struct hinic_recv_msg *recv_msg)
430 wmb(); /* verify writing all, before reading */
432 complete(&recv_msg->recv_done);
436 * recv_mgmt_msg_handler - handler for a message from mgmt cpu
437 * @pf_to_mgmt: PF to MGMT channel
438 * @header: the header of the message
439 * @recv_msg: received message details
441 static void recv_mgmt_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
442 u64 *header, struct hinic_recv_msg *recv_msg)
444 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
445 struct pci_dev *pdev = hwif->pdev;
449 seq_id = HINIC_MSG_HEADER_GET(*header, SEQID);
450 seg_len = HINIC_MSG_HEADER_GET(*header, SEG_LEN);
452 if (seq_id >= (MAX_MSG_LEN / SEGMENT_LEN)) {
453 dev_err(&pdev->dev, "recv big mgmt msg\n");
457 msg_body = (u8 *)header + sizeof(*header);
458 memcpy(recv_msg->msg + seq_id * SEGMENT_LEN, msg_body, seg_len);
460 if (!HINIC_MSG_HEADER_GET(*header, LAST))
463 recv_msg->cmd = HINIC_MSG_HEADER_GET(*header, CMD);
464 recv_msg->mod = HINIC_MSG_HEADER_GET(*header, MODULE);
465 recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(*header,
467 recv_msg->msg_len = HINIC_MSG_HEADER_GET(*header, MSG_LEN);
468 recv_msg->msg_id = HINIC_MSG_HEADER_GET(*header, MSG_ID);
470 if (HINIC_MSG_HEADER_GET(*header, DIRECTION) == MGMT_RESP)
471 mgmt_resp_msg_handler(pf_to_mgmt, recv_msg);
473 mgmt_recv_msg_handler(pf_to_mgmt, recv_msg);
477 * mgmt_msg_aeqe_handler - handler for a mgmt message event
478 * @handle: PF to MGMT channel
479 * @data: the header of the message
482 static void mgmt_msg_aeqe_handler(void *handle, void *data, u8 size)
484 struct hinic_pf_to_mgmt *pf_to_mgmt = handle;
485 struct hinic_recv_msg *recv_msg;
486 u64 *header = (u64 *)data;
488 recv_msg = HINIC_MSG_HEADER_GET(*header, DIRECTION) ==
490 &pf_to_mgmt->recv_msg_from_mgmt :
491 &pf_to_mgmt->recv_resp_msg_from_mgmt;
493 recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg);
497 * alloc_recv_msg - allocate receive message memory
498 * @pf_to_mgmt: PF to MGMT channel
499 * @recv_msg: pointer that will hold the allocated data
501 * Return 0 - Success, negative - Failure
503 static int alloc_recv_msg(struct hinic_pf_to_mgmt *pf_to_mgmt,
504 struct hinic_recv_msg *recv_msg)
506 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
507 struct pci_dev *pdev = hwif->pdev;
509 recv_msg->msg = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
514 recv_msg->buf_out = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
516 if (!recv_msg->buf_out)
523 * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
524 * @pf_to_mgmt: PF to MGMT channel
526 * Return 0 - Success, negative - Failure
528 static int alloc_msg_buf(struct hinic_pf_to_mgmt *pf_to_mgmt)
530 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
531 struct pci_dev *pdev = hwif->pdev;
534 err = alloc_recv_msg(pf_to_mgmt,
535 &pf_to_mgmt->recv_msg_from_mgmt);
537 dev_err(&pdev->dev, "Failed to allocate recv msg\n");
541 err = alloc_recv_msg(pf_to_mgmt,
542 &pf_to_mgmt->recv_resp_msg_from_mgmt);
544 dev_err(&pdev->dev, "Failed to allocate resp recv msg\n");
548 pf_to_mgmt->sync_msg_buf = devm_kzalloc(&pdev->dev,
549 MAX_PF_MGMT_BUF_SIZE,
551 if (!pf_to_mgmt->sync_msg_buf)
558 * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
559 * @pf_to_mgmt: PF to MGMT channel
560 * @hwif: HW interface the PF to MGMT will use for accessing HW
562 * Return 0 - Success, negative - Failure
564 int hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt *pf_to_mgmt,
565 struct hinic_hwif *hwif)
567 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
568 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
569 struct pci_dev *pdev = hwif->pdev;
572 pf_to_mgmt->hwif = hwif;
574 sema_init(&pf_to_mgmt->sync_msg_lock, 1);
575 pf_to_mgmt->sync_msg_id = 0;
577 err = alloc_msg_buf(pf_to_mgmt);
579 dev_err(&pdev->dev, "Failed to allocate msg buffers\n");
583 err = hinic_api_cmd_init(pf_to_mgmt->cmd_chain, hwif);
585 dev_err(&pdev->dev, "Failed to initialize cmd chains\n");
589 hinic_aeq_register_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU,
591 mgmt_msg_aeqe_handler);
596 * hinic_pf_to_mgmt_free - free PF to MGMT channel
597 * @pf_to_mgmt: PF to MGMT channel
599 void hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt *pf_to_mgmt)
601 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
602 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
604 hinic_aeq_unregister_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU);
605 hinic_api_cmd_free(pf_to_mgmt->cmd_chain);