cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hinic_hw_mgmt.c (19035B)


      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 * @timeout: time-out period of waiting for response
    242 *
    243 * Return 0 - Success, negative - Failure
    244 **/
    245static 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,
    250			    u16 resp_msg_id, u32 timeout)
    251{
    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;
    256	unsigned long timeo;
    257	u16 msg_id;
    258	int err;
    259
    260	/* Lock the sync_msg_buf */
    261	down(&pf_to_mgmt->sync_msg_lock);
    262
    263	recv_msg = &pf_to_mgmt->recv_resp_msg_from_mgmt;
    264	recv_done = &recv_msg->recv_done;
    265
    266	if (resp_msg_id == MSG_NOT_RESP)
    267		msg_id = SYNC_MSG_ID(pf_to_mgmt);
    268	else
    269		msg_id = resp_msg_id;
    270
    271	init_completion(recv_done);
    272
    273	err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
    274			       MSG_ACK, direction, resp_msg_id);
    275	if (err) {
    276		dev_err(&pdev->dev, "Failed to send sync msg to mgmt\n");
    277		goto unlock_sync_msg;
    278	}
    279
    280	timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
    281
    282	if (!wait_for_completion_timeout(recv_done, timeo)) {
    283		dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
    284		hinic_dump_aeq_info(pf_to_mgmt->hwdev);
    285		err = -ETIMEDOUT;
    286		goto unlock_sync_msg;
    287	}
    288
    289	smp_rmb();      /* verify reading after completion */
    290
    291	if (recv_msg->msg_id != msg_id) {
    292		dev_err(&pdev->dev, "incorrect MSG for id = %d\n", msg_id);
    293		err = -EFAULT;
    294		goto unlock_sync_msg;
    295	}
    296
    297	if (buf_out && recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE) {
    298		memcpy(buf_out, recv_msg->msg, recv_msg->msg_len);
    299		*out_size = recv_msg->msg_len;
    300	}
    301
    302unlock_sync_msg:
    303	up(&pf_to_mgmt->sync_msg_lock);
    304	return err;
    305}
    306
    307/**
    308 * msg_to_mgmt_async - send message to mgmt without response
    309 * @pf_to_mgmt: PF to MGMT channel
    310 * @mod: module in the chip that will get the message
    311 * @cmd: command of the message
    312 * @buf_in: the msg data
    313 * @in_size: the msg data length
    314 * @direction: the direction of the original message
    315 * @resp_msg_id: msg id to response for
    316 *
    317 * Return 0 - Success, negative - Failure
    318 **/
    319static int msg_to_mgmt_async(struct hinic_pf_to_mgmt *pf_to_mgmt,
    320			     enum hinic_mod_type mod, u8 cmd,
    321			     u8 *buf_in, u16 in_size,
    322			     enum mgmt_direction_type direction,
    323			     u16 resp_msg_id)
    324{
    325	int err;
    326
    327	/* Lock the sync_msg_buf */
    328	down(&pf_to_mgmt->sync_msg_lock);
    329
    330	err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size,
    331			       MSG_NO_ACK, direction, resp_msg_id);
    332
    333	up(&pf_to_mgmt->sync_msg_lock);
    334	return err;
    335}
    336
    337/**
    338 * hinic_msg_to_mgmt - send message to mgmt
    339 * @pf_to_mgmt: PF to MGMT channel
    340 * @mod: module in the chip that will get the message
    341 * @cmd: command of the message
    342 * @buf_in: the msg data
    343 * @in_size: the msg data length
    344 * @buf_out: response
    345 * @out_size: returned response length
    346 * @sync: sync msg or async msg
    347 *
    348 * Return 0 - Success, negative - Failure
    349 **/
    350int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt,
    351		      enum hinic_mod_type mod, u8 cmd,
    352		      void *buf_in, u16 in_size, void *buf_out, u16 *out_size,
    353		      enum hinic_mgmt_msg_type sync)
    354{
    355	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
    356	struct pci_dev *pdev = hwif->pdev;
    357	u32 timeout = 0;
    358
    359	if (sync != HINIC_MGMT_MSG_SYNC) {
    360		dev_err(&pdev->dev, "Invalid MGMT msg type\n");
    361		return -EINVAL;
    362	}
    363
    364	if (!MSG_SZ_IS_VALID(in_size)) {
    365		dev_err(&pdev->dev, "Invalid MGMT msg buffer size\n");
    366		return -EINVAL;
    367	}
    368
    369	if (HINIC_IS_VF(hwif)) {
    370		if (cmd == HINIC_PORT_CMD_SET_FUNC_STATE)
    371			timeout = SET_FUNC_PORT_MBOX_TIMEOUT;
    372
    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,
    382				buf_out, out_size, MGMT_DIRECT_SEND,
    383				MSG_NOT_RESP, timeout);
    384	}
    385}
    386
    387static 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);
    432}
    433
    434/**
    435 * mgmt_recv_msg_handler - handler for message from mgmt cpu
    436 * @pf_to_mgmt: PF to MGMT channel
    437 * @recv_msg: received message details
    438 **/
    439static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
    440				  struct hinic_recv_msg *recv_msg)
    441{
    442	struct hinic_mgmt_msg_handle_work *mgmt_work = NULL;
    443
    444	mgmt_work = kzalloc(sizeof(*mgmt_work), GFP_KERNEL);
    445	if (!mgmt_work)
    446		return;
    447
    448	if (recv_msg->msg_len) {
    449		mgmt_work->msg = kzalloc(recv_msg->msg_len, GFP_KERNEL);
    450		if (!mgmt_work->msg) {
    451			kfree(mgmt_work);
    452			return;
    453		}
    454	}
    455
    456	mgmt_work->pf_to_mgmt = pf_to_mgmt;
    457	mgmt_work->msg_len = recv_msg->msg_len;
    458	memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len);
    459	mgmt_work->msg_id = recv_msg->msg_id;
    460	mgmt_work->mod = recv_msg->mod;
    461	mgmt_work->cmd = recv_msg->cmd;
    462	mgmt_work->async_mgmt_to_pf = recv_msg->async_mgmt_to_pf;
    463
    464	INIT_WORK(&mgmt_work->work, recv_mgmt_msg_work_handler);
    465	queue_work(pf_to_mgmt->workq, &mgmt_work->work);
    466}
    467
    468/**
    469 * mgmt_resp_msg_handler - handler for a response message from mgmt cpu
    470 * @pf_to_mgmt: PF to MGMT channel
    471 * @recv_msg: received message details
    472 **/
    473static void mgmt_resp_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
    474				  struct hinic_recv_msg *recv_msg)
    475{
    476	wmb();  /* verify writing all, before reading */
    477
    478	complete(&recv_msg->recv_done);
    479}
    480
    481/**
    482 * recv_mgmt_msg_handler - handler for a message from mgmt cpu
    483 * @pf_to_mgmt: PF to MGMT channel
    484 * @header: the header of the message
    485 * @recv_msg: received message details
    486 **/
    487static void recv_mgmt_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt,
    488				  u64 *header, struct hinic_recv_msg *recv_msg)
    489{
    490	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
    491	struct pci_dev *pdev = hwif->pdev;
    492	int seq_id, seg_len;
    493	u8 *msg_body;
    494
    495	seq_id = HINIC_MSG_HEADER_GET(*header, SEQID);
    496	seg_len = HINIC_MSG_HEADER_GET(*header, SEG_LEN);
    497
    498	if (seq_id >= (MAX_MSG_LEN / SEGMENT_LEN)) {
    499		dev_err(&pdev->dev, "recv big mgmt msg\n");
    500		return;
    501	}
    502
    503	msg_body = (u8 *)header + sizeof(*header);
    504	memcpy(recv_msg->msg + seq_id * SEGMENT_LEN, msg_body, seg_len);
    505
    506	if (!HINIC_MSG_HEADER_GET(*header, LAST))
    507		return;
    508
    509	recv_msg->cmd = HINIC_MSG_HEADER_GET(*header, CMD);
    510	recv_msg->mod = HINIC_MSG_HEADER_GET(*header, MODULE);
    511	recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(*header,
    512							  ASYNC_MGMT_TO_PF);
    513	recv_msg->msg_len = HINIC_MSG_HEADER_GET(*header, MSG_LEN);
    514	recv_msg->msg_id = HINIC_MSG_HEADER_GET(*header, MSG_ID);
    515
    516	if (HINIC_MSG_HEADER_GET(*header, DIRECTION) == MGMT_RESP)
    517		mgmt_resp_msg_handler(pf_to_mgmt, recv_msg);
    518	else
    519		mgmt_recv_msg_handler(pf_to_mgmt, recv_msg);
    520}
    521
    522/**
    523 * mgmt_msg_aeqe_handler - handler for a mgmt message event
    524 * @handle: PF to MGMT channel
    525 * @data: the header of the message
    526 * @size: unused
    527 **/
    528static void mgmt_msg_aeqe_handler(void *handle, void *data, u8 size)
    529{
    530	struct hinic_pf_to_mgmt *pf_to_mgmt = handle;
    531	struct hinic_recv_msg *recv_msg;
    532	u64 *header = (u64 *)data;
    533
    534	recv_msg = HINIC_MSG_HEADER_GET(*header, DIRECTION) ==
    535		   MGMT_DIRECT_SEND ?
    536		   &pf_to_mgmt->recv_msg_from_mgmt :
    537		   &pf_to_mgmt->recv_resp_msg_from_mgmt;
    538
    539	recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg);
    540}
    541
    542/**
    543 * alloc_recv_msg - allocate receive message memory
    544 * @pf_to_mgmt: PF to MGMT channel
    545 * @recv_msg: pointer that will hold the allocated data
    546 *
    547 * Return 0 - Success, negative - Failure
    548 **/
    549static int alloc_recv_msg(struct hinic_pf_to_mgmt *pf_to_mgmt,
    550			  struct hinic_recv_msg *recv_msg)
    551{
    552	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
    553	struct pci_dev *pdev = hwif->pdev;
    554
    555	recv_msg->msg = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
    556				     GFP_KERNEL);
    557	if (!recv_msg->msg)
    558		return -ENOMEM;
    559
    560	recv_msg->buf_out = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE,
    561					 GFP_KERNEL);
    562	if (!recv_msg->buf_out)
    563		return -ENOMEM;
    564
    565	return 0;
    566}
    567
    568/**
    569 * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
    570 * @pf_to_mgmt: PF to MGMT channel
    571 *
    572 * Return 0 - Success, negative - Failure
    573 **/
    574static int alloc_msg_buf(struct hinic_pf_to_mgmt *pf_to_mgmt)
    575{
    576	struct hinic_hwif *hwif = pf_to_mgmt->hwif;
    577	struct pci_dev *pdev = hwif->pdev;
    578	int err;
    579
    580	err = alloc_recv_msg(pf_to_mgmt,
    581			     &pf_to_mgmt->recv_msg_from_mgmt);
    582	if (err) {
    583		dev_err(&pdev->dev, "Failed to allocate recv msg\n");
    584		return err;
    585	}
    586
    587	err = alloc_recv_msg(pf_to_mgmt,
    588			     &pf_to_mgmt->recv_resp_msg_from_mgmt);
    589	if (err) {
    590		dev_err(&pdev->dev, "Failed to allocate resp recv msg\n");
    591		return err;
    592	}
    593
    594	pf_to_mgmt->sync_msg_buf = devm_kzalloc(&pdev->dev,
    595						MAX_PF_MGMT_BUF_SIZE,
    596						GFP_KERNEL);
    597	if (!pf_to_mgmt->sync_msg_buf)
    598		return -ENOMEM;
    599
    600	pf_to_mgmt->mgmt_ack_buf = devm_kzalloc(&pdev->dev,
    601						MAX_PF_MGMT_BUF_SIZE,
    602						GFP_KERNEL);
    603	if (!pf_to_mgmt->mgmt_ack_buf)
    604		return -ENOMEM;
    605
    606	return 0;
    607}
    608
    609/**
    610 * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
    611 * @pf_to_mgmt: PF to MGMT channel
    612 * @hwif: HW interface the PF to MGMT will use for accessing HW
    613 *
    614 * Return 0 - Success, negative - Failure
    615 **/
    616int hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt *pf_to_mgmt,
    617			  struct hinic_hwif *hwif)
    618{
    619	struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
    620	struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
    621	struct pci_dev *pdev = hwif->pdev;
    622	int err;
    623
    624	pf_to_mgmt->hwif = hwif;
    625	pf_to_mgmt->hwdev = hwdev;
    626
    627	if (HINIC_IS_VF(hwif))
    628		return 0;
    629
    630	err = hinic_health_reporters_create(hwdev->devlink_dev);
    631	if (err)
    632		return err;
    633
    634	sema_init(&pf_to_mgmt->sync_msg_lock, 1);
    635	pf_to_mgmt->workq = create_singlethread_workqueue("hinic_mgmt");
    636	if (!pf_to_mgmt->workq) {
    637		dev_err(&pdev->dev, "Failed to initialize MGMT workqueue\n");
    638		hinic_health_reporters_destroy(hwdev->devlink_dev);
    639		return -ENOMEM;
    640	}
    641	pf_to_mgmt->sync_msg_id = 0;
    642
    643	err = alloc_msg_buf(pf_to_mgmt);
    644	if (err) {
    645		dev_err(&pdev->dev, "Failed to allocate msg buffers\n");
    646		destroy_workqueue(pf_to_mgmt->workq);
    647		hinic_health_reporters_destroy(hwdev->devlink_dev);
    648		return err;
    649	}
    650
    651	err = hinic_api_cmd_init(pf_to_mgmt->cmd_chain, hwif);
    652	if (err) {
    653		dev_err(&pdev->dev, "Failed to initialize cmd chains\n");
    654		destroy_workqueue(pf_to_mgmt->workq);
    655		hinic_health_reporters_destroy(hwdev->devlink_dev);
    656		return err;
    657	}
    658
    659	hinic_aeq_register_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU,
    660				 pf_to_mgmt,
    661				 mgmt_msg_aeqe_handler);
    662	return 0;
    663}
    664
    665/**
    666 * hinic_pf_to_mgmt_free - free PF to MGMT channel
    667 * @pf_to_mgmt: PF to MGMT channel
    668 **/
    669void hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt *pf_to_mgmt)
    670{
    671	struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt);
    672	struct hinic_hwdev *hwdev = &pfhwdev->hwdev;
    673
    674	if (HINIC_IS_VF(hwdev->hwif))
    675		return;
    676
    677	hinic_aeq_unregister_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU);
    678	hinic_api_cmd_free(pf_to_mgmt->cmd_chain);
    679	destroy_workqueue(pf_to_mgmt->workq);
    680	hinic_health_reporters_destroy(hwdev->devlink_dev);
    681}