1198 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Huawei HiNIC PCI Express Linux driver4 * Copyright(c) 2017 Huawei Technologies Co., Ltd5 */6 7#include <linux/kernel.h>8#include <linux/types.h>9#include <linux/pci.h>10#include <linux/device.h>11#include <linux/errno.h>12#include <linux/slab.h>13#include <linux/bitops.h>14#include <linux/delay.h>15#include <linux/jiffies.h>16#include <linux/log2.h>17#include <linux/err.h>18#include <linux/netdevice.h>19#include <net/devlink.h>20 21#include "hinic_devlink.h"22#include "hinic_sriov.h"23#include "hinic_dev.h"24#include "hinic_hw_if.h"25#include "hinic_hw_eqs.h"26#include "hinic_hw_mgmt.h"27#include "hinic_hw_qp_ctxt.h"28#include "hinic_hw_qp.h"29#include "hinic_hw_io.h"30#include "hinic_hw_dev.h"31 32#define OUTBOUND_STATE_TIMEOUT 10033#define DB_STATE_TIMEOUT 10034 35#define MAX_IRQS(max_qps, num_aeqs, num_ceqs) \36 (2 * (max_qps) + (num_aeqs) + (num_ceqs))37 38#define ADDR_IN_4BYTES(addr) ((addr) >> 2)39 40enum intr_type {41 INTR_MSIX_TYPE,42};43 44/**45 * parse_capability - convert device capabilities to NIC capabilities46 * @hwdev: the HW device to set and convert device capabilities for47 * @dev_cap: device capabilities from FW48 *49 * Return 0 - Success, negative - Failure50 **/51static int parse_capability(struct hinic_hwdev *hwdev,52 struct hinic_dev_cap *dev_cap)53{54 struct hinic_cap *nic_cap = &hwdev->nic_cap;55 int num_aeqs, num_ceqs, num_irqs;56 57 if (!HINIC_IS_VF(hwdev->hwif) && dev_cap->intr_type != INTR_MSIX_TYPE)58 return -EFAULT;59 60 num_aeqs = HINIC_HWIF_NUM_AEQS(hwdev->hwif);61 num_ceqs = HINIC_HWIF_NUM_CEQS(hwdev->hwif);62 num_irqs = HINIC_HWIF_NUM_IRQS(hwdev->hwif);63 64 /* Each QP has its own (SQ + RQ) interrupts */65 nic_cap->num_qps = (num_irqs - (num_aeqs + num_ceqs)) / 2;66 67 if (nic_cap->num_qps > HINIC_Q_CTXT_MAX)68 nic_cap->num_qps = HINIC_Q_CTXT_MAX;69 70 if (!HINIC_IS_VF(hwdev->hwif))71 nic_cap->max_qps = dev_cap->max_sqs + 1;72 else73 nic_cap->max_qps = dev_cap->max_sqs;74 75 if (nic_cap->num_qps > nic_cap->max_qps)76 nic_cap->num_qps = nic_cap->max_qps;77 78 if (!HINIC_IS_VF(hwdev->hwif)) {79 nic_cap->max_vf = dev_cap->max_vf;80 nic_cap->max_vf_qps = dev_cap->max_vf_sqs + 1;81 }82 83 hwdev->port_id = dev_cap->port_id;84 85 return 0;86}87 88/**89 * get_capability - get device capabilities from FW90 * @pfhwdev: the PF HW device to get capabilities for91 *92 * Return 0 - Success, negative - Failure93 **/94static int get_capability(struct hinic_pfhwdev *pfhwdev)95{96 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;97 struct hinic_hwif *hwif = hwdev->hwif;98 struct pci_dev *pdev = hwif->pdev;99 struct hinic_dev_cap dev_cap;100 u16 out_len;101 int err;102 103 out_len = sizeof(dev_cap);104 105 err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_CFGM,106 HINIC_CFG_NIC_CAP, &dev_cap, sizeof(dev_cap),107 &dev_cap, &out_len, HINIC_MGMT_MSG_SYNC);108 if (err) {109 dev_err(&pdev->dev, "Failed to get capability from FW\n");110 return err;111 }112 113 return parse_capability(hwdev, &dev_cap);114}115 116/**117 * get_dev_cap - get device capabilities118 * @hwdev: the NIC HW device to get capabilities for119 *120 * Return 0 - Success, negative - Failure121 **/122static int get_dev_cap(struct hinic_hwdev *hwdev)123{124 struct hinic_hwif *hwif = hwdev->hwif;125 struct pci_dev *pdev = hwif->pdev;126 struct hinic_pfhwdev *pfhwdev;127 int err;128 129 switch (HINIC_FUNC_TYPE(hwif)) {130 case HINIC_PPF:131 case HINIC_PF:132 case HINIC_VF:133 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);134 err = get_capability(pfhwdev);135 if (err) {136 dev_err(&pdev->dev, "Failed to get capability\n");137 return err;138 }139 break;140 default:141 dev_err(&pdev->dev, "Unsupported PCI Function type\n");142 return -EINVAL;143 }144 145 return 0;146}147 148/**149 * init_msix - enable the msix and save the entries150 * @hwdev: the NIC HW device151 *152 * Return 0 - Success, negative - Failure153 **/154static int init_msix(struct hinic_hwdev *hwdev)155{156 struct hinic_hwif *hwif = hwdev->hwif;157 struct pci_dev *pdev = hwif->pdev;158 int nr_irqs, num_aeqs, num_ceqs;159 int i, err;160 161 num_aeqs = HINIC_HWIF_NUM_AEQS(hwif);162 num_ceqs = HINIC_HWIF_NUM_CEQS(hwif);163 nr_irqs = MAX_IRQS(HINIC_MAX_QPS, num_aeqs, num_ceqs);164 if (nr_irqs > HINIC_HWIF_NUM_IRQS(hwif))165 nr_irqs = HINIC_HWIF_NUM_IRQS(hwif);166 167 hwdev->msix_entries = devm_kcalloc(&pdev->dev, nr_irqs,168 sizeof(*hwdev->msix_entries),169 GFP_KERNEL);170 if (!hwdev->msix_entries)171 return -ENOMEM;172 173 for (i = 0; i < nr_irqs; i++)174 hwdev->msix_entries[i].entry = i;175 176 err = pci_enable_msix_exact(pdev, hwdev->msix_entries, nr_irqs);177 if (err) {178 dev_err(&pdev->dev, "Failed to enable pci msix\n");179 return err;180 }181 182 return 0;183}184 185/**186 * disable_msix - disable the msix187 * @hwdev: the NIC HW device188 **/189static void disable_msix(struct hinic_hwdev *hwdev)190{191 struct hinic_hwif *hwif = hwdev->hwif;192 struct pci_dev *pdev = hwif->pdev;193 194 pci_disable_msix(pdev);195}196 197/**198 * hinic_port_msg_cmd - send port msg to mgmt199 * @hwdev: the NIC HW device200 * @cmd: the port command201 * @buf_in: input buffer202 * @in_size: input size203 * @buf_out: output buffer204 * @out_size: returned output size205 *206 * Return 0 - Success, negative - Failure207 **/208int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd,209 void *buf_in, u16 in_size, void *buf_out, u16 *out_size)210{211 struct hinic_pfhwdev *pfhwdev;212 213 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);214 215 return hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_L2NIC, cmd,216 buf_in, in_size, buf_out, out_size,217 HINIC_MGMT_MSG_SYNC);218}219 220int hinic_hilink_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_hilink_cmd cmd,221 void *buf_in, u16 in_size, void *buf_out,222 u16 *out_size)223{224 struct hinic_pfhwdev *pfhwdev;225 226 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);227 228 return hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_HILINK, cmd,229 buf_in, in_size, buf_out, out_size,230 HINIC_MGMT_MSG_SYNC);231}232 233/**234 * init_fw_ctxt- Init Firmware tables before network mgmt and io operations235 * @hwdev: the NIC HW device236 *237 * Return 0 - Success, negative - Failure238 **/239static int init_fw_ctxt(struct hinic_hwdev *hwdev)240{241 struct hinic_hwif *hwif = hwdev->hwif;242 struct pci_dev *pdev = hwif->pdev;243 struct hinic_cmd_fw_ctxt fw_ctxt;244 u16 out_size = sizeof(fw_ctxt);245 int err;246 247 fw_ctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif);248 fw_ctxt.rx_buf_sz = HINIC_RX_BUF_SZ;249 250 err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_FWCTXT_INIT,251 &fw_ctxt, sizeof(fw_ctxt),252 &fw_ctxt, &out_size);253 if (err || out_size != sizeof(fw_ctxt) || fw_ctxt.status) {254 dev_err(&pdev->dev, "Failed to init FW ctxt, err: %d, status: 0x%x, out size: 0x%x\n",255 err, fw_ctxt.status, out_size);256 return -EIO;257 }258 259 return 0;260}261 262/**263 * set_hw_ioctxt - set the shape of the IO queues in FW264 * @hwdev: the NIC HW device265 * @rq_depth: rq depth266 * @sq_depth: sq depth267 *268 * Return 0 - Success, negative - Failure269 **/270static int set_hw_ioctxt(struct hinic_hwdev *hwdev, unsigned int sq_depth,271 unsigned int rq_depth)272{273 struct hinic_hwif *hwif = hwdev->hwif;274 struct hinic_cmd_hw_ioctxt hw_ioctxt;275 struct hinic_pfhwdev *pfhwdev;276 277 hw_ioctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif);278 hw_ioctxt.ppf_idx = HINIC_HWIF_PPF_IDX(hwif);279 280 hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_DEFAULT;281 hw_ioctxt.cmdq_depth = 0;282 283 hw_ioctxt.lro_en = 1;284 285 hw_ioctxt.rq_depth = ilog2(rq_depth);286 287 hw_ioctxt.rx_buf_sz_idx = HINIC_RX_BUF_SZ_IDX;288 289 hw_ioctxt.sq_depth = ilog2(sq_depth);290 291 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);292 293 return hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,294 HINIC_COMM_CMD_HWCTXT_SET,295 &hw_ioctxt, sizeof(hw_ioctxt), NULL,296 NULL, HINIC_MGMT_MSG_SYNC);297}298 299static int wait_for_outbound_state(struct hinic_hwdev *hwdev)300{301 enum hinic_outbound_state outbound_state;302 struct hinic_hwif *hwif = hwdev->hwif;303 struct pci_dev *pdev = hwif->pdev;304 unsigned long end;305 306 end = jiffies + msecs_to_jiffies(OUTBOUND_STATE_TIMEOUT);307 do {308 outbound_state = hinic_outbound_state_get(hwif);309 310 if (outbound_state == HINIC_OUTBOUND_ENABLE)311 return 0;312 313 msleep(20);314 } while (time_before(jiffies, end));315 316 dev_err(&pdev->dev, "Wait for OUTBOUND - Timeout\n");317 return -EFAULT;318}319 320static int wait_for_db_state(struct hinic_hwdev *hwdev)321{322 struct hinic_hwif *hwif = hwdev->hwif;323 struct pci_dev *pdev = hwif->pdev;324 enum hinic_db_state db_state;325 unsigned long end;326 327 end = jiffies + msecs_to_jiffies(DB_STATE_TIMEOUT);328 do {329 db_state = hinic_db_state_get(hwif);330 331 if (db_state == HINIC_DB_ENABLE)332 return 0;333 334 msleep(20);335 } while (time_before(jiffies, end));336 337 dev_err(&pdev->dev, "Wait for DB - Timeout\n");338 return -EFAULT;339}340 341/**342 * clear_io_resources - set the IO resources as not active in the NIC343 * @hwdev: the NIC HW device344 *345 * Return 0 - Success, negative - Failure346 **/347static int clear_io_resources(struct hinic_hwdev *hwdev)348{349 struct hinic_cmd_clear_io_res cmd_clear_io_res;350 struct hinic_hwif *hwif = hwdev->hwif;351 struct pci_dev *pdev = hwif->pdev;352 struct hinic_pfhwdev *pfhwdev;353 int err;354 355 /* sleep 100ms to wait for firmware stopping I/O */356 msleep(100);357 358 cmd_clear_io_res.func_idx = HINIC_HWIF_FUNC_IDX(hwif);359 360 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);361 362 err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,363 HINIC_COMM_CMD_IO_RES_CLEAR, &cmd_clear_io_res,364 sizeof(cmd_clear_io_res), NULL, NULL,365 HINIC_MGMT_MSG_SYNC);366 if (err) {367 dev_err(&pdev->dev, "Failed to clear IO resources\n");368 return err;369 }370 371 return 0;372}373 374/**375 * set_resources_state - set the state of the resources in the NIC376 * @hwdev: the NIC HW device377 * @state: the state to set378 *379 * Return 0 - Success, negative - Failure380 **/381static int set_resources_state(struct hinic_hwdev *hwdev,382 enum hinic_res_state state)383{384 struct hinic_cmd_set_res_state res_state;385 struct hinic_hwif *hwif = hwdev->hwif;386 struct hinic_pfhwdev *pfhwdev;387 388 res_state.func_idx = HINIC_HWIF_FUNC_IDX(hwif);389 res_state.state = state;390 391 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);392 393 return hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt,394 HINIC_MOD_COMM,395 HINIC_COMM_CMD_RES_STATE_SET,396 &res_state, sizeof(res_state), NULL,397 NULL, HINIC_MGMT_MSG_SYNC);398}399 400/**401 * get_base_qpn - get the first qp number402 * @hwdev: the NIC HW device403 * @base_qpn: returned qp number404 *405 * Return 0 - Success, negative - Failure406 **/407static int get_base_qpn(struct hinic_hwdev *hwdev, u16 *base_qpn)408{409 struct hinic_cmd_base_qpn cmd_base_qpn;410 struct hinic_hwif *hwif = hwdev->hwif;411 u16 out_size = sizeof(cmd_base_qpn);412 struct pci_dev *pdev = hwif->pdev;413 int err;414 415 cmd_base_qpn.func_idx = HINIC_HWIF_FUNC_IDX(hwif);416 417 err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_GLOBAL_QPN,418 &cmd_base_qpn, sizeof(cmd_base_qpn),419 &cmd_base_qpn, &out_size);420 if (err || out_size != sizeof(cmd_base_qpn) || cmd_base_qpn.status) {421 dev_err(&pdev->dev, "Failed to get base qpn, err: %d, status: 0x%x, out size: 0x%x\n",422 err, cmd_base_qpn.status, out_size);423 return -EIO;424 }425 426 *base_qpn = cmd_base_qpn.qpn;427 return 0;428}429 430/**431 * hinic_hwdev_ifup - Preparing the HW for passing IO432 * @hwdev: the NIC HW device433 * @sq_depth: the send queue depth434 * @rq_depth: the receive queue depth435 *436 * Return 0 - Success, negative - Failure437 **/438int hinic_hwdev_ifup(struct hinic_hwdev *hwdev, u16 sq_depth, u16 rq_depth)439{440 struct hinic_func_to_io *func_to_io = &hwdev->func_to_io;441 struct hinic_cap *nic_cap = &hwdev->nic_cap;442 struct hinic_hwif *hwif = hwdev->hwif;443 int err, num_aeqs, num_ceqs, num_qps;444 struct msix_entry *ceq_msix_entries;445 struct msix_entry *sq_msix_entries;446 struct msix_entry *rq_msix_entries;447 struct pci_dev *pdev = hwif->pdev;448 u16 base_qpn;449 450 err = get_base_qpn(hwdev, &base_qpn);451 if (err) {452 dev_err(&pdev->dev, "Failed to get global base qp number\n");453 return err;454 }455 456 num_aeqs = HINIC_HWIF_NUM_AEQS(hwif);457 num_ceqs = HINIC_HWIF_NUM_CEQS(hwif);458 459 ceq_msix_entries = &hwdev->msix_entries[num_aeqs];460 func_to_io->hwdev = hwdev;461 func_to_io->sq_depth = sq_depth;462 func_to_io->rq_depth = rq_depth;463 func_to_io->global_qpn = base_qpn;464 465 err = hinic_io_init(func_to_io, hwif, nic_cap->max_qps, num_ceqs,466 ceq_msix_entries);467 if (err) {468 dev_err(&pdev->dev, "Failed to init IO channel\n");469 return err;470 }471 472 num_qps = nic_cap->num_qps;473 sq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs];474 rq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs + num_qps];475 476 err = hinic_io_create_qps(func_to_io, base_qpn, num_qps,477 sq_msix_entries, rq_msix_entries);478 if (err) {479 dev_err(&pdev->dev, "Failed to create QPs\n");480 goto err_create_qps;481 }482 483 err = wait_for_db_state(hwdev);484 if (err) {485 dev_warn(&pdev->dev, "db - disabled, try again\n");486 hinic_db_state_set(hwif, HINIC_DB_ENABLE);487 }488 489 err = set_hw_ioctxt(hwdev, sq_depth, rq_depth);490 if (err) {491 dev_err(&pdev->dev, "Failed to set HW IO ctxt\n");492 goto err_hw_ioctxt;493 }494 495 return 0;496 497err_hw_ioctxt:498 hinic_io_destroy_qps(func_to_io, num_qps);499 500err_create_qps:501 hinic_io_free(func_to_io);502 return err;503}504 505/**506 * hinic_hwdev_ifdown - Closing the HW for passing IO507 * @hwdev: the NIC HW device508 *509 **/510void hinic_hwdev_ifdown(struct hinic_hwdev *hwdev)511{512 struct hinic_func_to_io *func_to_io = &hwdev->func_to_io;513 struct hinic_cap *nic_cap = &hwdev->nic_cap;514 515 clear_io_resources(hwdev);516 517 hinic_io_destroy_qps(func_to_io, nic_cap->num_qps);518 hinic_io_free(func_to_io);519}520 521/**522 * hinic_hwdev_cb_register - register callback handler for MGMT events523 * @hwdev: the NIC HW device524 * @cmd: the mgmt event525 * @handle: private data for the handler526 * @handler: event handler527 **/528void hinic_hwdev_cb_register(struct hinic_hwdev *hwdev,529 enum hinic_mgmt_msg_cmd cmd, void *handle,530 void (*handler)(void *handle, void *buf_in,531 u16 in_size, void *buf_out,532 u16 *out_size))533{534 struct hinic_pfhwdev *pfhwdev;535 struct hinic_nic_cb *nic_cb;536 u8 cmd_cb;537 538 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);539 540 cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE;541 nic_cb = &pfhwdev->nic_cb[cmd_cb];542 543 nic_cb->handler = handler;544 nic_cb->handle = handle;545 nic_cb->cb_state = HINIC_CB_ENABLED;546}547 548/**549 * hinic_hwdev_cb_unregister - unregister callback handler for MGMT events550 * @hwdev: the NIC HW device551 * @cmd: the mgmt event552 **/553void hinic_hwdev_cb_unregister(struct hinic_hwdev *hwdev,554 enum hinic_mgmt_msg_cmd cmd)555{556 struct hinic_hwif *hwif = hwdev->hwif;557 struct hinic_pfhwdev *pfhwdev;558 struct hinic_nic_cb *nic_cb;559 u8 cmd_cb;560 561 if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif))562 return;563 564 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);565 566 cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE;567 nic_cb = &pfhwdev->nic_cb[cmd_cb];568 569 nic_cb->cb_state &= ~HINIC_CB_ENABLED;570 571 while (nic_cb->cb_state & HINIC_CB_RUNNING)572 schedule();573 574 nic_cb->handler = NULL;575}576 577/**578 * nic_mgmt_msg_handler - nic mgmt event handler579 * @handle: private data for the handler580 * @cmd: message command581 * @buf_in: input buffer582 * @in_size: input size583 * @buf_out: output buffer584 * @out_size: returned output size585 **/586static void nic_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in,587 u16 in_size, void *buf_out, u16 *out_size)588{589 struct hinic_pfhwdev *pfhwdev = handle;590 enum hinic_cb_state cb_state;591 struct hinic_nic_cb *nic_cb;592 struct hinic_hwdev *hwdev;593 struct hinic_hwif *hwif;594 struct pci_dev *pdev;595 u8 cmd_cb;596 597 hwdev = &pfhwdev->hwdev;598 hwif = hwdev->hwif;599 pdev = hwif->pdev;600 601 if (cmd < HINIC_MGMT_MSG_CMD_BASE ||602 cmd >= HINIC_MGMT_MSG_CMD_MAX) {603 dev_err(&pdev->dev, "unknown L2NIC event, cmd = %d\n", cmd);604 return;605 }606 607 cmd_cb = cmd - HINIC_MGMT_MSG_CMD_BASE;608 609 nic_cb = &pfhwdev->nic_cb[cmd_cb];610 611 cb_state = cmpxchg(&nic_cb->cb_state,612 HINIC_CB_ENABLED,613 HINIC_CB_ENABLED | HINIC_CB_RUNNING);614 615 if (cb_state == HINIC_CB_ENABLED && nic_cb->handler)616 nic_cb->handler(nic_cb->handle, buf_in,617 in_size, buf_out, out_size);618 else619 dev_err(&pdev->dev, "Unhandled NIC Event %d\n", cmd);620 621 nic_cb->cb_state &= ~HINIC_CB_RUNNING;622}623 624static void hinic_comm_recv_mgmt_self_cmd_reg(struct hinic_pfhwdev *pfhwdev,625 u8 cmd,626 comm_mgmt_self_msg_proc proc)627{628 u8 cmd_idx;629 630 cmd_idx = pfhwdev->proc.cmd_num;631 if (cmd_idx >= HINIC_COMM_SELF_CMD_MAX) {632 dev_err(&pfhwdev->hwdev.hwif->pdev->dev,633 "Register recv mgmt process failed, cmd: 0x%x\n", cmd);634 return;635 }636 637 pfhwdev->proc.info[cmd_idx].cmd = cmd;638 pfhwdev->proc.info[cmd_idx].proc = proc;639 pfhwdev->proc.cmd_num++;640}641 642static void hinic_comm_recv_mgmt_self_cmd_unreg(struct hinic_pfhwdev *pfhwdev,643 u8 cmd)644{645 u8 cmd_idx;646 647 cmd_idx = pfhwdev->proc.cmd_num;648 if (cmd_idx >= HINIC_COMM_SELF_CMD_MAX) {649 dev_err(&pfhwdev->hwdev.hwif->pdev->dev, "Unregister recv mgmt process failed, cmd: 0x%x\n",650 cmd);651 return;652 }653 654 for (cmd_idx = 0; cmd_idx < HINIC_COMM_SELF_CMD_MAX; cmd_idx++) {655 if (cmd == pfhwdev->proc.info[cmd_idx].cmd) {656 pfhwdev->proc.info[cmd_idx].cmd = 0;657 pfhwdev->proc.info[cmd_idx].proc = NULL;658 pfhwdev->proc.cmd_num--;659 }660 }661}662 663static void comm_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in,664 u16 in_size, void *buf_out, u16 *out_size)665{666 struct hinic_pfhwdev *pfhwdev = handle;667 u8 cmd_idx;668 669 for (cmd_idx = 0; cmd_idx < pfhwdev->proc.cmd_num; cmd_idx++) {670 if (cmd == pfhwdev->proc.info[cmd_idx].cmd) {671 if (!pfhwdev->proc.info[cmd_idx].proc) {672 dev_warn(&pfhwdev->hwdev.hwif->pdev->dev,673 "PF recv mgmt comm msg handle null, cmd: 0x%x\n",674 cmd);675 } else {676 pfhwdev->proc.info[cmd_idx].proc677 (&pfhwdev->hwdev, buf_in, in_size,678 buf_out, out_size);679 }680 681 return;682 }683 }684 685 dev_warn(&pfhwdev->hwdev.hwif->pdev->dev, "Received unknown mgmt cpu event: 0x%x\n",686 cmd);687 688 *out_size = 0;689}690 691/* pf fault report event */692static void pf_fault_event_handler(void *dev, void *buf_in, u16 in_size,693 void *buf_out, u16 *out_size)694{695 struct hinic_cmd_fault_event *fault_event = buf_in;696 struct hinic_hwdev *hwdev = dev;697 698 if (in_size != sizeof(*fault_event)) {699 dev_err(&hwdev->hwif->pdev->dev, "Invalid fault event report, length: %d, should be %zu\n",700 in_size, sizeof(*fault_event));701 return;702 }703 704 if (!hwdev->devlink_dev || IS_ERR_OR_NULL(hwdev->devlink_dev->hw_fault_reporter))705 return;706 707 devlink_health_report(hwdev->devlink_dev->hw_fault_reporter,708 "HW fatal error reported", &fault_event->event);709}710 711static void mgmt_watchdog_timeout_event_handler(void *dev,712 void *buf_in, u16 in_size,713 void *buf_out, u16 *out_size)714{715 struct hinic_mgmt_watchdog_info *watchdog_info = buf_in;716 struct hinic_hwdev *hwdev = dev;717 718 if (in_size != sizeof(*watchdog_info)) {719 dev_err(&hwdev->hwif->pdev->dev, "Invalid mgmt watchdog report, length: %d, should be %zu\n",720 in_size, sizeof(*watchdog_info));721 return;722 }723 724 if (!hwdev->devlink_dev || IS_ERR_OR_NULL(hwdev->devlink_dev->fw_fault_reporter))725 return;726 727 devlink_health_report(hwdev->devlink_dev->fw_fault_reporter,728 "FW fatal error reported", watchdog_info);729}730 731/**732 * init_pfhwdev - Initialize the extended components of PF733 * @pfhwdev: the HW device for PF734 *735 * Return 0 - success, negative - failure736 **/737static int init_pfhwdev(struct hinic_pfhwdev *pfhwdev)738{739 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;740 struct hinic_hwif *hwif = hwdev->hwif;741 struct pci_dev *pdev = hwif->pdev;742 int err;743 744 err = hinic_pf_to_mgmt_init(&pfhwdev->pf_to_mgmt, hwif);745 if (err) {746 dev_err(&pdev->dev, "Failed to initialize PF to MGMT channel\n");747 return err;748 }749 750 err = hinic_func_to_func_init(hwdev);751 if (err) {752 dev_err(&hwif->pdev->dev, "Failed to init mailbox\n");753 hinic_pf_to_mgmt_free(&pfhwdev->pf_to_mgmt);754 return err;755 }756 757 if (!HINIC_IS_VF(hwif)) {758 hinic_register_mgmt_msg_cb(&pfhwdev->pf_to_mgmt,759 HINIC_MOD_L2NIC, pfhwdev,760 nic_mgmt_msg_handler);761 hinic_register_mgmt_msg_cb(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,762 pfhwdev, comm_mgmt_msg_handler);763 hinic_comm_recv_mgmt_self_cmd_reg(pfhwdev,764 HINIC_COMM_CMD_FAULT_REPORT,765 pf_fault_event_handler);766 hinic_comm_recv_mgmt_self_cmd_reg767 (pfhwdev, HINIC_COMM_CMD_WATCHDOG_INFO,768 mgmt_watchdog_timeout_event_handler);769 } else {770 hinic_register_vf_mbox_cb(hwdev, HINIC_MOD_L2NIC,771 nic_mgmt_msg_handler);772 }773 774 hinic_set_pf_action(hwif, HINIC_PF_MGMT_ACTIVE);775 hinic_devlink_register(hwdev->devlink_dev);776 return 0;777}778 779/**780 * free_pfhwdev - Free the extended components of PF781 * @pfhwdev: the HW device for PF782 **/783static void free_pfhwdev(struct hinic_pfhwdev *pfhwdev)784{785 struct hinic_hwdev *hwdev = &pfhwdev->hwdev;786 787 hinic_devlink_unregister(hwdev->devlink_dev);788 hinic_set_pf_action(hwdev->hwif, HINIC_PF_MGMT_INIT);789 790 if (!HINIC_IS_VF(hwdev->hwif)) {791 hinic_comm_recv_mgmt_self_cmd_unreg(pfhwdev,792 HINIC_COMM_CMD_WATCHDOG_INFO);793 hinic_comm_recv_mgmt_self_cmd_unreg(pfhwdev,794 HINIC_COMM_CMD_FAULT_REPORT);795 hinic_unregister_mgmt_msg_cb(&pfhwdev->pf_to_mgmt,796 HINIC_MOD_COMM);797 hinic_unregister_mgmt_msg_cb(&pfhwdev->pf_to_mgmt,798 HINIC_MOD_L2NIC);799 } else {800 hinic_unregister_vf_mbox_cb(hwdev, HINIC_MOD_L2NIC);801 }802 803 hinic_func_to_func_free(hwdev);804 805 hinic_pf_to_mgmt_free(&pfhwdev->pf_to_mgmt);806}807 808static int hinic_l2nic_reset(struct hinic_hwdev *hwdev)809{810 struct hinic_cmd_l2nic_reset l2nic_reset = {0};811 u16 out_size = sizeof(l2nic_reset);812 struct hinic_pfhwdev *pfhwdev;813 int err;814 815 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);816 817 l2nic_reset.func_id = HINIC_HWIF_FUNC_IDX(hwdev->hwif);818 /* 0 represents standard l2nic reset flow */819 l2nic_reset.reset_flag = 0;820 821 err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,822 HINIC_COMM_CMD_L2NIC_RESET, &l2nic_reset,823 sizeof(l2nic_reset), &l2nic_reset,824 &out_size, HINIC_MGMT_MSG_SYNC);825 if (err || !out_size || l2nic_reset.status) {826 dev_err(&hwdev->hwif->pdev->dev, "Failed to reset L2NIC resources, err: %d, status: 0x%x, out_size: 0x%x\n",827 err, l2nic_reset.status, out_size);828 return -EIO;829 }830 831 return 0;832}833 834static int hinic_get_interrupt_cfg(struct hinic_hwdev *hwdev,835 struct hinic_msix_config *interrupt_info)836{837 u16 out_size = sizeof(*interrupt_info);838 struct hinic_pfhwdev *pfhwdev;839 int err;840 841 if (!hwdev || !interrupt_info)842 return -EINVAL;843 844 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);845 846 interrupt_info->func_id = HINIC_HWIF_FUNC_IDX(hwdev->hwif);847 848 err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,849 HINIC_COMM_CMD_MSI_CTRL_REG_RD_BY_UP,850 interrupt_info, sizeof(*interrupt_info),851 interrupt_info, &out_size, HINIC_MGMT_MSG_SYNC);852 if (err || !out_size || interrupt_info->status) {853 dev_err(&hwdev->hwif->pdev->dev, "Failed to get interrupt config, err: %d, status: 0x%x, out size: 0x%x\n",854 err, interrupt_info->status, out_size);855 return -EIO;856 }857 858 return 0;859}860 861int hinic_set_interrupt_cfg(struct hinic_hwdev *hwdev,862 struct hinic_msix_config *interrupt_info)863{864 u16 out_size = sizeof(*interrupt_info);865 struct hinic_msix_config temp_info;866 struct hinic_pfhwdev *pfhwdev;867 int err;868 869 if (!hwdev)870 return -EINVAL;871 872 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);873 874 interrupt_info->func_id = HINIC_HWIF_FUNC_IDX(hwdev->hwif);875 876 err = hinic_get_interrupt_cfg(hwdev, &temp_info);877 if (err)878 return -EINVAL;879 880 interrupt_info->lli_credit_cnt = temp_info.lli_credit_cnt;881 interrupt_info->lli_timer_cnt = temp_info.lli_timer_cnt;882 883 err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,884 HINIC_COMM_CMD_MSI_CTRL_REG_WR_BY_UP,885 interrupt_info, sizeof(*interrupt_info),886 interrupt_info, &out_size, HINIC_MGMT_MSG_SYNC);887 if (err || !out_size || interrupt_info->status) {888 dev_err(&hwdev->hwif->pdev->dev, "Failed to get interrupt config, err: %d, status: 0x%x, out size: 0x%x\n",889 err, interrupt_info->status, out_size);890 return -EIO;891 }892 893 return 0;894}895 896/**897 * hinic_init_hwdev - Initialize the NIC HW898 * @pdev: the NIC pci device899 * @devlink: the poniter of hinic devlink900 *901 * Return initialized NIC HW device902 *903 * Initialize the NIC HW device and return a pointer to it904 **/905struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev, struct devlink *devlink)906{907 struct hinic_pfhwdev *pfhwdev;908 struct hinic_hwdev *hwdev;909 struct hinic_hwif *hwif;910 int err, num_aeqs;911 912 hwif = devm_kzalloc(&pdev->dev, sizeof(*hwif), GFP_KERNEL);913 if (!hwif)914 return ERR_PTR(-ENOMEM);915 916 err = hinic_init_hwif(hwif, pdev);917 if (err) {918 dev_err(&pdev->dev, "Failed to init HW interface\n");919 return ERR_PTR(err);920 }921 922 pfhwdev = devm_kzalloc(&pdev->dev, sizeof(*pfhwdev), GFP_KERNEL);923 if (!pfhwdev) {924 err = -ENOMEM;925 goto err_pfhwdev_alloc;926 }927 928 hwdev = &pfhwdev->hwdev;929 hwdev->hwif = hwif;930 hwdev->devlink_dev = devlink_priv(devlink);931 hwdev->devlink_dev->hwdev = hwdev;932 933 err = init_msix(hwdev);934 if (err) {935 dev_err(&pdev->dev, "Failed to init msix\n");936 goto err_init_msix;937 }938 939 err = wait_for_outbound_state(hwdev);940 if (err) {941 dev_warn(&pdev->dev, "outbound - disabled, try again\n");942 hinic_outbound_state_set(hwif, HINIC_OUTBOUND_ENABLE);943 }944 945 num_aeqs = HINIC_HWIF_NUM_AEQS(hwif);946 947 err = hinic_aeqs_init(&hwdev->aeqs, hwif, num_aeqs,948 HINIC_DEFAULT_AEQ_LEN, HINIC_EQ_PAGE_SIZE,949 hwdev->msix_entries);950 if (err) {951 dev_err(&pdev->dev, "Failed to init async event queues\n");952 goto err_aeqs_init;953 }954 955 err = init_pfhwdev(pfhwdev);956 if (err) {957 dev_err(&pdev->dev, "Failed to init PF HW device\n");958 goto err_init_pfhwdev;959 }960 961 err = hinic_l2nic_reset(hwdev);962 if (err)963 goto err_l2nic_reset;964 965 err = get_dev_cap(hwdev);966 if (err) {967 dev_err(&pdev->dev, "Failed to get device capabilities\n");968 goto err_dev_cap;969 }970 971 mutex_init(&hwdev->func_to_io.nic_cfg.cfg_mutex);972 973 err = hinic_vf_func_init(hwdev);974 if (err) {975 dev_err(&pdev->dev, "Failed to init nic mbox\n");976 goto err_vf_func_init;977 }978 979 err = init_fw_ctxt(hwdev);980 if (err) {981 dev_err(&pdev->dev, "Failed to init function table\n");982 goto err_init_fw_ctxt;983 }984 985 err = set_resources_state(hwdev, HINIC_RES_ACTIVE);986 if (err) {987 dev_err(&pdev->dev, "Failed to set resources state\n");988 goto err_resources_state;989 }990 991 return hwdev;992 993err_resources_state:994err_init_fw_ctxt:995 hinic_vf_func_free(hwdev);996err_vf_func_init:997err_l2nic_reset:998err_dev_cap:999 free_pfhwdev(pfhwdev);1000 1001err_init_pfhwdev:1002 hinic_aeqs_free(&hwdev->aeqs);1003 1004err_aeqs_init:1005 disable_msix(hwdev);1006 1007err_init_msix:1008err_pfhwdev_alloc:1009 hinic_free_hwif(hwif);1010 if (err > 0)1011 err = -EIO;1012 return ERR_PTR(err);1013}1014 1015/**1016 * hinic_free_hwdev - Free the NIC HW device1017 * @hwdev: the NIC HW device1018 **/1019void hinic_free_hwdev(struct hinic_hwdev *hwdev)1020{1021 struct hinic_pfhwdev *pfhwdev = container_of(hwdev,1022 struct hinic_pfhwdev,1023 hwdev);1024 1025 set_resources_state(hwdev, HINIC_RES_CLEAN);1026 1027 hinic_vf_func_free(hwdev);1028 1029 free_pfhwdev(pfhwdev);1030 1031 hinic_aeqs_free(&hwdev->aeqs);1032 1033 disable_msix(hwdev);1034 1035 hinic_free_hwif(hwdev->hwif);1036}1037 1038/**1039 * hinic_hwdev_num_qps - return the number QPs available for use1040 * @hwdev: the NIC HW device1041 *1042 * Return number QPs available for use1043 **/1044int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev)1045{1046 struct hinic_cap *nic_cap = &hwdev->nic_cap;1047 1048 return nic_cap->num_qps;1049}1050 1051/**1052 * hinic_hwdev_get_sq - get SQ1053 * @hwdev: the NIC HW device1054 * @i: the position of the SQ1055 *1056 * Return: the SQ in the i position1057 **/1058struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i)1059{1060 struct hinic_func_to_io *func_to_io = &hwdev->func_to_io;1061 struct hinic_qp *qp = &func_to_io->qps[i];1062 1063 if (i >= hinic_hwdev_num_qps(hwdev))1064 return NULL;1065 1066 return &qp->sq;1067}1068 1069/**1070 * hinic_hwdev_get_rq - get RQ1071 * @hwdev: the NIC HW device1072 * @i: the position of the RQ1073 *1074 * Return: the RQ in the i position1075 **/1076struct hinic_rq *hinic_hwdev_get_rq(struct hinic_hwdev *hwdev, int i)1077{1078 struct hinic_func_to_io *func_to_io = &hwdev->func_to_io;1079 struct hinic_qp *qp = &func_to_io->qps[i];1080 1081 if (i >= hinic_hwdev_num_qps(hwdev))1082 return NULL;1083 1084 return &qp->rq;1085}1086 1087/**1088 * hinic_hwdev_msix_cnt_set - clear message attribute counters for msix entry1089 * @hwdev: the NIC HW device1090 * @msix_index: msix_index1091 *1092 * Return 0 - Success, negative - Failure1093 **/1094int hinic_hwdev_msix_cnt_set(struct hinic_hwdev *hwdev, u16 msix_index)1095{1096 return hinic_msix_attr_cnt_clear(hwdev->hwif, msix_index);1097}1098 1099/**1100 * hinic_hwdev_msix_set - set message attribute for msix entry1101 * @hwdev: the NIC HW device1102 * @msix_index: msix_index1103 * @pending_limit: the maximum pending interrupt events (unit 8)1104 * @coalesc_timer: coalesc period for interrupt (unit 8 us)1105 * @lli_timer_cfg: replenishing period for low latency credit (unit 8 us)1106 * @lli_credit_limit: maximum credits for low latency msix messages (unit 8)1107 * @resend_timer: maximum wait for resending msix (unit coalesc period)1108 *1109 * Return 0 - Success, negative - Failure1110 **/1111int hinic_hwdev_msix_set(struct hinic_hwdev *hwdev, u16 msix_index,1112 u8 pending_limit, u8 coalesc_timer,1113 u8 lli_timer_cfg, u8 lli_credit_limit,1114 u8 resend_timer)1115{1116 return hinic_msix_attr_set(hwdev->hwif, msix_index,1117 pending_limit, coalesc_timer,1118 lli_timer_cfg, lli_credit_limit,1119 resend_timer);1120}1121 1122/**1123 * hinic_hwdev_hw_ci_addr_set - set cons idx addr and attributes in HW for sq1124 * @hwdev: the NIC HW device1125 * @sq: send queue1126 * @pending_limit: the maximum pending update ci events (unit 8)1127 * @coalesc_timer: coalesc period for update ci (unit 8 us)1128 *1129 * Return 0 - Success, negative - Failure1130 **/1131int hinic_hwdev_hw_ci_addr_set(struct hinic_hwdev *hwdev, struct hinic_sq *sq,1132 u8 pending_limit, u8 coalesc_timer)1133{1134 struct hinic_qp *qp = container_of(sq, struct hinic_qp, sq);1135 struct hinic_hwif *hwif = hwdev->hwif;1136 struct hinic_pfhwdev *pfhwdev;1137 struct hinic_cmd_hw_ci hw_ci;1138 1139 hw_ci.dma_attr_off = 0;1140 hw_ci.pending_limit = pending_limit;1141 hw_ci.coalesc_timer = coalesc_timer;1142 1143 hw_ci.msix_en = 1;1144 hw_ci.msix_entry_idx = sq->msix_entry;1145 1146 hw_ci.func_idx = HINIC_HWIF_FUNC_IDX(hwif);1147 1148 hw_ci.sq_id = qp->q_id;1149 1150 hw_ci.ci_addr = ADDR_IN_4BYTES(sq->hw_ci_dma_addr);1151 1152 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);1153 return hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt,1154 HINIC_MOD_COMM,1155 HINIC_COMM_CMD_SQ_HI_CI_SET,1156 &hw_ci, sizeof(hw_ci), NULL,1157 NULL, HINIC_MGMT_MSG_SYNC);1158}1159 1160/**1161 * hinic_hwdev_set_msix_state- set msix state1162 * @hwdev: the NIC HW device1163 * @msix_index: IRQ corresponding index number1164 * @flag: msix state1165 *1166 **/1167void hinic_hwdev_set_msix_state(struct hinic_hwdev *hwdev, u16 msix_index,1168 enum hinic_msix_state flag)1169{1170 hinic_set_msix_state(hwdev->hwif, msix_index, flag);1171}1172 1173int hinic_get_board_info(struct hinic_hwdev *hwdev,1174 struct hinic_comm_board_info *board_info)1175{1176 u16 out_size = sizeof(*board_info);1177 struct hinic_pfhwdev *pfhwdev;1178 int err;1179 1180 if (!hwdev || !board_info)1181 return -EINVAL;1182 1183 pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);1184 1185 err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,1186 HINIC_COMM_CMD_GET_BOARD_INFO,1187 board_info, sizeof(*board_info),1188 board_info, &out_size, HINIC_MGMT_MSG_SYNC);1189 if (err || board_info->status || !out_size) {1190 dev_err(&hwdev->hwif->pdev->dev,1191 "Failed to get board info, err: %d, status: 0x%x, out size: 0x%x\n",1192 err, board_info->status, out_size);1193 return -EIO;1194 }1195 1196 return 0;1197}1198