18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Cavium, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "cptvf.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define DRV_NAME "thunder-cptvf" 128c2ecf20Sopenharmony_ci#define DRV_VERSION "1.0" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistruct cptvf_wqe { 158c2ecf20Sopenharmony_ci struct tasklet_struct twork; 168c2ecf20Sopenharmony_ci void *cptvf; 178c2ecf20Sopenharmony_ci u32 qno; 188c2ecf20Sopenharmony_ci}; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct cptvf_wqe_info { 218c2ecf20Sopenharmony_ci struct cptvf_wqe vq_wqe[CPT_NUM_QS_PER_VF]; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void vq_work_handler(unsigned long data) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct cptvf_wqe_info *cwqe_info = (struct cptvf_wqe_info *)data; 278c2ecf20Sopenharmony_ci struct cptvf_wqe *cwqe = &cwqe_info->vq_wqe[0]; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci vq_post_process(cwqe->cptvf, cwqe->qno); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int init_worker_threads(struct cpt_vf *cptvf) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 358c2ecf20Sopenharmony_ci struct cptvf_wqe_info *cwqe_info; 368c2ecf20Sopenharmony_ci int i; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci cwqe_info = kzalloc(sizeof(*cwqe_info), GFP_KERNEL); 398c2ecf20Sopenharmony_ci if (!cwqe_info) 408c2ecf20Sopenharmony_ci return -ENOMEM; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (cptvf->nr_queues) { 438c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Creating VQ worker threads (%d)\n", 448c2ecf20Sopenharmony_ci cptvf->nr_queues); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) { 488c2ecf20Sopenharmony_ci tasklet_init(&cwqe_info->vq_wqe[i].twork, vq_work_handler, 498c2ecf20Sopenharmony_ci (u64)cwqe_info); 508c2ecf20Sopenharmony_ci cwqe_info->vq_wqe[i].qno = i; 518c2ecf20Sopenharmony_ci cwqe_info->vq_wqe[i].cptvf = cptvf; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci cptvf->wqe_info = cwqe_info; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void cleanup_worker_threads(struct cpt_vf *cptvf) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct cptvf_wqe_info *cwqe_info; 628c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 638c2ecf20Sopenharmony_ci int i; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci cwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info; 668c2ecf20Sopenharmony_ci if (!cwqe_info) 678c2ecf20Sopenharmony_ci return; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (cptvf->nr_queues) { 708c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Cleaning VQ worker threads (%u)\n", 718c2ecf20Sopenharmony_ci cptvf->nr_queues); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) 758c2ecf20Sopenharmony_ci tasklet_kill(&cwqe_info->vq_wqe[i].twork); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci kfree_sensitive(cwqe_info); 788c2ecf20Sopenharmony_ci cptvf->wqe_info = NULL; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void free_pending_queues(struct pending_qinfo *pqinfo) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci int i; 848c2ecf20Sopenharmony_ci struct pending_queue *queue; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci for_each_pending_queue(pqinfo, queue, i) { 878c2ecf20Sopenharmony_ci if (!queue->head) 888c2ecf20Sopenharmony_ci continue; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* free single queue */ 918c2ecf20Sopenharmony_ci kfree_sensitive((queue->head)); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci queue->front = 0; 948c2ecf20Sopenharmony_ci queue->rear = 0; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci pqinfo->qlen = 0; 1008c2ecf20Sopenharmony_ci pqinfo->nr_queues = 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int alloc_pending_queues(struct pending_qinfo *pqinfo, u32 qlen, 1048c2ecf20Sopenharmony_ci u32 nr_queues) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u32 i; 1078c2ecf20Sopenharmony_ci size_t size; 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci struct pending_queue *queue = NULL; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci pqinfo->nr_queues = nr_queues; 1128c2ecf20Sopenharmony_ci pqinfo->qlen = qlen; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci size = (qlen * sizeof(struct pending_entry)); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci for_each_pending_queue(pqinfo, queue, i) { 1178c2ecf20Sopenharmony_ci queue->head = kzalloc((size), GFP_KERNEL); 1188c2ecf20Sopenharmony_ci if (!queue->head) { 1198c2ecf20Sopenharmony_ci ret = -ENOMEM; 1208c2ecf20Sopenharmony_ci goto pending_qfail; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci queue->front = 0; 1248c2ecf20Sopenharmony_ci queue->rear = 0; 1258c2ecf20Sopenharmony_ci atomic64_set((&queue->pending_count), (0)); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* init queue spin lock */ 1288c2ecf20Sopenharmony_ci spin_lock_init(&queue->lock); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cipending_qfail: 1348c2ecf20Sopenharmony_ci free_pending_queues(pqinfo); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return ret; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int init_pending_queues(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 1428c2ecf20Sopenharmony_ci int ret; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (!nr_queues) 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ret = alloc_pending_queues(&cptvf->pqinfo, qlen, nr_queues); 1488c2ecf20Sopenharmony_ci if (ret) { 1498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to setup pending queues (%u)\n", 1508c2ecf20Sopenharmony_ci nr_queues); 1518c2ecf20Sopenharmony_ci return ret; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void cleanup_pending_queues(struct cpt_vf *cptvf) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (!cptvf->nr_queues) 1628c2ecf20Sopenharmony_ci return; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Cleaning VQ pending queue (%u)\n", 1658c2ecf20Sopenharmony_ci cptvf->nr_queues); 1668c2ecf20Sopenharmony_ci free_pending_queues(&cptvf->pqinfo); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void free_command_queues(struct cpt_vf *cptvf, 1708c2ecf20Sopenharmony_ci struct command_qinfo *cqinfo) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int i; 1738c2ecf20Sopenharmony_ci struct command_queue *queue = NULL; 1748c2ecf20Sopenharmony_ci struct command_chunk *chunk = NULL; 1758c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 1768c2ecf20Sopenharmony_ci struct hlist_node *node; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* clean up for each queue */ 1798c2ecf20Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) { 1808c2ecf20Sopenharmony_ci queue = &cqinfo->queue[i]; 1818c2ecf20Sopenharmony_ci if (hlist_empty(&cqinfo->queue[i].chead)) 1828c2ecf20Sopenharmony_ci continue; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead, 1858c2ecf20Sopenharmony_ci nextchunk) { 1868c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, chunk->size, 1878c2ecf20Sopenharmony_ci chunk->head, 1888c2ecf20Sopenharmony_ci chunk->dma_addr); 1898c2ecf20Sopenharmony_ci chunk->head = NULL; 1908c2ecf20Sopenharmony_ci chunk->dma_addr = 0; 1918c2ecf20Sopenharmony_ci hlist_del(&chunk->nextchunk); 1928c2ecf20Sopenharmony_ci kfree_sensitive(chunk); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci queue->nchunks = 0; 1968c2ecf20Sopenharmony_ci queue->idx = 0; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* common cleanup */ 2008c2ecf20Sopenharmony_ci cqinfo->cmd_size = 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int alloc_command_queues(struct cpt_vf *cptvf, 2048c2ecf20Sopenharmony_ci struct command_qinfo *cqinfo, size_t cmd_size, 2058c2ecf20Sopenharmony_ci u32 qlen) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci int i; 2088c2ecf20Sopenharmony_ci size_t q_size; 2098c2ecf20Sopenharmony_ci struct command_queue *queue = NULL; 2108c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* common init */ 2138c2ecf20Sopenharmony_ci cqinfo->cmd_size = cmd_size; 2148c2ecf20Sopenharmony_ci /* Qsize in dwords, needed for SADDR config, 1-next chunk pointer */ 2158c2ecf20Sopenharmony_ci cptvf->qsize = min(qlen, cqinfo->qchunksize) * 2168c2ecf20Sopenharmony_ci CPT_NEXT_CHUNK_PTR_SIZE + 1; 2178c2ecf20Sopenharmony_ci /* Qsize in bytes to create space for alignment */ 2188c2ecf20Sopenharmony_ci q_size = qlen * cqinfo->cmd_size; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* per queue initialization */ 2218c2ecf20Sopenharmony_ci for (i = 0; i < cptvf->nr_queues; i++) { 2228c2ecf20Sopenharmony_ci size_t c_size = 0; 2238c2ecf20Sopenharmony_ci size_t rem_q_size = q_size; 2248c2ecf20Sopenharmony_ci struct command_chunk *curr = NULL, *first = NULL, *last = NULL; 2258c2ecf20Sopenharmony_ci u32 qcsize_bytes = cqinfo->qchunksize * cqinfo->cmd_size; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci queue = &cqinfo->queue[i]; 2288c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&cqinfo->queue[i].chead); 2298c2ecf20Sopenharmony_ci do { 2308c2ecf20Sopenharmony_ci curr = kzalloc(sizeof(*curr), GFP_KERNEL); 2318c2ecf20Sopenharmony_ci if (!curr) 2328c2ecf20Sopenharmony_ci goto cmd_qfail; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci c_size = (rem_q_size > qcsize_bytes) ? qcsize_bytes : 2358c2ecf20Sopenharmony_ci rem_q_size; 2368c2ecf20Sopenharmony_ci curr->head = (u8 *)dma_alloc_coherent(&pdev->dev, 2378c2ecf20Sopenharmony_ci c_size + CPT_NEXT_CHUNK_PTR_SIZE, 2388c2ecf20Sopenharmony_ci &curr->dma_addr, 2398c2ecf20Sopenharmony_ci GFP_KERNEL); 2408c2ecf20Sopenharmony_ci if (!curr->head) { 2418c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Command Q (%d) chunk (%d) allocation failed\n", 2428c2ecf20Sopenharmony_ci i, queue->nchunks); 2438c2ecf20Sopenharmony_ci kfree(curr); 2448c2ecf20Sopenharmony_ci goto cmd_qfail; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci curr->size = c_size; 2488c2ecf20Sopenharmony_ci if (queue->nchunks == 0) { 2498c2ecf20Sopenharmony_ci hlist_add_head(&curr->nextchunk, 2508c2ecf20Sopenharmony_ci &cqinfo->queue[i].chead); 2518c2ecf20Sopenharmony_ci first = curr; 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci hlist_add_behind(&curr->nextchunk, 2548c2ecf20Sopenharmony_ci &last->nextchunk); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci queue->nchunks++; 2588c2ecf20Sopenharmony_ci rem_q_size -= c_size; 2598c2ecf20Sopenharmony_ci if (last) 2608c2ecf20Sopenharmony_ci *((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci last = curr; 2638c2ecf20Sopenharmony_ci } while (rem_q_size); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Make the queue circular */ 2668c2ecf20Sopenharmony_ci /* Tie back last chunk entry to head */ 2678c2ecf20Sopenharmony_ci curr = first; 2688c2ecf20Sopenharmony_ci *((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr; 2698c2ecf20Sopenharmony_ci queue->qhead = curr; 2708c2ecf20Sopenharmony_ci spin_lock_init(&queue->lock); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cicmd_qfail: 2758c2ecf20Sopenharmony_ci free_command_queues(cptvf, cqinfo); 2768c2ecf20Sopenharmony_ci return -ENOMEM; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int init_command_queues(struct cpt_vf *cptvf, u32 qlen) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 2828c2ecf20Sopenharmony_ci int ret; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* setup AE command queues */ 2858c2ecf20Sopenharmony_ci ret = alloc_command_queues(cptvf, &cptvf->cqinfo, CPT_INST_SIZE, 2868c2ecf20Sopenharmony_ci qlen); 2878c2ecf20Sopenharmony_ci if (ret) { 2888c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate AE command queues (%u)\n", 2898c2ecf20Sopenharmony_ci cptvf->nr_queues); 2908c2ecf20Sopenharmony_ci return ret; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return ret; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void cleanup_command_queues(struct cpt_vf *cptvf) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!cptvf->nr_queues) 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Cleaning VQ command queue (%u)\n", 3048c2ecf20Sopenharmony_ci cptvf->nr_queues); 3058c2ecf20Sopenharmony_ci free_command_queues(cptvf, &cptvf->cqinfo); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic void cptvf_sw_cleanup(struct cpt_vf *cptvf) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci cleanup_worker_threads(cptvf); 3118c2ecf20Sopenharmony_ci cleanup_pending_queues(cptvf); 3128c2ecf20Sopenharmony_ci cleanup_command_queues(cptvf); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int cptvf_sw_init(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 3188c2ecf20Sopenharmony_ci int ret = 0; 3198c2ecf20Sopenharmony_ci u32 max_dev_queues = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci max_dev_queues = CPT_NUM_QS_PER_VF; 3228c2ecf20Sopenharmony_ci /* possible cpus */ 3238c2ecf20Sopenharmony_ci nr_queues = min_t(u32, nr_queues, max_dev_queues); 3248c2ecf20Sopenharmony_ci cptvf->nr_queues = nr_queues; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ret = init_command_queues(cptvf, qlen); 3278c2ecf20Sopenharmony_ci if (ret) { 3288c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup command queues (%u)\n", 3298c2ecf20Sopenharmony_ci nr_queues); 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ret = init_pending_queues(cptvf, qlen, nr_queues); 3348c2ecf20Sopenharmony_ci if (ret) { 3358c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup pending queues (%u)\n", 3368c2ecf20Sopenharmony_ci nr_queues); 3378c2ecf20Sopenharmony_ci goto setup_pqfail; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Create worker threads for BH processing */ 3418c2ecf20Sopenharmony_ci ret = init_worker_threads(cptvf); 3428c2ecf20Sopenharmony_ci if (ret) { 3438c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup worker threads\n"); 3448c2ecf20Sopenharmony_ci goto init_work_fail; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ciinit_work_fail: 3508c2ecf20Sopenharmony_ci cleanup_worker_threads(cptvf); 3518c2ecf20Sopenharmony_ci cleanup_pending_queues(cptvf); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cisetup_pqfail: 3548c2ecf20Sopenharmony_ci cleanup_command_queues(cptvf); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return ret; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void cptvf_free_irq_affinity(struct cpt_vf *cptvf, int vec) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci irq_set_affinity_hint(pci_irq_vector(cptvf->pdev, vec), NULL); 3628c2ecf20Sopenharmony_ci free_cpumask_var(cptvf->affinity_mask[vec]); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic void cptvf_write_vq_ctl(struct cpt_vf *cptvf, bool val) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci union cptx_vqx_ctl vqx_ctl; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci vqx_ctl.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0)); 3708c2ecf20Sopenharmony_ci vqx_ctl.s.ena = val; 3718c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0), vqx_ctl.u); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_civoid cptvf_write_vq_doorbell(struct cpt_vf *cptvf, u32 val) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci union cptx_vqx_doorbell vqx_dbell; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci vqx_dbell.u = cpt_read_csr64(cptvf->reg_base, 3798c2ecf20Sopenharmony_ci CPTX_VQX_DOORBELL(0, 0)); 3808c2ecf20Sopenharmony_ci vqx_dbell.s.dbell_cnt = val * 8; /* Num of Instructions * 8 words */ 3818c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DOORBELL(0, 0), 3828c2ecf20Sopenharmony_ci vqx_dbell.u); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic void cptvf_write_vq_inprog(struct cpt_vf *cptvf, u8 val) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci union cptx_vqx_inprog vqx_inprg; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci vqx_inprg.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0)); 3908c2ecf20Sopenharmony_ci vqx_inprg.s.inflight = val; 3918c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0), vqx_inprg.u); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void cptvf_write_vq_done_numwait(struct cpt_vf *cptvf, u32 val) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci union cptx_vqx_done_wait vqx_dwait; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci vqx_dwait.u = cpt_read_csr64(cptvf->reg_base, 3998c2ecf20Sopenharmony_ci CPTX_VQX_DONE_WAIT(0, 0)); 4008c2ecf20Sopenharmony_ci vqx_dwait.s.num_wait = val; 4018c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0), 4028c2ecf20Sopenharmony_ci vqx_dwait.u); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void cptvf_write_vq_done_timewait(struct cpt_vf *cptvf, u16 time) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci union cptx_vqx_done_wait vqx_dwait; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci vqx_dwait.u = cpt_read_csr64(cptvf->reg_base, 4108c2ecf20Sopenharmony_ci CPTX_VQX_DONE_WAIT(0, 0)); 4118c2ecf20Sopenharmony_ci vqx_dwait.s.time_wait = time; 4128c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0), 4138c2ecf20Sopenharmony_ci vqx_dwait.u); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void cptvf_enable_swerr_interrupts(struct cpt_vf *cptvf) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci union cptx_vqx_misc_ena_w1s vqx_misc_ena; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base, 4218c2ecf20Sopenharmony_ci CPTX_VQX_MISC_ENA_W1S(0, 0)); 4228c2ecf20Sopenharmony_ci /* Set mbox(0) interupts for the requested vf */ 4238c2ecf20Sopenharmony_ci vqx_misc_ena.s.swerr = 1; 4248c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0), 4258c2ecf20Sopenharmony_ci vqx_misc_ena.u); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void cptvf_enable_mbox_interrupts(struct cpt_vf *cptvf) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci union cptx_vqx_misc_ena_w1s vqx_misc_ena; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base, 4338c2ecf20Sopenharmony_ci CPTX_VQX_MISC_ENA_W1S(0, 0)); 4348c2ecf20Sopenharmony_ci /* Set mbox(0) interupts for the requested vf */ 4358c2ecf20Sopenharmony_ci vqx_misc_ena.s.mbox = 1; 4368c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0), 4378c2ecf20Sopenharmony_ci vqx_misc_ena.u); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic void cptvf_enable_done_interrupts(struct cpt_vf *cptvf) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci union cptx_vqx_done_ena_w1s vqx_done_ena; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci vqx_done_ena.u = cpt_read_csr64(cptvf->reg_base, 4458c2ecf20Sopenharmony_ci CPTX_VQX_DONE_ENA_W1S(0, 0)); 4468c2ecf20Sopenharmony_ci /* Set DONE interrupt for the requested vf */ 4478c2ecf20Sopenharmony_ci vqx_done_ena.s.done = 1; 4488c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ENA_W1S(0, 0), 4498c2ecf20Sopenharmony_ci vqx_done_ena.u); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void cptvf_clear_dovf_intr(struct cpt_vf *cptvf) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 4578c2ecf20Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 4588c2ecf20Sopenharmony_ci /* W1C for the VF */ 4598c2ecf20Sopenharmony_ci vqx_misc_int.s.dovf = 1; 4608c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 4618c2ecf20Sopenharmony_ci vqx_misc_int.u); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic void cptvf_clear_irde_intr(struct cpt_vf *cptvf) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 4698c2ecf20Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 4708c2ecf20Sopenharmony_ci /* W1C for the VF */ 4718c2ecf20Sopenharmony_ci vqx_misc_int.s.irde = 1; 4728c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 4738c2ecf20Sopenharmony_ci vqx_misc_int.u); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void cptvf_clear_nwrp_intr(struct cpt_vf *cptvf) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 4818c2ecf20Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 4828c2ecf20Sopenharmony_ci /* W1C for the VF */ 4838c2ecf20Sopenharmony_ci vqx_misc_int.s.nwrp = 1; 4848c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, 4858c2ecf20Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0), vqx_misc_int.u); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void cptvf_clear_mbox_intr(struct cpt_vf *cptvf) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 4938c2ecf20Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 4948c2ecf20Sopenharmony_ci /* W1C for the VF */ 4958c2ecf20Sopenharmony_ci vqx_misc_int.s.mbox = 1; 4968c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 4978c2ecf20Sopenharmony_ci vqx_misc_int.u); 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic void cptvf_clear_swerr_intr(struct cpt_vf *cptvf) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci union cptx_vqx_misc_int vqx_misc_int; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base, 5058c2ecf20Sopenharmony_ci CPTX_VQX_MISC_INT(0, 0)); 5068c2ecf20Sopenharmony_ci /* W1C for the VF */ 5078c2ecf20Sopenharmony_ci vqx_misc_int.s.swerr = 1; 5088c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0), 5098c2ecf20Sopenharmony_ci vqx_misc_int.u); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic u64 cptvf_read_vf_misc_intr_status(struct cpt_vf *cptvf) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci return cpt_read_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0)); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic irqreturn_t cptvf_misc_intr_handler(int irq, void *cptvf_irq) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq; 5208c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 5218c2ecf20Sopenharmony_ci u64 intr; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci intr = cptvf_read_vf_misc_intr_status(cptvf); 5248c2ecf20Sopenharmony_ci /*Check for MISC interrupt types*/ 5258c2ecf20Sopenharmony_ci if (likely(intr & CPT_VF_INTR_MBOX_MASK)) { 5268c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Mailbox interrupt 0x%llx on CPT VF %d\n", 5278c2ecf20Sopenharmony_ci intr, cptvf->vfid); 5288c2ecf20Sopenharmony_ci cptvf_handle_mbox_intr(cptvf); 5298c2ecf20Sopenharmony_ci cptvf_clear_mbox_intr(cptvf); 5308c2ecf20Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_DOVF_MASK)) { 5318c2ecf20Sopenharmony_ci cptvf_clear_dovf_intr(cptvf); 5328c2ecf20Sopenharmony_ci /*Clear doorbell count*/ 5338c2ecf20Sopenharmony_ci cptvf_write_vq_doorbell(cptvf, 0); 5348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Doorbell overflow error interrupt 0x%llx on CPT VF %d\n", 5358c2ecf20Sopenharmony_ci intr, cptvf->vfid); 5368c2ecf20Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_IRDE_MASK)) { 5378c2ecf20Sopenharmony_ci cptvf_clear_irde_intr(cptvf); 5388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Instruction NCB read error interrupt 0x%llx on CPT VF %d\n", 5398c2ecf20Sopenharmony_ci intr, cptvf->vfid); 5408c2ecf20Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_NWRP_MASK)) { 5418c2ecf20Sopenharmony_ci cptvf_clear_nwrp_intr(cptvf); 5428c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "NCB response write error interrupt 0x%llx on CPT VF %d\n", 5438c2ecf20Sopenharmony_ci intr, cptvf->vfid); 5448c2ecf20Sopenharmony_ci } else if (unlikely(intr & CPT_VF_INTR_SERR_MASK)) { 5458c2ecf20Sopenharmony_ci cptvf_clear_swerr_intr(cptvf); 5468c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Software error interrupt 0x%llx on CPT VF %d\n", 5478c2ecf20Sopenharmony_ci intr, cptvf->vfid); 5488c2ecf20Sopenharmony_ci } else { 5498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unhandled interrupt in CPT VF %d\n", 5508c2ecf20Sopenharmony_ci cptvf->vfid); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic inline struct cptvf_wqe *get_cptvf_vq_wqe(struct cpt_vf *cptvf, 5578c2ecf20Sopenharmony_ci int qno) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct cptvf_wqe_info *nwqe_info; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (unlikely(qno >= cptvf->nr_queues)) 5628c2ecf20Sopenharmony_ci return NULL; 5638c2ecf20Sopenharmony_ci nwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return &nwqe_info->vq_wqe[qno]; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic inline u32 cptvf_read_vq_done_count(struct cpt_vf *cptvf) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci union cptx_vqx_done vqx_done; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci vqx_done.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_DONE(0, 0)); 5738c2ecf20Sopenharmony_ci return vqx_done.s.done; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic inline void cptvf_write_vq_done_ack(struct cpt_vf *cptvf, 5778c2ecf20Sopenharmony_ci u32 ackcnt) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci union cptx_vqx_done_ack vqx_dack_cnt; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci vqx_dack_cnt.u = cpt_read_csr64(cptvf->reg_base, 5828c2ecf20Sopenharmony_ci CPTX_VQX_DONE_ACK(0, 0)); 5838c2ecf20Sopenharmony_ci vqx_dack_cnt.s.done_ack = ackcnt; 5848c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ACK(0, 0), 5858c2ecf20Sopenharmony_ci vqx_dack_cnt.u); 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic irqreturn_t cptvf_done_intr_handler(int irq, void *cptvf_irq) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq; 5918c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 5928c2ecf20Sopenharmony_ci /* Read the number of completions */ 5938c2ecf20Sopenharmony_ci u32 intr = cptvf_read_vq_done_count(cptvf); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (intr) { 5968c2ecf20Sopenharmony_ci struct cptvf_wqe *wqe; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Acknowledge the number of 5998c2ecf20Sopenharmony_ci * scheduled completions for processing 6008c2ecf20Sopenharmony_ci */ 6018c2ecf20Sopenharmony_ci cptvf_write_vq_done_ack(cptvf, intr); 6028c2ecf20Sopenharmony_ci wqe = get_cptvf_vq_wqe(cptvf, 0); 6038c2ecf20Sopenharmony_ci if (unlikely(!wqe)) { 6048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No work to schedule for VF (%d)", 6058c2ecf20Sopenharmony_ci cptvf->vfid); 6068c2ecf20Sopenharmony_ci return IRQ_NONE; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci tasklet_hi_schedule(&wqe->twork); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic void cptvf_set_irq_affinity(struct cpt_vf *cptvf, int vec) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 6178c2ecf20Sopenharmony_ci int cpu; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (!zalloc_cpumask_var(&cptvf->affinity_mask[vec], 6208c2ecf20Sopenharmony_ci GFP_KERNEL)) { 6218c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Allocation failed for affinity_mask for VF %d", 6228c2ecf20Sopenharmony_ci cptvf->vfid); 6238c2ecf20Sopenharmony_ci return; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci cpu = cptvf->vfid % num_online_cpus(); 6278c2ecf20Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(cpu, cptvf->node), 6288c2ecf20Sopenharmony_ci cptvf->affinity_mask[vec]); 6298c2ecf20Sopenharmony_ci irq_set_affinity_hint(pci_irq_vector(pdev, vec), 6308c2ecf20Sopenharmony_ci cptvf->affinity_mask[vec]); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic void cptvf_write_vq_saddr(struct cpt_vf *cptvf, u64 val) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci union cptx_vqx_saddr vqx_saddr; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci vqx_saddr.u = val; 6388c2ecf20Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VQX_SADDR(0, 0), vqx_saddr.u); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic void cptvf_device_init(struct cpt_vf *cptvf) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci u64 base_addr = 0; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Disable the VQ */ 6468c2ecf20Sopenharmony_ci cptvf_write_vq_ctl(cptvf, 0); 6478c2ecf20Sopenharmony_ci /* Reset the doorbell */ 6488c2ecf20Sopenharmony_ci cptvf_write_vq_doorbell(cptvf, 0); 6498c2ecf20Sopenharmony_ci /* Clear inflight */ 6508c2ecf20Sopenharmony_ci cptvf_write_vq_inprog(cptvf, 0); 6518c2ecf20Sopenharmony_ci /* Write VQ SADDR */ 6528c2ecf20Sopenharmony_ci /* TODO: for now only one queue, so hard coded */ 6538c2ecf20Sopenharmony_ci base_addr = (u64)(cptvf->cqinfo.queue[0].qhead->dma_addr); 6548c2ecf20Sopenharmony_ci cptvf_write_vq_saddr(cptvf, base_addr); 6558c2ecf20Sopenharmony_ci /* Configure timerhold / coalescence */ 6568c2ecf20Sopenharmony_ci cptvf_write_vq_done_timewait(cptvf, CPT_TIMER_THOLD); 6578c2ecf20Sopenharmony_ci cptvf_write_vq_done_numwait(cptvf, 1); 6588c2ecf20Sopenharmony_ci /* Enable the VQ */ 6598c2ecf20Sopenharmony_ci cptvf_write_vq_ctl(cptvf, 1); 6608c2ecf20Sopenharmony_ci /* Flag the VF ready */ 6618c2ecf20Sopenharmony_ci cptvf->flags |= CPT_FLAG_DEVICE_READY; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic int cptvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6678c2ecf20Sopenharmony_ci struct cpt_vf *cptvf; 6688c2ecf20Sopenharmony_ci int err; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci cptvf = devm_kzalloc(dev, sizeof(*cptvf), GFP_KERNEL); 6718c2ecf20Sopenharmony_ci if (!cptvf) 6728c2ecf20Sopenharmony_ci return -ENOMEM; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, cptvf); 6758c2ecf20Sopenharmony_ci cptvf->pdev = pdev; 6768c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 6778c2ecf20Sopenharmony_ci if (err) { 6788c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable PCI device\n"); 6798c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 6808c2ecf20Sopenharmony_ci return err; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 6848c2ecf20Sopenharmony_ci if (err) { 6858c2ecf20Sopenharmony_ci dev_err(dev, "PCI request regions failed 0x%x\n", err); 6868c2ecf20Sopenharmony_ci goto cptvf_err_disable_device; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci /* Mark as VF driver */ 6898c2ecf20Sopenharmony_ci cptvf->flags |= CPT_FLAG_VF_DRIVER; 6908c2ecf20Sopenharmony_ci err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48)); 6918c2ecf20Sopenharmony_ci if (err) { 6928c2ecf20Sopenharmony_ci dev_err(dev, "Unable to get usable DMA configuration\n"); 6938c2ecf20Sopenharmony_ci goto cptvf_err_release_regions; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48)); 6978c2ecf20Sopenharmony_ci if (err) { 6988c2ecf20Sopenharmony_ci dev_err(dev, "Unable to get 48-bit DMA for consistent allocations\n"); 6998c2ecf20Sopenharmony_ci goto cptvf_err_release_regions; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* MAP PF's configuration registers */ 7038c2ecf20Sopenharmony_ci cptvf->reg_base = pcim_iomap(pdev, 0, 0); 7048c2ecf20Sopenharmony_ci if (!cptvf->reg_base) { 7058c2ecf20Sopenharmony_ci dev_err(dev, "Cannot map config register space, aborting\n"); 7068c2ecf20Sopenharmony_ci err = -ENOMEM; 7078c2ecf20Sopenharmony_ci goto cptvf_err_release_regions; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci cptvf->node = dev_to_node(&pdev->dev); 7118c2ecf20Sopenharmony_ci err = pci_alloc_irq_vectors(pdev, CPT_VF_MSIX_VECTORS, 7128c2ecf20Sopenharmony_ci CPT_VF_MSIX_VECTORS, PCI_IRQ_MSIX); 7138c2ecf20Sopenharmony_ci if (err < 0) { 7148c2ecf20Sopenharmony_ci dev_err(dev, "Request for #%d msix vectors failed\n", 7158c2ecf20Sopenharmony_ci CPT_VF_MSIX_VECTORS); 7168c2ecf20Sopenharmony_ci goto cptvf_err_release_regions; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), 7208c2ecf20Sopenharmony_ci cptvf_misc_intr_handler, 0, "CPT VF misc intr", 7218c2ecf20Sopenharmony_ci cptvf); 7228c2ecf20Sopenharmony_ci if (err) { 7238c2ecf20Sopenharmony_ci dev_err(dev, "Request misc irq failed"); 7248c2ecf20Sopenharmony_ci goto cptvf_free_vectors; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* Enable mailbox interrupt */ 7288c2ecf20Sopenharmony_ci cptvf_enable_mbox_interrupts(cptvf); 7298c2ecf20Sopenharmony_ci cptvf_enable_swerr_interrupts(cptvf); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Check ready with PF */ 7328c2ecf20Sopenharmony_ci /* Gets chip ID / device Id from PF if ready */ 7338c2ecf20Sopenharmony_ci err = cptvf_check_pf_ready(cptvf); 7348c2ecf20Sopenharmony_ci if (err) { 7358c2ecf20Sopenharmony_ci dev_err(dev, "PF not responding to READY msg"); 7368c2ecf20Sopenharmony_ci goto cptvf_free_misc_irq; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* CPT VF software resources initialization */ 7408c2ecf20Sopenharmony_ci cptvf->cqinfo.qchunksize = CPT_CMD_QCHUNK_SIZE; 7418c2ecf20Sopenharmony_ci err = cptvf_sw_init(cptvf, CPT_CMD_QLEN, CPT_NUM_QS_PER_VF); 7428c2ecf20Sopenharmony_ci if (err) { 7438c2ecf20Sopenharmony_ci dev_err(dev, "cptvf_sw_init() failed"); 7448c2ecf20Sopenharmony_ci goto cptvf_free_misc_irq; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci /* Convey VQ LEN to PF */ 7478c2ecf20Sopenharmony_ci err = cptvf_send_vq_size_msg(cptvf); 7488c2ecf20Sopenharmony_ci if (err) { 7498c2ecf20Sopenharmony_ci dev_err(dev, "PF not responding to QLEN msg"); 7508c2ecf20Sopenharmony_ci goto cptvf_free_misc_irq; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* CPT VF device initialization */ 7548c2ecf20Sopenharmony_ci cptvf_device_init(cptvf); 7558c2ecf20Sopenharmony_ci /* Send msg to PF to assign currnet Q to required group */ 7568c2ecf20Sopenharmony_ci cptvf->vfgrp = 1; 7578c2ecf20Sopenharmony_ci err = cptvf_send_vf_to_grp_msg(cptvf); 7588c2ecf20Sopenharmony_ci if (err) { 7598c2ecf20Sopenharmony_ci dev_err(dev, "PF not responding to VF_GRP msg"); 7608c2ecf20Sopenharmony_ci goto cptvf_free_misc_irq; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci cptvf->priority = 1; 7648c2ecf20Sopenharmony_ci err = cptvf_send_vf_priority_msg(cptvf); 7658c2ecf20Sopenharmony_ci if (err) { 7668c2ecf20Sopenharmony_ci dev_err(dev, "PF not responding to VF_PRIO msg"); 7678c2ecf20Sopenharmony_ci goto cptvf_free_misc_irq; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), 7718c2ecf20Sopenharmony_ci cptvf_done_intr_handler, 0, "CPT VF done intr", 7728c2ecf20Sopenharmony_ci cptvf); 7738c2ecf20Sopenharmony_ci if (err) { 7748c2ecf20Sopenharmony_ci dev_err(dev, "Request done irq failed\n"); 7758c2ecf20Sopenharmony_ci goto cptvf_free_misc_irq; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* Enable mailbox interrupt */ 7798c2ecf20Sopenharmony_ci cptvf_enable_done_interrupts(cptvf); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* Set irq affinity masks */ 7828c2ecf20Sopenharmony_ci cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 7838c2ecf20Sopenharmony_ci cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci err = cptvf_send_vf_up(cptvf); 7868c2ecf20Sopenharmony_ci if (err) { 7878c2ecf20Sopenharmony_ci dev_err(dev, "PF not responding to UP msg"); 7888c2ecf20Sopenharmony_ci goto cptvf_free_irq_affinity; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci err = cvm_crypto_init(cptvf); 7918c2ecf20Sopenharmony_ci if (err) { 7928c2ecf20Sopenharmony_ci dev_err(dev, "Algorithm register failed\n"); 7938c2ecf20Sopenharmony_ci goto cptvf_free_irq_affinity; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cicptvf_free_irq_affinity: 7988c2ecf20Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 7998c2ecf20Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 8008c2ecf20Sopenharmony_cicptvf_free_misc_irq: 8018c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf); 8028c2ecf20Sopenharmony_cicptvf_free_vectors: 8038c2ecf20Sopenharmony_ci pci_free_irq_vectors(cptvf->pdev); 8048c2ecf20Sopenharmony_cicptvf_err_release_regions: 8058c2ecf20Sopenharmony_ci pci_release_regions(pdev); 8068c2ecf20Sopenharmony_cicptvf_err_disable_device: 8078c2ecf20Sopenharmony_ci pci_disable_device(pdev); 8088c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return err; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic void cptvf_remove(struct pci_dev *pdev) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct cpt_vf *cptvf = pci_get_drvdata(pdev); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (!cptvf) { 8188c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Invalid CPT-VF device\n"); 8198c2ecf20Sopenharmony_ci return; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* Convey DOWN to PF */ 8238c2ecf20Sopenharmony_ci if (cptvf_send_vf_down(cptvf)) { 8248c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "PF not responding to DOWN msg"); 8258c2ecf20Sopenharmony_ci } else { 8268c2ecf20Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE); 8278c2ecf20Sopenharmony_ci cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC); 8288c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), cptvf); 8298c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf); 8308c2ecf20Sopenharmony_ci pci_free_irq_vectors(cptvf->pdev); 8318c2ecf20Sopenharmony_ci cptvf_sw_cleanup(cptvf); 8328c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 8338c2ecf20Sopenharmony_ci pci_release_regions(pdev); 8348c2ecf20Sopenharmony_ci pci_disable_device(pdev); 8358c2ecf20Sopenharmony_ci cvm_crypto_exit(); 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic void cptvf_shutdown(struct pci_dev *pdev) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci cptvf_remove(pdev); 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci/* Supported devices */ 8458c2ecf20Sopenharmony_cistatic const struct pci_device_id cptvf_id_table[] = { 8468c2ecf20Sopenharmony_ci {PCI_VDEVICE(CAVIUM, CPT_81XX_PCI_VF_DEVICE_ID), 0}, 8478c2ecf20Sopenharmony_ci { 0, } /* end of table */ 8488c2ecf20Sopenharmony_ci}; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic struct pci_driver cptvf_pci_driver = { 8518c2ecf20Sopenharmony_ci .name = DRV_NAME, 8528c2ecf20Sopenharmony_ci .id_table = cptvf_id_table, 8538c2ecf20Sopenharmony_ci .probe = cptvf_probe, 8548c2ecf20Sopenharmony_ci .remove = cptvf_remove, 8558c2ecf20Sopenharmony_ci .shutdown = cptvf_shutdown, 8568c2ecf20Sopenharmony_ci}; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cimodule_pci_driver(cptvf_pci_driver); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ciMODULE_AUTHOR("George Cherian <george.cherian@cavium.com>"); 8618c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cavium Thunder CPT Virtual Function Driver"); 8628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 8638c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 8648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cptvf_id_table); 865