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 1000
57 #define mgmt_to_pfhwdev(pf_mgmt) \
58 container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
60 enum msg_segment_type
{
65 enum mgmt_direction_type
{
76 * hinic_register_mgmt_msg_cb - register msg handler for a msg from a module
77 * @pf_to_mgmt: PF to MGMT channel
78 * @mod: module in the chip that this handler will handle its messages
79 * @handle: private data for the callback
80 * @callback: the handler that will handle messages
82 void hinic_register_mgmt_msg_cb(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
83 enum hinic_mod_type mod
,
85 void (*callback
)(void *handle
,
87 u16 in_size
, void *buf_out
,
90 struct hinic_mgmt_cb
*mgmt_cb
= &pf_to_mgmt
->mgmt_cb
[mod
];
92 mgmt_cb
->cb
= callback
;
93 mgmt_cb
->handle
= handle
;
94 mgmt_cb
->state
= HINIC_MGMT_CB_ENABLED
;
98 * hinic_unregister_mgmt_msg_cb - unregister msg handler for a msg from a module
99 * @pf_to_mgmt: PF to MGMT channel
100 * @mod: module in the chip that this handler handles its messages
102 void hinic_unregister_mgmt_msg_cb(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
103 enum hinic_mod_type mod
)
105 struct hinic_mgmt_cb
*mgmt_cb
= &pf_to_mgmt
->mgmt_cb
[mod
];
107 mgmt_cb
->state
&= ~HINIC_MGMT_CB_ENABLED
;
109 while (mgmt_cb
->state
& HINIC_MGMT_CB_RUNNING
)
116 * prepare_header - prepare the header of the message
117 * @pf_to_mgmt: PF to MGMT channel
118 * @msg_len: the length of the message
119 * @mod: module in the chip that will get the message
120 * @ack_type: ask for response
121 * @direction: the direction of the message
122 * @cmd: command of the message
123 * @msg_id: message id
125 * Return the prepared header value
127 static u64
prepare_header(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
128 u16 msg_len
, enum hinic_mod_type mod
,
129 enum msg_ack_type ack_type
,
130 enum mgmt_direction_type direction
,
133 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
135 return HINIC_MSG_HEADER_SET(msg_len
, MSG_LEN
) |
136 HINIC_MSG_HEADER_SET(mod
, MODULE
) |
137 HINIC_MSG_HEADER_SET(SEGMENT_LEN
, SEG_LEN
) |
138 HINIC_MSG_HEADER_SET(ack_type
, NO_ACK
) |
139 HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF
) |
140 HINIC_MSG_HEADER_SET(0, SEQID
) |
141 HINIC_MSG_HEADER_SET(LAST_SEGMENT
, LAST
) |
142 HINIC_MSG_HEADER_SET(direction
, DIRECTION
) |
143 HINIC_MSG_HEADER_SET(cmd
, CMD
) |
144 HINIC_MSG_HEADER_SET(HINIC_HWIF_PCI_INTF(hwif
), PCI_INTF
) |
145 HINIC_MSG_HEADER_SET(HINIC_HWIF_PF_IDX(hwif
), PF_IDX
) |
146 HINIC_MSG_HEADER_SET(msg_id
, MSG_ID
);
150 * prepare_mgmt_cmd - prepare the mgmt command
151 * @mgmt_cmd: pointer to the command to prepare
152 * @header: pointer of the header for the message
153 * @msg: the data of the message
154 * @msg_len: the length of the message
156 static void prepare_mgmt_cmd(u8
*mgmt_cmd
, u64
*header
, u8
*msg
, u16 msg_len
)
158 memset(mgmt_cmd
, 0, MGMT_MSG_RSVD_FOR_DEV
);
160 mgmt_cmd
+= MGMT_MSG_RSVD_FOR_DEV
;
161 memcpy(mgmt_cmd
, header
, sizeof(*header
));
163 mgmt_cmd
+= sizeof(*header
);
164 memcpy(mgmt_cmd
, msg
, msg_len
);
168 * mgmt_msg_len - calculate the total message length
169 * @msg_data_len: the length of the message data
171 * Return the total message length
173 static u16
mgmt_msg_len(u16 msg_data_len
)
175 /* RSVD + HEADER_SIZE + DATA_LEN */
176 u16 msg_len
= MGMT_MSG_RSVD_FOR_DEV
+ sizeof(u64
) + msg_data_len
;
178 if (msg_len
> MGMT_MSG_LEN_MIN
)
179 msg_len
= MGMT_MSG_LEN_MIN
+
180 ALIGN((msg_len
- MGMT_MSG_LEN_MIN
),
183 msg_len
= MGMT_MSG_LEN_MIN
;
189 * send_msg_to_mgmt - send message to mgmt by API CMD
190 * @pf_to_mgmt: PF to MGMT channel
191 * @mod: module in the chip that will get the message
192 * @cmd: command of the message
193 * @data: the msg data
194 * @data_len: the msg data length
195 * @ack_type: ask for response
196 * @direction: the direction of the original message
197 * @resp_msg_id: msg id to response for
199 * Return 0 - Success, negative - Failure
201 static int send_msg_to_mgmt(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
202 enum hinic_mod_type mod
, u8 cmd
,
203 u8
*data
, u16 data_len
,
204 enum msg_ack_type ack_type
,
205 enum mgmt_direction_type direction
,
208 struct hinic_api_cmd_chain
*chain
;
212 msg_id
= SYNC_MSG_ID(pf_to_mgmt
);
214 if (direction
== MGMT_RESP
) {
215 header
= prepare_header(pf_to_mgmt
, data_len
, mod
, ack_type
,
216 direction
, cmd
, resp_msg_id
);
218 SYNC_MSG_ID_INC(pf_to_mgmt
);
219 header
= prepare_header(pf_to_mgmt
, data_len
, mod
, ack_type
,
220 direction
, cmd
, msg_id
);
223 prepare_mgmt_cmd(pf_to_mgmt
->sync_msg_buf
, &header
, data
, data_len
);
225 chain
= pf_to_mgmt
->cmd_chain
[HINIC_API_CMD_WRITE_TO_MGMT_CPU
];
226 return hinic_api_cmd_write(chain
, HINIC_NODE_ID_MGMT
,
227 pf_to_mgmt
->sync_msg_buf
,
228 mgmt_msg_len(data_len
));
232 * msg_to_mgmt_sync - send sync message to mgmt
233 * @pf_to_mgmt: PF to MGMT channel
234 * @mod: module in the chip that will get the message
235 * @cmd: command of the message
236 * @buf_in: the msg data
237 * @in_size: the msg data length
239 * @out_size: response length
240 * @direction: the direction of the original message
241 * @resp_msg_id: msg id to response for
243 * Return 0 - Success, negative - Failure
245 static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
246 enum hinic_mod_type mod
, u8 cmd
,
247 u8
*buf_in
, u16 in_size
,
248 u8
*buf_out
, u16
*out_size
,
249 enum mgmt_direction_type direction
,
252 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
253 struct pci_dev
*pdev
= hwif
->pdev
;
254 struct hinic_recv_msg
*recv_msg
;
255 struct completion
*recv_done
;
259 /* Lock the sync_msg_buf */
260 down(&pf_to_mgmt
->sync_msg_lock
);
262 recv_msg
= &pf_to_mgmt
->recv_resp_msg_from_mgmt
;
263 recv_done
= &recv_msg
->recv_done
;
265 if (resp_msg_id
== MSG_NOT_RESP
)
266 msg_id
= SYNC_MSG_ID(pf_to_mgmt
);
268 msg_id
= resp_msg_id
;
270 init_completion(recv_done
);
272 err
= send_msg_to_mgmt(pf_to_mgmt
, mod
, cmd
, buf_in
, in_size
,
273 MSG_ACK
, direction
, resp_msg_id
);
275 dev_err(&pdev
->dev
, "Failed to send sync msg to mgmt\n");
276 goto unlock_sync_msg
;
279 if (!wait_for_completion_timeout(recv_done
, MGMT_MSG_TIMEOUT
)) {
280 dev_err(&pdev
->dev
, "MGMT timeout, MSG id = %d\n", msg_id
);
282 goto unlock_sync_msg
;
285 smp_rmb(); /* verify reading after completion */
287 if (recv_msg
->msg_id
!= msg_id
) {
288 dev_err(&pdev
->dev
, "incorrect MSG for id = %d\n", msg_id
);
290 goto unlock_sync_msg
;
293 if ((buf_out
) && (recv_msg
->msg_len
<= MAX_PF_MGMT_BUF_SIZE
)) {
294 memcpy(buf_out
, recv_msg
->msg
, recv_msg
->msg_len
);
295 *out_size
= recv_msg
->msg_len
;
299 up(&pf_to_mgmt
->sync_msg_lock
);
304 * msg_to_mgmt_async - send message to mgmt without response
305 * @pf_to_mgmt: PF to MGMT channel
306 * @mod: module in the chip that will get the message
307 * @cmd: command of the message
308 * @buf_in: the msg data
309 * @in_size: the msg data length
310 * @direction: the direction of the original message
311 * @resp_msg_id: msg id to response for
313 * Return 0 - Success, negative - Failure
315 static int msg_to_mgmt_async(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
316 enum hinic_mod_type mod
, u8 cmd
,
317 u8
*buf_in
, u16 in_size
,
318 enum mgmt_direction_type direction
,
323 /* Lock the sync_msg_buf */
324 down(&pf_to_mgmt
->sync_msg_lock
);
326 err
= send_msg_to_mgmt(pf_to_mgmt
, mod
, cmd
, buf_in
, in_size
,
327 MSG_NO_ACK
, direction
, resp_msg_id
);
329 up(&pf_to_mgmt
->sync_msg_lock
);
334 * hinic_msg_to_mgmt - send message to mgmt
335 * @pf_to_mgmt: PF to MGMT channel
336 * @mod: module in the chip that will get the message
337 * @cmd: command of the message
338 * @buf_in: the msg data
339 * @in_size: the msg data length
341 * @out_size: returned response length
342 * @sync: sync msg or async msg
344 * Return 0 - Success, negative - Failure
346 int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt
*pf_to_mgmt
,
347 enum hinic_mod_type mod
, u8 cmd
,
348 void *buf_in
, u16 in_size
, void *buf_out
, u16
*out_size
,
349 enum hinic_mgmt_msg_type sync
)
351 struct hinic_hwif
*hwif
= pf_to_mgmt
->hwif
;
352 struct pci_dev
*pdev
= hwif
->pdev
;
354 if (sync
!= HINIC_MGMT_MSG_SYNC
) {
355 dev_err(&pdev
->dev
, "Invalid MGMT msg type\n");
359 if (!MSG_SZ_IS_VALID(in_size
)) {
360 dev_err(&pdev
->dev
, "Invalid MGMT msg buffer size\n");
364 return msg_to_mgmt_sync(pf_to_mgmt
, mod
, cmd
, buf_in
, in_size
,
365 buf_out
, out_size
, MGMT_DIRECT_SEND
,
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
);