/* SPDX-License-Identifier: GPL-2.0 */ // Copyright (c) 2025 Broadcom. #ifndef __BNG_FW_H__ #define __BNG_FW_H__ #include "bng_tlv.h" /* FW DB related */ #define BNG_FW_CMDQ_TRIG_VAL 1 #define BNG_FW_COMM_PCI_BAR_REGION 0 #define BNG_FW_COMM_CONS_PCI_BAR_REGION 2 #define BNG_FW_DBR_BASE_PAGE_SHIFT 12 #define BNG_FW_COMM_SIZE 0x104 #define BNG_FW_COMM_BASE_OFFSET 0x600 #define BNG_FW_COMM_TRIG_OFFSET 0x100 #define BNG_FW_PF_VF_COMM_PROD_OFFSET 0xc #define BNG_FW_CREQ_DB_LEN 8 /* CREQ */ #define BNG_FW_CREQE_MAX_CNT (64 * 1024) #define BNG_FW_CREQE_UNITS 16 #define BNG_FW_CREQ_ENTRY_POLL_BUDGET 0x100 #define BNG_FW_CREQ_CMP_VALID(hdr, pass) \ (!!((hdr)->v & CREQ_BASE_V) == \ !((pass) & BNG_RE_FLAG_EPOCH_CONS_MASK)) #define BNG_FW_CREQ_ENTRY_POLL_BUDGET 0x100 /* CMDQ */ struct bng_fw_cmdqe { u8 data[16]; }; #define BNG_FW_CMDQE_MAX_CNT 8192 #define BNG_FW_CMDQE_UNITS sizeof(struct bng_fw_cmdqe) #define BNG_FW_CMDQE_BYTES(depth) ((depth) * BNG_FW_CMDQE_UNITS) #define BNG_FW_MAX_COOKIE_VALUE (BNG_FW_CMDQE_MAX_CNT - 1) #define BNG_FW_CMD_IS_BLOCKING 0x8000 /* Crsq buf is 1024-Byte */ struct bng_re_crsbe { u8 data[1024]; }; static inline u32 bng_fw_cmdqe_npages(u32 depth) { u32 npages; npages = BNG_FW_CMDQE_BYTES(depth) / PAGE_SIZE; if (BNG_FW_CMDQE_BYTES(depth) % PAGE_SIZE) npages++; return npages; } static inline u32 bng_fw_cmdqe_page_size(u32 depth) { return (bng_fw_cmdqe_npages(depth) * PAGE_SIZE); } struct bng_re_cmdq_mbox { struct bng_re_reg_desc reg; void __iomem *prod; void __iomem *db; }; /* HWQ */ struct bng_re_cmdq_ctx { struct bng_re_hwq hwq; struct bng_re_cmdq_mbox cmdq_mbox; unsigned long flags; #define FIRMWARE_INITIALIZED_FLAG (0) #define FIRMWARE_STALL_DETECTED (3) #define FIRMWARE_FIRST_FLAG (31) wait_queue_head_t waitq; u32 seq_num; }; struct bng_re_creq_db { struct bng_re_reg_desc reg; struct bng_re_db_info dbinfo; }; struct bng_re_creq_stat { u64 creq_qp_event_processed; u64 creq_func_event_processed; }; struct bng_re_creq_ctx { struct bng_re_hwq hwq; struct bng_re_creq_db creq_db; struct bng_re_creq_stat stats; struct tasklet_struct creq_tasklet; u16 ring_id; int msix_vec; bool irq_handler_avail; char *irq_name; }; struct bng_re_crsqe { struct creq_qp_event *resp; u32 req_size; /* Free slots at the time of submission */ u32 free_slots; u8 opcode; bool is_waiter_alive; bool is_in_used; }; struct bng_re_rcfw_sbuf { void *sb; dma_addr_t dma_addr; u32 size; }; /* RoCE FW Communication Channels */ struct bng_re_rcfw { struct pci_dev *pdev; struct bng_re_res *res; struct bng_re_cmdq_ctx cmdq; struct bng_re_creq_ctx creq; struct bng_re_crsqe *crsqe_tbl; /* To synchronize the qp-handle hash table */ spinlock_t tbl_lock; u32 cmdq_depth; /* cached from chip cctx for quick reference in slow path */ u16 max_timeout; atomic_t rcfw_intr_enabled; }; struct bng_re_cmdqmsg { struct cmdq_base *req; struct creq_base *resp; void *sb; u32 req_sz; u32 res_sz; u8 block; }; static inline void bng_re_rcfw_cmd_prep(struct cmdq_base *req, u8 opcode, u8 cmd_size) { req->opcode = opcode; req->cmd_size = cmd_size; } static inline void bng_re_fill_cmdqmsg(struct bng_re_cmdqmsg *msg, void *req, void *resp, void *sb, u32 req_sz, u32 res_sz, u8 block) { msg->req = req; msg->resp = resp; msg->sb = sb; msg->req_sz = req_sz; msg->res_sz = res_sz; msg->block = block; } /* Get the number of command units required for the req. The * function returns correct value only if called before * setting using bng_re_set_cmd_slots */ static inline u32 bng_re_get_cmd_slots(struct cmdq_base *req) { u32 cmd_units = 0; if (HAS_TLV_HEADER(req)) { struct roce_tlv *tlv_req = (struct roce_tlv *)req; cmd_units = tlv_req->total_size; } else { cmd_units = (req->cmd_size + BNG_FW_CMDQE_UNITS - 1) / BNG_FW_CMDQE_UNITS; } return cmd_units; } static inline u32 bng_re_set_cmd_slots(struct cmdq_base *req) { u32 cmd_byte = 0; if (HAS_TLV_HEADER(req)) { struct roce_tlv *tlv_req = (struct roce_tlv *)req; cmd_byte = tlv_req->total_size * BNG_FW_CMDQE_UNITS; } else { cmd_byte = req->cmd_size; req->cmd_size = (req->cmd_size + BNG_FW_CMDQE_UNITS - 1) / BNG_FW_CMDQE_UNITS; } return cmd_byte; } void bng_re_free_rcfw_channel(struct bng_re_rcfw *rcfw); int bng_re_alloc_fw_channel(struct bng_re_res *res, struct bng_re_rcfw *rcfw); int bng_re_enable_fw_channel(struct bng_re_rcfw *rcfw, int msix_vector, int cp_bar_reg_off); void bng_re_disable_rcfw_channel(struct bng_re_rcfw *rcfw); int bng_re_rcfw_start_irq(struct bng_re_rcfw *rcfw, int msix_vector, bool need_init); void bng_re_rcfw_stop_irq(struct bng_re_rcfw *rcfw, bool kill); int bng_re_rcfw_send_message(struct bng_re_rcfw *rcfw, struct bng_re_cmdqmsg *msg); int bng_re_init_rcfw(struct bng_re_rcfw *rcfw, struct bng_re_stats *stats_ctx); int bng_re_deinit_rcfw(struct bng_re_rcfw *rcfw); #endif