162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright (c) 2021, Microsoft Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/pci.h> 662306a36Sopenharmony_ci#include <linux/utsname.h> 762306a36Sopenharmony_ci#include <linux/version.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <net/mana/mana.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic u32 mana_gd_r32(struct gdma_context *g, u64 offset) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci return readl(g->bar0_va + offset); 1462306a36Sopenharmony_ci} 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic u64 mana_gd_r64(struct gdma_context *g, u64 offset) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci return readq(g->bar0_va + offset); 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void mana_gd_init_pf_regs(struct pci_dev *pdev) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 2462306a36Sopenharmony_ci void __iomem *sriov_base_va; 2562306a36Sopenharmony_ci u64 sriov_base_off; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci gc->db_page_size = mana_gd_r32(gc, GDMA_PF_REG_DB_PAGE_SIZE) & 0xFFFF; 2862306a36Sopenharmony_ci gc->db_page_base = gc->bar0_va + 2962306a36Sopenharmony_ci mana_gd_r64(gc, GDMA_PF_REG_DB_PAGE_OFF); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci sriov_base_off = mana_gd_r64(gc, GDMA_SRIOV_REG_CFG_BASE_OFF); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci sriov_base_va = gc->bar0_va + sriov_base_off; 3462306a36Sopenharmony_ci gc->shm_base = sriov_base_va + 3562306a36Sopenharmony_ci mana_gd_r64(gc, sriov_base_off + GDMA_PF_REG_SHM_OFF); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void mana_gd_init_vf_regs(struct pci_dev *pdev) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci gc->db_page_size = mana_gd_r32(gc, GDMA_REG_DB_PAGE_SIZE) & 0xFFFF; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci gc->db_page_base = gc->bar0_va + 4562306a36Sopenharmony_ci mana_gd_r64(gc, GDMA_REG_DB_PAGE_OFFSET); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci gc->phys_db_page_base = gc->bar0_pa + 4862306a36Sopenharmony_ci mana_gd_r64(gc, GDMA_REG_DB_PAGE_OFFSET); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci gc->shm_base = gc->bar0_va + mana_gd_r64(gc, GDMA_REG_SHM_OFFSET); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void mana_gd_init_registers(struct pci_dev *pdev) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (gc->is_pf) 5862306a36Sopenharmony_ci mana_gd_init_pf_regs(pdev); 5962306a36Sopenharmony_ci else 6062306a36Sopenharmony_ci mana_gd_init_vf_regs(pdev); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int mana_gd_query_max_resources(struct pci_dev *pdev) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 6662306a36Sopenharmony_ci struct gdma_query_max_resources_resp resp = {}; 6762306a36Sopenharmony_ci struct gdma_general_req req = {}; 6862306a36Sopenharmony_ci int err; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_QUERY_MAX_RESOURCES, 7162306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 7462306a36Sopenharmony_ci if (err || resp.hdr.status) { 7562306a36Sopenharmony_ci dev_err(gc->dev, "Failed to query resource info: %d, 0x%x\n", 7662306a36Sopenharmony_ci err, resp.hdr.status); 7762306a36Sopenharmony_ci return err ? err : -EPROTO; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (gc->num_msix_usable > resp.max_msix) 8162306a36Sopenharmony_ci gc->num_msix_usable = resp.max_msix; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (gc->num_msix_usable <= 1) 8462306a36Sopenharmony_ci return -ENOSPC; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci gc->max_num_queues = num_online_cpus(); 8762306a36Sopenharmony_ci if (gc->max_num_queues > MANA_MAX_NUM_QUEUES) 8862306a36Sopenharmony_ci gc->max_num_queues = MANA_MAX_NUM_QUEUES; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (gc->max_num_queues > resp.max_eq) 9162306a36Sopenharmony_ci gc->max_num_queues = resp.max_eq; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (gc->max_num_queues > resp.max_cq) 9462306a36Sopenharmony_ci gc->max_num_queues = resp.max_cq; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (gc->max_num_queues > resp.max_sq) 9762306a36Sopenharmony_ci gc->max_num_queues = resp.max_sq; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (gc->max_num_queues > resp.max_rq) 10062306a36Sopenharmony_ci gc->max_num_queues = resp.max_rq; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* The Hardware Channel (HWC) used 1 MSI-X */ 10362306a36Sopenharmony_ci if (gc->max_num_queues > gc->num_msix_usable - 1) 10462306a36Sopenharmony_ci gc->max_num_queues = gc->num_msix_usable - 1; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int mana_gd_query_hwc_timeout(struct pci_dev *pdev, u32 *timeout_val) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 11262306a36Sopenharmony_ci struct gdma_query_hwc_timeout_resp resp = {}; 11362306a36Sopenharmony_ci struct gdma_query_hwc_timeout_req req = {}; 11462306a36Sopenharmony_ci int err; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_QUERY_HWC_TIMEOUT, 11762306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 11862306a36Sopenharmony_ci req.timeout_ms = *timeout_val; 11962306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 12062306a36Sopenharmony_ci if (err || resp.hdr.status) 12162306a36Sopenharmony_ci return err ? err : -EPROTO; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci *timeout_val = resp.timeout_ms; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int mana_gd_detect_devices(struct pci_dev *pdev) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 13162306a36Sopenharmony_ci struct gdma_list_devices_resp resp = {}; 13262306a36Sopenharmony_ci struct gdma_general_req req = {}; 13362306a36Sopenharmony_ci struct gdma_dev_id dev; 13462306a36Sopenharmony_ci u32 i, max_num_devs; 13562306a36Sopenharmony_ci u16 dev_type; 13662306a36Sopenharmony_ci int err; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_LIST_DEVICES, sizeof(req), 13962306a36Sopenharmony_ci sizeof(resp)); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 14262306a36Sopenharmony_ci if (err || resp.hdr.status) { 14362306a36Sopenharmony_ci dev_err(gc->dev, "Failed to detect devices: %d, 0x%x\n", err, 14462306a36Sopenharmony_ci resp.hdr.status); 14562306a36Sopenharmony_ci return err ? err : -EPROTO; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci max_num_devs = min_t(u32, MAX_NUM_GDMA_DEVICES, resp.num_of_devs); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci for (i = 0; i < max_num_devs; i++) { 15162306a36Sopenharmony_ci dev = resp.devs[i]; 15262306a36Sopenharmony_ci dev_type = dev.type; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* HWC is already detected in mana_hwc_create_channel(). */ 15562306a36Sopenharmony_ci if (dev_type == GDMA_DEVICE_HWC) 15662306a36Sopenharmony_ci continue; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (dev_type == GDMA_DEVICE_MANA) { 15962306a36Sopenharmony_ci gc->mana.gdma_context = gc; 16062306a36Sopenharmony_ci gc->mana.dev_id = dev; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return gc->mana.dev_id.type == 0 ? -ENODEV : 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ciint mana_gd_send_request(struct gdma_context *gc, u32 req_len, const void *req, 16862306a36Sopenharmony_ci u32 resp_len, void *resp) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct hw_channel_context *hwc = gc->hwc.driver_data; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return mana_hwc_send_request(hwc, req_len, req, resp_len, resp); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ciEXPORT_SYMBOL_NS(mana_gd_send_request, NET_MANA); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint mana_gd_alloc_memory(struct gdma_context *gc, unsigned int length, 17762306a36Sopenharmony_ci struct gdma_mem_info *gmi) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci dma_addr_t dma_handle; 18062306a36Sopenharmony_ci void *buf; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (length < PAGE_SIZE || !is_power_of_2(length)) 18362306a36Sopenharmony_ci return -EINVAL; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci gmi->dev = gc->dev; 18662306a36Sopenharmony_ci buf = dma_alloc_coherent(gmi->dev, length, &dma_handle, GFP_KERNEL); 18762306a36Sopenharmony_ci if (!buf) 18862306a36Sopenharmony_ci return -ENOMEM; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci gmi->dma_handle = dma_handle; 19162306a36Sopenharmony_ci gmi->virt_addr = buf; 19262306a36Sopenharmony_ci gmi->length = length; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid mana_gd_free_memory(struct gdma_mem_info *gmi) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci dma_free_coherent(gmi->dev, gmi->length, gmi->virt_addr, 20062306a36Sopenharmony_ci gmi->dma_handle); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int mana_gd_create_hw_eq(struct gdma_context *gc, 20462306a36Sopenharmony_ci struct gdma_queue *queue) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct gdma_create_queue_resp resp = {}; 20762306a36Sopenharmony_ci struct gdma_create_queue_req req = {}; 20862306a36Sopenharmony_ci int err; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (queue->type != GDMA_EQ) 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_CREATE_QUEUE, 21462306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci req.hdr.dev_id = queue->gdma_dev->dev_id; 21762306a36Sopenharmony_ci req.type = queue->type; 21862306a36Sopenharmony_ci req.pdid = queue->gdma_dev->pdid; 21962306a36Sopenharmony_ci req.doolbell_id = queue->gdma_dev->doorbell; 22062306a36Sopenharmony_ci req.gdma_region = queue->mem_info.dma_region_handle; 22162306a36Sopenharmony_ci req.queue_size = queue->queue_size; 22262306a36Sopenharmony_ci req.log2_throttle_limit = queue->eq.log2_throttle_limit; 22362306a36Sopenharmony_ci req.eq_pci_msix_index = queue->eq.msix_index; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 22662306a36Sopenharmony_ci if (err || resp.hdr.status) { 22762306a36Sopenharmony_ci dev_err(gc->dev, "Failed to create queue: %d, 0x%x\n", err, 22862306a36Sopenharmony_ci resp.hdr.status); 22962306a36Sopenharmony_ci return err ? err : -EPROTO; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci queue->id = resp.queue_index; 23362306a36Sopenharmony_ci queue->eq.disable_needed = true; 23462306a36Sopenharmony_ci queue->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION; 23562306a36Sopenharmony_ci return 0; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int mana_gd_disable_queue(struct gdma_queue *queue) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct gdma_context *gc = queue->gdma_dev->gdma_context; 24162306a36Sopenharmony_ci struct gdma_disable_queue_req req = {}; 24262306a36Sopenharmony_ci struct gdma_general_resp resp = {}; 24362306a36Sopenharmony_ci int err; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci WARN_ON(queue->type != GDMA_EQ); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_DISABLE_QUEUE, 24862306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci req.hdr.dev_id = queue->gdma_dev->dev_id; 25162306a36Sopenharmony_ci req.type = queue->type; 25262306a36Sopenharmony_ci req.queue_index = queue->id; 25362306a36Sopenharmony_ci req.alloc_res_id_on_creation = 1; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 25662306a36Sopenharmony_ci if (err || resp.hdr.status) { 25762306a36Sopenharmony_ci dev_err(gc->dev, "Failed to disable queue: %d, 0x%x\n", err, 25862306a36Sopenharmony_ci resp.hdr.status); 25962306a36Sopenharmony_ci return err ? err : -EPROTO; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#define DOORBELL_OFFSET_SQ 0x0 26662306a36Sopenharmony_ci#define DOORBELL_OFFSET_RQ 0x400 26762306a36Sopenharmony_ci#define DOORBELL_OFFSET_CQ 0x800 26862306a36Sopenharmony_ci#define DOORBELL_OFFSET_EQ 0xFF8 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index, 27162306a36Sopenharmony_ci enum gdma_queue_type q_type, u32 qid, 27262306a36Sopenharmony_ci u32 tail_ptr, u8 num_req) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci void __iomem *addr = gc->db_page_base + gc->db_page_size * db_index; 27562306a36Sopenharmony_ci union gdma_doorbell_entry e = {}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci switch (q_type) { 27862306a36Sopenharmony_ci case GDMA_EQ: 27962306a36Sopenharmony_ci e.eq.id = qid; 28062306a36Sopenharmony_ci e.eq.tail_ptr = tail_ptr; 28162306a36Sopenharmony_ci e.eq.arm = num_req; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci addr += DOORBELL_OFFSET_EQ; 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci case GDMA_CQ: 28762306a36Sopenharmony_ci e.cq.id = qid; 28862306a36Sopenharmony_ci e.cq.tail_ptr = tail_ptr; 28962306a36Sopenharmony_ci e.cq.arm = num_req; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci addr += DOORBELL_OFFSET_CQ; 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci case GDMA_RQ: 29562306a36Sopenharmony_ci e.rq.id = qid; 29662306a36Sopenharmony_ci e.rq.tail_ptr = tail_ptr; 29762306a36Sopenharmony_ci e.rq.wqe_cnt = num_req; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci addr += DOORBELL_OFFSET_RQ; 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci case GDMA_SQ: 30362306a36Sopenharmony_ci e.sq.id = qid; 30462306a36Sopenharmony_ci e.sq.tail_ptr = tail_ptr; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci addr += DOORBELL_OFFSET_SQ; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci default: 31062306a36Sopenharmony_ci WARN_ON(1); 31162306a36Sopenharmony_ci return; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Ensure all writes are done before ring doorbell */ 31562306a36Sopenharmony_ci wmb(); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci writeq(e.as_uint64, addr); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_civoid mana_gd_wq_ring_doorbell(struct gdma_context *gc, struct gdma_queue *queue) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci /* Hardware Spec specifies that software client should set 0 for 32362306a36Sopenharmony_ci * wqe_cnt for Receive Queues. This value is not used in Send Queues. 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci mana_gd_ring_doorbell(gc, queue->gdma_dev->doorbell, queue->type, 32662306a36Sopenharmony_ci queue->id, queue->head * GDMA_WQE_BU_SIZE, 0); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_civoid mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct gdma_context *gc = cq->gdma_dev->gdma_context; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci u32 num_cqe = cq->queue_size / GDMA_CQE_SIZE; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci u32 head = cq->head % (num_cqe << GDMA_CQE_OWNER_BITS); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci mana_gd_ring_doorbell(gc, cq->gdma_dev->doorbell, cq->type, cq->id, 33862306a36Sopenharmony_ci head, arm_bit); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void mana_gd_process_eqe(struct gdma_queue *eq) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci u32 head = eq->head % (eq->queue_size / GDMA_EQE_SIZE); 34462306a36Sopenharmony_ci struct gdma_context *gc = eq->gdma_dev->gdma_context; 34562306a36Sopenharmony_ci struct gdma_eqe *eq_eqe_ptr = eq->queue_mem_ptr; 34662306a36Sopenharmony_ci union gdma_eqe_info eqe_info; 34762306a36Sopenharmony_ci enum gdma_eqe_type type; 34862306a36Sopenharmony_ci struct gdma_event event; 34962306a36Sopenharmony_ci struct gdma_queue *cq; 35062306a36Sopenharmony_ci struct gdma_eqe *eqe; 35162306a36Sopenharmony_ci u32 cq_id; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci eqe = &eq_eqe_ptr[head]; 35462306a36Sopenharmony_ci eqe_info.as_uint32 = eqe->eqe_info; 35562306a36Sopenharmony_ci type = eqe_info.type; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci switch (type) { 35862306a36Sopenharmony_ci case GDMA_EQE_COMPLETION: 35962306a36Sopenharmony_ci cq_id = eqe->details[0] & 0xFFFFFF; 36062306a36Sopenharmony_ci if (WARN_ON_ONCE(cq_id >= gc->max_num_cqs)) 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci cq = gc->cq_table[cq_id]; 36462306a36Sopenharmony_ci if (WARN_ON_ONCE(!cq || cq->type != GDMA_CQ || cq->id != cq_id)) 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (cq->cq.callback) 36862306a36Sopenharmony_ci cq->cq.callback(cq->cq.context, cq); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci case GDMA_EQE_TEST_EVENT: 37362306a36Sopenharmony_ci gc->test_event_eq_id = eq->id; 37462306a36Sopenharmony_ci complete(&gc->eq_test_event); 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci case GDMA_EQE_HWC_INIT_EQ_ID_DB: 37862306a36Sopenharmony_ci case GDMA_EQE_HWC_INIT_DATA: 37962306a36Sopenharmony_ci case GDMA_EQE_HWC_INIT_DONE: 38062306a36Sopenharmony_ci if (!eq->eq.callback) 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci event.type = type; 38462306a36Sopenharmony_ci memcpy(&event.details, &eqe->details, GDMA_EVENT_DATA_SIZE); 38562306a36Sopenharmony_ci eq->eq.callback(eq->eq.context, eq, &event); 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci default: 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void mana_gd_process_eq_events(void *arg) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci u32 owner_bits, new_bits, old_bits; 39662306a36Sopenharmony_ci union gdma_eqe_info eqe_info; 39762306a36Sopenharmony_ci struct gdma_eqe *eq_eqe_ptr; 39862306a36Sopenharmony_ci struct gdma_queue *eq = arg; 39962306a36Sopenharmony_ci struct gdma_context *gc; 40062306a36Sopenharmony_ci struct gdma_eqe *eqe; 40162306a36Sopenharmony_ci u32 head, num_eqe; 40262306a36Sopenharmony_ci int i; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci gc = eq->gdma_dev->gdma_context; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci num_eqe = eq->queue_size / GDMA_EQE_SIZE; 40762306a36Sopenharmony_ci eq_eqe_ptr = eq->queue_mem_ptr; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Process up to 5 EQEs at a time, and update the HW head. */ 41062306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 41162306a36Sopenharmony_ci eqe = &eq_eqe_ptr[eq->head % num_eqe]; 41262306a36Sopenharmony_ci eqe_info.as_uint32 = eqe->eqe_info; 41362306a36Sopenharmony_ci owner_bits = eqe_info.owner_bits; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci old_bits = (eq->head / num_eqe - 1) & GDMA_EQE_OWNER_MASK; 41662306a36Sopenharmony_ci /* No more entries */ 41762306a36Sopenharmony_ci if (owner_bits == old_bits) 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci new_bits = (eq->head / num_eqe) & GDMA_EQE_OWNER_MASK; 42162306a36Sopenharmony_ci if (owner_bits != new_bits) { 42262306a36Sopenharmony_ci dev_err(gc->dev, "EQ %d: overflow detected\n", eq->id); 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* Per GDMA spec, rmb is necessary after checking owner_bits, before 42762306a36Sopenharmony_ci * reading eqe. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci rmb(); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci mana_gd_process_eqe(eq); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci eq->head++; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci head = eq->head % (num_eqe << GDMA_EQE_OWNER_BITS); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci mana_gd_ring_doorbell(gc, eq->gdma_dev->doorbell, eq->type, eq->id, 43962306a36Sopenharmony_ci head, SET_ARM_BIT); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int mana_gd_register_irq(struct gdma_queue *queue, 44362306a36Sopenharmony_ci const struct gdma_queue_spec *spec) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct gdma_dev *gd = queue->gdma_dev; 44662306a36Sopenharmony_ci struct gdma_irq_context *gic; 44762306a36Sopenharmony_ci struct gdma_context *gc; 44862306a36Sopenharmony_ci struct gdma_resource *r; 44962306a36Sopenharmony_ci unsigned int msi_index; 45062306a36Sopenharmony_ci unsigned long flags; 45162306a36Sopenharmony_ci struct device *dev; 45262306a36Sopenharmony_ci int err = 0; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci gc = gd->gdma_context; 45562306a36Sopenharmony_ci r = &gc->msix_resource; 45662306a36Sopenharmony_ci dev = gc->dev; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci spin_lock_irqsave(&r->lock, flags); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci msi_index = find_first_zero_bit(r->map, r->size); 46162306a36Sopenharmony_ci if (msi_index >= r->size || msi_index >= gc->num_msix_usable) { 46262306a36Sopenharmony_ci err = -ENOSPC; 46362306a36Sopenharmony_ci } else { 46462306a36Sopenharmony_ci bitmap_set(r->map, msi_index, 1); 46562306a36Sopenharmony_ci queue->eq.msix_index = msi_index; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci spin_unlock_irqrestore(&r->lock, flags); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (err) { 47162306a36Sopenharmony_ci dev_err(dev, "Register IRQ err:%d, msi:%u rsize:%u, nMSI:%u", 47262306a36Sopenharmony_ci err, msi_index, r->size, gc->num_msix_usable); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return err; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci gic = &gc->irq_contexts[msi_index]; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci WARN_ON(gic->handler || gic->arg); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci gic->arg = queue; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci gic->handler = mana_gd_process_eq_events; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic void mana_gd_deregiser_irq(struct gdma_queue *queue) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct gdma_dev *gd = queue->gdma_dev; 49162306a36Sopenharmony_ci struct gdma_irq_context *gic; 49262306a36Sopenharmony_ci struct gdma_context *gc; 49362306a36Sopenharmony_ci struct gdma_resource *r; 49462306a36Sopenharmony_ci unsigned int msix_index; 49562306a36Sopenharmony_ci unsigned long flags; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci gc = gd->gdma_context; 49862306a36Sopenharmony_ci r = &gc->msix_resource; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* At most num_online_cpus() + 1 interrupts are used. */ 50162306a36Sopenharmony_ci msix_index = queue->eq.msix_index; 50262306a36Sopenharmony_ci if (WARN_ON(msix_index >= gc->num_msix_usable)) 50362306a36Sopenharmony_ci return; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci gic = &gc->irq_contexts[msix_index]; 50662306a36Sopenharmony_ci gic->handler = NULL; 50762306a36Sopenharmony_ci gic->arg = NULL; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci spin_lock_irqsave(&r->lock, flags); 51062306a36Sopenharmony_ci bitmap_clear(r->map, msix_index, 1); 51162306a36Sopenharmony_ci spin_unlock_irqrestore(&r->lock, flags); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci queue->eq.msix_index = INVALID_PCI_MSIX_INDEX; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciint mana_gd_test_eq(struct gdma_context *gc, struct gdma_queue *eq) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct gdma_generate_test_event_req req = {}; 51962306a36Sopenharmony_ci struct gdma_general_resp resp = {}; 52062306a36Sopenharmony_ci struct device *dev = gc->dev; 52162306a36Sopenharmony_ci int err; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci mutex_lock(&gc->eq_test_event_mutex); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci init_completion(&gc->eq_test_event); 52662306a36Sopenharmony_ci gc->test_event_eq_id = INVALID_QUEUE_ID; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_GENERATE_TEST_EQE, 52962306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci req.hdr.dev_id = eq->gdma_dev->dev_id; 53262306a36Sopenharmony_ci req.queue_index = eq->id; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 53562306a36Sopenharmony_ci if (err) { 53662306a36Sopenharmony_ci dev_err(dev, "test_eq failed: %d\n", err); 53762306a36Sopenharmony_ci goto out; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci err = -EPROTO; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (resp.hdr.status) { 54362306a36Sopenharmony_ci dev_err(dev, "test_eq failed: 0x%x\n", resp.hdr.status); 54462306a36Sopenharmony_ci goto out; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&gc->eq_test_event, 30 * HZ)) { 54862306a36Sopenharmony_ci dev_err(dev, "test_eq timed out on queue %d\n", eq->id); 54962306a36Sopenharmony_ci goto out; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (eq->id != gc->test_event_eq_id) { 55362306a36Sopenharmony_ci dev_err(dev, "test_eq got an event on wrong queue %d (%d)\n", 55462306a36Sopenharmony_ci gc->test_event_eq_id, eq->id); 55562306a36Sopenharmony_ci goto out; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci err = 0; 55962306a36Sopenharmony_ciout: 56062306a36Sopenharmony_ci mutex_unlock(&gc->eq_test_event_mutex); 56162306a36Sopenharmony_ci return err; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void mana_gd_destroy_eq(struct gdma_context *gc, bool flush_evenets, 56562306a36Sopenharmony_ci struct gdma_queue *queue) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci int err; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (flush_evenets) { 57062306a36Sopenharmony_ci err = mana_gd_test_eq(gc, queue); 57162306a36Sopenharmony_ci if (err) 57262306a36Sopenharmony_ci dev_warn(gc->dev, "Failed to flush EQ: %d\n", err); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci mana_gd_deregiser_irq(queue); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (queue->eq.disable_needed) 57862306a36Sopenharmony_ci mana_gd_disable_queue(queue); 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic int mana_gd_create_eq(struct gdma_dev *gd, 58262306a36Sopenharmony_ci const struct gdma_queue_spec *spec, 58362306a36Sopenharmony_ci bool create_hwq, struct gdma_queue *queue) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 58662306a36Sopenharmony_ci struct device *dev = gc->dev; 58762306a36Sopenharmony_ci u32 log2_num_entries; 58862306a36Sopenharmony_ci int err; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci queue->eq.msix_index = INVALID_PCI_MSIX_INDEX; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci log2_num_entries = ilog2(queue->queue_size / GDMA_EQE_SIZE); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (spec->eq.log2_throttle_limit > log2_num_entries) { 59562306a36Sopenharmony_ci dev_err(dev, "EQ throttling limit (%lu) > maximum EQE (%u)\n", 59662306a36Sopenharmony_ci spec->eq.log2_throttle_limit, log2_num_entries); 59762306a36Sopenharmony_ci return -EINVAL; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci err = mana_gd_register_irq(queue, spec); 60162306a36Sopenharmony_ci if (err) { 60262306a36Sopenharmony_ci dev_err(dev, "Failed to register irq: %d\n", err); 60362306a36Sopenharmony_ci return err; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci queue->eq.callback = spec->eq.callback; 60762306a36Sopenharmony_ci queue->eq.context = spec->eq.context; 60862306a36Sopenharmony_ci queue->head |= INITIALIZED_OWNER_BIT(log2_num_entries); 60962306a36Sopenharmony_ci queue->eq.log2_throttle_limit = spec->eq.log2_throttle_limit ?: 1; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (create_hwq) { 61262306a36Sopenharmony_ci err = mana_gd_create_hw_eq(gc, queue); 61362306a36Sopenharmony_ci if (err) 61462306a36Sopenharmony_ci goto out; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci err = mana_gd_test_eq(gc, queue); 61762306a36Sopenharmony_ci if (err) 61862306a36Sopenharmony_ci goto out; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci return 0; 62262306a36Sopenharmony_ciout: 62362306a36Sopenharmony_ci dev_err(dev, "Failed to create EQ: %d\n", err); 62462306a36Sopenharmony_ci mana_gd_destroy_eq(gc, false, queue); 62562306a36Sopenharmony_ci return err; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic void mana_gd_create_cq(const struct gdma_queue_spec *spec, 62962306a36Sopenharmony_ci struct gdma_queue *queue) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci u32 log2_num_entries = ilog2(spec->queue_size / GDMA_CQE_SIZE); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci queue->head |= INITIALIZED_OWNER_BIT(log2_num_entries); 63462306a36Sopenharmony_ci queue->cq.parent = spec->cq.parent_eq; 63562306a36Sopenharmony_ci queue->cq.context = spec->cq.context; 63662306a36Sopenharmony_ci queue->cq.callback = spec->cq.callback; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic void mana_gd_destroy_cq(struct gdma_context *gc, 64062306a36Sopenharmony_ci struct gdma_queue *queue) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci u32 id = queue->id; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (id >= gc->max_num_cqs) 64562306a36Sopenharmony_ci return; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (!gc->cq_table[id]) 64862306a36Sopenharmony_ci return; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci gc->cq_table[id] = NULL; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ciint mana_gd_create_hwc_queue(struct gdma_dev *gd, 65462306a36Sopenharmony_ci const struct gdma_queue_spec *spec, 65562306a36Sopenharmony_ci struct gdma_queue **queue_ptr) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 65862306a36Sopenharmony_ci struct gdma_mem_info *gmi; 65962306a36Sopenharmony_ci struct gdma_queue *queue; 66062306a36Sopenharmony_ci int err; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci queue = kzalloc(sizeof(*queue), GFP_KERNEL); 66362306a36Sopenharmony_ci if (!queue) 66462306a36Sopenharmony_ci return -ENOMEM; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci gmi = &queue->mem_info; 66762306a36Sopenharmony_ci err = mana_gd_alloc_memory(gc, spec->queue_size, gmi); 66862306a36Sopenharmony_ci if (err) 66962306a36Sopenharmony_ci goto free_q; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci queue->head = 0; 67262306a36Sopenharmony_ci queue->tail = 0; 67362306a36Sopenharmony_ci queue->queue_mem_ptr = gmi->virt_addr; 67462306a36Sopenharmony_ci queue->queue_size = spec->queue_size; 67562306a36Sopenharmony_ci queue->monitor_avl_buf = spec->monitor_avl_buf; 67662306a36Sopenharmony_ci queue->type = spec->type; 67762306a36Sopenharmony_ci queue->gdma_dev = gd; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (spec->type == GDMA_EQ) 68062306a36Sopenharmony_ci err = mana_gd_create_eq(gd, spec, false, queue); 68162306a36Sopenharmony_ci else if (spec->type == GDMA_CQ) 68262306a36Sopenharmony_ci mana_gd_create_cq(spec, queue); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (err) 68562306a36Sopenharmony_ci goto out; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci *queue_ptr = queue; 68862306a36Sopenharmony_ci return 0; 68962306a36Sopenharmony_ciout: 69062306a36Sopenharmony_ci mana_gd_free_memory(gmi); 69162306a36Sopenharmony_cifree_q: 69262306a36Sopenharmony_ci kfree(queue); 69362306a36Sopenharmony_ci return err; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ciint mana_gd_destroy_dma_region(struct gdma_context *gc, u64 dma_region_handle) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct gdma_destroy_dma_region_req req = {}; 69962306a36Sopenharmony_ci struct gdma_general_resp resp = {}; 70062306a36Sopenharmony_ci int err; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (dma_region_handle == GDMA_INVALID_DMA_REGION) 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_DMA_REGION, sizeof(req), 70662306a36Sopenharmony_ci sizeof(resp)); 70762306a36Sopenharmony_ci req.dma_region_handle = dma_region_handle; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 71062306a36Sopenharmony_ci if (err || resp.hdr.status) { 71162306a36Sopenharmony_ci dev_err(gc->dev, "Failed to destroy DMA region: %d, 0x%x\n", 71262306a36Sopenharmony_ci err, resp.hdr.status); 71362306a36Sopenharmony_ci return -EPROTO; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return 0; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ciEXPORT_SYMBOL_NS(mana_gd_destroy_dma_region, NET_MANA); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int mana_gd_create_dma_region(struct gdma_dev *gd, 72162306a36Sopenharmony_ci struct gdma_mem_info *gmi) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci unsigned int num_page = gmi->length / PAGE_SIZE; 72462306a36Sopenharmony_ci struct gdma_create_dma_region_req *req = NULL; 72562306a36Sopenharmony_ci struct gdma_create_dma_region_resp resp = {}; 72662306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 72762306a36Sopenharmony_ci struct hw_channel_context *hwc; 72862306a36Sopenharmony_ci u32 length = gmi->length; 72962306a36Sopenharmony_ci size_t req_msg_size; 73062306a36Sopenharmony_ci int err; 73162306a36Sopenharmony_ci int i; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (length < PAGE_SIZE || !is_power_of_2(length)) 73462306a36Sopenharmony_ci return -EINVAL; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (offset_in_page(gmi->virt_addr) != 0) 73762306a36Sopenharmony_ci return -EINVAL; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci hwc = gc->hwc.driver_data; 74062306a36Sopenharmony_ci req_msg_size = struct_size(req, page_addr_list, num_page); 74162306a36Sopenharmony_ci if (req_msg_size > hwc->max_req_msg_size) 74262306a36Sopenharmony_ci return -EINVAL; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci req = kzalloc(req_msg_size, GFP_KERNEL); 74562306a36Sopenharmony_ci if (!req) 74662306a36Sopenharmony_ci return -ENOMEM; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci mana_gd_init_req_hdr(&req->hdr, GDMA_CREATE_DMA_REGION, 74962306a36Sopenharmony_ci req_msg_size, sizeof(resp)); 75062306a36Sopenharmony_ci req->length = length; 75162306a36Sopenharmony_ci req->offset_in_page = 0; 75262306a36Sopenharmony_ci req->gdma_page_type = GDMA_PAGE_TYPE_4K; 75362306a36Sopenharmony_ci req->page_count = num_page; 75462306a36Sopenharmony_ci req->page_addr_list_len = num_page; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci for (i = 0; i < num_page; i++) 75762306a36Sopenharmony_ci req->page_addr_list[i] = gmi->dma_handle + i * PAGE_SIZE; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci err = mana_gd_send_request(gc, req_msg_size, req, sizeof(resp), &resp); 76062306a36Sopenharmony_ci if (err) 76162306a36Sopenharmony_ci goto out; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (resp.hdr.status || 76462306a36Sopenharmony_ci resp.dma_region_handle == GDMA_INVALID_DMA_REGION) { 76562306a36Sopenharmony_ci dev_err(gc->dev, "Failed to create DMA region: 0x%x\n", 76662306a36Sopenharmony_ci resp.hdr.status); 76762306a36Sopenharmony_ci err = -EPROTO; 76862306a36Sopenharmony_ci goto out; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci gmi->dma_region_handle = resp.dma_region_handle; 77262306a36Sopenharmony_ciout: 77362306a36Sopenharmony_ci kfree(req); 77462306a36Sopenharmony_ci return err; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ciint mana_gd_create_mana_eq(struct gdma_dev *gd, 77862306a36Sopenharmony_ci const struct gdma_queue_spec *spec, 77962306a36Sopenharmony_ci struct gdma_queue **queue_ptr) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 78262306a36Sopenharmony_ci struct gdma_mem_info *gmi; 78362306a36Sopenharmony_ci struct gdma_queue *queue; 78462306a36Sopenharmony_ci int err; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (spec->type != GDMA_EQ) 78762306a36Sopenharmony_ci return -EINVAL; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci queue = kzalloc(sizeof(*queue), GFP_KERNEL); 79062306a36Sopenharmony_ci if (!queue) 79162306a36Sopenharmony_ci return -ENOMEM; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci gmi = &queue->mem_info; 79462306a36Sopenharmony_ci err = mana_gd_alloc_memory(gc, spec->queue_size, gmi); 79562306a36Sopenharmony_ci if (err) 79662306a36Sopenharmony_ci goto free_q; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci err = mana_gd_create_dma_region(gd, gmi); 79962306a36Sopenharmony_ci if (err) 80062306a36Sopenharmony_ci goto out; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci queue->head = 0; 80362306a36Sopenharmony_ci queue->tail = 0; 80462306a36Sopenharmony_ci queue->queue_mem_ptr = gmi->virt_addr; 80562306a36Sopenharmony_ci queue->queue_size = spec->queue_size; 80662306a36Sopenharmony_ci queue->monitor_avl_buf = spec->monitor_avl_buf; 80762306a36Sopenharmony_ci queue->type = spec->type; 80862306a36Sopenharmony_ci queue->gdma_dev = gd; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci err = mana_gd_create_eq(gd, spec, true, queue); 81162306a36Sopenharmony_ci if (err) 81262306a36Sopenharmony_ci goto out; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci *queue_ptr = queue; 81562306a36Sopenharmony_ci return 0; 81662306a36Sopenharmony_ciout: 81762306a36Sopenharmony_ci mana_gd_free_memory(gmi); 81862306a36Sopenharmony_cifree_q: 81962306a36Sopenharmony_ci kfree(queue); 82062306a36Sopenharmony_ci return err; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ciint mana_gd_create_mana_wq_cq(struct gdma_dev *gd, 82462306a36Sopenharmony_ci const struct gdma_queue_spec *spec, 82562306a36Sopenharmony_ci struct gdma_queue **queue_ptr) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 82862306a36Sopenharmony_ci struct gdma_mem_info *gmi; 82962306a36Sopenharmony_ci struct gdma_queue *queue; 83062306a36Sopenharmony_ci int err; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (spec->type != GDMA_CQ && spec->type != GDMA_SQ && 83362306a36Sopenharmony_ci spec->type != GDMA_RQ) 83462306a36Sopenharmony_ci return -EINVAL; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci queue = kzalloc(sizeof(*queue), GFP_KERNEL); 83762306a36Sopenharmony_ci if (!queue) 83862306a36Sopenharmony_ci return -ENOMEM; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci gmi = &queue->mem_info; 84162306a36Sopenharmony_ci err = mana_gd_alloc_memory(gc, spec->queue_size, gmi); 84262306a36Sopenharmony_ci if (err) 84362306a36Sopenharmony_ci goto free_q; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci err = mana_gd_create_dma_region(gd, gmi); 84662306a36Sopenharmony_ci if (err) 84762306a36Sopenharmony_ci goto out; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci queue->head = 0; 85062306a36Sopenharmony_ci queue->tail = 0; 85162306a36Sopenharmony_ci queue->queue_mem_ptr = gmi->virt_addr; 85262306a36Sopenharmony_ci queue->queue_size = spec->queue_size; 85362306a36Sopenharmony_ci queue->monitor_avl_buf = spec->monitor_avl_buf; 85462306a36Sopenharmony_ci queue->type = spec->type; 85562306a36Sopenharmony_ci queue->gdma_dev = gd; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (spec->type == GDMA_CQ) 85862306a36Sopenharmony_ci mana_gd_create_cq(spec, queue); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci *queue_ptr = queue; 86162306a36Sopenharmony_ci return 0; 86262306a36Sopenharmony_ciout: 86362306a36Sopenharmony_ci mana_gd_free_memory(gmi); 86462306a36Sopenharmony_cifree_q: 86562306a36Sopenharmony_ci kfree(queue); 86662306a36Sopenharmony_ci return err; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_civoid mana_gd_destroy_queue(struct gdma_context *gc, struct gdma_queue *queue) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct gdma_mem_info *gmi = &queue->mem_info; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci switch (queue->type) { 87462306a36Sopenharmony_ci case GDMA_EQ: 87562306a36Sopenharmony_ci mana_gd_destroy_eq(gc, queue->eq.disable_needed, queue); 87662306a36Sopenharmony_ci break; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci case GDMA_CQ: 87962306a36Sopenharmony_ci mana_gd_destroy_cq(gc, queue); 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci case GDMA_RQ: 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci case GDMA_SQ: 88662306a36Sopenharmony_ci break; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci default: 88962306a36Sopenharmony_ci dev_err(gc->dev, "Can't destroy unknown queue: type=%d\n", 89062306a36Sopenharmony_ci queue->type); 89162306a36Sopenharmony_ci return; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci mana_gd_destroy_dma_region(gc, gmi->dma_region_handle); 89562306a36Sopenharmony_ci mana_gd_free_memory(gmi); 89662306a36Sopenharmony_ci kfree(queue); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ciint mana_gd_verify_vf_version(struct pci_dev *pdev) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 90262306a36Sopenharmony_ci struct gdma_verify_ver_resp resp = {}; 90362306a36Sopenharmony_ci struct gdma_verify_ver_req req = {}; 90462306a36Sopenharmony_ci struct hw_channel_context *hwc; 90562306a36Sopenharmony_ci int err; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci hwc = gc->hwc.driver_data; 90862306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_VERIFY_VF_DRIVER_VERSION, 90962306a36Sopenharmony_ci sizeof(req), sizeof(resp)); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci req.protocol_ver_min = GDMA_PROTOCOL_FIRST; 91262306a36Sopenharmony_ci req.protocol_ver_max = GDMA_PROTOCOL_LAST; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci req.gd_drv_cap_flags1 = GDMA_DRV_CAP_FLAGS1; 91562306a36Sopenharmony_ci req.gd_drv_cap_flags2 = GDMA_DRV_CAP_FLAGS2; 91662306a36Sopenharmony_ci req.gd_drv_cap_flags3 = GDMA_DRV_CAP_FLAGS3; 91762306a36Sopenharmony_ci req.gd_drv_cap_flags4 = GDMA_DRV_CAP_FLAGS4; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci req.drv_ver = 0; /* Unused*/ 92062306a36Sopenharmony_ci req.os_type = 0x10; /* Linux */ 92162306a36Sopenharmony_ci req.os_ver_major = LINUX_VERSION_MAJOR; 92262306a36Sopenharmony_ci req.os_ver_minor = LINUX_VERSION_PATCHLEVEL; 92362306a36Sopenharmony_ci req.os_ver_build = LINUX_VERSION_SUBLEVEL; 92462306a36Sopenharmony_ci strscpy(req.os_ver_str1, utsname()->sysname, sizeof(req.os_ver_str1)); 92562306a36Sopenharmony_ci strscpy(req.os_ver_str2, utsname()->release, sizeof(req.os_ver_str2)); 92662306a36Sopenharmony_ci strscpy(req.os_ver_str3, utsname()->version, sizeof(req.os_ver_str3)); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 92962306a36Sopenharmony_ci if (err || resp.hdr.status) { 93062306a36Sopenharmony_ci dev_err(gc->dev, "VfVerifyVersionOutput: %d, status=0x%x\n", 93162306a36Sopenharmony_ci err, resp.hdr.status); 93262306a36Sopenharmony_ci return err ? err : -EPROTO; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci if (resp.pf_cap_flags1 & GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG) { 93562306a36Sopenharmony_ci err = mana_gd_query_hwc_timeout(pdev, &hwc->hwc_timeout); 93662306a36Sopenharmony_ci if (err) { 93762306a36Sopenharmony_ci dev_err(gc->dev, "Failed to set the hwc timeout %d\n", err); 93862306a36Sopenharmony_ci return err; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci dev_dbg(gc->dev, "set the hwc timeout to %u\n", hwc->hwc_timeout); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci return 0; 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ciint mana_gd_register_device(struct gdma_dev *gd) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 94862306a36Sopenharmony_ci struct gdma_register_device_resp resp = {}; 94962306a36Sopenharmony_ci struct gdma_general_req req = {}; 95062306a36Sopenharmony_ci int err; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci gd->pdid = INVALID_PDID; 95362306a36Sopenharmony_ci gd->doorbell = INVALID_DOORBELL; 95462306a36Sopenharmony_ci gd->gpa_mkey = INVALID_MEM_KEY; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_REGISTER_DEVICE, sizeof(req), 95762306a36Sopenharmony_ci sizeof(resp)); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci req.hdr.dev_id = gd->dev_id; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 96262306a36Sopenharmony_ci if (err || resp.hdr.status) { 96362306a36Sopenharmony_ci dev_err(gc->dev, "gdma_register_device_resp failed: %d, 0x%x\n", 96462306a36Sopenharmony_ci err, resp.hdr.status); 96562306a36Sopenharmony_ci return err ? err : -EPROTO; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci gd->pdid = resp.pdid; 96962306a36Sopenharmony_ci gd->gpa_mkey = resp.gpa_mkey; 97062306a36Sopenharmony_ci gd->doorbell = resp.db_id; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci return 0; 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ciint mana_gd_deregister_device(struct gdma_dev *gd) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct gdma_context *gc = gd->gdma_context; 97862306a36Sopenharmony_ci struct gdma_general_resp resp = {}; 97962306a36Sopenharmony_ci struct gdma_general_req req = {}; 98062306a36Sopenharmony_ci int err; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (gd->pdid == INVALID_PDID) 98362306a36Sopenharmony_ci return -EINVAL; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_DEREGISTER_DEVICE, sizeof(req), 98662306a36Sopenharmony_ci sizeof(resp)); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci req.hdr.dev_id = gd->dev_id; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 99162306a36Sopenharmony_ci if (err || resp.hdr.status) { 99262306a36Sopenharmony_ci dev_err(gc->dev, "Failed to deregister device: %d, 0x%x\n", 99362306a36Sopenharmony_ci err, resp.hdr.status); 99462306a36Sopenharmony_ci if (!err) 99562306a36Sopenharmony_ci err = -EPROTO; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci gd->pdid = INVALID_PDID; 99962306a36Sopenharmony_ci gd->doorbell = INVALID_DOORBELL; 100062306a36Sopenharmony_ci gd->gpa_mkey = INVALID_MEM_KEY; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci return err; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ciu32 mana_gd_wq_avail_space(struct gdma_queue *wq) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci u32 used_space = (wq->head - wq->tail) * GDMA_WQE_BU_SIZE; 100862306a36Sopenharmony_ci u32 wq_size = wq->queue_size; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci WARN_ON_ONCE(used_space > wq_size); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return wq_size - used_space; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ciu8 *mana_gd_get_wqe_ptr(const struct gdma_queue *wq, u32 wqe_offset) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci u32 offset = (wqe_offset * GDMA_WQE_BU_SIZE) & (wq->queue_size - 1); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci WARN_ON_ONCE((offset + GDMA_WQE_BU_SIZE) > wq->queue_size); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci return wq->queue_mem_ptr + offset; 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic u32 mana_gd_write_client_oob(const struct gdma_wqe_request *wqe_req, 102562306a36Sopenharmony_ci enum gdma_queue_type q_type, 102662306a36Sopenharmony_ci u32 client_oob_size, u32 sgl_data_size, 102762306a36Sopenharmony_ci u8 *wqe_ptr) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci bool oob_in_sgl = !!(wqe_req->flags & GDMA_WR_OOB_IN_SGL); 103062306a36Sopenharmony_ci bool pad_data = !!(wqe_req->flags & GDMA_WR_PAD_BY_SGE0); 103162306a36Sopenharmony_ci struct gdma_wqe *header = (struct gdma_wqe *)wqe_ptr; 103262306a36Sopenharmony_ci u8 *ptr; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci memset(header, 0, sizeof(struct gdma_wqe)); 103562306a36Sopenharmony_ci header->num_sge = wqe_req->num_sge; 103662306a36Sopenharmony_ci header->inline_oob_size_div4 = client_oob_size / sizeof(u32); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (oob_in_sgl) { 103962306a36Sopenharmony_ci WARN_ON_ONCE(!pad_data || wqe_req->num_sge < 2); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci header->client_oob_in_sgl = 1; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (pad_data) 104462306a36Sopenharmony_ci header->last_vbytes = wqe_req->sgl[0].size; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (q_type == GDMA_SQ) 104862306a36Sopenharmony_ci header->client_data_unit = wqe_req->client_data_unit; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* The size of gdma_wqe + client_oob_size must be less than or equal 105162306a36Sopenharmony_ci * to one Basic Unit (i.e. 32 bytes), so the pointer can't go beyond 105262306a36Sopenharmony_ci * the queue memory buffer boundary. 105362306a36Sopenharmony_ci */ 105462306a36Sopenharmony_ci ptr = wqe_ptr + sizeof(header); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (wqe_req->inline_oob_data && wqe_req->inline_oob_size > 0) { 105762306a36Sopenharmony_ci memcpy(ptr, wqe_req->inline_oob_data, wqe_req->inline_oob_size); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (client_oob_size > wqe_req->inline_oob_size) 106062306a36Sopenharmony_ci memset(ptr + wqe_req->inline_oob_size, 0, 106162306a36Sopenharmony_ci client_oob_size - wqe_req->inline_oob_size); 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci return sizeof(header) + client_oob_size; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic void mana_gd_write_sgl(struct gdma_queue *wq, u8 *wqe_ptr, 106862306a36Sopenharmony_ci const struct gdma_wqe_request *wqe_req) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci u32 sgl_size = sizeof(struct gdma_sge) * wqe_req->num_sge; 107162306a36Sopenharmony_ci const u8 *address = (u8 *)wqe_req->sgl; 107262306a36Sopenharmony_ci u8 *base_ptr, *end_ptr; 107362306a36Sopenharmony_ci u32 size_to_end; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci base_ptr = wq->queue_mem_ptr; 107662306a36Sopenharmony_ci end_ptr = base_ptr + wq->queue_size; 107762306a36Sopenharmony_ci size_to_end = (u32)(end_ptr - wqe_ptr); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (size_to_end < sgl_size) { 108062306a36Sopenharmony_ci memcpy(wqe_ptr, address, size_to_end); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci wqe_ptr = base_ptr; 108362306a36Sopenharmony_ci address += size_to_end; 108462306a36Sopenharmony_ci sgl_size -= size_to_end; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci memcpy(wqe_ptr, address, sgl_size); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ciint mana_gd_post_work_request(struct gdma_queue *wq, 109162306a36Sopenharmony_ci const struct gdma_wqe_request *wqe_req, 109262306a36Sopenharmony_ci struct gdma_posted_wqe_info *wqe_info) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci u32 client_oob_size = wqe_req->inline_oob_size; 109562306a36Sopenharmony_ci struct gdma_context *gc; 109662306a36Sopenharmony_ci u32 sgl_data_size; 109762306a36Sopenharmony_ci u32 max_wqe_size; 109862306a36Sopenharmony_ci u32 wqe_size; 109962306a36Sopenharmony_ci u8 *wqe_ptr; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (wqe_req->num_sge == 0) 110262306a36Sopenharmony_ci return -EINVAL; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (wq->type == GDMA_RQ) { 110562306a36Sopenharmony_ci if (client_oob_size != 0) 110662306a36Sopenharmony_ci return -EINVAL; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci client_oob_size = INLINE_OOB_SMALL_SIZE; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci max_wqe_size = GDMA_MAX_RQE_SIZE; 111162306a36Sopenharmony_ci } else { 111262306a36Sopenharmony_ci if (client_oob_size != INLINE_OOB_SMALL_SIZE && 111362306a36Sopenharmony_ci client_oob_size != INLINE_OOB_LARGE_SIZE) 111462306a36Sopenharmony_ci return -EINVAL; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci max_wqe_size = GDMA_MAX_SQE_SIZE; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci sgl_data_size = sizeof(struct gdma_sge) * wqe_req->num_sge; 112062306a36Sopenharmony_ci wqe_size = ALIGN(sizeof(struct gdma_wqe) + client_oob_size + 112162306a36Sopenharmony_ci sgl_data_size, GDMA_WQE_BU_SIZE); 112262306a36Sopenharmony_ci if (wqe_size > max_wqe_size) 112362306a36Sopenharmony_ci return -EINVAL; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (wq->monitor_avl_buf && wqe_size > mana_gd_wq_avail_space(wq)) { 112662306a36Sopenharmony_ci gc = wq->gdma_dev->gdma_context; 112762306a36Sopenharmony_ci dev_err(gc->dev, "unsuccessful flow control!\n"); 112862306a36Sopenharmony_ci return -ENOSPC; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (wqe_info) 113262306a36Sopenharmony_ci wqe_info->wqe_size_in_bu = wqe_size / GDMA_WQE_BU_SIZE; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci wqe_ptr = mana_gd_get_wqe_ptr(wq, wq->head); 113562306a36Sopenharmony_ci wqe_ptr += mana_gd_write_client_oob(wqe_req, wq->type, client_oob_size, 113662306a36Sopenharmony_ci sgl_data_size, wqe_ptr); 113762306a36Sopenharmony_ci if (wqe_ptr >= (u8 *)wq->queue_mem_ptr + wq->queue_size) 113862306a36Sopenharmony_ci wqe_ptr -= wq->queue_size; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci mana_gd_write_sgl(wq, wqe_ptr, wqe_req); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci wq->head += wqe_size / GDMA_WQE_BU_SIZE; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci return 0; 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ciint mana_gd_post_and_ring(struct gdma_queue *queue, 114862306a36Sopenharmony_ci const struct gdma_wqe_request *wqe_req, 114962306a36Sopenharmony_ci struct gdma_posted_wqe_info *wqe_info) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct gdma_context *gc = queue->gdma_dev->gdma_context; 115262306a36Sopenharmony_ci int err; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci err = mana_gd_post_work_request(queue, wqe_req, wqe_info); 115562306a36Sopenharmony_ci if (err) 115662306a36Sopenharmony_ci return err; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci mana_gd_wq_ring_doorbell(gc, queue); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int mana_gd_read_cqe(struct gdma_queue *cq, struct gdma_comp *comp) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci unsigned int num_cqe = cq->queue_size / sizeof(struct gdma_cqe); 116662306a36Sopenharmony_ci struct gdma_cqe *cq_cqe = cq->queue_mem_ptr; 116762306a36Sopenharmony_ci u32 owner_bits, new_bits, old_bits; 116862306a36Sopenharmony_ci struct gdma_cqe *cqe; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci cqe = &cq_cqe[cq->head % num_cqe]; 117162306a36Sopenharmony_ci owner_bits = cqe->cqe_info.owner_bits; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci old_bits = (cq->head / num_cqe - 1) & GDMA_CQE_OWNER_MASK; 117462306a36Sopenharmony_ci /* Return 0 if no more entries. */ 117562306a36Sopenharmony_ci if (owner_bits == old_bits) 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci new_bits = (cq->head / num_cqe) & GDMA_CQE_OWNER_MASK; 117962306a36Sopenharmony_ci /* Return -1 if overflow detected. */ 118062306a36Sopenharmony_ci if (WARN_ON_ONCE(owner_bits != new_bits)) 118162306a36Sopenharmony_ci return -1; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci /* Per GDMA spec, rmb is necessary after checking owner_bits, before 118462306a36Sopenharmony_ci * reading completion info 118562306a36Sopenharmony_ci */ 118662306a36Sopenharmony_ci rmb(); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci comp->wq_num = cqe->cqe_info.wq_num; 118962306a36Sopenharmony_ci comp->is_sq = cqe->cqe_info.is_sq; 119062306a36Sopenharmony_ci memcpy(comp->cqe_data, cqe->cqe_data, GDMA_COMP_DATA_SIZE); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci return 1; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ciint mana_gd_poll_cq(struct gdma_queue *cq, struct gdma_comp *comp, int num_cqe) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci int cqe_idx; 119862306a36Sopenharmony_ci int ret; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci for (cqe_idx = 0; cqe_idx < num_cqe; cqe_idx++) { 120162306a36Sopenharmony_ci ret = mana_gd_read_cqe(cq, &comp[cqe_idx]); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (ret < 0) { 120462306a36Sopenharmony_ci cq->head -= cqe_idx; 120562306a36Sopenharmony_ci return ret; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (ret == 0) 120962306a36Sopenharmony_ci break; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci cq->head++; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci return cqe_idx; 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cistatic irqreturn_t mana_gd_intr(int irq, void *arg) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct gdma_irq_context *gic = arg; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (gic->handler) 122262306a36Sopenharmony_ci gic->handler(gic->arg); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci return IRQ_HANDLED; 122562306a36Sopenharmony_ci} 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ciint mana_gd_alloc_res_map(u32 res_avail, struct gdma_resource *r) 122862306a36Sopenharmony_ci{ 122962306a36Sopenharmony_ci r->map = bitmap_zalloc(res_avail, GFP_KERNEL); 123062306a36Sopenharmony_ci if (!r->map) 123162306a36Sopenharmony_ci return -ENOMEM; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci r->size = res_avail; 123462306a36Sopenharmony_ci spin_lock_init(&r->lock); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci return 0; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_civoid mana_gd_free_res_map(struct gdma_resource *r) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci bitmap_free(r->map); 124262306a36Sopenharmony_ci r->map = NULL; 124362306a36Sopenharmony_ci r->size = 0; 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_cistatic int mana_gd_setup_irqs(struct pci_dev *pdev) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci unsigned int max_queues_per_port = num_online_cpus(); 124962306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 125062306a36Sopenharmony_ci struct gdma_irq_context *gic; 125162306a36Sopenharmony_ci unsigned int max_irqs, cpu; 125262306a36Sopenharmony_ci int nvec, irq; 125362306a36Sopenharmony_ci int err, i = 0, j; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci if (max_queues_per_port > MANA_MAX_NUM_QUEUES) 125662306a36Sopenharmony_ci max_queues_per_port = MANA_MAX_NUM_QUEUES; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci /* Need 1 interrupt for the Hardware communication Channel (HWC) */ 125962306a36Sopenharmony_ci max_irqs = max_queues_per_port + 1; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX); 126262306a36Sopenharmony_ci if (nvec < 0) 126362306a36Sopenharmony_ci return nvec; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci gc->irq_contexts = kcalloc(nvec, sizeof(struct gdma_irq_context), 126662306a36Sopenharmony_ci GFP_KERNEL); 126762306a36Sopenharmony_ci if (!gc->irq_contexts) { 126862306a36Sopenharmony_ci err = -ENOMEM; 126962306a36Sopenharmony_ci goto free_irq_vector; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci for (i = 0; i < nvec; i++) { 127362306a36Sopenharmony_ci gic = &gc->irq_contexts[i]; 127462306a36Sopenharmony_ci gic->handler = NULL; 127562306a36Sopenharmony_ci gic->arg = NULL; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci if (!i) 127862306a36Sopenharmony_ci snprintf(gic->name, MANA_IRQ_NAME_SZ, "mana_hwc@pci:%s", 127962306a36Sopenharmony_ci pci_name(pdev)); 128062306a36Sopenharmony_ci else 128162306a36Sopenharmony_ci snprintf(gic->name, MANA_IRQ_NAME_SZ, "mana_q%d@pci:%s", 128262306a36Sopenharmony_ci i - 1, pci_name(pdev)); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci irq = pci_irq_vector(pdev, i); 128562306a36Sopenharmony_ci if (irq < 0) { 128662306a36Sopenharmony_ci err = irq; 128762306a36Sopenharmony_ci goto free_irq; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci err = request_irq(irq, mana_gd_intr, 0, gic->name, gic); 129162306a36Sopenharmony_ci if (err) 129262306a36Sopenharmony_ci goto free_irq; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci cpu = cpumask_local_spread(i, gc->numa_node); 129562306a36Sopenharmony_ci irq_set_affinity_and_hint(irq, cpumask_of(cpu)); 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci err = mana_gd_alloc_res_map(nvec, &gc->msix_resource); 129962306a36Sopenharmony_ci if (err) 130062306a36Sopenharmony_ci goto free_irq; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci gc->max_num_msix = nvec; 130362306a36Sopenharmony_ci gc->num_msix_usable = nvec; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci return 0; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cifree_irq: 130862306a36Sopenharmony_ci for (j = i - 1; j >= 0; j--) { 130962306a36Sopenharmony_ci irq = pci_irq_vector(pdev, j); 131062306a36Sopenharmony_ci gic = &gc->irq_contexts[j]; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci irq_update_affinity_hint(irq, NULL); 131362306a36Sopenharmony_ci free_irq(irq, gic); 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci kfree(gc->irq_contexts); 131762306a36Sopenharmony_ci gc->irq_contexts = NULL; 131862306a36Sopenharmony_cifree_irq_vector: 131962306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 132062306a36Sopenharmony_ci return err; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic void mana_gd_remove_irqs(struct pci_dev *pdev) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 132662306a36Sopenharmony_ci struct gdma_irq_context *gic; 132762306a36Sopenharmony_ci int irq, i; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (gc->max_num_msix < 1) 133062306a36Sopenharmony_ci return; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci mana_gd_free_res_map(&gc->msix_resource); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci for (i = 0; i < gc->max_num_msix; i++) { 133562306a36Sopenharmony_ci irq = pci_irq_vector(pdev, i); 133662306a36Sopenharmony_ci if (irq < 0) 133762306a36Sopenharmony_ci continue; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci gic = &gc->irq_contexts[i]; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci /* Need to clear the hint before free_irq */ 134262306a36Sopenharmony_ci irq_update_affinity_hint(irq, NULL); 134362306a36Sopenharmony_ci free_irq(irq, gic); 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci gc->max_num_msix = 0; 134962306a36Sopenharmony_ci gc->num_msix_usable = 0; 135062306a36Sopenharmony_ci kfree(gc->irq_contexts); 135162306a36Sopenharmony_ci gc->irq_contexts = NULL; 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic int mana_gd_setup(struct pci_dev *pdev) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 135762306a36Sopenharmony_ci int err; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci mana_gd_init_registers(pdev); 136062306a36Sopenharmony_ci mana_smc_init(&gc->shm_channel, gc->dev, gc->shm_base); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci err = mana_gd_setup_irqs(pdev); 136362306a36Sopenharmony_ci if (err) 136462306a36Sopenharmony_ci return err; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci err = mana_hwc_create_channel(gc); 136762306a36Sopenharmony_ci if (err) 136862306a36Sopenharmony_ci goto remove_irq; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci err = mana_gd_verify_vf_version(pdev); 137162306a36Sopenharmony_ci if (err) 137262306a36Sopenharmony_ci goto destroy_hwc; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci err = mana_gd_query_max_resources(pdev); 137562306a36Sopenharmony_ci if (err) 137662306a36Sopenharmony_ci goto destroy_hwc; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci err = mana_gd_detect_devices(pdev); 137962306a36Sopenharmony_ci if (err) 138062306a36Sopenharmony_ci goto destroy_hwc; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci return 0; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cidestroy_hwc: 138562306a36Sopenharmony_ci mana_hwc_destroy_channel(gc); 138662306a36Sopenharmony_ciremove_irq: 138762306a36Sopenharmony_ci mana_gd_remove_irqs(pdev); 138862306a36Sopenharmony_ci return err; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic void mana_gd_cleanup(struct pci_dev *pdev) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci mana_hwc_destroy_channel(gc); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci mana_gd_remove_irqs(pdev); 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic bool mana_is_pf(unsigned short dev_id) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci return dev_id == MANA_PF_DEVICE_ID; 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cistatic int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci struct gdma_context *gc; 140862306a36Sopenharmony_ci void __iomem *bar0_va; 140962306a36Sopenharmony_ci int bar = 0; 141062306a36Sopenharmony_ci int err; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* Each port has 2 CQs, each CQ has at most 1 EQE at a time */ 141362306a36Sopenharmony_ci BUILD_BUG_ON(2 * MAX_PORTS_IN_MANA_DEV * GDMA_EQE_SIZE > EQ_SIZE); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci err = pci_enable_device(pdev); 141662306a36Sopenharmony_ci if (err) 141762306a36Sopenharmony_ci return -ENXIO; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci pci_set_master(pdev); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci err = pci_request_regions(pdev, "mana"); 142262306a36Sopenharmony_ci if (err) 142362306a36Sopenharmony_ci goto disable_dev; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 142662306a36Sopenharmony_ci if (err) 142762306a36Sopenharmony_ci goto release_region; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci err = dma_set_max_seg_size(&pdev->dev, UINT_MAX); 143062306a36Sopenharmony_ci if (err) { 143162306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to set dma device segment size\n"); 143262306a36Sopenharmony_ci goto release_region; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci err = -ENOMEM; 143662306a36Sopenharmony_ci gc = vzalloc(sizeof(*gc)); 143762306a36Sopenharmony_ci if (!gc) 143862306a36Sopenharmony_ci goto release_region; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci mutex_init(&gc->eq_test_event_mutex); 144162306a36Sopenharmony_ci pci_set_drvdata(pdev, gc); 144262306a36Sopenharmony_ci gc->bar0_pa = pci_resource_start(pdev, 0); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci bar0_va = pci_iomap(pdev, bar, 0); 144562306a36Sopenharmony_ci if (!bar0_va) 144662306a36Sopenharmony_ci goto free_gc; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci gc->numa_node = dev_to_node(&pdev->dev); 144962306a36Sopenharmony_ci gc->is_pf = mana_is_pf(pdev->device); 145062306a36Sopenharmony_ci gc->bar0_va = bar0_va; 145162306a36Sopenharmony_ci gc->dev = &pdev->dev; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci err = mana_gd_setup(pdev); 145462306a36Sopenharmony_ci if (err) 145562306a36Sopenharmony_ci goto unmap_bar; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci err = mana_probe(&gc->mana, false); 145862306a36Sopenharmony_ci if (err) 145962306a36Sopenharmony_ci goto cleanup_gd; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci return 0; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_cicleanup_gd: 146462306a36Sopenharmony_ci mana_gd_cleanup(pdev); 146562306a36Sopenharmony_ciunmap_bar: 146662306a36Sopenharmony_ci pci_iounmap(pdev, bar0_va); 146762306a36Sopenharmony_cifree_gc: 146862306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 146962306a36Sopenharmony_ci vfree(gc); 147062306a36Sopenharmony_cirelease_region: 147162306a36Sopenharmony_ci pci_release_regions(pdev); 147262306a36Sopenharmony_cidisable_dev: 147362306a36Sopenharmony_ci pci_disable_device(pdev); 147462306a36Sopenharmony_ci dev_err(&pdev->dev, "gdma probe failed: err = %d\n", err); 147562306a36Sopenharmony_ci return err; 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_cistatic void mana_gd_remove(struct pci_dev *pdev) 147962306a36Sopenharmony_ci{ 148062306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci mana_remove(&gc->mana, false); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci mana_gd_cleanup(pdev); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci pci_iounmap(pdev, gc->bar0_va); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci vfree(gc); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci pci_release_regions(pdev); 149162306a36Sopenharmony_ci pci_disable_device(pdev); 149262306a36Sopenharmony_ci} 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci/* The 'state' parameter is not used. */ 149562306a36Sopenharmony_cistatic int mana_gd_suspend(struct pci_dev *pdev, pm_message_t state) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci mana_remove(&gc->mana, true); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci mana_gd_cleanup(pdev); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci return 0; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci/* In case the NIC hardware stops working, the suspend and resume callbacks will 150762306a36Sopenharmony_ci * fail -- if this happens, it's safer to just report an error than try to undo 150862306a36Sopenharmony_ci * what has been done. 150962306a36Sopenharmony_ci */ 151062306a36Sopenharmony_cistatic int mana_gd_resume(struct pci_dev *pdev) 151162306a36Sopenharmony_ci{ 151262306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 151362306a36Sopenharmony_ci int err; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci err = mana_gd_setup(pdev); 151662306a36Sopenharmony_ci if (err) 151762306a36Sopenharmony_ci return err; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci err = mana_probe(&gc->mana, true); 152062306a36Sopenharmony_ci if (err) 152162306a36Sopenharmony_ci return err; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci return 0; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci/* Quiesce the device for kexec. This is also called upon reboot/shutdown. */ 152762306a36Sopenharmony_cistatic void mana_gd_shutdown(struct pci_dev *pdev) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci struct gdma_context *gc = pci_get_drvdata(pdev); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci dev_info(&pdev->dev, "Shutdown was called\n"); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci mana_remove(&gc->mana, true); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci mana_gd_cleanup(pdev); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci pci_disable_device(pdev); 153862306a36Sopenharmony_ci} 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cistatic const struct pci_device_id mana_id_table[] = { 154162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_PF_DEVICE_ID) }, 154262306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_VF_DEVICE_ID) }, 154362306a36Sopenharmony_ci { } 154462306a36Sopenharmony_ci}; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_cistatic struct pci_driver mana_driver = { 154762306a36Sopenharmony_ci .name = "mana", 154862306a36Sopenharmony_ci .id_table = mana_id_table, 154962306a36Sopenharmony_ci .probe = mana_gd_probe, 155062306a36Sopenharmony_ci .remove = mana_gd_remove, 155162306a36Sopenharmony_ci .suspend = mana_gd_suspend, 155262306a36Sopenharmony_ci .resume = mana_gd_resume, 155362306a36Sopenharmony_ci .shutdown = mana_gd_shutdown, 155462306a36Sopenharmony_ci}; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cimodule_pci_driver(mana_driver); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mana_id_table); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 156162306a36Sopenharmony_ciMODULE_DESCRIPTION("Microsoft Azure Network Adapter driver"); 1562