Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1668370 > unrolled thread
| Started by | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| First post | 2017-06-17 19:30 +0200 |
| Last post | 2017-06-18 19:00 +0200 |
| Articles | 17 — 6 participants |
Back to article view | Back to linux.kernel
[PATCH V3 net-next 0/8] Hisilicon Network Subsystem 3 Ethernet Driver Salil Mehta <salil.mehta@huawei.com> - 2017-06-17 19:30 +0200
[PATCH V3 net-next 3/8] net: hns3: Add HNS3 IMP(Integrated Mgmt Proc) Cmd Interface Support Salil Mehta <salil.mehta@huawei.com> - 2017-06-17 19:30 +0200
[PATCH V3 net-next 8/8] net: hns3: Add HNS3 driver to kernel build framework & MAINTAINERS Salil Mehta <salil.mehta@huawei.com> - 2017-06-17 19:30 +0200
[PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework Salil Mehta <salil.mehta@huawei.com> - 2017-06-17 19:30 +0200
Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework Andrew Lunn <andrew@lunn.ch> - 2017-06-17 21:50 +0200
Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework Andrew Lunn <andrew@lunn.ch> - 2017-06-18 17:10 +0200
Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework Bo Yu <tsu.yubo@gmail.com> - 2017-06-18 18:50 +0200
Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework Stephen Hemminger <stephen@networkplumber.org> - 2017-06-19 19:00 +0200
[PATCH V3 net-next 7/8] net: hns3: Add Ethtool support to HNS3 driver Salil Mehta <salil.mehta@huawei.com> - 2017-06-17 19:30 +0200
[PATCH V3 net-next 6/8] net: hns3: Add MDIO support to HNS3 Ethernet driver for hip08 SoC Salil Mehta <salil.mehta@huawei.com> - 2017-06-17 19:30 +0200
Re: [PATCH V3 net-next 6/8] net: hns3: Add MDIO support to HNS3 Ethernet driver for hip08 SoC Andrew Lunn <andrew@lunn.ch> - 2017-06-19 06:00 +0200
[PATCH V3 net-next 5/8] net: hns3: Add support of TX Scheduler & Shaper to HNS3 driver Salil Mehta <salil.mehta@huawei.com> - 2017-06-17 19:30 +0200
Re: [PATCH V3 net-next 5/8] net: hns3: Add support of TX Scheduler & Shaper to HNS3 driver Richard Cochran <richardcochran@gmail.com> - 2017-06-18 18:50 +0200
Re: [PATCH V3 net-next 1/8] net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC Andrew Lunn <andrew@lunn.ch> - 2017-06-17 20:00 +0200
Re: [PATCH V3 net-next 1/8] net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC Andrew Lunn <andrew@lunn.ch> - 2017-06-17 21:50 +0200
Re: [PATCH V3 net-next 0/8] Hisilicon Network Subsystem 3 Ethernet Driver Leon Romanovsky <leon@kernel.org> - 2017-06-18 08:10 +0200
Re: [PATCH V3 net-next 1/8] net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC Bo Yu <tsu.yubo@gmail.com> - 2017-06-18 19:00 +0200
| From | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| Date | 2017-06-17 19:30 +0200 |
| Subject | [PATCH V3 net-next 0/8] Hisilicon Network Subsystem 3 Ethernet Driver |
| Message-ID | <tTpHP-1Qt-1@gated-at.bofh.it> |
This patch-set contains the support of the HNS3 (Hisilicon Network Subsystem 3)
Ethernet driver for hip08 family of SoCs and future upcoming SoCs.
Hisilicon's new hip08 SoCs have integrated ethernet based on PCI Express and
hence there was a need of new driver over the previous HNS driver which is
already part of the Linux mainline. This new driver is NOT backward
compatible with HNS.
This current driver is meant to control the Physical Function and there would
soon be a support of a separate driver for Virtual Function once this base PF
driver has been accepted. Also, this driver is the ongoing development work and
HNS3 Ethernet driver would be incrementally enhanced with more new features.
High Level Architecture:
[ Ethtool ]
^ |
| |
[Ethernet Client] [RoCE Client] . . . [ Ethernet Client ]
--------------------------------------------- |
| |
[ HNAE3 Framework (Register/unregister) ] |
| |
--------------------------------------------- |
[ HNAE Device ] |
| |
[ HCLGE Layer] |
________________|_________________ |
| | | |
[ MDIO ] [ Scheduler/Shaper ] [ Debugfs ] |
| | | |
|________________|_________________| |
| |
[ IMP command Interface ] |
--------------------------------------------- |
HIP08 H A R D W A R E *
Current patch-set broadly adds the support of the following PF functionality:
1. Basic Rx and Tx functionality
2. TSO support
3. Ethtool support
4. HNAE framework and hardware compatability layer
5. Scheduler and Shaper support in transmit function
6. MDIO support
7. kernel build supporrt, Makefiles, Kconfig etc.
Change Log:
V2->V3: Addressed comments
* Yuval Mintz: Removal of redundant userprio-to-tc code
* Stephen Hemminger: Ethtool & interuupt enable
* Andrew Lunn: On C45/C22 PHy support, HNAE, ethtool
* Florian Fainelli: C45/C22 and phy_connect/attach
* Intel kbuild errors
V1->V2: Addressed some comments by kbuild, Yuval MIntz, Andrew Lunn &
Florian Fainelli in the following patches:
* Add support of HNS3 Ethernet Driver for hip08 SoC
* Add MDIO support to HNS3 Ethernet driver for hip08 SoC
* Add support of debugfs interface to HNS3 driver
Salil Mehta (8):
net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC
net: hns3: Add support of the HNAE3 framework
net: hns3: Add HNS3 IMP(Integrated Mgmt Proc) Cmd Interface Support
net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support
net: hns3: Add support of TX Scheduler & Shaper to HNS3 driver
net: hns3: Add MDIO support to HNS3 Ethernet driver for hip08 SoC
net: hns3: Add Ethtool support to HNS3 driver
net: hns3: Add HNS3 driver to kernel build framework & MAINTAINERS
MAINTAINERS | 8 +
drivers/net/ethernet/hisilicon/Kconfig | 27 +
drivers/net/ethernet/hisilicon/Makefile | 1 +
drivers/net/ethernet/hisilicon/hns3/Makefile | 7 +
drivers/net/ethernet/hisilicon/hns3/hnae3.c | 305 ++
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 449 +++
.../net/ethernet/hisilicon/hns3/hns3pf/Makefile | 11 +
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 347 ++
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 742 ++++
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4246 ++++++++++++++++++++
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 493 +++
.../ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 249 ++
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 1018 +++++
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 108 +
.../net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c | 2838 +++++++++++++
.../net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.h | 585 +++
.../ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c | 878 ++++
17 files changed, 12312 insertions(+)
create mode 100644 drivers/net/ethernet/hisilicon/hns3/Makefile
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hnae3.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hnae3.h
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.h
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c
--
2.7.4
[toc] | [next] | [standalone]
| From | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| Date | 2017-06-17 19:30 +0200 |
| Subject | [PATCH V3 net-next 3/8] net: hns3: Add HNS3 IMP(Integrated Mgmt Proc) Cmd Interface Support |
| Message-ID | <tTpHP-1Qt-3@gated-at.bofh.it> |
| In reply to | #1668370 |
This patch adds the support of IMP (Integrated Management Processor)
command interface to the HNS3 driver.
Each PF/VF has support of CQP(Command Queue Pair) ring interface.
Each CQP consis of send queue CSQ and receive queue CRQ.
There are various commands a PF/VF may support, like for Flow Table
manipulation, Device management, Packet buffer allocation, Forwarding,
VLANs config, Tunneling/Overlays etc.
This patch contains code to initialize the command queue, manage the
command queue descriptors and Rx/Tx protocol with the command processor
in the form of various commands/results and acknowledgements.
Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: lipeng <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Yisen Zhuang <yisen.zhuang@huawei.com>
---
---
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 347 ++++++++++
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 742 +++++++++++++++++++++
2 files changed, 1089 insertions(+)
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
new file mode 100644
index 0000000..ec20ec4
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2016~2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/dma-direction.h>
+#include "hclge_cmd.h"
+#include "hnae3.h"
+#include "hclge_main.h"
+
+#define hclge_is_csq(ring) ((ring)->flag & HCLGE_TYPE_CSQ)
+#define hclge_ring_to_dma_dir(ring) (hclge_is_csq(ring) ? \
+ DMA_TO_DEVICE : DMA_FROM_DEVICE)
+#define cmq_ring_to_dev(ring) (&(ring)->dev->pdev->dev)
+
+static int hclge_ring_space(struct hclge_cmq_ring *ring)
+{
+ int ntu = ring->next_to_use;
+ int ntc = ring->next_to_clean;
+ int used = (ntu - ntc + ring->desc_num) % ring->desc_num;
+
+ return ring->desc_num - used - 1;
+}
+
+static int hclge_alloc_cmd_desc(struct hclge_cmq_ring *ring)
+{
+ int size = ring->desc_num * sizeof(struct hclge_desc);
+
+ ring->desc = kzalloc(size, GFP_KERNEL);
+ if (!ring->desc)
+ return -ENOMEM;
+
+ ring->desc_dma_addr = dma_map_single(cmq_ring_to_dev(ring), ring->desc,
+ size, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(cmq_ring_to_dev(ring), ring->desc_dma_addr)) {
+ ring->desc_dma_addr = 0;
+ kfree(ring->desc);
+ ring->desc = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void hclge_free_cmd_desc(struct hclge_cmq_ring *ring)
+{
+ dma_unmap_single(cmq_ring_to_dev(ring), ring->desc_dma_addr,
+ ring->desc_num * sizeof(ring->desc[0]),
+ DMA_BIDIRECTIONAL);
+
+ ring->desc_dma_addr = 0;
+ kfree(ring->desc);
+ ring->desc = NULL;
+}
+
+static int hclge_init_cmd_queue(struct hclge_dev *hdev, int ring_type)
+{
+ struct hclge_hw *hw = &hdev->hw;
+ struct hclge_cmq_ring *ring =
+ (ring_type == HCLGE_TYPE_CSQ) ? &hw->cmq.csq : &hw->cmq.crq;
+ int ret;
+
+ ring->flag = ring_type;
+ ring->dev = hdev;
+
+ ret = hclge_alloc_cmd_desc(ring);
+ if (ret) {
+ dev_err(&hdev->pdev->dev, "descriptor %s alloc error %d\n",
+ (ring_type == HCLGE_TYPE_CSQ) ? "CSQ" : "CRQ", ret);
+ return ret;
+ }
+
+ ring->next_to_clean = 0;
+ ring->next_to_use = 0;
+
+ return 0;
+}
+
+void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read)
+{
+ desc->flag = cpu_to_le16(HCLGE_CMD_FLAG_NO_INTR | HCLGE_CMD_FLAG_IN);
+ if (is_read)
+ desc->flag |= cpu_to_le16(HCLGE_CMD_FLAG_WR);
+ else
+ desc->flag &= cpu_to_le16(~HCLGE_CMD_FLAG_WR);
+}
+
+void hclge_cmd_setup_basic_desc(struct hclge_desc *desc,
+ enum hclge_opcode_type opcode, bool is_read)
+{
+ memset((void *)desc, 0, sizeof(struct hclge_desc));
+ desc->opcode = cpu_to_le16(opcode);
+ desc->flag = cpu_to_le16(HCLGE_CMD_FLAG_NO_INTR | HCLGE_CMD_FLAG_IN);
+
+ if (is_read)
+ desc->flag |= cpu_to_le16(HCLGE_CMD_FLAG_WR);
+ else
+ desc->flag &= cpu_to_le16(~HCLGE_CMD_FLAG_WR);
+}
+
+static void hclge_cmd_config_regs(struct hclge_cmq_ring *ring)
+{
+ dma_addr_t dma = ring->desc_dma_addr;
+ struct hclge_dev *hdev = ring->dev;
+ struct hclge_hw *hw = &hdev->hw;
+
+ if (ring->flag == HCLGE_TYPE_CSQ) {
+ hclge_write_dev(hw, HCLGE_NIC_CSQ_BASEADDR_L_REG,
+ (u32)dma);
+ hclge_write_dev(hw, HCLGE_NIC_CSQ_BASEADDR_H_REG,
+ (u32)((dma >> 31) >> 1));
+ hclge_write_dev(hw, HCLGE_NIC_CSQ_DEPTH_REG,
+ (ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S) |
+ HCLGE_NIC_CMQ_ENABLE);
+ hclge_write_dev(hw, HCLGE_NIC_CSQ_TAIL_REG, 0);
+ hclge_write_dev(hw, HCLGE_NIC_CSQ_HEAD_REG, 0);
+ } else {
+ hclge_write_dev(hw, HCLGE_NIC_CRQ_BASEADDR_L_REG,
+ (u32)dma);
+ hclge_write_dev(hw, HCLGE_NIC_CRQ_BASEADDR_H_REG,
+ (u32)((dma >> 31) >> 1));
+ hclge_write_dev(hw, HCLGE_NIC_CRQ_DEPTH_REG,
+ (ring->desc_num >> HCLGE_NIC_CMQ_DESC_NUM_S) |
+ HCLGE_NIC_CMQ_ENABLE);
+ hclge_write_dev(hw, HCLGE_NIC_CRQ_TAIL_REG, 0);
+ hclge_write_dev(hw, HCLGE_NIC_CRQ_HEAD_REG, 0);
+ }
+}
+
+static void hclge_cmd_init_regs(struct hclge_hw *hw)
+{
+ hclge_cmd_config_regs(&hw->cmq.csq);
+ hclge_cmd_config_regs(&hw->cmq.crq);
+}
+
+static int hclge_cmd_csq_clean(struct hclge_hw *hw)
+{
+ struct hclge_cmq_ring *csq = &hw->cmq.csq;
+ u16 ntc = csq->next_to_clean;
+ struct hclge_desc *desc;
+ int clean = 0;
+ u32 head;
+
+ desc = &csq->desc[ntc];
+ head = hclge_read_dev(hw, HCLGE_NIC_CSQ_HEAD_REG);
+
+ while (head != ntc) {
+ memset(desc, 0, sizeof(*desc));
+ ntc++;
+ if (ntc == csq->desc_num)
+ ntc = 0;
+ desc = &csq->desc[ntc];
+ clean++;
+ }
+ csq->next_to_clean = ntc;
+
+ return clean;
+}
+
+static int hclge_cmd_csq_done(struct hclge_hw *hw)
+{
+ u32 head = hclge_read_dev(hw, HCLGE_NIC_CSQ_HEAD_REG);
+ return head == hw->cmq.csq.next_to_use;
+}
+
+/**
+ * hclge_cmd_send - send command to command queue
+ * @hw: pointer to the hw struct
+ * @desc: prefilled descriptor for describing the command
+ * @num : the number of descriptors to be sent
+ *
+ * This is the main send command for command queue, it
+ * sends the queue, cleans the queue, etc
+ **/
+enum hclge_cmd_status hclge_cmd_send(struct hclge_hw *hw,
+ struct hclge_desc *desc, int num)
+{
+ struct hclge_dev *hdev = (struct hclge_dev *)hw->back;
+ enum hclge_cmd_status status = 0;
+ struct hclge_desc *desc_to_use;
+ bool complete = false;
+ u32 timeout = 0;
+ int handle = 0;
+ u16 retval;
+ int ntc;
+
+ spin_lock_bh(&hw->cmq.csq.lock);
+
+ if (num > hclge_ring_space(&hw->cmq.csq)) {
+ spin_unlock_bh(&hw->cmq.csq.lock);
+ return HCLGE_ERR_CSQ_FULL;
+ }
+
+ /**
+ * Record the location of desc in the ring for this time
+ * which will be use for hardware to write back
+ */
+ ntc = hw->cmq.csq.next_to_use;
+
+ while (handle < num) {
+ desc_to_use = &hw->cmq.csq.desc[hw->cmq.csq.next_to_use];
+ *desc_to_use = desc[handle];
+ (hw->cmq.csq.next_to_use)++;
+ if (hw->cmq.csq.next_to_use == hw->cmq.csq.desc_num)
+ hw->cmq.csq.next_to_use = 0;
+ handle++;
+ }
+
+ /* Write to hardware */
+ hclge_write_dev(hw, HCLGE_NIC_CSQ_TAIL_REG, hw->cmq.csq.next_to_use);
+
+ /**
+ * If the command is sync, wait for the firmware to write back,
+ * if multi descriptors to be sent, use the first one to check
+ */
+ if (HCLGE_SEND_SYNC(desc->flag)) {
+ do {
+ if (hclge_cmd_csq_done(hw))
+ break;
+ udelay(1);
+ timeout++;
+ } while (timeout < hw->cmq.tx_timeout);
+ }
+
+ if (hclge_cmd_csq_done(hw)) {
+ complete = true;
+ handle = 0;
+ while (handle < num) {
+ /* Get the result of hardware write back */
+ desc_to_use = &hw->cmq.csq.desc[ntc];
+ desc[handle] = *desc_to_use;
+ retval = desc[handle].retval;
+ if ((enum hclge_cmd_return_status)retval ==
+ HCLGE_CMD_EXEC_SUCCESS)
+ status = 0;
+ else
+ status = HCLGE_ERR_CSQ_ERROR;
+ hw->cmq.last_status = (enum hclge_cmd_status)retval;
+ ntc++;
+ handle++;
+ if (ntc == hw->cmq.csq.desc_num)
+ ntc = 0;
+ }
+ }
+
+ if (!complete)
+ status = HCLGE_ERR_CSQ_TIMEOUT;
+
+ /* Clean the command send queue */
+ handle = hclge_cmd_csq_clean(hw);
+ if (handle != num) {
+ dev_warn(&hdev->pdev->dev,
+ "cleaned %d, need to clean %d\n", handle, num);
+ }
+
+ spin_unlock_bh(&hw->cmq.csq.lock);
+
+ return status;
+}
+
+enum hclge_cmd_status hclge_cmd_query_firmware_version(struct hclge_hw *hw,
+ u32 *version)
+{
+ struct hclge_query_version *resp;
+ enum hclge_cmd_status status;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_FW_VER, 1);
+ resp = (struct hclge_query_version *)desc.data;
+
+ status = hclge_cmd_send(hw, &desc, 1);
+ if (!status)
+ *version = le32_to_cpu(resp->firmware);
+
+ return status;
+}
+
+int hclge_cmd_init(struct hclge_dev *hdev)
+{
+ u32 version;
+ int ret;
+
+ /* Setup the queue entries for use cmd queue */
+ hdev->hw.cmq.csq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
+ hdev->hw.cmq.crq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
+
+ /* Setup the lock for command queue */
+ spin_lock_init(&hdev->hw.cmq.csq.lock);
+ spin_lock_init(&hdev->hw.cmq.crq.lock);
+
+ /* Setup Tx write back timeout */
+ hdev->hw.cmq.tx_timeout = HCLGE_CMDQ_TX_TIMEOUT;
+
+ /* Setup queue rings */
+ ret = hclge_init_cmd_queue(hdev, HCLGE_TYPE_CSQ);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "CSQ ring setup error %d\n", ret);
+ return ret;
+ }
+
+ ret = hclge_init_cmd_queue(hdev, HCLGE_TYPE_CRQ);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "CRQ ring setup error %d\n", ret);
+ goto err_csq;
+ }
+
+ hclge_cmd_init_regs(&hdev->hw);
+
+ ret = hclge_cmd_query_firmware_version(&hdev->hw, &version);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "firmware version query failed %d\n", ret);
+ return ret;
+ }
+ hdev->fw_version = version;
+
+ dev_info(&hdev->pdev->dev, "The firware version is %08x\n", version);
+
+ return 0;
+err_csq:
+ hclge_free_cmd_desc(&hdev->hw.cmq.csq);
+ return ret;
+}
+
+static void hclge_destroy_queue(struct hclge_cmq_ring *ring)
+{
+ spin_lock_bh(&ring->lock);
+ hclge_free_cmd_desc(ring);
+ spin_unlock_bh(&ring->lock);
+}
+
+void hclge_destroy_cmd_queue(struct hclge_hw *hw)
+{
+ hclge_destroy_queue(&hw->cmq.csq);
+ hclge_destroy_queue(&hw->cmq.crq);
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
new file mode 100644
index 0000000..6699fb0
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2016~2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __HCLGE_CMD_H
+#define __HCLGE_CMD_H
+#include <linux/types.h>
+#include <linux/io.h>
+
+#define HCLGE_CMDQ_TX_TIMEOUT 200
+
+struct hclge_dev;
+struct hclge_desc {
+ __le16 opcode;
+
+#define HCLGE_CMDQ_RX_INVLD_B 0
+#define HCLGE_CMDQ_RX_OUTVLD_B 1
+
+ __le16 flag;
+ __le16 retval;
+ __le16 rsv;
+ __le32 data[6];
+};
+
+struct hclge_desc_cb {
+ dma_addr_t dma;
+ void *va;
+ u32 length;
+};
+
+struct hclge_cmq_ring {
+ dma_addr_t desc_dma_addr;
+ struct hclge_desc *desc;
+ struct hclge_desc_cb *desc_cb;
+ struct hclge_dev *dev;
+ u32 head;
+ u32 tail;
+
+ u16 buf_size;
+ u16 desc_num;
+ int next_to_use;
+ int next_to_clean;
+ u8 flag;
+ spinlock_t lock; /* Command queue lock */
+};
+
+enum hclge_cmd_return_status {
+ HCLGE_CMD_EXEC_SUCCESS = 0,
+ HCLGE_CMD_NO_AUTH = 1,
+ HCLGE_CMD_NOT_EXEC = 2,
+ HCLGE_CMD_QUEUE_FULL = 3,
+};
+
+enum hclge_cmd_status {
+ HCLGE_STATUS_SUCCESS = 0,
+ HCLGE_ERR_CSQ_FULL = -1,
+ HCLGE_ERR_CSQ_TIMEOUT = -2,
+ HCLGE_ERR_CSQ_ERROR = -3,
+};
+
+struct hclge_cmq {
+ struct hclge_cmq_ring csq;
+ struct hclge_cmq_ring crq;
+ u16 tx_timeout; /* Tx timeout */
+ enum hclge_cmd_status last_status;
+};
+
+#define HCLGE_CMD_FLAG_IN_VALID_SHIFT 0
+#define HCLGE_CMD_FLAG_OUT_VALID_SHIFT 1
+#define HCLGE_CMD_FLAG_NEXT_SHIFT 2
+#define HCLGE_CMD_FLAG_WR_OR_RD_SHIFT 3
+#define HCLGE_CMD_FLAG_NO_INTR_SHIFT 4
+#define HCLGE_CMD_FLAG_ERR_INTR_SHIFT 5
+
+#define HCLGE_CMD_FLAG_IN BIT(HCLGE_CMD_FLAG_IN_VALID_SHIFT)
+#define HCLGE_CMD_FLAG_OUT BIT(HCLGE_CMD_FLAG_OUT_VALID_SHIFT)
+#define HCLGE_CMD_FLAG_NEXT BIT(HCLGE_CMD_FLAG_NEXT_SHIFT)
+#define HCLGE_CMD_FLAG_WR BIT(HCLGE_CMD_FLAG_WR_OR_RD_SHIFT)
+#define HCLGE_CMD_FLAG_NO_INTR BIT(HCLGE_CMD_FLAG_NO_INTR_SHIFT)
+#define HCLGE_CMD_FLAG_ERR_INTR BIT(HCLGE_CMD_FLAG_ERR_INTR_SHIFT)
+
+enum hclge_opcode_type {
+ /* Generic command */
+ HCLGE_OPC_QUERY_FW_VER = 0x0001,
+ HCLGE_OPC_CFG_RST_TRIGGER = 0x0020,
+ HCLGE_OPC_GBL_RST_STATUS = 0x0021,
+ HCLGE_OPC_QUERY_FUNC_STATUS = 0x0022,
+ HCLGE_OPC_QUERY_PF_RSRC = 0x0023,
+ HCLGE_OPC_QUERY_VF_RSRC = 0x0024,
+ HCLGE_OPC_GET_CFG_PARAM = 0x0025,
+
+ HCLGE_OPC_STATS_64_BIT = 0x0030,
+ HCLGE_OPC_STATS_32_BIT = 0x0031,
+ HCLGE_OPC_STATS_MAC = 0x0032,
+ /* Device management command */
+
+ /* MAC commond */
+ HCLGE_OPC_CONFIG_MAC_MODE = 0x0301,
+ HCLGE_OPC_CONFIG_AN_MODE = 0x0304,
+ HCLGE_OPC_QUERY_AN_RESULT = 0x0306,
+ HCLGE_OPC_QUERY_LINK_STATUS = 0x0307,
+ HCLGE_OPC_CONFIG_MAX_FRM_SIZE = 0x0308,
+ HCLGE_OPC_CONFIG_SPEED_DUP = 0x0309,
+ /* MACSEC command */
+
+ /* PFC/Pause CMD*/
+ HCLGE_OPC_CFG_MAC_PAUSE_EN = 0x0701,
+ HCLGE_OPC_CFG_PFC_PAUSE_EN = 0x0702,
+ HCLGE_OPC_CFG_MAC_PARA = 0x0703,
+ HCLGE_OPC_CFG_PFC_PARA = 0x0704,
+ HCLGE_OPC_QUERY_MAC_TX_PKT_CNT = 0x0705,
+ HCLGE_OPC_QUERY_MAC_RX_PKT_CNT = 0x0706,
+ HCLGE_OPC_QUERY_PFC_TX_PKT_CNT = 0x0707,
+ HCLGE_OPC_QUERY_PFC_RX_PKT_CNT = 0x0708,
+ HCLGE_OPC_PRI_TO_TC_MAPPING = 0x0709,
+ HCLGE_OPC_QOS_MAP = 0x070A,
+
+ /* ETS/scheduler commands */
+ HCLGE_OPC_TM_PG_TO_PRI_LINK = 0x0804,
+ HCLGE_OPC_TM_QS_TO_PRI_LINK = 0x0805,
+ HCLGE_OPC_TM_NQ_TO_QS_LINK = 0x0806,
+ HCLGE_OPC_TM_RQ_TO_QS_LINK = 0x0807,
+ HCLGE_OPC_TM_PORT_WEIGHT = 0x0808,
+ HCLGE_OPC_TM_PG_WEIGHT = 0x0809,
+ HCLGE_OPC_TM_QS_WEIGHT = 0x080A,
+ HCLGE_OPC_TM_PRI_WEIGHT = 0x080B,
+ HCLGE_OPC_TM_PRI_C_SHAPPING = 0x080C,
+ HCLGE_OPC_TM_PRI_P_SHAPPING = 0x080D,
+ HCLGE_OPC_TM_PG_C_SHAPPING = 0x080E,
+ HCLGE_OPC_TM_PG_P_SHAPPING = 0x080F,
+ HCLGE_OPC_TM_PORT_SHAPPING = 0x0810,
+ HCLGE_OPC_TM_PG_SCH_MODE_CFG = 0x0812,
+ HCLGE_OPC_TM_PRI_SCH_MODE_CFG = 0x0813,
+ HCLGE_OPC_TM_QS_SCH_MODE_CFG = 0x0814,
+ HCLGE_OPC_TM_BP_TO_QSET_MAPPING = 0x0815,
+
+ /* Packet buffer allocate command */
+ HCLGE_OPC_TX_BUFF_ALLOC = 0x0901,
+ HCLGE_OPC_RX_PRIV_BUFF_ALLOC = 0x0902,
+ HCLGE_OPC_RX_PRIV_WL_ALLOC = 0x0903,
+ HCLGE_OPC_RX_COM_THRD_ALLOC = 0x0904,
+ HCLGE_OPC_RX_COM_WL_ALLOC = 0x0905,
+ HCLGE_OPC_RX_GBL_PKT_CNT = 0x0906,
+
+ /* PTP command */
+ /* TQP management command */
+ HCLGE_OPC_SET_TQP_MAP = 0x0A01,
+
+ /* TQP command */
+ HCLGE_OPC_CFG_TX_QUEUE = 0x0B01,
+ HCLGE_OPC_QUERY_TX_POINTER = 0x0B02,
+ HCLGE_OPC_QUERY_TX_STATUS = 0x0B03,
+ HCLGE_OPC_CFG_RX_QUEUE = 0x0B11,
+ HCLGE_OPC_QUERY_RX_POINTER = 0x0B12,
+ HCLGE_OPC_QUERY_RX_STATUS = 0x0B13,
+ HCLGE_OPC_STASH_RX_QUEUE_LRO = 0x0B16,
+ HCLGE_OPC_CFG_RX_QUEUE_LRO = 0x0B17,
+ HCLGE_OPC_CFG_COM_TQP_QUEUE = 0x0B20,
+ HCLGE_OPC_RESET_TQP_QUEUE = 0x0B22,
+
+ /* TSO cmd */
+ HCLGE_OPC_TSO_GENERIC_CONFIG = 0x0C01,
+
+ /* RSS cmd */
+ HCLGE_OPC_RSS_GENERIC_CONFIG = 0x0D01,
+ HCLGE_OPC_RSS_INDIR_TABLE = 0x0D07,
+ HCLGE_OPC_RSS_TC_MODE = 0x0D08,
+ HCLGE_OPC_RSS_INPUT_TUPLE = 0x0D02,
+
+ /* Promisuous mode command */
+ HCLGE_OPC_CFG_PROMISC_MODE = 0x0E01,
+
+ /* Interrupts cmd */
+ HCLGE_OPC_ADD_RING_TO_VECTOR = 0x1503,
+ HCLGE_OPC_DEL_RING_TO_VECTOR = 0x1504,
+
+ /* MAC command */
+ HCLGE_OPC_MAC_VLAN_ADD = 0x1000,
+ HCLGE_OPC_MAC_VLAN_REMOVE = 0x1001,
+ HCLGE_OPC_MAC_VLAN_TYPE_ID = 0x1002,
+ HCLGE_OPC_MAC_VLAN_INSERT = 0x1003,
+ HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010,
+ HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011,
+
+ /* Multicast linear table cmd */
+ HCLGE_OPC_MTA_MAC_MODE_CFG = 0x1020,
+ HCLGE_OPC_MTA_MAC_FUNC_CFG = 0x1021,
+ HCLGE_OPC_MTA_TBL_ITEM_CFG = 0x1022,
+ HCLGE_OPC_MTA_TBL_ITEM_QUERY = 0x1023,
+
+ /* VLAN command */
+ HCLGE_OPC_VLAN_FILTER_CTRL = 0x1100,
+ HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101,
+ HCLGE_OPC_VLAN_FILTER_VF_CFG = 0x1102,
+
+ /* MDIO command */
+ HCLGE_OPC_MDIO_CONFIG = 0x1900,
+
+ /* QCN command */
+ HCLGE_OPC_QCN_MOD_CFG = 0x1A01,
+ HCLGE_OPC_QCN_GRP_TMPLT_CFG = 0x1A02,
+ HCLGE_OPC_QCN_SHAPPING_IR_CFG = 0x1A03,
+ HCLGE_OPC_QCN_SHAPPING_BS_CFG = 0x1A04,
+ HCLGE_OPC_QCN_QSET_LINK_CFG = 0x1A05,
+ HCLGE_OPC_QCN_RP_STATUS_GET = 0x1A06,
+ HCLGE_OPC_QCN_AJUST_INIT = 0x1A07,
+ HCLGE_OPC_QCN_DFX_CNT_STATUS = 0x1A08,
+
+ /* Mailbox cmd */
+ HCLGEVF_OPC_MBX_PF_TO_VF = 0x2000,
+};
+
+#define HCLGE_TQP_REG_OFFSET 0x80000
+#define HCLGE_TQP_REG_SIZE 0x200
+
+#define HCLGE_RCB_INIT_QUERY_TIMEOUT 10
+#define HCLGE_RCB_INIT_FLAG_EN_B 0
+#define HCLGE_RCB_INIT_FLAG_FINI_B 8
+struct hclge_config_rcb_init {
+ __le16 rcb_init_flag;
+ u8 rsv[22];
+};
+
+struct hclge_tqp_map {
+ __le16 tqp_id; /* Absolute tqp id for in this pf */
+ u8 tqp_vf; /* VF id */
+#define HCLGE_TQP_MAP_TYPE_PF 0
+#define HCLGE_TQP_MAP_TYPE_VF 1
+#define HCLGE_TQP_MAP_TYPE_B 0
+#define HCLGE_TQP_MAP_EN_B 1
+ u8 tqp_flag; /* Indicate it's pf or vf tqp */
+ __le16 tqp_vid; /* Virtual id in this pf/vf */
+ u8 rsv[18];
+};
+
+#define HCLGE_VECTOR_ELEMENTS_PER_CMD 11
+
+enum hclge_int_type {
+ HCLGE_INT_TX,
+ HCLGE_INT_RX,
+ HCLGE_INT_EVENT,
+};
+
+struct hclge_ctrl_vector_chain {
+ u8 int_vector_id;
+ u8 int_cause_num;
+#define HCLGE_INT_TYPE_S 0
+#define HCLGE_INT_TYPE_M 0x3
+#define HCLGE_TQP_ID_S 2
+#define HCLGE_TQP_ID_M (0x3fff << HCLGE_TQP_ID_S)
+ __le16 tqp_type_and_id[HCLGE_VECTOR_ELEMENTS_PER_CMD];
+};
+
+#define HCLGE_TC_NUM 8
+#define HCLGE_TC0_PRI_BUF_EN_B 15 /* Bit 15 indicate enable or not */
+#define HCLGE_BUF_UNIT_S 7 /* Buf size is united by 128 bytes */
+struct hclge_tx_buff_alloc {
+ __le16 tx_pkt_buff[HCLGE_TC_NUM];
+ u8 tx_buff_rsv[8];
+};
+
+struct hclge_rx_priv_buff {
+ __le16 buf_num[HCLGE_TC_NUM];
+ u8 rsv[8];
+};
+
+struct hclge_query_version {
+ __le32 firmware;
+ __le32 firmware_rsv[5];
+};
+
+#define HCLGE_RX_PRIV_EN_B 15
+#define HCLGE_TC_NUM_ONE_DESC 4
+struct hclge_priv_wl {
+ __le16 high;
+ __le16 low;
+};
+
+struct hclge_rx_priv_wl_buf {
+ struct hclge_priv_wl tc_wl[HCLGE_TC_NUM_ONE_DESC];
+};
+
+struct hclge_rx_com_thrd {
+ struct hclge_priv_wl com_thrd[HCLGE_TC_NUM_ONE_DESC];
+};
+
+struct hclge_rx_com_wl {
+ struct hclge_priv_wl com_wl;
+};
+
+struct hclge_waterline {
+ u32 low;
+ u32 high;
+};
+
+struct hclge_tc_thrd {
+ u32 low;
+ u32 high;
+};
+
+struct hclge_priv_buf {
+ struct hclge_waterline wl; /* Waterline for low and high*/
+ u32 buf_size; /* TC private buffer size */
+ u32 enable; /* Enable TC private buffer or not */
+};
+
+#define HCLGE_MAX_TC_NUM 8
+struct hclge_shared_buf {
+ struct hclge_waterline self;
+ struct hclge_tc_thrd tc_thrd[HCLGE_MAX_TC_NUM];
+ u32 buf_size;
+};
+
+#define HCLGE_RX_COM_WL_EN_B 15
+struct hclge_rx_com_wl_buf {
+ __le16 high_wl;
+ __le16 low_wl;
+ u8 rsv[20];
+};
+
+#define HCLGE_RX_PKT_EN_B 15
+struct hclge_rx_pkt_buf {
+ __le16 high_pkt;
+ __le16 low_pkt;
+ u8 rsv[20];
+};
+
+#define HCLGE_PF_STATE_DONE_B 0
+#define HCLGE_PF_STATE_MAIN_B 1
+#define HCLGE_PF_STATE_BOND_B 2
+#define HCLGE_PF_STATE_MAC_N_B 6
+#define HCLGE_PF_MAC_NUM_MASK 0x3
+#define HCLGE_PF_STATE_MAIN BIT(HCLGE_PF_STATE_MAIN_B)
+#define HCLGE_PF_STATE_DONE BIT(HCLGE_PF_STATE_DONE_B)
+struct hclge_func_status {
+ __le32 vf_rst_state[4];
+ u8 pf_state;
+ u8 mac_id;
+ u8 rsv1;
+ u8 pf_cnt_in_mac;
+ u8 pf_num;
+ u8 vf_num;
+ u8 rsv[2];
+};
+
+struct hclge_pf_res {
+ __le16 tqp_num;
+ __le16 buf_size;
+ __le16 msixcap_localid_ba_nic;
+ __le16 msixcap_localid_ba_rocee;
+#define HCLGE_PF_VEC_NUM_S 0
+#define HCLGE_PF_VEC_NUM_M (0xff << HCLGE_PF_VEC_NUM_S)
+ __le16 pf_intr_vector_number;
+ __le16 pf_own_fun_number;
+ __le32 rsv[3];
+};
+
+#define HCLGE_CFG_OFFSET_S 0
+#define HCLGE_CFG_OFFSET_M 0xfffff /* Byte (8-10.3) */
+#define HCLGE_CFG_RD_LEN_S 24
+#define HCLGE_CFG_RD_LEN_M (0xf << HCLGE_CFG_RD_LEN_S)
+#define HCLGE_CFG_RD_LEN_BYTES 16
+#define HCLGE_CFG_RD_LEN_UNIT 4
+
+#define HCLGE_CFG_VMDQ_S 0
+#define HCLGE_CFG_VMDQ_M (0xff << HCLGE_CFG_VMDQ_S)
+#define HCLGE_CFG_TC_NUM_S 8
+#define HCLGE_CFG_TC_NUM_M (0xff << HCLGE_CFG_TC_NUM_S)
+#define HCLGE_CFG_TQP_DESC_N_S 16
+#define HCLGE_CFG_TQP_DESC_N_M (0xffff << HCLGE_CFG_TQP_DESC_N_S)
+#define HCLGE_CFG_PHY_ADDR_S 0
+#define HCLGE_CFG_PHY_ADDR_M (0x1f << HCLGE_CFG_PHY_ADDR_S)
+#define HCLGE_CFG_MEDIA_TP_S 8
+#define HCLGE_CFG_MEDIA_TP_M (0xff << HCLGE_CFG_MEDIA_TP_S)
+#define HCLGE_CFG_RX_BUF_LEN_S 16
+#define HCLGE_CFG_RX_BUF_LEN_M (0xffff << HCLGE_CFG_RX_BUF_LEN_S)
+#define HCLGE_CFG_MAC_ADDR_H_S 0
+#define HCLGE_CFG_MAC_ADDR_H_M (0xffff << HCLGE_CFG_MAC_ADDR_H_S)
+#define HCLGE_CFG_DEFAULT_SPEED_S 16
+#define HCLGE_CFG_DEFAULT_SPEED_M (0xff << HCLGE_CFG_DEFAULT_SPEED_S)
+
+struct hclge_cfg_param {
+ __le32 offset;
+ __le32 rsv;
+ __le32 param[4];
+};
+
+#define HCLGE_MAC_MODE 0x0
+#define HCLGE_DESC_NUM 0x40
+
+#define HCLGE_ALLOC_VALID_B 0
+struct hclge_vf_num {
+ u8 alloc_valid;
+ u8 rsv[23];
+};
+
+#define HCLGE_RSS_DEFAULT_OUTPORT_B 4
+#define HCLGE_RSS_HASH_KEY_OFFSET_B 4
+#define HCLGE_RSS_HASH_KEY_NUM 16
+struct hclge_rss_config {
+ u8 hash_config;
+ u8 rsv[7];
+ u8 hash_key[HCLGE_RSS_HASH_KEY_NUM];
+};
+
+struct hclge_rss_input_tuple {
+ u8 ipv4_tcp_en;
+ u8 ipv4_udp_en;
+ u8 ipv4_sctp_en;
+ u8 ipv4_fragment_en;
+ u8 ipv6_tcp_en;
+ u8 ipv6_udp_en;
+ u8 ipv6_sctp_en;
+ u8 ipv6_fragment_en;
+ u8 rsv[16];
+};
+
+#define HCLGE_RSS_CFG_TBL_SIZE 16
+
+struct hclge_rss_indirection_table {
+ u16 start_table_index;
+ u16 rss_set_bitmap;
+ u8 rsv[4];
+ u8 rss_result[HCLGE_RSS_CFG_TBL_SIZE];
+};
+
+#define HCLGE_RSS_TC_OFFSET_S 0
+#define HCLGE_RSS_TC_OFFSET_M (0x3ff << HCLGE_RSS_TC_OFFSET_S)
+#define HCLGE_RSS_TC_SIZE_S 12
+#define HCLGE_RSS_TC_SIZE_M (0x7 << HCLGE_RSS_TC_SIZE_S)
+#define HCLGE_RSS_TC_VALID_B 15
+struct hclge_rss_tc_mode {
+ u16 rss_tc_mode[HCLGE_MAX_TC_NUM];
+ u8 rsv[8];
+};
+
+#define HCLGE_LINK_STS_B 0
+#define HCLGE_LINK_STATUS BIT(HCLGE_LINK_STS_B)
+struct hclge_link_status {
+ u8 status;
+ u8 rsv[23];
+};
+
+struct hclge_promisc_param {
+ u8 vf_id;
+ u8 enable;
+};
+
+#define HCLGE_PROMISC_EN_B 1
+#define HCLGE_PROMISC_EN_ALL 0x7
+#define HCLGE_PROMISC_EN_UC 0x1
+#define HCLGE_PROMISC_EN_MC 0x2
+#define HCLGE_PROMISC_EN_BC 0x4
+struct hclge_promisc_cfg {
+ u8 flag;
+ u8 vf_id;
+ __le16 rsv0;
+ u8 rsv1[20];
+};
+
+enum hclge_promisc_type {
+ HCLGE_UNICAST = 1,
+ HCLGE_MULTICAST = 2,
+ HCLGE_BROADCAST = 3,
+};
+
+#define HCLGE_MAC_TX_EN_B 6
+#define HCLGE_MAC_RX_EN_B 7
+#define HCLGE_MAC_PAD_TX_B 11
+#define HCLGE_MAC_PAD_RX_B 12
+#define HCLGE_MAC_1588_TX_B 13
+#define HCLGE_MAC_1588_RX_B 14
+#define HCLGE_MAC_APP_LP_B 15
+#define HCLGE_MAC_LINE_LP_B 16
+#define HCLGE_MAC_FCS_TX_B 17
+#define HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B 18
+#define HCLGE_MAC_RX_FCS_STRIP_B 19
+#define HCLGE_MAC_RX_FCS_B 20
+#define HCLGE_MAC_TX_UNDER_MIN_ERR_B 21
+#define HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B 22
+
+struct hclge_config_mac_mode {
+ __le32 txrx_pad_fcs_loop_en;
+ u8 rsv[20];
+};
+
+#define HCLGE_CFG_SPEED_S 0
+#define HCLGE_CFG_SPEED_M (0x3f << HCLGE_CFG_SPEED_S)
+
+#define HCLGE_CFG_DUPLEX_B 7
+#define HCLGE_CFG_DUPLEX_M BIT(HCLGE_CFG_DUPLEX_B)
+
+struct hclge_config_mac_speed_dup {
+ u8 speed_dup;
+
+#define HCLGE_CFG_MAC_SPEED_CHANGE_EN_B 0
+ u8 mac_change_fec_en;
+ u8 rsv[22];
+};
+
+#define HCLGE_QUERY_SPEED_S 3
+#define HCLGE_QUERY_AN_B 0
+#define HCLGE_QUERY_DUPLEX_B 2
+
+#define HCLGE_QUERY_SPEED_M (0x1f << HCLGE_QUERY_SPEED_S)
+#define HCLGE_QUERY_AN_M BIT(HCLGE_QUERY_AN_B)
+#define HCLGE_QUERY_DUPLEX_M BIT(HCLGE_QUERY_DUPLEX_B)
+
+struct hclge_query_an_speed_dup {
+ u8 an_syn_dup_speed;
+ u8 pause;
+ u8 rsv[23];
+};
+
+#define HCLGE_RING_ID_MASK 0x3ff
+#define HCLGE_TQP_ENABLE_B 0
+
+#define HCLGE_MAC_CFG_AN_EN_B 0
+#define HCLGE_MAC_CFG_AN_INT_EN_B 1
+#define HCLGE_MAC_CFG_AN_INT_MSK_B 2
+#define HCLGE_MAC_CFG_AN_INT_CLR_B 3
+#define HCLGE_MAC_CFG_AN_RST_B 4
+
+#define HCLGE_MAC_CFG_AN_EN BIT(HCLGE_MAC_CFG_AN_EN_B)
+
+struct hclge_config_auto_neg {
+ __le32 cfg_an_cmd_flag;
+ u8 rsv[20];
+};
+
+#define HCLGE_MAC_MIN_MTU 64
+#define HCLGE_MAC_MAX_MTU 9728
+#define HCLGE_MAC_UPLINK_PORT 0x100
+
+struct hclge_config_max_frm_size {
+ __le16 max_frm_size;
+ u8 rsv[22];
+};
+
+enum hclge_mac_vlan_tbl_opcode {
+ HCLGE_MAC_VLAN_ADD, /* Add new or modify mac_vlan */
+ HCLGE_MAC_VLAN_UPDATE, /* Modify other fields of this table */
+ HCLGE_MAC_VLAN_REMOVE, /* Remove a entry through mac_vlan key */
+ HCLGE_MAC_VLAN_LKUP, /* Lookup a entry through mac_vlan key */
+};
+
+#define HCLGE_MAC_VLAN_BIT0_EN_B 0x0
+#define HCLGE_MAC_VLAN_BIT1_EN_B 0x1
+#define HCLGE_MAC_EPORT_SW_EN_B 0xc
+#define HCLGE_MAC_EPORT_TYPE_B 0xb
+#define HCLGE_MAC_EPORT_VFID_S 0x3
+#define HCLGE_MAC_EPORT_VFID_M (0xff << HCLGE_MAC_EPORT_VFID_S)
+#define HCLGE_MAC_EPORT_PFID_S 0x0
+#define HCLGE_MAC_EPORT_PFID_M (0x7 << HCLGE_MAC_EPORT_PFID_S)
+struct hclge_mac_vlan_tbl_entry {
+ u8 flags;
+ u8 resp_code;
+ __le16 vlan_tag;
+ __le32 mac_addr_hi32;
+ __le16 mac_addr_lo16;
+ __le16 rsv1;
+ u8 entry_type;
+ u8 mc_mac_en;
+ __le16 egress_port;
+ __le16 egress_queue;
+ u8 rsv2[6];
+};
+
+#define HCLGE_CFG_MTA_MAC_SEL_S 0x0
+#define HCLGE_CFG_MTA_MAC_SEL_M (0x3 << HCLGE_CFG_MTA_MAC_SEL_S)
+#define HCLGE_CFG_MTA_MAC_EN_B 0x7
+struct hclge_mta_filter_mode {
+ u8 dmac_sel_en; /* Use lowest 2 bit as sel_mode, bit 7 as enable */
+ u8 rsv[23];
+};
+
+#define HCLGE_CFG_FUNC_MTA_ACCEPT_B 0x0
+struct hclge_cfg_func_mta_filter {
+ u8 accept; /* Only used lowest 1 bit */
+ u8 function_id;
+ u8 rsv[22];
+};
+
+#define HCLGE_CFG_MTA_ITEM_ACCEPT_B 0x0
+#define HCLGE_CFG_MTA_ITEM_IDX_S 0x0
+#define HCLGE_CFG_MTA_ITEM_IDX_M (0xfff << HCLGE_CFG_MTA_ITEM_IDX_S)
+struct hclge_cfg_func_mta_item {
+ u16 item_idx; /* Only used lowest 12 bit */
+ u8 accept; /* Only used lowest 1 bit */
+ u8 rsv[21];
+};
+
+struct hclge_mac_vlan_add {
+ __le16 flags;
+ __le16 mac_addr_hi16;
+ __le32 mac_addr_lo32;
+ __le32 mac_addr_msk_hi32;
+ __le16 mac_addr_msk_lo16;
+ __le16 vlan_tag;
+ __le16 ingress_port;
+ __le16 egress_port;
+ u8 rsv[4];
+};
+
+#define HNS3_MAC_VLAN_CFG_FLAG_BIT 0
+struct hclge_mac_vlan_remove {
+ __le16 flags;
+ __le16 mac_addr_hi16;
+ __le32 mac_addr_lo32;
+ __le32 mac_addr_msk_hi32;
+ __le16 mac_addr_msk_lo16;
+ __le16 vlan_tag;
+ __le16 ingress_port;
+ __le16 egress_port;
+ u8 rsv[4];
+};
+
+struct hclge_vlan_filter_ctrl {
+ u8 vlan_type;
+ u8 vlan_fe;
+ u8 rsv[22];
+};
+
+struct hclge_vlan_filter_pf_cfg {
+ u8 vlan_offset;
+ u8 vlan_cfg;
+ u8 rsv[2];
+ u8 vlan_offset_bitmap[20];
+};
+
+struct hclge_vlan_filter_vf_cfg {
+ u16 vlan_id;
+ u8 resp_code;
+ u8 rsv;
+ u8 vlan_cfg;
+ u8 rsv1[3];
+ u8 vf_bitmap[16];
+};
+
+struct hclge_cfg_com_tqp_queue {
+ __le16 tqp_id;
+ __le16 stream_id;
+ u8 enable;
+ u8 rsv[19];
+};
+
+struct hclge_cfg_tx_queue_pointer {
+ __le16 tqp_id;
+ __le16 tx_tail;
+ __le16 tx_head;
+ __le16 fbd_num;
+ __le16 ring_offset;
+ u8 rsv[14];
+};
+
+#define HCLGE_TSO_MSS_MIN_S 0
+#define HCLGE_TSO_MSS_MIN_M (0x3FFF << HCLGE_TSO_MSS_MIN_S)
+
+#define HCLGE_TSO_MSS_MAX_S 16
+#define HCLGE_TSO_MSS_MAX_M (0x3FFF << HCLGE_TSO_MSS_MAX_S)
+
+struct hclge_cfg_tso_status {
+ __le16 tso_mss_min;
+ __le16 tso_mss_max;
+ u8 rsv[20];
+};
+
+#define HCLGE_TSO_MSS_MIN 256
+#define HCLGE_TSO_MSS_MAX 9668
+
+#define HCLGE_TQP_RESET_B 0
+struct hclge_reset_tqp_queue {
+ __le16 tqp_id;
+ u8 reset_req;
+ u8 ready_to_reset;
+ u8 rsv[20];
+};
+
+#define HCLGE_DEFAULT_TX_BUF 0x4000 /* 16k bytes */
+#define HCLGE_TOTAL_PKT_BUF 0x108000 /* 1.03125M bytes */
+#define HCLGE_DEFAULT_DV 0xA000 /* 40k byte */
+
+#define HCLGE_TYPE_CRQ 0
+#define HCLGE_TYPE_CSQ 1
+#define HCLGE_NIC_CSQ_BASEADDR_L_REG 0x27000
+#define HCLGE_NIC_CSQ_BASEADDR_H_REG 0x27004
+#define HCLGE_NIC_CSQ_DEPTH_REG 0x27008
+#define HCLGE_NIC_CSQ_TAIL_REG 0x27010
+#define HCLGE_NIC_CSQ_HEAD_REG 0x27014
+#define HCLGE_NIC_CRQ_BASEADDR_L_REG 0x27018
+#define HCLGE_NIC_CRQ_BASEADDR_H_REG 0x2701c
+#define HCLGE_NIC_CRQ_DEPTH_REG 0x27020
+#define HCLGE_NIC_CRQ_TAIL_REG 0x27024
+#define HCLGE_NIC_CRQ_HEAD_REG 0x27028
+#define HCLGE_NIC_CMQ_EN_B 16
+#define HCLGE_NIC_CMQ_ENABLE BIT(HCLGE_NIC_CMQ_EN_B)
+#define HCLGE_NIC_CMQ_DESC_NUM 1024
+#define HCLGE_NIC_CMQ_DESC_NUM_S 3
+
+int hclge_cmd_init(struct hclge_dev *hdev);
+static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
+{
+ writel(value, base + reg);
+}
+
+#define hclge_write_dev(a, reg, value) \
+ hclge_write_reg((a)->io_base, (reg), (value))
+#define hclge_read_dev(a, reg) \
+ hclge_read_reg((a)->io_base, (reg))
+
+static inline u32 hclge_read_reg(u8 __iomem *base, u32 reg)
+{
+ u8 __iomem *reg_addr = READ_ONCE(base);
+
+ return readl(reg_addr + reg);
+}
+
+#define HCLGE_SEND_SYNC(flag) \
+ ((flag) & HCLGE_CMD_FLAG_NO_INTR)
+
+struct hclge_hw;
+enum hclge_cmd_status hclge_cmd_send(struct hclge_hw *hw,
+ struct hclge_desc *desc, int num);
+void hclge_cmd_setup_basic_desc(struct hclge_desc *desc,
+ enum hclge_opcode_type opcode, bool is_read);
+
+void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read);
+int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
+ struct hclge_promisc_param *param);
+
+enum hclge_cmd_status hclge_cmd_mdio_write(struct hclge_hw *hw,
+ struct hclge_desc *desc);
+enum hclge_cmd_status hclge_cmd_mdio_read(struct hclge_hw *hw,
+ struct hclge_desc *desc);
+
+void hclge_destroy_cmd_queue(struct hclge_hw *hw);
+#endif
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| Date | 2017-06-17 19:30 +0200 |
| Subject | [PATCH V3 net-next 8/8] net: hns3: Add HNS3 driver to kernel build framework & MAINTAINERS |
| Message-ID | <tTpHQ-1Qt-9@gated-at.bofh.it> |
| In reply to | #1668370 |
This patch updates the MAINTAINERS file with HNS3 Ethernet driver maintainers names and other details. This also introduces the new Makefiles required to build the HNS3 Ethernet driver and updates the existing Kconfig file in the hisilicon folder. Signed-off-by: Salil Mehta <salil.mehta@huawei.com> --- Patch V3: Addressed below errors: 1. Intel kbuild: https://lkml.org/lkml/2017/6/14/313 2. Intel Kbuild: https://lkml.org/lkml/2017/6/14/636 Patch V2: No change Patch V1: Initial Submit --- MAINTAINERS | 8 +++++++ drivers/net/ethernet/hisilicon/Kconfig | 27 ++++++++++++++++++++++ drivers/net/ethernet/hisilicon/Makefile | 1 + drivers/net/ethernet/hisilicon/hns3/Makefile | 7 ++++++ .../net/ethernet/hisilicon/hns3/hns3pf/Makefile | 11 +++++++++ 5 files changed, 54 insertions(+) create mode 100644 drivers/net/ethernet/hisilicon/hns3/Makefile create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile diff --git a/MAINTAINERS b/MAINTAINERS index 8b8249b..cda0e80 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6070,6 +6070,14 @@ S: Maintained F: drivers/net/ethernet/hisilicon/ F: Documentation/devicetree/bindings/net/hisilicon*.txt +HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3) +M: Yisen Zhuang <yisen.zhuang@huawei.com> +M: Salil Mehta <salil.mehta@huawei.com> +L: netdev@vger.kernel.org +W: http://www.hisilicon.com +S: Maintained +F: drivers/net/ethernet/hisilicon/hns3/ + HISILICON ROCE DRIVER M: Lijun Ou <oulijun@huawei.com> M: Wei Hu(Xavier) <xavier.huwei@huawei.com> diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index d11287e..9f8ea28 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -76,4 +76,31 @@ config HNS_ENET This selects the general ethernet driver for HNS. This module make use of any HNS AE driver, such as HNS_DSAF +config HNS3 + tristate "Hisilicon Network Subsystem Support HNS3 (Framework)" + depends on PCI + ---help--- + This selects the framework support for Hisilicon Network Subsystem 3. + This layer facilitates clients like ENET, RoCE and user-space ethernet + drivers(like ODP)to register with HNAE devices and their associated + operations. + +config HNS3_HCLGE + tristate "Hisilicon HNS3 HCLGE Acceleration Engine & Compatibility Layer Support" + depends on PCI_MSI + select HNS3 + ---help--- + This selects the HNS3_HCLGE network acceleration engine & its hardware + compatibility layer. The engine would be used in Hisilicon hip08 family of + SoCs and further upcoming SoCs. + +config HNS3_ENET + tristate "Hisilicon HNS3 Ethernet Device Support" + depends on 64BIT && PCI + select HNS3 + ---help--- + This selects the Ethernet Driver for Hisilicon Network Subsystem 3 for hip08 + family of SoCs. This module depends upon HNAE3 driver to access the HNAE3 + devices and their associated operations. + endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile index 8661695..3828c43 100644 --- a/drivers/net/ethernet/hisilicon/Makefile +++ b/drivers/net/ethernet/hisilicon/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_HIX5HD2_GMAC) += hix5hd2_gmac.o obj-$(CONFIG_HIP04_ETH) += hip04_eth.o obj-$(CONFIG_HNS_MDIO) += hns_mdio.o obj-$(CONFIG_HNS) += hns/ +obj-$(CONFIG_HNS3) += hns3/ obj-$(CONFIG_HISI_FEMAC) += hisi_femac.o diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile new file mode 100644 index 0000000..5e53735 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the HISILICON network device drivers. +# + +obj-$(CONFIG_HNS3) += hns3pf/ + +obj-$(CONFIG_HNS3) +=hnae3.o diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile b/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile new file mode 100644 index 0000000..c0a92b5 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the HISILICON network device drivers. +# + +ccflags-y := -Idrivers/net/ethernet/hisilicon/hns3 + +obj-$(CONFIG_HNS3_HCLGE) += hclge.o +hclge-objs =hclge_main.o hclge_cmd.o hclge_mdio.o hclge_tm.o + +obj-$(CONFIG_HNS3_ENET) += hns3.o +hns3-objs = hns3_enet.o hns3_ethtool.o -- 2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| Date | 2017-06-17 19:30 +0200 |
| Subject | [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework |
| Message-ID | <tTpHQ-1Qt-7@gated-at.bofh.it> |
| In reply to | #1668370 |
This patch adds the support of the HNAE3 (Hisilicon Network
Acceleration Engine 3) framework support to the HNS3 driver.
Framework facilitates clients like ENET(HNS3 Ethernet Driver), RoCE
and user-space Ethernet drivers (like ODP etc.) to register with HNAE3
devices and their associated operations.
Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: lipeng <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Yisen Zhuang <yisen.zhuang@huawei.com>
---
Patch V3: Addressed comments
1. Andrew Lunn: https://lkml.org/lkml/2017/6/13/1025
Patch V2: No change
Patch V1: Initial Submit
---
drivers/net/ethernet/hisilicon/hns3/hnae3.c | 305 +++++++++++++++++++
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 449 ++++++++++++++++++++++++++++
2 files changed, 754 insertions(+)
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hnae3.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hnae3.h
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
new file mode 100644
index 0000000..77a665d
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2016-2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include "hnae3.h"
+
+static LIST_HEAD(hnae3_ae_algo_list);
+static LIST_HEAD(hnae3_client_list);
+static LIST_HEAD(hnae3_ae_dev_list);
+
+static DEFINE_SPINLOCK(hnae3_list_ae_algo_lock);
+static DEFINE_SPINLOCK(hnae3_list_client_lock);
+static DEFINE_SPINLOCK(hnae3_list_ae_dev_lock);
+
+static void hnae3_list_add(spinlock_t *lock, struct list_head *node,
+ struct list_head *head)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ list_add_tail(node, head);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void hnae3_list_del(spinlock_t *lock, struct list_head *node)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ list_del(node);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static bool hnae3_client_match(enum hnae3_client_type client_type,
+ enum hnae3_dev_type dev_type)
+{
+ if (dev_type == HNAE3_DEV_KNIC) {
+ switch (client_type) {
+ case HNAE3_CLIENT_KNIC:
+ case HNAE3_CLIENT_ROCE:
+ return true;
+ default:
+ return false;
+ }
+ } else if (dev_type == HNAE3_DEV_UNIC) {
+ switch (client_type) {
+ case HNAE3_CLIENT_UNIC:
+ return true;
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
+int hnae3_register_client(struct hnae3_client *client)
+{
+ struct hnae3_client *client_tmp;
+ struct hnae3_ae_dev *ae_dev;
+ int ret;
+
+ /* One system should only have one client for every type */
+ list_for_each_entry(client_tmp, &hnae3_client_list, node) {
+ if (client_tmp->type == client->type)
+ return 0;
+ }
+
+ hnae3_list_add(&hnae3_list_client_lock, &client->node,
+ &hnae3_client_list);
+
+ /* Check if there are matched ae_dev */
+ list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
+ if (hnae3_client_match(client->type, ae_dev->dev_type) &&
+ hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) {
+ if (ae_dev->ops && ae_dev->ops->register_client) {
+ ret = ae_dev->ops->register_client(client,
+ ae_dev);
+ if (ret) {
+ dev_err(&ae_dev->pdev->dev,
+ "init ae_dev error.\n");
+ return ret;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hnae3_register_client);
+
+void hnae3_unregister_client(struct hnae3_client *client)
+{
+ struct hnae3_ae_dev *ae_dev;
+
+ /* Check if there are matched ae_dev */
+ list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
+ if (hnae3_client_match(client->type, ae_dev->dev_type) &&
+ hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
+ if (ae_dev->ops && ae_dev->ops->unregister_client)
+ ae_dev->ops->unregister_client(client, ae_dev);
+ }
+ hnae3_list_del(&hnae3_list_client_lock, &client->node);
+}
+EXPORT_SYMBOL(hnae3_unregister_client);
+
+/* hnae_ae_register - register a AE engine to hnae framework
+ * @hdev: the hnae ae engine device
+ * @owner: the module who provides this dev
+ * NOTE: the duplicated name will not be checked
+ */
+int hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
+{
+ struct hnae3_ae_dev *ae_dev;
+ struct hnae3_client *client;
+ const struct pci_device_id *id;
+ int ret;
+
+ hnae3_list_add(&hnae3_list_ae_algo_lock, &ae_algo->node,
+ &hnae3_ae_algo_list);
+
+ /* Check if there are matched ae_dev */
+ list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
+ id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
+ if (!id)
+ continue;
+
+ /* ae_dev init should set flag */
+ ae_dev->ops = ae_algo->ops;
+ ret = ae_algo->ops->init_ae_dev(ae_dev);
+ if (!ret) {
+ hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
+ } else {
+ dev_err(&ae_dev->pdev->dev, "init ae_dev error.\n");
+ return ret;
+ }
+
+ list_for_each_entry(client, &hnae3_client_list, node) {
+ if (hnae3_client_match(client->type,
+ ae_dev->dev_type) &&
+ hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) {
+ if (ae_dev->ops &&
+ ae_dev->ops->register_client) {
+ ret = ae_dev->ops->register_client(
+ client, ae_dev);
+ if (ret) {
+ dev_err(&ae_dev->pdev->dev,
+ "init ae_dev error.\n");
+ return ret;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hnae3_register_ae_algo);
+
+/* hnae_ae_unregister - unregisters a HNAE AE engine
+ * @cdev: the device to unregister
+ */
+void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
+{
+ struct hnae3_ae_dev *ae_dev;
+ struct hnae3_client *client;
+ const struct pci_device_id *id;
+
+ /* Check if there are matched ae_dev */
+ list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
+ id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
+ if (!id)
+ continue;
+
+ /* Check if there are matched client */
+ list_for_each_entry(client, &hnae3_client_list, node) {
+ if (hnae3_client_match(client->type,
+ ae_dev->dev_type) &&
+ hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) {
+ hnae3_unregister_client(client);
+ continue;
+ }
+ }
+
+ ae_algo->ops->uninit_ae_dev(ae_dev);
+ hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
+ }
+
+ hnae3_list_del(&hnae3_list_ae_algo_lock, &ae_algo->node);
+}
+EXPORT_SYMBOL(hnae3_unregister_ae_algo);
+
+/* hnae_ae_register - register a AE engine to hnae framework
+ * @hdev: the hnae ae engine device
+ * @owner: the module who provides this dev
+ * NOTE: the duplicated name will not be checked
+ */
+int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
+{
+ struct hnae3_ae_algo *ae_algo;
+ struct hnae3_client *client;
+ const struct pci_device_id *id;
+ int ret;
+
+ hnae3_list_add(&hnae3_list_ae_dev_lock, &ae_dev->node,
+ &hnae3_ae_dev_list);
+
+ /* Check if there are matched ae_algo */
+ list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
+ id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
+ if (!id)
+ continue;
+
+ ae_dev->ops = ae_algo->ops;
+
+ /* ae_dev init should set flag */
+ ret = ae_dev->ops->init_ae_dev(ae_dev);
+ if (!ret) {
+ hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
+ break;
+ }
+
+ dev_err(&ae_dev->pdev->dev, "init ae_dev error.\n");
+ return ret;
+ }
+
+ if (!ae_dev->ops)
+ return 0;
+
+ list_for_each_entry(client, &hnae3_client_list, node) {
+ if (hnae3_client_match(client->type, ae_dev->dev_type) &&
+ hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) {
+ if (ae_dev->ops && ae_dev->ops->register_client) {
+ ret = ae_dev->ops->register_client(client,
+ ae_dev);
+ if (ret) {
+ dev_err(&ae_dev->pdev->dev,
+ "init ae_dev error.\n");
+ return ret;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hnae3_register_ae_dev);
+
+/* hnae_ae_unregister - unregisters a HNAE AE engine
+ * @cdev: the device to unregister
+ */
+void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
+{
+ struct hnae3_ae_algo *ae_algo;
+ struct hnae3_client *client;
+ const struct pci_device_id *id;
+
+ /* Check if there are matched ae_algo */
+ list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
+ id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
+ if (!id)
+ continue;
+
+ /* Check if there are matched client */
+ list_for_each_entry(client, &hnae3_client_list, node) {
+ if (hnae3_client_match(client->type,
+ ae_dev->dev_type) &&
+ hnae_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B)) {
+ hnae3_unregister_client(client);
+ continue;
+ }
+ }
+
+ ae_algo->ops->uninit_ae_dev(ae_dev);
+ hnae_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
+ }
+
+ hnae3_list_del(&hnae3_list_ae_dev_lock, &ae_dev->node);
+}
+EXPORT_SYMBOL(hnae3_unregister_ae_dev);
+
+static int __init hnae3_init(void)
+{
+ return 0;
+}
+
+static void __exit hnae3_exit(void)
+{
+}
+
+module_init(hnae3_init);
+module_exit(hnae3_exit);
+
+MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
new file mode 100644
index 0000000..2575f30
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2016-2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __HNAE_H
+#define __HNAE_H
+
+/* Names used in this framework:
+ * ae handle (handle):
+ * a set of queues provided by AE
+ * ring buffer queue (rbq):
+ * the channel between upper layer and the AE, can do tx and rx
+ * ring:
+ * a tx or rx channel within a rbq
+ * ring description (desc):
+ * an element in the ring with packet information
+ * buffer:
+ * a memory region referred by desc with the full packet payload
+ *
+ * "num" means a static number set as a parameter, "count" mean a dynamic
+ * number set while running
+ * "cb" means control block
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#define HNAE_DRIVER_VERSION "1.0"
+#define HNAE_DRIVER_NAME "hns3"
+#define HNAE_COPYRIGHT "Copyright(c) 2017 Huawei Corporation."
+#define HNAE_DRIVER_STRING "Hisilicon Network Subsystem Driver"
+#define HNAE_DEFAULT_DEVICE_DESCR "Hisilicon Network Subsystem"
+
+/* Device IDs */
+#define HISILICON 0x19E5
+#define HNAE3_DEV_ID_GE 0xA220
+#define HNAE3_DEV_ID_25GE 0xA221
+#define HNAE3_DEV_ID_25GE_RDMA 0xA222
+#define HNAE3_DEV_ID_25GE_RDMA_MACSEC 0xA223
+#define HNAE3_DEV_ID_50GE_RDMA 0xA224
+#define HNAE3_DEV_ID_50GE_RDMA_MACSEC 0xA225
+#define HNAE3_DEV_ID_100G_RDMA_MACSEC 0xA226
+#define HNAE3_DEV_ID_100G_VF 0xA22E
+#define HNAE3_DEV_ID_100G_RDMA_DCB_PFC_VF 0xA22F
+
+#define HNAE3_CLASS_NAME_SIZE 16
+
+#define HNAE3_DEV_INITED_B 0x0
+#define HNAE_DEV_SUPPORT_ROCE_B 0x1
+
+#define ring_ptr_move_fw(ring, p) \
+ ((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
+#define ring_ptr_move_bw(ring, p) \
+ ((ring)->p = ((ring)->p - 1 + (ring)->desc_num) % (ring)->desc_num)
+
+enum hns_desc_type {
+ DESC_TYPE_SKB,
+ DESC_TYPE_PAGE,
+};
+
+struct hnae3_handle;
+
+struct hnae3_queue {
+ void __iomem *io_base;
+ struct hnae3_ae_algo *ae_algo;
+ struct hnae3_handle *handle;
+ int tqp_index; /* index in a handle */
+ u32 buf_size; /* size for hnae_desc->addr, preset by AE */
+ u16 desc_num; /* total number of desc */
+};
+
+/*hnae3 loop mode*/
+enum hnae3_loop {
+ HNAE3_MAC_INTER_LOOP_MAC,
+ HNAE3_MAC_INTER_LOOP_SERDES,
+ HNAE3_MAC_INTER_LOOP_PHY,
+ HNAE3_MAC_LOOP_NONE,
+};
+
+enum hnae3_client_type {
+ HNAE3_CLIENT_KNIC,
+ HNAE3_CLIENT_UNIC,
+ HNAE3_CLIENT_ROCE,
+};
+
+enum hnae3_dev_type {
+ HNAE3_DEV_KNIC,
+ HNAE3_DEV_UNIC,
+};
+
+/* mac media type */
+enum hnae3_media_type {
+ HNAE3_MEDIA_TYPE_UNKNOWN,
+ HNAE3_MEDIA_TYPE_FIBER,
+ HNAE3_MEDIA_TYPE_COPPER,
+ HNAE3_MEDIA_TYPE_BACKPLANE,
+};
+
+struct hnae3_vector_info {
+ u8 __iomem *io_addr;
+ int vector;
+};
+
+#define HNAE3_RING_TYPE_B 0
+#define HNAE3_RING_TYPE_TX 0
+#define HNAE3_RING_TYPE_RX 1
+
+struct hnae3_ring_chain_node {
+ struct hnae3_ring_chain_node *next;
+ u32 tqp_index;
+ u32 flag;
+};
+
+#define HNAE3_IS_TX_RING(node) \
+ (((node)->flag & (1 << HNAE3_RING_TYPE_B)) == HNAE3_RING_TYPE_TX)
+
+struct hnae3_client_ops {
+ int (*init_instance)(struct hnae3_handle *handle);
+ void (*uninit_instance)(struct hnae3_handle *handle, bool reset);
+ void (*link_status_change)(struct hnae3_handle *handle, bool state);
+};
+
+#define HNAE3_CLIENT_NAME_LENGTH 16
+struct hnae3_client {
+ char name[HNAE3_CLIENT_NAME_LENGTH];
+ u16 version;
+ unsigned long state;
+ enum hnae3_client_type type;
+ const struct hnae3_client_ops *ops;
+ struct list_head node;
+};
+
+struct hnae3_ae_dev {
+ struct pci_dev *pdev;
+ struct hnae3_ae_ops *ops;
+ struct list_head node;
+ u32 flag;
+ enum hnae3_dev_type dev_type;
+ void *priv;
+};
+
+/* This struct defines the operation on the handle.
+ *
+ * init_ae_dev(): (mandatory)
+ * Get PF configure from pci_dev and initialize PF hardware
+ * uninit_ae_dev()
+ * Disable PF device and release PF resource
+ * register_client
+ * Register client to ae_dev
+ * unregister_client()
+ * Unregister client from ae_dev
+ * start()
+ * Enable the hardware
+ * stop()
+ * Disable the hardware
+ * get_status()
+ * Get the carrier state of the back channel of the handle, 1 for ok, 0 for
+ * non-ok
+ * get_ksettings_an_result()
+ * Get negotiation status,speed and duplex
+ * update_speed_duplex_h()
+ * Update hardware speed and duplex
+ * get_media_type()
+ * Get media type of MAC
+ * adjust_link()
+ * Adjust link status
+ * set_loopback()
+ * Set loopback
+ * set_promisc_mode
+ * Set promisc mode
+ * set_mtu()
+ * set mtu
+ * get_pauseparam()
+ * get tx and rx of pause frame use
+ * set_pauseparam()
+ * set tx and rx of pause frame use
+ * set_autoneg()
+ * set auto autonegotiation of pause frame use
+ * get_autoneg()
+ * get auto autonegotiation of pause frame use
+ * get_coalesce_usecs()
+ * get usecs to delay a TX interrupt after a packet is sent
+ * get_rx_max_coalesced_frames()
+ * get Maximum number of packets to be sent before a TX interrupt.
+ * set_coalesce_usecs()
+ * set usecs to delay a TX interrupt after a packet is sent
+ * set_coalesce_frames()
+ * set Maximum number of packets to be sent before a TX interrupt.
+ * get_mac_addr()
+ * get mac address
+ * set_mac_addr()
+ * set mac address
+ * add_uc_addr
+ * Add unicast addr to mac table
+ * rm_uc_addr
+ * Remove unicast addr from mac table
+ * set_mc_addr()
+ * Set multicast address
+ * add_mc_addr
+ * Add multicast address to mac table
+ * rm_mc_addr
+ * Remove multicast address from mac table
+ * update_stats()
+ * Update Old network device statistics
+ * get_ethtool_stats()
+ * Get ethtool network device statistics
+ * get_strings()
+ * Get a set of strings that describe the requested objects
+ * get_sset_count()
+ * Get number of strings that @get_strings will write
+ * update_led_status()
+ * Update the led status
+ * set_led_id()
+ * Set led id
+ * get_regs()
+ * Get regs dump
+ * get_regs_len()
+ * Get the len of the regs dump
+ * get_rss_key_size()
+ * Get rss key size
+ * get_rss_indir_size()
+ * Get rss indirection table size
+ * get_rss()
+ * Get rss table
+ * set_rss()
+ * Set rss table
+ * get_tc_size()
+ * Get tc size of handle
+ * get_vector()
+ * Get vector number and vector infomation
+ * map_ring_to_vector()
+ * Map rings to vector
+ * unmap_ring_from_vector()
+ * Unmap rings from vector
+ * add_tunnel_udp()
+ * Add tunnel information to hardware
+ * del_tunnel_udp()
+ * Delete tunnel information from hardware
+ * reset_queue()
+ * Reset queue
+ * get_fw_version()
+ * Get firmware version
+ * get_mdix_mode()
+ * Get media typr of phy
+ * set_vlan_filter()
+ * Set vlan filter config of Ports
+ * set_vf_vlan_filter()
+ * Set vlan filter config of vf
+ */
+struct hnae3_ae_ops {
+ int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
+ void (*uninit_ae_dev)(struct hnae3_ae_dev *ae_dev);
+
+ int (*register_client)(struct hnae3_client *client,
+ struct hnae3_ae_dev *ae_dev);
+ void (*unregister_client)(struct hnae3_client *client,
+ struct hnae3_ae_dev *ae_dev);
+ int (*start)(struct hnae3_handle *handle);
+ void (*stop)(struct hnae3_handle *handle);
+ int (*get_status)(struct hnae3_handle *handle);
+ void (*get_ksettings_an_result)(struct hnae3_handle *handle,
+ u8 *auto_neg, u32 *speed, u8 *duplex);
+
+ int (*update_speed_duplex_h)(struct hnae3_handle *handle);
+ int (*cfg_mac_speed_dup_h)(struct hnae3_handle *handle, int speed,
+ u8 duplex);
+
+ void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type);
+ void (*adjust_link)(struct hnae3_handle *handle, int speed, int duplex);
+ int (*set_loopback)(struct hnae3_handle *handle,
+ enum hnae3_loop loop_mode, bool en);
+
+ void (*set_promisc_mode)(struct hnae3_handle *handle, u32 en);
+ int (*set_mtu)(struct hnae3_handle *handle, int new_mtu);
+
+ void (*get_pauseparam)(struct hnae3_handle *handle,
+ u32 *auto_neg, u32 *rx_en, u32 *tx_en);
+ int (*set_pauseparam)(struct hnae3_handle *handle,
+ u32 auto_neg, u32 rx_en, u32 tx_en);
+
+ int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
+ int (*get_autoneg)(struct hnae3_handle *handle);
+
+ void (*get_coalesce_usecs)(struct hnae3_handle *handle,
+ u32 *tx_usecs, u32 *rx_usecs);
+ void (*get_rx_max_coalesced_frames)(struct hnae3_handle *handle,
+ u32 *tx_frames, u32 *rx_frames);
+ int (*set_coalesce_usecs)(struct hnae3_handle *handle, u32 timeout);
+ int (*set_coalesce_frames)(struct hnae3_handle *handle,
+ u32 coalesce_frames);
+ void (*get_coalesce_range)(struct hnae3_handle *handle,
+ u32 *tx_frames_low, u32 *rx_frames_low,
+ u32 *tx_frames_high, u32 *rx_frames_high,
+ u32 *tx_usecs_low, u32 *rx_usecs_low,
+ u32 *tx_usecs_high, u32 *rx_usecs_high);
+
+ void (*get_mac_addr)(struct hnae3_handle *handle, u8 *p);
+ int (*set_mac_addr)(struct hnae3_handle *handle, void *p);
+ int (*add_uc_addr)(struct hnae3_handle *handle,
+ const unsigned char *addr);
+ int (*rm_uc_addr)(struct hnae3_handle *handle,
+ const unsigned char *addr);
+ int (*set_mc_addr)(struct hnae3_handle *handle, void *addr);
+ int (*add_mc_addr)(struct hnae3_handle *handle,
+ const unsigned char *addr);
+ int (*rm_mc_addr)(struct hnae3_handle *handle,
+ const unsigned char *addr);
+
+ void (*set_tso_stats)(struct hnae3_handle *handle, int enable);
+ void (*update_stats)(struct hnae3_handle *handle,
+ struct net_device_stats *net_stats);
+ void (*get_stats)(struct hnae3_handle *handle, u64 *data);
+
+ void (*get_strings)(struct hnae3_handle *handle,
+ u32 stringset, u8 *data);
+ int (*get_sset_count)(struct hnae3_handle *handle, int stringset);
+
+ void (*get_regs)(struct hnae3_handle *handle, void *data);
+ int (*get_regs_len)(struct hnae3_handle *handle);
+
+ u32 (*get_rss_key_size)(struct hnae3_handle *handle);
+ u32 (*get_rss_indir_size)(struct hnae3_handle *handle);
+ int (*get_rss)(struct hnae3_handle *handle, u32 *indir, u8 *key,
+ u8 *hfunc);
+ int (*set_rss)(struct hnae3_handle *handle, const u32 *indir,
+ const u8 *key, const u8 hfunc);
+
+ int (*get_tc_size)(struct hnae3_handle *handle);
+
+ int (*get_vector)(struct hnae3_handle *handle, u16 vector_num,
+ struct hnae3_vector_info *vector_info);
+ int (*map_ring_to_vector)(struct hnae3_handle *handle,
+ int vector_num,
+ struct hnae3_ring_chain_node *vr_chain);
+ int (*unmap_ring_from_vector)(struct hnae3_handle *handle,
+ int vector_num,
+ struct hnae3_ring_chain_node *vr_chain);
+
+ int (*add_tunnel_udp)(struct hnae3_handle *handle, u16 port_num);
+ int (*del_tunnel_udp)(struct hnae3_handle *handle, u16 port_num);
+
+ void (*reset_queue)(struct hnae3_handle *handle, u16 queue_id);
+ u32 (*get_fw_version)(struct hnae3_handle *handle);
+ void (*get_mdix_mode)(struct hnae3_handle *handle,
+ u8 *tp_mdix_ctrl, u8 *tp_mdix);
+
+ int (*set_vlan_filter)(struct hnae3_handle *handle, __be16 proto,
+ u16 vlan_id, bool is_kill);
+ int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
+ u16 vlan, u8 qos, __be16 proto);
+};
+
+struct hnae3_ae_algo {
+ struct hnae3_ae_ops *ops;
+ struct list_head node;
+ char name[HNAE3_CLASS_NAME_SIZE];
+ const struct pci_device_id *pdev_id_table;
+};
+
+#define HNAE3_INT_NAME_LEN (IFNAMSIZ + 16)
+#define HNAE3_ITR_COUNTDOWN_START 100
+
+struct hnae3_tc_info {
+ u16 tqp_offset; /* TQP offset from base TQP */
+ u16 tqp_count; /* Total TQPs */
+ u8 up; /* user priority */
+ u8 tc; /* TC index */
+ bool enable; /* If this TC is enable or not */
+};
+
+#define HNAE3_MAX_TC 8
+struct hnae3_knic_private_info {
+ struct net_device *netdev; /* Set by KNIC client when init instance */
+ u16 rss_size; /* Allocated RSS queues */
+ u16 rx_buf_len;
+ u16 num_desc;
+
+ u8 num_tc; /* Total number of enabled TCs */
+ struct hnae3_tc_info tc_info[HNAE3_MAX_TC]; /* Idx of array is HW TC */
+
+ u16 num_tqps; /* total number of TQPs in this handle */
+ struct hnae3_queue **tqp; /* array base of all TQPs in this instance */
+};
+
+struct hnae3_roce_private_info {
+ void __iomem *roce_io_base;
+ struct net_device *netdev;
+ int base_vector;
+ int num_vectors;
+};
+
+struct hnae3_unic_private_info {
+ u16 rx_buf_len;
+ u16 num_desc;
+ u16 num_tqps; /* total number of tqps in this handle */
+ struct hnae3_queue **tqp; /* array base of all TQPs of this instance */
+};
+
+#define HNAE3_SUPPORT_MAC_LOOPBACK 1
+#define HNAE3_SUPPORT_PHY_LOOPBACK 2
+#define HNAE3_SUPPORT_SERDES_LOOPBACK 4
+
+struct hnae3_handle {
+ struct hnae3_client *client;
+ struct pci_dev *pdev;
+ void *priv;
+ struct hnae3_ae_algo *ae_algo; /* the class who provides this handle */
+ u64 flags; /* Indicate the capabilities for this handle*/
+
+ union {
+ struct hnae3_knic_private_info kinfo;
+ struct hnae3_unic_private_info uinfo;
+ struct hnae3_roce_private_info rinfo;
+ };
+
+ u32 numa_node_mask; /* for multi-chip support */
+};
+
+#define hnae_set_field(origin, mask, shift, val) \
+ do { \
+ (origin) &= (~(mask)); \
+ (origin) |= ((val) << (shift)) & (mask); \
+ } while (0)
+#define hnae_get_field(origin, mask, shift) (((origin) & (mask)) >> (shift))
+
+#define hnae_set_bit(origin, shift, val) \
+ hnae_set_field((origin), (0x1 << (shift)), (shift), (val))
+#define hnae_get_bit(origin, shift) \
+ hnae_get_field((origin), (0x1 << (shift)), (shift))
+
+int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev);
+void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev);
+
+void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo);
+int hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo);
+
+void hnae3_unregister_client(struct hnae3_client *client);
+int hnae3_register_client(struct hnae3_client *client);
+#endif
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Andrew Lunn <andrew@lunn.ch> |
|---|---|
| Date | 2017-06-17 21:50 +0200 |
| Subject | Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework |
| Message-ID | <tTrTj-3hR-3@gated-at.bofh.it> |
| In reply to | #1668373 |
> +static void hnae3_list_add(spinlock_t *lock, struct list_head *node,
> + struct list_head *head)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(lock, flags);
> + list_add_tail(node, head);
> + spin_unlock_irqrestore(lock, flags);
> +}
> +
> +static void hnae3_list_del(spinlock_t *lock, struct list_head *node)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(lock, flags);
> + list_del(node);
> + spin_unlock_irqrestore(lock, flags);
> +}
> +
> +int hnae3_register_client(struct hnae3_client *client)
> +{
> + struct hnae3_client *client_tmp;
> + struct hnae3_ae_dev *ae_dev;
> + int ret;
> +
> + /* One system should only have one client for every type */
> + list_for_each_entry(client_tmp, &hnae3_client_list, node) {
> + if (client_tmp->type == client->type)
> + return 0;
> + }
> +
> + hnae3_list_add(&hnae3_list_client_lock, &client->node,
> + &hnae3_client_list);
Please could you explain your locking scheme. I don't get it.
Thanks
Andrew
[toc] | [prev] | [next] | [standalone]
| From | Andrew Lunn <andrew@lunn.ch> |
|---|---|
| Date | 2017-06-18 17:10 +0200 |
| Subject | Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework |
| Message-ID | <tTJZT-6Lz-15@gated-at.bofh.it> |
| In reply to | #1668373 |
> +static int __init hnae3_init(void)
> +{
> + return 0;
> +}
> +
> +static void __exit hnae3_exit(void)
> +{
> +}
> +
> +module_init(hnae3_init);
> +module_exit(hnae3_exit);
I think init and exit functions are optional. Since your's don't do
anything useful, please try without them.
Andrew
[toc] | [prev] | [next] | [standalone]
| From | Bo Yu <tsu.yubo@gmail.com> |
|---|---|
| Date | 2017-06-18 18:50 +0200 |
| Subject | Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework |
| Message-ID | <tTLyG-7By-19@gated-at.bofh.it> |
| In reply to | #1668373 |
Hi,
On Sat, Jun 17, 2017 at 06:24:25PM +0100, Salil Mehta wrote:
>+ * Unregister client from ae_dev
>+ * start()
>+ * Enable the hardware
>+ * stop()
>+ * Disable the hardware
>+ * get_status()
>+ * Get the carrier state of the back channel of the handle, 1 for ok, 0 for
>+ * non-ok
>+ * get_ksettings_an_result()
>+ * Get negotiation status,speed and duplex
>+ * update_speed_duplex_h()
>+ * Update hardware speed and duplex
>+ * get_media_type()
>+ * Get media type of MAC
>+ * adjust_link()
>+ * Adjust link status
>+ * set_loopback()
>+ * Set loopback
>+ * set_promisc_mode
>+ * Set promisc mode
>+ * set_mtu()
>+ * set mtu
>+ * get_pauseparam()
>+ * get tx and rx of pause frame use
>+ * set_pauseparam()
>+ * set tx and rx of pause frame use
>+ * set_autoneg()
>+ * set auto autonegotiation of pause frame use
>+ * get_autoneg()
>+ * get auto autonegotiation of pause frame use
>+ * get_coalesce_usecs()
>+ * get usecs to delay a TX interrupt after a packet is sent
>+ * get_rx_max_coalesced_frames()
>+ * get Maximum number of packets to be sent before a TX interrupt.
>+ * set_coalesce_usecs()
>+ * set usecs to delay a TX interrupt after a packet is sent
>+ * set_coalesce_frames()
>+ * set Maximum number of packets to be sent before a TX interrupt.
>+ * get_mac_addr()
>+ * get mac address
>+ * set_mac_addr()
>+ * set mac address
>+ * add_uc_addr
>+ * Add unicast addr to mac table
>+ * rm_uc_addr
>+ * Remove unicast addr from mac table
>+ * set_mc_addr()
>+ * Set multicast address
>+ * add_mc_addr
>+ * Add multicast address to mac table
>+ * rm_mc_addr
>+ * Remove multicast address from mac table
>+ * update_stats()
>+ * Update Old network device statistics
>+ * get_ethtool_stats()
>+ * Get ethtool network device statistics
>+ * get_strings()
>+ * Get a set of strings that describe the requested objects
>+ * get_sset_count()
>+ * Get number of strings that @get_strings will write
>+ * update_led_status()
>+ * Update the led status
>+ * set_led_id()
>+ * Set led id
>+ * get_regs()
>+ * Get regs dump
>+ * get_regs_len()
>+ * Get the len of the regs dump
>+ * get_rss_key_size()
>+ * Get rss key size
>+ * get_rss_indir_size()
>+ * Get rss indirection table size
>+ * get_rss()
>+ * Get rss table
>+ * set_rss()
>+ * Set rss table
>+ * get_tc_size()
>+ * Get tc size of handle
>+ * get_vector()
>+ * Get vector number and vector infomation
Just another spealling : information
Checkpatch will report it also.
>+ * map_ring_to_vector()
>+ * Map rings to vector
>+ * unmap_ring_from_vector()
>+ * Unmap rings from vector
>+ * add_tunnel_udp()
>+ * Add tunnel information to hardware
>+ * del_tunnel_udp()
>+ * Delete tunnel information from hardware
>+ * reset_queue()
>+ * Reset queue
>+ * get_fw_version()
>+ * Get firmware version
>+ * get_mdix_mode()
>+ * Get media typr of phy
>+ * set_vlan_filter()
>+ * Set vlan filter config of Ports
>+ * set_vf_vlan_filter()
>+ * Set vlan filter config of vf
>+ */
>+struct hnae3_ae_ops {
>+ int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
>+ void (*uninit_ae_dev)(struct hnae3_ae_dev *ae_dev);
>+
>+ int (*register_client)(struct hnae3_client *client,
>+ struct hnae3_ae_dev *ae_dev);
>+ void (*unregister_client)(struct hnae3_client *client,
>+ struct hnae3_ae_dev *ae_dev);
>+ int (*start)(struct hnae3_handle *handle);
>+ void (*stop)(struct hnae3_handle *handle);
>+ int (*get_status)(struct hnae3_handle *handle);
>+ void (*get_ksettings_an_result)(struct hnae3_handle *handle,
>+ u8 *auto_neg, u32 *speed, u8 *duplex);
>+
>+ int (*update_speed_duplex_h)(struct hnae3_handle *handle);
>+ int (*cfg_mac_speed_dup_h)(struct hnae3_handle *handle, int speed,
>+ u8 duplex);
>+
>+ void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type);
>+ void (*adjust_link)(struct hnae3_handle *handle, int speed, int duplex);
>+ int (*set_loopback)(struct hnae3_handle *handle,
>+ enum hnae3_loop loop_mode, bool en);
>+
>+ void (*set_promisc_mode)(struct hnae3_handle *handle, u32 en);
>+ int (*set_mtu)(struct hnae3_handle *handle, int new_mtu);
>+
>+ void (*get_pauseparam)(struct hnae3_handle *handle,
>+ u32 *auto_neg, u32 *rx_en, u32 *tx_en);
>+ int (*set_pauseparam)(struct hnae3_handle *handle,
>+ u32 auto_neg, u32 rx_en, u32 tx_en);
>+
>+ int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
>+ int (*get_autoneg)(struct hnae3_handle *handle);
>+
>+ void (*get_coalesce_usecs)(struct hnae3_handle *handle,
>+ u32 *tx_usecs, u32 *rx_usecs);
>+ void (*get_rx_max_coalesced_frames)(struct hnae3_handle *handle,
>+ u32 *tx_frames, u32 *rx_frames);
>+ int (*set_coalesce_usecs)(struct hnae3_handle *handle, u32 timeout);
>+ int (*set_coalesce_frames)(struct hnae3_handle *handle,
>+ u32 coalesce_frames);
>+ void (*get_coalesce_range)(struct hnae3_handle *handle,
>+ u32 *tx_frames_low, u32 *rx_frames_low,
>+ u32 *tx_frames_high, u32 *rx_frames_high,
>+ u32 *tx_usecs_low, u32 *rx_usecs_low,
>+ u32 *tx_usecs_high, u32 *rx_usecs_high);
>+
>+ void (*get_mac_addr)(struct hnae3_handle *handle, u8 *p);
>+ int (*set_mac_addr)(struct hnae3_handle *handle, void *p);
>+ int (*add_uc_addr)(struct hnae3_handle *handle,
>+ const unsigned char *addr);
>+ int (*rm_uc_addr)(struct hnae3_handle *handle,
>+ const unsigned char *addr);
>+ int (*set_mc_addr)(struct hnae3_handle *handle, void *addr);
>+ int (*add_mc_addr)(struct hnae3_handle *handle,
>+ const unsigned char *addr);
>+ int (*rm_mc_addr)(struct hnae3_handle *handle,
>+ const unsigned char *addr);
>+
>+ void (*set_tso_stats)(struct hnae3_handle *handle, int enable);
>+ void (*update_stats)(struct hnae3_handle *handle,
>+ struct net_device_stats *net_stats);
>+ void (*get_stats)(struct hnae3_handle *handle, u64 *data);
>+
>+ void (*get_strings)(struct hnae3_handle *handle,
>+ u32 stringset, u8 *data);
>+ int (*get_sset_count)(struct hnae3_handle *handle, int stringset);
>+
>+ void (*get_regs)(struct hnae3_handle *handle, void *data);
>+ int (*get_regs_len)(struct hnae3_handle *handle);
>+
>+ u32 (*get_rss_key_size)(struct hnae3_handle *handle);
>+ u32 (*get_rss_indir_size)(struct hnae3_handle *handle);
>+ int (*get_rss)(struct hnae3_handle *handle, u32 *indir, u8 *key,
>+ u8 *hfunc);
>+ int (*set_rss)(struct hnae3_handle *handle, const u32 *indir,
>+ const u8 *key, const u8 hfunc);
>+
>+ int (*get_tc_size)(struct hnae3_handle *handle);
>+
>+ int (*get_vector)(struct hnae3_handle *handle, u16 vector_num,
>+ struct hnae3_vector_info *vector_info);
>+ int (*map_ring_to_vector)(struct hnae3_handle *handle,
>+ int vector_num,
>+ struct hnae3_ring_chain_node *vr_chain);
>+ int (*unmap_ring_from_vector)(struct hnae3_handle *handle,
>+ int vector_num,
>+ struct hnae3_ring_chain_node *vr_chain);
>+
>+ int (*add_tunnel_udp)(struct hnae3_handle *handle, u16 port_num);
>+ int (*del_tunnel_udp)(struct hnae3_handle *handle, u16 port_num);
>+
>+ void (*reset_queue)(struct hnae3_handle *handle, u16 queue_id);
>+ u32 (*get_fw_version)(struct hnae3_handle *handle);
>+ void (*get_mdix_mode)(struct hnae3_handle *handle,
>+ u8 *tp_mdix_ctrl, u8 *tp_mdix);
>+
>+ int (*set_vlan_filter)(struct hnae3_handle *handle, __be16 proto,
>+ u16 vlan_id, bool is_kill);
>+ int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
>+ u16 vlan, u8 qos, __be16 proto);
>+};
>+
>+struct hnae3_ae_algo {
>+ struct hnae3_ae_ops *ops;
>+ struct list_head node;
>+ char name[HNAE3_CLASS_NAME_SIZE];
>+ const struct pci_device_id *pdev_id_table;
>+};
>+
>+#define HNAE3_INT_NAME_LEN (IFNAMSIZ + 16)
>+#define HNAE3_ITR_COUNTDOWN_START 100
>+
>+struct hnae3_tc_info {
>+ u16 tqp_offset; /* TQP offset from base TQP */
>+ u16 tqp_count; /* Total TQPs */
>+ u8 up; /* user priority */
>+ u8 tc; /* TC index */
>+ bool enable; /* If this TC is enable or not */
>+};
>+
>+#define HNAE3_MAX_TC 8
>+struct hnae3_knic_private_info {
>+ struct net_device *netdev; /* Set by KNIC client when init instance */
>+ u16 rss_size; /* Allocated RSS queues */
>+ u16 rx_buf_len;
>+ u16 num_desc;
>+
>+ u8 num_tc; /* Total number of enabled TCs */
>+ struct hnae3_tc_info tc_info[HNAE3_MAX_TC]; /* Idx of array is HW TC */
>+
>+ u16 num_tqps; /* total number of TQPs in this handle */
>+ struct hnae3_queue **tqp; /* array base of all TQPs in this instance */
>+};
>+
>+struct hnae3_roce_private_info {
>+ void __iomem *roce_io_base;
>+ struct net_device *netdev;
>+ int base_vector;
>+ int num_vectors;
>+};
>+
>+struct hnae3_unic_private_info {
>+ u16 rx_buf_len;
>+ u16 num_desc;
>+ u16 num_tqps; /* total number of tqps in this handle */
>+ struct hnae3_queue **tqp; /* array base of all TQPs of this instance */
>+};
>+
>+#define HNAE3_SUPPORT_MAC_LOOPBACK 1
>+#define HNAE3_SUPPORT_PHY_LOOPBACK 2
>+#define HNAE3_SUPPORT_SERDES_LOOPBACK 4
>+
>+struct hnae3_handle {
>+ struct hnae3_client *client;
>+ struct pci_dev *pdev;
>+ void *priv;
>+ struct hnae3_ae_algo *ae_algo; /* the class who provides this handle */
>+ u64 flags; /* Indicate the capabilities for this handle*/
>+
>+ union {
>+ struct hnae3_knic_private_info kinfo;
>+ struct hnae3_unic_private_info uinfo;
>+ struct hnae3_roce_private_info rinfo;
>+ };
>+
>+ u32 numa_node_mask; /* for multi-chip support */
>+};
>+
>+#define hnae_set_field(origin, mask, shift, val) \
>+ do { \
>+ (origin) &= (~(mask)); \
>+ (origin) |= ((val) << (shift)) & (mask); \
>+ } while (0)
>+#define hnae_get_field(origin, mask, shift) (((origin) & (mask)) >> (shift))
>+
>+#define hnae_set_bit(origin, shift, val) \
>+ hnae_set_field((origin), (0x1 << (shift)), (shift), (val))
>+#define hnae_get_bit(origin, shift) \
>+ hnae_get_field((origin), (0x1 << (shift)), (shift))
>+
>+int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev);
>+void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev);
>+
>+void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo);
>+int hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo);
>+
>+void hnae3_unregister_client(struct hnae3_client *client);
>+int hnae3_register_client(struct hnae3_client *client);
>+#endif
>--
>2.7.4
>
>
[toc] | [prev] | [next] | [standalone]
| From | Stephen Hemminger <stephen@networkplumber.org> |
|---|---|
| Date | 2017-06-19 19:00 +0200 |
| Subject | Re: [PATCH V3 net-next 2/8] net: hns3: Add support of the HNAE3 framework |
| Message-ID | <tU8bV-5do-43@gated-at.bofh.it> |
| In reply to | #1668373 |
On Sat, 17 Jun 2017 18:24:25 +0100
Salil Mehta <salil.mehta@huawei.com> wrote:
> +
> +/* This struct defines the operation on the handle.
> + *
> + * init_ae_dev(): (mandatory)
> + * Get PF configure from pci_dev and initialize PF hardware
> + * uninit_ae_dev()
> + * Disable PF device and release PF resource
> + * register_client
> + * Register client to ae_dev
> + * unregister_client()
> + * Unregister client from ae_dev
> + * start()
> + * Enable the hardware
> + * stop()
> + * Disable the hardware
> + * get_status()
> + * Get the carrier state of the back channel of the handle, 1 for ok, 0 for
> + * non-ok
> + * get_ksettings_an_result()
> + * Get negotiation status,speed and duplex
> + * update_speed_duplex_h()
> + * Update hardware speed and duplex
> + * get_media_type()
> + * Get media type of MAC
> + * adjust_link()
> + * Adjust link status
> + * set_loopback()
> + * Set loopback
> + * set_promisc_mode
> + * Set promisc mode
> + * set_mtu()
> + * set mtu
> + * get_pauseparam()
> + * get tx and rx of pause frame use
> + * set_pauseparam()
> + * set tx and rx of pause frame use
> + * set_autoneg()
> + * set auto autonegotiation of pause frame use
> + * get_autoneg()
> + * get auto autonegotiation of pause frame use
> + * get_coalesce_usecs()
> + * get usecs to delay a TX interrupt after a packet is sent
> + * get_rx_max_coalesced_frames()
> + * get Maximum number of packets to be sent before a TX interrupt.
> + * set_coalesce_usecs()
> + * set usecs to delay a TX interrupt after a packet is sent
> + * set_coalesce_frames()
> + * set Maximum number of packets to be sent before a TX interrupt.
> + * get_mac_addr()
> + * get mac address
> + * set_mac_addr()
> + * set mac address
> + * add_uc_addr
> + * Add unicast addr to mac table
> + * rm_uc_addr
> + * Remove unicast addr from mac table
> + * set_mc_addr()
> + * Set multicast address
> + * add_mc_addr
> + * Add multicast address to mac table
> + * rm_mc_addr
> + * Remove multicast address from mac table
> + * update_stats()
> + * Update Old network device statistics
> + * get_ethtool_stats()
> + * Get ethtool network device statistics
> + * get_strings()
> + * Get a set of strings that describe the requested objects
> + * get_sset_count()
> + * Get number of strings that @get_strings will write
> + * update_led_status()
> + * Update the led status
> + * set_led_id()
> + * Set led id
> + * get_regs()
> + * Get regs dump
> + * get_regs_len()
> + * Get the len of the regs dump
> + * get_rss_key_size()
> + * Get rss key size
> + * get_rss_indir_size()
> + * Get rss indirection table size
> + * get_rss()
> + * Get rss table
> + * set_rss()
> + * Set rss table
> + * get_tc_size()
> + * Get tc size of handle
> + * get_vector()
> + * Get vector number and vector infomation
> + * map_ring_to_vector()
> + * Map rings to vector
> + * unmap_ring_from_vector()
> + * Unmap rings from vector
> + * add_tunnel_udp()
> + * Add tunnel information to hardware
> + * del_tunnel_udp()
> + * Delete tunnel information from hardware
> + * reset_queue()
> + * Reset queue
> + * get_fw_version()
> + * Get firmware version
> + * get_mdix_mode()
> + * Get media typr of phy
> + * set_vlan_filter()
> + * Set vlan filter config of Ports
> + * set_vf_vlan_filter()
> + * Set vlan filter config of vf
> + */
> +struct hnae3_ae_ops {
> + int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
> + void (*uninit_ae_dev)(struct hnae3_ae_dev *ae_dev);
> +
> + int (*register_client)(struct hnae3_client *client,
> + struct hnae3_ae_dev *ae_dev);
> + void (*unregister_client)(struct hnae3_client *client,
> + struct hnae3_ae_dev *ae_dev);
> + int (*start)(struct hnae3_handle *handle);
> + void (*stop)(struct hnae3_handle *handle);
> + int (*get_status)(struct hnae3_handle *handle);
> + void (*get_ksettings_an_result)(struct hnae3_handle *handle,
> + u8 *auto_neg, u32 *speed, u8 *duplex);
> +
> + int (*update_speed_duplex_h)(struct hnae3_handle *handle);
> + int (*cfg_mac_speed_dup_h)(struct hnae3_handle *handle, int speed,
> + u8 duplex);
> +
> + void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type);
> + void (*adjust_link)(struct hnae3_handle *handle, int speed, int duplex);
> + int (*set_loopback)(struct hnae3_handle *handle,
> + enum hnae3_loop loop_mode, bool en);
> +
> + void (*set_promisc_mode)(struct hnae3_handle *handle, u32 en);
> + int (*set_mtu)(struct hnae3_handle *handle, int new_mtu);
> +
> + void (*get_pauseparam)(struct hnae3_handle *handle,
> + u32 *auto_neg, u32 *rx_en, u32 *tx_en);
> + int (*set_pauseparam)(struct hnae3_handle *handle,
> + u32 auto_neg, u32 rx_en, u32 tx_en);
> +
> + int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
> + int (*get_autoneg)(struct hnae3_handle *handle);
> +
> + void (*get_coalesce_usecs)(struct hnae3_handle *handle,
> + u32 *tx_usecs, u32 *rx_usecs);
> + void (*get_rx_max_coalesced_frames)(struct hnae3_handle *handle,
> + u32 *tx_frames, u32 *rx_frames);
> + int (*set_coalesce_usecs)(struct hnae3_handle *handle, u32 timeout);
> + int (*set_coalesce_frames)(struct hnae3_handle *handle,
> + u32 coalesce_frames);
> + void (*get_coalesce_range)(struct hnae3_handle *handle,
> + u32 *tx_frames_low, u32 *rx_frames_low,
> + u32 *tx_frames_high, u32 *rx_frames_high,
> + u32 *tx_usecs_low, u32 *rx_usecs_low,
> + u32 *tx_usecs_high, u32 *rx_usecs_high);
> +
> + void (*get_mac_addr)(struct hnae3_handle *handle, u8 *p);
> + int (*set_mac_addr)(struct hnae3_handle *handle, void *p);
> + int (*add_uc_addr)(struct hnae3_handle *handle,
> + const unsigned char *addr);
> + int (*rm_uc_addr)(struct hnae3_handle *handle,
> + const unsigned char *addr);
> + int (*set_mc_addr)(struct hnae3_handle *handle, void *addr);
> + int (*add_mc_addr)(struct hnae3_handle *handle,
> + const unsigned char *addr);
> + int (*rm_mc_addr)(struct hnae3_handle *handle,
> + const unsigned char *addr);
> +
> + void (*set_tso_stats)(struct hnae3_handle *handle, int enable);
> + void (*update_stats)(struct hnae3_handle *handle,
> + struct net_device_stats *net_stats);
> + void (*get_stats)(struct hnae3_handle *handle, u64 *data);
> +
> + void (*get_strings)(struct hnae3_handle *handle,
> + u32 stringset, u8 *data);
> + int (*get_sset_count)(struct hnae3_handle *handle, int stringset);
> +
> + void (*get_regs)(struct hnae3_handle *handle, void *data);
> + int (*get_regs_len)(struct hnae3_handle *handle);
> +
> + u32 (*get_rss_key_size)(struct hnae3_handle *handle);
> + u32 (*get_rss_indir_size)(struct hnae3_handle *handle);
> + int (*get_rss)(struct hnae3_handle *handle, u32 *indir, u8 *key,
> + u8 *hfunc);
> + int (*set_rss)(struct hnae3_handle *handle, const u32 *indir,
> + const u8 *key, const u8 hfunc);
> +
> + int (*get_tc_size)(struct hnae3_handle *handle);
> +
> + int (*get_vector)(struct hnae3_handle *handle, u16 vector_num,
> + struct hnae3_vector_info *vector_info);
> + int (*map_ring_to_vector)(struct hnae3_handle *handle,
> + int vector_num,
> + struct hnae3_ring_chain_node *vr_chain);
> + int (*unmap_ring_from_vector)(struct hnae3_handle *handle,
> + int vector_num,
> + struct hnae3_ring_chain_node *vr_chain);
> +
> + int (*add_tunnel_udp)(struct hnae3_handle *handle, u16 port_num);
> + int (*del_tunnel_udp)(struct hnae3_handle *handle, u16 port_num);
> +
> + void (*reset_queue)(struct hnae3_handle *handle, u16 queue_id);
> + u32 (*get_fw_version)(struct hnae3_handle *handle);
> + void (*get_mdix_mode)(struct hnae3_handle *handle,
> + u8 *tp_mdix_ctrl, u8 *tp_mdix);
> +
> + int (*set_vlan_filter)(struct hnae3_handle *handle, __be16 proto,
> + u16 vlan_id, bool is_kill);
> + int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
> + u16 vlan, u8 qos, __be16 proto);
> +};
> +
Since ae_ops contains only function pointers. All definitions of it must be const
(and therefore pointers as well).
[toc] | [prev] | [next] | [standalone]
| From | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| Date | 2017-06-17 19:30 +0200 |
| Subject | [PATCH V3 net-next 7/8] net: hns3: Add Ethtool support to HNS3 driver |
| Message-ID | <tTpHQ-1Qt-11@gated-at.bofh.it> |
| In reply to | #1668370 |
This patch adds the support of the Ethtool interface to
the HNS3 Ethernet driver. Various commands to read the
statistics, configure the offloading, loopback selftest etc.
are supported.
Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: lipeng <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Yisen Zhuang <yisen.zhuang@huawei.com>
---
Patch V3: Address below comments:
1. Stephen Hemminger: https://lkml.org/lkml/2017/6/13/974
2. Andrew Lunn: https://lkml.org/lkml/2017/6/13/1037
Patch V2: No change
Patch V1: Initial Submit
---
.../ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c | 878 +++++++++++++++++++++
1 file changed, 878 insertions(+)
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c
new file mode 100644
index 0000000..9cc7712
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c
@@ -0,0 +1,878 @@
+/*
+ * Copyright (c) 2016~2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/etherdevice.h>
+#include "hns3_enet.h"
+
+struct hns3_stats {
+ char stats_string[ETH_GSTRING_LEN];
+ int stats_size;
+ int stats_offset;
+};
+
+/* netdev related stats */
+#define HNS3_NETDEV_STAT(_string, _member) \
+ { _string, \
+ FIELD_SIZEOF(struct rtnl_link_stats64, _member), \
+ offsetof(struct rtnl_link_stats64, _member), \
+ }
+
+static const struct hns3_stats hns3_netdev_stats[] = {
+ /* misc. Rx/Tx statistics */
+ HNS3_NETDEV_STAT("rx_packets", rx_packets),
+ HNS3_NETDEV_STAT("tx_packets", tx_packets),
+ HNS3_NETDEV_STAT("rx_bytes", rx_bytes),
+ HNS3_NETDEV_STAT("tx_bytes", tx_bytes),
+ HNS3_NETDEV_STAT("rx_errors", rx_errors),
+ HNS3_NETDEV_STAT("tx_errors", tx_errors),
+ HNS3_NETDEV_STAT("rx_dropped", rx_dropped),
+ HNS3_NETDEV_STAT("tx_dropped", tx_dropped),
+ HNS3_NETDEV_STAT("multicast", multicast),
+ HNS3_NETDEV_STAT("collisions", collisions),
+
+ /* detailed Rx errors */
+ HNS3_NETDEV_STAT("rx_length_errors", rx_length_errors),
+ HNS3_NETDEV_STAT("rx_over_errors", rx_over_errors),
+ HNS3_NETDEV_STAT("rx_crc_errors", rx_crc_errors),
+ HNS3_NETDEV_STAT("rx_frame_errors", rx_frame_errors),
+ HNS3_NETDEV_STAT("rx_fifo_errors", rx_fifo_errors),
+ HNS3_NETDEV_STAT("rx_missed_errors", rx_missed_errors),
+
+ /* detailed Tx errors */
+ HNS3_NETDEV_STAT("tx_aborted_errors", tx_aborted_errors),
+ HNS3_NETDEV_STAT("tx_carrier_errors", tx_carrier_errors),
+ HNS3_NETDEV_STAT("tx_fifo_errors", tx_fifo_errors),
+ HNS3_NETDEV_STAT("tx_heartbeat_errors", tx_heartbeat_errors),
+ HNS3_NETDEV_STAT("tx_window_errors", tx_window_errors),
+
+ /* for cslip etc */
+ HNS3_NETDEV_STAT("rx_compressed", rx_compressed),
+ HNS3_NETDEV_STAT("tx_compressed", tx_compressed),
+};
+
+#define HNS3_NETDEV_STATS_COUNT ARRAY_SIZE(hns3_netdev_stats)
+
+/* tqp related stats */
+#define HNS3_TQP_STAT(_string, _member) \
+ { _string, \
+ FIELD_SIZEOF(struct ring_stats, _member), \
+ offsetof(struct hns3_enet_ring, stats), \
+ }
+
+static const struct hns3_stats hns3_txq_stats[] = {
+ /* Tx per-queue statistics */
+ HNS3_TQP_STAT("tx_io_err_cnt", io_err_cnt),
+ HNS3_TQP_STAT("tx_sw_err_cnt", sw_err_cnt),
+ HNS3_TQP_STAT("tx_seg_pkt_cnt", seg_pkt_cnt),
+ HNS3_TQP_STAT("tx_pkts", tx_pkts),
+ HNS3_TQP_STAT("tx_bytes", tx_bytes),
+ HNS3_TQP_STAT("tx_err_cnt", tx_err_cnt),
+ HNS3_TQP_STAT("tx_restart_queue", restart_queue),
+ HNS3_TQP_STAT("tx_busy", tx_busy),
+};
+
+#define HNS3_TXQ_STATS_COUNT ARRAY_SIZE(hns3_txq_stats)
+
+static const struct hns3_stats hns3_rxq_stats[] = {
+ /* Rx per-queue statistics */
+ HNS3_TQP_STAT("rx_io_err_cnt", io_err_cnt),
+ HNS3_TQP_STAT("rx_sw_err_cnt", sw_err_cnt),
+ HNS3_TQP_STAT("rx_seg_pkt_cnt", seg_pkt_cnt),
+ HNS3_TQP_STAT("rx_pkts", rx_pkts),
+ HNS3_TQP_STAT("rx_bytes", rx_bytes),
+ HNS3_TQP_STAT("rx_err_cnt", rx_err_cnt),
+ HNS3_TQP_STAT("rx_reuse_pg_cnt", reuse_pg_cnt),
+ HNS3_TQP_STAT("rx_err_pkt_len", err_pkt_len),
+ HNS3_TQP_STAT("rx_non_vld_descs", non_vld_descs),
+ HNS3_TQP_STAT("rx_err_bd_num", err_bd_num),
+ HNS3_TQP_STAT("rx_l2_err", l2_err),
+ HNS3_TQP_STAT("rx_l3l4_csum_err", l3l4_csum_err),
+};
+
+#define HNS3_RXQ_STATS_COUNT ARRAY_SIZE(hns3_rxq_stats)
+
+#define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT)
+
+struct hns3_link_mode_mapping {
+ u32 hns3_link_mode;
+ u32 ethtool_link_mode;
+};
+
+static const struct hns3_link_mode_mapping hns3_lm_map[] = {
+ {HNS3_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
+ {HNS3_LM_AUTONEG_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
+ {HNS3_LM_TP_BIT, ETHTOOL_LINK_MODE_TP_BIT},
+ {HNS3_LM_PAUSE_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
+ {HNS3_LM_BACKPLANE_BIT, ETHTOOL_LINK_MODE_Backplane_BIT},
+ {HNS3_LM_10BASET_HALF_BIT, ETHTOOL_LINK_MODE_10baseT_Half_BIT},
+ {HNS3_LM_10BASET_FULL_BIT, ETHTOOL_LINK_MODE_10baseT_Full_BIT},
+ {HNS3_LM_100BASET_HALF_BIT, ETHTOOL_LINK_MODE_100baseT_Half_BIT},
+ {HNS3_LM_100BASET_FULL_BIT, ETHTOOL_LINK_MODE_100baseT_Full_BIT},
+ {HNS3_LM_1000BASET_FULL_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
+};
+
+#define HNS3_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name) \
+{ \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(hns3_lm_map); i++) { \
+ if ((caps) & hns3_lm_map[i].hns3_link_mode) \
+ __set_bit(hns3_lm_map[i].ethtool_link_mode,\
+ (lk_ksettings)->link_modes.name); \
+ } \
+}
+
+static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop)
+{
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
+ struct hnae3_handle *h = priv->ae_handle;
+ struct hnae3_ae_ops *ops = h->ae_algo->ops;
+ int ret = 0;
+
+ switch (loop) {
+ case HNAE3_MAC_INTER_LOOP_MAC:
+ if (ops->set_loopback)
+ ret = ops->set_loopback(h, loop, true);
+ break;
+ case HNAE3_MAC_LOOP_NONE:
+ if (ops->set_loopback)
+ ret = ops->set_loopback(h,
+ HNAE3_MAC_INTER_LOOP_MAC, false);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!ret) {
+ if (loop == HNAE3_MAC_LOOP_NONE)
+ ops->set_promisc_mode(h, ndev->flags & IFF_PROMISC);
+ else
+ ops->set_promisc_mode(h, 1);
+ }
+ return ret;
+}
+
+static int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode)
+{
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
+ struct hnae3_handle *h = priv->ae_handle;
+ struct hnae3_ae_ops *ops = h->ae_algo->ops;
+ int ret;
+
+ if (ops->start) {
+ ret = ops->start(h);
+ if (ret) {
+ netdev_err(ndev,
+ "error: hns3_lb_up start ops return error:%d\n",
+ ret);
+ return ret;
+ }
+ } else {
+ netdev_err(ndev, "error: hns3_lb_up ops do NOT have start\n");
+ }
+
+ ret = hns3_lp_setup(ndev, loop_mode);
+ if (ret)
+ return ret;
+
+ msleep(200);
+
+ return 0;
+}
+
+static int hns3_lp_down(struct net_device *ndev)
+{
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
+ struct hnae3_handle *h = priv->ae_handle;
+ int ret;
+
+ ret = hns3_lp_setup(ndev, HNAE3_MAC_LOOP_NONE);
+ if (ret)
+ netdev_err(ndev, "lb_setup return error(%d)!\n",
+ ret);
+
+ if (h->ae_algo->ops->stop)
+ h->ae_algo->ops->stop(h);
+
+ usleep_range(10000, 20000);
+
+ return 0;
+}
+
+static void hns3_lp_setup_skb(struct sk_buff *skb)
+{
+ struct hns3_nic_priv *priv;
+ unsigned int frame_size;
+ struct net_device *ndev;
+
+ ndev = skb->dev;
+ priv = netdev_priv(ndev);
+ frame_size = skb->len;
+ memset(skb->data, 0xFF, frame_size);
+ ether_addr_copy(skb->data, ndev->dev_addr);
+ skb->data[5] += 0x1f;
+ frame_size &= ~1ul;
+ memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+ memset(&skb->data[frame_size / 2 + 10], 0xBE, frame_size / 2 - 11);
+ memset(&skb->data[frame_size / 2 + 12], 0xAF, frame_size / 2 - 13);
+}
+
+static bool hns3_lb_check_skb_data(struct sk_buff *skb)
+{
+ unsigned int frame_size;
+ char buff[33]; /* 32B data and the last character '\0' */
+ int check_ok;
+ u32 i;
+
+ frame_size = skb->len;
+ frame_size &= ~1ul;
+ check_ok = 0;
+ if (*(skb->data + 10) == 0xFF) { /* for rx check frame*/
+ if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+ (*(skb->data + frame_size / 2 + 12) == 0xAF))
+ check_ok = 1;
+ }
+
+ if (!check_ok) {
+ for (i = 0; i < skb->len; i++) {
+ snprintf(buff + i % 16 * 2, 3, /* tailing \0*/
+ "%02x", *(skb->data + i));
+ if ((i % 16 == 15) || (i == skb->len - 1))
+ pr_info("%s\n", buff);
+ }
+ return false;
+ }
+ return true;
+}
+
+static u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv,
+ u32 start_ringid,
+ u32 end_ringid,
+ u32 budget)
+{
+ struct hns3_enet_ring *ring;
+ struct sk_buff *skb = NULL;
+ u32 rcv_good_pkt_cnt = 0;
+ int status;
+ u32 i;
+
+ struct net_device *ndev = priv->netdev;
+ unsigned long rx_packets = ndev->stats.rx_packets;
+ unsigned long rx_bytes = ndev->stats.rx_bytes;
+ unsigned long rx_frame_errors = ndev->stats.rx_frame_errors;
+
+ for (i = start_ringid; i <= end_ringid; i++) {
+ skb = NULL;
+ ring = priv->ring_data[i].ring;
+ status = hns3_clean_rx_ring_ex(ring, &skb, budget);
+ if (status > 0 && skb) {
+ if (hns3_lb_check_skb_data(skb))
+ rcv_good_pkt_cnt += 1;
+
+ dev_kfree_skb_any(skb);
+ }
+ }
+ ndev->stats.rx_packets = rx_packets;
+ ndev->stats.rx_bytes = rx_bytes;
+ ndev->stats.rx_frame_errors = rx_frame_errors;
+ return rcv_good_pkt_cnt;
+}
+
+static void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv,
+ u32 start_ringid,
+ u32 end_ringid,
+ u32 budget)
+{
+ struct net_device *ndev = priv->netdev;
+ unsigned long rx_frame_errors = ndev->stats.rx_frame_errors;
+ unsigned long rx_packets = ndev->stats.rx_packets;
+ unsigned long rx_bytes = ndev->stats.rx_bytes;
+ struct netdev_queue *dev_queue;
+ struct hns3_enet_ring *ring;
+ int status;
+ u32 i;
+
+ for (i = start_ringid; i <= end_ringid; i++) {
+ ring = priv->ring_data[i].ring;
+ status = hns3_clean_tx_ring(ring, budget);
+ if (status)
+ dev_err(priv->dev,
+ "hns3_clean_tx_ring failed ,status:%d\n",
+ status);
+
+ dev_queue = netdev_get_tx_queue(ndev,
+ priv->ring_data[i].queue_index);
+ netdev_tx_reset_queue(dev_queue);
+ }
+
+ ndev->stats.rx_packets = rx_packets;
+ ndev->stats.rx_bytes = rx_bytes;
+ ndev->stats.rx_frame_errors = rx_frame_errors;
+}
+
+/* hns3_lp_run_test - run loopback test
+ * @ndev: net device
+ * @mode: loopback type
+ */
+static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode)
+{
+#define HNS3_NIC_LB_TEST_PKT_NUM 1
+#define HNS3_NIC_LB_TEST_RING_ID 0
+#define HNS3_NIC_LB_TEST_FRAME_SIZE 128
+/* Nic loopback test err */
+#define HNS3_NIC_LB_TEST_NO_MEM_ERR 1
+#define HNS3_NIC_LB_TEST_TX_CNT_ERR 2
+#define HNS3_NIC_LB_TEST_RX_CNT_ERR 3
+#define HNS3_NIC_LB_TEST_RX_PKG_ERR 4
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
+ struct hnae3_handle *h = priv->ae_handle;
+ struct hnae3_knic_private_info *kinfo = &h->kinfo;
+ int i, j, lc, good_cnt;
+ netdev_tx_t tx_ret_val;
+ struct sk_buff *skb;
+ unsigned int size;
+ int ret_val = 0;
+
+ size = HNS3_NIC_LB_TEST_FRAME_SIZE;
+ /* Allocate test skb */
+ skb = alloc_skb(size, GFP_KERNEL);
+ if (!skb)
+ return HNS3_NIC_LB_TEST_NO_MEM_ERR;
+
+ /* Place data into test skb */
+ (void)skb_put(skb, size);
+ skb->dev = ndev;
+ hns3_lp_setup_skb(skb);
+ skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID;
+ lc = 1;
+ for (j = 0; j < lc; j++) {
+ /* Reset count of good packets */
+ good_cnt = 0;
+ /* Place 64 packets on the transmit queue */
+ for (i = 0; i < HNS3_NIC_LB_TEST_PKT_NUM; i++) {
+ (void)skb_get(skb);
+ tx_ret_val = (netdev_tx_t)hns3_nic_net_xmit_hw(
+ ndev, skb,
+ &tx_ring_data(priv,
+ skb->queue_mapping));
+ if (tx_ret_val == NETDEV_TX_OK) {
+ good_cnt++;
+ } else {
+ dev_err(priv->dev,
+ "hns3_lb_run_test hns3_nic_net_xmit_hw FAILED %d\n",
+ tx_ret_val);
+ break;
+ }
+ }
+ if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
+ ret_val = HNS3_NIC_LB_TEST_TX_CNT_ERR;
+ dev_err(priv->dev, "mode %d sent fail, cnt=0x%x, budget=0x%x\n",
+ mode, good_cnt,
+ HNS3_NIC_LB_TEST_PKT_NUM);
+ break;
+ }
+
+ /* Allow 100 milliseconds for packets to go from Tx to Rx */
+ msleep(100);
+
+ good_cnt = hns3_lb_check_rx_ring(priv,
+ kinfo->num_tqps,
+ kinfo->num_tqps * 2 - 1,
+ HNS3_NIC_LB_TEST_PKT_NUM);
+ if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
+ ret_val = HNS3_NIC_LB_TEST_RX_CNT_ERR;
+ dev_err(priv->dev, "mode %d recv fail, cnt=0x%x, budget=0x%x\n",
+ mode, good_cnt,
+ HNS3_NIC_LB_TEST_PKT_NUM);
+ break;
+ }
+ hns3_lb_clear_tx_ring(priv,
+ HNS3_NIC_LB_TEST_RING_ID,
+ HNS3_NIC_LB_TEST_RING_ID,
+ HNS3_NIC_LB_TEST_PKT_NUM);
+ }
+
+ /* Free the original skb */
+ kfree_skb(skb);
+
+ return ret_val;
+}
+
+/* hns_nic_self_test - self test
+ * @ndev: net device
+ * @eth_test: test cmd
+ * @data: test result
+ */
+static void hns3_self_test(struct net_device *ndev,
+ struct ethtool_test *eth_test, u64 *data)
+{
+#define HNS3_SELF_TEST_TPYE_NUM 3
+
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
+ struct hnae3_handle *h = priv->ae_handle;
+ int st_param[HNS3_SELF_TEST_TPYE_NUM][2];
+ bool if_running = netif_running(ndev);
+ int test_index = 0;
+ int i;
+
+ st_param[0][0] = HNAE3_MAC_INTER_LOOP_MAC; /* XGE not supported lb */
+ st_param[0][1] = h->flags & HNAE3_SUPPORT_MAC_LOOPBACK;
+ st_param[1][0] = HNAE3_MAC_INTER_LOOP_SERDES;
+ st_param[1][1] = h->flags & HNAE3_SUPPORT_SERDES_LOOPBACK;
+ st_param[2][0] = HNAE3_MAC_INTER_LOOP_PHY;
+ st_param[2][1] = h->flags & HNAE3_SUPPORT_PHY_LOOPBACK;
+
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ set_bit(HNS3_NIC_STATE_TESTING, &priv->state);
+
+ if (if_running)
+ (void)dev_close(ndev);
+
+ for (i = 0; i < HNS3_SELF_TEST_TPYE_NUM; i++) {
+ if (!st_param[i][1])
+ continue; /* NEXT testing */
+
+ data[test_index] = hns3_lp_up(ndev,
+ (enum hnae3_loop)st_param[i][0]);
+ if (!data[test_index]) {
+ data[test_index] = hns3_lp_run_test(
+ ndev,
+ (enum hnae3_loop)st_param[i][0]);
+ (void)hns3_lp_down(ndev);
+ }
+
+ if (data[test_index])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ test_index++;
+ }
+
+ clear_bit(HNS3_NIC_STATE_TESTING, &priv->state);
+
+ if (if_running)
+ (void)dev_open(ndev);
+ }
+ (void)msleep_interruptible(4 * 1000);
+}
+
+static int hns3_get_sset_count(struct net_device *netdev, int stringset)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+ struct hnae3_ae_ops *ops = h->ae_algo->ops;
+
+ if (!ops->get_sset_count) {
+ netdev_err(netdev, "could not get string set count\n");
+ return -EOPNOTSUPP;
+ }
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ return (HNS3_NETDEV_STATS_COUNT +
+ (HNS3_TQP_STATS_COUNT * h->kinfo.num_tqps) +
+ ops->get_sset_count(h, stringset));
+
+ case ETH_SS_TEST:
+ return ops->get_sset_count(h, stringset);
+ }
+
+ return 0;
+}
+
+static u8 *hns3_get_strings_netdev(u8 *data)
+{
+ int i;
+
+ for (i = 0; i < HNS3_NETDEV_STATS_COUNT; i++) {
+ memcpy(data, hns3_netdev_stats[i].stats_string,
+ ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+
+ return data;
+}
+
+static u8 *hns3_get_strings_tqps(struct hnae3_handle *handle, u8 *data)
+{
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
+ int i, j;
+
+ /* get strings for Tx */
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ for (j = 0; j < HNS3_TXQ_STATS_COUNT; j++) {
+ u8 gstr[ETH_GSTRING_LEN];
+
+ sprintf(gstr, "rcb_q%d_", i);
+ strcat(gstr, hns3_txq_stats[j].stats_string);
+
+ memcpy(data, gstr, ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+
+ /* get strings for Rx */
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ for (j = 0; j < HNS3_RXQ_STATS_COUNT; j++) {
+ u8 gstr[ETH_GSTRING_LEN];
+
+ sprintf(gstr, "rcb_q%d_", i);
+ strcat(gstr, hns3_rxq_stats[j].stats_string);
+
+ memcpy(data, gstr, ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+
+ return data;
+}
+
+static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+ struct hnae3_ae_ops *ops = h->ae_algo->ops;
+ char *buff = (char *)data;
+
+ if (!ops->get_strings) {
+ netdev_err(netdev, "could not get strings!\n");
+ return;
+ }
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ buff = hns3_get_strings_netdev(buff);
+ buff = hns3_get_strings_tqps(h, buff);
+ h->ae_algo->ops->get_strings(h, stringset, (u8 *)buff);
+ break;
+ case ETH_SS_TEST:
+ ops->get_strings(h, stringset, data);
+ break;
+ }
+}
+
+static u64 *hns3_get_stats_netdev(struct net_device *netdev, u64 *data)
+{
+ const struct rtnl_link_stats64 *net_stats;
+ struct rtnl_link_stats64 temp;
+ u8 *stat;
+ int i;
+
+ net_stats = dev_get_stats(netdev, &temp);
+
+ for (i = 0; i < HNS3_NETDEV_STATS_COUNT; i++) {
+ stat = (u8 *)net_stats + hns3_netdev_stats[i].stats_offset;
+ *data++ = *(u64 *)stat;
+ }
+
+ return data;
+}
+
+static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data)
+{
+ struct hns3_nic_priv *nic_priv = (struct hns3_nic_priv *)handle->priv;
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
+ struct hns3_enet_ring *ring;
+ u8 *stat;
+ int i;
+
+ /* get stats for Tx */
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ ring = nic_priv->ring_data[i].ring;
+ for (i = 0; i < HNS3_TXQ_STATS_COUNT; i++) {
+ stat = (u8 *)ring + hns3_txq_stats[i].stats_offset;
+ *data++ = *(u64 *)stat;
+ }
+ }
+
+ /* get stats for Rx */
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ ring = nic_priv->ring_data[i + kinfo->num_tqps].ring;
+ for (i = 0; i < HNS3_RXQ_STATS_COUNT; i++) {
+ stat = (u8 *)ring + hns3_rxq_stats[i].stats_offset;
+ *data++ = *(u64 *)stat;
+ }
+ }
+
+ return data;
+}
+
+/* hns3_get_stats - get detail statistics.
+ * @netdev: net device
+ * @stats: statistics info.
+ * @data: statistics data.
+ */
+void hns3_get_stats(struct net_device *netdev, struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+ u64 *p = data;
+
+ if (!h->ae_algo->ops->get_stats || !h->ae_algo->ops->update_stats) {
+ netdev_err(netdev, "could not get any statistics\n");
+ return;
+ }
+
+ h->ae_algo->ops->update_stats(h, &netdev->stats);
+
+ /* get netdev related stats */
+ p = hns3_get_stats_netdev(netdev, p);
+
+ /* get per-queue stats */
+ p = hns3_get_stats_tqps(h, p);
+
+ /* get MAC & other misc hardware stats */
+ h->ae_algo->ops->get_stats(h, p);
+}
+
+static void hns3_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct hns3_nic_priv *priv = netdev_priv(net_dev);
+ struct hnae3_handle *h = priv->ae_handle;
+
+ strncpy(drvinfo->version, HNAE_DRIVER_VERSION,
+ sizeof(drvinfo->version));
+ drvinfo->version[sizeof(drvinfo->version) - 1] = '\0';
+
+ strncpy(drvinfo->driver, HNAE_DRIVER_NAME, sizeof(drvinfo->driver));
+ drvinfo->driver[sizeof(drvinfo->driver) - 1] = '\0';
+
+ strncpy(drvinfo->bus_info, priv->dev->bus->name,
+ sizeof(drvinfo->bus_info));
+ drvinfo->bus_info[ETHTOOL_BUSINFO_LEN - 1] = '\0';
+
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "0x%08x",
+ priv->ae_handle->ae_algo->ops->get_fw_version(h));
+}
+
+static u32 hns3_get_link(struct net_device *net_dev)
+{
+ struct hns3_nic_priv *priv = netdev_priv(net_dev);
+ struct hnae3_handle *h;
+
+ h = priv->ae_handle;
+
+ if (h->ae_algo && h->ae_algo->ops && h->ae_algo->ops->get_status)
+ return h->ae_algo->ops->get_status(h);
+ else
+ return 0;
+}
+
+static void hns3_get_ringparam(struct net_device *net_dev,
+ struct ethtool_ringparam *param)
+{
+ struct hns3_nic_priv *priv = netdev_priv(net_dev);
+ int queue_num = priv->ae_handle->kinfo.num_tqps;
+
+ param->tx_max_pending = HNS3_RING_MAX_PENDING;
+ param->rx_max_pending = HNS3_RING_MAX_PENDING;
+
+ param->tx_pending = priv->ring_data[0].ring->desc_num;
+ param->rx_pending = priv->ring_data[queue_num].ring->desc_num;
+}
+
+static void hns3_get_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *param)
+{
+ struct hns3_nic_priv *priv = netdev_priv(net_dev);
+ struct hnae3_handle *h = priv->ae_handle;
+
+ if (h->ae_algo && h->ae_algo->ops && h->ae_algo->ops->get_pauseparam)
+ h->ae_algo->ops->get_pauseparam(h, ¶m->autoneg,
+ ¶m->rx_pause, ¶m->tx_pause);
+}
+
+static int hns3_get_link_ksettings(struct net_device *net_dev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct hns3_nic_priv *priv = netdev_priv(net_dev);
+ struct hnae3_handle *h = priv->ae_handle;
+ u32 supported_caps;
+ u32 advertised_caps;
+ u8 media_type;
+ u8 link_stat;
+ u8 auto_neg;
+ u8 duplex;
+ u32 speed;
+
+ if (!h->ae_algo || !h->ae_algo->ops)
+ return -ESRCH;
+
+ /* 1.auto_neg&speed&duplex from cmd */
+ if (h->ae_algo->ops->get_ksettings_an_result) {
+ h->ae_algo->ops->get_ksettings_an_result(h, &auto_neg,
+ &speed, &duplex);
+ cmd->base.autoneg = auto_neg;
+ cmd->base.speed = speed;
+ cmd->base.duplex = duplex;
+
+ link_stat = hns3_get_link(net_dev);
+ if (!link_stat) {
+ cmd->base.speed = (u32)SPEED_UNKNOWN;
+ cmd->base.duplex = DUPLEX_UNKNOWN;
+ }
+ }
+
+ /* 2.media_type get from bios parameter block */
+ if (h->ae_algo->ops->get_media_type)
+ h->ae_algo->ops->get_media_type(h, &media_type);
+
+ switch (media_type) {
+ case HNAE3_MEDIA_TYPE_FIBER:
+ cmd->base.port = PORT_FIBRE;
+ supported_caps = HNS3_LM_FIBRE_BIT | HNS3_LM_AUTONEG_BIT |
+ HNS3_LM_PAUSE_BIT | HNS3_LM_1000BASET_FULL_BIT;
+
+ advertised_caps = supported_caps;
+ break;
+ case HNAE3_MEDIA_TYPE_COPPER:
+ cmd->base.port = PORT_TP;
+ supported_caps = HNS3_LM_TP_BIT | HNS3_LM_AUTONEG_BIT |
+ HNS3_LM_PAUSE_BIT | HNS3_LM_1000BASET_FULL_BIT |
+ HNS3_LM_100BASET_FULL_BIT | HNS3_LM_100BASET_HALF_BIT |
+ HNS3_LM_10BASET_FULL_BIT | HNS3_LM_10BASET_HALF_BIT;
+ advertised_caps = supported_caps;
+ break;
+ case HNAE3_MEDIA_TYPE_BACKPLANE:
+ cmd->base.port = PORT_NONE;
+ supported_caps = HNS3_LM_BACKPLANE_BIT | HNS3_LM_PAUSE_BIT |
+ HNS3_LM_AUTONEG_BIT | HNS3_LM_1000BASET_FULL_BIT |
+ HNS3_LM_100BASET_FULL_BIT | HNS3_LM_100BASET_HALF_BIT |
+ HNS3_LM_10BASET_FULL_BIT | HNS3_LM_10BASET_HALF_BIT;
+
+ advertised_caps = supported_caps;
+ break;
+ case HNAE3_MEDIA_TYPE_UNKNOWN:
+ default:
+ cmd->base.port = PORT_OTHER;
+ supported_caps = 0;
+ advertised_caps = 0;
+ break;
+ }
+
+ ethtool_link_ksettings_zero_link_mode(cmd, supported);
+ HNS3_DRV_TO_ETHTOOL_CAPS(supported_caps, cmd, supported)
+
+ ethtool_link_ksettings_zero_link_mode(cmd, advertising);
+ HNS3_DRV_TO_ETHTOOL_CAPS(advertised_caps, cmd, advertising)
+
+ /* 3.mdix_ctrl&mdix get from phy reg */
+ if (h->ae_algo->ops->get_mdix_mode)
+ h->ae_algo->ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl,
+ &cmd->base.eth_tp_mdix);
+ /* 4.mdio_support */
+ cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
+
+ return 0;
+}
+
+static u32 hns3_get_rss_key_size(struct net_device *netdev)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+
+ if (!h->ae_algo || !h->ae_algo->ops ||
+ !h->ae_algo->ops->get_rss_key_size)
+ return -EOPNOTSUPP;
+
+ return h->ae_algo->ops->get_rss_key_size(h);
+}
+
+static u32 hns3_get_rss_indir_size(struct net_device *netdev)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+
+ if (!h->ae_algo || !h->ae_algo->ops ||
+ !h->ae_algo->ops->get_rss_indir_size)
+ return -EOPNOTSUPP;
+
+ return h->ae_algo->ops->get_rss_indir_size(h);
+}
+
+static int hns3_get_rss(struct net_device *netdev, u32 *indir, u8 *key,
+ u8 *hfunc)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+
+ if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss)
+ return -EOPNOTSUPP;
+
+ return h->ae_algo->ops->get_rss(h, indir, key, hfunc);
+}
+
+static int hns3_set_rss(struct net_device *netdev, const u32 *indir,
+ const u8 *key, const u8 hfunc)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+
+ if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss)
+ return -EOPNOTSUPP;
+
+ /* currently we only support Toeplitz hash */
+ if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP)) {
+ netdev_err(netdev,
+ "hash func not supported (only Toeplitz hash)\n");
+ return -EOPNOTSUPP;
+ }
+ if (!indir) {
+ netdev_err(netdev,
+ "set rss failed for indir is empty\n");
+ return -EOPNOTSUPP;
+ }
+
+ return h->ae_algo->ops->set_rss(h, indir, key, hfunc);
+}
+
+static int hns3_get_rxnfc(struct net_device *netdev,
+ struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+
+ if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_tc_size)
+ return -EOPNOTSUPP;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXRINGS:
+ cmd->data = h->ae_algo->ops->get_tc_size(h);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static const struct ethtool_ops hns3_ethtool_ops = {
+ .get_drvinfo = hns3_get_drvinfo,
+ .get_link = hns3_get_link,
+ .get_ringparam = hns3_get_ringparam,
+ .get_pauseparam = hns3_get_pauseparam,
+ .self_test = hns3_self_test,
+ .get_strings = hns3_get_strings,
+ .get_ethtool_stats = hns3_get_stats,
+ .get_sset_count = hns3_get_sset_count,
+ .get_rxnfc = hns3_get_rxnfc,
+ .get_rxfh_key_size = hns3_get_rss_key_size,
+ .get_rxfh_indir_size = hns3_get_rss_indir_size,
+ .get_rxfh = hns3_get_rss,
+ .set_rxfh = hns3_set_rss,
+ .get_link_ksettings = hns3_get_link_ksettings,
+};
+
+void hns3_ethtool_set_ops(struct net_device *ndev)
+{
+ ndev->ethtool_ops = &hns3_ethtool_ops;
+}
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| Date | 2017-06-17 19:30 +0200 |
| Subject | [PATCH V3 net-next 6/8] net: hns3: Add MDIO support to HNS3 Ethernet driver for hip08 SoC |
| Message-ID | <tTpHQ-1Qt-17@gated-at.bofh.it> |
| In reply to | #1668370 |
This patch adds the support of MDIO bus interface for HNS3 driver.
Code provides various interfaces to start and stop the PHY layer
and to read and write the MDIO bus or PHY.
Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: lipeng <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Yisen Zhuang <yisen.zhuang@huawei.com>
---
Patch V3: Addressed Below comments:
1. Florian Fainelli: https://lkml.org/lkml/2017/6/13/963
2. Andrew Lunn: https://lkml.org/lkml/2017/6/13/1039
Patch V2: Addressed below comments:
1. Florian Fainelli: https://lkml.org/lkml/2017/6/10/130
2. Andrew Lunn: https://lkml.org/lkml/2017/6/10/168
Patch V1: Initial Submit
---
.../ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 249 +++++++++++++++++++++
1 file changed, 249 insertions(+)
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
new file mode 100644
index 0000000..5b21c50
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2016~2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+
+#include "hclge_cmd.h"
+#include "hclge_main.h"
+
+enum hclge_mdio_c22_op_seq {
+ HCLGE_MDIO_C22_WRITE = 1,
+ HCLGE_MDIO_C22_READ = 2
+};
+
+#define HCLGE_MDIO_CTRL_START_BIT BIT(0)
+#define HCLGE_MDIO_CTRL_ST_MSK GENMASK(2, 1)
+#define HCLGE_MDIO_CTRL_ST_LSH 1
+#define HCLGE_MDIO_IS_C22(c22) (((c22) << HCLGE_MDIO_CTRL_ST_LSH) & \
+ HCLGE_MDIO_CTRL_ST_MSK)
+
+#define HCLGE_MDIO_CTRL_OP_MSK GENMASK(4, 3)
+#define HCLGE_MDIO_CTRL_OP_LSH 3
+#define HCLGE_MDIO_CTRL_OP(access) \
+ (((access) << HCLGE_MDIO_CTRL_OP_LSH) & HCLGE_MDIO_CTRL_OP_MSK)
+#define HCLGE_MDIO_CTRL_PRTAD_MSK GENMASK(4, 0)
+#define HCLGE_MDIO_CTRL_DEVAD_MSK GENMASK(4, 0)
+
+#define HCLGE_MDIO_STA_VAL(val) ((val) & BIT(0))
+
+struct hclge_mdio_cfg_cmd {
+ u8 ctrl_bit;
+ u8 prtad; /* The external port address */
+ u8 devad; /* The external device address */
+ u8 rsvd;
+ __le16 reserve;
+ __le16 data_wr;
+ __le16 data_rd;
+ __le16 sta;
+};
+
+static int hclge_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
+ u16 data)
+{
+ struct hclge_dev *hdev = (struct hclge_dev *)bus->priv;
+ struct hclge_mdio_cfg_cmd *mdio_cmd;
+ enum hclge_cmd_status status;
+ struct hclge_desc desc;
+ u8 devad;
+
+ if (!bus)
+ return -EINVAL;
+
+ devad = ((regnum >> 16) & 0x1f);
+
+ dev_dbg(&bus->dev, "phy id=%d, devad=%d\n", phy_id, devad);
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, false);
+
+ mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
+
+ mdio_cmd->prtad = phy_id & HCLGE_MDIO_CTRL_PRTAD_MSK;
+ mdio_cmd->data_wr = cpu_to_le16(data);
+ mdio_cmd->devad = devad & HCLGE_MDIO_CTRL_DEVAD_MSK;
+
+ /* Write reg and data */
+ mdio_cmd->ctrl_bit = HCLGE_MDIO_IS_C22(1);
+ mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_OP(HCLGE_MDIO_C22_WRITE);
+ mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_START_BIT;
+
+ status = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (status) {
+ dev_err(&hdev->pdev->dev,
+ "mdio write fail when sending cmd, status is %d.\n",
+ status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int hclge_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ struct hclge_dev *hdev = (struct hclge_dev *)bus->priv;
+ struct hclge_mdio_cfg_cmd *mdio_cmd;
+ enum hclge_cmd_status status;
+ struct hclge_desc desc;
+ u8 devad;
+
+ if (!bus)
+ return -EINVAL;
+
+ devad = ((regnum >> 16) & GENMASK(4, 0));
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, true);
+
+ mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
+
+ dev_dbg(&bus->dev, "phy id=%d, devad=%d\n", phy_id, devad);
+
+ mdio_cmd->prtad = phy_id & HCLGE_MDIO_CTRL_PRTAD_MSK;
+ mdio_cmd->devad = devad & HCLGE_MDIO_CTRL_DEVAD_MSK;
+
+ /* Write reg and data */
+ mdio_cmd->ctrl_bit = HCLGE_MDIO_IS_C22(1);
+ mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_OP(HCLGE_MDIO_C22_WRITE);
+ mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_START_BIT;
+
+ /* Read out phy data */
+ status = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (status) {
+ dev_err(&hdev->pdev->dev,
+ "mdio read fail when get data, status is %d.\n",
+ status);
+ return status;
+ }
+
+ if (HCLGE_MDIO_STA_VAL(mdio_cmd->sta)) {
+ dev_err(&hdev->pdev->dev, "mdio read data error\n");
+ return -EIO;
+ }
+
+ return le16_to_cpu(mdio_cmd->data_rd);
+}
+
+int hclge_mac_mdio_config(struct hclge_dev *hdev)
+{
+ struct hclge_mac *mac = &hdev->hw.mac;
+ struct net_device *ndev = &mac->ndev;
+ struct phy_device *phy_dev;
+ struct mii_bus *mdio_bus;
+ int ret;
+
+ if (hdev->hw.mac.phy_addr >= PHY_MAX_ADDR)
+ return 0;
+
+ SET_NETDEV_DEV(ndev, &hdev->pdev->dev);
+
+ mdio_bus = devm_mdiobus_alloc(&hdev->pdev->dev);
+ if (!mdio_bus) {
+ ret = -ENOMEM;
+ goto err_miibus_alloc;
+ }
+
+ mdio_bus->name = "hisilicon MII bus";
+ mdio_bus->read = hclge_mdio_read;
+ mdio_bus->write = hclge_mdio_write;
+ snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii",
+ dev_name(&hdev->pdev->dev));
+
+ mdio_bus->parent = &hdev->pdev->dev;
+ mdio_bus->priv = hdev;
+ mdio_bus->phy_mask = ~(1 << mac->phy_addr);
+ ret = mdiobus_register(mdio_bus);
+ if (ret) {
+ dev_err(mdio_bus->parent,
+ "Failed to register MDIO bus ret = %#x\n", ret);
+ goto err_mdio_register;
+ }
+
+ phy_dev = mdiobus_get_phy(mdio_bus, mac->phy_addr);
+ if (!phy_dev || IS_ERR(phy_dev)) {
+ dev_err(mdio_bus->parent, "Failed to get phy device\n");
+ ret = -EIO;
+ goto err_mdio_register;
+ }
+
+ phy_dev->irq = mdio_bus->irq[mac->phy_addr];
+ mac->phy_dev = phy_dev;
+
+ return 0;
+
+err_mdio_register:
+ mdiobus_unregister(mdio_bus);
+ mdiobus_free(mdio_bus);
+err_miibus_alloc:
+ return ret;
+}
+
+static void hclge_mac_adjust_link(struct net_device *net_dev)
+{
+ struct hclge_mac *hw_mac;
+ struct hclge_dev *hdev;
+ struct hclge_hw *hw;
+ int duplex;
+ int speed;
+
+ if (!net_dev)
+ return;
+
+ hw_mac = container_of(net_dev, struct hclge_mac, ndev);
+ hw = container_of(hw_mac, struct hclge_hw, mac);
+ hdev = hw->back;
+
+ speed = hw_mac->phy_dev->speed;
+ duplex = hw_mac->phy_dev->duplex;
+
+ /* update antoneg. */
+ hw_mac->autoneg = hw_mac->phy_dev->autoneg;
+
+ if ((hw_mac->speed != speed) || (hw_mac->duplex != duplex))
+ (void)hclge_cfg_mac_speed_dup(hdev, speed, !!duplex);
+}
+
+int hclge_mac_start_phy(struct hclge_dev *hdev)
+{
+ struct hclge_mac *mac = &hdev->hw.mac;
+ struct phy_device *phy_dev = mac->phy_dev;
+ struct net_device *ndev = &mac->ndev;
+ int ret;
+
+ if (!phy_dev)
+ return 0;
+
+ phy_dev->dev_flags = 0;
+
+ ret = phy_connect_direct(ndev, phy_dev,
+ hclge_mac_adjust_link,
+ PHY_INTERFACE_MODE_SGMII);
+ if (unlikely(ret)) {
+ pr_info("phy_connect_direct err");
+ return -ENODEV;
+ }
+
+ phy_dev->supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_1000baseT_Full;
+
+ phy_start(mac->phy_dev);
+
+ return 0;
+}
+
+void hclge_mac_stop_phy(struct hclge_dev *hdev)
+{
+ if (!hdev->hw.mac.phy_dev)
+ return;
+
+ phy_disconnect(hdev->hw.mac.phy_dev);
+ phy_stop(hdev->hw.mac.phy_dev);
+}
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Andrew Lunn <andrew@lunn.ch> |
|---|---|
| Date | 2017-06-19 06:00 +0200 |
| Subject | Re: [PATCH V3 net-next 6/8] net: hns3: Add MDIO support to HNS3 Ethernet driver for hip08 SoC |
| Message-ID | <tTW13-5Of-3@gated-at.bofh.it> |
| In reply to | #1668375 |
On Sat, Jun 17, 2017 at 06:24:29PM +0100, Salil Mehta wrote:
> This patch adds the support of MDIO bus interface for HNS3 driver.
> Code provides various interfaces to start and stop the PHY layer
> and to read and write the MDIO bus or PHY.
>
> Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
> Signed-off-by: lipeng <lipeng321@huawei.com>
> Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
> Signed-off-by: Yisen Zhuang <yisen.zhuang@huawei.com>
> ---
> Patch V3: Addressed Below comments:
> 1. Florian Fainelli: https://lkml.org/lkml/2017/6/13/963
> 2. Andrew Lunn: https://lkml.org/lkml/2017/6/13/1039
It is normal to say what you actually changed.
> Patch V2: Addressed below comments:
> 1. Florian Fainelli: https://lkml.org/lkml/2017/6/10/130
> 2. Andrew Lunn: https://lkml.org/lkml/2017/6/10/168
> Patch V1: Initial Submit
> ---
> .../ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 249 +++++++++++++++++++++
> 1 file changed, 249 insertions(+)
> create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
>
> diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
> new file mode 100644
> index 0000000..5b21c50
> --- /dev/null
> +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
> @@ -0,0 +1,249 @@
> +/*
> + * Copyright (c) 2016~2017 Hisilicon Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/etherdevice.h>
> +#include <linux/kernel.h>
> +
> +#include "hclge_cmd.h"
> +#include "hclge_main.h"
> +
> +enum hclge_mdio_c22_op_seq {
> + HCLGE_MDIO_C22_WRITE = 1,
> + HCLGE_MDIO_C22_READ = 2
> +};
> +
> +#define HCLGE_MDIO_CTRL_START_BIT BIT(0)
> +#define HCLGE_MDIO_CTRL_ST_MSK GENMASK(2, 1)
> +#define HCLGE_MDIO_CTRL_ST_LSH 1
> +#define HCLGE_MDIO_IS_C22(c22) (((c22) << HCLGE_MDIO_CTRL_ST_LSH) & \
> + HCLGE_MDIO_CTRL_ST_MSK)
> +
> +#define HCLGE_MDIO_CTRL_OP_MSK GENMASK(4, 3)
> +#define HCLGE_MDIO_CTRL_OP_LSH 3
> +#define HCLGE_MDIO_CTRL_OP(access) \
> + (((access) << HCLGE_MDIO_CTRL_OP_LSH) & HCLGE_MDIO_CTRL_OP_MSK)
> +#define HCLGE_MDIO_CTRL_PRTAD_MSK GENMASK(4, 0)
> +#define HCLGE_MDIO_CTRL_DEVAD_MSK GENMASK(4, 0)
This all seems overly complex. How about
#define HCLGE_MDIO_CTRL_START_BIT BIT(0)
#define HCLGE_MDIO_C22 BIT(1)
#define HCLGE_MDIO_WRITE (1 << 3)
#define HCLGE_MDIO_READ (2 << 3)
#define HCLGE_MDIO_C22_WRITE (HCLGE_MDIO_CTRL_START_BIT | HCLGE_MDIO_C22 | HCLGE_MDIO_WRITE)
#define HCLGE_MDIO_C22_READ (HCLGE_MDIO_CTRL_START_BIT | HCLGE_MDIO_C22 | HCLGE_MDIO_READ)
#define HCLGE_MDIO_C45_WRITE (HCLGE_MDIO_CTRL_START_BIT | HCLGE_MDIO_WRITE)
#define HCLGE_MDIO_C45_READ (HCLGE_MDIO_CTRL_START_BIT | HCLGE_MDIO_READ)
#define HCLGE_MDIO_STATUS_ERROR BIT(0)
Keep it simple, don't have more defines than what you need.
> +static int hclge_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
> + u16 data)
> +{
> + struct hclge_dev *hdev = (struct hclge_dev *)bus->priv;
> + struct hclge_mdio_cfg_cmd *mdio_cmd;
> + enum hclge_cmd_status status;
> + struct hclge_desc desc;
> + u8 devad;
> +
> + if (!bus)
> + return -EINVAL;
> +
> + devad = ((regnum >> 16) & 0x1f);
So you have changed this to only support C22. Which means devad is not
needed, since that is c45 only.
> +
> + dev_dbg(&bus->dev, "phy id=%d, devad=%d\n", phy_id, devad);
> +
> + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, false);
> +
> + mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
> +
> + mdio_cmd->prtad = phy_id & HCLGE_MDIO_CTRL_PRTAD_MSK;
> + mdio_cmd->data_wr = cpu_to_le16(data);
> + mdio_cmd->devad = devad & HCLGE_MDIO_CTRL_DEVAD_MSK;
> +
> + /* Write reg and data */
> + mdio_cmd->ctrl_bit = HCLGE_MDIO_IS_C22(1);
Passing the parameter is now pointless if you are only doing C22.
> + mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_OP(HCLGE_MDIO_C22_WRITE);
> + mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_START_BIT;
Given the above defines, this now becomes
mdio_cmd->ctrl_bit = HCLGE_MDIO_C22_WRITE;
> +
> + status = hclge_cmd_send(&hdev->hw, &desc, 1);
> + if (status) {
> + dev_err(&hdev->pdev->dev,
> + "mdio write fail when sending cmd, status is %d.\n",
> + status);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int hclge_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
> +{
> + struct hclge_dev *hdev = (struct hclge_dev *)bus->priv;
> + struct hclge_mdio_cfg_cmd *mdio_cmd;
> + enum hclge_cmd_status status;
> + struct hclge_desc desc;
> + u8 devad;
> +
> + if (!bus)
> + return -EINVAL;
> +
> + devad = ((regnum >> 16) & GENMASK(4, 0));
> +
> + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, true);
> +
> + mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
> +
> + dev_dbg(&bus->dev, "phy id=%d, devad=%d\n", phy_id, devad);
Generally, you would do this after the read has completed, so you can
include the value read.
> +
> + mdio_cmd->prtad = phy_id & HCLGE_MDIO_CTRL_PRTAD_MSK;
> + mdio_cmd->devad = devad & HCLGE_MDIO_CTRL_DEVAD_MSK;
> +
> + /* Write reg and data */
> + mdio_cmd->ctrl_bit = HCLGE_MDIO_IS_C22(1);
> + mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_OP(HCLGE_MDIO_C22_WRITE);
> + mdio_cmd->ctrl_bit |= HCLGE_MDIO_CTRL_START_BIT;
> +
> + /* Read out phy data */
> + status = hclge_cmd_send(&hdev->hw, &desc, 1);
> + if (status) {
> + dev_err(&hdev->pdev->dev,
Be consistent. With dev_dbg() you used bus->dev.
> + "mdio read fail when get data, status is %d.\n",
> + status);
> + return status;
> + }
> +
> + if (HCLGE_MDIO_STA_VAL(mdio_cmd->sta)) {
if (mdio_cmd->status & HCLGE_MDIO_STATUS_ERROR) {
is much more readable.
> + dev_err(&hdev->pdev->dev, "mdio read data error\n");
> + return -EIO;
> + }
> +
> + return le16_to_cpu(mdio_cmd->data_rd);
> +}
> +
> +int hclge_mac_mdio_config(struct hclge_dev *hdev)
> +{
> + struct hclge_mac *mac = &hdev->hw.mac;
> + struct net_device *ndev = &mac->ndev;
> + struct phy_device *phy_dev;
It is normal to call this phydev.
> + struct mii_bus *mdio_bus;
> + int ret;
> +
> + if (hdev->hw.mac.phy_addr >= PHY_MAX_ADDR)
> + return 0;
> +
> + SET_NETDEV_DEV(ndev, &hdev->pdev->dev);
It seems odd doing this here. It is normally done in the probe()
function.
> +
> + mdio_bus = devm_mdiobus_alloc(&hdev->pdev->dev);
> + if (!mdio_bus) {
> + ret = -ENOMEM;
> + goto err_miibus_alloc;
> + }
> +
Just
return -ENOMEM;
> + mdio_bus->name = "hisilicon MII bus";
> + mdio_bus->read = hclge_mdio_read;
> + mdio_bus->write = hclge_mdio_write;
> + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii",
> + dev_name(&hdev->pdev->dev));
> +
> + mdio_bus->parent = &hdev->pdev->dev;
> + mdio_bus->priv = hdev;
> + mdio_bus->phy_mask = ~(1 << mac->phy_addr);
> + ret = mdiobus_register(mdio_bus);
> + if (ret) {
> + dev_err(mdio_bus->parent,
> + "Failed to register MDIO bus ret = %#x\n", ret);
> + goto err_mdio_register;
If register failed, you don't want to call unregister.
> + }
> +
> + phy_dev = mdiobus_get_phy(mdio_bus, mac->phy_addr);
> + if (!phy_dev || IS_ERR(phy_dev)) {
> + dev_err(mdio_bus->parent, "Failed to get phy device\n");
> + ret = -EIO;
> + goto err_mdio_register;
> + }
> +
> + phy_dev->irq = mdio_bus->irq[mac->phy_addr];
The core will do this for you in phy_device_create().
> + mac->phy_dev = phy_dev;
After you have attached the phydev to the netdev, you can use
ndev->phydev. It is better to use that, than keep it in the priv
structure.
> +
> + return 0;
> +
> +err_mdio_register:
> + mdiobus_unregister(mdio_bus);
> + mdiobus_free(mdio_bus);
You allocated it using devm_mdiobus_alloc(). So this is going to cause
a double free of the memory.
> +err_miibus_alloc:
> + return ret;
> +}
> +
> +static void hclge_mac_adjust_link(struct net_device *net_dev)
ndev is the most used name for the net_device.
> +{
> + struct hclge_mac *hw_mac;
> + struct hclge_dev *hdev;
> + struct hclge_hw *hw;
> + int duplex;
> + int speed;
> +
> + if (!net_dev)
> + return;
> +
> + hw_mac = container_of(net_dev, struct hclge_mac, ndev);
> + hw = container_of(hw_mac, struct hclge_hw, mac);
> + hdev = hw->back;
> +
> + speed = hw_mac->phy_dev->speed;
> + duplex = hw_mac->phy_dev->duplex;
speed = ndev->phydev->speed
duplex = ndev->phydev->duplex
> +
> + /* update antoneg. */
> + hw_mac->autoneg = hw_mac->phy_dev->autoneg;
> +
> + if ((hw_mac->speed != speed) || (hw_mac->duplex != duplex))
> + (void)hclge_cfg_mac_speed_dup(hdev, speed, !!duplex);
> +}
> +
> +int hclge_mac_start_phy(struct hclge_dev *hdev)
> +{
> + struct hclge_mac *mac = &hdev->hw.mac;
> + struct phy_device *phy_dev = mac->phy_dev;
> + struct net_device *ndev = &mac->ndev;
> + int ret;
> +
> + if (!phy_dev)
> + return 0;
> +
> + phy_dev->dev_flags = 0;
It is pretty unusual to do this. So a comment would be good explaining
why it is needed.
> +
> + ret = phy_connect_direct(ndev, phy_dev,
> + hclge_mac_adjust_link,
> + PHY_INTERFACE_MODE_SGMII);
> + if (unlikely(ret)) {
If this was on the hotpath, handling 10 million packets per second,
using unlikely() might bring some benefit. But this function is only
going to be called once when the interface is opened. Don't use
unlikely().
> + pr_info("phy_connect_direct err");
netdev_dbg(ndev, "phy_connect_direct %d\n", ret);
> + return -ENODEV;
Use the error code which phy_connect_direct() gave you.
> + }
> +
> + phy_dev->supported = SUPPORTED_10baseT_Half |
> + SUPPORTED_10baseT_Full |
> + SUPPORTED_100baseT_Half |
> + SUPPORTED_100baseT_Full |
> + SUPPORTED_Autoneg |
> + SUPPORTED_1000baseT_Full;
> +
phydev->supported &= PHY_GBIT_FEATURES;
> + phy_start(mac->phy_dev);
phy_start(ndev->phydev)
> +
> + return 0;
> +}
> +
> +void hclge_mac_stop_phy(struct hclge_dev *hdev)
> +{
> + if (!hdev->hw.mac.phy_dev)
> + return;
> +
> + phy_disconnect(hdev->hw.mac.phy_dev);
> + phy_stop(hdev->hw.mac.phy_dev);
No need to call phy_stop() if you have called phy_disconnect():
/**
* phy_disconnect - disable interrupts, stop state machine, and detach a PHY
* device
* @phydev: target phy_device struct
*/
Andrew
[toc] | [prev] | [next] | [standalone]
| From | Salil Mehta <salil.mehta@huawei.com> |
|---|---|
| Date | 2017-06-17 19:30 +0200 |
| Subject | [PATCH V3 net-next 5/8] net: hns3: Add support of TX Scheduler & Shaper to HNS3 driver |
| Message-ID | <tTpHQ-1Qt-13@gated-at.bofh.it> |
| In reply to | #1668370 |
THis patch adds the support of the Scheduling and Shaping
functionalities during the transmit leg. This also adds the
support of Pause at MAC level. (Pause at per-priority level
shall be added later along with the DCB feature).
Hardware as such consists of two types of cofiguration of 6 level
schedulers. Algorithms varies according to the level and type
of scheduler being used. Current patch is used to initialize
the mapping, algorithms(like SP, DWRR etc) and shaper(CIR, PIR etc)
being used.
Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: lipeng <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Yisen Zhuang <yisen.zhuang@huawei.com>
---
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 1018 ++++++++++++++++++++
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 108 +++
2 files changed, 1126 insertions(+)
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
new file mode 100644
index 0000000..2b66a0e
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (c) 2016~2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/etherdevice.h>
+
+#include "hclge_cmd.h"
+#include "hclge_main.h"
+#include "hclge_tm.h"
+
+enum hclge_shaper_level {
+ HCLGE_SHAPER_LVL_PRI = 0,
+ HCLGE_SHAPER_LVL_PG = 1,
+ HCLGE_SHAPER_LVL_PORT = 2,
+ HCLGE_SHAPER_LVL_QSET = 3,
+ HCLGE_SHAPER_LVL_CNT = 4,
+ HCLGE_SHAPER_LVL_VF = 0,
+ HCLGE_SHAPER_LVL_PF = 1,
+};
+
+#define HCLGE_SHAPER_BS_U_DEF 1
+#define HCLGE_SHAPER_BS_S_DEF 4
+
+#define HCLGE_ETHER_MAX_RATE 100000
+
+/* hclge_shaper_para_calc: calculate ir parameter for the shaper
+ * @ir: Rate to be config, its unit is Mbps
+ * @shaper_level: the shaper level. eg: port, pg, priority, queueset
+ * @ir_b: IR_B parameter of IR shaper
+ * @ir_u: IR_U parameter of IR shaper
+ * @ir_s: IR_S parameter of IR shaper
+ *
+ * the formula:
+ *
+ * IR_b * (2 ^ IR_u) * 8
+ * IR(Mbps) = ------------------------- * CLOCK(1000Mbps)
+ * Tick * (2 ^ IR_s)
+ *
+ * @return: 0: calculate sucessful, negative: fail
+ */
+static int hclge_shaper_para_calc(u32 ir, u8 shaper_level,
+ u8 *ir_b, u8 *ir_u, u8 *ir_s)
+{
+ const u16 tick_array[HCLGE_SHAPER_LVL_CNT] = {
+ 6 * 256, /* Prioriy level */
+ 6 * 32, /* Prioriy group level */
+ 6 * 8, /* Port level */
+ 6 * 256 /* Qset level */
+ };
+ u8 ir_u_calc = 0, ir_s_calc = 0;
+ u32 ir_calc;
+ u32 tick;
+
+ /* Calc tick */
+ if (shaper_level >= HCLGE_SHAPER_LVL_CNT)
+ return -ENOMEM;
+
+ tick = tick_array[shaper_level];
+
+ /**
+ * Calc the speed if ir_b = 126, ir_u = 0 and ir_s = 0
+ * the formula is changed to:
+ * 126 * 1 * 8
+ * ir_calc = ---------------- * 1000
+ * tick * 1
+ */
+ ir_calc = (1008000 + (tick >> 1) - 1) / tick;
+
+ if (ir_calc == ir) {
+ *ir_b = 126;
+ *ir_u = 0;
+ *ir_s = 0;
+
+ return 0;
+ } else if (ir_calc > ir) {
+ /* Increasing the denominator to select ir_s value */
+ while (ir_calc > ir) {
+ ir_s_calc++;
+ ir_calc = 1008000 / (tick * (1 << ir_s_calc));
+ }
+
+ if (ir_calc == ir)
+ *ir_b = 126;
+ else
+ *ir_b = (ir * tick * (1 << ir_s_calc) + 4000) / 8000;
+ } else {
+ /* Increasing the numerator to select ir_u value */
+ u32 numerator;
+
+ while (ir_calc < ir) {
+ ir_u_calc++;
+ numerator = 1008000 * (1 << ir_u_calc);
+ ir_calc = (numerator + (tick >> 1)) / tick;
+ }
+
+ if (ir_calc == ir) {
+ *ir_b = 126;
+ } else {
+ u32 denominator = (8000 * (1 << --ir_u_calc));
+ *ir_b = (ir * tick + (denominator >> 1)) / denominator;
+ }
+ }
+
+ *ir_u = ir_u_calc;
+ *ir_s = ir_s_calc;
+
+ return 0;
+}
+
+static int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx)
+{
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PAUSE_EN, false);
+
+ desc.data[0] = cpu_to_le32((tx ? HCLGE_TX_MAC_PAUSE_EN_MSK : 0) |
+ (rx ? HCLGE_RX_MAC_PAUSE_EN_MSK : 0));
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_fill_pri_array(struct hclge_dev *hdev, u8 *pri, u8 pri_id)
+{
+ u8 tc;
+
+ for (tc = 0; tc < hdev->tm_info.num_tc; tc++)
+ if (hdev->tm_info.tc_info[tc].up == pri_id)
+ break;
+
+ if (tc >= hdev->tm_info.num_tc)
+ return -ENOMEM;
+
+ /**
+ * the register for priority has four bytes, the first bytes includes
+ * priority0 and priority1, the higher 4bit stands for priority1
+ * while the lower 4bit stands for priority0, as below:
+ * first byte: | pri_1 | pri_0 |
+ * second byte: | pri_3 | pri_2 |
+ * third byte: | pri_5 | pri_4 |
+ * fourth byte: | pri_7 | pri_6 |
+ */
+ pri[pri_id >> 1] |= tc << ((pri_id & 1) * 4);
+
+ return 0;
+}
+
+static int hclge_up_to_tc_map(struct hclge_dev *hdev)
+{
+ struct hclge_desc desc;
+ u8 *pri = (u8 *)desc.data;
+ u8 pri_id;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PRI_TO_TC_MAPPING, false);
+
+ for (pri_id = 0; pri_id < hdev->tm_info.num_tc; pri_id++) {
+ ret = hclge_fill_pri_array(hdev, pri, pri_id);
+ if (ret)
+ return ret;
+ }
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_pg_to_pri_map_cfg(struct hclge_dev *hdev,
+ u8 pg_id, u8 pri_bit_map)
+{
+ struct hclge_pg_to_pri_link_cmd *map;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_TO_PRI_LINK, false);
+
+ map = (struct hclge_pg_to_pri_link_cmd *)desc.data;
+
+ map->pg_id = cpu_to_le16(pg_id);
+ map->pri_bit_map = pri_bit_map;
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_qs_to_pri_map_cfg(struct hclge_dev *hdev,
+ u16 qs_id, u8 pri)
+{
+ struct hclge_qs_to_pri_link_cmd *map;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_TO_PRI_LINK, false);
+
+ map = (struct hclge_qs_to_pri_link_cmd *)desc.data;
+
+ map->qs_id = cpu_to_le16(qs_id);
+ map->priority = pri;
+ map->link_vld = HCLGE_TM_QS_PRI_LINK_VLD_MSK;
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_q_to_qs_map_cfg(struct hclge_dev *hdev,
+ u8 q_id, u16 qs_id)
+{
+ struct hclge_nq_to_qs_link_cmd *map;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_NQ_TO_QS_LINK, false);
+
+ map = (struct hclge_nq_to_qs_link_cmd *)desc.data;
+
+ map->nq_id = cpu_to_le16(q_id);
+ map->qset_id = cpu_to_le16(qs_id | HCLGE_TM_Q_QS_LINK_VLD_MSK);
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_gp_weight_cfg(struct hclge_dev *hdev, u8 pg_id,
+ u8 dwrr)
+{
+ struct hclge_pg_weight_cmd *weight;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_WEIGHT, false);
+
+ weight = (struct hclge_pg_weight_cmd *)desc.data;
+
+ weight->pg_id = pg_id;
+ weight->dwrr = dwrr;
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_pri_weight_cfg(struct hclge_dev *hdev, u8 pri_id,
+ u8 dwrr)
+{
+ struct hclge_priority_weight_cmd *weight;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PRI_WEIGHT, false);
+
+ weight = (struct hclge_priority_weight_cmd *)desc.data;
+
+ weight->pri_id = pri_id;
+ weight->dwrr = dwrr;
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_qs_weight_cfg(struct hclge_dev *hdev, u16 qs_id,
+ u8 dwrr)
+{
+ struct hclge_qs_weight_cmd *weight;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_WEIGHT, false);
+
+ weight = (struct hclge_qs_weight_cmd *)desc.data;
+
+ weight->qs_id = cpu_to_le16(qs_id);
+ weight->dwrr = dwrr;
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_pg_shapping_cfg(struct hclge_dev *hdev,
+ enum hclge_shap_bucket bucket, u8 pg_id,
+ u8 ir_b, u8 ir_u, u8 ir_s, u8 bs_b, u8 bs_s)
+{
+ struct hclge_pg_shapping_cmd *shap_cfg_cmd;
+ enum hclge_opcode_type opcode;
+ struct hclge_desc desc;
+
+ opcode = bucket ? HCLGE_OPC_TM_PG_P_SHAPPING :
+ HCLGE_OPC_TM_PG_C_SHAPPING;
+ hclge_cmd_setup_basic_desc(&desc, opcode, false);
+
+ shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
+
+ shap_cfg_cmd->pg_id = pg_id;
+
+ hclge_tm_set_feild(shap_cfg_cmd->pg_shapping_para, IR_B, ir_b);
+ hclge_tm_set_feild(shap_cfg_cmd->pg_shapping_para, IR_U, ir_u);
+ hclge_tm_set_feild(shap_cfg_cmd->pg_shapping_para, IR_S, ir_s);
+ hclge_tm_set_feild(shap_cfg_cmd->pg_shapping_para, BS_B, bs_b);
+ hclge_tm_set_feild(shap_cfg_cmd->pg_shapping_para, BS_S, bs_s);
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_pri_shapping_cfg(struct hclge_dev *hdev,
+ enum hclge_shap_bucket bucket, u8 pri_id,
+ u8 ir_b, u8 ir_u, u8 ir_s,
+ u8 bs_b, u8 bs_s)
+{
+ struct hclge_pri_shapping_cmd *shap_cfg_cmd;
+ enum hclge_opcode_type opcode;
+ struct hclge_desc desc;
+
+ opcode = bucket ? HCLGE_OPC_TM_PRI_P_SHAPPING :
+ HCLGE_OPC_TM_PRI_C_SHAPPING;
+
+ hclge_cmd_setup_basic_desc(&desc, opcode, false);
+
+ shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data;
+
+ shap_cfg_cmd->pri_id = pri_id;
+
+ hclge_tm_set_feild(shap_cfg_cmd->pri_shapping_para, IR_B, ir_b);
+ hclge_tm_set_feild(shap_cfg_cmd->pri_shapping_para, IR_U, ir_u);
+ hclge_tm_set_feild(shap_cfg_cmd->pri_shapping_para, IR_S, ir_s);
+ hclge_tm_set_feild(shap_cfg_cmd->pri_shapping_para, BS_B, bs_b);
+ hclge_tm_set_feild(shap_cfg_cmd->pri_shapping_para, BS_S, bs_s);
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_pg_schd_mode_cfg(struct hclge_dev *hdev, u8 pg_id)
+{
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_SCH_MODE_CFG, false);
+
+ if (hdev->tm_info.pg_info[pg_id].pg_sch_mode == HCLGE_SCH_MODE_DWRR)
+ desc.data[1] = cpu_to_le32(HCLGE_TM_TX_SCHD_DWRR_MSK);
+ else
+ desc.data[1] = 0;
+
+ desc.data[0] = cpu_to_le32(pg_id);
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_pri_schd_mode_cfg(struct hclge_dev *hdev, u8 pri_id)
+{
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PRI_SCH_MODE_CFG, false);
+
+ if (hdev->tm_info.tc_info[pri_id].tc_sch_mode == HCLGE_SCH_MODE_DWRR)
+ desc.data[1] = cpu_to_le32(HCLGE_TM_TX_SCHD_DWRR_MSK);
+ else
+ desc.data[1] = 0;
+
+ desc.data[0] = cpu_to_le32(pri_id);
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_qs_schd_mode_cfg(struct hclge_dev *hdev, u16 qs_id)
+{
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_SCH_MODE_CFG, false);
+
+ if (hdev->tm_info.tc_info[qs_id].tc_sch_mode == HCLGE_SCH_MODE_DWRR)
+ desc.data[1] = cpu_to_le32(HCLGE_TM_TX_SCHD_DWRR_MSK);
+ else
+ desc.data[1] = 0;
+
+ desc.data[0] = cpu_to_le32(qs_id);
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static int hclge_tm_qs_bp_cfg(struct hclge_dev *hdev, u8 tc)
+{
+ struct hclge_bp_to_qs_map_cmd *bp_to_qs_map_cmd;
+ struct hclge_desc desc;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_BP_TO_QSET_MAPPING,
+ false);
+
+ bp_to_qs_map_cmd = (struct hclge_bp_to_qs_map_cmd *)desc.data;
+
+ bp_to_qs_map_cmd->tc_id = tc;
+
+ /* Qset and tc is one by one mapping */
+ bp_to_qs_map_cmd->qs_bit_map = cpu_to_le32(1 << tc);
+
+ return hclge_cmd_send(&hdev->hw, &desc, 1);
+}
+
+static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport)
+{
+ struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+ struct hclge_dev *hdev = vport->back;
+ u8 i;
+
+ kinfo = &vport->nic.kinfo;
+ vport->bw_limit = hdev->tm_info.pg_info[0].bw_limit;
+ kinfo->num_tc =
+ min_t(u16, kinfo->num_tqps, hdev->tm_info.num_tc);
+ kinfo->rss_size
+ = min_t(u16, hdev->rss_size_max,
+ kinfo->num_tqps / kinfo->num_tc);
+ vport->qs_offset = hdev->tm_info.num_tc * vport->vport_id;
+ vport->dwrr = 100; /* 100 percent as init */
+
+ for (i = 0; i < kinfo->num_tc; i++) {
+ if (hdev->hw_tc_map & BIT(i)) {
+ kinfo->tc_info[i].enable = true;
+ kinfo->tc_info[i].tqp_offset = i * kinfo->rss_size;
+ kinfo->tc_info[i].tqp_count = kinfo->rss_size;
+ kinfo->tc_info[i].tc = i;
+ kinfo->tc_info[i].up = hdev->tm_info.tc_info[i].up;
+ } else {
+ /* Set to default queue if TC is disable */
+ kinfo->tc_info[i].enable = false;
+ kinfo->tc_info[i].tqp_offset = 0;
+ kinfo->tc_info[i].tqp_count = 1;
+ kinfo->tc_info[i].tc = 0;
+ kinfo->tc_info[i].up = 0;
+ }
+ }
+}
+
+static void hclge_tm_vport_info_update(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport = hdev->vport;
+ u32 i;
+
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ hclge_tm_vport_tc_info_update(vport);
+
+ vport++;
+ }
+}
+
+static void hclge_tm_tc_info_init(struct hclge_dev *hdev)
+{
+ u8 i;
+
+ for (i = 0; i < hdev->tm_info.num_tc; i++) {
+ hdev->tm_info.tc_info[i].tc_id = i;
+ hdev->tm_info.tc_info[i].tc_sch_mode = HCLGE_SCH_MODE_DWRR;
+ hdev->tm_info.tc_info[i].up = i;
+ hdev->tm_info.tc_info[i].pgid = 0;
+ hdev->tm_info.tc_info[i].bw_limit =
+ hdev->tm_info.pg_info[0].bw_limit;
+ }
+
+ hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
+}
+
+static void hclge_tm_pg_info_init(struct hclge_dev *hdev)
+{
+ u8 i;
+
+ for (i = 0; i < hdev->tm_info.num_pg; i++) {
+ int k;
+
+ hdev->tm_info.pg_dwrr[i] = i ? 0 : 100;
+
+ hdev->tm_info.pg_info[i].pg_id = i;
+ hdev->tm_info.pg_info[i].pg_sch_mode = HCLGE_SCH_MODE_DWRR;
+
+ hdev->tm_info.pg_info[i].bw_limit = HCLGE_ETHER_MAX_RATE;
+
+ if (i != 0)
+ continue;
+
+ hdev->tm_info.pg_info[i].tc_bit_map = hdev->hw_tc_map;
+ for (k = 0; k < hdev->tm_info.num_tc; k++)
+ hdev->tm_info.pg_info[i].tc_dwrr[k] = 100;
+ }
+}
+
+static int hclge_tm_schd_info_init(struct hclge_dev *hdev)
+{
+ if ((hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE) &&
+ (hdev->tm_info.num_pg != 1))
+ return -EINVAL;
+
+ hclge_tm_pg_info_init(hdev);
+
+ hclge_tm_tc_info_init(hdev);
+
+ hclge_tm_vport_info_update(hdev);
+
+ hdev->tm_info.fc_mode = HCLGE_FC_NONE;
+ if (hdev->tm_info.num_tc != 1)
+ hdev->fc_mode_last_time = hdev->tm_info.fc_mode;
+ else
+ hdev->fc_mode_last_time = hdev->tm_info.fc_mode;
+
+ return 0;
+}
+
+static int hclge_tm_pg_to_pri_map(struct hclge_dev *hdev)
+{
+ int ret;
+ u32 i;
+
+ if (hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE)
+ return 0;
+
+ for (i = 0; i < hdev->tm_info.num_pg; i++) {
+ /* Cfg mapping */
+ ret = hclge_tm_pg_to_pri_map_cfg(
+ hdev, i, hdev->tm_info.pg_info[i].tc_bit_map);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pg_shaper_cfg(struct hclge_dev *hdev)
+{
+ u8 ir_u, ir_b, ir_s;
+ int ret;
+ u32 i;
+
+ /* Cfg pg schd */
+ if (hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE)
+ return 0;
+
+ /* Pg to pri */
+ for (i = 0; i < hdev->tm_info.num_pg; i++) {
+ /* Calc shaper para */
+ ret = hclge_shaper_para_calc(
+ hdev->tm_info.pg_info[i].bw_limit,
+ HCLGE_SHAPER_LVL_PG,
+ &ir_b, &ir_u, &ir_s);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_pg_shapping_cfg(hdev,
+ HCLGE_TM_SHAP_C_BUCKET, i,
+ 0, 0, 0, HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_pg_shapping_cfg(hdev,
+ HCLGE_TM_SHAP_P_BUCKET, i,
+ ir_b, ir_u, ir_s,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pg_dwrr_cfg(struct hclge_dev *hdev)
+{
+ int ret;
+ u32 i;
+
+ /* cfg pg schd */
+ if (hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE)
+ return 0;
+
+ /* pg to prio */
+ for (i = 0; i < hdev->tm_info.num_pg; i++) {
+ /* Cfg dwrr */
+ ret = hclge_tm_gp_weight_cfg(hdev, i,
+ hdev->tm_info.pg_dwrr[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_vport_q_to_qs_map(struct hclge_dev *hdev,
+ struct hclge_vport *vport)
+{
+ struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+ struct hnae3_queue **tqp = kinfo->tqp;
+ struct hnae3_tc_info *v_tc_info;
+ u32 i, j;
+ int ret;
+
+ for (i = 0; i < kinfo->num_tc; i++) {
+ v_tc_info = &kinfo->tc_info[i];
+ for (j = 0; j < v_tc_info->tqp_count; j++) {
+ struct hnae3_queue *q = tqp[v_tc_info->tqp_offset + j];
+
+ ret = hclge_tm_q_to_qs_map_cfg(hdev,
+ hclge_get_queue_id(q),
+ vport->qs_offset + i);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_q_qs_cfg(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport = hdev->vport;
+ int ret;
+ u32 i;
+
+ if (hdev->tx_sch_mode == HCLGE_FLAG_TC_BASE_SCH_MODE) {
+ /* Cfg qs -> pri mapping, one by one mapping */
+ for (i = 0; i < hdev->tm_info.num_tc; i++) {
+ ret = hclge_tm_qs_to_pri_map_cfg(hdev, i, i);
+ if (ret)
+ return ret;
+ }
+ } else if (hdev->tx_sch_mode == HCLGE_FLAG_VNET_BASE_SCH_MODE) {
+ int k;
+ /* Cfg qs -> pri mapping, qs = tc, pri = vf, 8 qs -> 1 pri */
+ for (k = 0; k < hdev->num_alloc_vport; k++)
+ for (i = 0; i < HNAE3_MAX_TC; i++) {
+ ret = hclge_tm_qs_to_pri_map_cfg(
+ hdev, vport[k].qs_offset + i, k);
+ if (ret)
+ return ret;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ /* Cfg q -> qs mapping */
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ ret = hclge_vport_q_to_qs_map(hdev, vport);
+ if (ret)
+ return ret;
+
+ vport++;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_tc_base_shaper_cfg(struct hclge_dev *hdev)
+{
+ u8 ir_u, ir_b, ir_s;
+ int ret;
+ u32 i;
+
+ for (i = 0; i < hdev->tm_info.num_tc; i++) {
+ ret = hclge_shaper_para_calc(
+ hdev->tm_info.tc_info[i].bw_limit,
+ HCLGE_SHAPER_LVL_PRI,
+ &ir_b, &ir_u, &ir_s);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_pri_shapping_cfg(
+ hdev, HCLGE_TM_SHAP_C_BUCKET, i,
+ 0, 0, 0, HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_pri_shapping_cfg(
+ hdev, HCLGE_TM_SHAP_P_BUCKET, i,
+ ir_b, ir_u, ir_s, HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_vnet_base_shaper_pri_cfg(struct hclge_vport *vport)
+{
+ struct hclge_dev *hdev = vport->back;
+ u8 ir_u, ir_b, ir_s;
+ int ret;
+
+ ret = hclge_shaper_para_calc(vport->bw_limit, HCLGE_SHAPER_LVL_VF,
+ &ir_b, &ir_u, &ir_s);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_pri_shapping_cfg(hdev, HCLGE_TM_SHAP_C_BUCKET,
+ vport->vport_id,
+ 0, 0, 0, HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_pri_shapping_cfg(hdev, HCLGE_TM_SHAP_P_BUCKET,
+ vport->vport_id,
+ ir_b, ir_u, ir_s,
+ HCLGE_SHAPER_BS_U_DEF,
+ HCLGE_SHAPER_BS_S_DEF);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int hclge_tm_pri_vnet_base_shaper_qs_cfg(struct hclge_vport *vport)
+{
+ struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+ struct hclge_dev *hdev = vport->back;
+ struct hnae3_tc_info *v_tc_info;
+ u8 ir_u, ir_b, ir_s;
+ u32 i;
+ int ret;
+
+ for (i = 0; i < kinfo->num_tc; i++) {
+ v_tc_info = &kinfo->tc_info[i];
+ ret = hclge_shaper_para_calc(
+ hdev->tm_info.tc_info[i].bw_limit,
+ HCLGE_SHAPER_LVL_QSET,
+ &ir_b, &ir_u, &ir_s);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_vnet_base_shaper_cfg(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport = hdev->vport;
+ int ret;
+ u32 i;
+
+ /* Need config vport shaper */
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ ret = hclge_tm_pri_vnet_base_shaper_pri_cfg(vport);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_pri_vnet_base_shaper_qs_cfg(vport);
+ if (ret)
+ return ret;
+
+ vport++;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_shaper_cfg(struct hclge_dev *hdev)
+{
+ int ret;
+
+ if (hdev->tx_sch_mode == HCLGE_FLAG_TC_BASE_SCH_MODE) {
+ ret = hclge_tm_pri_tc_base_shaper_cfg(hdev);
+ if (ret)
+ return ret;
+ } else {
+ ret = hclge_tm_pri_vnet_base_shaper_cfg(hdev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_tc_base_dwrr_cfg(struct hclge_dev *hdev)
+{
+ struct hclge_pg_info *pg_info;
+ u8 dwrr;
+ int ret;
+ u32 i;
+
+ for (i = 0; i < hdev->tm_info.num_tc; i++) {
+ pg_info =
+ &hdev->tm_info.pg_info[hdev->tm_info.tc_info[i].pgid];
+ dwrr = pg_info->tc_dwrr[i];
+
+ ret = hclge_tm_pri_weight_cfg(hdev, i, dwrr);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_qs_weight_cfg(hdev, i, dwrr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_vnet_base_dwrr_pri_cfg(struct hclge_vport *vport)
+{
+ struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+ struct hclge_dev *hdev = vport->back;
+ int ret;
+ u8 i;
+
+ /* Vf dwrr */
+ ret = hclge_tm_pri_weight_cfg(hdev, vport->vport_id, vport->dwrr);
+ if (ret)
+ return ret;
+
+ /* Qset dwrr */
+ for (i = 0; i < kinfo->num_tc; i++) {
+ ret = hclge_tm_qs_weight_cfg(
+ hdev, vport->qs_offset + i,
+ hdev->tm_info.pg_info[0].tc_dwrr[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_vnet_base_dwrr_cfg(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport = hdev->vport;
+ int ret;
+ u32 i;
+
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ ret = hclge_tm_pri_vnet_base_dwrr_pri_cfg(vport);
+ if (ret)
+ return ret;
+
+ vport++;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_pri_dwrr_cfg(struct hclge_dev *hdev)
+{
+ int ret;
+
+ if (hdev->tx_sch_mode == HCLGE_FLAG_TC_BASE_SCH_MODE) {
+ ret = hclge_tm_pri_tc_base_dwrr_cfg(hdev);
+ if (ret)
+ return ret;
+ } else {
+ ret = hclge_tm_pri_vnet_base_dwrr_cfg(hdev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_map_cfg(struct hclge_dev *hdev)
+{
+ int ret;
+
+ ret = hclge_tm_pg_to_pri_map(hdev);
+ if (ret)
+ return ret;
+
+ return hclge_tm_pri_q_qs_cfg(hdev);
+}
+
+static int hclge_tm_shaper_cfg(struct hclge_dev *hdev)
+{
+ int ret;
+
+ ret = hclge_tm_pg_shaper_cfg(hdev);
+ if (ret)
+ return ret;
+
+ return hclge_tm_pri_shaper_cfg(hdev);
+}
+
+int hclge_tm_dwrr_cfg(struct hclge_dev *hdev)
+{
+ int ret;
+
+ ret = hclge_tm_pg_dwrr_cfg(hdev);
+ if (ret)
+ return ret;
+
+ return hclge_tm_pri_dwrr_cfg(hdev);
+}
+
+static int hclge_tm_lvl2_schd_mode_cfg(struct hclge_dev *hdev)
+{
+ int ret;
+ u8 i;
+
+ /* Only being config on TC-Based scheduler mode */
+ if (hdev->tx_sch_mode == HCLGE_FLAG_VNET_BASE_SCH_MODE)
+ return 0;
+
+ for (i = 0; i < hdev->tm_info.num_pg; i++) {
+ ret = hclge_tm_pg_schd_mode_cfg(hdev, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_schd_mode_vnet_base_cfg(struct hclge_vport *vport)
+{
+ struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+ struct hclge_dev *hdev = vport->back;
+ int ret;
+ u8 i;
+
+ ret = hclge_tm_pri_schd_mode_cfg(hdev, vport->vport_id);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < kinfo->num_tc; i++) {
+ ret = hclge_tm_qs_schd_mode_cfg(hdev, vport->qs_offset + i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hclge_tm_lvl34_schd_mode_cfg(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport = hdev->vport;
+ int ret;
+ u8 i;
+
+ if (hdev->tx_sch_mode == HCLGE_FLAG_TC_BASE_SCH_MODE) {
+ for (i = 0; i < hdev->tm_info.num_tc; i++) {
+ ret = hclge_tm_pri_schd_mode_cfg(hdev, i);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_qs_schd_mode_cfg(hdev, i);
+ if (ret)
+ return ret;
+ }
+ } else {
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ ret = hclge_tm_schd_mode_vnet_base_cfg(vport);
+ if (ret)
+ return ret;
+
+ vport++;
+ }
+ }
+
+ return 0;
+}
+
+static int hclge_tm_schd_mode_hw(struct hclge_dev *hdev)
+{
+ int ret;
+
+ ret = hclge_tm_lvl2_schd_mode_cfg(hdev);
+ if (ret)
+ return ret;
+
+ return hclge_tm_lvl34_schd_mode_cfg(hdev);
+}
+
+static int hclge_tm_schd_setup_hw(struct hclge_dev *hdev)
+{
+ int ret;
+
+ /* Cfg tm mapping */
+ ret = hclge_tm_map_cfg(hdev);
+ if (ret)
+ return ret;
+
+ /* Cfg tm shaper */
+ ret = hclge_tm_shaper_cfg(hdev);
+ if (ret)
+ return ret;
+
+ /* Cfg dwrr */
+ ret = hclge_tm_dwrr_cfg(hdev);
+ if (ret)
+ return ret;
+
+ /* Cfg schd mode for each level schd */
+ return hclge_tm_schd_mode_hw(hdev);
+}
+
+int hclge_pause_setup_hw(struct hclge_dev *hdev)
+{
+ bool en = hdev->tm_info.fc_mode != HCLGE_FC_PFC;
+ int ret;
+ u8 i;
+
+ ret = hclge_mac_pause_en_cfg(hdev, en, en);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < hdev->tm_info.num_tc; i++) {
+ ret = hclge_tm_qs_bp_cfg(hdev, i);
+ if (ret)
+ return ret;
+ }
+
+ return hclge_up_to_tc_map(hdev);
+}
+
+int hclge_tm_init_hw(struct hclge_dev *hdev)
+{
+ int ret;
+
+ if ((hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE) &&
+ (hdev->tx_sch_mode != HCLGE_FLAG_VNET_BASE_SCH_MODE))
+ return -ENOTSUPP;
+
+ ret = hclge_tm_schd_setup_hw(hdev);
+ if (ret)
+ return ret;
+
+ ret = hclge_pause_setup_hw(hdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int hclge_tm_schd_init(struct hclge_dev *hdev)
+{
+ int ret = hclge_tm_schd_info_init(hdev);
+
+ if (ret)
+ return ret;
+
+ return hclge_tm_init_hw(hdev);
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
new file mode 100644
index 0000000..59316aa
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016~2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __HCLGE_TX_SCHD_H__
+#define __HCLGE_TX_SCHD_H__
+
+#include <linux/types.h>
+
+/* MAC Pause */
+#define HCLGE_TX_MAC_PAUSE_EN_MSK BIT(0)
+#define HCLGE_RX_MAC_PAUSE_EN_MSK BIT(1)
+
+#define HCLGE_TM_PORT_BASE_MODE_MSK BIT(0)
+
+/* SP or DWRR */
+#define HCLGE_TM_TX_SCHD_DWRR_MSK BIT(0)
+#define HCLGE_TM_TX_SCHD_SP_MSK (0xFE)
+
+struct hclge_pg_to_pri_link_cmd {
+ u8 pg_id;
+ u8 rsvd1[3];
+ u8 pri_bit_map;
+};
+
+struct hclge_qs_to_pri_link_cmd {
+ __le16 qs_id;
+ __le16 rsvd;
+ u8 priority;
+#define HCLGE_TM_QS_PRI_LINK_VLD_MSK BIT(0)
+ u8 link_vld;
+};
+
+struct hclge_nq_to_qs_link_cmd {
+ __le16 nq_id;
+ __le16 rsvd;
+#define HCLGE_TM_Q_QS_LINK_VLD_MSK BIT(10)
+ __le16 qset_id;
+};
+
+struct hclge_pg_weight_cmd {
+ u8 pg_id;
+ u8 dwrr;
+};
+
+struct hclge_priority_weight_cmd {
+ u8 pri_id;
+ u8 dwrr;
+};
+
+struct hclge_qs_weight_cmd {
+ __le16 qs_id;
+ u8 dwrr;
+};
+
+#define HCLGE_TM_SHAP_IR_B_MSK BIT_MASK(8)
+#define HCLGE_TM_SHAP_IR_B_LSH 0
+#define HCLGE_TM_SHAP_IR_U_MSK GENMASK(11, 8)
+#define HCLGE_TM_SHAP_IR_U_LSH 8
+#define HCLGE_TM_SHAP_IR_S_MSK GENMASK(15, 12)
+#define HCLGE_TM_SHAP_IR_S_LSH 12
+#define HCLGE_TM_SHAP_BS_B_MSK GENMASK(20, 16)
+#define HCLGE_TM_SHAP_BS_B_LSH 16
+#define HCLGE_TM_SHAP_BS_S_MSK GENMASK(25, 21)
+#define HCLGE_TM_SHAP_BS_S_LSH 21
+
+enum hclge_shap_bucket {
+ HCLGE_TM_SHAP_C_BUCKET = 0,
+ HCLGE_TM_SHAP_P_BUCKET,
+};
+
+struct hclge_pri_shapping_cmd {
+ u8 pri_id;
+ u8 rsvd[3];
+ __le32 pri_shapping_para;
+};
+
+struct hclge_pg_shapping_cmd {
+ u8 pg_id;
+ u8 rsvd[3];
+ __le32 pg_shapping_para;
+};
+
+struct hclge_bp_to_qs_map_cmd {
+ u8 tc_id;
+ u8 rsvd[2];
+ u8 qs_group_id;
+ __le32 qs_bit_map;
+ u32 rsvd1;
+};
+
+#define hclge_tm_set_feild(dest, string, val) \
+ hnae_set_field((dest), (HCLGE_TM_SHAP_##string##_MSK), \
+ (HCLGE_TM_SHAP_##string##_LSH), val)
+#define hclge_tm_get_feild(src, string) \
+ hnae_get_field((src), (HCLGE_TM_SHAP_##string##_MSK), \
+ (HCLGE_TM_SHAP_##string##_LSH))
+
+int hclge_tm_schd_init(struct hclge_dev *hdev);
+int hclge_tm_setup_tc(struct hclge_dev *hdev);
+int hclge_pause_setup_hw(struct hclge_dev *hdev);
+
+#endif
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2017-06-18 18:50 +0200 |
| Subject | Re: [PATCH V3 net-next 5/8] net: hns3: Add support of TX Scheduler & Shaper to HNS3 driver |
| Message-ID | <tTLyG-7By-15@gated-at.bofh.it> |
| In reply to | #1668376 |
On Sat, Jun 17, 2017 at 06:24:28PM +0100, Salil Mehta wrote: > + > +int hclge_tm_schd_init(struct hclge_dev *hdev); > +int hclge_tm_setup_tc(struct hclge_dev *hdev); The definition of this function DNE. > +int hclge_pause_setup_hw(struct hclge_dev *hdev); > + > +#endif > -- > 2.7.4 Thanks, Richard
[toc] | [prev] | [next] | [standalone]
| From | Andrew Lunn <andrew@lunn.ch> |
|---|---|
| Date | 2017-06-17 20:00 +0200 |
| Subject | Re: [PATCH V3 net-next 1/8] net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC |
| Message-ID | <tTqaS-23R-5@gated-at.bofh.it> |
| In reply to | #1668370 |
> +static int hns3_nic_net_up(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int i, j;
> + int ret;
> +
> + ret = hns3_nic_init_irq(priv);
> + if (ret != 0) {
if (ret)
No need to compare with zero.
> + netdev_err(ndev, "hns init irq failed! ret=%d\n", ret);
> + return ret;
> +static int hns3_nic_net_open(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret;
> +
> + netif_carrier_off(ndev);
> +
> + ret = netif_set_real_num_tx_queues(ndev, h->kinfo.num_tqps);
> + if (ret < 0) {
> + netdev_err(ndev, "netif_set_real_num_tx_queues fail, ret=%d!\n",
> + ret);
> + return ret;
> + }
In general, functions return 0 for success, and something else for an
error. So there is no need to do a comparison. Please remove all
comparisons, unless it is really needed. It also makes the code look
consistent. At the moment you sometime have < 0, sometime !=0, and
sometimes no comparison at all.
Andrew
[toc] | [prev] | [next] | [standalone]
| From | Andrew Lunn <andrew@lunn.ch> |
|---|---|
| Date | 2017-06-17 21:50 +0200 |
| Subject | Re: [PATCH V3 net-next 1/8] net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC |
| Message-ID | <tTrTj-3hR-5@gated-at.bofh.it> |
| In reply to | #1668370 |
> +
> + for (i = 0; i < priv->vector_num; i++) {
> + tqp_vectors = &priv->tqp_vector[i];
> +
> + if (tqp_vectors->irq_init_flag == HNS3_VEVTOR_INITED)
Should VEVTOR be VECTOR?
> +static void hns3_set_vector_gl(struct hns3_enet_tqp_vector *tqp_vector,
> + u32 gl_value)
> +{
> + writel(gl_value, tqp_vector->mask_addr + HNS3_VECTOR_GL0_OFFSET);
> + writel(gl_value, tqp_vector->mask_addr + HNS3_VECTOR_GL1_OFFSET);
> + writel(gl_value, tqp_vector->mask_addr + HNS3_VECTOR_GL2_OFFSET);
> +}
> +
> +static void hns3_set_vector_rl(struct hns3_enet_tqp_vector *tqp_vector,
> + u32 rl_value)
Could you use more informative names. What does gl and rl mean?
> +{
> + writel(rl_value, tqp_vector->mask_addr + HNS3_VECTOR_RL_OFFSET);
> +}
> +
> +static void hns3_vector_gl_rl_init(struct hns3_enet_tqp_vector *tqp_vector)
> +{
> + /* Default :enable interrupt coalesce */
> + tqp_vector->rx_group.int_gl = HNS3_INT_GL_50K;
> + tqp_vector->tx_group.int_gl = HNS3_INT_GL_50K;
> + hns3_set_vector_gl(tqp_vector, HNS3_INT_GL_50K);
> + hns3_set_vector_rl(tqp_vector, 0);
> + tqp_vector->rx_group.flow_level = HNS3_FLOW_LOW;
> + tqp_vector->tx_group.flow_level = HNS3_FLOW_LOW;
> +}
> +
> +static int hns3_nic_net_up(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int i, j;
> + int ret;
> +
> + ret = hns3_nic_init_irq(priv);
> + if (ret != 0) {
> + netdev_err(ndev, "hns init irq failed! ret=%d\n", ret);
> + return ret;
> + }
> +
> + for (i = 0; i < priv->vector_num; i++)
> + hns3_vector_enable(&priv->tqp_vector[i]);
> +
> + ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0;
> + if (ret)
> + goto out_start_err;
> +
> + return 0;
> +
> +out_start_err:
> + netif_stop_queue(ndev);
This seems asymmetric. Where is the netif_start_queue()?
> +
> + for (j = i - 1; j >= 0; j--)
> + hns3_vector_disable(&priv->tqp_vector[j]);
> +
> + return ret;
> +}
> +
> +static int hns3_nic_net_open(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret;
> +
> + netif_carrier_off(ndev);
> +
> + ret = netif_set_real_num_tx_queues(ndev, h->kinfo.num_tqps);
> + if (ret < 0) {
> + netdev_err(ndev, "netif_set_real_num_tx_queues fail, ret=%d!\n",
> + ret);
> + return ret;
> + }
> +
> + ret = netif_set_real_num_rx_queues(ndev, h->kinfo.num_tqps);
> + if (ret < 0) {
> + netdev_err(ndev,
> + "netif_set_real_num_rx_queues fail, ret=%d!\n", ret);
> + return ret;
> + }
> +
> + ret = hns3_nic_net_up(ndev);
> + if (ret) {
> + netdev_err(ndev,
> + "hns net up fail, ret=%d!\n", ret);
> + return ret;
> + }
> +
> + netif_carrier_on(ndev);
Carrier on should be performed when the PHY says there is link.
> + netif_tx_wake_all_queues(ndev);
> +
> + return 0;
> +}
> +
> +static void hns3_nic_net_down(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_ae_ops *ops;
> + int i;
> +
> + netif_tx_stop_all_queues(ndev);
> + netif_carrier_off(ndev);
> +
> + ops = priv->ae_handle->ae_algo->ops;
> +
> + if (ops->stop)
> + ops->stop(priv->ae_handle);
> +
> + for (i = 0; i < priv->vector_num; i++)
> + hns3_vector_disable(&priv->tqp_vector[i]);
> +}
> +
> +static int hns3_nic_net_stop(struct net_device *ndev)
> +{
> + hns3_nic_net_down(ndev);
> +
> + return 0;
> +}
> +
> +void hns3_set_multicast_list(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + struct netdev_hw_addr *ha = NULL;
> +
> + if (!h) {
> + netdev_err(ndev, "hnae handle is null\n");
> + return;
> + }
> +
> + if (h->ae_algo->ops->set_mc_addr) {
> + netdev_for_each_mc_addr(ha, ndev)
> + if (h->ae_algo->ops->set_mc_addr(h, ha->addr))
> + netdev_err(ndev, "set multicast fail\n");
> + }
> +}
> +
> +static int hns3_nic_uc_sync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->add_uc_addr)
> + return h->ae_algo->ops->add_uc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_uc_unsync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->rm_uc_addr)
> + return h->ae_algo->ops->rm_uc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_mc_sync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->add_uc_addr)
> + return h->ae_algo->ops->add_mc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_mc_unsync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->rm_uc_addr)
> + return h->ae_algo->ops->rm_mc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +void hns3_nic_set_rx_mode(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->set_promisc_mode) {
> + if (ndev->flags & IFF_PROMISC)
> + h->ae_algo->ops->set_promisc_mode(h, 1);
> + else
> + h->ae_algo->ops->set_promisc_mode(h, 0);
> + }
> + if (__dev_uc_sync(ndev, hns3_nic_uc_sync, hns3_nic_uc_unsync))
> + netdev_err(ndev, "sync uc address fail\n");
> + if (ndev->flags & IFF_MULTICAST)
> + if (__dev_mc_sync(ndev, hns3_nic_mc_sync, hns3_nic_mc_unsync))
> + netdev_err(ndev, "sync mc address fail\n");
> +}
> +
> +static int hns3_set_tso(struct sk_buff *skb, u32 *paylen,
> + u16 *mss, u32 *type_cs_vlan_tso)
> +{
> + union {
> + struct iphdr *v4;
> + struct ipv6hdr *v6;
> + unsigned char *hdr;
> + } l3;
You have this repeated a few times. Might be better to pull it out
into a header file.
> + union {
> + struct tcphdr *tcp;
> + struct udphdr *udp;
> + unsigned char *hdr;
> + } l4;
You can probably pull this out as well, or maybe the version with the
gre header.
> +static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
> + int size, dma_addr_t dma, int frag_end,
> + enum hns_desc_type type)
> +{
> + struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
> + struct hns3_desc *desc = &ring->desc[ring->next_to_use];
> + u32 ol_type_vlan_len_msec = 0;
> + u16 bdtp_fe_sc_vld_ra_ri = 0;
> + u32 type_cs_vlan_tso = 0;
> + struct sk_buff *skb;
> + u32 paylen = 0;
> + u16 mss = 0;
> + __be16 protocol;
> + u8 ol4_proto;
> + u8 il4_proto;
> + int ret;
> +
> + /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */
> + desc_cb->priv = priv;
> + desc_cb->length = size;
> + desc_cb->dma = dma;
> + desc_cb->type = type;
> +
> + /* now, fill the descriptor */
> + desc->addr = cpu_to_le64(dma);
> + desc->tx.send_size = cpu_to_le16((u16)size);
> + hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end);
> + desc->tx.bdtp_fe_sc_vld_ra_ri = cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
> +
> + if (type == DESC_TYPE_SKB) {
> + skb = (struct sk_buff *)priv;
> + paylen = cpu_to_le16(skb->len);
> +
> + if (skb->ip_summed == CHECKSUM_PARTIAL) {
> + skb_reset_mac_len(skb);
> + protocol = skb->protocol;
> +
> + /* vlan packe t*/
> + if (protocol == htons(ETH_P_8021Q)) {
> + protocol = vlan_get_protocol(skb);
> + skb->protocol = protocol;
> + }
> + hns3_get_l4_protocol(skb, &ol4_proto, &il4_proto);
> + hns3_set_l2l3l4_len(skb, ol4_proto, il4_proto,
> + &type_cs_vlan_tso,
> + &ol_type_vlan_len_msec);
> + ret = hns3_set_l3l4_type_csum(skb, ol4_proto, il4_proto,
> + &type_cs_vlan_tso,
> + &ol_type_vlan_len_msec);
> + if (ret)
> + return ret;
> +
> + ret = hns3_set_tso(skb, &paylen, &mss,
> + &type_cs_vlan_tso);
> + if (ret)
> + return ret;
> + }
> +
> + /* Set txbd */
> + desc->tx.ol_type_vlan_len_msec =
> + cpu_to_le32(ol_type_vlan_len_msec);
> + desc->tx.type_cs_vlan_tso_len =
> + cpu_to_le32(type_cs_vlan_tso);
> + desc->tx.paylen = cpu_to_le16(paylen);
> + desc->tx.mss = cpu_to_le16(mss);
> + }
> +
> + /* move ring pointer to next.*/
> + ring_ptr_move_fw(ring, next_to_use);
> +
> + return 0;
> +}
> +
> +static int hns3_fill_desc_tso(struct hns3_enet_ring *ring, void *priv,
> + int size, dma_addr_t dma, int frag_end,
> + enum hns_desc_type type)
> +{
> + int frag_buf_num;
> + int sizeoflast;
> + int ret, k;
> +
> + frag_buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE;
> + sizeoflast = size % HNS3_MAX_BD_SIZE;
> + sizeoflast = sizeoflast ? sizeoflast : HNS3_MAX_BD_SIZE;
> +
> + /* When the frag size is bigger than hardware, split this frag */
> + for (k = 0; k < frag_buf_num; k++) {
> + ret = hns3_fill_desc(ring, priv,
> + (k == frag_buf_num - 1) ?
> + sizeoflast : HNS3_MAX_BD_SIZE,
> + dma + HNS3_MAX_BD_SIZE * k,
> + frag_end && (k == frag_buf_num - 1) ? 1 : 0,
> + (type == DESC_TYPE_SKB && !k) ?
> + DESC_TYPE_SKB : DESC_TYPE_PAGE);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int hns3_nic_maybe_stop_tso(struct sk_buff **out_skb, int *bnum,
> + struct hns3_enet_ring *ring)
> +{
> + struct sk_buff *skb = *out_skb;
> + struct skb_frag_struct *frag;
> + int bdnum_for_frag;
> + int frag_num;
> + int buf_num;
> + int size;
> + int i;
> +
> + size = skb_headlen(skb);
> + buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE;
> +
> + frag_num = skb_shinfo(skb)->nr_frags;
> + for (i = 0; i < frag_num; i++) {
> + frag = &skb_shinfo(skb)->frags[i];
> + size = skb_frag_size(frag);
> + bdnum_for_frag =
> + (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE;
> + if (bdnum_for_frag > HNS3_MAX_BD_PER_FRAG)
> + return -ENOMEM;
> +
> + buf_num += bdnum_for_frag;
> + }
> +
> + if (buf_num > ring_space(ring))
> + return -EBUSY;
> +
> + *bnum = buf_num;
> + return 0;
> +}
> +
> +static int hns3_nic_maybe_stop_tx(struct sk_buff **out_skb, int *bnum,
> + struct hns3_enet_ring *ring)
> +{
> + struct sk_buff *skb = *out_skb;
> + int buf_num;
> +
> + /* No. of segments (plus a header) */
> + buf_num = skb_shinfo(skb)->nr_frags + 1;
> +
> + if (buf_num > ring_space(ring))
> + return -EBUSY;
> +
> + *bnum = buf_num;
> +
> + return 0;
> +}
> +
> +static void hns_nic_dma_unmap(struct hns3_enet_ring *ring, int next_to_use_orig)
> +{
> + struct device *dev = ring_to_dev(ring);
> +
> + while (1) {
> + /* check if this is where we started */
> + if (ring->next_to_use == next_to_use_orig)
> + break;
> +
> + /* unmap the descriptor dma address */
> + if (ring->desc_cb[ring->next_to_use].type == DESC_TYPE_SKB)
> + dma_unmap_single(dev,
> + ring->desc_cb[ring->next_to_use].dma,
> + ring->desc_cb[ring->next_to_use].length,
> + DMA_TO_DEVICE);
> + else
> + dma_unmap_page(dev,
> + ring->desc_cb[ring->next_to_use].dma,
> + ring->desc_cb[ring->next_to_use].length,
> + DMA_TO_DEVICE);
> +
> + /* rollback one */
> + ring_ptr_move_bw(ring, next_to_use);
> + }
> +}
> +
> +int hns3_nic_net_xmit_hw(struct net_device *ndev,
> + struct sk_buff *skb,
> + struct hns3_nic_ring_data *ring_data)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hns3_enet_ring *ring = ring_data->ring;
> + struct device *dev = priv->dev;
> + struct netdev_queue *dev_queue;
> + struct skb_frag_struct *frag;
> + int next_to_use_head;
> + int next_to_use_frag;
> + dma_addr_t dma;
> + int buf_num;
> + int seg_num;
> + int size;
> + int ret;
> + int i;
> +
> + if (!skb || !ring)
> + return -ENOMEM;
> +
> + /* Prefetch the data used later */
> + prefetch(skb->data);
> +
> + switch (priv->ops.maybe_stop_tx(&skb, &buf_num, ring)) {
> + case -EBUSY:
> + ring->stats.tx_busy++;
> + goto out_net_tx_busy;
> + case -ENOMEM:
> + ring->stats.sw_err_cnt++;
> + netdev_err(ndev, "no memory to xmit!\n");
> + goto out_err_tx_ok;
> + default:
> + break;
> + }
> +
> + /* No. of segments (plus a header) */
> + seg_num = skb_shinfo(skb)->nr_frags + 1;
> + /* Fill the first part */
> + size = skb_headlen(skb);
> +
> + next_to_use_head = ring->next_to_use;
> +
> + dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
> + if (dma_mapping_error(dev, dma)) {
> + netdev_err(ndev, "TX head DMA map failed\n");
> + ring->stats.sw_err_cnt++;
> + goto out_err_tx_ok;
> + }
> +
> + ret = priv->ops.fill_desc(ring, skb, size, dma, seg_num == 1 ? 1 : 0,
> + DESC_TYPE_SKB);
> + if (ret)
> + goto head_dma_map_err;
> +
> + next_to_use_frag = ring->next_to_use;
> + /* Fill the fragments */
> + for (i = 1; i < seg_num; i++) {
> + frag = &skb_shinfo(skb)->frags[i - 1];
> + size = skb_frag_size(frag);
> + dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
> + if (dma_mapping_error(dev, dma)) {
> + netdev_err(ndev, "TX frag(%d) DMA map failed\n", i);
> + ring->stats.sw_err_cnt++;
> + goto frag_dma_map_err;
> + }
> + ret = priv->ops.fill_desc(ring, skb_frag_page(frag), size, dma,
> + seg_num - 1 == i ? 1 : 0,
> + DESC_TYPE_PAGE);
> +
> + if (ret)
> + goto frag_dma_map_err;
> + }
> +
> + /* Complete translate all packets */
> + dev_queue = netdev_get_tx_queue(ndev, ring_data->queue_index);
> + netdev_tx_sent_queue(dev_queue, skb->len);
> +
> + wmb(); /* Commit all data before submit */
> +
> + hnae_queue_xmit(ring->tqp, buf_num);
> +
> + ring->stats.tx_pkts++;
> + ring->stats.tx_bytes += skb->len;
> +
> + return NETDEV_TX_OK;
> +
> +frag_dma_map_err:
> + hns_nic_dma_unmap(ring, next_to_use_frag);
> +
> +head_dma_map_err:
> + hns_nic_dma_unmap(ring, next_to_use_head);
> +
> +out_err_tx_ok:
> + dev_kfree_skb_any(skb);
> + return NETDEV_TX_OK;
> +
> +out_net_tx_busy:
> + netif_stop_subqueue(ndev, ring_data->queue_index);
> + smp_mb(); /* Commit all data before submit */
> +
> + return NETDEV_TX_BUSY;
> +}
> +
> +static netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb,
> + struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + int ret;
> +
> + ret = hns3_nic_net_xmit_hw(ndev, skb,
> + &tx_ring_data(priv, skb->queue_mapping));
> + if (ret == NETDEV_TX_OK) {
> + netif_trans_update(ndev);
> + ndev->stats.tx_bytes += skb->len;
> + ndev->stats.tx_packets++;
> + }
> +
> + return (netdev_tx_t)ret;
> +}
> +
> +static int hns3_nic_net_set_mac_address(struct net_device *ndev, void *p)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + struct sockaddr *mac_addr = p;
> + int ret;
> +
> + if (!mac_addr || !is_valid_ether_addr((const u8 *)mac_addr->sa_data))
> + return -EADDRNOTAVAIL;
> +
> + ret = h->ae_algo->ops->set_mac_addr(h, mac_addr->sa_data);
> + if (ret) {
> + netdev_err(ndev, "set_mac_address fail, ret=%d!\n", ret);
> + return ret;
> + }
> +
> + ether_addr_copy(ndev->dev_addr, mac_addr->sa_data);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_set_features(struct net_device *netdev,
> + netdev_features_t features)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> +
> + if (features & (NETIF_F_TSO | NETIF_F_TSO6)) {
> + priv->ops.fill_desc = hns3_fill_desc_tso;
> + priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tso;
> + } else {
> + priv->ops.fill_desc = hns3_fill_desc;
> + priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tx;
> + }
> +
> + netdev->features = features;
> + return 0;
> +}
> +
> +static void
> +hns3_nic_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + int queue_num = priv->ae_handle->kinfo.num_tqps;
> + u64 tx_bytes = 0;
> + u64 rx_bytes = 0;
> + u64 tx_pkts = 0;
> + u64 rx_pkts = 0;
> + int idx = 0;
> +
> + for (idx = 0; idx < queue_num; idx++) {
> + tx_bytes += priv->ring_data[idx].ring->stats.tx_bytes;
> + tx_pkts += priv->ring_data[idx].ring->stats.tx_pkts;
> + rx_bytes +=
> + priv->ring_data[idx + queue_num].ring->stats.rx_bytes;
> + rx_pkts += priv->ring_data[idx + queue_num].ring->stats.rx_pkts;
> + }
> +
> + stats->tx_bytes = tx_bytes;
> + stats->tx_packets = tx_pkts;
> + stats->rx_bytes = rx_bytes;
> + stats->rx_packets = rx_pkts;
> +
> + stats->rx_errors = ndev->stats.rx_errors;
> + stats->multicast = ndev->stats.multicast;
> + stats->rx_length_errors = ndev->stats.rx_length_errors;
> + stats->rx_crc_errors = ndev->stats.rx_crc_errors;
> + stats->rx_missed_errors = ndev->stats.rx_missed_errors;
> +
> + stats->tx_errors = ndev->stats.tx_errors;
> + stats->rx_dropped = ndev->stats.rx_dropped;
> + stats->tx_dropped = ndev->stats.tx_dropped;
> + stats->collisions = ndev->stats.collisions;
> + stats->rx_over_errors = ndev->stats.rx_over_errors;
> + stats->rx_frame_errors = ndev->stats.rx_frame_errors;
> + stats->rx_fifo_errors = ndev->stats.rx_fifo_errors;
> + stats->tx_aborted_errors = ndev->stats.tx_aborted_errors;
> + stats->tx_carrier_errors = ndev->stats.tx_carrier_errors;
> + stats->tx_fifo_errors = ndev->stats.tx_fifo_errors;
> + stats->tx_heartbeat_errors = ndev->stats.tx_heartbeat_errors;
> + stats->tx_window_errors = ndev->stats.tx_window_errors;
> + stats->rx_compressed = ndev->stats.rx_compressed;
> + stats->tx_compressed = ndev->stats.tx_compressed;
> +}
> +
> +static void hns3_add_tunnel_port(struct net_device *ndev, u16 port,
> + enum hns3_udp_tnl_type type)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hns3_udp_tunnel *udp_tnl = &priv->udp_tnl[type];
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (udp_tnl->used && udp_tnl->dst_port == port) {
> + udp_tnl->used++;
> + return;
> + }
> +
> + if (udp_tnl->used) {
> + netdev_warn(ndev,
> + "UDP tunnel [%d], port [%d] offload\n", type, port);
> + return;
> + }
> +
> + udp_tnl->dst_port = port;
> + udp_tnl->used = 1;
> + /* TBD send command to hardware to add port */
> + if (h->ae_algo->ops->add_tunnel_udp)
> + h->ae_algo->ops->add_tunnel_udp(h, port);
> +}
> +
> +static void hns3_del_tunnel_port(struct net_device *ndev, u16 port,
> + enum hns3_udp_tnl_type type)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hns3_udp_tunnel *udp_tnl = &priv->udp_tnl[type];
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (!udp_tnl->used || udp_tnl->dst_port != port) {
> + netdev_warn(ndev,
> + "Invalid UDP tunnel port %d\n", port);
> + return;
> + }
> +
> + udp_tnl->used--;
> + if (udp_tnl->used)
> + return;
> +
> + udp_tnl->dst_port = 0;
> + /* TBD send command to hardware to del port */
> + if (h->ae_algo->ops->del_tunnel_udp)
> + h->ae_algo->ops->add_tunnel_udp(h, port);
> +}
> +
> +/* hns3_nic_udp_tunnel_add - Get notifiacetion about UDP tunnel ports
> + * @netdev: This physical ports's netdev
> + * @ti: Tunnel information
> + */
> +static void hns3_nic_udp_tunnel_add(struct net_device *ndev,
> + struct udp_tunnel_info *ti)
> +{
> + u16 port_n = ntohs(ti->port);
> +
> + switch (ti->type) {
> + case UDP_TUNNEL_TYPE_VXLAN:
> + hns3_add_tunnel_port(ndev, port_n, HNS3_UDP_TNL_VXLAN);
> + break;
> + case UDP_TUNNEL_TYPE_GENEVE:
> + hns3_add_tunnel_port(ndev, port_n, HNS3_UDP_TNL_GENEVE);
> + break;
> + default:
> + netdev_err(ndev, "unsupported tunnel type %d\n", ti->type);
> + break;
> + }
> +}
> +
> +static void hns3_nic_udp_tunnel_del(struct net_device *ndev,
> + struct udp_tunnel_info *ti)
> +{
> + u16 port_n = ntohs(ti->port);
> +
> + switch (ti->type) {
> + case UDP_TUNNEL_TYPE_VXLAN:
> + hns3_del_tunnel_port(ndev, port_n, HNS3_UDP_TNL_VXLAN);
> + break;
> + case UDP_TUNNEL_TYPE_GENEVE:
> + hns3_del_tunnel_port(ndev, port_n, HNS3_UDP_TNL_GENEVE);
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static int hns3_setup_tc(struct net_device *ndev, u8 tc)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + struct hnae3_knic_private_info *kinfo = &h->kinfo;
> + int i, ret;
> +
> + if (tc > HNAE3_MAX_TC)
> + return -EINVAL;
> +
> + if (kinfo->num_tc == tc)
> + return 0;
> +
> + if (!ndev)
> + return -EINVAL;
> +
> + if (!tc) {
> + netdev_reset_tc(ndev);
> + return 0;
> + }
> +
> + /* Set num_tc for netdev */
> + ret = netdev_set_num_tc(ndev, tc);
> + if (ret)
> + return ret;
> +
> + /* Set per TC queues for the VSI */
> + for (i = 0; i < HNAE3_MAX_TC; i++) {
> + if (kinfo->tc_info[i].enable)
> + netdev_set_tc_queue(ndev,
> + kinfo->tc_info[i].tc,
> + kinfo->tc_info[i].tqp_count,
> + kinfo->tc_info[i].tqp_offset);
> + }
> +
> + return 0;
> +}
> +
> +static int hns3_nic_setup_tc(struct net_device *dev, u32 handle,
> + u32 chain_index, __be16 protocol,
> + struct tc_to_netdev *tc)
> +{
> + if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
> + return -EINVAL;
> +
> + return hns3_setup_tc(dev, tc->mqprio->num_tc);
> +}
> +
> +static int hns3_vlan_rx_add_vid(struct net_device *ndev,
> + __be16 proto, u16 vid)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret = -EIO;
> +
> + if (h->ae_algo->ops->set_vlan_filter)
> + ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, false);
> +
> + return ret;
> +}
> +
> +static int hns3_vlan_rx_kill_vid(struct net_device *ndev,
> + __be16 proto, u16 vid)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret = -EIO;
> +
> + if (h->ae_algo->ops->set_vlan_filter)
> + ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, true);
> +
> + return ret;
> +}
> +
> +static int hns3_ndo_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
> + u8 qos, __be16 vlan_proto)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret = -EIO;
> +
> + if (h->ae_algo->ops->set_vf_vlan_filter)
> + ret = h->ae_algo->ops->set_vf_vlan_filter(h, vf, vlan,
> + qos, vlan_proto);
> +
> + return ret;
> +}
> +
> +static const struct net_device_ops hns3_nic_netdev_ops = {
> + .ndo_open = hns3_nic_net_open,
> + .ndo_stop = hns3_nic_net_stop,
> + .ndo_start_xmit = hns3_nic_net_xmit,
> + .ndo_set_mac_address = hns3_nic_net_set_mac_address,
> + .ndo_set_features = hns3_nic_set_features,
> + .ndo_get_stats64 = hns3_nic_get_stats64,
> + .ndo_setup_tc = hns3_nic_setup_tc,
> + .ndo_set_rx_mode = hns3_nic_set_rx_mode,
> + .ndo_udp_tunnel_add = hns3_nic_udp_tunnel_add,
> + .ndo_udp_tunnel_del = hns3_nic_udp_tunnel_del,
> + .ndo_vlan_rx_add_vid = hns3_vlan_rx_add_vid,
> + .ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid,
> + .ndo_set_vf_vlan = hns3_ndo_set_vf_vlan,
> +};
> +
> +/* hns3_probe - Device initialization routine
> + * @pdev: PCI device information struct
> + * @ent: entry in hns3_pci_tbl
> + *
> + * hns3_probe initializes a PF identified by a pci_dev structure.
> + * The OS initialization, configuring of the PF private structure,
> + * and a hardware reset occur.
> + *
> + * Returns 0 on success, negative on failure
> + */
> +static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> + struct hnae3_ae_dev *ae_dev;
> + int ret;
> +
> + ae_dev = kzalloc(sizeof(*ae_dev), GFP_KERNEL);
> + if (!ae_dev) {
> + ret = -ENOMEM;
> + return ret;
> + }
> +
> + ae_dev->pdev = pdev;
> + ae_dev->dev_type = HNAE3_DEV_KNIC;
> + pci_set_drvdata(pdev, ae_dev);
> +
> + return hnae3_register_ae_dev(ae_dev);
> +}
> +
> +/* hns3_remove - Device removal routine
> + * @pdev: PCI device information struct
> + */
> +static void hns3_remove(struct pci_dev *pdev)
> +{
> + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
> +
> + hnae3_unregister_ae_dev(ae_dev);
> +
> + pci_set_drvdata(pdev, NULL);
> +}
> +
> +static struct pci_driver hns3_driver = {
> + .name = hns3_driver_name,
> + .id_table = hns3_pci_tbl,
> + .probe = hns3_probe,
> + .remove = hns3_remove,
> +};
> +
> +/* set default feature to hns3 */
> +static void hns3_set_default_feature(struct net_device *ndev)
> +{
> + ndev->priv_flags |= IFF_UNICAST_FLT;
> +
> + ndev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
> + NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +
> + ndev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
> +
> + ndev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
> +
> + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> + NETIF_F_HW_VLAN_CTAG_FILTER |
> + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
> + NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +
> + ndev->vlan_features |=
> + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
> + NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO |
> + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +
> + ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> + NETIF_F_HW_VLAN_CTAG_FILTER |
> + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
> + NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +}
> +
> +static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
> +{
> + unsigned int order = hnae_page_order(ring);
> + struct page *p;
> +
> + p = dev_alloc_pages(order);
> + if (!p)
> + return -ENOMEM;
> +
> + cb->priv = p;
> + cb->page_offset = 0;
> + cb->reuse_flag = 0;
> + cb->buf = page_address(p);
> + cb->length = hnae_page_size(ring);
> + cb->type = DESC_TYPE_PAGE;
> +
> + memset(cb->buf, 0, cb->length);
> +
> + return 0;
> +}
> +
> +static void hns3_free_buffer(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
> +{
> + if (cb->type == DESC_TYPE_SKB)
> + dev_kfree_skb_any((struct sk_buff *)cb->priv);
> + else if (!HNAE3_IS_TX_RING(ring))
> + put_page((struct page *)cb->priv);
> + memset(cb, 0, sizeof(*cb));
> +}
> +
> +static int hns3_map_buffer(struct hns3_enet_ring *ring, struct hns3_desc_cb *cb)
> +{
> + cb->dma = dma_map_page(ring_to_dev(ring), cb->priv, 0,
> + cb->length, ring_to_dma_dir(ring));
> +
> + if (dma_mapping_error(ring_to_dev(ring), cb->dma))
> + return -EIO;
> +
> + return 0;
> +}
> +
> +static void hns3_unmap_buffer(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
> +{
> + if (cb->type == DESC_TYPE_SKB)
> + dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length,
> + ring_to_dma_dir(ring));
> + else
> + dma_unmap_page(ring_to_dev(ring), cb->dma, cb->length,
> + ring_to_dma_dir(ring));
> +}
> +
> +static inline void hns3_buffer_detach(struct hns3_enet_ring *ring, int i)
> +{
> + hns3_unmap_buffer(ring, &ring->desc_cb[i]);
> + ring->desc[i].addr = 0;
> +}
> +
> +static inline void hns3_free_buffer_detach(struct hns3_enet_ring *ring, int i)
> +{
> + struct hns3_desc_cb *cb = &ring->desc_cb[i];
> +
> + if (!ring->desc_cb[i].dma)
> + return;
> +
> + hns3_buffer_detach(ring, i);
> + hns3_free_buffer(ring, cb);
> +}
> +
> +static void hns3_free_buffers(struct hns3_enet_ring *ring)
> +{
> + int i;
> +
> + for (i = 0; i < ring->desc_num; i++)
> + hns3_free_buffer_detach(ring, i);
> +}
> +
> +/* free desc along with its attached buffer */
> +static void hns3_free_desc(struct hns3_enet_ring *ring)
> +{
> + hns3_free_buffers(ring);
> +
> + dma_unmap_single(ring_to_dev(ring), ring->desc_dma_addr,
> + ring->desc_num * sizeof(ring->desc[0]),
> + DMA_BIDIRECTIONAL);
> + ring->desc_dma_addr = 0;
> + kfree(ring->desc);
> + ring->desc = NULL;
> +}
> +
> +static int hns3_alloc_desc(struct hns3_enet_ring *ring)
> +{
> + int size = ring->desc_num * sizeof(ring->desc[0]);
> +
> + ring->desc = kzalloc(size, GFP_KERNEL);
> + if (!ring->desc)
> + return -ENOMEM;
> +
> + ring->desc_dma_addr = dma_map_single(ring_to_dev(ring),
> + ring->desc, size, DMA_BIDIRECTIONAL);
> + if (dma_mapping_error(ring_to_dev(ring), ring->desc_dma_addr)) {
> + ring->desc_dma_addr = 0;
> + kfree(ring->desc);
> + ring->desc = NULL;
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +static inline int hns3_reserve_buffer_map(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
No need to use inline. Leave the compiler to decide. This is true in
general.
> +static bool hns3_get_new_int_gl(struct hns3_enet_ring_group *ring_group)
> +{
> + enum hns3_flow_level_range new_flow_level;
> + struct hns3_enet_tqp_vector *tqp_vector;
> + int packets_per_secs;
> + int bytes_per_usecs;
> + u16 new_int_gl;
> + int usecs;
> +
> + if (!ring_group->int_gl)
> + return false;
> +
> + if (ring_group->total_packets == 0) {
> + ring_group->int_gl = HNS3_INT_GL_50K;
> + ring_group->flow_level = HNS3_FLOW_LOW;
> + return true;
> + }
> + /* Simple throttlerate management
> + * 0-10MB/s lower (50000 ints/s)
> + * 10-20MB/s middle (20000 ints/s)
> + * 20-1249MB/s high (18000 ints/s)
> + * > 40000pps ultra (8000 ints/s)
> + */
> +
> + new_flow_level = ring_group->flow_level;
> + new_int_gl = ring_group->int_gl;
> + tqp_vector = ring_group->ring->tqp_vector;
> + usecs = (ring_group->int_gl << 1);
> + bytes_per_usecs = ring_group->total_bytes / usecs;
> + /* 1000000 microseconds */
> + packets_per_secs = ring_group->total_packets * 1000000 / usecs;
> +
> + switch (new_flow_level) {
> + case HNS3_FLOW_LOW:
> + if (bytes_per_usecs > 10)
> + new_flow_level = HNS3_FLOW_MID;
> + break;
> + case HNS3_FLOW_MID:
> + if (bytes_per_usecs > 20)
> + new_flow_level = HNS3_FLOW_HIGH;
> + else if (bytes_per_usecs <= 10)
> + new_flow_level = HNS3_FLOW_LOW;
> + break;
> + case HNS3_FLOW_HIGH:
> + case HNS3_FLOW_ULTRA:
> + default:
> + if (bytes_per_usecs <= 20)
> + new_flow_level = HNS3_FLOW_MID;
> + break;
> + }
> +#define HNS3_RX_ULTRA_PACKET_RATE 40000
It is not normal to put #defines like this in the middle of the code.
> +
> + if ((packets_per_secs > HNS3_RX_ULTRA_PACKET_RATE) &&
> + (&tqp_vector->rx_group == ring_group))
> + new_flow_level = HNS3_FLOW_ULTRA;
> +
> + switch (new_flow_level) {
> + case HNS3_FLOW_LOW:
> + new_int_gl = HNS3_INT_GL_50K;
> + break;
> + case HNS3_FLOW_MID:
> + new_int_gl = HNS3_INT_GL_20K;
> + break;
> + case HNS3_FLOW_HIGH:
> + new_int_gl = HNS3_INT_GL_18K;
> + break;
> + case HNS3_FLOW_ULTRA:
> + new_int_gl = HNS3_INT_GL_8K;
> + break;
> + default:
> + break;
> + }
> +
> + ring_group->total_bytes = 0;
> + ring_group->total_packets = 0;
> + ring_group->flow_level = new_flow_level;
> + if (new_int_gl != ring_group->int_gl) {
> + ring_group->int_gl = new_int_gl;
> + return true;
> + }
> + return false;
> +}
> +/* Set mac addr if it is configed. or leave it to the AE driver */
configured
> +/* hns3_init_module - Driver registration routine
> + * hns3_init_module is the first routine called when the driver is
> + * loaded. All it does is register with the PCI subsystem.
> + */
> +static int __init hns3_init_module(void)
> +{
> + struct hnae3_client *client;
> + int ret;
> +
> + pr_info("%s: %s - version\n", hns3_driver_name, hns3_driver_string);
> + pr_info("%s: %s\n", hns3_driver_name, hns3_copyright);
> +
> + client = kzalloc(sizeof(*client), GFP_KERNEL);
> + if (!client) {
> + ret = -ENOMEM;
> + goto err_client_alloc;
> + }
> +
> + client->type = HNAE3_CLIENT_KNIC;
> + snprintf(client->name, HNAE3_CLIENT_NAME_LENGTH - 1, "%s",
> + hns3_driver_name);
> +
> + client->ops = &client_ops;
> +
> + ret = hnae3_register_client(client);
> + if (ret)
> + return ret;
> +
> + return pci_register_driver(&hns3_driver);
> +
> +err_client_alloc:
> + return ret;
> +}
> +module_init(hns3_init_module);
> +
> +/* hns3_exit_module - Driver exit cleanup routine
> + * hns3_exit_module is called just before the driver is removed
> + * from memory.
> + */
> +static void __exit hns3_exit_module(void)
> +{
> + pci_unregister_driver(&hns3_driver);
You would normally expect any memory allocated in the init function to
be cleared in the exit function. When does client memory get freed?
Andrew
[toc] | [prev] | [next] | [standalone]
| From | Leon Romanovsky <leon@kernel.org> |
|---|---|
| Date | 2017-06-18 08:10 +0200 |
| Subject | Re: [PATCH V3 net-next 0/8] Hisilicon Network Subsystem 3 Ethernet Driver |
| Message-ID | <tTBzj-1qs-1@gated-at.bofh.it> |
| In reply to | #1668370 |
[Multipart message — attachments visible in raw view] — view raw
On Sat, Jun 17, 2017 at 06:24:23PM +0100, Salil Mehta wrote: > This patch-set contains the support of the HNS3 (Hisilicon Network Subsystem 3) > Ethernet driver for hip08 family of SoCs and future upcoming SoCs. > > Hisilicon's new hip08 SoCs have integrated ethernet based on PCI Express and > hence there was a need of new driver over the previous HNS driver which is > already part of the Linux mainline. This new driver is NOT backward > compatible with HNS. > > This current driver is meant to control the Physical Function and there would > soon be a support of a separate driver for Virtual Function once this base PF > driver has been accepted. Also, this driver is the ongoing development work and > HNS3 Ethernet driver would be incrementally enhanced with more new features. > > High Level Architecture: > > [ Ethtool ] > ^ | > | | > [Ethernet Client] [RoCE Client] . . . [ Ethernet Client ] > --------------------------------------------- | > | | > [ HNAE3 Framework (Register/unregister) ] | > | | > --------------------------------------------- | > [ HNAE Device ] | > | | > [ HCLGE Layer] | > ________________|_________________ | > | | | | > [ MDIO ] [ Scheduler/Shaper ] [ Debugfs ] | > | | | | > |________________|_________________| | > | | > [ IMP command Interface ] | > --------------------------------------------- | > HIP08 H A R D W A R E * > > > Current patch-set broadly adds the support of the following PF functionality: > 1. Basic Rx and Tx functionality > 2. TSO support > 3. Ethtool support > 4. HNAE framework and hardware compatability layer > 5. Scheduler and Shaper support in transmit function > 6. MDIO support > 7. kernel build supporrt, Makefiles, Kconfig etc. Since it is RoCE too, it will be handy to CC: linux-rdma@ for this too. Thanks
[toc] | [prev] | [next] | [standalone]
| From | Bo Yu <tsu.yubo@gmail.com> |
|---|---|
| Date | 2017-06-18 19:00 +0200 |
| Subject | Re: [PATCH V3 net-next 1/8] net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC |
| Message-ID | <tTLIm-7ER-5@gated-at.bofh.it> |
| In reply to | #1668370 |
Hi,
On Sat, Jun 17, 2017 at 06:24:24PM +0100, Salil Mehta wrote:
>+ struct notifier_block notifier_block;
>+ /* Vxlan/Geneve information */
>+ struct hns3_udp_tunnel udp_tnl[HNS3_UDP_TNL_MAX];
>+};
>+
>+/* the distance between [begin, end) in a ring buffer
>+ * note: there is a unuse slot between the begin and the end
>+ */
>+static inline int ring_dist(struct hns3_enet_ring *ring, int begin, int end)
>+{
>+ return (end - begin + ring->desc_num) % ring->desc_num;
>+}
>+
>+static inline int ring_space(struct hns3_enet_ring *ring)
>+{
>+ return ring->desc_num -
>+ ring_dist(ring, ring->next_to_clean, ring->next_to_use) - 1;
>+}
>+
>+static inline int is_ring_empty(struct hns3_enet_ring *ring)
>+{
>+ return ring->next_to_use == ring->next_to_clean;
>+}
>+
>+static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
>+{
>+ u8 __iomem *reg_addr = READ_ONCE(base);
>+
>+ writel(value, reg_addr + reg);
>+}
>+
>+#define hns3_write_dev(a, reg, value) \
>+ hns3_write_reg((a)->io_base, (reg), (value))
>+
>+#define hnae_queue_xmit(tqp, buf_num) writel_relaxed(buf_num, \
>+ (tqp)->io_base + HNS3_RING_TX_RING_TAIL_REG)
>+
>+#define ring_to_dev(ring) (&(ring)->tqp->handle->pdev->dev)
>+
>+#define ring_to_dma_dir(ring) (HNAE3_IS_TX_RING(ring) ? \
>+ DMA_TO_DEVICE : DMA_FROM_DEVICE)
>+
>+#define tx_ring_data(priv, idx) ((priv)->ring_data[idx])
>+
>+#define hnae_buf_size(_ring) ((_ring)->buf_size)
>+#define hnae_page_order(_ring) (get_order(hnae_buf_size(_ring)))
>+#define hnae_page_size(_ring) (PAGE_SIZE << hnae_page_order(_ring))
>+
>+/* iterator for handling rings in ring group */
>+#define hns3_for_each_ring(pos, head) \
>+ for (pos = (head).ring; pos != NULL; pos = pos->next)
Only a pos? Comparsion to NULL could be written "pos" noticed by
checkpatch.
>+
>+void hns3_ethtool_set_ops(struct net_device *ndev);
>+
>+int hns3_nic_net_xmit_hw(
>+ struct net_device *ndev,
>+ struct sk_buff *skb,
>+ struct hns3_nic_ring_data *ring_data);
>+int hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget);
>+int hns3_clean_rx_ring_ex(
>+ struct hns3_enet_ring *ring,
>+ struct sk_buff **skb_ex,
>+ int budget);
>+#endif
>--
>2.7.4
>
>
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web