linux/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Huawei HiNIC PCI Express Linux driver
   4 * Copyright(c) 2017 Huawei Technologies Co., Ltd
   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/* Data should be SEG LEN size aligned */
  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 * hinic_register_mgmt_msg_cb - register msg handler for a msg from a module
  76 * @pf_to_mgmt: PF to MGMT channel
  77 * @mod: module in the chip that this handler will handle its messages
  78 * @handle: private data for the callback
  79 * @callback: the handler that will handle messages
  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 * hinic_unregister_mgmt_msg_cb - unregister msg handler for a msg from a module
  98 * @pf_to_mgmt: PF to MGMT channel
  99 * @mod: module in the chip that this handler handles its messages
 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 * prepare_header - prepare the header of the message
 116 * @pf_to_mgmt: PF to MGMT channel
 117 * @msg_len: the length of the message
 118 * @mod: module in the chip that will get the message
 119 * @ack_type: ask for response
 120 * @direction: the direction of the message
 121 * @cmd: command of the message
 122 * @msg_id: message id
 123 *
 124 * Return the prepared header value
 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 * prepare_mgmt_cmd - prepare the mgmt command
 150 * @mgmt_cmd: pointer to the command to prepare
 151 * @header: pointer of the header for the message
 152 * @msg: the data of the message
 153 * @msg_len: the length of the message
 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 * mgmt_msg_len - calculate the total message length
 168 * @msg_data_len: the length of the message data
 169 *
 170 * Return the total message length
 171 **/
 172static u16 mgmt_msg_len(u16 msg_data_len)
 173{
 174        /* RSVD + HEADER_SIZE + DATA_LEN */
 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 * send_msg_to_mgmt - send message to mgmt by API CMD
 189 * @pf_to_mgmt: PF to MGMT channel
 190 * @mod: module in the chip that will get the message
 191 * @cmd: command of the message
 192 * @data: the msg data
 193 * @data_len: the msg data length
 194 * @ack_type: ask for response
 195 * @direction: the direction of the original message
 196 * @resp_msg_id: msg id to response for
 197 *
 198 * Return 0 - Success, negative - Failure
 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 * msg_to_mgmt_sync - send sync message to mgmt
 232 * @pf_to_mgmt: PF to MGMT channel
 233 * @mod: module in the chip that will get the message
 234 * @cmd: command of the message
 235 * @buf_in: the msg data
 236 * @in_size: the msg data length
 237 * @buf_out: response
 238 * @out_size: response length
 239 * @direction: the direction of the original message
 240 * @resp_msg_id: msg id to response for
 241 *
 242 * Return 0 - Success, negative - Failure
 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        /* Lock the sync_msg_buf */
 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();      /* verify reading after completion */
 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 * msg_to_mgmt_async - send message to mgmt without response
 308 * @pf_to_mgmt: PF to MGMT channel
 309 * @mod: module in the chip that will get the message
 310 * @cmd: command of the message
 311 * @buf_in: the msg data
 312 * @in_size: the msg data length
 313 * @direction: the direction of the original message
 314 * @resp_msg_id: msg id to response for
 315 *
 316 * Return 0 - Success, negative - Failure
 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        /* Lock the sync_msg_buf */
 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 * hinic_msg_to_mgmt - send message to mgmt
 338 * @pf_to_mgmt: PF to MGMT channel
 339 * @mod: module in the chip that will get the message
 340 * @cmd: command of the message
 341 * @buf_in: the msg data
 342 * @in_size: the msg data length
 343 * @buf_out: response
 344 * @out_size: returned response length
 345 * @sync: sync msg or async msg
 346 *
 347 * Return 0 - Success, negative - Failure
 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                /* MGMT sent sync msg, send the response */
 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 * mgmt_recv_msg_handler - handler for message from mgmt cpu
 435 * @pf_to_mgmt: PF to MGMT channel
 436 * @recv_msg: received message details
 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 * mgmt_resp_msg_handler - handler for a response message from mgmt cpu
 473 * @pf_to_mgmt: PF to MGMT channel
 474 * @recv_msg: received message details
 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();  /* verify writing all, before reading */
 480
 481        complete(&recv_msg->recv_done);
 482}
 483
 484/**
 485 * recv_mgmt_msg_handler - handler for a message from mgmt cpu
 486 * @pf_to_mgmt: PF to MGMT channel
 487 * @header: the header of the message
 488 * @recv_msg: received message details
 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 * mgmt_msg_aeqe_handler - handler for a mgmt message event
 527 * @handle: PF to MGMT channel
 528 * @data: the header of the message
 529 * @size: unused
 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 * alloc_recv_msg - allocate receive message memory
 547 * @pf_to_mgmt: PF to MGMT channel
 548 * @recv_msg: pointer that will hold the allocated data
 549 *
 550 * Return 0 - Success, negative - Failure
 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 * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
 573 * @pf_to_mgmt: PF to MGMT channel
 574 *
 575 * Return 0 - Success, negative - Failure
 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 * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
 614 * @pf_to_mgmt: PF to MGMT channel
 615 * @hwif: HW interface the PF to MGMT will use for accessing HW
 616 *
 617 * Return 0 - Success, negative - Failure
 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 * hinic_pf_to_mgmt_free - free PF to MGMT channel
 668 * @pf_to_mgmt: PF to MGMT channel
 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