Path: blob/master/drivers/crypto/cavium/cpt/cptvf_main.c
26285 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2016 Cavium, Inc.3*/45#include <linux/interrupt.h>6#include <linux/module.h>78#include "cptvf.h"910#define DRV_NAME "thunder-cptvf"11#define DRV_VERSION "1.0"1213struct cptvf_wqe {14struct tasklet_struct twork;15void *cptvf;16u32 qno;17};1819struct cptvf_wqe_info {20struct cptvf_wqe vq_wqe[CPT_NUM_QS_PER_VF];21};2223static void vq_work_handler(unsigned long data)24{25struct cptvf_wqe_info *cwqe_info = (struct cptvf_wqe_info *)data;26struct cptvf_wqe *cwqe = &cwqe_info->vq_wqe[0];2728vq_post_process(cwqe->cptvf, cwqe->qno);29}3031static int init_worker_threads(struct cpt_vf *cptvf)32{33struct pci_dev *pdev = cptvf->pdev;34struct cptvf_wqe_info *cwqe_info;35int i;3637cwqe_info = kzalloc(sizeof(*cwqe_info), GFP_KERNEL);38if (!cwqe_info)39return -ENOMEM;4041if (cptvf->nr_queues) {42dev_info(&pdev->dev, "Creating VQ worker threads (%d)\n",43cptvf->nr_queues);44}4546for (i = 0; i < cptvf->nr_queues; i++) {47tasklet_init(&cwqe_info->vq_wqe[i].twork, vq_work_handler,48(u64)cwqe_info);49cwqe_info->vq_wqe[i].qno = i;50cwqe_info->vq_wqe[i].cptvf = cptvf;51}5253cptvf->wqe_info = cwqe_info;5455return 0;56}5758static void cleanup_worker_threads(struct cpt_vf *cptvf)59{60struct cptvf_wqe_info *cwqe_info;61struct pci_dev *pdev = cptvf->pdev;62int i;6364cwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info;65if (!cwqe_info)66return;6768if (cptvf->nr_queues) {69dev_info(&pdev->dev, "Cleaning VQ worker threads (%u)\n",70cptvf->nr_queues);71}7273for (i = 0; i < cptvf->nr_queues; i++)74tasklet_kill(&cwqe_info->vq_wqe[i].twork);7576kfree_sensitive(cwqe_info);77cptvf->wqe_info = NULL;78}7980static void free_pending_queues(struct pending_qinfo *pqinfo)81{82int i;83struct pending_queue *queue;8485for_each_pending_queue(pqinfo, queue, i) {86if (!queue->head)87continue;8889/* free single queue */90kfree_sensitive((queue->head));9192queue->front = 0;93queue->rear = 0;9495return;96}9798pqinfo->qlen = 0;99pqinfo->nr_queues = 0;100}101102static int alloc_pending_queues(struct pending_qinfo *pqinfo, u32 qlen,103u32 nr_queues)104{105u32 i;106int ret;107struct pending_queue *queue = NULL;108109pqinfo->nr_queues = nr_queues;110pqinfo->qlen = qlen;111112for_each_pending_queue(pqinfo, queue, i) {113queue->head = kcalloc(qlen, sizeof(*queue->head), GFP_KERNEL);114if (!queue->head) {115ret = -ENOMEM;116goto pending_qfail;117}118119queue->front = 0;120queue->rear = 0;121atomic64_set((&queue->pending_count), (0));122123/* init queue spin lock */124spin_lock_init(&queue->lock);125}126127return 0;128129pending_qfail:130free_pending_queues(pqinfo);131132return ret;133}134135static int init_pending_queues(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues)136{137struct pci_dev *pdev = cptvf->pdev;138int ret;139140if (!nr_queues)141return 0;142143ret = alloc_pending_queues(&cptvf->pqinfo, qlen, nr_queues);144if (ret) {145dev_err(&pdev->dev, "failed to setup pending queues (%u)\n",146nr_queues);147return ret;148}149150return 0;151}152153static void cleanup_pending_queues(struct cpt_vf *cptvf)154{155struct pci_dev *pdev = cptvf->pdev;156157if (!cptvf->nr_queues)158return;159160dev_info(&pdev->dev, "Cleaning VQ pending queue (%u)\n",161cptvf->nr_queues);162free_pending_queues(&cptvf->pqinfo);163}164165static void free_command_queues(struct cpt_vf *cptvf,166struct command_qinfo *cqinfo)167{168int i;169struct command_queue *queue = NULL;170struct command_chunk *chunk = NULL;171struct pci_dev *pdev = cptvf->pdev;172struct hlist_node *node;173174/* clean up for each queue */175for (i = 0; i < cptvf->nr_queues; i++) {176queue = &cqinfo->queue[i];177if (hlist_empty(&cqinfo->queue[i].chead))178continue;179180hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead,181nextchunk) {182dma_free_coherent(&pdev->dev, chunk->size,183chunk->head,184chunk->dma_addr);185chunk->head = NULL;186chunk->dma_addr = 0;187hlist_del(&chunk->nextchunk);188kfree_sensitive(chunk);189}190191queue->nchunks = 0;192queue->idx = 0;193}194195/* common cleanup */196cqinfo->cmd_size = 0;197}198199static int alloc_command_queues(struct cpt_vf *cptvf,200struct command_qinfo *cqinfo, size_t cmd_size,201u32 qlen)202{203int i;204size_t q_size;205struct command_queue *queue = NULL;206struct pci_dev *pdev = cptvf->pdev;207208/* common init */209cqinfo->cmd_size = cmd_size;210/* Qsize in dwords, needed for SADDR config, 1-next chunk pointer */211cptvf->qsize = min(qlen, cqinfo->qchunksize) *212CPT_NEXT_CHUNK_PTR_SIZE + 1;213/* Qsize in bytes to create space for alignment */214q_size = qlen * cqinfo->cmd_size;215216/* per queue initialization */217for (i = 0; i < cptvf->nr_queues; i++) {218size_t c_size = 0;219size_t rem_q_size = q_size;220struct command_chunk *curr = NULL, *first = NULL, *last = NULL;221u32 qcsize_bytes = cqinfo->qchunksize * cqinfo->cmd_size;222223queue = &cqinfo->queue[i];224INIT_HLIST_HEAD(&cqinfo->queue[i].chead);225do {226curr = kzalloc(sizeof(*curr), GFP_KERNEL);227if (!curr)228goto cmd_qfail;229230c_size = (rem_q_size > qcsize_bytes) ? qcsize_bytes :231rem_q_size;232curr->head = dma_alloc_coherent(&pdev->dev,233c_size + CPT_NEXT_CHUNK_PTR_SIZE,234&curr->dma_addr,235GFP_KERNEL);236if (!curr->head) {237dev_err(&pdev->dev, "Command Q (%d) chunk (%d) allocation failed\n",238i, queue->nchunks);239kfree(curr);240goto cmd_qfail;241}242243curr->size = c_size;244if (queue->nchunks == 0) {245hlist_add_head(&curr->nextchunk,246&cqinfo->queue[i].chead);247first = curr;248} else {249hlist_add_behind(&curr->nextchunk,250&last->nextchunk);251}252253queue->nchunks++;254rem_q_size -= c_size;255if (last)256*((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr;257258last = curr;259} while (rem_q_size);260261/* Make the queue circular */262/* Tie back last chunk entry to head */263curr = first;264*((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr;265queue->qhead = curr;266spin_lock_init(&queue->lock);267}268return 0;269270cmd_qfail:271free_command_queues(cptvf, cqinfo);272return -ENOMEM;273}274275static int init_command_queues(struct cpt_vf *cptvf, u32 qlen)276{277struct pci_dev *pdev = cptvf->pdev;278int ret;279280/* setup AE command queues */281ret = alloc_command_queues(cptvf, &cptvf->cqinfo, CPT_INST_SIZE,282qlen);283if (ret) {284dev_err(&pdev->dev, "failed to allocate AE command queues (%u)\n",285cptvf->nr_queues);286return ret;287}288289return ret;290}291292static void cleanup_command_queues(struct cpt_vf *cptvf)293{294struct pci_dev *pdev = cptvf->pdev;295296if (!cptvf->nr_queues)297return;298299dev_info(&pdev->dev, "Cleaning VQ command queue (%u)\n",300cptvf->nr_queues);301free_command_queues(cptvf, &cptvf->cqinfo);302}303304static void cptvf_sw_cleanup(struct cpt_vf *cptvf)305{306cleanup_worker_threads(cptvf);307cleanup_pending_queues(cptvf);308cleanup_command_queues(cptvf);309}310311static int cptvf_sw_init(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues)312{313struct pci_dev *pdev = cptvf->pdev;314int ret = 0;315u32 max_dev_queues = 0;316317max_dev_queues = CPT_NUM_QS_PER_VF;318/* possible cpus */319nr_queues = min_t(u32, nr_queues, max_dev_queues);320cptvf->nr_queues = nr_queues;321322ret = init_command_queues(cptvf, qlen);323if (ret) {324dev_err(&pdev->dev, "Failed to setup command queues (%u)\n",325nr_queues);326return ret;327}328329ret = init_pending_queues(cptvf, qlen, nr_queues);330if (ret) {331dev_err(&pdev->dev, "Failed to setup pending queues (%u)\n",332nr_queues);333goto setup_pqfail;334}335336/* Create worker threads for BH processing */337ret = init_worker_threads(cptvf);338if (ret) {339dev_err(&pdev->dev, "Failed to setup worker threads\n");340goto init_work_fail;341}342343return 0;344345init_work_fail:346cleanup_worker_threads(cptvf);347cleanup_pending_queues(cptvf);348349setup_pqfail:350cleanup_command_queues(cptvf);351352return ret;353}354355static void cptvf_free_irq_affinity(struct cpt_vf *cptvf, int vec)356{357irq_set_affinity_hint(pci_irq_vector(cptvf->pdev, vec), NULL);358free_cpumask_var(cptvf->affinity_mask[vec]);359}360361static void cptvf_write_vq_ctl(struct cpt_vf *cptvf, bool val)362{363union cptx_vqx_ctl vqx_ctl;364365vqx_ctl.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0));366vqx_ctl.s.ena = val;367cpt_write_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0), vqx_ctl.u);368}369370void cptvf_write_vq_doorbell(struct cpt_vf *cptvf, u32 val)371{372union cptx_vqx_doorbell vqx_dbell;373374vqx_dbell.u = cpt_read_csr64(cptvf->reg_base,375CPTX_VQX_DOORBELL(0, 0));376vqx_dbell.s.dbell_cnt = val * 8; /* Num of Instructions * 8 words */377cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DOORBELL(0, 0),378vqx_dbell.u);379}380381static void cptvf_write_vq_inprog(struct cpt_vf *cptvf, u8 val)382{383union cptx_vqx_inprog vqx_inprg;384385vqx_inprg.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0));386vqx_inprg.s.inflight = val;387cpt_write_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0), vqx_inprg.u);388}389390static void cptvf_write_vq_done_numwait(struct cpt_vf *cptvf, u32 val)391{392union cptx_vqx_done_wait vqx_dwait;393394vqx_dwait.u = cpt_read_csr64(cptvf->reg_base,395CPTX_VQX_DONE_WAIT(0, 0));396vqx_dwait.s.num_wait = val;397cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0),398vqx_dwait.u);399}400401static void cptvf_write_vq_done_timewait(struct cpt_vf *cptvf, u16 time)402{403union cptx_vqx_done_wait vqx_dwait;404405vqx_dwait.u = cpt_read_csr64(cptvf->reg_base,406CPTX_VQX_DONE_WAIT(0, 0));407vqx_dwait.s.time_wait = time;408cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0),409vqx_dwait.u);410}411412static void cptvf_enable_swerr_interrupts(struct cpt_vf *cptvf)413{414union cptx_vqx_misc_ena_w1s vqx_misc_ena;415416vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base,417CPTX_VQX_MISC_ENA_W1S(0, 0));418/* Set mbox(0) interupts for the requested vf */419vqx_misc_ena.s.swerr = 1;420cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0),421vqx_misc_ena.u);422}423424static void cptvf_enable_mbox_interrupts(struct cpt_vf *cptvf)425{426union cptx_vqx_misc_ena_w1s vqx_misc_ena;427428vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base,429CPTX_VQX_MISC_ENA_W1S(0, 0));430/* Set mbox(0) interupts for the requested vf */431vqx_misc_ena.s.mbox = 1;432cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0),433vqx_misc_ena.u);434}435436static void cptvf_enable_done_interrupts(struct cpt_vf *cptvf)437{438union cptx_vqx_done_ena_w1s vqx_done_ena;439440vqx_done_ena.u = cpt_read_csr64(cptvf->reg_base,441CPTX_VQX_DONE_ENA_W1S(0, 0));442/* Set DONE interrupt for the requested vf */443vqx_done_ena.s.done = 1;444cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ENA_W1S(0, 0),445vqx_done_ena.u);446}447448static void cptvf_clear_dovf_intr(struct cpt_vf *cptvf)449{450union cptx_vqx_misc_int vqx_misc_int;451452vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,453CPTX_VQX_MISC_INT(0, 0));454/* W1C for the VF */455vqx_misc_int.s.dovf = 1;456cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),457vqx_misc_int.u);458}459460static void cptvf_clear_irde_intr(struct cpt_vf *cptvf)461{462union cptx_vqx_misc_int vqx_misc_int;463464vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,465CPTX_VQX_MISC_INT(0, 0));466/* W1C for the VF */467vqx_misc_int.s.irde = 1;468cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),469vqx_misc_int.u);470}471472static void cptvf_clear_nwrp_intr(struct cpt_vf *cptvf)473{474union cptx_vqx_misc_int vqx_misc_int;475476vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,477CPTX_VQX_MISC_INT(0, 0));478/* W1C for the VF */479vqx_misc_int.s.nwrp = 1;480cpt_write_csr64(cptvf->reg_base,481CPTX_VQX_MISC_INT(0, 0), vqx_misc_int.u);482}483484static void cptvf_clear_mbox_intr(struct cpt_vf *cptvf)485{486union cptx_vqx_misc_int vqx_misc_int;487488vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,489CPTX_VQX_MISC_INT(0, 0));490/* W1C for the VF */491vqx_misc_int.s.mbox = 1;492cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),493vqx_misc_int.u);494}495496static void cptvf_clear_swerr_intr(struct cpt_vf *cptvf)497{498union cptx_vqx_misc_int vqx_misc_int;499500vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,501CPTX_VQX_MISC_INT(0, 0));502/* W1C for the VF */503vqx_misc_int.s.swerr = 1;504cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),505vqx_misc_int.u);506}507508static u64 cptvf_read_vf_misc_intr_status(struct cpt_vf *cptvf)509{510return cpt_read_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0));511}512513static irqreturn_t cptvf_misc_intr_handler(int irq, void *cptvf_irq)514{515struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq;516struct pci_dev *pdev = cptvf->pdev;517u64 intr;518519intr = cptvf_read_vf_misc_intr_status(cptvf);520/*Check for MISC interrupt types*/521if (likely(intr & CPT_VF_INTR_MBOX_MASK)) {522dev_dbg(&pdev->dev, "Mailbox interrupt 0x%llx on CPT VF %d\n",523intr, cptvf->vfid);524cptvf_handle_mbox_intr(cptvf);525cptvf_clear_mbox_intr(cptvf);526} else if (unlikely(intr & CPT_VF_INTR_DOVF_MASK)) {527cptvf_clear_dovf_intr(cptvf);528/*Clear doorbell count*/529cptvf_write_vq_doorbell(cptvf, 0);530dev_err(&pdev->dev, "Doorbell overflow error interrupt 0x%llx on CPT VF %d\n",531intr, cptvf->vfid);532} else if (unlikely(intr & CPT_VF_INTR_IRDE_MASK)) {533cptvf_clear_irde_intr(cptvf);534dev_err(&pdev->dev, "Instruction NCB read error interrupt 0x%llx on CPT VF %d\n",535intr, cptvf->vfid);536} else if (unlikely(intr & CPT_VF_INTR_NWRP_MASK)) {537cptvf_clear_nwrp_intr(cptvf);538dev_err(&pdev->dev, "NCB response write error interrupt 0x%llx on CPT VF %d\n",539intr, cptvf->vfid);540} else if (unlikely(intr & CPT_VF_INTR_SERR_MASK)) {541cptvf_clear_swerr_intr(cptvf);542dev_err(&pdev->dev, "Software error interrupt 0x%llx on CPT VF %d\n",543intr, cptvf->vfid);544} else {545dev_err(&pdev->dev, "Unhandled interrupt in CPT VF %d\n",546cptvf->vfid);547}548549return IRQ_HANDLED;550}551552static inline struct cptvf_wqe *get_cptvf_vq_wqe(struct cpt_vf *cptvf,553int qno)554{555struct cptvf_wqe_info *nwqe_info;556557if (unlikely(qno >= cptvf->nr_queues))558return NULL;559nwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info;560561return &nwqe_info->vq_wqe[qno];562}563564static inline u32 cptvf_read_vq_done_count(struct cpt_vf *cptvf)565{566union cptx_vqx_done vqx_done;567568vqx_done.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_DONE(0, 0));569return vqx_done.s.done;570}571572static inline void cptvf_write_vq_done_ack(struct cpt_vf *cptvf,573u32 ackcnt)574{575union cptx_vqx_done_ack vqx_dack_cnt;576577vqx_dack_cnt.u = cpt_read_csr64(cptvf->reg_base,578CPTX_VQX_DONE_ACK(0, 0));579vqx_dack_cnt.s.done_ack = ackcnt;580cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ACK(0, 0),581vqx_dack_cnt.u);582}583584static irqreturn_t cptvf_done_intr_handler(int irq, void *cptvf_irq)585{586struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq;587struct pci_dev *pdev = cptvf->pdev;588/* Read the number of completions */589u32 intr = cptvf_read_vq_done_count(cptvf);590591if (intr) {592struct cptvf_wqe *wqe;593594/* Acknowledge the number of595* scheduled completions for processing596*/597cptvf_write_vq_done_ack(cptvf, intr);598wqe = get_cptvf_vq_wqe(cptvf, 0);599if (unlikely(!wqe)) {600dev_err(&pdev->dev, "No work to schedule for VF (%d)",601cptvf->vfid);602return IRQ_NONE;603}604tasklet_hi_schedule(&wqe->twork);605}606607return IRQ_HANDLED;608}609610static void cptvf_set_irq_affinity(struct cpt_vf *cptvf, int vec)611{612struct pci_dev *pdev = cptvf->pdev;613int cpu;614615if (!zalloc_cpumask_var(&cptvf->affinity_mask[vec],616GFP_KERNEL)) {617dev_err(&pdev->dev, "Allocation failed for affinity_mask for VF %d",618cptvf->vfid);619return;620}621622cpu = cptvf->vfid % num_online_cpus();623cpumask_set_cpu(cpumask_local_spread(cpu, cptvf->node),624cptvf->affinity_mask[vec]);625irq_set_affinity_hint(pci_irq_vector(pdev, vec),626cptvf->affinity_mask[vec]);627}628629static void cptvf_write_vq_saddr(struct cpt_vf *cptvf, u64 val)630{631union cptx_vqx_saddr vqx_saddr;632633vqx_saddr.u = val;634cpt_write_csr64(cptvf->reg_base, CPTX_VQX_SADDR(0, 0), vqx_saddr.u);635}636637static void cptvf_device_init(struct cpt_vf *cptvf)638{639u64 base_addr = 0;640641/* Disable the VQ */642cptvf_write_vq_ctl(cptvf, 0);643/* Reset the doorbell */644cptvf_write_vq_doorbell(cptvf, 0);645/* Clear inflight */646cptvf_write_vq_inprog(cptvf, 0);647/* Write VQ SADDR */648/* TODO: for now only one queue, so hard coded */649base_addr = (u64)(cptvf->cqinfo.queue[0].qhead->dma_addr);650cptvf_write_vq_saddr(cptvf, base_addr);651/* Configure timerhold / coalescence */652cptvf_write_vq_done_timewait(cptvf, CPT_TIMER_THOLD);653cptvf_write_vq_done_numwait(cptvf, 1);654/* Enable the VQ */655cptvf_write_vq_ctl(cptvf, 1);656/* Flag the VF ready */657cptvf->flags |= CPT_FLAG_DEVICE_READY;658}659660static int cptvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)661{662struct device *dev = &pdev->dev;663struct cpt_vf *cptvf;664int err;665666cptvf = devm_kzalloc(dev, sizeof(*cptvf), GFP_KERNEL);667if (!cptvf)668return -ENOMEM;669670pci_set_drvdata(pdev, cptvf);671cptvf->pdev = pdev;672err = pci_enable_device(pdev);673if (err) {674dev_err(dev, "Failed to enable PCI device\n");675pci_set_drvdata(pdev, NULL);676return err;677}678679err = pci_request_regions(pdev, DRV_NAME);680if (err) {681dev_err(dev, "PCI request regions failed 0x%x\n", err);682goto cptvf_err_disable_device;683}684/* Mark as VF driver */685cptvf->flags |= CPT_FLAG_VF_DRIVER;686err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));687if (err) {688dev_err(dev, "Unable to get usable 48-bit DMA configuration\n");689goto cptvf_err_release_regions;690}691692/* MAP PF's configuration registers */693cptvf->reg_base = pcim_iomap(pdev, 0, 0);694if (!cptvf->reg_base) {695dev_err(dev, "Cannot map config register space, aborting\n");696err = -ENOMEM;697goto cptvf_err_release_regions;698}699700cptvf->node = dev_to_node(&pdev->dev);701err = pci_alloc_irq_vectors(pdev, CPT_VF_MSIX_VECTORS,702CPT_VF_MSIX_VECTORS, PCI_IRQ_MSIX);703if (err < 0) {704dev_err(dev, "Request for #%d msix vectors failed\n",705CPT_VF_MSIX_VECTORS);706goto cptvf_err_release_regions;707}708709err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC),710cptvf_misc_intr_handler, 0, "CPT VF misc intr",711cptvf);712if (err) {713dev_err(dev, "Request misc irq failed");714goto cptvf_free_vectors;715}716717/* Enable mailbox interrupt */718cptvf_enable_mbox_interrupts(cptvf);719cptvf_enable_swerr_interrupts(cptvf);720721/* Check ready with PF */722/* Gets chip ID / device Id from PF if ready */723err = cptvf_check_pf_ready(cptvf);724if (err) {725dev_err(dev, "PF not responding to READY msg");726goto cptvf_free_misc_irq;727}728729/* CPT VF software resources initialization */730cptvf->cqinfo.qchunksize = CPT_CMD_QCHUNK_SIZE;731err = cptvf_sw_init(cptvf, CPT_CMD_QLEN, CPT_NUM_QS_PER_VF);732if (err) {733dev_err(dev, "cptvf_sw_init() failed");734goto cptvf_free_misc_irq;735}736/* Convey VQ LEN to PF */737err = cptvf_send_vq_size_msg(cptvf);738if (err) {739dev_err(dev, "PF not responding to QLEN msg");740goto cptvf_free_misc_irq;741}742743/* CPT VF device initialization */744cptvf_device_init(cptvf);745/* Send msg to PF to assign currnet Q to required group */746cptvf->vfgrp = 1;747err = cptvf_send_vf_to_grp_msg(cptvf);748if (err) {749dev_err(dev, "PF not responding to VF_GRP msg");750goto cptvf_free_misc_irq;751}752753cptvf->priority = 1;754err = cptvf_send_vf_priority_msg(cptvf);755if (err) {756dev_err(dev, "PF not responding to VF_PRIO msg");757goto cptvf_free_misc_irq;758}759760err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE),761cptvf_done_intr_handler, 0, "CPT VF done intr",762cptvf);763if (err) {764dev_err(dev, "Request done irq failed\n");765goto cptvf_free_misc_irq;766}767768/* Enable mailbox interrupt */769cptvf_enable_done_interrupts(cptvf);770771/* Set irq affinity masks */772cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC);773cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE);774775err = cptvf_send_vf_up(cptvf);776if (err) {777dev_err(dev, "PF not responding to UP msg");778goto cptvf_free_irq_affinity;779}780err = cvm_crypto_init(cptvf);781if (err) {782dev_err(dev, "Algorithm register failed\n");783goto cptvf_free_irq_affinity;784}785return 0;786787cptvf_free_irq_affinity:788cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE);789cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC);790cptvf_free_misc_irq:791free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf);792cptvf_free_vectors:793pci_free_irq_vectors(cptvf->pdev);794cptvf_err_release_regions:795pci_release_regions(pdev);796cptvf_err_disable_device:797pci_disable_device(pdev);798pci_set_drvdata(pdev, NULL);799800return err;801}802803static void cptvf_remove(struct pci_dev *pdev)804{805struct cpt_vf *cptvf = pci_get_drvdata(pdev);806807if (!cptvf) {808dev_err(&pdev->dev, "Invalid CPT-VF device\n");809return;810}811812/* Convey DOWN to PF */813if (cptvf_send_vf_down(cptvf)) {814dev_err(&pdev->dev, "PF not responding to DOWN msg");815} else {816cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE);817cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC);818free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), cptvf);819free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf);820pci_free_irq_vectors(cptvf->pdev);821cptvf_sw_cleanup(cptvf);822pci_set_drvdata(pdev, NULL);823pci_release_regions(pdev);824pci_disable_device(pdev);825cvm_crypto_exit();826}827}828829static void cptvf_shutdown(struct pci_dev *pdev)830{831cptvf_remove(pdev);832}833834/* Supported devices */835static const struct pci_device_id cptvf_id_table[] = {836{PCI_VDEVICE(CAVIUM, CPT_81XX_PCI_VF_DEVICE_ID), 0},837{ 0, } /* end of table */838};839840static struct pci_driver cptvf_pci_driver = {841.name = DRV_NAME,842.id_table = cptvf_id_table,843.probe = cptvf_probe,844.remove = cptvf_remove,845.shutdown = cptvf_shutdown,846};847848module_pci_driver(cptvf_pci_driver);849850MODULE_AUTHOR("George Cherian <[email protected]>");851MODULE_DESCRIPTION("Cavium Thunder CPT Virtual Function Driver");852MODULE_LICENSE("GPL v2");853MODULE_VERSION(DRV_VERSION);854MODULE_DEVICE_TABLE(pci, cptvf_id_table);855856857