162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Marvell OcteonTX CPT driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2019 Marvell International Ltd. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 762306a36Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 862306a36Sopenharmony_ci * published by the Free Software Foundation. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include "otx_cptvf.h" 1462306a36Sopenharmony_ci#include "otx_cptvf_algs.h" 1562306a36Sopenharmony_ci#include "otx_cptvf_reqmgr.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define DRV_NAME "octeontx-cptvf" 1862306a36Sopenharmony_ci#define DRV_VERSION "1.0" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic void vq_work_handler(unsigned long data) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct otx_cptvf_wqe_info *cwqe_info = 2362306a36Sopenharmony_ci (struct otx_cptvf_wqe_info *) data; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci otx_cpt_post_process(&cwqe_info->vq_wqe[0]); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int init_worker_threads(struct otx_cptvf *cptvf) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 3162306a36Sopenharmony_ci struct otx_cptvf_wqe_info *cwqe_info; 3262306a36Sopenharmony_ci int i; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci cwqe_info = kzalloc(sizeof(*cwqe_info), GFP_KERNEL); 3562306a36Sopenharmony_ci if (!cwqe_info) 3662306a36Sopenharmony_ci return -ENOMEM; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (cptvf->num_queues) { 3962306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Creating VQ worker threads (%d)\n", 4062306a36Sopenharmony_ci cptvf->num_queues); 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci for (i = 0; i < cptvf->num_queues; i++) { 4462306a36Sopenharmony_ci tasklet_init(&cwqe_info->vq_wqe[i].twork, vq_work_handler, 4562306a36Sopenharmony_ci (u64)cwqe_info); 4662306a36Sopenharmony_ci cwqe_info->vq_wqe[i].cptvf = cptvf; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci cptvf->wqe_info = cwqe_info; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void cleanup_worker_threads(struct otx_cptvf *cptvf) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 5662306a36Sopenharmony_ci struct otx_cptvf_wqe_info *cwqe_info; 5762306a36Sopenharmony_ci int i; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci cwqe_info = (struct otx_cptvf_wqe_info *)cptvf->wqe_info; 6062306a36Sopenharmony_ci if (!cwqe_info) 6162306a36Sopenharmony_ci return; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (cptvf->num_queues) { 6462306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Cleaning VQ worker threads (%u)\n", 6562306a36Sopenharmony_ci cptvf->num_queues); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci for (i = 0; i < cptvf->num_queues; i++) 6962306a36Sopenharmony_ci tasklet_kill(&cwqe_info->vq_wqe[i].twork); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci kfree_sensitive(cwqe_info); 7262306a36Sopenharmony_ci cptvf->wqe_info = NULL; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void free_pending_queues(struct otx_cpt_pending_qinfo *pqinfo) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct otx_cpt_pending_queue *queue; 7862306a36Sopenharmony_ci int i; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci for_each_pending_queue(pqinfo, queue, i) { 8162306a36Sopenharmony_ci if (!queue->head) 8262306a36Sopenharmony_ci continue; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* free single queue */ 8562306a36Sopenharmony_ci kfree_sensitive((queue->head)); 8662306a36Sopenharmony_ci queue->front = 0; 8762306a36Sopenharmony_ci queue->rear = 0; 8862306a36Sopenharmony_ci queue->qlen = 0; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci pqinfo->num_queues = 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int alloc_pending_queues(struct otx_cpt_pending_qinfo *pqinfo, u32 qlen, 9462306a36Sopenharmony_ci u32 num_queues) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct otx_cpt_pending_queue *queue = NULL; 9762306a36Sopenharmony_ci int ret; 9862306a36Sopenharmony_ci u32 i; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci pqinfo->num_queues = num_queues; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci for_each_pending_queue(pqinfo, queue, i) { 10362306a36Sopenharmony_ci queue->head = kcalloc(qlen, sizeof(*queue->head), GFP_KERNEL); 10462306a36Sopenharmony_ci if (!queue->head) { 10562306a36Sopenharmony_ci ret = -ENOMEM; 10662306a36Sopenharmony_ci goto pending_qfail; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci queue->pending_count = 0; 11062306a36Sopenharmony_ci queue->front = 0; 11162306a36Sopenharmony_ci queue->rear = 0; 11262306a36Sopenharmony_ci queue->qlen = qlen; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* init queue spin lock */ 11562306a36Sopenharmony_ci spin_lock_init(&queue->lock); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cipending_qfail: 12062306a36Sopenharmony_ci free_pending_queues(pqinfo); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return ret; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int init_pending_queues(struct otx_cptvf *cptvf, u32 qlen, 12662306a36Sopenharmony_ci u32 num_queues) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 12962306a36Sopenharmony_ci int ret; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (!num_queues) 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ret = alloc_pending_queues(&cptvf->pqinfo, qlen, num_queues); 13562306a36Sopenharmony_ci if (ret) { 13662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup pending queues (%u)\n", 13762306a36Sopenharmony_ci num_queues); 13862306a36Sopenharmony_ci return ret; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void cleanup_pending_queues(struct otx_cptvf *cptvf) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (!cptvf->num_queues) 14862306a36Sopenharmony_ci return; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Cleaning VQ pending queue (%u)\n", 15162306a36Sopenharmony_ci cptvf->num_queues); 15262306a36Sopenharmony_ci free_pending_queues(&cptvf->pqinfo); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void free_command_queues(struct otx_cptvf *cptvf, 15662306a36Sopenharmony_ci struct otx_cpt_cmd_qinfo *cqinfo) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct otx_cpt_cmd_queue *queue = NULL; 15962306a36Sopenharmony_ci struct otx_cpt_cmd_chunk *chunk = NULL; 16062306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 16162306a36Sopenharmony_ci int i; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* clean up for each queue */ 16462306a36Sopenharmony_ci for (i = 0; i < cptvf->num_queues; i++) { 16562306a36Sopenharmony_ci queue = &cqinfo->queue[i]; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci while (!list_empty(&cqinfo->queue[i].chead)) { 16862306a36Sopenharmony_ci chunk = list_first_entry(&cqinfo->queue[i].chead, 16962306a36Sopenharmony_ci struct otx_cpt_cmd_chunk, nextchunk); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, chunk->size, 17262306a36Sopenharmony_ci chunk->head, 17362306a36Sopenharmony_ci chunk->dma_addr); 17462306a36Sopenharmony_ci chunk->head = NULL; 17562306a36Sopenharmony_ci chunk->dma_addr = 0; 17662306a36Sopenharmony_ci list_del(&chunk->nextchunk); 17762306a36Sopenharmony_ci kfree_sensitive(chunk); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci queue->num_chunks = 0; 18062306a36Sopenharmony_ci queue->idx = 0; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int alloc_command_queues(struct otx_cptvf *cptvf, 18662306a36Sopenharmony_ci struct otx_cpt_cmd_qinfo *cqinfo, 18762306a36Sopenharmony_ci u32 qlen) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct otx_cpt_cmd_chunk *curr, *first, *last; 19062306a36Sopenharmony_ci struct otx_cpt_cmd_queue *queue = NULL; 19162306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 19262306a36Sopenharmony_ci size_t q_size, c_size, rem_q_size; 19362306a36Sopenharmony_ci u32 qcsize_bytes; 19462306a36Sopenharmony_ci int i; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* Qsize in dwords, needed for SADDR config, 1-next chunk pointer */ 19862306a36Sopenharmony_ci cptvf->qsize = min(qlen, cqinfo->qchunksize) * 19962306a36Sopenharmony_ci OTX_CPT_NEXT_CHUNK_PTR_SIZE + 1; 20062306a36Sopenharmony_ci /* Qsize in bytes to create space for alignment */ 20162306a36Sopenharmony_ci q_size = qlen * OTX_CPT_INST_SIZE; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci qcsize_bytes = cqinfo->qchunksize * OTX_CPT_INST_SIZE; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* per queue initialization */ 20662306a36Sopenharmony_ci for (i = 0; i < cptvf->num_queues; i++) { 20762306a36Sopenharmony_ci rem_q_size = q_size; 20862306a36Sopenharmony_ci first = NULL; 20962306a36Sopenharmony_ci last = NULL; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci queue = &cqinfo->queue[i]; 21262306a36Sopenharmony_ci INIT_LIST_HEAD(&queue->chead); 21362306a36Sopenharmony_ci do { 21462306a36Sopenharmony_ci curr = kzalloc(sizeof(*curr), GFP_KERNEL); 21562306a36Sopenharmony_ci if (!curr) 21662306a36Sopenharmony_ci goto cmd_qfail; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci c_size = (rem_q_size > qcsize_bytes) ? qcsize_bytes : 21962306a36Sopenharmony_ci rem_q_size; 22062306a36Sopenharmony_ci curr->head = dma_alloc_coherent(&pdev->dev, 22162306a36Sopenharmony_ci c_size + OTX_CPT_NEXT_CHUNK_PTR_SIZE, 22262306a36Sopenharmony_ci &curr->dma_addr, GFP_KERNEL); 22362306a36Sopenharmony_ci if (!curr->head) { 22462306a36Sopenharmony_ci dev_err(&pdev->dev, 22562306a36Sopenharmony_ci "Command Q (%d) chunk (%d) allocation failed\n", 22662306a36Sopenharmony_ci i, queue->num_chunks); 22762306a36Sopenharmony_ci goto free_curr; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci curr->size = c_size; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (queue->num_chunks == 0) { 23262306a36Sopenharmony_ci first = curr; 23362306a36Sopenharmony_ci queue->base = first; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci list_add_tail(&curr->nextchunk, 23662306a36Sopenharmony_ci &cqinfo->queue[i].chead); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci queue->num_chunks++; 23962306a36Sopenharmony_ci rem_q_size -= c_size; 24062306a36Sopenharmony_ci if (last) 24162306a36Sopenharmony_ci *((u64 *)(&last->head[last->size])) = 24262306a36Sopenharmony_ci (u64)curr->dma_addr; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci last = curr; 24562306a36Sopenharmony_ci } while (rem_q_size); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* 24862306a36Sopenharmony_ci * Make the queue circular, tie back last chunk entry to head 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci curr = first; 25162306a36Sopenharmony_ci *((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr; 25262306a36Sopenharmony_ci queue->qhead = curr; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_cifree_curr: 25662306a36Sopenharmony_ci kfree(curr); 25762306a36Sopenharmony_cicmd_qfail: 25862306a36Sopenharmony_ci free_command_queues(cptvf, cqinfo); 25962306a36Sopenharmony_ci return -ENOMEM; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int init_command_queues(struct otx_cptvf *cptvf, u32 qlen) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 26562306a36Sopenharmony_ci int ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* setup command queues */ 26862306a36Sopenharmony_ci ret = alloc_command_queues(cptvf, &cptvf->cqinfo, qlen); 26962306a36Sopenharmony_ci if (ret) { 27062306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate command queues (%u)\n", 27162306a36Sopenharmony_ci cptvf->num_queues); 27262306a36Sopenharmony_ci return ret; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci return ret; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void cleanup_command_queues(struct otx_cptvf *cptvf) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (!cptvf->num_queues) 28262306a36Sopenharmony_ci return; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Cleaning VQ command queue (%u)\n", 28562306a36Sopenharmony_ci cptvf->num_queues); 28662306a36Sopenharmony_ci free_command_queues(cptvf, &cptvf->cqinfo); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void cptvf_sw_cleanup(struct otx_cptvf *cptvf) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci cleanup_worker_threads(cptvf); 29262306a36Sopenharmony_ci cleanup_pending_queues(cptvf); 29362306a36Sopenharmony_ci cleanup_command_queues(cptvf); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int cptvf_sw_init(struct otx_cptvf *cptvf, u32 qlen, u32 num_queues) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 29962306a36Sopenharmony_ci u32 max_dev_queues = 0; 30062306a36Sopenharmony_ci int ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci max_dev_queues = OTX_CPT_NUM_QS_PER_VF; 30362306a36Sopenharmony_ci /* possible cpus */ 30462306a36Sopenharmony_ci num_queues = min_t(u32, num_queues, max_dev_queues); 30562306a36Sopenharmony_ci cptvf->num_queues = num_queues; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci ret = init_command_queues(cptvf, qlen); 30862306a36Sopenharmony_ci if (ret) { 30962306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup command queues (%u)\n", 31062306a36Sopenharmony_ci num_queues); 31162306a36Sopenharmony_ci return ret; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ret = init_pending_queues(cptvf, qlen, num_queues); 31562306a36Sopenharmony_ci if (ret) { 31662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup pending queues (%u)\n", 31762306a36Sopenharmony_ci num_queues); 31862306a36Sopenharmony_ci goto setup_pqfail; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Create worker threads for BH processing */ 32262306a36Sopenharmony_ci ret = init_worker_threads(cptvf); 32362306a36Sopenharmony_ci if (ret) { 32462306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup worker threads\n"); 32562306a36Sopenharmony_ci goto init_work_fail; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci return 0; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ciinit_work_fail: 33062306a36Sopenharmony_ci cleanup_worker_threads(cptvf); 33162306a36Sopenharmony_ci cleanup_pending_queues(cptvf); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cisetup_pqfail: 33462306a36Sopenharmony_ci cleanup_command_queues(cptvf); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return ret; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void cptvf_free_irq_affinity(struct otx_cptvf *cptvf, int vec) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci irq_set_affinity_hint(pci_irq_vector(cptvf->pdev, vec), NULL); 34262306a36Sopenharmony_ci free_cpumask_var(cptvf->affinity_mask[vec]); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void cptvf_write_vq_ctl(struct otx_cptvf *cptvf, bool val) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci union otx_cptx_vqx_ctl vqx_ctl; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci vqx_ctl.u = readq(cptvf->reg_base + OTX_CPT_VQX_CTL(0)); 35062306a36Sopenharmony_ci vqx_ctl.s.ena = val; 35162306a36Sopenharmony_ci writeq(vqx_ctl.u, cptvf->reg_base + OTX_CPT_VQX_CTL(0)); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_civoid otx_cptvf_write_vq_doorbell(struct otx_cptvf *cptvf, u32 val) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci union otx_cptx_vqx_doorbell vqx_dbell; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci vqx_dbell.u = readq(cptvf->reg_base + OTX_CPT_VQX_DOORBELL(0)); 35962306a36Sopenharmony_ci vqx_dbell.s.dbell_cnt = val * 8; /* Num of Instructions * 8 words */ 36062306a36Sopenharmony_ci writeq(vqx_dbell.u, cptvf->reg_base + OTX_CPT_VQX_DOORBELL(0)); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void cptvf_write_vq_inprog(struct otx_cptvf *cptvf, u8 val) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci union otx_cptx_vqx_inprog vqx_inprg; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci vqx_inprg.u = readq(cptvf->reg_base + OTX_CPT_VQX_INPROG(0)); 36862306a36Sopenharmony_ci vqx_inprg.s.inflight = val; 36962306a36Sopenharmony_ci writeq(vqx_inprg.u, cptvf->reg_base + OTX_CPT_VQX_INPROG(0)); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void cptvf_write_vq_done_numwait(struct otx_cptvf *cptvf, u32 val) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci union otx_cptx_vqx_done_wait vqx_dwait; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci vqx_dwait.u = readq(cptvf->reg_base + OTX_CPT_VQX_DONE_WAIT(0)); 37762306a36Sopenharmony_ci vqx_dwait.s.num_wait = val; 37862306a36Sopenharmony_ci writeq(vqx_dwait.u, cptvf->reg_base + OTX_CPT_VQX_DONE_WAIT(0)); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic u32 cptvf_read_vq_done_numwait(struct otx_cptvf *cptvf) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci union otx_cptx_vqx_done_wait vqx_dwait; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci vqx_dwait.u = readq(cptvf->reg_base + OTX_CPT_VQX_DONE_WAIT(0)); 38662306a36Sopenharmony_ci return vqx_dwait.s.num_wait; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic void cptvf_write_vq_done_timewait(struct otx_cptvf *cptvf, u16 time) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci union otx_cptx_vqx_done_wait vqx_dwait; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci vqx_dwait.u = readq(cptvf->reg_base + OTX_CPT_VQX_DONE_WAIT(0)); 39462306a36Sopenharmony_ci vqx_dwait.s.time_wait = time; 39562306a36Sopenharmony_ci writeq(vqx_dwait.u, cptvf->reg_base + OTX_CPT_VQX_DONE_WAIT(0)); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic u16 cptvf_read_vq_done_timewait(struct otx_cptvf *cptvf) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci union otx_cptx_vqx_done_wait vqx_dwait; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci vqx_dwait.u = readq(cptvf->reg_base + OTX_CPT_VQX_DONE_WAIT(0)); 40462306a36Sopenharmony_ci return vqx_dwait.s.time_wait; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void cptvf_enable_swerr_interrupts(struct otx_cptvf *cptvf) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci union otx_cptx_vqx_misc_ena_w1s vqx_misc_ena; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci vqx_misc_ena.u = readq(cptvf->reg_base + OTX_CPT_VQX_MISC_ENA_W1S(0)); 41262306a36Sopenharmony_ci /* Enable SWERR interrupts for the requested VF */ 41362306a36Sopenharmony_ci vqx_misc_ena.s.swerr = 1; 41462306a36Sopenharmony_ci writeq(vqx_misc_ena.u, cptvf->reg_base + OTX_CPT_VQX_MISC_ENA_W1S(0)); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void cptvf_enable_mbox_interrupts(struct otx_cptvf *cptvf) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci union otx_cptx_vqx_misc_ena_w1s vqx_misc_ena; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci vqx_misc_ena.u = readq(cptvf->reg_base + OTX_CPT_VQX_MISC_ENA_W1S(0)); 42262306a36Sopenharmony_ci /* Enable MBOX interrupt for the requested VF */ 42362306a36Sopenharmony_ci vqx_misc_ena.s.mbox = 1; 42462306a36Sopenharmony_ci writeq(vqx_misc_ena.u, cptvf->reg_base + OTX_CPT_VQX_MISC_ENA_W1S(0)); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic void cptvf_enable_done_interrupts(struct otx_cptvf *cptvf) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci union otx_cptx_vqx_done_ena_w1s vqx_done_ena; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci vqx_done_ena.u = readq(cptvf->reg_base + OTX_CPT_VQX_DONE_ENA_W1S(0)); 43262306a36Sopenharmony_ci /* Enable DONE interrupt for the requested VF */ 43362306a36Sopenharmony_ci vqx_done_ena.s.done = 1; 43462306a36Sopenharmony_ci writeq(vqx_done_ena.u, cptvf->reg_base + OTX_CPT_VQX_DONE_ENA_W1S(0)); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void cptvf_clear_dovf_intr(struct otx_cptvf *cptvf) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci union otx_cptx_vqx_misc_int vqx_misc_int; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci vqx_misc_int.u = readq(cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 44262306a36Sopenharmony_ci /* W1C for the VF */ 44362306a36Sopenharmony_ci vqx_misc_int.s.dovf = 1; 44462306a36Sopenharmony_ci writeq(vqx_misc_int.u, cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void cptvf_clear_irde_intr(struct otx_cptvf *cptvf) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci union otx_cptx_vqx_misc_int vqx_misc_int; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci vqx_misc_int.u = readq(cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 45262306a36Sopenharmony_ci /* W1C for the VF */ 45362306a36Sopenharmony_ci vqx_misc_int.s.irde = 1; 45462306a36Sopenharmony_ci writeq(vqx_misc_int.u, cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic void cptvf_clear_nwrp_intr(struct otx_cptvf *cptvf) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci union otx_cptx_vqx_misc_int vqx_misc_int; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci vqx_misc_int.u = readq(cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 46262306a36Sopenharmony_ci /* W1C for the VF */ 46362306a36Sopenharmony_ci vqx_misc_int.s.nwrp = 1; 46462306a36Sopenharmony_ci writeq(vqx_misc_int.u, cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic void cptvf_clear_mbox_intr(struct otx_cptvf *cptvf) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci union otx_cptx_vqx_misc_int vqx_misc_int; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci vqx_misc_int.u = readq(cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 47262306a36Sopenharmony_ci /* W1C for the VF */ 47362306a36Sopenharmony_ci vqx_misc_int.s.mbox = 1; 47462306a36Sopenharmony_ci writeq(vqx_misc_int.u, cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic void cptvf_clear_swerr_intr(struct otx_cptvf *cptvf) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci union otx_cptx_vqx_misc_int vqx_misc_int; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci vqx_misc_int.u = readq(cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 48262306a36Sopenharmony_ci /* W1C for the VF */ 48362306a36Sopenharmony_ci vqx_misc_int.s.swerr = 1; 48462306a36Sopenharmony_ci writeq(vqx_misc_int.u, cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic u64 cptvf_read_vf_misc_intr_status(struct otx_cptvf *cptvf) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci return readq(cptvf->reg_base + OTX_CPT_VQX_MISC_INT(0)); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic irqreturn_t cptvf_misc_intr_handler(int __always_unused irq, 49362306a36Sopenharmony_ci void *arg) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct otx_cptvf *cptvf = arg; 49662306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 49762306a36Sopenharmony_ci u64 intr; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci intr = cptvf_read_vf_misc_intr_status(cptvf); 50062306a36Sopenharmony_ci /* Check for MISC interrupt types */ 50162306a36Sopenharmony_ci if (likely(intr & OTX_CPT_VF_INTR_MBOX_MASK)) { 50262306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Mailbox interrupt 0x%llx on CPT VF %d\n", 50362306a36Sopenharmony_ci intr, cptvf->vfid); 50462306a36Sopenharmony_ci otx_cptvf_handle_mbox_intr(cptvf); 50562306a36Sopenharmony_ci cptvf_clear_mbox_intr(cptvf); 50662306a36Sopenharmony_ci } else if (unlikely(intr & OTX_CPT_VF_INTR_DOVF_MASK)) { 50762306a36Sopenharmony_ci cptvf_clear_dovf_intr(cptvf); 50862306a36Sopenharmony_ci /* Clear doorbell count */ 50962306a36Sopenharmony_ci otx_cptvf_write_vq_doorbell(cptvf, 0); 51062306a36Sopenharmony_ci dev_err(&pdev->dev, 51162306a36Sopenharmony_ci "Doorbell overflow error interrupt 0x%llx on CPT VF %d\n", 51262306a36Sopenharmony_ci intr, cptvf->vfid); 51362306a36Sopenharmony_ci } else if (unlikely(intr & OTX_CPT_VF_INTR_IRDE_MASK)) { 51462306a36Sopenharmony_ci cptvf_clear_irde_intr(cptvf); 51562306a36Sopenharmony_ci dev_err(&pdev->dev, 51662306a36Sopenharmony_ci "Instruction NCB read error interrupt 0x%llx on CPT VF %d\n", 51762306a36Sopenharmony_ci intr, cptvf->vfid); 51862306a36Sopenharmony_ci } else if (unlikely(intr & OTX_CPT_VF_INTR_NWRP_MASK)) { 51962306a36Sopenharmony_ci cptvf_clear_nwrp_intr(cptvf); 52062306a36Sopenharmony_ci dev_err(&pdev->dev, 52162306a36Sopenharmony_ci "NCB response write error interrupt 0x%llx on CPT VF %d\n", 52262306a36Sopenharmony_ci intr, cptvf->vfid); 52362306a36Sopenharmony_ci } else if (unlikely(intr & OTX_CPT_VF_INTR_SERR_MASK)) { 52462306a36Sopenharmony_ci cptvf_clear_swerr_intr(cptvf); 52562306a36Sopenharmony_ci dev_err(&pdev->dev, 52662306a36Sopenharmony_ci "Software error interrupt 0x%llx on CPT VF %d\n", 52762306a36Sopenharmony_ci intr, cptvf->vfid); 52862306a36Sopenharmony_ci } else { 52962306a36Sopenharmony_ci dev_err(&pdev->dev, "Unhandled interrupt in OTX_CPT VF %d\n", 53062306a36Sopenharmony_ci cptvf->vfid); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return IRQ_HANDLED; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic inline struct otx_cptvf_wqe *get_cptvf_vq_wqe(struct otx_cptvf *cptvf, 53762306a36Sopenharmony_ci int qno) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct otx_cptvf_wqe_info *nwqe_info; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (unlikely(qno >= cptvf->num_queues)) 54262306a36Sopenharmony_ci return NULL; 54362306a36Sopenharmony_ci nwqe_info = (struct otx_cptvf_wqe_info *)cptvf->wqe_info; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return &nwqe_info->vq_wqe[qno]; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic inline u32 cptvf_read_vq_done_count(struct otx_cptvf *cptvf) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci union otx_cptx_vqx_done vqx_done; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci vqx_done.u = readq(cptvf->reg_base + OTX_CPT_VQX_DONE(0)); 55362306a36Sopenharmony_ci return vqx_done.s.done; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic inline void cptvf_write_vq_done_ack(struct otx_cptvf *cptvf, 55762306a36Sopenharmony_ci u32 ackcnt) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci union otx_cptx_vqx_done_ack vqx_dack_cnt; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci vqx_dack_cnt.u = readq(cptvf->reg_base + OTX_CPT_VQX_DONE_ACK(0)); 56262306a36Sopenharmony_ci vqx_dack_cnt.s.done_ack = ackcnt; 56362306a36Sopenharmony_ci writeq(vqx_dack_cnt.u, cptvf->reg_base + OTX_CPT_VQX_DONE_ACK(0)); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic irqreturn_t cptvf_done_intr_handler(int __always_unused irq, 56762306a36Sopenharmony_ci void *cptvf_dev) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct otx_cptvf *cptvf = (struct otx_cptvf *)cptvf_dev; 57062306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 57162306a36Sopenharmony_ci /* Read the number of completions */ 57262306a36Sopenharmony_ci u32 intr = cptvf_read_vq_done_count(cptvf); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (intr) { 57562306a36Sopenharmony_ci struct otx_cptvf_wqe *wqe; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* 57862306a36Sopenharmony_ci * Acknowledge the number of scheduled completions for 57962306a36Sopenharmony_ci * processing 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci cptvf_write_vq_done_ack(cptvf, intr); 58262306a36Sopenharmony_ci wqe = get_cptvf_vq_wqe(cptvf, 0); 58362306a36Sopenharmony_ci if (unlikely(!wqe)) { 58462306a36Sopenharmony_ci dev_err(&pdev->dev, "No work to schedule for VF (%d)\n", 58562306a36Sopenharmony_ci cptvf->vfid); 58662306a36Sopenharmony_ci return IRQ_NONE; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci tasklet_hi_schedule(&wqe->twork); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return IRQ_HANDLED; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic void cptvf_set_irq_affinity(struct otx_cptvf *cptvf, int vec) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 59762306a36Sopenharmony_ci int cpu; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (!zalloc_cpumask_var(&cptvf->affinity_mask[vec], 60062306a36Sopenharmony_ci GFP_KERNEL)) { 60162306a36Sopenharmony_ci dev_err(&pdev->dev, 60262306a36Sopenharmony_ci "Allocation failed for affinity_mask for VF %d\n", 60362306a36Sopenharmony_ci cptvf->vfid); 60462306a36Sopenharmony_ci return; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci cpu = cptvf->vfid % num_online_cpus(); 60862306a36Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(cpu, cptvf->node), 60962306a36Sopenharmony_ci cptvf->affinity_mask[vec]); 61062306a36Sopenharmony_ci irq_set_affinity_hint(pci_irq_vector(pdev, vec), 61162306a36Sopenharmony_ci cptvf->affinity_mask[vec]); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic void cptvf_write_vq_saddr(struct otx_cptvf *cptvf, u64 val) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci union otx_cptx_vqx_saddr vqx_saddr; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci vqx_saddr.u = val; 61962306a36Sopenharmony_ci writeq(vqx_saddr.u, cptvf->reg_base + OTX_CPT_VQX_SADDR(0)); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic void cptvf_device_init(struct otx_cptvf *cptvf) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci u64 base_addr = 0; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* Disable the VQ */ 62762306a36Sopenharmony_ci cptvf_write_vq_ctl(cptvf, 0); 62862306a36Sopenharmony_ci /* Reset the doorbell */ 62962306a36Sopenharmony_ci otx_cptvf_write_vq_doorbell(cptvf, 0); 63062306a36Sopenharmony_ci /* Clear inflight */ 63162306a36Sopenharmony_ci cptvf_write_vq_inprog(cptvf, 0); 63262306a36Sopenharmony_ci /* Write VQ SADDR */ 63362306a36Sopenharmony_ci base_addr = (u64)(cptvf->cqinfo.queue[0].qhead->dma_addr); 63462306a36Sopenharmony_ci cptvf_write_vq_saddr(cptvf, base_addr); 63562306a36Sopenharmony_ci /* Configure timerhold / coalescence */ 63662306a36Sopenharmony_ci cptvf_write_vq_done_timewait(cptvf, OTX_CPT_TIMER_HOLD); 63762306a36Sopenharmony_ci cptvf_write_vq_done_numwait(cptvf, OTX_CPT_COUNT_HOLD); 63862306a36Sopenharmony_ci /* Enable the VQ */ 63962306a36Sopenharmony_ci cptvf_write_vq_ctl(cptvf, 1); 64062306a36Sopenharmony_ci /* Flag the VF ready */ 64162306a36Sopenharmony_ci cptvf->flags |= OTX_CPT_FLAG_DEVICE_READY; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic ssize_t vf_type_show(struct device *dev, 64562306a36Sopenharmony_ci struct device_attribute *attr, 64662306a36Sopenharmony_ci char *buf) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct otx_cptvf *cptvf = dev_get_drvdata(dev); 64962306a36Sopenharmony_ci char *msg; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci switch (cptvf->vftype) { 65262306a36Sopenharmony_ci case OTX_CPT_AE_TYPES: 65362306a36Sopenharmony_ci msg = "AE"; 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci case OTX_CPT_SE_TYPES: 65762306a36Sopenharmony_ci msg = "SE"; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci default: 66162306a36Sopenharmony_ci msg = "Invalid"; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", msg); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic ssize_t vf_engine_group_show(struct device *dev, 66862306a36Sopenharmony_ci struct device_attribute *attr, 66962306a36Sopenharmony_ci char *buf) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct otx_cptvf *cptvf = dev_get_drvdata(dev); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", cptvf->vfgrp); 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic ssize_t vf_engine_group_store(struct device *dev, 67762306a36Sopenharmony_ci struct device_attribute *attr, 67862306a36Sopenharmony_ci const char *buf, size_t count) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct otx_cptvf *cptvf = dev_get_drvdata(dev); 68162306a36Sopenharmony_ci int val, ret; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci ret = kstrtoint(buf, 10, &val); 68462306a36Sopenharmony_ci if (ret) 68562306a36Sopenharmony_ci return ret; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (val < 0) 68862306a36Sopenharmony_ci return -EINVAL; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (val >= OTX_CPT_MAX_ENGINE_GROUPS) { 69162306a36Sopenharmony_ci dev_err(dev, "Engine group >= than max available groups %d\n", 69262306a36Sopenharmony_ci OTX_CPT_MAX_ENGINE_GROUPS); 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci ret = otx_cptvf_send_vf_to_grp_msg(cptvf, val); 69762306a36Sopenharmony_ci if (ret) 69862306a36Sopenharmony_ci return ret; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci return count; 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic ssize_t vf_coalesc_time_wait_show(struct device *dev, 70462306a36Sopenharmony_ci struct device_attribute *attr, 70562306a36Sopenharmony_ci char *buf) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct otx_cptvf *cptvf = dev_get_drvdata(dev); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", 71062306a36Sopenharmony_ci cptvf_read_vq_done_timewait(cptvf)); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic ssize_t vf_coalesc_num_wait_show(struct device *dev, 71462306a36Sopenharmony_ci struct device_attribute *attr, 71562306a36Sopenharmony_ci char *buf) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct otx_cptvf *cptvf = dev_get_drvdata(dev); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", 72062306a36Sopenharmony_ci cptvf_read_vq_done_numwait(cptvf)); 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic ssize_t vf_coalesc_time_wait_store(struct device *dev, 72462306a36Sopenharmony_ci struct device_attribute *attr, 72562306a36Sopenharmony_ci const char *buf, size_t count) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct otx_cptvf *cptvf = dev_get_drvdata(dev); 72862306a36Sopenharmony_ci long val; 72962306a36Sopenharmony_ci int ret; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 73262306a36Sopenharmony_ci if (ret != 0) 73362306a36Sopenharmony_ci return ret; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (val < OTX_CPT_COALESC_MIN_TIME_WAIT || 73662306a36Sopenharmony_ci val > OTX_CPT_COALESC_MAX_TIME_WAIT) 73762306a36Sopenharmony_ci return -EINVAL; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci cptvf_write_vq_done_timewait(cptvf, val); 74062306a36Sopenharmony_ci return count; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic ssize_t vf_coalesc_num_wait_store(struct device *dev, 74462306a36Sopenharmony_ci struct device_attribute *attr, 74562306a36Sopenharmony_ci const char *buf, size_t count) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct otx_cptvf *cptvf = dev_get_drvdata(dev); 74862306a36Sopenharmony_ci long val; 74962306a36Sopenharmony_ci int ret; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci ret = kstrtol(buf, 10, &val); 75262306a36Sopenharmony_ci if (ret != 0) 75362306a36Sopenharmony_ci return ret; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (val < OTX_CPT_COALESC_MIN_NUM_WAIT || 75662306a36Sopenharmony_ci val > OTX_CPT_COALESC_MAX_NUM_WAIT) 75762306a36Sopenharmony_ci return -EINVAL; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci cptvf_write_vq_done_numwait(cptvf, val); 76062306a36Sopenharmony_ci return count; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(vf_type); 76462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(vf_engine_group); 76562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(vf_coalesc_time_wait); 76662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(vf_coalesc_num_wait); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic struct attribute *otx_cptvf_attrs[] = { 76962306a36Sopenharmony_ci &dev_attr_vf_type.attr, 77062306a36Sopenharmony_ci &dev_attr_vf_engine_group.attr, 77162306a36Sopenharmony_ci &dev_attr_vf_coalesc_time_wait.attr, 77262306a36Sopenharmony_ci &dev_attr_vf_coalesc_num_wait.attr, 77362306a36Sopenharmony_ci NULL 77462306a36Sopenharmony_ci}; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic const struct attribute_group otx_cptvf_sysfs_group = { 77762306a36Sopenharmony_ci .attrs = otx_cptvf_attrs, 77862306a36Sopenharmony_ci}; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int otx_cptvf_probe(struct pci_dev *pdev, 78162306a36Sopenharmony_ci const struct pci_device_id *ent) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 78462306a36Sopenharmony_ci struct otx_cptvf *cptvf; 78562306a36Sopenharmony_ci int err; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci cptvf = devm_kzalloc(dev, sizeof(*cptvf), GFP_KERNEL); 78862306a36Sopenharmony_ci if (!cptvf) 78962306a36Sopenharmony_ci return -ENOMEM; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci pci_set_drvdata(pdev, cptvf); 79262306a36Sopenharmony_ci cptvf->pdev = pdev; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci err = pci_enable_device(pdev); 79562306a36Sopenharmony_ci if (err) { 79662306a36Sopenharmony_ci dev_err(dev, "Failed to enable PCI device\n"); 79762306a36Sopenharmony_ci goto clear_drvdata; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 80062306a36Sopenharmony_ci if (err) { 80162306a36Sopenharmony_ci dev_err(dev, "PCI request regions failed 0x%x\n", err); 80262306a36Sopenharmony_ci goto disable_device; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); 80562306a36Sopenharmony_ci if (err) { 80662306a36Sopenharmony_ci dev_err(dev, "Unable to get usable 48-bit DMA configuration\n"); 80762306a36Sopenharmony_ci goto release_regions; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* MAP PF's configuration registers */ 81162306a36Sopenharmony_ci cptvf->reg_base = pci_iomap(pdev, OTX_CPT_VF_PCI_CFG_BAR, 0); 81262306a36Sopenharmony_ci if (!cptvf->reg_base) { 81362306a36Sopenharmony_ci dev_err(dev, "Cannot map config register space, aborting\n"); 81462306a36Sopenharmony_ci err = -ENOMEM; 81562306a36Sopenharmony_ci goto release_regions; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci cptvf->node = dev_to_node(&pdev->dev); 81962306a36Sopenharmony_ci err = pci_alloc_irq_vectors(pdev, OTX_CPT_VF_MSIX_VECTORS, 82062306a36Sopenharmony_ci OTX_CPT_VF_MSIX_VECTORS, PCI_IRQ_MSIX); 82162306a36Sopenharmony_ci if (err < 0) { 82262306a36Sopenharmony_ci dev_err(dev, "Request for #%d msix vectors failed\n", 82362306a36Sopenharmony_ci OTX_CPT_VF_MSIX_VECTORS); 82462306a36Sopenharmony_ci goto unmap_region; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), 82862306a36Sopenharmony_ci cptvf_misc_intr_handler, 0, "CPT VF misc intr", 82962306a36Sopenharmony_ci cptvf); 83062306a36Sopenharmony_ci if (err) { 83162306a36Sopenharmony_ci dev_err(dev, "Failed to request misc irq\n"); 83262306a36Sopenharmony_ci goto free_vectors; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* Enable mailbox interrupt */ 83662306a36Sopenharmony_ci cptvf_enable_mbox_interrupts(cptvf); 83762306a36Sopenharmony_ci cptvf_enable_swerr_interrupts(cptvf); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* Check cpt pf status, gets chip ID / device Id from PF if ready */ 84062306a36Sopenharmony_ci err = otx_cptvf_check_pf_ready(cptvf); 84162306a36Sopenharmony_ci if (err) 84262306a36Sopenharmony_ci goto free_misc_irq; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* CPT VF software resources initialization */ 84562306a36Sopenharmony_ci cptvf->cqinfo.qchunksize = OTX_CPT_CMD_QCHUNK_SIZE; 84662306a36Sopenharmony_ci err = cptvf_sw_init(cptvf, OTX_CPT_CMD_QLEN, OTX_CPT_NUM_QS_PER_VF); 84762306a36Sopenharmony_ci if (err) { 84862306a36Sopenharmony_ci dev_err(dev, "cptvf_sw_init() failed\n"); 84962306a36Sopenharmony_ci goto free_misc_irq; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci /* Convey VQ LEN to PF */ 85262306a36Sopenharmony_ci err = otx_cptvf_send_vq_size_msg(cptvf); 85362306a36Sopenharmony_ci if (err) 85462306a36Sopenharmony_ci goto sw_cleanup; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* CPT VF device initialization */ 85762306a36Sopenharmony_ci cptvf_device_init(cptvf); 85862306a36Sopenharmony_ci /* Send msg to PF to assign currnet Q to required group */ 85962306a36Sopenharmony_ci err = otx_cptvf_send_vf_to_grp_msg(cptvf, cptvf->vfgrp); 86062306a36Sopenharmony_ci if (err) 86162306a36Sopenharmony_ci goto sw_cleanup; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci cptvf->priority = 1; 86462306a36Sopenharmony_ci err = otx_cptvf_send_vf_priority_msg(cptvf); 86562306a36Sopenharmony_ci if (err) 86662306a36Sopenharmony_ci goto sw_cleanup; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), 86962306a36Sopenharmony_ci cptvf_done_intr_handler, 0, "CPT VF done intr", 87062306a36Sopenharmony_ci cptvf); 87162306a36Sopenharmony_ci if (err) { 87262306a36Sopenharmony_ci dev_err(dev, "Failed to request done irq\n"); 87362306a36Sopenharmony_ci goto free_done_irq; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* Enable done interrupt */ 87762306a36Sopenharmony_ci cptvf_enable_done_interrupts(cptvf); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* Set irq affinity masks */ 88062306a36Sopenharmony_ci cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 88162306a36Sopenharmony_ci cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci err = otx_cptvf_send_vf_up(cptvf); 88462306a36Sopenharmony_ci if (err) 88562306a36Sopenharmony_ci goto free_irq_affinity; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Initialize algorithms and set ops */ 88862306a36Sopenharmony_ci err = otx_cpt_crypto_init(pdev, THIS_MODULE, 88962306a36Sopenharmony_ci cptvf->vftype == OTX_CPT_SE_TYPES ? OTX_CPT_SE : OTX_CPT_AE, 89062306a36Sopenharmony_ci cptvf->vftype, 1, cptvf->num_vfs); 89162306a36Sopenharmony_ci if (err) { 89262306a36Sopenharmony_ci dev_err(dev, "Failed to register crypto algs\n"); 89362306a36Sopenharmony_ci goto free_irq_affinity; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci err = sysfs_create_group(&dev->kobj, &otx_cptvf_sysfs_group); 89762306a36Sopenharmony_ci if (err) { 89862306a36Sopenharmony_ci dev_err(dev, "Creating sysfs entries failed\n"); 89962306a36Sopenharmony_ci goto crypto_exit; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci return 0; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cicrypto_exit: 90562306a36Sopenharmony_ci otx_cpt_crypto_exit(pdev, THIS_MODULE, cptvf->vftype); 90662306a36Sopenharmony_cifree_irq_affinity: 90762306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 90862306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 90962306a36Sopenharmony_cifree_done_irq: 91062306a36Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), cptvf); 91162306a36Sopenharmony_cisw_cleanup: 91262306a36Sopenharmony_ci cptvf_sw_cleanup(cptvf); 91362306a36Sopenharmony_cifree_misc_irq: 91462306a36Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf); 91562306a36Sopenharmony_cifree_vectors: 91662306a36Sopenharmony_ci pci_free_irq_vectors(cptvf->pdev); 91762306a36Sopenharmony_ciunmap_region: 91862306a36Sopenharmony_ci pci_iounmap(pdev, cptvf->reg_base); 91962306a36Sopenharmony_cirelease_regions: 92062306a36Sopenharmony_ci pci_release_regions(pdev); 92162306a36Sopenharmony_cidisable_device: 92262306a36Sopenharmony_ci pci_disable_device(pdev); 92362306a36Sopenharmony_ciclear_drvdata: 92462306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci return err; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic void otx_cptvf_remove(struct pci_dev *pdev) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci struct otx_cptvf *cptvf = pci_get_drvdata(pdev); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (!cptvf) { 93462306a36Sopenharmony_ci dev_err(&pdev->dev, "Invalid CPT-VF device\n"); 93562306a36Sopenharmony_ci return; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Convey DOWN to PF */ 93962306a36Sopenharmony_ci if (otx_cptvf_send_vf_down(cptvf)) { 94062306a36Sopenharmony_ci dev_err(&pdev->dev, "PF not responding to DOWN msg\n"); 94162306a36Sopenharmony_ci } else { 94262306a36Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &otx_cptvf_sysfs_group); 94362306a36Sopenharmony_ci otx_cpt_crypto_exit(pdev, THIS_MODULE, cptvf->vftype); 94462306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 94562306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 94662306a36Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), cptvf); 94762306a36Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf); 94862306a36Sopenharmony_ci cptvf_sw_cleanup(cptvf); 94962306a36Sopenharmony_ci pci_free_irq_vectors(cptvf->pdev); 95062306a36Sopenharmony_ci pci_iounmap(pdev, cptvf->reg_base); 95162306a36Sopenharmony_ci pci_release_regions(pdev); 95262306a36Sopenharmony_ci pci_disable_device(pdev); 95362306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci/* Supported devices */ 95862306a36Sopenharmony_cistatic const struct pci_device_id otx_cptvf_id_table[] = { 95962306a36Sopenharmony_ci {PCI_VDEVICE(CAVIUM, OTX_CPT_PCI_VF_DEVICE_ID), 0}, 96062306a36Sopenharmony_ci { 0, } /* end of table */ 96162306a36Sopenharmony_ci}; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic struct pci_driver otx_cptvf_pci_driver = { 96462306a36Sopenharmony_ci .name = DRV_NAME, 96562306a36Sopenharmony_ci .id_table = otx_cptvf_id_table, 96662306a36Sopenharmony_ci .probe = otx_cptvf_probe, 96762306a36Sopenharmony_ci .remove = otx_cptvf_remove, 96862306a36Sopenharmony_ci}; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cimodule_pci_driver(otx_cptvf_pci_driver); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ciMODULE_AUTHOR("Marvell International Ltd."); 97362306a36Sopenharmony_ciMODULE_DESCRIPTION("Marvell OcteonTX CPT Virtual Function Driver"); 97462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 97562306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 97662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, otx_cptvf_id_table); 977