.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Huawei HiNIC PCI Express Linux driver |
---|
3 | 4 | * Copyright(c) 2017 Huawei Technologies Co., Ltd |
---|
4 | | - * |
---|
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. |
---|
8 | | - * |
---|
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 |
---|
12 | | - * for more details. |
---|
13 | | - * |
---|
14 | 5 | */ |
---|
15 | 6 | |
---|
16 | 7 | #include <linux/kernel.h> |
---|
.. | .. |
---|
21 | 12 | #include <linux/semaphore.h> |
---|
22 | 13 | #include <linux/completion.h> |
---|
23 | 14 | #include <linux/slab.h> |
---|
| 15 | +#include <net/devlink.h> |
---|
24 | 16 | #include <asm/barrier.h> |
---|
25 | 17 | |
---|
| 18 | +#include "hinic_devlink.h" |
---|
26 | 19 | #include "hinic_hw_if.h" |
---|
27 | 20 | #include "hinic_hw_eqs.h" |
---|
28 | 21 | #include "hinic_hw_api_cmd.h" |
---|
.. | .. |
---|
54 | 47 | |
---|
55 | 48 | #define MGMT_MSG_TIMEOUT 5000 |
---|
56 | 49 | |
---|
| 50 | +#define SET_FUNC_PORT_MBOX_TIMEOUT 30000 |
---|
| 51 | + |
---|
57 | 52 | #define SET_FUNC_PORT_MGMT_TIMEOUT 25000 |
---|
| 53 | + |
---|
| 54 | +#define UPDATE_FW_MGMT_TIMEOUT 20000 |
---|
58 | 55 | |
---|
59 | 56 | #define mgmt_to_pfhwdev(pf_mgmt) \ |
---|
60 | 57 | container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt) |
---|
.. | .. |
---|
241 | 238 | * @out_size: response length |
---|
242 | 239 | * @direction: the direction of the original message |
---|
243 | 240 | * @resp_msg_id: msg id to response for |
---|
| 241 | + * @timeout: time-out period of waiting for response |
---|
244 | 242 | * |
---|
245 | 243 | * Return 0 - Success, negative - Failure |
---|
246 | 244 | **/ |
---|
.. | .. |
---|
283 | 281 | |
---|
284 | 282 | if (!wait_for_completion_timeout(recv_done, timeo)) { |
---|
285 | 283 | dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id); |
---|
| 284 | + hinic_dump_aeq_info(pf_to_mgmt->hwdev); |
---|
286 | 285 | err = -ETIMEDOUT; |
---|
287 | 286 | goto unlock_sync_msg; |
---|
288 | 287 | } |
---|
.. | .. |
---|
367 | 366 | return -EINVAL; |
---|
368 | 367 | } |
---|
369 | 368 | |
---|
370 | | - if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE) |
---|
371 | | - timeout = SET_FUNC_PORT_MGMT_TIMEOUT; |
---|
| 369 | + if (HINIC_IS_VF(hwif)) { |
---|
| 370 | + if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE) |
---|
| 371 | + timeout = SET_FUNC_PORT_MBOX_TIMEOUT; |
---|
372 | 372 | |
---|
373 | | - return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size, |
---|
| 373 | + return hinic_mbox_to_pf(pf_to_mgmt->hwdev, mod, cmd, buf_in, |
---|
| 374 | + in_size, buf_out, out_size, timeout); |
---|
| 375 | + } else { |
---|
| 376 | + if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE) |
---|
| 377 | + timeout = SET_FUNC_PORT_MGMT_TIMEOUT; |
---|
| 378 | + else if (cmd == HINIC_PORT_CMD_UPDATE_FW) |
---|
| 379 | + timeout = UPDATE_FW_MGMT_TIMEOUT; |
---|
| 380 | + |
---|
| 381 | + return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size, |
---|
374 | 382 | buf_out, out_size, MGMT_DIRECT_SEND, |
---|
375 | 383 | MSG_NOT_RESP, timeout); |
---|
| 384 | + } |
---|
| 385 | +} |
---|
| 386 | + |
---|
| 387 | +static void recv_mgmt_msg_work_handler(struct work_struct *work) |
---|
| 388 | +{ |
---|
| 389 | + struct hinic_mgmt_msg_handle_work *mgmt_work = |
---|
| 390 | + container_of(work, struct hinic_mgmt_msg_handle_work, work); |
---|
| 391 | + struct hinic_pf_to_mgmt *pf_to_mgmt = mgmt_work->pf_to_mgmt; |
---|
| 392 | + struct pci_dev *pdev = pf_to_mgmt->hwif->pdev; |
---|
| 393 | + u8 *buf_out = pf_to_mgmt->mgmt_ack_buf; |
---|
| 394 | + struct hinic_mgmt_cb *mgmt_cb; |
---|
| 395 | + unsigned long cb_state; |
---|
| 396 | + u16 out_size = 0; |
---|
| 397 | + |
---|
| 398 | + memset(buf_out, 0, MAX_PF_MGMT_BUF_SIZE); |
---|
| 399 | + |
---|
| 400 | + if (mgmt_work->mod >= HINIC_MOD_MAX) { |
---|
| 401 | + dev_err(&pdev->dev, "Unknown MGMT MSG module = %d\n", |
---|
| 402 | + mgmt_work->mod); |
---|
| 403 | + kfree(mgmt_work->msg); |
---|
| 404 | + kfree(mgmt_work); |
---|
| 405 | + return; |
---|
| 406 | + } |
---|
| 407 | + |
---|
| 408 | + mgmt_cb = &pf_to_mgmt->mgmt_cb[mgmt_work->mod]; |
---|
| 409 | + |
---|
| 410 | + cb_state = cmpxchg(&mgmt_cb->state, |
---|
| 411 | + HINIC_MGMT_CB_ENABLED, |
---|
| 412 | + HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING); |
---|
| 413 | + |
---|
| 414 | + if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb)) |
---|
| 415 | + mgmt_cb->cb(mgmt_cb->handle, mgmt_work->cmd, |
---|
| 416 | + mgmt_work->msg, mgmt_work->msg_len, |
---|
| 417 | + buf_out, &out_size); |
---|
| 418 | + else |
---|
| 419 | + dev_err(&pdev->dev, "No MGMT msg handler, mod: %d, cmd: %d\n", |
---|
| 420 | + mgmt_work->mod, mgmt_work->cmd); |
---|
| 421 | + |
---|
| 422 | + mgmt_cb->state &= ~HINIC_MGMT_CB_RUNNING; |
---|
| 423 | + |
---|
| 424 | + if (!mgmt_work->async_mgmt_to_pf) |
---|
| 425 | + /* MGMT sent sync msg, send the response */ |
---|
| 426 | + msg_to_mgmt_async(pf_to_mgmt, mgmt_work->mod, mgmt_work->cmd, |
---|
| 427 | + buf_out, out_size, MGMT_RESP, |
---|
| 428 | + mgmt_work->msg_id); |
---|
| 429 | + |
---|
| 430 | + kfree(mgmt_work->msg); |
---|
| 431 | + kfree(mgmt_work); |
---|
376 | 432 | } |
---|
377 | 433 | |
---|
378 | 434 | /** |
---|
.. | .. |
---|
383 | 439 | static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt, |
---|
384 | 440 | struct hinic_recv_msg *recv_msg) |
---|
385 | 441 | { |
---|
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; |
---|
391 | | - u16 out_size = 0; |
---|
| 442 | + struct hinic_mgmt_msg_handle_work *mgmt_work = NULL; |
---|
| 443 | + struct pci_dev *pdev = pf_to_mgmt->hwif->pdev; |
---|
392 | 444 | |
---|
393 | | - if (recv_msg->mod >= HINIC_MOD_MAX) { |
---|
394 | | - dev_err(&pdev->dev, "Unknown MGMT MSG module = %d\n", |
---|
395 | | - recv_msg->mod); |
---|
| 445 | + mgmt_work = kzalloc(sizeof(*mgmt_work), GFP_KERNEL); |
---|
| 446 | + if (!mgmt_work) { |
---|
| 447 | + dev_err(&pdev->dev, "Allocate mgmt work memory failed\n"); |
---|
396 | 448 | return; |
---|
397 | 449 | } |
---|
398 | 450 | |
---|
399 | | - mgmt_cb = &pf_to_mgmt->mgmt_cb[recv_msg->mod]; |
---|
| 451 | + if (recv_msg->msg_len) { |
---|
| 452 | + mgmt_work->msg = kzalloc(recv_msg->msg_len, GFP_KERNEL); |
---|
| 453 | + if (!mgmt_work->msg) { |
---|
| 454 | + dev_err(&pdev->dev, "Allocate mgmt msg memory failed\n"); |
---|
| 455 | + kfree(mgmt_work); |
---|
| 456 | + return; |
---|
| 457 | + } |
---|
| 458 | + } |
---|
400 | 459 | |
---|
401 | | - cb_state = cmpxchg(&mgmt_cb->state, |
---|
402 | | - HINIC_MGMT_CB_ENABLED, |
---|
403 | | - HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING); |
---|
| 460 | + mgmt_work->pf_to_mgmt = pf_to_mgmt; |
---|
| 461 | + mgmt_work->msg_len = recv_msg->msg_len; |
---|
| 462 | + memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len); |
---|
| 463 | + mgmt_work->msg_id = recv_msg->msg_id; |
---|
| 464 | + mgmt_work->mod = recv_msg->mod; |
---|
| 465 | + mgmt_work->cmd = recv_msg->cmd; |
---|
| 466 | + mgmt_work->async_mgmt_to_pf = recv_msg->async_mgmt_to_pf; |
---|
404 | 467 | |
---|
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, |
---|
408 | | - buf_out, &out_size); |
---|
409 | | - else |
---|
410 | | - dev_err(&pdev->dev, "No MGMT msg handler, mod = %d\n", |
---|
411 | | - recv_msg->mod); |
---|
412 | | - |
---|
413 | | - mgmt_cb->state &= ~HINIC_MGMT_CB_RUNNING; |
---|
414 | | - |
---|
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, |
---|
419 | | - recv_msg->msg_id); |
---|
| 468 | + INIT_WORK(&mgmt_work->work, recv_mgmt_msg_work_handler); |
---|
| 469 | + queue_work(pf_to_mgmt->workq, &mgmt_work->work); |
---|
420 | 470 | } |
---|
421 | 471 | |
---|
422 | 472 | /** |
---|
.. | .. |
---|
551 | 601 | if (!pf_to_mgmt->sync_msg_buf) |
---|
552 | 602 | return -ENOMEM; |
---|
553 | 603 | |
---|
| 604 | + pf_to_mgmt->mgmt_ack_buf = devm_kzalloc(&pdev->dev, |
---|
| 605 | + MAX_PF_MGMT_BUF_SIZE, |
---|
| 606 | + GFP_KERNEL); |
---|
| 607 | + if (!pf_to_mgmt->mgmt_ack_buf) |
---|
| 608 | + return -ENOMEM; |
---|
| 609 | + |
---|
554 | 610 | return 0; |
---|
555 | 611 | } |
---|
556 | 612 | |
---|
.. | .. |
---|
570 | 626 | int err; |
---|
571 | 627 | |
---|
572 | 628 | pf_to_mgmt->hwif = hwif; |
---|
| 629 | + pf_to_mgmt->hwdev = hwdev; |
---|
| 630 | + |
---|
| 631 | + if (HINIC_IS_VF(hwif)) |
---|
| 632 | + return 0; |
---|
| 633 | + |
---|
| 634 | + err = hinic_health_reporters_create(hwdev->devlink_dev); |
---|
| 635 | + if (err) |
---|
| 636 | + return err; |
---|
573 | 637 | |
---|
574 | 638 | sema_init(&pf_to_mgmt->sync_msg_lock, 1); |
---|
| 639 | + pf_to_mgmt->workq = create_singlethread_workqueue("hinic_mgmt"); |
---|
| 640 | + if (!pf_to_mgmt->workq) { |
---|
| 641 | + dev_err(&pdev->dev, "Failed to initialize MGMT workqueue\n"); |
---|
| 642 | + hinic_health_reporters_destroy(hwdev->devlink_dev); |
---|
| 643 | + return -ENOMEM; |
---|
| 644 | + } |
---|
575 | 645 | pf_to_mgmt->sync_msg_id = 0; |
---|
576 | 646 | |
---|
577 | 647 | err = alloc_msg_buf(pf_to_mgmt); |
---|
578 | 648 | if (err) { |
---|
579 | 649 | dev_err(&pdev->dev, "Failed to allocate msg buffers\n"); |
---|
| 650 | + destroy_workqueue(pf_to_mgmt->workq); |
---|
| 651 | + hinic_health_reporters_destroy(hwdev->devlink_dev); |
---|
580 | 652 | return err; |
---|
581 | 653 | } |
---|
582 | 654 | |
---|
583 | 655 | err = hinic_api_cmd_init(pf_to_mgmt->cmd_chain, hwif); |
---|
584 | 656 | if (err) { |
---|
585 | 657 | dev_err(&pdev->dev, "Failed to initialize cmd chains\n"); |
---|
| 658 | + destroy_workqueue(pf_to_mgmt->workq); |
---|
| 659 | + hinic_health_reporters_destroy(hwdev->devlink_dev); |
---|
586 | 660 | return err; |
---|
587 | 661 | } |
---|
588 | 662 | |
---|
.. | .. |
---|
601 | 675 | struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt); |
---|
602 | 676 | struct hinic_hwdev *hwdev = &pfhwdev->hwdev; |
---|
603 | 677 | |
---|
| 678 | + if (HINIC_IS_VF(hwdev->hwif)) |
---|
| 679 | + return; |
---|
| 680 | + |
---|
604 | 681 | hinic_aeq_unregister_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU); |
---|
605 | 682 | hinic_api_cmd_free(pf_to_mgmt->cmd_chain); |
---|
| 683 | + destroy_workqueue(pf_to_mgmt->workq); |
---|
| 684 | + hinic_health_reporters_destroy(hwdev->devlink_dev); |
---|
606 | 685 | } |
---|