add HW layer related definitions and product ops Signed-off-by: illusion.wang --- .../net/ethernet/nebula-matrix/nbl/Makefile | 4 +- .../net/ethernet/nebula-matrix/nbl/nbl_core.h | 11 ++ .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c | 179 ++++++++++++++++++ .../nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h | 13 ++ .../nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h | 156 +++++++++++++++ .../nbl/nbl_include/nbl_def_hw.h | 23 +++ .../nbl/nbl_include/nbl_include.h | 14 ++ .../net/ethernet/nebula-matrix/nbl/nbl_main.c | 19 +- 8 files changed, 416 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h create mode 100644 drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h diff --git a/drivers/net/ethernet/nebula-matrix/nbl/Makefile b/drivers/net/ethernet/nebula-matrix/nbl/Makefile index df16a3436a5c..d5cadc289366 100644 --- a/drivers/net/ethernet/nebula-matrix/nbl/Makefile +++ b/drivers/net/ethernet/nebula-matrix/nbl/Makefile @@ -4,8 +4,10 @@ obj-$(CONFIG_NBL_CORE) := nbl_core.o -nbl_core-objs += nbl_main.o +nbl_core-objs += nbl_hw/nbl_hw_leonis/nbl_hw_leonis.o \ + nbl_main.o # Provide include files ccflags-y += -I$(srctree)/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/ +ccflags-y += -I$(srctree)/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw ccflags-y += -I$(srctree)/drivers/net/ethernet/nebula-matrix/nbl/ diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h index 4e2618bef23a..33ed810ec7d0 100644 --- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core.h @@ -9,12 +9,16 @@ #include #include "nbl_product_base.h" +#include "nbl_def_hw.h" #include "nbl_def_common.h" #define NBL_ADAP_TO_PDEV(adapter) ((adapter)->pdev) #define NBL_ADAP_TO_DEV(adapter) (&((adapter)->pdev->dev)) #define NBL_ADAP_TO_COMMON(adapter) (&((adapter)->common)) #define NBL_ADAP_TO_RPDUCT_BASE_OPS(adapter) ((adapter)->product_base_ops) + +#define NBL_ADAP_TO_HW_MGT(adapter) ((adapter)->core.hw_mgt) +#define NBL_ADAP_TO_HW_OPS_TBL(adapter) ((adapter)->intf.hw_ops_tbl) #define NBL_CAP_TEST_BIT(val, loc) (((val) >> (loc)) & 0x1) #define NBL_CAP_IS_CTRL(val) NBL_CAP_TEST_BIT(val, NBL_CAP_HAS_CTRL_BIT) @@ -34,9 +38,16 @@ enum { }; struct nbl_interface { + struct nbl_hw_ops_tbl *hw_ops_tbl; }; struct nbl_core { + void *hw_mgt; + void *res_mgt; + void *disp_mgt; + void *serv_mgt; + void *dev_mgt; + void *chan_mgt; }; struct nbl_adapter { diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c new file mode 100644 index 000000000000..40701ff147e2 --- /dev/null +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Nebula Matrix Limited. + * Author: + */ + +#include "nbl_hw_leonis.h" + +static struct nbl_hw_ops hw_ops = { +}; + +/* Structure starts here, adding an op should not modify anything below */ +static int nbl_hw_setup_hw_mgt(struct nbl_common_info *common, + struct nbl_hw_mgt_leonis **hw_mgt_leonis) +{ + struct device *dev; + + dev = NBL_COMMON_TO_DEV(common); + *hw_mgt_leonis = + devm_kzalloc(dev, sizeof(struct nbl_hw_mgt_leonis), GFP_KERNEL); + if (!*hw_mgt_leonis) + return -ENOMEM; + + (&(*hw_mgt_leonis)->hw_mgt)->common = common; + + return 0; +} + +static void nbl_hw_remove_hw_mgt(struct nbl_common_info *common, + struct nbl_hw_mgt_leonis **hw_mgt_leonis) +{ + struct device *dev; + + dev = NBL_COMMON_TO_DEV(common); + devm_kfree(dev, *hw_mgt_leonis); + *hw_mgt_leonis = NULL; +} + +static int nbl_hw_setup_ops(struct nbl_common_info *common, + struct nbl_hw_ops_tbl **hw_ops_tbl, + struct nbl_hw_mgt_leonis *hw_mgt_leonis) +{ + struct device *dev; + + dev = NBL_COMMON_TO_DEV(common); + *hw_ops_tbl = + devm_kzalloc(dev, sizeof(struct nbl_hw_ops_tbl), GFP_KERNEL); + if (!*hw_ops_tbl) + return -ENOMEM; + + (*hw_ops_tbl)->ops = &hw_ops; + (*hw_ops_tbl)->priv = hw_mgt_leonis; + + return 0; +} + +static void nbl_hw_remove_ops(struct nbl_common_info *common, + struct nbl_hw_ops_tbl **hw_ops_tbl) +{ + struct device *dev; + + dev = NBL_COMMON_TO_DEV(common); + devm_kfree(dev, *hw_ops_tbl); + *hw_ops_tbl = NULL; +} + +int nbl_hw_init_leonis(void *p, struct nbl_init_param *param) +{ + struct nbl_adapter *adapter = (struct nbl_adapter *)p; + struct nbl_common_info *common; + struct pci_dev *pdev; + struct nbl_hw_mgt_leonis **hw_mgt_leonis; + struct nbl_hw_mgt *hw_mgt; + struct nbl_hw_ops_tbl **hw_ops_tbl; + int bar_mask; + int ret = 0; + + common = NBL_ADAP_TO_COMMON(adapter); + hw_mgt_leonis = + (struct nbl_hw_mgt_leonis **)&NBL_ADAP_TO_HW_MGT(adapter); + hw_ops_tbl = &NBL_ADAP_TO_HW_OPS_TBL(adapter); + pdev = NBL_COMMON_TO_PDEV(common); + + ret = nbl_hw_setup_hw_mgt(common, hw_mgt_leonis); + if (ret) + goto setup_mgt_fail; + + hw_mgt = &(*hw_mgt_leonis)->hw_mgt; + bar_mask = BIT(NBL_MEMORY_BAR) | BIT(NBL_MAILBOX_BAR); + ret = pci_request_selected_regions(pdev, bar_mask, NBL_DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, + "Request memory bar and mailbox bar failed, err = %d\n", + ret); + goto request_bar_region_fail; + } + + if (param->caps.has_ctrl) { + hw_mgt->hw_addr = + ioremap(pci_resource_start(pdev, NBL_MEMORY_BAR), + pci_resource_len(pdev, NBL_MEMORY_BAR) - + NBL_RDMA_NOTIFY_OFF); + if (!hw_mgt->hw_addr) { + dev_err(&pdev->dev, "Memory bar ioremap failed\n"); + ret = -EIO; + goto ioremap_err; + } + hw_mgt->hw_size = pci_resource_len(pdev, NBL_MEMORY_BAR) - + NBL_RDMA_NOTIFY_OFF; + } else { + hw_mgt->hw_addr = + ioremap(pci_resource_start(pdev, NBL_MEMORY_BAR), + NBL_RDMA_NOTIFY_OFF); + if (!hw_mgt->hw_addr) { + dev_err(&pdev->dev, "Memory bar ioremap failed\n"); + ret = -EIO; + goto ioremap_err; + } + hw_mgt->hw_size = NBL_RDMA_NOTIFY_OFF; + } + + hw_mgt->notify_offset = 0; + hw_mgt->mailbox_bar_hw_addr = pci_ioremap_bar(pdev, NBL_MAILBOX_BAR); + if (!hw_mgt->mailbox_bar_hw_addr) { + dev_err(&pdev->dev, "Mailbox bar ioremap failed\n"); + ret = -EIO; + goto mailbox_ioremap_err; + } + + spin_lock_init(&hw_mgt->reg_lock); + hw_mgt->should_lock = true; + + ret = nbl_hw_setup_ops(common, hw_ops_tbl, *hw_mgt_leonis); + if (ret) + goto setup_ops_fail; + + (*hw_mgt_leonis)->ro_enable = pcie_relaxed_ordering_enabled(pdev); + + return 0; + +setup_ops_fail: + iounmap(hw_mgt->mailbox_bar_hw_addr); +mailbox_ioremap_err: + iounmap(hw_mgt->hw_addr); +ioremap_err: + pci_release_selected_regions(pdev, bar_mask); +request_bar_region_fail: + nbl_hw_remove_hw_mgt(common, hw_mgt_leonis); +setup_mgt_fail: + return ret; +} + +void nbl_hw_remove_leonis(void *p) +{ + struct nbl_adapter *adapter = (struct nbl_adapter *)p; + struct nbl_common_info *common; + struct nbl_hw_mgt_leonis **hw_mgt_leonis; + struct nbl_hw_ops_tbl **hw_ops_tbl; + struct pci_dev *pdev; + u8 __iomem *hw_addr; + u8 __iomem *mailbox_bar_hw_addr; + int bar_mask = BIT(NBL_MEMORY_BAR) | BIT(NBL_MAILBOX_BAR); + + common = NBL_ADAP_TO_COMMON(adapter); + hw_mgt_leonis = + (struct nbl_hw_mgt_leonis **)&NBL_ADAP_TO_HW_MGT(adapter); + hw_ops_tbl = &NBL_ADAP_TO_HW_OPS_TBL(adapter); + pdev = NBL_COMMON_TO_PDEV(common); + + hw_addr = (*hw_mgt_leonis)->hw_mgt.hw_addr; + mailbox_bar_hw_addr = (*hw_mgt_leonis)->hw_mgt.mailbox_bar_hw_addr; + + iounmap(mailbox_bar_hw_addr); + iounmap(hw_addr); + pci_release_selected_regions(pdev, bar_mask); + nbl_hw_remove_hw_mgt(common, hw_mgt_leonis); + + nbl_hw_remove_ops(common, hw_ops_tbl); +} diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h new file mode 100644 index 000000000000..b078b765f772 --- /dev/null +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0*/ +/* + * Copyright (c) 2025 Nebula Matrix Limited. + * Author: + */ + +#ifndef _NBL_HW_LEONIS_H_ +#define _NBL_HW_LEONIS_H_ + +#include "nbl_core.h" +#include "nbl_hw_reg.h" + +#endif diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h new file mode 100644 index 000000000000..51518bb78b4f --- /dev/null +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_reg.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: GPL-2.0*/ +/* + * Copyright (c) 2025 Nebula Matrix Limited. + * Author: + */ + +#ifndef _NBL_HW_REG_H_ +#define _NBL_HW_REG_H_ + +#include "nbl_core.h" + +#define NBL_HW_MGT_TO_COMMON(hw_mgt) ((hw_mgt)->common) +#define NBL_HW_MGT_TO_DEV(hw_mgt) \ + NBL_COMMON_TO_DEV(NBL_HW_MGT_TO_COMMON(hw_mgt)) +#define NBL_MEMORY_BAR (0) +#define NBL_MAILBOX_BAR (2) +#define NBL_RDMA_NOTIFY_OFF (8192) + +struct nbl_hw_mgt { + struct nbl_common_info *common; + u8 __iomem *hw_addr; + u8 __iomem *mailbox_bar_hw_addr; + u64 notify_offset; + u32 version; + u32 hw_size; + spinlock_t reg_lock; /* Protect reg access */ + bool should_lock; + u8 resv[3]; + enum nbl_hw_status hw_status; +}; + +static inline u32 rd32(u8 __iomem *addr, u64 reg) +{ + return readl(addr + (reg)); +} + +static inline void wr32_barrier(u8 __iomem *addr, u64 reg, u32 value) +{ + writel((value), (addr + (reg))); +} + +static inline void nbl_hw_rd_regs(struct nbl_hw_mgt *hw_mgt, u64 reg, + u8 *data, u32 len) +{ + u32 size = len / 4; + u32 i = 0; + + if (len % 4) + return; + + if (hw_mgt->hw_status) { + for (i = 0; i < size; i++) + *(u32 *)(data + i * sizeof(u32)) = U32_MAX; + return; + } + + spin_lock(&hw_mgt->reg_lock); + + for (i = 0; i < size; i++) + *(u32 *)(data + i * sizeof(u32)) = + rd32(hw_mgt->hw_addr, reg + i * sizeof(u32)); + spin_unlock(&hw_mgt->reg_lock); +} + +static inline void nbl_hw_wr_regs(struct nbl_hw_mgt *hw_mgt, + u64 reg, const u8 *data, u32 len) +{ + u32 size = len / 4; + u32 i = 0; + + if (len % 4) + return; + + if (hw_mgt->hw_status) + return; + spin_lock(&hw_mgt->reg_lock); + for (i = 0; i < size; i++) + /* Used for emu, make sure that we won't write too frequently */ + wr32_barrier(hw_mgt->hw_addr, reg + i * sizeof(u32), + *(u32 *)(data + i * sizeof(u32))); + spin_unlock(&hw_mgt->reg_lock); +} + +static inline void nbl_hw_wr32(struct nbl_hw_mgt *hw_mgt, u64 reg, u32 value) +{ + if (hw_mgt->hw_status) + return; + + /* Used for emu, make sure that we won't write too frequently */ + wr32_barrier(hw_mgt->hw_addr, reg, value); +} + +static inline u32 nbl_hw_rd32(struct nbl_hw_mgt *hw_mgt, u64 reg) +{ + if (hw_mgt->hw_status) + return U32_MAX; + + return rd32(hw_mgt->hw_addr, reg); +} + +static inline void nbl_mbx_wr32(void *priv, u64 reg, u32 value) +{ + struct nbl_hw_mgt *hw_mgt = (struct nbl_hw_mgt *)priv; + + if (hw_mgt->hw_status) + return; + + writel((value), ((hw_mgt)->mailbox_bar_hw_addr + (reg))); +} + +static inline u32 nbl_mbx_rd32(void *priv, u64 reg) +{ + struct nbl_hw_mgt *hw_mgt = (struct nbl_hw_mgt *)priv; + + if (hw_mgt->hw_status) + return U32_MAX; + + return readl((hw_mgt)->mailbox_bar_hw_addr + (reg)); +} + +static inline void nbl_hw_read_mbx_regs(struct nbl_hw_mgt *hw_mgt, + u64 reg, u8 *data, u32 len) +{ + u32 i = 0; + + if (len % 4) + return; + + for (i = 0; i < len / 4; i++) + *(u32 *)(data + i * sizeof(u32)) = + nbl_mbx_rd32(hw_mgt, reg + i * sizeof(u32)); +} + +static inline void nbl_hw_write_mbx_regs(struct nbl_hw_mgt *hw_mgt, + u64 reg, const u8 *data, u32 len) +{ + u32 i = 0; + + if (len % 4) + return; + + for (i = 0; i < len / 4; i++) + /* Used for emu, make sure that we won't write too frequently */ + nbl_mbx_wr32(hw_mgt, reg + i * sizeof(u32), + *(u32 *)(data + i * sizeof(u32))); +} + +/* Mgt structure for each product. + * Every indivisual mgt must have the common mgt as its first member, + * and contains its unique data structure in the reset of it. + */ +struct nbl_hw_mgt_leonis { + struct nbl_hw_mgt hw_mgt; + bool ro_enable; +}; +#endif diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h new file mode 100644 index 000000000000..6ac72e26ccd6 --- /dev/null +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_hw.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0*/ +/* + * Copyright (c) 2025 Nebula Matrix Limited. + * Author: + */ + +#ifndef _NBL_DEF_HW_H_ +#define _NBL_DEF_HW_H_ + +#include "nbl_include.h" + +struct nbl_hw_ops { +}; + +struct nbl_hw_ops_tbl { + struct nbl_hw_ops *ops; + void *priv; +}; + +int nbl_hw_init_leonis(void *p, struct nbl_init_param *param); +void nbl_hw_remove_leonis(void *p); + +#endif diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h index 6f655d95d654..e620feb382c1 100644 --- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_include.h @@ -12,11 +12,25 @@ /* ------ Basic definitions ------- */ #define NBL_DRIVER_NAME "nbl_core" +#define NBL_MAX_PF 8 +#define NBL_NEXT_ID(id, max) \ + ({ \ + typeof(id) _id = (id); \ + ((_id) == (max) ? 0 : (_id) + 1); \ + }) + enum nbl_product_type { NBL_LEONIS_TYPE, NBL_PRODUCT_MAX, }; +enum nbl_hw_status { + NBL_HW_NOMAL, + /* Most hw module is not work nomal exclude pcie/emp */ + NBL_HW_FATAL_ERR, + NBL_HW_STATUS_MAX, +}; + struct nbl_func_caps { u32 has_ctrl:1; u32 has_net:1; diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c index d9d79803bef5..a93aa98f2316 100644 --- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_main.c @@ -9,8 +9,8 @@ static struct nbl_product_base_ops nbl_product_base_ops[NBL_PRODUCT_MAX] = { { - .hw_init = NULL, - .hw_remove = NULL, + .hw_init = nbl_hw_init_leonis, + .hw_remove = nbl_hw_remove_leonis, .res_init = NULL, .res_remove = NULL, .chan_init = NULL, @@ -33,6 +33,7 @@ struct nbl_adapter *nbl_core_init(struct pci_dev *pdev, struct nbl_adapter *adapter; struct nbl_common_info *common; struct nbl_product_base_ops *product_base_ops; + int ret = 0; if (!pdev) return NULL; @@ -60,14 +61,28 @@ struct nbl_adapter *nbl_core_init(struct pci_dev *pdev, nbl_core_setup_product_ops(adapter, param, &product_base_ops); + /* + *every product's hw/chan/res layer has a great difference, + *so call their own init ops + */ + ret = product_base_ops->hw_init(adapter, param); + if (ret) + goto hw_init_fail; + return adapter; +hw_init_fail: + devm_kfree(&pdev->dev, adapter); + return NULL; } void nbl_core_remove(struct nbl_adapter *adapter) { + struct nbl_product_base_ops *product_base_ops; struct device *dev; dev = NBL_ADAP_TO_DEV(adapter); + product_base_ops = NBL_ADAP_TO_RPDUCT_BASE_OPS(adapter); + product_base_ops->hw_remove(adapter); devm_kfree(dev, adapter); } -- 2.47.3