162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Cavium, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/interrupt.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "cptvf.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define DRV_NAME "thunder-cptvf" 1262306a36Sopenharmony_ci#define DRV_VERSION "1.0" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistruct cptvf_wqe { 1562306a36Sopenharmony_ci struct tasklet_struct twork; 1662306a36Sopenharmony_ci void *cptvf; 1762306a36Sopenharmony_ci u32 qno; 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct cptvf_wqe_info { 2162306a36Sopenharmony_ci struct cptvf_wqe vq_wqe[CPT_NUM_QS_PER_VF]; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void vq_work_handler(unsigned long data) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct cptvf_wqe_info *cwqe_info = (struct cptvf_wqe_info *)data; 2762306a36Sopenharmony_ci struct cptvf_wqe *cwqe = &cwqe_info->vq_wqe[0]; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci vq_post_process(cwqe->cptvf, cwqe->qno); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int init_worker_threads(struct cpt_vf *cptvf) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 3562306a36Sopenharmony_ci struct cptvf_wqe_info *cwqe_info; 3662306a36Sopenharmony_ci int i; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci cwqe_info = kzalloc(sizeof(*cwqe_info), GFP_KERNEL); 3962306a36Sopenharmony_ci if (!cwqe_info) 4062306a36Sopenharmony_ci return -ENOMEM; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (cptvf->nr_queues) { 4362306a36Sopenharmony_ci dev_info(&pdev->dev, "Creating VQ worker threads (%d)\n", 4462306a36Sopenharmony_ci cptvf->nr_queues); 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) { 4862306a36Sopenharmony_ci tasklet_init(&cwqe_info->vq_wqe[i].twork, vq_work_handler, 4962306a36Sopenharmony_ci (u64)cwqe_info); 5062306a36Sopenharmony_ci cwqe_info->vq_wqe[i].qno = i; 5162306a36Sopenharmony_ci cwqe_info->vq_wqe[i].cptvf = cptvf; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci cptvf->wqe_info = cwqe_info; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void cleanup_worker_threads(struct cpt_vf *cptvf) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct cptvf_wqe_info *cwqe_info; 6262306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 6362306a36Sopenharmony_ci int i; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci cwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info; 6662306a36Sopenharmony_ci if (!cwqe_info) 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (cptvf->nr_queues) { 7062306a36Sopenharmony_ci dev_info(&pdev->dev, "Cleaning VQ worker threads (%u)\n", 7162306a36Sopenharmony_ci cptvf->nr_queues); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) 7562306a36Sopenharmony_ci tasklet_kill(&cwqe_info->vq_wqe[i].twork); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci kfree_sensitive(cwqe_info); 7862306a36Sopenharmony_ci cptvf->wqe_info = NULL; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void free_pending_queues(struct pending_qinfo *pqinfo) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci int i; 8462306a36Sopenharmony_ci struct pending_queue *queue; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for_each_pending_queue(pqinfo, queue, i) { 8762306a36Sopenharmony_ci if (!queue->head) 8862306a36Sopenharmony_ci continue; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* free single queue */ 9162306a36Sopenharmony_ci kfree_sensitive((queue->head)); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci queue->front = 0; 9462306a36Sopenharmony_ci queue->rear = 0; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci pqinfo->qlen = 0; 10062306a36Sopenharmony_ci pqinfo->nr_queues = 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int alloc_pending_queues(struct pending_qinfo *pqinfo, u32 qlen, 10462306a36Sopenharmony_ci u32 nr_queues) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci u32 i; 10762306a36Sopenharmony_ci int ret; 10862306a36Sopenharmony_ci struct pending_queue *queue = NULL; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci pqinfo->nr_queues = nr_queues; 11162306a36Sopenharmony_ci pqinfo->qlen = qlen; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for_each_pending_queue(pqinfo, queue, i) { 11462306a36Sopenharmony_ci queue->head = kcalloc(qlen, sizeof(*queue->head), GFP_KERNEL); 11562306a36Sopenharmony_ci if (!queue->head) { 11662306a36Sopenharmony_ci ret = -ENOMEM; 11762306a36Sopenharmony_ci goto pending_qfail; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci queue->front = 0; 12162306a36Sopenharmony_ci queue->rear = 0; 12262306a36Sopenharmony_ci atomic64_set((&queue->pending_count), (0)); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* init queue spin lock */ 12562306a36Sopenharmony_ci spin_lock_init(&queue->lock); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cipending_qfail: 13162306a36Sopenharmony_ci free_pending_queues(pqinfo); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return ret; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int init_pending_queues(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 13962306a36Sopenharmony_ci int ret; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (!nr_queues) 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ret = alloc_pending_queues(&cptvf->pqinfo, qlen, nr_queues); 14562306a36Sopenharmony_ci if (ret) { 14662306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to setup pending queues (%u)\n", 14762306a36Sopenharmony_ci nr_queues); 14862306a36Sopenharmony_ci return ret; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void cleanup_pending_queues(struct cpt_vf *cptvf) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (!cptvf->nr_queues) 15962306a36Sopenharmony_ci return; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci dev_info(&pdev->dev, "Cleaning VQ pending queue (%u)\n", 16262306a36Sopenharmony_ci cptvf->nr_queues); 16362306a36Sopenharmony_ci free_pending_queues(&cptvf->pqinfo); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic void free_command_queues(struct cpt_vf *cptvf, 16762306a36Sopenharmony_ci struct command_qinfo *cqinfo) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci int i; 17062306a36Sopenharmony_ci struct command_queue *queue = NULL; 17162306a36Sopenharmony_ci struct command_chunk *chunk = NULL; 17262306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 17362306a36Sopenharmony_ci struct hlist_node *node; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* clean up for each queue */ 17662306a36Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) { 17762306a36Sopenharmony_ci queue = &cqinfo->queue[i]; 17862306a36Sopenharmony_ci if (hlist_empty(&cqinfo->queue[i].chead)) 17962306a36Sopenharmony_ci continue; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, 18262306a36Sopenharmony_ci nextchunk) { 18362306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, chunk->size, 18462306a36Sopenharmony_ci chunk->head, 18562306a36Sopenharmony_ci chunk->dma_addr); 18662306a36Sopenharmony_ci chunk->head = NULL; 18762306a36Sopenharmony_ci chunk->dma_addr = 0; 18862306a36Sopenharmony_ci hlist_del(&chunk->nextchunk); 18962306a36Sopenharmony_ci kfree_sensitive(chunk); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci queue->nchunks = 0; 19362306a36Sopenharmony_ci queue->idx = 0; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* common cleanup */ 19762306a36Sopenharmony_ci cqinfo->cmd_size = 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int alloc_command_queues(struct cpt_vf *cptvf, 20162306a36Sopenharmony_ci struct command_qinfo *cqinfo, size_t cmd_size, 20262306a36Sopenharmony_ci u32 qlen) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci int i; 20562306a36Sopenharmony_ci size_t q_size; 20662306a36Sopenharmony_ci struct command_queue *queue = NULL; 20762306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* common init */ 21062306a36Sopenharmony_ci cqinfo->cmd_size = cmd_size; 21162306a36Sopenharmony_ci /* Qsize in dwords, needed for SADDR config, 1-next chunk pointer */ 21262306a36Sopenharmony_ci cptvf->qsize = min(qlen, cqinfo->qchunksize) * 21362306a36Sopenharmony_ci CPT_NEXT_CHUNK_PTR_SIZE + 1; 21462306a36Sopenharmony_ci /* Qsize in bytes to create space for alignment */ 21562306a36Sopenharmony_ci q_size = qlen * cqinfo->cmd_size; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* per queue initialization */ 21862306a36Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) { 21962306a36Sopenharmony_ci size_t c_size = 0; 22062306a36Sopenharmony_ci size_t rem_q_size = q_size; 22162306a36Sopenharmony_ci struct command_chunk *curr = NULL, *first = NULL, *last = NULL; 22262306a36Sopenharmony_ci u32 qcsize_bytes = cqinfo->qchunksize * cqinfo->cmd_size; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci queue = &cqinfo->queue[i]; 22562306a36Sopenharmony_ci INIT_HLIST_HEAD(&cqinfo->queue[i].chead); 22662306a36Sopenharmony_ci do { 22762306a36Sopenharmony_ci curr = kzalloc(sizeof(*curr), GFP_KERNEL); 22862306a36Sopenharmony_ci if (!curr) 22962306a36Sopenharmony_ci goto cmd_qfail; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci c_size = (rem_q_size > qcsize_bytes) ? qcsize_bytes : 23262306a36Sopenharmony_ci rem_q_size; 23362306a36Sopenharmony_ci curr->head = dma_alloc_coherent(&pdev->dev, 23462306a36Sopenharmony_ci c_size + CPT_NEXT_CHUNK_PTR_SIZE, 23562306a36Sopenharmony_ci &curr->dma_addr, 23662306a36Sopenharmony_ci GFP_KERNEL); 23762306a36Sopenharmony_ci if (!curr->head) { 23862306a36Sopenharmony_ci dev_err(&pdev->dev, "Command Q (%d) chunk (%d) allocation failed\n", 23962306a36Sopenharmony_ci i, queue->nchunks); 24062306a36Sopenharmony_ci kfree(curr); 24162306a36Sopenharmony_ci goto cmd_qfail; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci curr->size = c_size; 24562306a36Sopenharmony_ci if (queue->nchunks == 0) { 24662306a36Sopenharmony_ci hlist_add_head(&curr->nextchunk, 24762306a36Sopenharmony_ci &cqinfo->queue[i].chead); 24862306a36Sopenharmony_ci first = curr; 24962306a36Sopenharmony_ci } else { 25062306a36Sopenharmony_ci hlist_add_behind(&curr->nextchunk, 25162306a36Sopenharmony_ci &last->nextchunk); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci queue->nchunks++; 25562306a36Sopenharmony_ci rem_q_size -= c_size; 25662306a36Sopenharmony_ci if (last) 25762306a36Sopenharmony_ci *((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci last = curr; 26062306a36Sopenharmony_ci } while (rem_q_size); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* Make the queue circular */ 26362306a36Sopenharmony_ci /* Tie back last chunk entry to head */ 26462306a36Sopenharmony_ci curr = first; 26562306a36Sopenharmony_ci *((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr; 26662306a36Sopenharmony_ci queue->qhead = curr; 26762306a36Sopenharmony_ci spin_lock_init(&queue->lock); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cicmd_qfail: 27262306a36Sopenharmony_ci free_command_queues(cptvf, cqinfo); 27362306a36Sopenharmony_ci return -ENOMEM; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int init_command_queues(struct cpt_vf *cptvf, u32 qlen) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 27962306a36Sopenharmony_ci int ret; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* setup AE command queues */ 28262306a36Sopenharmony_ci ret = alloc_command_queues(cptvf, &cptvf->cqinfo, CPT_INST_SIZE, 28362306a36Sopenharmony_ci qlen); 28462306a36Sopenharmony_ci if (ret) { 28562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate AE command queues (%u)\n", 28662306a36Sopenharmony_ci cptvf->nr_queues); 28762306a36Sopenharmony_ci return ret; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic void cleanup_command_queues(struct cpt_vf *cptvf) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (!cptvf->nr_queues) 29862306a36Sopenharmony_ci return; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci dev_info(&pdev->dev, "Cleaning VQ command queue (%u)\n", 30162306a36Sopenharmony_ci cptvf->nr_queues); 30262306a36Sopenharmony_ci free_command_queues(cptvf, &cptvf->cqinfo); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic void cptvf_sw_cleanup(struct cpt_vf *cptvf) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci cleanup_worker_threads(cptvf); 30862306a36Sopenharmony_ci cleanup_pending_queues(cptvf); 30962306a36Sopenharmony_ci cleanup_command_queues(cptvf); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int cptvf_sw_init(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 31562306a36Sopenharmony_ci int ret = 0; 31662306a36Sopenharmony_ci u32 max_dev_queues = 0; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci max_dev_queues = CPT_NUM_QS_PER_VF; 31962306a36Sopenharmony_ci /* possible cpus */ 32062306a36Sopenharmony_ci nr_queues = min_t(u32, nr_queues, max_dev_queues); 32162306a36Sopenharmony_ci cptvf->nr_queues = nr_queues; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ret = init_command_queues(cptvf, qlen); 32462306a36Sopenharmony_ci if (ret) { 32562306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup command queues (%u)\n", 32662306a36Sopenharmony_ci nr_queues); 32762306a36Sopenharmony_ci return ret; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ret = init_pending_queues(cptvf, qlen, nr_queues); 33162306a36Sopenharmony_ci if (ret) { 33262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup pending queues (%u)\n", 33362306a36Sopenharmony_ci nr_queues); 33462306a36Sopenharmony_ci goto setup_pqfail; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Create worker threads for BH processing */ 33862306a36Sopenharmony_ci ret = init_worker_threads(cptvf); 33962306a36Sopenharmony_ci if (ret) { 34062306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup worker threads\n"); 34162306a36Sopenharmony_ci goto init_work_fail; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ciinit_work_fail: 34762306a36Sopenharmony_ci cleanup_worker_threads(cptvf); 34862306a36Sopenharmony_ci cleanup_pending_queues(cptvf); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cisetup_pqfail: 35162306a36Sopenharmony_ci cleanup_command_queues(cptvf); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return ret; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void cptvf_free_irq_affinity(struct cpt_vf *cptvf, int vec) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci irq_set_affinity_hint(pci_irq_vector(cptvf->pdev, vec), NULL); 35962306a36Sopenharmony_ci free_cpumask_var(cptvf->affinity_mask[vec]); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void cptvf_write_vq_ctl(struct cpt_vf *cptvf, bool val) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci union cptx_vqx_ctl vqx_ctl; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci vqx_ctl.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0)); 36762306a36Sopenharmony_ci vqx_ctl.s.ena = val; 36862306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0), vqx_ctl.u); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_civoid cptvf_write_vq_doorbell(struct cpt_vf *cptvf, u32 val) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci union cptx_vqx_doorbell vqx_dbell; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci vqx_dbell.u = cpt_read_csr64(cptvf->reg_base, 37662306a36Sopenharmony_ci CPTX_VQX_DOORBELL(0, 0)); 37762306a36Sopenharmony_ci vqx_dbell.s.dbell_cnt = val * 8; /* Num of Instructions * 8 words */ 37862306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DOORBELL(0, 0), 37962306a36Sopenharmony_ci vqx_dbell.u); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void cptvf_write_vq_inprog(struct cpt_vf *cptvf, u8 val) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci union cptx_vqx_inprog vqx_inprg; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci vqx_inprg.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0)); 38762306a36Sopenharmony_ci vqx_inprg.s.inflight = val; 38862306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0), vqx_inprg.u); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void cptvf_write_vq_done_numwait(struct cpt_vf *cptvf, u32 val) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci union cptx_vqx_done_wait vqx_dwait; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci vqx_dwait.u = cpt_read_csr64(cptvf->reg_base, 39662306a36Sopenharmony_ci CPTX_VQX_DONE_WAIT(0, 0)); 39762306a36Sopenharmony_ci vqx_dwait.s.num_wait = val; 39862306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0), 39962306a36Sopenharmony_ci vqx_dwait.u); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void cptvf_write_vq_done_timewait(struct cpt_vf *cptvf, u16 time) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci union cptx_vqx_done_wait vqx_dwait; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci vqx_dwait.u = cpt_read_csr64(cptvf->reg_base, 40762306a36Sopenharmony_ci CPTX_VQX_DONE_WAIT(0, 0)); 40862306a36Sopenharmony_ci vqx_dwait.s.time_wait = time; 40962306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0), 41062306a36Sopenharmony_ci vqx_dwait.u); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void cptvf_enable_swerr_interrupts(struct cpt_vf *cptvf) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci union cptx_vqx_misc_ena_w1s vqx_misc_ena; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base, 41862306a36Sopenharmony_ci CPTX_VQX_MISC_ENA_W1S(0, 0)); 41962306a36Sopenharmony_ci /* Set mbox(0) interupts for the requested vf */ 42062306a36Sopenharmony_ci vqx_misc_ena.s.swerr = 1; 42162306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0), 42262306a36Sopenharmony_ci vqx_misc_ena.u); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic void cptvf_enable_mbox_interrupts(struct cpt_vf *cptvf) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci union cptx_vqx_misc_ena_w1s vqx_misc_ena; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base, 43062306a36Sopenharmony_ci CPTX_VQX_MISC_ENA_W1S(0, 0)); 43162306a36Sopenharmony_ci /* Set mbox(0) interupts for the requested vf */ 43262306a36Sopenharmony_ci vqx_misc_ena.s.mbox = 1; 43362306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0), 43462306a36Sopenharmony_ci vqx_misc_ena.u); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void cptvf_enable_done_interrupts(struct cpt_vf *cptvf) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci union cptx_vqx_done_ena_w1s vqx_done_ena; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci vqx_done_ena.u = cpt_read_csr64(cptvf->reg_base, 44262306a36Sopenharmony_ci CPTX_VQX_DONE_ENA_W1S(0, 0)); 44362306a36Sopenharmony_ci /* Set DONE interrupt for the requested vf */ 44462306a36Sopenharmony_ci vqx_done_ena.s.done = 1; 44562306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ENA_W1S(0, 0), 44662306a36Sopenharmony_ci vqx_done_ena.u); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic void cptvf_clear_dovf_intr(struct cpt_vf *cptvf) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 45462306a36Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 45562306a36Sopenharmony_ci /* W1C for the VF */ 45662306a36Sopenharmony_ci vqx_misc_int.s.dovf = 1; 45762306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 45862306a36Sopenharmony_ci vqx_misc_int.u); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void cptvf_clear_irde_intr(struct cpt_vf *cptvf) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 46662306a36Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 46762306a36Sopenharmony_ci /* W1C for the VF */ 46862306a36Sopenharmony_ci vqx_misc_int.s.irde = 1; 46962306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 47062306a36Sopenharmony_ci vqx_misc_int.u); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic void cptvf_clear_nwrp_intr(struct cpt_vf *cptvf) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 47862306a36Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 47962306a36Sopenharmony_ci /* W1C for the VF */ 48062306a36Sopenharmony_ci vqx_misc_int.s.nwrp = 1; 48162306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, 48262306a36Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0), vqx_misc_int.u); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic void cptvf_clear_mbox_intr(struct cpt_vf *cptvf) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 49062306a36Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 49162306a36Sopenharmony_ci /* W1C for the VF */ 49262306a36Sopenharmony_ci vqx_misc_int.s.mbox = 1; 49362306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 49462306a36Sopenharmony_ci vqx_misc_int.u); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic void cptvf_clear_swerr_intr(struct cpt_vf *cptvf) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 50262306a36Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 50362306a36Sopenharmony_ci /* W1C for the VF */ 50462306a36Sopenharmony_ci vqx_misc_int.s.swerr = 1; 50562306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 50662306a36Sopenharmony_ci vqx_misc_int.u); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic u64 cptvf_read_vf_misc_intr_status(struct cpt_vf *cptvf) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci return cpt_read_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0)); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic irqreturn_t cptvf_misc_intr_handler(int irq, void *cptvf_irq) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq; 51762306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 51862306a36Sopenharmony_ci u64 intr; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci intr = cptvf_read_vf_misc_intr_status(cptvf); 52162306a36Sopenharmony_ci /*Check for MISC interrupt types*/ 52262306a36Sopenharmony_ci if (likely(intr & CPT_VF_INTR_MBOX_MASK)) { 52362306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Mailbox interrupt 0x%llx on CPT VF %d\n", 52462306a36Sopenharmony_ci intr, cptvf->vfid); 52562306a36Sopenharmony_ci cptvf_handle_mbox_intr(cptvf); 52662306a36Sopenharmony_ci cptvf_clear_mbox_intr(cptvf); 52762306a36Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_DOVF_MASK)) { 52862306a36Sopenharmony_ci cptvf_clear_dovf_intr(cptvf); 52962306a36Sopenharmony_ci /*Clear doorbell count*/ 53062306a36Sopenharmony_ci cptvf_write_vq_doorbell(cptvf, 0); 53162306a36Sopenharmony_ci dev_err(&pdev->dev, "Doorbell overflow error interrupt 0x%llx on CPT VF %d\n", 53262306a36Sopenharmony_ci intr, cptvf->vfid); 53362306a36Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_IRDE_MASK)) { 53462306a36Sopenharmony_ci cptvf_clear_irde_intr(cptvf); 53562306a36Sopenharmony_ci dev_err(&pdev->dev, "Instruction NCB read error interrupt 0x%llx on CPT VF %d\n", 53662306a36Sopenharmony_ci intr, cptvf->vfid); 53762306a36Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_NWRP_MASK)) { 53862306a36Sopenharmony_ci cptvf_clear_nwrp_intr(cptvf); 53962306a36Sopenharmony_ci dev_err(&pdev->dev, "NCB response write error interrupt 0x%llx on CPT VF %d\n", 54062306a36Sopenharmony_ci intr, cptvf->vfid); 54162306a36Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_SERR_MASK)) { 54262306a36Sopenharmony_ci cptvf_clear_swerr_intr(cptvf); 54362306a36Sopenharmony_ci dev_err(&pdev->dev, "Software error interrupt 0x%llx on CPT VF %d\n", 54462306a36Sopenharmony_ci intr, cptvf->vfid); 54562306a36Sopenharmony_ci } else { 54662306a36Sopenharmony_ci dev_err(&pdev->dev, "Unhandled interrupt in CPT VF %d\n", 54762306a36Sopenharmony_ci cptvf->vfid); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return IRQ_HANDLED; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic inline struct cptvf_wqe *get_cptvf_vq_wqe(struct cpt_vf *cptvf, 55462306a36Sopenharmony_ci int qno) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct cptvf_wqe_info *nwqe_info; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (unlikely(qno >= cptvf->nr_queues)) 55962306a36Sopenharmony_ci return NULL; 56062306a36Sopenharmony_ci nwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return &nwqe_info->vq_wqe[qno]; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic inline u32 cptvf_read_vq_done_count(struct cpt_vf *cptvf) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci union cptx_vqx_done vqx_done; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci vqx_done.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_DONE(0, 0)); 57062306a36Sopenharmony_ci return vqx_done.s.done; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic inline void cptvf_write_vq_done_ack(struct cpt_vf *cptvf, 57462306a36Sopenharmony_ci u32 ackcnt) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci union cptx_vqx_done_ack vqx_dack_cnt; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci vqx_dack_cnt.u = cpt_read_csr64(cptvf->reg_base, 57962306a36Sopenharmony_ci CPTX_VQX_DONE_ACK(0, 0)); 58062306a36Sopenharmony_ci vqx_dack_cnt.s.done_ack = ackcnt; 58162306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ACK(0, 0), 58262306a36Sopenharmony_ci vqx_dack_cnt.u); 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic irqreturn_t cptvf_done_intr_handler(int irq, void *cptvf_irq) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq; 58862306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 58962306a36Sopenharmony_ci /* Read the number of completions */ 59062306a36Sopenharmony_ci u32 intr = cptvf_read_vq_done_count(cptvf); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (intr) { 59362306a36Sopenharmony_ci struct cptvf_wqe *wqe; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Acknowledge the number of 59662306a36Sopenharmony_ci * scheduled completions for processing 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ci cptvf_write_vq_done_ack(cptvf, intr); 59962306a36Sopenharmony_ci wqe = get_cptvf_vq_wqe(cptvf, 0); 60062306a36Sopenharmony_ci if (unlikely(!wqe)) { 60162306a36Sopenharmony_ci dev_err(&pdev->dev, "No work to schedule for VF (%d)", 60262306a36Sopenharmony_ci cptvf->vfid); 60362306a36Sopenharmony_ci return IRQ_NONE; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci tasklet_hi_schedule(&wqe->twork); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return IRQ_HANDLED; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic void cptvf_set_irq_affinity(struct cpt_vf *cptvf, int vec) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 61462306a36Sopenharmony_ci int cpu; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (!zalloc_cpumask_var(&cptvf->affinity_mask[vec], 61762306a36Sopenharmony_ci GFP_KERNEL)) { 61862306a36Sopenharmony_ci dev_err(&pdev->dev, "Allocation failed for affinity_mask for VF %d", 61962306a36Sopenharmony_ci cptvf->vfid); 62062306a36Sopenharmony_ci return; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci cpu = cptvf->vfid % num_online_cpus(); 62462306a36Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(cpu, cptvf->node), 62562306a36Sopenharmony_ci cptvf->affinity_mask[vec]); 62662306a36Sopenharmony_ci irq_set_affinity_hint(pci_irq_vector(pdev, vec), 62762306a36Sopenharmony_ci cptvf->affinity_mask[vec]); 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic void cptvf_write_vq_saddr(struct cpt_vf *cptvf, u64 val) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci union cptx_vqx_saddr vqx_saddr; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci vqx_saddr.u = val; 63562306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_SADDR(0, 0), vqx_saddr.u); 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic void cptvf_device_init(struct cpt_vf *cptvf) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci u64 base_addr = 0; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* Disable the VQ */ 64362306a36Sopenharmony_ci cptvf_write_vq_ctl(cptvf, 0); 64462306a36Sopenharmony_ci /* Reset the doorbell */ 64562306a36Sopenharmony_ci cptvf_write_vq_doorbell(cptvf, 0); 64662306a36Sopenharmony_ci /* Clear inflight */ 64762306a36Sopenharmony_ci cptvf_write_vq_inprog(cptvf, 0); 64862306a36Sopenharmony_ci /* Write VQ SADDR */ 64962306a36Sopenharmony_ci /* TODO: for now only one queue, so hard coded */ 65062306a36Sopenharmony_ci base_addr = (u64)(cptvf->cqinfo.queue[0].qhead->dma_addr); 65162306a36Sopenharmony_ci cptvf_write_vq_saddr(cptvf, base_addr); 65262306a36Sopenharmony_ci /* Configure timerhold / coalescence */ 65362306a36Sopenharmony_ci cptvf_write_vq_done_timewait(cptvf, CPT_TIMER_THOLD); 65462306a36Sopenharmony_ci cptvf_write_vq_done_numwait(cptvf, 1); 65562306a36Sopenharmony_ci /* Enable the VQ */ 65662306a36Sopenharmony_ci cptvf_write_vq_ctl(cptvf, 1); 65762306a36Sopenharmony_ci /* Flag the VF ready */ 65862306a36Sopenharmony_ci cptvf->flags |= CPT_FLAG_DEVICE_READY; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic int cptvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 66462306a36Sopenharmony_ci struct cpt_vf *cptvf; 66562306a36Sopenharmony_ci int err; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci cptvf = devm_kzalloc(dev, sizeof(*cptvf), GFP_KERNEL); 66862306a36Sopenharmony_ci if (!cptvf) 66962306a36Sopenharmony_ci return -ENOMEM; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci pci_set_drvdata(pdev, cptvf); 67262306a36Sopenharmony_ci cptvf->pdev = pdev; 67362306a36Sopenharmony_ci err = pci_enable_device(pdev); 67462306a36Sopenharmony_ci if (err) { 67562306a36Sopenharmony_ci dev_err(dev, "Failed to enable PCI device\n"); 67662306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 67762306a36Sopenharmony_ci return err; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 68162306a36Sopenharmony_ci if (err) { 68262306a36Sopenharmony_ci dev_err(dev, "PCI request regions failed 0x%x\n", err); 68362306a36Sopenharmony_ci goto cptvf_err_disable_device; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci /* Mark as VF driver */ 68662306a36Sopenharmony_ci cptvf->flags |= CPT_FLAG_VF_DRIVER; 68762306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); 68862306a36Sopenharmony_ci if (err) { 68962306a36Sopenharmony_ci dev_err(dev, "Unable to get usable 48-bit DMA configuration\n"); 69062306a36Sopenharmony_ci goto cptvf_err_release_regions; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* MAP PF's configuration registers */ 69462306a36Sopenharmony_ci cptvf->reg_base = pcim_iomap(pdev, 0, 0); 69562306a36Sopenharmony_ci if (!cptvf->reg_base) { 69662306a36Sopenharmony_ci dev_err(dev, "Cannot map config register space, aborting\n"); 69762306a36Sopenharmony_ci err = -ENOMEM; 69862306a36Sopenharmony_ci goto cptvf_err_release_regions; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci cptvf->node = dev_to_node(&pdev->dev); 70262306a36Sopenharmony_ci err = pci_alloc_irq_vectors(pdev, CPT_VF_MSIX_VECTORS, 70362306a36Sopenharmony_ci CPT_VF_MSIX_VECTORS, PCI_IRQ_MSIX); 70462306a36Sopenharmony_ci if (err < 0) { 70562306a36Sopenharmony_ci dev_err(dev, "Request for #%d msix vectors failed\n", 70662306a36Sopenharmony_ci CPT_VF_MSIX_VECTORS); 70762306a36Sopenharmony_ci goto cptvf_err_release_regions; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), 71162306a36Sopenharmony_ci cptvf_misc_intr_handler, 0, "CPT VF misc intr", 71262306a36Sopenharmony_ci cptvf); 71362306a36Sopenharmony_ci if (err) { 71462306a36Sopenharmony_ci dev_err(dev, "Request misc irq failed"); 71562306a36Sopenharmony_ci goto cptvf_free_vectors; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* Enable mailbox interrupt */ 71962306a36Sopenharmony_ci cptvf_enable_mbox_interrupts(cptvf); 72062306a36Sopenharmony_ci cptvf_enable_swerr_interrupts(cptvf); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* Check ready with PF */ 72362306a36Sopenharmony_ci /* Gets chip ID / device Id from PF if ready */ 72462306a36Sopenharmony_ci err = cptvf_check_pf_ready(cptvf); 72562306a36Sopenharmony_ci if (err) { 72662306a36Sopenharmony_ci dev_err(dev, "PF not responding to READY msg"); 72762306a36Sopenharmony_ci goto cptvf_free_misc_irq; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* CPT VF software resources initialization */ 73162306a36Sopenharmony_ci cptvf->cqinfo.qchunksize = CPT_CMD_QCHUNK_SIZE; 73262306a36Sopenharmony_ci err = cptvf_sw_init(cptvf, CPT_CMD_QLEN, CPT_NUM_QS_PER_VF); 73362306a36Sopenharmony_ci if (err) { 73462306a36Sopenharmony_ci dev_err(dev, "cptvf_sw_init() failed"); 73562306a36Sopenharmony_ci goto cptvf_free_misc_irq; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci /* Convey VQ LEN to PF */ 73862306a36Sopenharmony_ci err = cptvf_send_vq_size_msg(cptvf); 73962306a36Sopenharmony_ci if (err) { 74062306a36Sopenharmony_ci dev_err(dev, "PF not responding to QLEN msg"); 74162306a36Sopenharmony_ci goto cptvf_free_misc_irq; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* CPT VF device initialization */ 74562306a36Sopenharmony_ci cptvf_device_init(cptvf); 74662306a36Sopenharmony_ci /* Send msg to PF to assign currnet Q to required group */ 74762306a36Sopenharmony_ci cptvf->vfgrp = 1; 74862306a36Sopenharmony_ci err = cptvf_send_vf_to_grp_msg(cptvf); 74962306a36Sopenharmony_ci if (err) { 75062306a36Sopenharmony_ci dev_err(dev, "PF not responding to VF_GRP msg"); 75162306a36Sopenharmony_ci goto cptvf_free_misc_irq; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci cptvf->priority = 1; 75562306a36Sopenharmony_ci err = cptvf_send_vf_priority_msg(cptvf); 75662306a36Sopenharmony_ci if (err) { 75762306a36Sopenharmony_ci dev_err(dev, "PF not responding to VF_PRIO msg"); 75862306a36Sopenharmony_ci goto cptvf_free_misc_irq; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), 76262306a36Sopenharmony_ci cptvf_done_intr_handler, 0, "CPT VF done intr", 76362306a36Sopenharmony_ci cptvf); 76462306a36Sopenharmony_ci if (err) { 76562306a36Sopenharmony_ci dev_err(dev, "Request done irq failed\n"); 76662306a36Sopenharmony_ci goto cptvf_free_misc_irq; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Enable mailbox interrupt */ 77062306a36Sopenharmony_ci cptvf_enable_done_interrupts(cptvf); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Set irq affinity masks */ 77362306a36Sopenharmony_ci cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 77462306a36Sopenharmony_ci cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci err = cptvf_send_vf_up(cptvf); 77762306a36Sopenharmony_ci if (err) { 77862306a36Sopenharmony_ci dev_err(dev, "PF not responding to UP msg"); 77962306a36Sopenharmony_ci goto cptvf_free_irq_affinity; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci err = cvm_crypto_init(cptvf); 78262306a36Sopenharmony_ci if (err) { 78362306a36Sopenharmony_ci dev_err(dev, "Algorithm register failed\n"); 78462306a36Sopenharmony_ci goto cptvf_free_irq_affinity; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cicptvf_free_irq_affinity: 78962306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 79062306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 79162306a36Sopenharmony_cicptvf_free_misc_irq: 79262306a36Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf); 79362306a36Sopenharmony_cicptvf_free_vectors: 79462306a36Sopenharmony_ci pci_free_irq_vectors(cptvf->pdev); 79562306a36Sopenharmony_cicptvf_err_release_regions: 79662306a36Sopenharmony_ci pci_release_regions(pdev); 79762306a36Sopenharmony_cicptvf_err_disable_device: 79862306a36Sopenharmony_ci pci_disable_device(pdev); 79962306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return err; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic void cptvf_remove(struct pci_dev *pdev) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct cpt_vf *cptvf = pci_get_drvdata(pdev); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (!cptvf) { 80962306a36Sopenharmony_ci dev_err(&pdev->dev, "Invalid CPT-VF device\n"); 81062306a36Sopenharmony_ci return; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* Convey DOWN to PF */ 81462306a36Sopenharmony_ci if (cptvf_send_vf_down(cptvf)) { 81562306a36Sopenharmony_ci dev_err(&pdev->dev, "PF not responding to DOWN msg"); 81662306a36Sopenharmony_ci } else { 81762306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 81862306a36Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 81962306a36Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), cptvf); 82062306a36Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf); 82162306a36Sopenharmony_ci pci_free_irq_vectors(cptvf->pdev); 82262306a36Sopenharmony_ci cptvf_sw_cleanup(cptvf); 82362306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 82462306a36Sopenharmony_ci pci_release_regions(pdev); 82562306a36Sopenharmony_ci pci_disable_device(pdev); 82662306a36Sopenharmony_ci cvm_crypto_exit(); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic void cptvf_shutdown(struct pci_dev *pdev) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci cptvf_remove(pdev); 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci/* Supported devices */ 83662306a36Sopenharmony_cistatic const struct pci_device_id cptvf_id_table[] = { 83762306a36Sopenharmony_ci {PCI_VDEVICE(CAVIUM, CPT_81XX_PCI_VF_DEVICE_ID), 0}, 83862306a36Sopenharmony_ci { 0, } /* end of table */ 83962306a36Sopenharmony_ci}; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic struct pci_driver cptvf_pci_driver = { 84262306a36Sopenharmony_ci .name = DRV_NAME, 84362306a36Sopenharmony_ci .id_table = cptvf_id_table, 84462306a36Sopenharmony_ci .probe = cptvf_probe, 84562306a36Sopenharmony_ci .remove = cptvf_remove, 84662306a36Sopenharmony_ci .shutdown = cptvf_shutdown, 84762306a36Sopenharmony_ci}; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cimodule_pci_driver(cptvf_pci_driver); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ciMODULE_AUTHOR("George Cherian <george.cherian@cavium.com>"); 85262306a36Sopenharmony_ciMODULE_DESCRIPTION("Cavium Thunder CPT Virtual Function Driver"); 85362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 85462306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 85562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cptvf_id_table); 856