Loading drivers/net/ethernet/huawei/hinic/Makefile +3 −2 Original line number Diff line number Diff line obj-$(CONFIG_HINIC) += hinic.o hinic-y := hinic_main.o hinic_port.o hinic_hw_dev.o hinic_hw_mgmt.o \ hinic_hw_api_cmd.o hinic_hw_eqs.o hinic_hw_if.o hinic-y := hinic_main.o hinic_tx.o hinic_rx.o hinic_port.o hinic_hw_dev.o \ hinic_hw_io.o hinic_hw_mgmt.o hinic_hw_api_cmd.o hinic_hw_eqs.o \ hinic_hw_if.o drivers/net/ethernet/huawei/hinic/hinic_dev.h +5 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <linux/bitops.h> #include "hinic_hw_dev.h" #include "hinic_tx.h" #include "hinic_rx.h" #define HINIC_DRV_NAME "hinic" Loading @@ -49,6 +51,9 @@ struct hinic_dev { struct hinic_rx_mode_work rx_mode_work; struct workqueue_struct *workq; struct hinic_txq *txqs; struct hinic_rxq *rxqs; }; #endif drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c +131 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #include "hinic_hw_if.h" #include "hinic_hw_eqs.h" #include "hinic_hw_mgmt.h" #include "hinic_hw_qp.h" #include "hinic_hw_io.h" #include "hinic_hw_dev.h" #define MAX_IRQS(max_qps, num_aeqs, num_ceqs) \ Loading Loading @@ -229,6 +231,99 @@ int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd, HINIC_MGMT_MSG_SYNC); } /** * get_base_qpn - get the first qp number * @hwdev: the NIC HW device * @base_qpn: returned qp number * * Return 0 - Success, negative - Failure **/ static int get_base_qpn(struct hinic_hwdev *hwdev, u16 *base_qpn) { struct hinic_cmd_base_qpn cmd_base_qpn; struct hinic_hwif *hwif = hwdev->hwif; struct pci_dev *pdev = hwif->pdev; u16 out_size; int err; cmd_base_qpn.func_idx = HINIC_HWIF_FUNC_IDX(hwif); err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_GLOBAL_QPN, &cmd_base_qpn, sizeof(cmd_base_qpn), &cmd_base_qpn, &out_size); if (err || (out_size != sizeof(cmd_base_qpn)) || cmd_base_qpn.status) { dev_err(&pdev->dev, "Failed to get base qpn, status = %d\n", cmd_base_qpn.status); return -EFAULT; } *base_qpn = cmd_base_qpn.qpn; return 0; } /** * hinic_hwdev_ifup - Preparing the HW for passing IO * @hwdev: the NIC HW device * * Return 0 - Success, negative - Failure **/ int hinic_hwdev_ifup(struct hinic_hwdev *hwdev) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_cap *nic_cap = &hwdev->nic_cap; struct hinic_hwif *hwif = hwdev->hwif; int err, num_aeqs, num_ceqs, num_qps; struct msix_entry *sq_msix_entries; struct msix_entry *rq_msix_entries; struct pci_dev *pdev = hwif->pdev; u16 base_qpn; err = get_base_qpn(hwdev, &base_qpn); if (err) { dev_err(&pdev->dev, "Failed to get global base qp number\n"); return err; } num_aeqs = HINIC_HWIF_NUM_AEQS(hwif); num_ceqs = HINIC_HWIF_NUM_CEQS(hwif); err = hinic_io_init(func_to_io, hwif, nic_cap->max_qps, 0, NULL); if (err) { dev_err(&pdev->dev, "Failed to init IO channel\n"); return err; } num_qps = nic_cap->num_qps; sq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs]; rq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs + num_qps]; err = hinic_io_create_qps(func_to_io, base_qpn, num_qps, sq_msix_entries, rq_msix_entries); if (err) { dev_err(&pdev->dev, "Failed to create QPs\n"); goto err_create_qps; } return 0; err_create_qps: hinic_io_free(func_to_io); return err; } /** * hinic_hwdev_ifdown - Closing the HW for passing IO * @hwdev: the NIC HW device * **/ void hinic_hwdev_ifdown(struct hinic_hwdev *hwdev) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_cap *nic_cap = &hwdev->nic_cap; hinic_io_destroy_qps(func_to_io, nic_cap->num_qps); hinic_io_free(func_to_io); } /** * hinic_hwdev_cb_register - register callback handler for MGMT events * @hwdev: the NIC HW device Loading Loading @@ -499,3 +594,39 @@ int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev) return nic_cap->num_qps; } /** * hinic_hwdev_get_sq - get SQ * @hwdev: the NIC HW device * @i: the position of the SQ * * Return: the SQ in the i position **/ struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_qp *qp = &func_to_io->qps[i]; if (i >= hinic_hwdev_num_qps(hwdev)) return NULL; return &qp->sq; } /** * hinic_hwdev_get_sq - get RQ * @hwdev: the NIC HW device * @i: the position of the RQ * * Return: the RQ in the i position **/ struct hinic_rq *hinic_hwdev_get_rq(struct hinic_hwdev *hwdev, int i) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_qp *qp = &func_to_io->qps[i]; if (i >= hinic_hwdev_num_qps(hwdev)) return NULL; return &qp->rq; } drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h +20 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "hinic_hw_if.h" #include "hinic_hw_eqs.h" #include "hinic_hw_mgmt.h" #include "hinic_hw_qp.h" #include "hinic_hw_io.h" #define HINIC_MAX_QPS 32 Loading Loading @@ -72,11 +74,21 @@ enum hinic_cb_state { HINIC_CB_RUNNING = BIT(1), }; struct hinic_cmd_base_qpn { u8 status; u8 version; u8 rsvd0[6]; u16 func_idx; u16 qpn; }; struct hinic_hwdev { struct hinic_hwif *hwif; struct msix_entry *msix_entries; struct hinic_aeqs aeqs; struct hinic_func_to_io func_to_io; struct hinic_cap nic_cap; }; Loading Loading @@ -111,10 +123,18 @@ int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size); int hinic_hwdev_ifup(struct hinic_hwdev *hwdev); void hinic_hwdev_ifdown(struct hinic_hwdev *hwdev); struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev); void hinic_free_hwdev(struct hinic_hwdev *hwdev); int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev); struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i); struct hinic_rq *hinic_hwdev_get_rq(struct hinic_hwdev *hwdev, int i); #endif drivers/net/ethernet/huawei/hinic/hinic_hw_io.c 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Huawei HiNIC PCI Express Linux driver * Copyright(c) 2017 Huawei Technologies Co., Ltd * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * */ #include <linux/types.h> #include <linux/pci.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/slab.h> #include "hinic_hw_if.h" #include "hinic_hw_qp.h" #include "hinic_hw_io.h" /** * init_qp - Initialize a Queue Pair * @func_to_io: func to io channel that holds the IO components * @qp: pointer to the qp to initialize * @q_id: the id of the qp * @sq_msix_entry: msix entry for sq * @rq_msix_entry: msix entry for rq * * Return 0 - Success, negative - Failure **/ static int init_qp(struct hinic_func_to_io *func_to_io, struct hinic_qp *qp, int q_id, struct msix_entry *sq_msix_entry, struct msix_entry *rq_msix_entry) { /* should be implemented */ return 0; } /** * destroy_qp - Clean the resources of a Queue Pair * @func_to_io: func to io channel that holds the IO components * @qp: pointer to the qp to clean **/ static void destroy_qp(struct hinic_func_to_io *func_to_io, struct hinic_qp *qp) { /* should be implemented */ } /** * hinic_io_create_qps - Create Queue Pairs * @func_to_io: func to io channel that holds the IO components * @base_qpn: base qp number * @num_qps: number queue pairs to create * @sq_msix_entry: msix entries for sq * @rq_msix_entry: msix entries for rq * * Return 0 - Success, negative - Failure **/ int hinic_io_create_qps(struct hinic_func_to_io *func_to_io, u16 base_qpn, int num_qps, struct msix_entry *sq_msix_entries, struct msix_entry *rq_msix_entries) { struct hinic_hwif *hwif = func_to_io->hwif; struct pci_dev *pdev = hwif->pdev; size_t qps_size; int i, j, err; qps_size = num_qps * sizeof(*func_to_io->qps); func_to_io->qps = devm_kzalloc(&pdev->dev, qps_size, GFP_KERNEL); if (!func_to_io->qps) return -ENOMEM; for (i = 0; i < num_qps; i++) { err = init_qp(func_to_io, &func_to_io->qps[i], i, &sq_msix_entries[i], &rq_msix_entries[i]); if (err) { dev_err(&pdev->dev, "Failed to create QP %d\n", i); goto err_init_qp; } } return 0; err_init_qp: for (j = 0; j < i; j++) destroy_qp(func_to_io, &func_to_io->qps[j]); devm_kfree(&pdev->dev, func_to_io->qps); return err; } /** * hinic_io_destroy_qps - Destroy the IO Queue Pairs * @func_to_io: func to io channel that holds the IO components * @num_qps: number queue pairs to destroy **/ void hinic_io_destroy_qps(struct hinic_func_to_io *func_to_io, int num_qps) { struct hinic_hwif *hwif = func_to_io->hwif; struct pci_dev *pdev = hwif->pdev; int i; for (i = 0; i < num_qps; i++) destroy_qp(func_to_io, &func_to_io->qps[i]); devm_kfree(&pdev->dev, func_to_io->qps); } /** * hinic_io_init - Initialize the IO components * @func_to_io: func to io channel that holds the IO components * @hwif: HW interface for accessing IO * @max_qps: maximum QPs in HW * @num_ceqs: number completion event queues * @ceq_msix_entries: msix entries for ceqs * * Return 0 - Success, negative - Failure **/ int hinic_io_init(struct hinic_func_to_io *func_to_io, struct hinic_hwif *hwif, u16 max_qps, int num_ceqs, struct msix_entry *ceq_msix_entries) { func_to_io->hwif = hwif; func_to_io->qps = NULL; func_to_io->max_qps = max_qps; return 0; } /** * hinic_io_free - Free the IO components * @func_to_io: func to io channel that holds the IO components **/ void hinic_io_free(struct hinic_func_to_io *func_to_io) { } Loading
drivers/net/ethernet/huawei/hinic/Makefile +3 −2 Original line number Diff line number Diff line obj-$(CONFIG_HINIC) += hinic.o hinic-y := hinic_main.o hinic_port.o hinic_hw_dev.o hinic_hw_mgmt.o \ hinic_hw_api_cmd.o hinic_hw_eqs.o hinic_hw_if.o hinic-y := hinic_main.o hinic_tx.o hinic_rx.o hinic_port.o hinic_hw_dev.o \ hinic_hw_io.o hinic_hw_mgmt.o hinic_hw_api_cmd.o hinic_hw_eqs.o \ hinic_hw_if.o
drivers/net/ethernet/huawei/hinic/hinic_dev.h +5 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <linux/bitops.h> #include "hinic_hw_dev.h" #include "hinic_tx.h" #include "hinic_rx.h" #define HINIC_DRV_NAME "hinic" Loading @@ -49,6 +51,9 @@ struct hinic_dev { struct hinic_rx_mode_work rx_mode_work; struct workqueue_struct *workq; struct hinic_txq *txqs; struct hinic_rxq *rxqs; }; #endif
drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c +131 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #include "hinic_hw_if.h" #include "hinic_hw_eqs.h" #include "hinic_hw_mgmt.h" #include "hinic_hw_qp.h" #include "hinic_hw_io.h" #include "hinic_hw_dev.h" #define MAX_IRQS(max_qps, num_aeqs, num_ceqs) \ Loading Loading @@ -229,6 +231,99 @@ int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd, HINIC_MGMT_MSG_SYNC); } /** * get_base_qpn - get the first qp number * @hwdev: the NIC HW device * @base_qpn: returned qp number * * Return 0 - Success, negative - Failure **/ static int get_base_qpn(struct hinic_hwdev *hwdev, u16 *base_qpn) { struct hinic_cmd_base_qpn cmd_base_qpn; struct hinic_hwif *hwif = hwdev->hwif; struct pci_dev *pdev = hwif->pdev; u16 out_size; int err; cmd_base_qpn.func_idx = HINIC_HWIF_FUNC_IDX(hwif); err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_GLOBAL_QPN, &cmd_base_qpn, sizeof(cmd_base_qpn), &cmd_base_qpn, &out_size); if (err || (out_size != sizeof(cmd_base_qpn)) || cmd_base_qpn.status) { dev_err(&pdev->dev, "Failed to get base qpn, status = %d\n", cmd_base_qpn.status); return -EFAULT; } *base_qpn = cmd_base_qpn.qpn; return 0; } /** * hinic_hwdev_ifup - Preparing the HW for passing IO * @hwdev: the NIC HW device * * Return 0 - Success, negative - Failure **/ int hinic_hwdev_ifup(struct hinic_hwdev *hwdev) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_cap *nic_cap = &hwdev->nic_cap; struct hinic_hwif *hwif = hwdev->hwif; int err, num_aeqs, num_ceqs, num_qps; struct msix_entry *sq_msix_entries; struct msix_entry *rq_msix_entries; struct pci_dev *pdev = hwif->pdev; u16 base_qpn; err = get_base_qpn(hwdev, &base_qpn); if (err) { dev_err(&pdev->dev, "Failed to get global base qp number\n"); return err; } num_aeqs = HINIC_HWIF_NUM_AEQS(hwif); num_ceqs = HINIC_HWIF_NUM_CEQS(hwif); err = hinic_io_init(func_to_io, hwif, nic_cap->max_qps, 0, NULL); if (err) { dev_err(&pdev->dev, "Failed to init IO channel\n"); return err; } num_qps = nic_cap->num_qps; sq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs]; rq_msix_entries = &hwdev->msix_entries[num_aeqs + num_ceqs + num_qps]; err = hinic_io_create_qps(func_to_io, base_qpn, num_qps, sq_msix_entries, rq_msix_entries); if (err) { dev_err(&pdev->dev, "Failed to create QPs\n"); goto err_create_qps; } return 0; err_create_qps: hinic_io_free(func_to_io); return err; } /** * hinic_hwdev_ifdown - Closing the HW for passing IO * @hwdev: the NIC HW device * **/ void hinic_hwdev_ifdown(struct hinic_hwdev *hwdev) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_cap *nic_cap = &hwdev->nic_cap; hinic_io_destroy_qps(func_to_io, nic_cap->num_qps); hinic_io_free(func_to_io); } /** * hinic_hwdev_cb_register - register callback handler for MGMT events * @hwdev: the NIC HW device Loading Loading @@ -499,3 +594,39 @@ int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev) return nic_cap->num_qps; } /** * hinic_hwdev_get_sq - get SQ * @hwdev: the NIC HW device * @i: the position of the SQ * * Return: the SQ in the i position **/ struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_qp *qp = &func_to_io->qps[i]; if (i >= hinic_hwdev_num_qps(hwdev)) return NULL; return &qp->sq; } /** * hinic_hwdev_get_sq - get RQ * @hwdev: the NIC HW device * @i: the position of the RQ * * Return: the RQ in the i position **/ struct hinic_rq *hinic_hwdev_get_rq(struct hinic_hwdev *hwdev, int i) { struct hinic_func_to_io *func_to_io = &hwdev->func_to_io; struct hinic_qp *qp = &func_to_io->qps[i]; if (i >= hinic_hwdev_num_qps(hwdev)) return NULL; return &qp->rq; }
drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h +20 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "hinic_hw_if.h" #include "hinic_hw_eqs.h" #include "hinic_hw_mgmt.h" #include "hinic_hw_qp.h" #include "hinic_hw_io.h" #define HINIC_MAX_QPS 32 Loading Loading @@ -72,11 +74,21 @@ enum hinic_cb_state { HINIC_CB_RUNNING = BIT(1), }; struct hinic_cmd_base_qpn { u8 status; u8 version; u8 rsvd0[6]; u16 func_idx; u16 qpn; }; struct hinic_hwdev { struct hinic_hwif *hwif; struct msix_entry *msix_entries; struct hinic_aeqs aeqs; struct hinic_func_to_io func_to_io; struct hinic_cap nic_cap; }; Loading Loading @@ -111,10 +123,18 @@ int hinic_port_msg_cmd(struct hinic_hwdev *hwdev, enum hinic_port_cmd cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size); int hinic_hwdev_ifup(struct hinic_hwdev *hwdev); void hinic_hwdev_ifdown(struct hinic_hwdev *hwdev); struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev); void hinic_free_hwdev(struct hinic_hwdev *hwdev); int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev); struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i); struct hinic_rq *hinic_hwdev_get_rq(struct hinic_hwdev *hwdev, int i); #endif
drivers/net/ethernet/huawei/hinic/hinic_hw_io.c 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Huawei HiNIC PCI Express Linux driver * Copyright(c) 2017 Huawei Technologies Co., Ltd * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * */ #include <linux/types.h> #include <linux/pci.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/slab.h> #include "hinic_hw_if.h" #include "hinic_hw_qp.h" #include "hinic_hw_io.h" /** * init_qp - Initialize a Queue Pair * @func_to_io: func to io channel that holds the IO components * @qp: pointer to the qp to initialize * @q_id: the id of the qp * @sq_msix_entry: msix entry for sq * @rq_msix_entry: msix entry for rq * * Return 0 - Success, negative - Failure **/ static int init_qp(struct hinic_func_to_io *func_to_io, struct hinic_qp *qp, int q_id, struct msix_entry *sq_msix_entry, struct msix_entry *rq_msix_entry) { /* should be implemented */ return 0; } /** * destroy_qp - Clean the resources of a Queue Pair * @func_to_io: func to io channel that holds the IO components * @qp: pointer to the qp to clean **/ static void destroy_qp(struct hinic_func_to_io *func_to_io, struct hinic_qp *qp) { /* should be implemented */ } /** * hinic_io_create_qps - Create Queue Pairs * @func_to_io: func to io channel that holds the IO components * @base_qpn: base qp number * @num_qps: number queue pairs to create * @sq_msix_entry: msix entries for sq * @rq_msix_entry: msix entries for rq * * Return 0 - Success, negative - Failure **/ int hinic_io_create_qps(struct hinic_func_to_io *func_to_io, u16 base_qpn, int num_qps, struct msix_entry *sq_msix_entries, struct msix_entry *rq_msix_entries) { struct hinic_hwif *hwif = func_to_io->hwif; struct pci_dev *pdev = hwif->pdev; size_t qps_size; int i, j, err; qps_size = num_qps * sizeof(*func_to_io->qps); func_to_io->qps = devm_kzalloc(&pdev->dev, qps_size, GFP_KERNEL); if (!func_to_io->qps) return -ENOMEM; for (i = 0; i < num_qps; i++) { err = init_qp(func_to_io, &func_to_io->qps[i], i, &sq_msix_entries[i], &rq_msix_entries[i]); if (err) { dev_err(&pdev->dev, "Failed to create QP %d\n", i); goto err_init_qp; } } return 0; err_init_qp: for (j = 0; j < i; j++) destroy_qp(func_to_io, &func_to_io->qps[j]); devm_kfree(&pdev->dev, func_to_io->qps); return err; } /** * hinic_io_destroy_qps - Destroy the IO Queue Pairs * @func_to_io: func to io channel that holds the IO components * @num_qps: number queue pairs to destroy **/ void hinic_io_destroy_qps(struct hinic_func_to_io *func_to_io, int num_qps) { struct hinic_hwif *hwif = func_to_io->hwif; struct pci_dev *pdev = hwif->pdev; int i; for (i = 0; i < num_qps; i++) destroy_qp(func_to_io, &func_to_io->qps[i]); devm_kfree(&pdev->dev, func_to_io->qps); } /** * hinic_io_init - Initialize the IO components * @func_to_io: func to io channel that holds the IO components * @hwif: HW interface for accessing IO * @max_qps: maximum QPs in HW * @num_ceqs: number completion event queues * @ceq_msix_entries: msix entries for ceqs * * Return 0 - Success, negative - Failure **/ int hinic_io_init(struct hinic_func_to_io *func_to_io, struct hinic_hwif *hwif, u16 max_qps, int num_ceqs, struct msix_entry *ceq_msix_entries) { func_to_io->hwif = hwif; func_to_io->qps = NULL; func_to_io->max_qps = max_qps; return 0; } /** * hinic_io_free - Free the IO components * @func_to_io: func to io channel that holds the IO components **/ void hinic_io_free(struct hinic_func_to_io *func_to_io) { }