net: hinic3: Add a driver for Huawei 3rd gen NIC - management interfaces
Subsystems (4)
Fan Gong
maintainerv14 cover net: hinic3: Add a driver for Huawei 3rd gen NIC - management interfaces
This is the 2/3 patch of the patch-set described below.
The patch-set contains driver for Huawei's 3rd generation HiNIC Ethernet device that will be available in the future.
This is an SRIOV device, designed for data centers. Initially, the driver only supports VFs.
Following the discussion over RFC01, the code will be submitted in separate smaller patches where until the last patch the driver is non-functional. The RFC02 submission contains overall view of the entire driver but every patch will be posted as a standalone submission.
Changes:
PATCH 02 V01: https://lore.kernel.org/netdev/[email protected]
PATCH 02 V02: https://lore.kernel.org/netdev/[email protected]
* Fix build allmodconfig warning (patchwork)
* Update cover-letter changes information.
PATCH 02 V03: https://lore.kernel.org/netdev/[email protected]
* Use refcount_*() instead of atomic_*() (Jakub Kicinski)
* Consistency fixes : HIG->HIGH, BAR45->BAR4/5 , etc (ALOK TIWARI)
* Code format fixes : use \n before return, remove extra spaces (ALOK TIWARI)
* Remove hinic3_request_irq redundant error print (ALOK TIWARI)
* Modify hinic3_wq_create error print (ALOK TIWARI)
PATCH 02 V04: https://lore.kernel.org/netdev/[email protected]
* Break it up into smaller patches (Jakub Kicinski)
PATCH 02 V05: https://lore.kernel.org/netdev/[email protected]
* Fix build clang warning (Jakub Kicinski)
PATCH 02 V06: https://lore.kernel.org/netdev/[email protected]
* Use kmalloc instead of kzalloc for cmd_buf allocation (Vadim Fedorenko)
* Use usleep_range() for avoid CPU busy waiting (Vadim Fedorenko)
* Use kcalloc for intr_coalesce initialization (Vadim Fedorenko)
* Code format fixes: use reverse x-mas tree (Vadim Fedorenko)
* Simplify hinic3_mbox_pre_init logic (Vadim Fedorenko)
PATCH 02 V07: https://lore.kernel.org/netdev/[email protected]
* Use threaded IRQ instead of tasklet (Paolo Abeni)
* Use wmb instead of rmb in cmdq_sync_cmd_handler (Paolo Abeni)
PATCH 02 V08: https://lore.kernel.org/netdev/[email protected]
* Remove msg_send_lock to avoid a double-locking schema (Vadim Fedorenko)
* Use send_msg_id when assigning the value to msg_id (Vadim Fedorenko)
PATCH 02 V09: https://lore.kernel.org/netdev/[email protected]
* Use iowrite32be & ioread32be instead of writel & readl (Jakub Kicinski)
* Use queue_work instead of queue_work_on(WORK_CPU_UNBOUND...) (Jakub Kicinski)
* Modify aeqe & ceqe wmb comment (Jakub Kicinski)
* Remove synchronize_irq before free_irq (Jakub Kicinski)
PATCH 02 V10: https://lore.kernel.org/netdev/[email protected]
* Use spin_lock in aeq & ceq events instead of bits ops (Jakub Kicinski)
* Modify memory barriers comments to explain more clearly (Jakub Kicinski)
PATCH 02 V11: https://lore.kernel.org/netdev/[email protected]
* Remove unused cb_state variable (Simon Horman)
PATCH 02 V12: https://lore.kernel.org/netdev/[email protected]
* Use swab32_array instead of swab32 (Simon Horman)
* Use __le16/32/64 value in structs for interacting with HW (Simon Horman)
* Remove const char __iomem * casts (Simon Horman)
* use u8 * instead of void * to be more meaningful (Simon Horman)
* use FIELD_PREP to mask and shift up values (Simon Horman)
PATCH 02 V13: https://lore.kernel.org/netdev/[email protected]
* Handle sparse build warnings (Kernel test robot)
PATCH 02 V14:
* Use disable_work_sync() instead of cancel_work_sync() (Paolo Abeni)
* Use goto statement in hinic3_pre_init error handling (Paolo Abeni)
Fan Gong (8):
hinic3: Async Event Queue interfaces
hinic3: Complete Event Queue interfaces
hinic3: Command Queue framework
hinic3: Command Queue interfaces
hinic3: TX & RX Queue coalesce interfaces
hinic3: Mailbox framework
hinic3: Mailbox management interfaces
hinic3: Interrupt request configuration
drivers/net/ethernet/huawei/hinic3/Makefile | 4 +- .../net/ethernet/huawei/hinic3/hinic3_cmdq.c | 915 ++++++++++++++++++ .../net/ethernet/huawei/hinic3/hinic3_cmdq.h | 156 +++ .../ethernet/huawei/hinic3/hinic3_common.c | 23 + .../ethernet/huawei/hinic3/hinic3_common.h | 27 + .../net/ethernet/huawei/hinic3/hinic3_csr.h | 79 ++ .../net/ethernet/huawei/hinic3/hinic3_eqs.c | 776 +++++++++++++++ .../net/ethernet/huawei/hinic3/hinic3_eqs.h | 122 +++ .../ethernet/huawei/hinic3/hinic3_hw_cfg.c | 43 + .../ethernet/huawei/hinic3/hinic3_hw_comm.c | 31 + .../ethernet/huawei/hinic3/hinic3_hw_comm.h | 13 + .../ethernet/huawei/hinic3/hinic3_hw_intf.h | 36 + .../net/ethernet/huawei/hinic3/hinic3_hwif.c | 148 ++- .../net/ethernet/huawei/hinic3/hinic3_hwif.h | 16 + .../net/ethernet/huawei/hinic3/hinic3_irq.c | 136 ++- .../net/ethernet/huawei/hinic3/hinic3_main.c | 61 +- .../net/ethernet/huawei/hinic3/hinic3_mbox.c | 848 +++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_mbox.h | 126 +++ .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 14 +- .../net/ethernet/huawei/hinic3/hinic3_tx.c | 6 +- .../net/ethernet/huawei/hinic3/hinic3_wq.c | 109 +++ .../net/ethernet/huawei/hinic3/hinic3_wq.h | 19 +- 22 files changed, 3686 insertions(+), 22 deletions(-) create mode 100644 drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c create mode 100644 drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.h create mode 100644 drivers/net/ethernet/huawei/hinic3/hinic3_csr.h create mode 100644 drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c create mode 100644 drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h
base-commit: bc4c0a48bdad7f225740b8e750fdc1da6d85e1eb
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 1/8 hinic3: Async Event Queue interfaces
Add async event queue interfaces initialization. It allows driver to handle async events reported by HW.
--- drivers/net/ethernet/huawei/hinic3/Makefile | 1 + .../ethernet/huawei/hinic3/hinic3_common.c | 9 + .../ethernet/huawei/hinic3/hinic3_common.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_csr.h | 65 +++ .../net/ethernet/huawei/hinic3/hinic3_eqs.c | 497 ++++++++++++++++++ .../net/ethernet/huawei/hinic3/hinic3_eqs.h | 90 ++++ .../ethernet/huawei/hinic3/hinic3_hw_cfg.c | 43 ++ .../net/ethernet/huawei/hinic3/hinic3_hwif.c | 28 + .../net/ethernet/huawei/hinic3/hinic3_hwif.h | 5 + 9 files changed, 740 insertions(+)
drivers/net/ethernet/huawei/hinic3/Makefile +1 -0
@@ -4,6 +4,7 @@ obj-$(CONFIG_HINIC3) += hinic3.o hinic3-objs := hinic3_common.o \ + hinic3_eqs.o \ hinic3_hw_cfg.o \ hinic3_hw_comm.o \ hinic3_hwdev.o \
drivers/net/ethernet/huawei/hinic3/hinic3_common.c +9 -0
@@ -51,3 +51,12 @@ void hinic3_dma_free_coherent_align(struct device *dev,dma_free_coherent (dev, mem_align->real_size, mem_align->ori_vaddr, mem_align->ori_paddr); } + +/* Data provided to/by cmdq is arranged in structs with little endian fields but +* every dword (32bits) should be swapped since HW swaps it again when it +* copies it from/to host memory. +*/ +void hinic3_cmdq_buf_swab32 (void *data,int len) +{ +swab32_array (data, len /sizeof (u32)); +}
drivers/net/ethernet/huawei/hinic3/hinic3_common.h +2 -0
@@ -24,4 +24,6 @@ int hinic3_dma_zalloc_coherent_align(struct device *dev, u32 size, u32 align,void hinic3_dma_free_coherent_align (struct device *dev,struct hinic3_dma_addr_align *mem_align); +void hinic3_cmdq_buf_swab32 (void *data,int len); +#endif
drivers/net/ethernet/huawei/hinic3/hinic3_csr.h new file +65 -0
65 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c new file +497 -0
497 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h new file +90 -0
90 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_hw_cfg.c +43 -0
49 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_hwif.c +28 -0
@@ -6,15 +6,43 @@#include <linux/io.h> #include "hinic3_common.h" +#include "hinic3_csr.h" #include "hinic3_hwdev.h" #include "hinic3_hwif.h" +#define HINIC3_GET_REG_ADDR (reg) ((reg) & (HINIC3_REGS_FLAG_MASK)) + +static void __iomem *hinic3_reg_addr (struct hinic3_hwif *hwif,u32 reg) +{ +return hwif->cfg_regs_base +HINIC3_GET_REG_ADDR (reg); +} + +u32 hinic3_hwif_read_reg (struct hinic3_hwif *hwif,u32 reg) +{ +void __iomem *addr =hinic3_reg_addr (hwif, reg); + +return ioread32be (addr); +} + +void hinic3_hwif_write_reg (struct hinic3_hwif *hwif,u32 reg,u32 val) +{ +void __iomem *addr =hinic3_reg_addr (hwif, reg); + +iowrite32be (val, addr); +} +void hinic3_set_msix_state (struct hinic3_hwdev *hwdev,u16 msix_idx,enum hinic3_msix_state flag) {/* Completed by later submission due to LoC limit. */ } +void hinic3_msix_intr_clear_resend_bit (struct hinic3_hwdev *hwdev,u16 msix_idx, +u8 clear_resend_en) +{ +/* Completed by later submission due to LoC limit. */ +} +u16 hinic3_global_func_id (struct hinic3_hwdev *hwdev) {return hwdev->hwif->attr.func_global_idx;
drivers/net/ethernet/huawei/hinic3/hinic3_hwif.h +5 -0
@@ -50,8 +50,13 @@ enum hinic3_msix_state { HINIC3_MSIX_DISABLE, }; +u32 hinic3_hwif_read_reg (struct hinic3_hwif *hwif,u32 reg); +void hinic3_hwif_write_reg (struct hinic3_hwif *hwif,u32 reg,u32 val); +void hinic3_set_msix_state (struct hinic3_hwdev *hwdev,u16 msix_idx,enum hinic3_msix_state flag); +void hinic3_msix_intr_clear_resend_bit (struct hinic3_hwdev *hwdev,u16 msix_idx, +u8 clear_resend_en);u16 hinic3_global_func_id (struct hinic3_hwdev *hwdev);
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 2/8 hinic3: Complete Event Queue interfaces
In reply to Fan GongAdd complete event queue interfaces initialization. It informs that driver should handle the messages from HW.
--- .../net/ethernet/huawei/hinic3/hinic3_csr.h | 16 +- .../net/ethernet/huawei/hinic3/hinic3_eqs.c | 383 +++++++++++++++--- .../net/ethernet/huawei/hinic3/hinic3_eqs.h | 32 ++ .../ethernet/huawei/hinic3/hinic3_hw_intf.h | 36 ++ .../net/ethernet/huawei/hinic3/hinic3_hwif.c | 122 +++++- .../net/ethernet/huawei/hinic3/hinic3_hwif.h | 11 + 6 files changed, 545 insertions(+), 55 deletions(-)
drivers/net/ethernet/huawei/hinic3/hinic3_csr.h +15 -1
@@ -41,11 +41,14 @@/* EQ registers */ #define HINIC3_AEQ_INDIR_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x210) +#define HINIC3_CEQ_INDIR_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x290)#define HINIC3_EQ_INDIR_IDX_ADDR (type) \ - HINIC3_AEQ_INDIR_IDX_ADDR + ((type == HINIC3_AEQ) ? HINIC3_AEQ_INDIR_IDX_ADDR : \ + HINIC3_CEQ_INDIR_IDX_ADDR)#define HINIC3_AEQ_MTT_OFF_BASE_ADDR (HINIC3_CFG_REGS_FLAG + 0x240) +#define HINIC3_CEQ_MTT_OFF_BASE_ADDR (HINIC3_CFG_REGS_FLAG + 0x2C0)#define HINIC3_CSR_EQ_PAGE_OFF_STRIDE 8
@@ -57,9 +60,20 @@ (HINIC3_AEQ_MTT_OFF_BASE_ADDR + (pg_num) * \ HINIC3_CSR_EQ_PAGE_OFF_STRIDE + 4) +#define HINIC3_CEQ_HI_PHYS_ADDR_REG (pg_num) \ + (HINIC3_CEQ_MTT_OFF_BASE_ADDR + (pg_num) * \ + HINIC3_CSR_EQ_PAGE_OFF_STRIDE) + +#define HINIC3_CEQ_LO_PHYS_ADDR_REG (pg_num) \ + (HINIC3_CEQ_MTT_OFF_BASE_ADDR + (pg_num) * \ + HINIC3_CSR_EQ_PAGE_OFF_STRIDE + 4) +#define HINIC3_CSR_AEQ_CTRL_0_ADDR (HINIC3_CFG_REGS_FLAG + 0x200)#define HINIC3_CSR_AEQ_CTRL_1_ADDR (HINIC3_CFG_REGS_FLAG + 0x204)#define HINIC3_CSR_AEQ_PROD_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x20C)#define HINIC3_CSR_AEQ_CI_SIMPLE_INDIR_ADDR (HINIC3_CFG_REGS_FLAG + 0x50) +#define HINIC3_CSR_CEQ_PROD_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x28c) +#define HINIC3_CSR_CEQ_CI_SIMPLE_INDIR_ADDR (HINIC3_CFG_REGS_FLAG + 0x54) +#endif
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c +331 -52
516 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_eqs.h +32 -0
@@ -10,15 +10,19 @@#include "hinic3_queue_common.h" #define HINIC3_MAX_AEQS 4 +#define HINIC3_MAX_CEQS 32#define HINIC3_AEQ_MAX_PAGES 4 +#define HINIC3_CEQ_MAX_PAGES 8#define HINIC3_AEQE_SIZE 64 +#define HINIC3_CEQE_SIZE 4#define HINIC3_AEQE_DESC_SIZE 4#define HINIC3_AEQE_DATA_SIZE (HINIC3_AEQE_SIZE - HINIC3_AEQE_DESC_SIZE)#define HINIC3_DEFAULT_AEQ_LEN 0x10000 +#define HINIC3_DEFAULT_CEQ_LEN 0x10000#define HINIC3_EQ_IRQ_NAME_LEN 64
@@ -27,6 +31,7 @@enum hinic3_eq_type {HINIC3_AEQ =0 , +HINIC3_CEQ =1 , };enum hinic3_eq_intr_mode {
@@ -78,6 +83,25 @@ struct hinic3_aeqs {spinlock_t aeq_lock; }; +enum hinic3_ceq_event { +HINIC3_CMDQ =3 , +HINIC3_MAX_CEQ_EVENTS =6 , +}; + +typedef void (*hinic3_ceq_event_cb )(struct hinic3_hwdev *hwdev, +__le32 ceqe_data); + +struct hinic3_ceqs { +struct hinic3_hwdev *hwdev; + +hinic3_ceq_event_cb ceq_cb[HINIC3_MAX_CEQ_EVENTS ]; + +struct hinic3_eq ceq[HINIC3_MAX_CEQS ]; +u16 num_ceqs; +/* lock for ceq event flag */ +spinlock_t ceq_lock; +}; +int hinic3_aeqs_init (struct hinic3_hwdev *hwdev,u16 num_aeqs,struct msix_entry *msix_entries);void hinic3_aeqs_free (struct hinic3_hwdev *hwdev);
@@ -86,5 +110,13 @@ int hinic3_aeq_register_cb(struct hinic3_hwdev *hwdev, hinic3_aeq_event_cb hwe_cb);void hinic3_aeq_unregister_cb (struct hinic3_hwdev *hwdev,enum hinic3_aeq_type event); +int hinic3_ceqs_init (struct hinic3_hwdev *hwdev,u16 num_ceqs, +struct msix_entry *msix_entries); +void hinic3_ceqs_free (struct hinic3_hwdev *hwdev); +int hinic3_ceq_register_cb (struct hinic3_hwdev *hwdev, +enum hinic3_ceq_event event, +hinic3_ceq_event_cb callback); +void hinic3_ceq_unregister_cb (struct hinic3_hwdev *hwdev, +enum hinic3_ceq_event event);#endif
drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h +36 -0
@@ -70,6 +70,20 @@ enum comm_cmd { COMM_CMD_SET_DMA_ATTR = 25, }; +struct comm_cmd_cfg_msix_ctrl_reg { +struct mgmt_msg_head head; +u16 func_id; +u8 opcode; +u8 rsvd1; +u16 msix_index; +u8 pending_cnt; +u8 coalesce_timer_cnt; +u8 resend_timer_cnt; +u8 lli_timer_cnt; +u8 lli_credit_cnt; +u8 rsvd2[5 ]; +}; +enum comm_func_reset_bits {COMM_FUNC_RESET_BIT_FLUSH =BIT (0 ),COMM_FUNC_RESET_BIT_MQM =BIT (1 ),
@@ -100,6 +114,28 @@ struct comm_cmd_feature_nego {u64 s_feature[COMM_MAX_FEATURE_QWORD ]; }; +struct comm_cmd_set_ceq_ctrl_reg { +struct mgmt_msg_head head; +u16 func_id; +u16 q_id; +u32 ctrl0; +u32 ctrl1; +u32 rsvd1; +}; + +struct comm_cmdq_ctxt_info { +__le64 curr_wqe_page_pfn; +__le64 wq_block_pfn; +}; + +struct comm_cmd_set_cmdq_ctxt { +struct mgmt_msg_head head; +u16 func_id; +u8 cmdq_id; +u8 rsvd1[5 ]; +struct comm_cmdq_ctxt_info ctxt; +}; +/* Services supported by HW. HW uses these values when delivering events. * HW supports multiple services that are not yet supported by driver * (e.g. RoCE).
drivers/net/ethernet/huawei/hinic3/hinic3_hwif.c +120 -2
142 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_hwif.h +11 -0
@@ -50,13 +50,24 @@ enum hinic3_msix_state { HINIC3_MSIX_DISABLE, }; +enum hinic3_msix_auto_mask { +HINIC3_CLR_MSIX_AUTO_MASK , +HINIC3_SET_MSIX_AUTO_MASK , +}; +u32 hinic3_hwif_read_reg (struct hinic3_hwif *hwif,u32 reg);void hinic3_hwif_write_reg (struct hinic3_hwif *hwif,u32 reg,u32 val); +int hinic3_alloc_db_addr (struct hinic3_hwdev *hwdev,void __iomem **db_base, +void __iomem **dwqe_base); +void hinic3_free_db_addr (struct hinic3_hwdev *hwdev,const u8 __iomem *db_base); +void hinic3_set_msix_state (struct hinic3_hwdev *hwdev,u16 msix_idx,enum hinic3_msix_state flag);void hinic3_msix_intr_clear_resend_bit (struct hinic3_hwdev *hwdev,u16 msix_idx,u8 clear_resend_en); +void hinic3_set_msix_auto_mask_state (struct hinic3_hwdev *hwdev,u16 msix_idx, +enum hinic3_msix_auto_mask flag);u16 hinic3_global_func_id (struct hinic3_hwdev *hwdev);
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 3/8 hinic3: Command Queue framework
In reply to Fan GongAdd Command Queue framework initialization.
It is used to set the related table items of the driver and obtain the HW configuration.
--- drivers/net/ethernet/huawei/hinic3/Makefile | 3 +- .../net/ethernet/huawei/hinic3/hinic3_cmdq.c | 407 ++++++++++++++++++ .../net/ethernet/huawei/hinic3/hinic3_cmdq.h | 151 +++++++ .../ethernet/huawei/hinic3/hinic3_common.h | 7 + .../net/ethernet/huawei/hinic3/hinic3_tx.c | 6 +- .../net/ethernet/huawei/hinic3/hinic3_wq.c | 109 +++++ .../net/ethernet/huawei/hinic3/hinic3_wq.h | 19 +- 7 files changed, 694 insertions(+), 8 deletions(-)
drivers/net/ethernet/huawei/hinic3/Makefile +2 -1
@@ -3,7 +3,8 @@ obj-$(CONFIG_HINIC3) += hinic3.o -hinic3-objs := hinic3_common.o \ +hinic3-objs := hinic3_cmdq.o \ + hinic3_common.o \ hinic3_eqs.o \ hinic3_hw_cfg.o \ hinic3_hw_comm.o \
drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c new file +407 -0
407 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.h new file +151 -0
151 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_common.h +7 -0
@@ -18,6 +18,13 @@ struct hinic3_dma_addr_align {dma_addr_t align_paddr; }; +struct hinic3_sge { +__le32 hi_addr; +__le32 lo_addr; +__le32 len; +__le32 rsvd; +}; +int hinic3_dma_zalloc_coherent_align (struct device *dev,u32 size,u32 align,gfp_t flag,struct hinic3_dma_addr_align *mem_align);
drivers/net/ethernet/huawei/hinic3/hinic3_tx.c +3 -3
@@ -55,9 +55,9 @@ void hinic3_free_txqs(struct net_device *netdev)static void hinic3_set_buf_desc (struct hinic3_sq_bufdesc *buf_descs,dma_addr_t addr,u32 len) { - buf_descs->hi_addr =upper_32_bits (addr); - buf_descs->lo_addr =lower_32_bits (addr); - buf_descs->len = len; + buf_descs->hi_addr =cpu_to_le32 (upper_32_bits (addr)); + buf_descs->lo_addr =cpu_to_le32 (lower_32_bits (addr)); + buf_descs->len =cpu_to_le32 (len); } static int hinic3_tx_map_skb(struct net_device *netdev, struct sk_buff *skb,
drivers/net/ethernet/huawei/hinic3/hinic3_wq.c +109 -0
118 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_wq.h +15 -4
@@ -10,10 +10,10 @@struct hinic3_sq_bufdesc {/* 31-bits Length, L2NIC only uses length[17:0] */ -u32 len; -u32 rsvd; -u32 hi_addr; -u32 lo_addr; +__le32 len; +__le32 rsvd; +__le32 hi_addr; +__le32 lo_addr; };/* Work queue is used to submit elements (tx, rx, cmd) to hw.
@@ -59,6 +59,7 @@ static inline void *hinic3_wq_get_one_wqebb(struct hinic3_wq *wq, u16 *pi) { *pi = wq->prod_idx & wq->idx_mask; wq->prod_idx++; +return get_q_element (&wq->qpages, *pi,NULL ); }
@@ -67,10 +68,20 @@ static inline void hinic3_wq_put_wqebbs(struct hinic3_wq *wq, u16 num_wqebbs) wq->cons_idx += num_wqebbs; } +static inline u64 hinic3_wq_get_first_wqe_page_addr (const struct hinic3_wq *wq) +{ +return wq->qpages.pages[0 ].align_paddr; +} + +int hinic3_wq_create (struct hinic3_hwdev *hwdev,struct hinic3_wq *wq, +u32 q_depth,u16 wqebb_size); +void hinic3_wq_destroy (struct hinic3_hwdev *hwdev,struct hinic3_wq *wq); +void hinic3_wq_reset (struct hinic3_wq *wq);void hinic3_wq_get_multi_wqebbs (struct hinic3_wq *wq,u16 num_wqebbs,u16 *prod_idx,struct hinic3_sq_bufdesc **first_part_wqebbs,struct hinic3_sq_bufdesc **second_part_wqebbs,u16 *first_part_wqebbs_num); +bool hinic3_wq_is_0_level_cla (const struct hinic3_wq *wq);#endif
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 4/8 hinic3: Command Queue interfaces
In reply to Fan GongAdd Command Queue interfaces initialization. It enables communictaion and operation with HW.
--- .../net/ethernet/huawei/hinic3/hinic3_cmdq.c | 508 ++++++++++++++++++ .../net/ethernet/huawei/hinic3/hinic3_cmdq.h | 5 + .../ethernet/huawei/hinic3/hinic3_common.h | 9 + 3 files changed, 522 insertions(+)
drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c +508 -0
@@ -2,6 +2,7 @@// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. #include <linux/bitfield.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include "hinic3_cmdq.h"
@@ -12,6 +13,9 @@#define CMDQ_BUF_SIZE 2048#define CMDQ_WQEBB_SIZE 64 +#define CMDQ_CMD_TIMEOUT 5000 +#define CMDQ_ENABLE_WAIT_TIMEOUT 300 +#define CMDQ_CTXT_CURR_WQE_PAGE_PFN_MASK GENMASK_ULL(51, 0)#define CMDQ_CTXT_EQ_ID_MASK GENMASK_ULL(60, 53)#define CMDQ_CTXT_CEQ_ARM_MASK BIT_ULL(61)
@@ -23,6 +27,48 @@#define CMDQ_CTXT_SET (val, member) \ FIELD_PREP(CMDQ_CTXT_##member##_MASK, val) +#define CMDQ_WQE_HDR_BUFDESC_LEN_MASK GENMASK(7, 0) +#define CMDQ_WQE_HDR_COMPLETE_FMT_MASK BIT(15) +#define CMDQ_WQE_HDR_DATA_FMT_MASK BIT(22) +#define CMDQ_WQE_HDR_COMPLETE_REQ_MASK BIT(23) +#define CMDQ_WQE_HDR_COMPLETE_SECT_LEN_MASK GENMASK(28, 27) +#define CMDQ_WQE_HDR_CTRL_LEN_MASK GENMASK(30, 29) +#define CMDQ_WQE_HDR_HW_BUSY_BIT_MASK BIT(31) +#define CMDQ_WQE_HDR_SET (val, member) \ + FIELD_PREP(CMDQ_WQE_HDR_##member##_MASK, val) +#define CMDQ_WQE_HDR_GET (val, member) \ + FIELD_GET(CMDQ_WQE_HDR_##member##_MASK, le32_to_cpu(val)) + +#define CMDQ_CTRL_PI_MASK GENMASK(15, 0) +#define CMDQ_CTRL_CMD_MASK GENMASK(23, 16) +#define CMDQ_CTRL_MOD_MASK GENMASK(28, 24) +#define CMDQ_CTRL_HW_BUSY_BIT_MASK BIT(31) +#define CMDQ_CTRL_SET (val, member) \ + FIELD_PREP(CMDQ_CTRL_##member##_MASK, val) +#define CMDQ_CTRL_GET (val, member) \ + FIELD_GET(CMDQ_CTRL_##member##_MASK, val) + +#define CMDQ_WQE_ERRCODE_VAL_MASK GENMASK(30, 0) +#define CMDQ_WQE_ERRCODE_GET (val, member) \ + FIELD_GET(CMDQ_WQE_ERRCODE_##member##_MASK, le32_to_cpu(val)) + +#define CMDQ_DB_INFO_HI_PROD_IDX_MASK GENMASK(7, 0) +#define CMDQ_DB_INFO_SET (val, member) \ + FIELD_PREP(CMDQ_DB_INFO_##member##_MASK, val) + +#define CMDQ_DB_HEAD_QUEUE_TYPE_MASK BIT(23) +#define CMDQ_DB_HEAD_CMDQ_TYPE_MASK GENMASK(26, 24) +#define CMDQ_DB_HEAD_SET (val, member) \ + FIELD_PREP(CMDQ_DB_HEAD_##member##_MASK, val) + +#define CMDQ_CEQE_TYPE_MASK GENMASK(2, 0) +#define CMDQ_CEQE_GET (val, member) \ + FIELD_GET(CMDQ_CEQE_##member##_MASK, le32_to_cpu(val)) + +#define CMDQ_WQE_HEADER (wqe) ((struct cmdq_header *)(wqe)) +#define CMDQ_WQE_COMPLETED (ctrl_info) \ + CMDQ_CTRL_GET(le32_to_cpu(ctrl_info), HW_BUSY_BIT) +#define CMDQ_PFN (addr) ((addr) >> 12)/* cmdq work queue's chip logical address table is up to 512B */
@@ -33,6 +79,31 @@#define CMDQ_DIRECT_SYNC_CMPT_CODE 11#define CMDQ_FORCE_STOP_CMPT_CODE 12 +enum cmdq_data_format { +CMDQ_DATA_SGE =0 , +CMDQ_DATA_DIRECT =1 , +}; + +enum cmdq_ctrl_sect_len { +CMDQ_CTRL_SECT_LEN =1 , +CMDQ_CTRL_DIRECT_SECT_LEN =2 , +}; + +enum cmdq_bufdesc_len { +CMDQ_BUFDESC_LCMD_LEN =2 , +CMDQ_BUFDESC_SCMD_LEN =3 , +}; + +enum cmdq_completion_format { +CMDQ_COMPLETE_DIRECT =0 , +CMDQ_COMPLETE_SGE =1 , +}; + +enum cmdq_cmd_type { +CMDQ_CMD_DIRECT_RESP , +CMDQ_CMD_SGE_RESP , +}; +#define CMDQ_WQE_NUM_WQEBBS 1static struct cmdq_wqe *cmdq_read_wqe (struct hinic3_wq *wq,u16 *ci)
@@ -45,6 +116,35 @@ static struct cmdq_wqe *cmdq_read_wqe(struct hinic3_wq *wq, u16 *ci)return get_q_element (&wq->qpages, wq->cons_idx,NULL ); } +struct hinic3_cmd_buf *hinic3_alloc_cmd_buf (struct hinic3_hwdev *hwdev) +{ +struct hinic3_cmd_buf *cmd_buf; +struct hinic3_cmdqs *cmdqs; + + cmdqs = hwdev->cmdqs; + + cmd_buf =kmalloc (sizeof (*cmd_buf),GFP_ATOMIC ); +if (!cmd_buf) +return NULL ; + + cmd_buf->buf =dma_pool_alloc (cmdqs->cmd_buf_pool,GFP_ATOMIC , + &cmd_buf->dma_addr); +if (!cmd_buf->buf) { +dev_err (hwdev->dev,"Failed to allocate cmdq cmd buf from the pool\n" ); + goto err_free_cmd_buf; + } + + cmd_buf->size =cpu_to_le16 (CMDQ_BUF_SIZE ); +refcount_set (&cmd_buf->ref_cnt,1 ); + +return cmd_buf; + +err_free_cmd_buf: +kfree (cmd_buf); + +return NULL ; +} +void hinic3_free_cmd_buf (struct hinic3_hwdev *hwdev,struct hinic3_cmd_buf *cmd_buf) {
@@ -68,6 +168,414 @@ static void cmdq_clear_cmd_buf(struct hinic3_cmdq_cmd_info *cmd_info, } } +static void clear_wqe_complete_bit (struct hinic3_cmdq *cmdq, +struct cmdq_wqe *wqe,u16 ci) +{ +struct cmdq_header *hdr =CMDQ_WQE_HEADER (wqe); +__le32 header_info = hdr->header_info; +enum cmdq_data_format df; +struct cmdq_ctrl *ctrl; + + df =CMDQ_WQE_HDR_GET (header_info,DATA_FMT ); +if (df ==CMDQ_DATA_SGE ) + ctrl = &wqe->wqe_lcmd.ctrl; +else + ctrl = &wqe->wqe_scmd.ctrl; + +/* clear HW busy bit */ + ctrl->ctrl_info =0 ; + cmdq->cmd_infos[ci].cmd_type =HINIC3_CMD_TYPE_NONE ; +wmb ();/* verify wqe is clear before updating ci */ +hinic3_wq_put_wqebbs (&cmdq->wq,CMDQ_WQE_NUM_WQEBBS ); +} + +static void cmdq_update_cmd_status (struct hinic3_cmdq *cmdq,u16 prod_idx, +struct cmdq_wqe *wqe) +{ +struct hinic3_cmdq_cmd_info *cmd_info; +struct cmdq_wqe_lcmd *wqe_lcmd; +__le32 status_info; + + wqe_lcmd = &wqe->wqe_lcmd; + cmd_info = &cmdq->cmd_infos[prod_idx]; +if (cmd_info->errcode) { + status_info = wqe_lcmd->status.status_info; + *cmd_info->errcode =CMDQ_WQE_ERRCODE_GET (status_info,VAL ); + } + +if (cmd_info->direct_resp) + *cmd_info->direct_resp = wqe_lcmd->completion.resp.direct.val; +} + +static void cmdq_sync_cmd_handler (struct hinic3_cmdq *cmdq, +struct cmdq_wqe *wqe,u16 ci) +{ +spin_lock (&cmdq->cmdq_lock); +cmdq_update_cmd_status (cmdq, ci, wqe); +if (cmdq->cmd_infos[ci].cmpt_code) { + *cmdq->cmd_infos[ci].cmpt_code =CMDQ_DIRECT_SYNC_CMPT_CODE ; + cmdq->cmd_infos[ci].cmpt_code =NULL ; + } + +/* Ensure that completion code has been updated before updating done */ +smp_wmb (); +if (cmdq->cmd_infos[ci].done) { +complete (cmdq->cmd_infos[ci].done); + cmdq->cmd_infos[ci].done =NULL ; + } +spin_unlock (&cmdq->cmdq_lock); + +cmdq_clear_cmd_buf (&cmdq->cmd_infos[ci], cmdq->hwdev); +clear_wqe_complete_bit (cmdq, wqe, ci); +} + +void hinic3_cmdq_ceq_handler (struct hinic3_hwdev *hwdev,__le32 ceqe_data) +{ +enum hinic3_cmdq_type cmdq_type =CMDQ_CEQE_GET (ceqe_data,TYPE ); +struct hinic3_cmdqs *cmdqs = hwdev->cmdqs; +struct hinic3_cmdq_cmd_info *cmd_info; +struct cmdq_wqe_lcmd *wqe_lcmd; +struct hinic3_cmdq *cmdq; +struct cmdq_wqe *wqe; +__le32 ctrl_info; +u16 ci; + +if (unlikely (cmdq_type >=ARRAY_SIZE (cmdqs->cmdq))) +return ; + + cmdq = &cmdqs->cmdq[cmdq_type]; +while ((wqe =cmdq_read_wqe (&cmdq->wq, &ci)) !=NULL ) { + cmd_info = &cmdq->cmd_infos[ci]; +switch (cmd_info->cmd_type) { +case HINIC3_CMD_TYPE_NONE : +return ; +case HINIC3_CMD_TYPE_TIMEOUT : +dev_warn (hwdev->dev,"Cmdq timeout, q_id: %u, ci: %u\n" , + cmdq_type, ci); + fallthrough; +case HINIC3_CMD_TYPE_FAKE_TIMEOUT : +cmdq_clear_cmd_buf (cmd_info, hwdev); +clear_wqe_complete_bit (cmdq, wqe, ci); +break ; +default : +/* only arm bit is using scmd wqe, +* the other wqe is lcmd +*/ + wqe_lcmd = &wqe->wqe_lcmd; + ctrl_info = wqe_lcmd->ctrl.ctrl_info; +if (!CMDQ_WQE_COMPLETED (ctrl_info)) +return ; + +dma_rmb (); +/* For FORCE_STOP cmd_type, we also need to wait for +* the firmware processing to complete to prevent the +* firmware from accessing the released cmd_buf +*/ +if (cmd_info->cmd_type ==HINIC3_CMD_TYPE_FORCE_STOP ) { +cmdq_clear_cmd_buf (cmd_info, hwdev); +clear_wqe_complete_bit (cmdq, wqe, ci); + }else { +cmdq_sync_cmd_handler (cmdq, wqe, ci); + } + +break ; + } + } +} + +static int wait_cmdqs_enable (struct hinic3_cmdqs *cmdqs) +{ +unsigned long end; + + end = jiffies +msecs_to_jiffies (CMDQ_ENABLE_WAIT_TIMEOUT ); +do { +if (cmdqs->status &HINIC3_CMDQ_ENABLE ) +return 0 ; +usleep_range (1000 ,2000 ); + }while (time_before (jiffies, end) && !cmdqs->disable_flag); + + cmdqs->disable_flag =1 ; + +return -EBUSY ; +} + +static void cmdq_set_completion (struct cmdq_completion *complete, +struct hinic3_cmd_buf *buf_out) +{ +struct hinic3_sge *sge = &complete->resp.sge; + +hinic3_set_sge (sge, buf_out->dma_addr,cpu_to_le32 (CMDQ_BUF_SIZE )); +} + +static struct cmdq_wqe *cmdq_get_wqe (struct hinic3_wq *wq,u16 *pi) +{ +if (!hinic3_wq_free_wqebbs (wq)) +return NULL ; + +return hinic3_wq_get_one_wqebb (wq, pi); +} + +static void cmdq_set_lcmd_bufdesc (struct cmdq_wqe_lcmd *wqe, +struct hinic3_cmd_buf *buf_in) +{ +hinic3_set_sge (&wqe->buf_desc.sge, buf_in->dma_addr, + (__force __le32 )buf_in->size); +} + +static void cmdq_set_db (struct hinic3_cmdq *cmdq, +enum hinic3_cmdq_type cmdq_type,u16 prod_idx) +{ +u8 __iomem *db_base = cmdq->hwdev->cmdqs->cmdqs_db_base; +u16 db_ofs = (prod_idx &0xFF ) <<3 ; +struct cmdq_db db; + + db.db_info =cpu_to_le32 (CMDQ_DB_INFO_SET (prod_idx >>8 ,HI_PROD_IDX )); + db.db_head =cpu_to_le32 (CMDQ_DB_HEAD_SET (1 ,QUEUE_TYPE ) | +CMDQ_DB_HEAD_SET (cmdq_type,CMDQ_TYPE )); +writeq (*(u64 *)&db, db_base + db_ofs); +} + +static void cmdq_wqe_fill (struct cmdq_wqe *hw_wqe, +const struct cmdq_wqe *shadow_wqe) +{ +const struct cmdq_header *src = (struct cmdq_header *)shadow_wqe; +struct cmdq_header *dst = (struct cmdq_header *)hw_wqe; +size_t len; + + len =sizeof (struct cmdq_wqe ) -sizeof (struct cmdq_header ); +memcpy (dst +1 , src +1 , len); +/* Ensure buffer len before updating header */ +wmb (); +WRITE_ONCE (*dst, *src); +} + +static void cmdq_prepare_wqe_ctrl (struct cmdq_wqe *wqe,u8 wrapped, +u8 mod,u8 cmd,u16 prod_idx, +enum cmdq_completion_format complete_format, +enum cmdq_data_format data_format, +enum cmdq_bufdesc_len buf_len) +{ +struct cmdq_header *hdr =CMDQ_WQE_HEADER (wqe); +enum cmdq_ctrl_sect_len ctrl_len; +struct cmdq_wqe_lcmd *wqe_lcmd; +struct cmdq_wqe_scmd *wqe_scmd; +struct cmdq_ctrl *ctrl; + +if (data_format ==CMDQ_DATA_SGE ) { + wqe_lcmd = &wqe->wqe_lcmd; + wqe_lcmd->status.status_info =0 ; + ctrl = &wqe_lcmd->ctrl; + ctrl_len =CMDQ_CTRL_SECT_LEN ; + }else { + wqe_scmd = &wqe->wqe_scmd; + wqe_scmd->status.status_info =0 ; + ctrl = &wqe_scmd->ctrl; + ctrl_len =CMDQ_CTRL_DIRECT_SECT_LEN ; + } + + ctrl->ctrl_info = +cpu_to_le32 (CMDQ_CTRL_SET (prod_idx,PI ) | +CMDQ_CTRL_SET (cmd,CMD ) | +CMDQ_CTRL_SET (mod,MOD )); + + hdr->header_info = +cpu_to_le32 (CMDQ_WQE_HDR_SET (buf_len,BUFDESC_LEN ) | +CMDQ_WQE_HDR_SET (complete_format,COMPLETE_FMT ) | +CMDQ_WQE_HDR_SET (data_format,DATA_FMT ) | +CMDQ_WQE_HDR_SET (1 ,COMPLETE_REQ ) | +CMDQ_WQE_HDR_SET (3 ,COMPLETE_SECT_LEN ) | +CMDQ_WQE_HDR_SET (ctrl_len,CTRL_LEN ) | +CMDQ_WQE_HDR_SET (wrapped,HW_BUSY_BIT )); +} + +static void cmdq_set_lcmd_wqe (struct cmdq_wqe *wqe, +enum cmdq_cmd_type cmd_type, +struct hinic3_cmd_buf *buf_in, +struct hinic3_cmd_buf *buf_out, +u8 wrapped,u8 mod,u8 cmd,u16 prod_idx) +{ +enum cmdq_completion_format complete_format =CMDQ_COMPLETE_DIRECT ; +struct cmdq_wqe_lcmd *wqe_lcmd = &wqe->wqe_lcmd; + +switch (cmd_type) { +case CMDQ_CMD_DIRECT_RESP : + wqe_lcmd->completion.resp.direct.val =0 ; +break ; +case CMDQ_CMD_SGE_RESP : +if (buf_out) { + complete_format =CMDQ_COMPLETE_SGE ; +cmdq_set_completion (&wqe_lcmd->completion, buf_out); + } +break ; + } + +cmdq_prepare_wqe_ctrl (wqe, wrapped, mod, cmd, prod_idx, complete_format, +CMDQ_DATA_SGE ,CMDQ_BUFDESC_LCMD_LEN ); +cmdq_set_lcmd_bufdesc (wqe_lcmd, buf_in); +} + +static int hinic3_cmdq_sync_timeout_check (struct hinic3_cmdq *cmdq, +struct cmdq_wqe *wqe,u16 pi) +{ +struct cmdq_wqe_lcmd *wqe_lcmd; +struct cmdq_ctrl *ctrl; +__le32 ctrl_info; + + wqe_lcmd = &wqe->wqe_lcmd; + ctrl = &wqe_lcmd->ctrl; + ctrl_info = ctrl->ctrl_info; +if (!CMDQ_WQE_COMPLETED (ctrl_info)) { +dev_dbg (cmdq->hwdev->dev,"Cmdq sync command check busy bit not set\n" ); +return -EFAULT ; + } +cmdq_update_cmd_status (cmdq, pi, wqe); + +return 0 ; +} + +static void clear_cmd_info (struct hinic3_cmdq_cmd_info *cmd_info, +const struct hinic3_cmdq_cmd_info *saved_cmd_info) +{ +if (cmd_info->errcode == saved_cmd_info->errcode) + cmd_info->errcode =NULL ; + +if (cmd_info->done == saved_cmd_info->done) + cmd_info->done =NULL ; + +if (cmd_info->direct_resp == saved_cmd_info->direct_resp) + cmd_info->direct_resp =NULL ; +} + +static int wait_cmdq_sync_cmd_completion (struct hinic3_cmdq *cmdq, +struct hinic3_cmdq_cmd_info *cmd_info, +struct hinic3_cmdq_cmd_info *saved_cmd_info, +u64 curr_msg_id,u16 curr_prod_idx, +struct cmdq_wqe *curr_wqe, +u32 timeout) +{ +ulong timeo =msecs_to_jiffies (timeout); +int err; + +if (wait_for_completion_timeout (saved_cmd_info->done, timeo)) +return 0 ; + +spin_lock_bh (&cmdq->cmdq_lock); +if (cmd_info->cmpt_code == saved_cmd_info->cmpt_code) + cmd_info->cmpt_code =NULL ; + +if (*saved_cmd_info->cmpt_code ==CMDQ_DIRECT_SYNC_CMPT_CODE ) { +dev_dbg (cmdq->hwdev->dev,"Cmdq direct sync command has been completed\n" ); +spin_unlock_bh (&cmdq->cmdq_lock); +return 0 ; + } + +if (curr_msg_id == cmd_info->cmdq_msg_id) { + err =hinic3_cmdq_sync_timeout_check (cmdq, curr_wqe, + curr_prod_idx); +if (err) + cmd_info->cmd_type =HINIC3_CMD_TYPE_TIMEOUT ; +else + cmd_info->cmd_type =HINIC3_CMD_TYPE_FAKE_TIMEOUT ; + }else { + err = -ETIMEDOUT ; +dev_err (cmdq->hwdev->dev, +"Cmdq sync command current msg id mismatch cmd_info msg id\n" ); + } + +clear_cmd_info (cmd_info, saved_cmd_info); +spin_unlock_bh (&cmdq->cmdq_lock); + +return err; +} + +static int cmdq_sync_cmd_direct_resp (struct hinic3_cmdq *cmdq,u8 mod,u8 cmd, +struct hinic3_cmd_buf *buf_in, +__le64 *out_param) +{ +struct hinic3_cmdq_cmd_info *cmd_info, saved_cmd_info; +int cmpt_code =CMDQ_SEND_CMPT_CODE ; +struct cmdq_wqe *curr_wqe, wqe = {}; +struct hinic3_wq *wq = &cmdq->wq; +u16 curr_prod_idx, next_prod_idx; +struct completion done; +u64 curr_msg_id; +int errcode; +u8 wrapped; +int err; + +spin_lock_bh (&cmdq->cmdq_lock); + curr_wqe =cmdq_get_wqe (wq, &curr_prod_idx); +if (!curr_wqe) { +spin_unlock_bh (&cmdq->cmdq_lock); +return -EBUSY ; + } + + wrapped = cmdq->wrapped; + next_prod_idx = curr_prod_idx +CMDQ_WQE_NUM_WQEBBS ; +if (next_prod_idx >= wq->q_depth) { + cmdq->wrapped ^=1 ; + next_prod_idx -= wq->q_depth; + } + + cmd_info = &cmdq->cmd_infos[curr_prod_idx]; +init_completion (&done); +refcount_inc (&buf_in->ref_cnt); + cmd_info->cmd_type =HINIC3_CMD_TYPE_DIRECT_RESP ; + cmd_info->done = &done; + cmd_info->errcode = &errcode; + cmd_info->direct_resp = out_param; + cmd_info->cmpt_code = &cmpt_code; + cmd_info->buf_in = buf_in; + saved_cmd_info = *cmd_info; +cmdq_set_lcmd_wqe (&wqe,CMDQ_CMD_DIRECT_RESP , buf_in,NULL , + wrapped, mod, cmd, curr_prod_idx); + +cmdq_wqe_fill (curr_wqe, &wqe); + (cmd_info->cmdq_msg_id)++; + curr_msg_id = cmd_info->cmdq_msg_id; +cmdq_set_db (cmdq,HINIC3_CMDQ_SYNC , next_prod_idx); +spin_unlock_bh (&cmdq->cmdq_lock); + + err =wait_cmdq_sync_cmd_completion (cmdq, cmd_info, &saved_cmd_info, + curr_msg_id, curr_prod_idx, + curr_wqe,CMDQ_CMD_TIMEOUT ); +if (err) { +dev_err (cmdq->hwdev->dev, +"Cmdq sync command timeout, mod: %u, cmd: %u, prod idx: 0x%x\n" , + mod, cmd, curr_prod_idx); + err = -ETIMEDOUT ; + } + +if (cmpt_code ==CMDQ_FORCE_STOP_CMPT_CODE ) { +dev_dbg (cmdq->hwdev->dev, +"Force stop cmdq cmd, mod: %u, cmd: %u\n" , mod, cmd); + err = -EAGAIN ; + } + +smp_rmb ();/* read error code after completion */ + +return err ? err : errcode; +} + +int hinic3_cmdq_direct_resp (struct hinic3_hwdev *hwdev,u8 mod,u8 cmd, +struct hinic3_cmd_buf *buf_in,__le64 *out_param) +{ +struct hinic3_cmdqs *cmdqs; +int err; + + cmdqs = hwdev->cmdqs; + err =wait_cmdqs_enable (cmdqs); +if (err) { +dev_err (hwdev->dev,"Cmdq is disabled\n" ); +return err; + } + + err =cmdq_sync_cmd_direct_resp (&cmdqs->cmdq[HINIC3_CMDQ_SYNC ], + mod, cmd, buf_in, out_param); + +return err; +} +static void cmdq_init_queue_ctxt (struct hinic3_hwdev *hwdev,u8 cmdq_id,struct comm_cmdq_ctxt_info *ctxt_info) {
drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.h +5 -0
@@ -141,8 +141,13 @@ struct hinic3_cmdqs {int hinic3_cmdqs_init (struct hinic3_hwdev *hwdev);void hinic3_cmdqs_free (struct hinic3_hwdev *hwdev); +struct hinic3_cmd_buf *hinic3_alloc_cmd_buf (struct hinic3_hwdev *hwdev);void hinic3_free_cmd_buf (struct hinic3_hwdev *hwdev,struct hinic3_cmd_buf *cmd_buf); +void hinic3_cmdq_ceq_handler (struct hinic3_hwdev *hwdev,__le32 ceqe_data); + +int hinic3_cmdq_direct_resp (struct hinic3_hwdev *hwdev,u8 mod,u8 cmd, +struct hinic3_cmd_buf *buf_in,__le64 *out_param);void hinic3_cmdq_flush_sync_cmd (struct hinic3_hwdev *hwdev);int hinic3_reinit_cmdq_ctxts (struct hinic3_hwdev *hwdev);
drivers/net/ethernet/huawei/hinic3/hinic3_common.h +9 -0
@@ -25,6 +25,15 @@ struct hinic3_sge {__le32 rsvd; }; +static inline void hinic3_set_sge (struct hinic3_sge *sge,dma_addr_t addr, +__le32 len) +{ + sge->hi_addr =cpu_to_le32 (upper_32_bits (addr)); + sge->lo_addr =cpu_to_le32 (lower_32_bits (addr)); + sge->len = len; + sge->rsvd =0 ; +} +int hinic3_dma_zalloc_coherent_align (struct device *dev,u32 size,u32 align,gfp_t flag,struct hinic3_dma_addr_align *mem_align);
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 5/8 hinic3: TX & RX Queue coalesce interfaces
In reply to Fan GongAdd TX RX queue coalesce interfaces initialization. It configures the parameters of tx & tx msix coalesce.
--- .../net/ethernet/huawei/hinic3/hinic3_main.c | 61 +++++++++++++++++-- .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 10 +++ 2 files changed, 66 insertions(+), 5 deletions(-)
drivers/net/ethernet/huawei/hinic3/hinic3_main.c +56 -5
@@ -17,12 +17,53 @@#define HINIC3_NIC_DRV_DESC "Intelligent Network Interface Card Driver" -#define HINIC3_RX_BUF_LEN 2048 -#define HINIC3_LRO_REPLENISH_THLD 256 -#define HINIC3_NIC_DEV_WQ_NAME "hinic3_nic_dev_wq" +#define HINIC3_RX_BUF_LEN 2048 +#define HINIC3_LRO_REPLENISH_THLD 256 +#define HINIC3_NIC_DEV_WQ_NAME "hinic3_nic_dev_wq" -#define HINIC3_SQ_DEPTH 1024 -#define HINIC3_RQ_DEPTH 1024 +#define HINIC3_SQ_DEPTH 1024 +#define HINIC3_RQ_DEPTH 1024 + +#define HINIC3_DEFAULT_TXRX_MSIX_PENDING_LIMIT 2 +#define HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG 25 +#define HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG 7 + +static void init_intr_coal_param (struct net_device *netdev) +{ +struct hinic3_nic_dev *nic_dev =netdev_priv (netdev); +struct hinic3_intr_coal_info *info; +u16 i; + +for (i =0 ; i < nic_dev->max_qps; i++) { + info = &nic_dev->intr_coalesce[i]; + info->pending_limit =HINIC3_DEFAULT_TXRX_MSIX_PENDING_LIMIT ; + info->coalesce_timer_cfg =HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG ; + info->resend_timer_cfg =HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG ; + } +} + +static int hinic3_init_intr_coalesce (struct net_device *netdev) +{ +struct hinic3_nic_dev *nic_dev =netdev_priv (netdev); + + nic_dev->intr_coalesce =kcalloc (nic_dev->max_qps, +sizeof (*nic_dev->intr_coalesce), +GFP_KERNEL ); + +if (!nic_dev->intr_coalesce) +return -ENOMEM ; + +init_intr_coal_param (netdev); + +return 0 ; +} + +static void hinic3_free_intr_coalesce (struct net_device *netdev) +{ +struct hinic3_nic_dev *nic_dev =netdev_priv (netdev); + +kfree (nic_dev->intr_coalesce); +}static int hinic3_alloc_txrxqs (struct net_device *netdev) {
@@ -42,8 +83,17 @@ static int hinic3_alloc_txrxqs(struct net_device *netdev) goto err_free_txqs; } + err =hinic3_init_intr_coalesce (netdev); +if (err) { +dev_err (hwdev->dev,"Failed to init_intr_coalesce\n" ); + goto err_free_rxqs; + } +return 0 ; +err_free_rxqs: +hinic3_free_rxqs (netdev); + err_free_txqs:hinic3_free_txqs (netdev);
@@ -52,6 +102,7 @@ static int hinic3_alloc_txrxqs(struct net_device *netdev)static void hinic3_free_txrxqs (struct net_device *netdev) { +hinic3_free_intr_coalesce (netdev);hinic3_free_rxqs (netdev);hinic3_free_txqs (netdev); }
drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +10 -0
@@ -51,6 +51,12 @@ struct hinic3_dyna_txrxq_params {struct hinic3_irq_cfg *irq_cfg; }; +struct hinic3_intr_coal_info { +u8 pending_limit; +u8 coalesce_timer_cfg; +u8 resend_timer_cfg; +}; +struct hinic3_nic_dev {struct pci_dev *pdev;struct net_device *netdev;
@@ -70,10 +76,14 @@ struct hinic3_nic_dev {u16 num_qp_irq;struct msix_entry *qps_msix_entries; +struct hinic3_intr_coal_info *intr_coalesce; +bool link_status_up; };void hinic3_set_netdev_ops (struct net_device *netdev); +int hinic3_qps_irq_init (struct net_device *netdev); +void hinic3_qps_irq_uninit (struct net_device *netdev);/* Temporary prototypes. Functions become static in later submission. */ void qp_add_napi (struct hinic3_irq_cfg *irq_cfg);
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 6/8 hinic3: Mailbox framework
In reply to Fan GongAdd mailbox framework initialization.
It allows driver to send commands to HW.
--- .../ethernet/huawei/hinic3/hinic3_common.c | 14 + .../ethernet/huawei/hinic3/hinic3_common.h | 9 + .../net/ethernet/huawei/hinic3/hinic3_mbox.c | 409 ++++++++++++++++++ .../net/ethernet/huawei/hinic3/hinic3_mbox.h | 103 +++++ 4 files changed, 535 insertions(+)
drivers/net/ethernet/huawei/hinic3/hinic3_common.c +14 -0
@@ -3,6 +3,7 @@#include <linux/delay.h> #include <linux/dma-mapping.h> +#include <linux/iopoll.h> #include "hinic3_common.h"
@@ -52,6 +53,19 @@ void hinic3_dma_free_coherent_align(struct device *dev, mem_align->ori_vaddr, mem_align->ori_paddr); } +int hinic3_wait_for_timeout (void *priv_data,wait_cpl_handler handler, +u32 wait_total_ms,u32 wait_once_us) +{ +enum hinic3_wait_return ret; +int err; + + err =read_poll_timeout (handler, ret, ret ==HINIC3_WAIT_PROCESS_CPL , + wait_once_us, wait_total_ms *USEC_PER_MSEC , + false, priv_data); + +return err; +} +/* Data provided to/by cmdq is arranged in structs with little endian fields but * every dword (32bits) should be swapped since HW swaps it again when it * copies it from/to host memory.
drivers/net/ethernet/huawei/hinic3/hinic3_common.h +9 -0
@@ -18,6 +18,11 @@ struct hinic3_dma_addr_align {dma_addr_t align_paddr; }; +enum hinic3_wait_return { +HINIC3_WAIT_PROCESS_CPL =0 , +HINIC3_WAIT_PROCESS_WAITING =1 , +}; +struct hinic3_sge {__le32 hi_addr;__le32 lo_addr;
@@ -40,6 +45,10 @@ int hinic3_dma_zalloc_coherent_align(struct device *dev, u32 size, u32 align,void hinic3_dma_free_coherent_align (struct device *dev,struct hinic3_dma_addr_align *mem_align); +typedef enum hinic3_wait_return (*wait_cpl_handler )(void *priv_data); +int hinic3_wait_for_timeout (void *priv_data,wait_cpl_handler handler, +u32 wait_total_ms,u32 wait_once_us); +void hinic3_cmdq_buf_swab32 (void *data,int len);#endif
drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +409 -0
419 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +103 -0
109 lines not on this page · raw message
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 7/8 hinic3: Mailbox management interfaces
In reply to Fan GongAdd mailbox management interfaces initialization. It enables mailbox to communicate with event queues from HW.
--- .../net/ethernet/huawei/hinic3/hinic3_mbox.c | 439 +++++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_mbox.h | 23 + 2 files changed, 460 insertions(+), 2 deletions(-)
drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +437 -2
@@ -9,6 +9,23 @@#include "hinic3_hwif.h" #include "hinic3_mbox.h" +#define MBOX_INT_DST_AEQN_MASK GENMASK(11, 10) +#define MBOX_INT_SRC_RESP_AEQN_MASK GENMASK(13, 12) +#define MBOX_INT_STAT_DMA_MASK GENMASK(19, 14) +/* TX size, expressed in 4 bytes units */ +#define MBOX_INT_TX_SIZE_MASK GENMASK(24, 20) +/* SO_RO == strong order, relaxed order */ +#define MBOX_INT_STAT_DMA_SO_RO_MASK GENMASK(26, 25) +#define MBOX_INT_WB_EN_MASK BIT(28) +#define MBOX_INT_SET (val, field) \ + FIELD_PREP(MBOX_INT_##field##_MASK, val) + +#define MBOX_CTRL_TRIGGER_AEQE_MASK BIT(0) +#define MBOX_CTRL_TX_STATUS_MASK BIT(1) +#define MBOX_CTRL_DST_FUNC_MASK GENMASK(28, 16) +#define MBOX_CTRL_SET (val, field) \ + FIELD_PREP(MBOX_CTRL_##field##_MASK, val) +#define MBOX_MSG_POLLING_TIMEOUT_MS 8000 // send msg seg timeout#define MBOX_COMP_POLLING_TIMEOUT_MS 40000 // response
@@ -25,6 +42,21 @@#define MBOX_LAST_SEG_MAX_LEN \ (MBOX_MAX_BUF_SZ - MBOX_SEQ_ID_MAX_VAL * MBOX_SEG_LEN) +/* mbox write back status is 16B, only first 4B is used */ +#define MBOX_WB_STATUS_ERRCODE_MASK 0xFFFF +#define MBOX_WB_STATUS_MASK 0xFF +#define MBOX_WB_ERROR_CODE_MASK 0xFF00 +#define MBOX_WB_STATUS_FINISHED_SUCCESS 0xFF +#define MBOX_WB_STATUS_NOT_FINISHED 0x00 + +#define MBOX_STATUS_FINISHED (wb) \ + ((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) != MBOX_WB_STATUS_NOT_FINISHED) +#define MBOX_STATUS_SUCCESS (wb) \ + ((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) == \ + MBOX_WB_STATUS_FINISHED_SUCCESS) +#define MBOX_STATUS_ERRCODE (wb) \ + ((wb) & MBOX_WB_ERROR_CODE_MASK) +#define MBOX_DMA_MSG_QUEUE_DEPTH 32#define MBOX_AREA (hwif) \ ((hwif)->cfg_regs_base + HINIC3_FUNC_CSR_MAILBOX_DATA_OFF)
@@ -417,9 +449,412 @@ void hinic3_free_mbox(struct hinic3_hwdev *hwdev)kfree (mbox); } +#define MBOX_DMA_MSG_INIT_XOR_VAL 0x5a5a5a5a +#define MBOX_XOR_DATA_ALIGN 4 +static u32 mbox_dma_msg_xor (u32 *data,u32 msg_len) +{ +u32 xor =MBOX_DMA_MSG_INIT_XOR_VAL ; +u32 dw_len = msg_len /sizeof (u32); +u32 i; + +for (i =0 ; i < dw_len; i++) + xor ^= data[i]; + +return xor; +} + +#define MBOX_MQ_ID_MASK (mq, idx) ((idx) & ((mq)->depth - 1)) + +static bool is_msg_queue_full (struct mbox_dma_queue *mq) +{ +return MBOX_MQ_ID_MASK (mq, (mq)->prod_idx +1 ) == +MBOX_MQ_ID_MASK (mq, (mq)->cons_idx); +} + +static int mbox_prepare_dma_entry (struct hinic3_mbox *mbox, +struct mbox_dma_queue *mq, +struct mbox_dma_msg *dma_msg, +const void *msg,u32 msg_len) +{ +u64 dma_addr, offset; +void *dma_vaddr; + +if (is_msg_queue_full (mq)) { +dev_err (mbox->hwdev->dev,"Mbox sync message queue is busy, pi: %u, ci: %u\n" , + mq->prod_idx,MBOX_MQ_ID_MASK (mq, mq->cons_idx)); +return -EBUSY ; + } + +/* copy data to DMA buffer */ + offset = mq->prod_idx *MBOX_MAX_BUF_SZ ; + dma_vaddr = (u8 *)mq->dma_buf_vaddr + offset; +memcpy (dma_vaddr, msg, msg_len); + dma_addr = mq->dma_buf_paddr + offset; + dma_msg->dma_addr_high =cpu_to_le32 (upper_32_bits (dma_addr)); + dma_msg->dma_addr_low =cpu_to_le32 (lower_32_bits (dma_addr)); + dma_msg->msg_len =cpu_to_le32 (msg_len); +/* The firmware obtains message based on 4B alignment. */ + dma_msg->xor =cpu_to_le32 (mbox_dma_msg_xor (dma_vaddr, +ALIGN (msg_len,MBOX_XOR_DATA_ALIGN ))); + mq->prod_idx++; + mq->prod_idx =MBOX_MQ_ID_MASK (mq, mq->prod_idx); + +return 0 ; +} + +static int mbox_prepare_dma_msg (struct hinic3_mbox *mbox, +enum mbox_msg_ack_type ack_type, +struct mbox_dma_msg *dma_msg,const void *msg, +u32 msg_len) +{ +struct mbox_dma_queue *mq; +u32 val; + + val =hinic3_hwif_read_reg (mbox->hwdev->hwif,MBOX_MQ_CI_OFFSET ); +if (ack_type ==MBOX_MSG_ACK ) { + mq = &mbox->sync_msg_queue; + mq->cons_idx =MBOX_MQ_CI_GET (val,SYNC ); + }else { + mq = &mbox->async_msg_queue; + mq->cons_idx =MBOX_MQ_CI_GET (val,ASYNC ); + } + +return mbox_prepare_dma_entry (mbox, mq, dma_msg, msg, msg_len); +} + +static void clear_mbox_status (struct hinic3_send_mbox *mbox) +{ +__be64 *wb_status = mbox->wb_vaddr; + + *wb_status =0 ; +/* clear mailbox write back status */ +wmb (); +} + +static void mbox_dword_write (const void *src,void __iomem *dst,u32 count) +{ +const __le32 *src32 = src; +u32 __iomem *dst32 = dst; +u32 i; + +/* Data written to mbox is arranged in structs with little endian fields +* but when written to HW every dword (32bits) should be swapped since +* the HW will swap it again. +*/ +for (i =0 ; i < count; i++) +__raw_writel (swab32 ((__force __u32 )src32[i]), dst32 + i); +} + +static void mbox_copy_header (struct hinic3_hwdev *hwdev, +struct hinic3_send_mbox *mbox,__le64 *header) +{ +mbox_dword_write (header, mbox->data,MBOX_HEADER_SZ /sizeof (__le32)); +} + +static void mbox_copy_send_data (struct hinic3_hwdev *hwdev, +struct hinic3_send_mbox *mbox,void *seg, +u32 seg_len) +{ +u32 __iomem *dst = (u32 __iomem *)(mbox->data +MBOX_HEADER_SZ ); +u32 count, leftover, last_dword; +const __le32 *src = seg; + + count = seg_len /sizeof (u32); + leftover = seg_len %sizeof (u32); +if (count >0 ) +mbox_dword_write (src, dst, count); + +if (leftover >0 ) { + last_dword =0 ; +memcpy (&last_dword, src + count, leftover); +mbox_dword_write (&last_dword, dst + count,1 ); + } +} + +static void write_mbox_msg_attr (struct hinic3_mbox *mbox, +u16 dst_func,u16 dst_aeqn,u32 seg_len) +{ +struct hinic3_hwif *hwif = mbox->hwdev->hwif; +u32 mbox_int, mbox_ctrl, tx_size; + + tx_size =ALIGN (seg_len +MBOX_HEADER_SZ ,MBOX_SEG_LEN_ALIGN ) >>2 ; + + mbox_int =MBOX_INT_SET (dst_aeqn,DST_AEQN ) | +MBOX_INT_SET (0 ,STAT_DMA ) | +MBOX_INT_SET (tx_size,TX_SIZE ) | +MBOX_INT_SET (0 ,STAT_DMA_SO_RO ) | +MBOX_INT_SET (1 ,WB_EN ); + + mbox_ctrl =MBOX_CTRL_SET (1 ,TX_STATUS ) | +MBOX_CTRL_SET (0 ,TRIGGER_AEQE ) | +MBOX_CTRL_SET (dst_func,DST_FUNC ); + +hinic3_hwif_write_reg (hwif,HINIC3_FUNC_CSR_MAILBOX_INT_OFF , mbox_int); +hinic3_hwif_write_reg (hwif,HINIC3_FUNC_CSR_MAILBOX_CONTROL_OFF , + mbox_ctrl); +} + +static u16 get_mbox_status (const struct hinic3_send_mbox *mbox) +{ +__be64 *wb_status = mbox->wb_vaddr; +u64 wb_val; + + wb_val =be64_to_cpu (*wb_status); +/* verify reading before check */ +rmb (); + +return wb_val &MBOX_WB_STATUS_ERRCODE_MASK ; +} + +static enum hinic3_wait_return check_mbox_wb_status (void *priv_data) +{ +struct hinic3_mbox *mbox = priv_data; +u16 wb_status; + + wb_status =get_mbox_status (&mbox->send_mbox); + +return MBOX_STATUS_FINISHED (wb_status) ? +HINIC3_WAIT_PROCESS_CPL :HINIC3_WAIT_PROCESS_WAITING ; +} + +static int send_mbox_seg (struct hinic3_mbox *mbox,__le64 header, +u16 dst_func,void *seg,u32 seg_len,void *msg_info) +{ +struct hinic3_send_mbox *send_mbox = &mbox->send_mbox; +struct hinic3_hwdev *hwdev = mbox->hwdev; +u8 num_aeqs = hwdev->hwif->attr.num_aeqs; +enum mbox_msg_direction_type dir; +u16 dst_aeqn, wb_status, errcode; +int err; + +/* mbox to mgmt cpu, hardware doesn't care about dst aeq id */ +if (num_aeqs >MBOX_MSG_AEQ_FOR_MBOX ) { + dir =MBOX_MSG_HEADER_GET (header,DIRECTION ); + dst_aeqn = (dir ==MBOX_MSG_SEND ) ? +MBOX_MSG_AEQ_FOR_EVENT :MBOX_MSG_AEQ_FOR_MBOX ; + }else { + dst_aeqn =0 ; + } + +clear_mbox_status (send_mbox); +mbox_copy_header (hwdev, send_mbox, &header); +mbox_copy_send_data (hwdev, send_mbox, seg, seg_len); +write_mbox_msg_attr (mbox, dst_func, dst_aeqn, seg_len); + + err =hinic3_wait_for_timeout (mbox, check_mbox_wb_status, +MBOX_MSG_POLLING_TIMEOUT_MS , +USEC_PER_MSEC ); + wb_status =get_mbox_status (send_mbox); +if (err) { +dev_err (hwdev->dev,"Send mailbox segment timeout, wb status: 0x%x\n" , + wb_status); +return err; + } + +if (!MBOX_STATUS_SUCCESS (wb_status)) { +dev_err (hwdev->dev, +"Send mailbox segment to function %u error, wb status: 0x%x\n" , + dst_func, wb_status); + errcode =MBOX_STATUS_ERRCODE (wb_status); +return errcode ? errcode : -EFAULT ; + } + +return 0 ; +} + +static int send_mbox_msg (struct hinic3_mbox *mbox,u8 mod,u16 cmd, +const void *msg,u32 msg_len,u16 dst_func, +enum mbox_msg_direction_type direction, +enum mbox_msg_ack_type ack_type, +struct mbox_msg_info *msg_info) +{ +enum mbox_msg_data_type data_type =MBOX_MSG_DATA_INLINE ; +struct hinic3_hwdev *hwdev = mbox->hwdev; +struct mbox_dma_msg dma_msg; +u32 seg_len =MBOX_SEG_LEN ; +__le64 header =0 ; +u32 seq_id =0 ; +u16 rsp_aeq_id; +u8 *msg_seg; +int err =0 ; +u32 left; + +if (hwdev->hwif->attr.num_aeqs >MBOX_MSG_AEQ_FOR_MBOX ) + rsp_aeq_id =MBOX_MSG_AEQ_FOR_MBOX ; +else + rsp_aeq_id =0 ; + +if (dst_func ==MBOX_MGMT_FUNC_ID && + !(hwdev->features[0 ] &MBOX_COMM_F_MBOX_SEGMENT )) { + err =mbox_prepare_dma_msg (mbox, ack_type, &dma_msg, + msg, msg_len); +if (err) + goto err_send; + + msg = &dma_msg; + msg_len =sizeof (dma_msg); + data_type =MBOX_MSG_DATA_DMA ; + } + + msg_seg = (u8 *)msg; + left = msg_len; + + header =cpu_to_le64 (MBOX_MSG_HEADER_SET (msg_len,MSG_LEN ) | +MBOX_MSG_HEADER_SET (mod,MODULE ) | +MBOX_MSG_HEADER_SET (seg_len,SEG_LEN ) | +MBOX_MSG_HEADER_SET (ack_type,NO_ACK ) | +MBOX_MSG_HEADER_SET (data_type,DATA_TYPE ) | +MBOX_MSG_HEADER_SET (MBOX_SEQ_ID_START_VAL ,SEQID ) | +MBOX_MSG_HEADER_SET (direction,DIRECTION ) | +MBOX_MSG_HEADER_SET (cmd,CMD ) | +MBOX_MSG_HEADER_SET (msg_info->msg_id,MSG_ID ) | +MBOX_MSG_HEADER_SET (rsp_aeq_id,AEQ_ID ) | +MBOX_MSG_HEADER_SET (MBOX_MSG_FROM_MBOX ,SOURCE ) | +MBOX_MSG_HEADER_SET (!!msg_info->status,STATUS )); + +while (!(MBOX_MSG_HEADER_GET (header,LAST ))) { +if (left <=MBOX_SEG_LEN ) { + header &=cpu_to_le64 (~MBOX_MSG_HEADER_SEG_LEN_MASK ); + header |= +cpu_to_le64 (MBOX_MSG_HEADER_SET (left,SEG_LEN ) | +MBOX_MSG_HEADER_SET (1 ,LAST )); + seg_len = left; + } + + err =send_mbox_seg (mbox, header, dst_func, msg_seg, + seg_len, msg_info); +if (err) { +dev_err (hwdev->dev,"Failed to send mbox seg, seq_id=0x%llx\n" , +MBOX_MSG_HEADER_GET (header,SEQID )); + goto err_send; + } + + left -=MBOX_SEG_LEN ; + msg_seg +=MBOX_SEG_LEN ; + seq_id++; + header &=cpu_to_le64 (~MBOX_MSG_HEADER_SEG_LEN_MASK ); + header |=cpu_to_le64 (MBOX_MSG_HEADER_SET (seq_id,SEQID )); + } + +err_send: +return err; +} + +static void set_mbox_to_func_event (struct hinic3_mbox *mbox, +enum mbox_event_state event_flag) +{ +spin_lock (&mbox->mbox_lock); + mbox->event_flag = event_flag; +spin_unlock (&mbox->mbox_lock); +} + +static enum hinic3_wait_return check_mbox_msg_finish (void *priv_data) +{ +struct hinic3_mbox *mbox = priv_data; + +return (mbox->event_flag ==MBOX_EVENT_SUCCESS ) ? +HINIC3_WAIT_PROCESS_CPL :HINIC3_WAIT_PROCESS_WAITING ; +} + +static int wait_mbox_msg_completion (struct hinic3_mbox *mbox, +u32 timeout) +{ +u32 wait_time; +int err; + + wait_time = (timeout !=0 ) ? timeout :MBOX_COMP_POLLING_TIMEOUT_MS ; + err =hinic3_wait_for_timeout (mbox, check_mbox_msg_finish, + wait_time,USEC_PER_MSEC ); +if (err) { +set_mbox_to_func_event (mbox,MBOX_EVENT_TIMEOUT ); +return err; + } +set_mbox_to_func_event (mbox,MBOX_EVENT_END ); + +return 0 ; +} +int hinic3_send_mbox_to_mgmt (struct hinic3_hwdev *hwdev,u8 mod,u16 cmd,const struct mgmt_msg_params *msg_params) { -/* Completed by later submission due to LoC limit. */ -return -EFAULT ; +struct hinic3_mbox *mbox = hwdev->mbox; +struct mbox_msg_info msg_info = {}; +struct hinic3_msg_desc *msg_desc; +u32 msg_len; +int err; + +/* expect response message */ + msg_desc =get_mbox_msg_desc (mbox,MBOX_MSG_RESP ,MBOX_MGMT_FUNC_ID ); +mutex_lock (&mbox->mbox_send_lock); + msg_info.msg_id = (mbox->send_msg_id +1 ) &0xF ; + mbox->send_msg_id = msg_info.msg_id; +set_mbox_to_func_event (mbox,MBOX_EVENT_START ); + + err =send_mbox_msg (mbox, mod, cmd, msg_params->buf_in, + msg_params->in_size,MBOX_MGMT_FUNC_ID , +MBOX_MSG_SEND ,MBOX_MSG_ACK , &msg_info); +if (err) { +dev_err (hwdev->dev,"Send mailbox mod %u, cmd %u failed, msg_id: %u, err: %d\n" , + mod, cmd, msg_info.msg_id, err); +set_mbox_to_func_event (mbox,MBOX_EVENT_FAIL ); + goto err_send; + } + +if (wait_mbox_msg_completion (mbox, msg_params->timeout_ms)) { +dev_err (hwdev->dev, +"Send mbox msg timeout, msg_id: %u\n" , msg_info.msg_id); + err = -ETIMEDOUT ; + goto err_send; + } + +if (mod != msg_desc->mod || cmd !=le16_to_cpu (msg_desc->cmd)) { +dev_err (hwdev->dev, +"Invalid response mbox message, mod: 0x%x, cmd: 0x%x, expect mod: 0x%x, cmd: 0x%x\n" , + msg_desc->mod, msg_desc->cmd, mod, cmd); + err = -EFAULT ; + goto err_send; + } + +if (msg_desc->msg_info.status) { + err = msg_desc->msg_info.status; + goto err_send; + } + +if (msg_params->buf_out) { + msg_len =le16_to_cpu (msg_desc->msg_len); +if (msg_len != msg_params->expected_out_size) { +dev_err (hwdev->dev, +"Invalid response mbox message length: %u for mod %d cmd %u, expected length: %u\n" , + msg_desc->msg_len, mod, cmd, + msg_params->expected_out_size); + err = -EFAULT ; + goto err_send; + } + +memcpy (msg_params->buf_out, msg_desc->msg, msg_len); + } + +err_send: +mutex_unlock (&mbox->mbox_send_lock); + +return err; +} + +int hinic3_send_mbox_to_mgmt_no_ack (struct hinic3_hwdev *hwdev,u8 mod,u16 cmd, +const struct mgmt_msg_params *msg_params) +{ +struct hinic3_mbox *mbox = hwdev->mbox; +struct mbox_msg_info msg_info = {}; +int err; + +mutex_lock (&mbox->mbox_send_lock); + err =send_mbox_msg (mbox, mod, cmd, msg_params->buf_in, + msg_params->in_size,MBOX_MGMT_FUNC_ID , +MBOX_MSG_SEND ,MBOX_MSG_NO_ACK , &msg_info); +if (err) +dev_err (hwdev->dev,"Send mailbox no ack failed\n" ); + +mutex_unlock (&mbox->mbox_send_lock); + +return err; }
drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +23 -0
@@ -8,6 +8,7 @@#include <linux/mutex.h> struct hinic3_hwdev ; +struct mgmt_msg_params ;#define MBOX_MSG_HEADER_SRC_GLB_FUNC_IDX_MASK GENMASK_ULL(12, 0)#define MBOX_MSG_HEADER_STATUS_MASK BIT_ULL(13)
@@ -38,6 +39,26 @@ enum mbox_msg_direction_type { MBOX_MSG_RESP = 1, }; +/* Indicates if mbox message expects a response (ack) or not */ +enum mbox_msg_ack_type { +MBOX_MSG_ACK =0 , +MBOX_MSG_NO_ACK =1 , +}; + +enum mbox_msg_data_type { +MBOX_MSG_DATA_INLINE =0 , +MBOX_MSG_DATA_DMA =1 , +}; + +enum mbox_msg_src_type { +MBOX_MSG_FROM_MBOX =1 , +}; + +enum mbox_msg_aeq_type { +MBOX_MSG_AEQ_FOR_EVENT =0 , +MBOX_MSG_AEQ_FOR_MBOX =1 , +}; +#define HINIC3_MBOX_WQ_NAME "hinic3_mbox"struct mbox_msg_info {
@@ -114,5 +135,7 @@ void hinic3_free_mbox(struct hinic3_hwdev *hwdev);int hinic3_send_mbox_to_mgmt (struct hinic3_hwdev *hwdev,u8 mod,u16 cmd,const struct mgmt_msg_params *msg_params); +int hinic3_send_mbox_to_mgmt_no_ack (struct hinic3_hwdev *hwdev,u8 mod,u16 cmd, +const struct mgmt_msg_params *msg_params);#endif
Signature · 1 line
2.43.0
Fan Gong
maintainerPATCH v14 8/8 hinic3: Interrupt request configuration
In reply to Fan GongConfigure interrupt request initialization.
It allows driver to receive packets and management information from HW.
--- .../ethernet/huawei/hinic3/hinic3_hw_comm.c | 31 ++++ .../ethernet/huawei/hinic3/hinic3_hw_comm.h | 13 ++ .../net/ethernet/huawei/hinic3/hinic3_irq.c | 136 +++++++++++++++++- .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 4 - 4 files changed, 178 insertions(+), 6 deletions(-)
drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.c +31 -0
@@ -8,6 +8,37 @@#include "hinic3_hwif.h" #include "hinic3_mbox.h" +int hinic3_set_interrupt_cfg_direct (struct hinic3_hwdev *hwdev, +const struct hinic3_interrupt_info *info) +{ +struct comm_cmd_cfg_msix_ctrl_reg msix_cfg = {}; +struct mgmt_msg_params msg_params = {}; +int err; + + msix_cfg.func_id =hinic3_global_func_id (hwdev); + msix_cfg.msix_index = info->msix_index; + msix_cfg.opcode =MGMT_MSG_CMD_OP_SET ; + + msix_cfg.lli_credit_cnt = info->lli_credit_limit; + msix_cfg.lli_timer_cnt = info->lli_timer_cfg; + msix_cfg.pending_cnt = info->pending_limit; + msix_cfg.coalesce_timer_cnt = info->coalesc_timer_cfg; + msix_cfg.resend_timer_cnt = info->resend_timer_cfg; + +mgmt_msg_params_init_default (&msg_params, &msix_cfg,sizeof (msix_cfg)); + + err =hinic3_send_mbox_to_mgmt (hwdev,MGMT_MOD_COMM , +COMM_CMD_CFG_MSIX_CTRL_REG , &msg_params); +if (err || msix_cfg.head.status) { +dev_err (hwdev->dev, +"Failed to set interrupt config, err: %d, status: 0x%x\n" , + err, msix_cfg.head.status); +return -EINVAL ; + } + +return 0 ; +} +int hinic3_func_reset (struct hinic3_hwdev *hwdev,u16 func_id,u64 reset_flag) {struct comm_cmd_func_reset func_reset = {};
drivers/net/ethernet/huawei/hinic3/hinic3_hw_comm.h +13 -0
@@ -8,6 +8,19 @@struct hinic3_hwdev ; +struct hinic3_interrupt_info { +u32 lli_set; +u32 interrupt_coalesc_set; +u16 msix_index; +u8 lli_credit_limit; +u8 lli_timer_cfg; +u8 pending_limit; +u8 coalesc_timer_cfg; +u8 resend_timer_cfg; +}; + +int hinic3_set_interrupt_cfg_direct (struct hinic3_hwdev *hwdev, +const struct hinic3_interrupt_info *info);int hinic3_func_reset (struct hinic3_hwdev *hwdev,u16 func_id,u64 reset_flag);#endif
drivers/net/ethernet/huawei/hinic3/hinic3_irq.c +134 -2
151 lines not on this page · raw message
drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +0 -4
@@ -85,8 +85,4 @@ void hinic3_set_netdev_ops(struct net_device *netdev);int hinic3_qps_irq_init (struct net_device *netdev);void hinic3_qps_irq_uninit (struct net_device *netdev); -/* Temporary prototypes. Functions become static in later submission. */ -void qp_add_napi (struct hinic3_irq_cfg *irq_cfg); -void qp_del_napi (struct hinic3_irq_cfg *irq_cfg); -#endif
Signature · 1 line
2.43.0
This series was applied to netdev/net-next.git (main) by Jakub Kicinski <[email protected]>:
Hello:
This series was applied to netdev/net-next.git (main) by Jakub Kicinski <[email protected]>:
Quoted 9 lines · On Wed, 20 Aug 2025 17:31:17 +0800 you wrote:
This is the 2/3 patch of the patch-set described below.
The patch-set contains driver for Huawei's 3rd generation HiNIC Ethernet device that will be available in the future.
This is an SRIOV device, designed for data centers. Initially, the driver only supports VFs.
[...]
Here is the summary with links:
- [net-next,v14,1/8] hinic3: Async Event Queue interfaces
https://git.kernel.org/netdev/net-next/c/a4511307be86 - [net-next,v14,2/8] hinic3: Complete Event Queue interfaces https://git.kernel.org/netdev/net-next/c/c4bbfd9b0d32 - [net-next,v14,3/8] hinic3: Command Queue framework https://git.kernel.org/netdev/net-next/c/db03a1ced61c - [net-next,v14,4/8] hinic3: Command Queue interfaces https://git.kernel.org/netdev/net-next/c/16a6fce06757 - [net-next,v14,5/8] hinic3: TX & RX Queue coalesce interfaces https://git.kernel.org/netdev/net-next/c/bef7c33c6754 - [net-next,v14,6/8] hinic3: Mailbox framework https://git.kernel.org/netdev/net-next/c/2742e06e2d42 - [net-next,v14,7/8] hinic3: Mailbox management interfaces https://git.kernel.org/netdev/net-next/c/a8255ea56aee - [net-next,v14,8/8] hinic3: Interrupt request configuration https://git.kernel.org/netdev/net-next/c/a5a90346bb12
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html