// SPDX-License-Identifier: GPL-2.0-only /* * Huawei HiNIC PCI Express Linux driver * Copyright(c) 2017 Huawei Technologies Co., Ltd */ #include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/atomic.h> #include <linux/semaphore.h> #include <linux/errno.h> #include <linux/vmalloc.h> #include <linux/err.h> #include <asm/byteorder.h> #include "hinic_hw_if.h" #include "hinic_hw_wqe.h" #include "hinic_hw_wq.h" #include "hinic_hw_cmdq.h" #define WQS_BLOCKS_PER_PAGE … #define WQ_BLOCK_SIZE … #define WQS_PAGE_SIZE … #define WQS_MAX_NUM_BLOCKS … #define WQS_FREE_BLOCKS_SIZE(wqs) … #define WQ_SIZE(wq) … #define WQ_PAGE_ADDR_SIZE … #define WQ_MAX_PAGES … #define CMDQ_BLOCK_SIZE … #define CMDQ_PAGE_SIZE … #define CMDQ_WQ_MAX_PAGES … #define WQ_BASE_VADDR(wqs, wq) … #define WQ_BASE_PADDR(wqs, wq) … #define WQ_BASE_ADDR(wqs, wq) … #define CMDQ_BASE_VADDR(cmdq_pages, wq) … #define CMDQ_BASE_PADDR(cmdq_pages, wq) … #define CMDQ_BASE_ADDR(cmdq_pages, wq) … #define WQ_PAGE_ADDR(wq, idx) … #define MASKED_WQE_IDX(wq, idx) … #define WQE_IN_RANGE(wqe, start, end) … #define WQE_SHADOW_PAGE(wq, wqe) … static inline int WQE_PAGE_OFF(struct hinic_wq *wq, u16 idx) { … } static inline int WQE_PAGE_NUM(struct hinic_wq *wq, u16 idx) { … } /** * queue_alloc_page - allocate page for Queue * @hwif: HW interface for allocating DMA * @vaddr: virtual address will be returned in this address * @paddr: physical address will be returned in this address * @shadow_vaddr: VM area will be return here for holding WQ page addresses * @page_sz: page size of each WQ page * * Return 0 - Success, negative - Failure **/ static int queue_alloc_page(struct hinic_hwif *hwif, u64 **vaddr, u64 *paddr, void ***shadow_vaddr, size_t page_sz) { … } /** * wqs_allocate_page - allocate page for WQ set * @wqs: Work Queue Set * @page_idx: the page index of the page will be allocated * * Return 0 - Success, negative - Failure **/ static int wqs_allocate_page(struct hinic_wqs *wqs, int page_idx) { … } /** * wqs_free_page - free page of WQ set * @wqs: Work Queue Set * @page_idx: the page index of the page will be freed **/ static void wqs_free_page(struct hinic_wqs *wqs, int page_idx) { … } /** * cmdq_allocate_page - allocate page for cmdq * @cmdq_pages: the pages of the cmdq queue struct to hold the page * * Return 0 - Success, negative - Failure **/ static int cmdq_allocate_page(struct hinic_cmdq_pages *cmdq_pages) { … } /** * cmdq_free_page - free page from cmdq * @cmdq_pages: the pages of the cmdq queue struct that hold the page **/ static void cmdq_free_page(struct hinic_cmdq_pages *cmdq_pages) { … } static int alloc_page_arrays(struct hinic_wqs *wqs) { … } static void free_page_arrays(struct hinic_wqs *wqs) { … } static int wqs_next_block(struct hinic_wqs *wqs, int *page_idx, int *block_idx) { … } static void wqs_return_block(struct hinic_wqs *wqs, int page_idx, int block_idx) { … } static void init_wqs_blocks_arr(struct hinic_wqs *wqs) { … } /** * hinic_wqs_alloc - allocate Work Queues set * @wqs: Work Queue Set * @max_wqs: maximum wqs to allocate * @hwif: HW interface for use for the allocation * * Return 0 - Success, negative - Failure **/ int hinic_wqs_alloc(struct hinic_wqs *wqs, int max_wqs, struct hinic_hwif *hwif) { … } /** * hinic_wqs_free - free Work Queues set * @wqs: Work Queue Set **/ void hinic_wqs_free(struct hinic_wqs *wqs) { … } /** * alloc_wqes_shadow - allocate WQE shadows for WQ * @wq: WQ to allocate shadows for * * Return 0 - Success, negative - Failure **/ static int alloc_wqes_shadow(struct hinic_wq *wq) { … } /** * free_wqes_shadow - free WQE shadows of WQ * @wq: WQ to free shadows from **/ static void free_wqes_shadow(struct hinic_wq *wq) { … } /** * free_wq_pages - free pages of WQ * @hwif: HW interface for releasing dma addresses * @wq: WQ to free pages from * @num_q_pages: number pages to free **/ static void free_wq_pages(struct hinic_wq *wq, struct hinic_hwif *hwif, int num_q_pages) { … } /** * alloc_wq_pages - alloc pages for WQ * @hwif: HW interface for allocating dma addresses * @wq: WQ to allocate pages for * @max_pages: maximum pages allowed * * Return 0 - Success, negative - Failure **/ static int alloc_wq_pages(struct hinic_wq *wq, struct hinic_hwif *hwif, int max_pages) { … } /** * hinic_wq_allocate - Allocate the WQ resources from the WQS * @wqs: WQ set from which to allocate the WQ resources * @wq: WQ to allocate resources for it from the WQ set * @wqebb_size: Work Queue Block Byte Size * @wq_page_size: the page size in the Work Queue * @q_depth: number of wqebbs in WQ * @max_wqe_size: maximum WQE size that will be used in the WQ * * Return 0 - Success, negative - Failure **/ int hinic_wq_allocate(struct hinic_wqs *wqs, struct hinic_wq *wq, u16 wqebb_size, u32 wq_page_size, u16 q_depth, u16 max_wqe_size) { … } /** * hinic_wq_free - Free the WQ resources to the WQS * @wqs: WQ set to free the WQ resources to it * @wq: WQ to free its resources to the WQ set resources **/ void hinic_wq_free(struct hinic_wqs *wqs, struct hinic_wq *wq) { … } /** * hinic_wqs_cmdq_alloc - Allocate wqs for cmdqs * @cmdq_pages: will hold the pages of the cmdq * @wq: returned wqs * @hwif: HW interface * @cmdq_blocks: number of cmdq blocks/wq to allocate * @wqebb_size: Work Queue Block Byte Size * @wq_page_size: the page size in the Work Queue * @q_depth: number of wqebbs in WQ * @max_wqe_size: maximum WQE size that will be used in the WQ * * Return 0 - Success, negative - Failure **/ int hinic_wqs_cmdq_alloc(struct hinic_cmdq_pages *cmdq_pages, struct hinic_wq *wq, struct hinic_hwif *hwif, int cmdq_blocks, u16 wqebb_size, u32 wq_page_size, u16 q_depth, u16 max_wqe_size) { … } /** * hinic_wqs_cmdq_free - Free wqs from cmdqs * @cmdq_pages: hold the pages of the cmdq * @wq: wqs to free * @cmdq_blocks: number of wqs to free **/ void hinic_wqs_cmdq_free(struct hinic_cmdq_pages *cmdq_pages, struct hinic_wq *wq, int cmdq_blocks) { … } static void copy_wqe_to_shadow(struct hinic_wq *wq, void *shadow_addr, int num_wqebbs, u16 idx) { … } static void copy_wqe_from_shadow(struct hinic_wq *wq, void *shadow_addr, int num_wqebbs, u16 idx) { … } /** * hinic_get_wqe - get wqe ptr in the current pi and update the pi * @wq: wq to get wqe from * @wqe_size: wqe size * @prod_idx: returned pi * * Return wqe pointer **/ struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size, u16 *prod_idx) { … } /** * hinic_return_wqe - return the wqe when transmit failed * @wq: wq to return wqe * @wqe_size: wqe size **/ void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size) { … } /** * hinic_put_wqe - return the wqe place to use for a new wqe * @wq: wq to return wqe * @wqe_size: wqe size **/ void hinic_put_wqe(struct hinic_wq *wq, unsigned int wqe_size) { … } /** * hinic_read_wqe - read wqe ptr in the current ci * @wq: wq to get read from * @wqe_size: wqe size * @cons_idx: returned ci * * Return wqe pointer **/ struct hinic_hw_wqe *hinic_read_wqe(struct hinic_wq *wq, unsigned int wqe_size, u16 *cons_idx) { … } /** * hinic_read_wqe_direct - read wqe directly from ci position * @wq: wq * @cons_idx: ci position * * Return wqe **/ struct hinic_hw_wqe *hinic_read_wqe_direct(struct hinic_wq *wq, u16 cons_idx) { … } /** * wqe_shadow - check if a wqe is shadow * @wq: wq of the wqe * @wqe: the wqe for shadow checking * * Return true - shadow, false - Not shadow **/ static inline bool wqe_shadow(struct hinic_wq *wq, struct hinic_hw_wqe *wqe) { … } /** * hinic_write_wqe - write the wqe to the wq * @wq: wq to write wqe to * @wqe: wqe to write * @wqe_size: wqe size **/ void hinic_write_wqe(struct hinic_wq *wq, struct hinic_hw_wqe *wqe, unsigned int wqe_size) { … }