/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd. * All rights reserved. */ #ifndef XSC_IB_H #define XSC_IB_H #include #include #include #include #include #include "common/xsc_core.h" #include "common/driver.h" #include "common/cq.h" #include "common/qp.h" #include #include #include "xsc_ib_compat.h" #define xsc_ib_dbg(dev, format, arg...) \ do { \ if (xsc_log_level <= XSC_LOG_LEVEL_DBG) \ pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, \ __func__, __LINE__, current->pid, ##arg); \ } while (0) #define xsc_ib_err(dev, format, arg...) \ do { \ if (xsc_log_level <= XSC_LOG_LEVEL_ERR) \ pr_err("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, \ __func__, __LINE__, current->pid, ##arg); \ } while (0) #define xsc_ib_warn(dev, format, arg...) \ do { \ if (xsc_log_level <= XSC_LOG_LEVEL_WARN) \ pr_warn("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, \ __func__, __LINE__, current->pid, ##arg); \ } while (0) struct xsc_ib_ucontext { struct ib_ucontext ibucontext; struct list_head db_page_list; /* protect doorbell record alloc/free */ struct mutex db_page_mutex; }; #define field_avail(type, fld, sz) (offsetof(type, fld) + \ sizeof(((type *)0)->fld) <= (sz)) static inline struct xsc_ib_ucontext *to_xucontext(struct ib_ucontext *ibucontext) { return container_of(ibucontext, struct xsc_ib_ucontext, ibucontext); } struct xsc_ib_pd { struct ib_pd ibpd; u32 pdn; u32 pa_lkey; }; /* Use macros here so that don't have to duplicate * enum ib_send_flags and enum ib_qp_type for low-level driver */ #define XSC_IB_QPT_REG_UMR IB_QPT_RESERVED1 enum { XSC_PAGE_SHIFT_4K = 12, XSC_PAGE_SHIFT_64K = 16, XSC_PAGE_SHIFT_2M = 21, XSC_PAGE_SHIFT_1G = 30, }; enum { XSC_PAGE_MODE_4K = 0, XSC_PAGE_MODE_64K = 1, XSC_PAGE_MODE_2M = 2, XSC_PAGE_MODE_1G = 3, }; struct wr_list { u16 opcode; u16 next; }; struct xsc_ib_wq { u64 *wrid; u32 *wr_data; struct wr_list *w_list; unsigned long *wqe_head; u16 unsig_count; /* serialize post to the work queue */ spinlock_t lock; int wqe_cnt; int ds_cnt; int max_post; int max_gs; int offset; int wqe_shift; unsigned int head; unsigned int tail; u16 cur_post; u16 last_poll; void *qend; void *hdr_buf; u32 hdr_size; dma_addr_t hdr_dma; int mad_queue_depth; int mad_index; }; enum { XSC_QP_USER, XSC_QP_KERNEL, XSC_QP_EMPTY }; struct xsc_ib_qp { struct ib_qp ibqp; struct xsc_core_qp xqp; struct xsc_buf buf; struct xsc_db db; struct xsc_ib_wq rq; u32 doorbell_qpn; u8 sq_signal_bits; u8 fm_cache; int sq_max_wqes_per_wr; int sq_spare_wqes; struct xsc_ib_wq sq; struct ib_umem *umem; int buf_size; /* serialize qp state modifications */ struct mutex mutex; u16 xrcdn; u32 flags; u8 port; u8 alt_port; u8 atomic_rd_en; u8 resp_depth; u8 state; int xsc_type; int wq_sig; int scat_cqe; int max_inline_data; int has_rq; int create_type; u32 pa_lkey; /* For QP1 */ struct ib_ud_header qp1_hdr; u32 send_psn; struct xsc_qp_context ctx; struct ib_cq *send_cq; struct ib_cq *recv_cq; /* For qp resources */ spinlock_t lock; }; struct xsc_ib_cq_buf { struct xsc_buf buf; struct ib_umem *umem; int cqe_size; }; enum xsc_ib_qp_flags { XSC_IB_QP_BLOCK_MULTICAST_LOOPBACK = 1 << 0, XSC_IB_QP_SIGNATURE_HANDLING = 1 << 1, }; struct xsc_shared_mr_info { int mr_id; struct ib_umem *umem; }; struct xsc_ib_cq { struct ib_cq ibcq; struct xsc_core_cq xcq; struct xsc_ib_cq_buf buf; struct xsc_db db; /* serialize access to the CQ */ spinlock_t lock; /* protect resize cq */ struct mutex resize_mutex; struct xsc_ib_cq_resize *resize_buf; struct ib_umem *resize_umem; int cqe_size; }; struct xsc_ib_xrcd { struct ib_xrcd ibxrcd; u32 xrcdn; }; struct xsc_ib_peer_id; struct xsc_ib_mr { struct ib_mr ibmr; struct xsc_core_mr mmr; struct ib_umem *umem; struct xsc_shared_mr_info *smr_info; struct list_head list; int order; __be64 *pas; dma_addr_t dma; int npages; struct completion done; enum ib_wc_status status; struct xsc_ib_peer_id *peer_id; atomic_t invalidated; struct completion invalidation_comp; }; struct xsc_ib_peer_id { struct completion comp; struct xsc_ib_mr *mr; }; struct xsc_cache_ent { struct list_head head; /* sync access to the cahce entry */ spinlock_t lock; struct dentry *dir; char name[4]; u32 order; u32 size; u32 cur; u32 miss; u32 limit; struct dentry *fsize; struct dentry *fcur; struct dentry *fmiss; struct dentry *flimit; struct xsc_ib_dev *dev; struct work_struct work; struct delayed_work dwork; }; struct xsc_mr_cache { struct workqueue_struct *wq; struct xsc_cache_ent ent[MAX_MR_CACHE_ENTRIES]; int stopped; struct dentry *root; unsigned long last_add; }; struct xsc_gid { u8 data[16]; }; struct xsc_sgid_tbl { struct xsc_gid *tbl; u32 max; u32 count; }; struct xsc_ib_res { struct xsc_sgid_tbl sgid_tbl; }; struct xsc_ib_resources { struct ib_cq *c0; struct ib_xrcd *x0; struct ib_xrcd *x1; struct ib_pd *p0; struct ib_srq *s0; }; struct xsc_ib_dev { struct ib_device ib_dev; struct uverbs_object_tree_def *driver_trees[6]; struct net_device *netdev; struct xsc_core_device *xdev; XSC_DECLARE_DOORBELL_LOCK(uar_lock); struct list_head eqs_list; int num_ports; int num_comp_vectors; /* serialize update of capability mask */ struct mutex cap_mask_mutex; u8 ib_active; /* sync used page count stats */ spinlock_t mr_lock; struct xsc_ib_res ib_res; struct xsc_ib_resources devr; struct xsc_mr_cache cache; u32 crc_32_table[256]; int cm_pcp; int cm_dscp; }; union xsc_ib_fw_ver { u64 data; struct { u16 chip_ver_h; u16 hotfix_num; u16 chip_ver_l; u16 feature_flag; } s; }; struct xsc_pa_chunk { struct list_head list; u64 va; dma_addr_t pa; size_t length; }; static inline struct xsc_ib_cq *to_xibcq(struct xsc_core_cq *xcq) { return container_of(xcq, struct xsc_ib_cq, xcq); } static inline struct xsc_ib_xrcd *to_mxrcd(struct ib_xrcd *ibxrcd) { return container_of(ibxrcd, struct xsc_ib_xrcd, ibxrcd); } static inline struct xsc_ib_dev *to_mdev(struct ib_device *ibdev) { return container_of(ibdev, struct xsc_ib_dev, ib_dev); } static inline struct xsc_ib_cq *to_xcq(struct ib_cq *ibcq) { return container_of(ibcq, struct xsc_ib_cq, ibcq); } static inline struct xsc_ib_qp *to_xibqp(struct xsc_core_qp *xqp) { return container_of(xqp, struct xsc_ib_qp, xqp); } static inline struct xsc_ib_pd *to_mpd(struct ib_pd *ibpd) { return container_of(ibpd, struct xsc_ib_pd, ibpd); } static inline struct xsc_ib_qp *to_xqp(struct ib_qp *ibqp) { return container_of(ibqp, struct xsc_ib_qp, ibqp); } static inline struct xsc_ib_mr *to_mmr(struct ib_mr *ibmr) { return container_of(ibmr, struct xsc_ib_mr, ibmr); } struct xsc_ib_ah { struct ib_ah ibah; struct xsc_av av; }; static inline struct xsc_ib_ah *to_mah(struct ib_ah *ibah) { return container_of(ibah, struct xsc_ib_ah, ibah); } static inline struct xsc_ib_dev *xdev2ibdev(struct xsc_core_device *xdev) { return container_of((void *)xdev, struct xsc_ib_dev, xdev); } int xsc_ib_query_port(struct ib_device *ibdev, u32 port, struct ib_port_attr *props); int xsc_ib_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr, struct ib_udata *udata); void __xsc_ib_cq_clean(struct xsc_ib_cq *cq, u32 qpn); void xsc_ib_cq_clean(struct xsc_ib_cq *cq, u32 qpn); int xsc_ib_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr); int xsc_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata); int xsc_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr); int xsc_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr); int xsc_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, const struct ib_recv_wr **bad_wr); void *xsc_get_send_wqe(struct xsc_ib_qp *qp, int n); int xsc_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); int xsc_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); struct ib_mr *xsc_ib_get_dma_mr(struct ib_pd *pd, int acc); struct ib_mr *xsc_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt_addr, int access_flags, struct ib_udata *udata); int xsc_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset); void xsc_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, int *ncont, int *order); void xsc_ib_populate_pas(struct xsc_ib_dev *dev, struct ib_umem *umem, int page_shift, __be64 *pas, int npages, bool need_to_devide); const struct uverbs_object_tree_def *xsc_ib_get_devx_tree(void); int xsc_ib_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, unsigned int *sg_offset); int xsc_wr_reg_mr(struct xsc_ib_dev *dev, const struct ib_send_wr *wr); int xsc_wr_invalidate_mr(struct xsc_ib_dev *dev, const struct ib_send_wr *wr); int xsc_find_best_pgsz(struct ib_umem *umem, unsigned long pgsz_bitmap, unsigned long addr, int *npage, int *shift, u64 **pas); static inline void init_query_mad(struct ib_smp *mad) { mad->base_version = 1; mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; mad->class_version = 1; mad->method = IB_MGMT_METHOD_GET; } static inline u8 convert_access(int acc) { return (acc & IB_ACCESS_REMOTE_ATOMIC ? XSC_PERM_ATOMIC : 0) | (acc & IB_ACCESS_REMOTE_WRITE ? XSC_PERM_REMOTE_WRITE : 0) | (acc & IB_ACCESS_REMOTE_READ ? XSC_PERM_REMOTE_READ : 0) | (acc & IB_ACCESS_LOCAL_WRITE ? XSC_PERM_LOCAL_WRITE : 0) | XSC_PERM_LOCAL_READ; } static inline enum ib_mtu xsc_net_to_ib_mtu(unsigned int mtu) { mtu = mtu - (IB_GRH_BYTES + IB_UDP_BYTES + IB_BTH_BYTES + IB_EXT_XRC_BYTES + IB_EXT_ATOMICETH_BYTES + IB_ICRC_BYTES); if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096)) return IB_MTU_4096; else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024)) return IB_MTU_1024; else return 0; } /** * UDP source port selection must adhere IANA port allocation ranges. Thus * we will be using IANA recommendation for Ephemeral port range of: * 49152-65535, or in hex: 0xC000-0xFFFF. */ #define IB_ROCE_UDP_ENCAP_VALID_PORT_MIN (0xC000) #define IB_ROCE_UDP_ENCAP_VALID_PORT_MAX (0xFFFF) #define IB_GRH_FLOWLABEL_MASK (0x000FFFFF) /** * rdma_flow_label_to_udp_sport - generate a RoCE v2 UDP src port value based * on the flow_label * * This function will convert the 20 bit flow_label input to a valid RoCE v2 * UDP src port 14 bit value. All RoCE V2 drivers should use this same * convention. */ static inline u16 xsc_flow_label_to_udp_sport(u32 fl) { u32 fl_low = fl & 0x03fff, fl_high = fl & 0xFC000; fl_low ^= fl_high >> 14; return (u16)(fl_low | IB_ROCE_UDP_ENCAP_VALID_PORT_MIN); } #endif /* XSC_IB_H */