1
2
3
4
5
6
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 <net/devlink.h>
16#include <asm/barrier.h>
17
18#include "hinic_devlink.h"
19#include "hinic_hw_if.h"
20#include "hinic_hw_eqs.h"
21#include "hinic_hw_api_cmd.h"
22#include "hinic_hw_mgmt.h"
23#include "hinic_hw_dev.h"
24
25#define SYNC_MSG_ID_MASK 0x1FF
26
27#define SYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->sync_msg_id)
28
29#define SYNC_MSG_ID_INC(pf_to_mgmt) (SYNC_MSG_ID(pf_to_mgmt) = \
30 ((SYNC_MSG_ID(pf_to_mgmt) + 1) & \
31 SYNC_MSG_ID_MASK))
32
33#define MSG_SZ_IS_VALID(in_size) ((in_size) <= MAX_MSG_LEN)
34
35#define MGMT_MSG_LEN_MIN 20
36#define MGMT_MSG_LEN_STEP 16
37#define MGMT_MSG_RSVD_FOR_DEV 8
38
39#define SEGMENT_LEN 48
40
41#define MAX_PF_MGMT_BUF_SIZE 2048
42
43
44#define MAX_MSG_LEN 2016
45
46#define MSG_NOT_RESP 0xFFFF
47
48#define MGMT_MSG_TIMEOUT 5000
49
50#define SET_FUNC_PORT_MBOX_TIMEOUT 30000
51
52#define SET_FUNC_PORT_MGMT_TIMEOUT 25000
53
54#define UPDATE_FW_MGMT_TIMEOUT 20000
55
56#define mgmt_to_pfhwdev(pf_mgmt) \
57 container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
58
59enum msg_segment_type {
60 NOT_LAST_SEGMENT = 0,
61 LAST_SEGMENT = 1,
62};
63
64enum mgmt_direction_type {
65 MGMT_DIRECT_SEND = 0,
66 MGMT_RESP = 1,
67};
68
69enum msg_ack_type {
70 MSG_ACK = 0,
71 MSG_NO_ACK = 1,
72};
73
74
75
76
77
78
79
80
81void hinic_register_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt,
82 enum hinic_mod_type mod,
83 void *handle,
84 void (*callback)(void *handle,
85 u8 cmd, void *buf_in,
86 u16 in_size, void *buf_out,
87 u16 *out_size))
88{
89 struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod];
90
91 mgmt_cb->cb = callback;
92 mgmt_cb->handle = handle;
93 mgmt_cb->state = HINIC_MGMT_CB_ENABLED;
94}
95
96
97
98
99
100
101void hinic_unregister_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt,
102 enum hinic_mod_type mod)
103{
104 struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod];
105
106 mgmt_cb->state &= ~HINIC_MGMT_CB_ENABLED;
107
108 while (mgmt_cb->state & HINIC_MGMT_CB_RUNNING)
109 schedule();
110
111 mgmt_cb->cb = NULL;
112}
113
114
115
116
117
118
119
120
121
122
123
124
125
126static u64 prepare_header(struct hinic_pf_to_mgmt *pf_to_mgmt,
127 u16 msg_len, enum hinic_mod_type mod,
128 enum msg_ack_type ack_type,
129 enum mgmt_direction_type direction,
130 u16 cmd, u16 msg_id)
131{
132 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
133
134 return HINIC_MSG_HEADER_SET(msg_len, MSG_LEN) |
135 HINIC_MSG_HEADER_SET(mod, MODULE) |
136 HINIC_MSG_HEADER_SET(SEGMENT_LEN, SEG_LEN) |
137 HINIC_MSG_HEADER_SET(ack_type, NO_ACK) |
138 HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF) |
139 HINIC_MSG_HEADER_SET(0, SEQID) |
140 HINIC_MSG_HEADER_SET(LAST_SEGMENT, LAST) |
141 HINIC_MSG_HEADER_SET(direction, DIRECTION) |
142 HINIC_MSG_HEADER_SET(cmd, CMD) |
143 HINIC_MSG_HEADER_SET(HINIC_HWIF_PCI_INTF(hwif), PCI_INTF) |
144 HINIC_MSG_HEADER_SET(HINIC_HWIF_PF_IDX(hwif), PF_IDX) |
145 HINIC_MSG_HEADER_SET(msg_id, MSG_ID);
146}
147
148
149
150
151
152
153
154
155static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, u8 *msg, u16 msg_len)
156{
157 memset(mgmt_cmd, 0, MGMT_MSG_RSVD_FOR_DEV);
158
159 mgmt_cmd += MGMT_MSG_RSVD_FOR_DEV;
160 memcpy(mgmt_cmd, header, sizeof(*header));
161
162 mgmt_cmd += sizeof(*header);
163 memcpy(mgmt_cmd, msg, msg_len);
164}
165
166
167
168
169
170
171
172static u16 mgmt_msg_len(u16 msg_data_len)
173{
174
175 u16 msg_len = MGMT_MSG_RSVD_FOR_DEV + sizeof(u64) + msg_data_len;
176
177 if (msg_len > MGMT_MSG_LEN_MIN)
178 msg_len = MGMT_MSG_LEN_MIN +
179 ALIGN((msg_len - MGMT_MSG_LEN_MIN),
180 MGMT_MSG_LEN_STEP);
181 else
182 msg_len = MGMT_MSG_LEN_MIN;
183
184 return msg_len;
185}
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200static int send_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
201 enum hinic_mod_type mod, u8 cmd,
202 u8 *data, u16 data_len,
203 enum msg_ack_type ack_type,
204 enum mgmt_direction_type direction,
205 u16 resp_msg_id)
206{
207 struct hinic_api_cmd_chain *chain;
208 u64 header;
209 u16 msg_id;
210
211 msg_id = SYNC_MSG_ID(pf_to_mgmt);
212
213 if (direction == MGMT_RESP) {
214 header = prepare_header(pf_to_mgmt, data_len, mod, ack_type,
215 direction, cmd, resp_msg_id);
216 } else {
217 SYNC_MSG_ID_INC(pf_to_mgmt);
218 header = prepare_header(pf_to_mgmt, data_len, mod, ack_type,
219 direction, cmd, msg_id);
220 }
221
222 prepare_mgmt_cmd(pf_to_mgmt->sync_msg_buf, &header, data, data_len);
223
224 chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_WRITE_TO_MGMT_CPU];
225 return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT,
226 pf_to_mgmt->sync_msg_buf,
227 mgmt_msg_len(data_len));
228}
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
245 enum hinic_mod_type mod, u8 cmd,
246 u8 *buf_in, u16 in_size,
247 u8 *buf_out, u16 *out_size,
248 enum mgmt_direction_type direction,
249 u16 resp_msg_id, u32 timeout)
250{
251 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
252 struct pci_dev *pdev = hwif->pdev;
253 struct hinic_recv_msg *recv_msg;
254 struct completion *recv_done;
255 unsigned long timeo;
256 u16 msg_id;
257 int err;
258
259
260 down(&pf_to_mgmt->sync_msg_lock);
261
262 recv_msg = &pf_to_mgmt->recv_resp_msg_from_mgmt;
263 recv_done = &recv_msg->recv_done;
264
265 if (resp_msg_id == MSG_NOT_RESP)
266 msg_id = SYNC_MSG_ID(pf_to_mgmt);
267 else
268 msg_id = resp_msg_id;
269
270 init_completion(recv_done);
271
272 err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
273 MSG_ACK, direction, resp_msg_id);
274 if (err) {
275 dev_err(&pdev->dev, "Failed to send sync msg to mgmt\n");
276 goto unlock_sync_msg;
277 }
278
279 timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
280
281 if (!wait_for_completion_timeout(recv_done, timeo)) {
282 dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
283 hinic_dump_aeq_info(pf_to_mgmt->hwdev);
284 err = -ETIMEDOUT;
285 goto unlock_sync_msg;
286 }
287
288 smp_rmb();
289
290 if (recv_msg->msg_id != msg_id) {
291 dev_err(&pdev->dev, "incorrect MSG for id = %d\n", msg_id);
292 err = -EFAULT;
293 goto unlock_sync_msg;
294 }
295
296 if ((buf_out) && (recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE)) {
297 memcpy(buf_out, recv_msg->msg, recv_msg->msg_len);
298 *out_size = recv_msg->msg_len;
299 }
300
301unlock_sync_msg:
302 up(&pf_to_mgmt->sync_msg_lock);
303 return err;
304}
305
306
307
308
309
310
311
312
313
314
315
316
317
318static int msg_to_mgmt_async(struct hinic_pf_to_mgmt *pf_to_mgmt,
319 enum hinic_mod_type mod, u8 cmd,
320 u8 *buf_in, u16 in_size,
321 enum mgmt_direction_type direction,
322 u16 resp_msg_id)
323{
324 int err;
325
326
327 down(&pf_to_mgmt->sync_msg_lock);
328
329 err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
330 MSG_NO_ACK, direction, resp_msg_id);
331
332 up(&pf_to_mgmt->sync_msg_lock);
333 return err;
334}
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
350 enum hinic_mod_type mod, u8 cmd,
351 void *buf_in, u16 in_size, void *buf_out, u16 *out_size,
352 enum hinic_mgmt_msg_type sync)
353{
354 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
355 struct pci_dev *pdev = hwif->pdev;
356 u32 timeout = 0;
357
358 if (sync != HINIC_MGMT_MSG_SYNC) {
359 dev_err(&pdev->dev, "Invalid MGMT msg type\n");
360 return -EINVAL;
361 }
362
363 if (!MSG_SZ_IS_VALID(in_size)) {
364 dev_err(&pdev->dev, "Invalid MGMT msg buffer size\n");
365 return -EINVAL;
366 }
367
368 if (HINIC_IS_VF(hwif)) {
369 if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
370 timeout = SET_FUNC_PORT_MBOX_TIMEOUT;
371
372 return hinic_mbox_to_pf(pf_to_mgmt->hwdev, mod, cmd, buf_in,
373 in_size, buf_out, out_size, timeout);
374 } else {
375 if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
376 timeout = SET_FUNC_PORT_MGMT_TIMEOUT;
377 else if (cmd == HINIC_PORT_CMD_UPDATE_FW)
378 timeout = UPDATE_FW_MGMT_TIMEOUT;
379
380 return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
381 buf_out, out_size, MGMT_DIRECT_SEND,
382 MSG_NOT_RESP, timeout);
383 }
384}
385
386static void recv_mgmt_msg_work_handler(struct work_struct *work)
387{
388 struct hinic_mgmt_msg_handle_work *mgmt_work =
389 container_of(work, struct hinic_mgmt_msg_handle_work, work);
390 struct hinic_pf_to_mgmt *pf_to_mgmt = mgmt_work->pf_to_mgmt;
391 struct pci_dev *pdev = pf_to_mgmt->hwif->pdev;
392 u8 *buf_out = pf_to_mgmt->mgmt_ack_buf;
393 struct hinic_mgmt_cb *mgmt_cb;
394 unsigned long cb_state;
395 u16 out_size = 0;
396
397 memset(buf_out, 0, MAX_PF_MGMT_BUF_SIZE);
398
399 if (mgmt_work->mod >= HINIC_MOD_MAX) {
400 dev_err(&pdev->dev, "Unknown MGMT MSG module = %d\n",
401 mgmt_work->mod);
402 kfree(mgmt_work->msg);
403 kfree(mgmt_work);
404 return;
405 }
406
407 mgmt_cb = &pf_to_mgmt->mgmt_cb[mgmt_work->mod];
408
409 cb_state = cmpxchg(&mgmt_cb->state,
410 HINIC_MGMT_CB_ENABLED,
411 HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING);
412
413 if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb))
414 mgmt_cb->cb(mgmt_cb->handle, mgmt_work->cmd,
415 mgmt_work->msg, mgmt_work->msg_len,
416 buf_out, &out_size);
417 else
418 dev_err(&pdev->dev, "No MGMT msg handler, mod: %d, cmd: %d\n",
419 mgmt_work->mod, mgmt_work->cmd);
420
421 mgmt_cb->state &= ~HINIC_MGMT_CB_RUNNING;
422
423 if (!mgmt_work->async_mgmt_to_pf)
424
425 msg_to_mgmt_async(pf_to_mgmt, mgmt_work->mod, mgmt_work->cmd,
426 buf_out, out_size, MGMT_RESP,
427 mgmt_work->msg_id);
428
429 kfree(mgmt_work->msg);
430 kfree(mgmt_work);
431}
432
433
434
435
436
437
438static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
439 struct hinic_recv_msg *recv_msg)
440{
441 struct hinic_mgmt_msg_handle_work *mgmt_work = NULL;
442 struct pci_dev *pdev = pf_to_mgmt->hwif->pdev;
443
444 mgmt_work = kzalloc(sizeof(*mgmt_work), GFP_KERNEL);
445 if (!mgmt_work) {
446 dev_err(&pdev->dev, "Allocate mgmt work memory failed\n");
447 return;
448 }
449
450 if (recv_msg->msg_len) {
451 mgmt_work->msg = kzalloc(recv_msg->msg_len, GFP_KERNEL);
452 if (!mgmt_work->msg) {
453 dev_err(&pdev->dev, "Allocate mgmt msg memory failed\n");
454 kfree(mgmt_work);
455 return;
456 }
457 }
458
459 mgmt_work->pf_to_mgmt = pf_to_mgmt;
460 mgmt_work->msg_len = recv_msg->msg_len;
461 memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len);
462 mgmt_work->msg_id = recv_msg->msg_id;
463 mgmt_work->mod = recv_msg->mod;
464 mgmt_work->cmd = recv_msg->cmd;
465 mgmt_work->async_mgmt_to_pf = recv_msg->async_mgmt_to_pf;
466
467 INIT_WORK(&mgmt_work->work, recv_mgmt_msg_work_handler);
468 queue_work(pf_to_mgmt->workq, &mgmt_work->work);
469}
470
471
472
473
474
475
476static void mgmt_resp_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
477 struct hinic_recv_msg *recv_msg)
478{
479 wmb();
480
481 complete(&recv_msg->recv_done);
482}
483
484
485
486
487
488
489
490static void recv_mgmt_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
491 u64 *header, struct hinic_recv_msg *recv_msg)
492{
493 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
494 struct pci_dev *pdev = hwif->pdev;
495 int seq_id, seg_len;
496 u8 *msg_body;
497
498 seq_id = HINIC_MSG_HEADER_GET(*header, SEQID);
499 seg_len = HINIC_MSG_HEADER_GET(*header, SEG_LEN);
500
501 if (seq_id >= (MAX_MSG_LEN / SEGMENT_LEN)) {
502 dev_err(&pdev->dev, "recv big mgmt msg\n");
503 return;
504 }
505
506 msg_body = (u8 *)header + sizeof(*header);
507 memcpy(recv_msg->msg + seq_id * SEGMENT_LEN, msg_body, seg_len);
508
509 if (!HINIC_MSG_HEADER_GET(*header, LAST))
510 return;
511
512 recv_msg->cmd = HINIC_MSG_HEADER_GET(*header, CMD);
513 recv_msg->mod = HINIC_MSG_HEADER_GET(*header, MODULE);
514 recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(*header,
515 ASYNC_MGMT_TO_PF);
516 recv_msg->msg_len = HINIC_MSG_HEADER_GET(*header, MSG_LEN);
517 recv_msg->msg_id = HINIC_MSG_HEADER_GET(*header, MSG_ID);
518
519 if (HINIC_MSG_HEADER_GET(*header, DIRECTION) == MGMT_RESP)
520 mgmt_resp_msg_handler(pf_to_mgmt, recv_msg);
521 else
522 mgmt_recv_msg_handler(pf_to_mgmt, recv_msg);
523}
524
525
526
527
528
529
530
531static void mgmt_msg_aeqe_handler(void *handle, void *data, u8 size)
532{
533 struct hinic_pf_to_mgmt *pf_to_mgmt = handle;
534 struct hinic_recv_msg *recv_msg;
535 u64 *header = (u64 *)data;
536
537 recv_msg = HINIC_MSG_HEADER_GET(*header, DIRECTION) ==
538 MGMT_DIRECT_SEND ?
539 &pf_to_mgmt->recv_msg_from_mgmt :
540 &pf_to_mgmt->recv_resp_msg_from_mgmt;
541
542 recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg);
543}
544
545
546
547
548
549
550
551
552static int alloc_recv_msg(struct hinic_pf_to_mgmt *pf_to_mgmt,
553 struct hinic_recv_msg *recv_msg)
554{
555 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
556 struct pci_dev *pdev = hwif->pdev;
557
558 recv_msg->msg = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
559 GFP_KERNEL);
560 if (!recv_msg->msg)
561 return -ENOMEM;
562
563 recv_msg->buf_out = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
564 GFP_KERNEL);
565 if (!recv_msg->buf_out)
566 return -ENOMEM;
567
568 return 0;
569}
570
571
572
573
574
575
576
577static int alloc_msg_buf(struct hinic_pf_to_mgmt *pf_to_mgmt)
578{
579 struct hinic_hwif *hwif = pf_to_mgmt->hwif;
580 struct pci_dev *pdev = hwif->pdev;
581 int err;
582
583 err = alloc_recv_msg(pf_to_mgmt,
584 &pf_to_mgmt->recv_msg_from_mgmt);
585 if (err) {
586 dev_err(&pdev->dev, "Failed to allocate recv msg\n");
587 return err;
588 }
589
590 err = alloc_recv_msg(pf_to_mgmt,
591 &pf_to_mgmt->recv_resp_msg_from_mgmt);
592 if (err) {
593 dev_err(&pdev->dev, "Failed to allocate resp recv msg\n");
594 return err;
595 }
596
597 pf_to_mgmt->sync_msg_buf = devm_kzalloc(&pdev->dev,
598 MAX_PF_MGMT_BUF_SIZE,
599 GFP_KERNEL);
600 if (!pf_to_mgmt->sync_msg_buf)
601 return -ENOMEM;
602
603 pf_to_mgmt->mgmt_ack_buf = devm_kzalloc(&pdev->dev,
604 MAX_PF_MGMT_BUF_SIZE,
605 GFP_KERNEL);
606 if (!pf_to_mgmt->mgmt_ack_buf)
607 return -ENOMEM;
608
609 return 0;
610}
611
612
613
614
615
616
617
618
619int hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt *pf_to_mgmt,
620 struct hinic_hwif *hwif)
621{
622 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
623 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
624 struct pci_dev *pdev = hwif->pdev;
625 int err;
626
627 pf_to_mgmt->hwif = hwif;
628 pf_to_mgmt->hwdev = hwdev;
629
630 if (HINIC_IS_VF(hwif))
631 return 0;
632
633 err = hinic_health_reporters_create(hwdev->devlink_dev);
634 if (err)
635 return err;
636
637 sema_init(&pf_to_mgmt->sync_msg_lock, 1);
638 pf_to_mgmt->workq = create_singlethread_workqueue("hinic_mgmt");
639 if (!pf_to_mgmt->workq) {
640 dev_err(&pdev->dev, "Failed to initialize MGMT workqueue\n");
641 hinic_health_reporters_destroy(hwdev->devlink_dev);
642 return -ENOMEM;
643 }
644 pf_to_mgmt->sync_msg_id = 0;
645
646 err = alloc_msg_buf(pf_to_mgmt);
647 if (err) {
648 dev_err(&pdev->dev, "Failed to allocate msg buffers\n");
649 hinic_health_reporters_destroy(hwdev->devlink_dev);
650 return err;
651 }
652
653 err = hinic_api_cmd_init(pf_to_mgmt->cmd_chain, hwif);
654 if (err) {
655 dev_err(&pdev->dev, "Failed to initialize cmd chains\n");
656 hinic_health_reporters_destroy(hwdev->devlink_dev);
657 return err;
658 }
659
660 hinic_aeq_register_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU,
661 pf_to_mgmt,
662 mgmt_msg_aeqe_handler);
663 return 0;
664}
665
666
667
668
669
670void hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt *pf_to_mgmt)
671{
672 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
673 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
674
675 if (HINIC_IS_VF(hwdev->hwif))
676 return;
677
678 hinic_aeq_unregister_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU);
679 hinic_api_cmd_free(pf_to_mgmt->cmd_chain);
680 destroy_workqueue(pf_to_mgmt->workq);
681 hinic_health_reporters_destroy(hwdev->devlink_dev);
682}
683