1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2016 Cavium, Inc.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/interrupt.h>
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "cptvf.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define DRV_NAME "thunder-cptvf"
12*4882a593Smuzhiyun #define DRV_VERSION "1.0"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun struct cptvf_wqe {
15*4882a593Smuzhiyun struct tasklet_struct twork;
16*4882a593Smuzhiyun void *cptvf;
17*4882a593Smuzhiyun u32 qno;
18*4882a593Smuzhiyun };
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun struct cptvf_wqe_info {
21*4882a593Smuzhiyun struct cptvf_wqe vq_wqe[CPT_NUM_QS_PER_VF];
22*4882a593Smuzhiyun };
23*4882a593Smuzhiyun
vq_work_handler(unsigned long data)24*4882a593Smuzhiyun static void vq_work_handler(unsigned long data)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun struct cptvf_wqe_info *cwqe_info = (struct cptvf_wqe_info *)data;
27*4882a593Smuzhiyun struct cptvf_wqe *cwqe = &cwqe_info->vq_wqe[0];
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun vq_post_process(cwqe->cptvf, cwqe->qno);
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
init_worker_threads(struct cpt_vf * cptvf)32*4882a593Smuzhiyun static int init_worker_threads(struct cpt_vf *cptvf)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
35*4882a593Smuzhiyun struct cptvf_wqe_info *cwqe_info;
36*4882a593Smuzhiyun int i;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun cwqe_info = kzalloc(sizeof(*cwqe_info), GFP_KERNEL);
39*4882a593Smuzhiyun if (!cwqe_info)
40*4882a593Smuzhiyun return -ENOMEM;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun if (cptvf->nr_queues) {
43*4882a593Smuzhiyun dev_info(&pdev->dev, "Creating VQ worker threads (%d)\n",
44*4882a593Smuzhiyun cptvf->nr_queues);
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun for (i = 0; i < cptvf->nr_queues; i++) {
48*4882a593Smuzhiyun tasklet_init(&cwqe_info->vq_wqe[i].twork, vq_work_handler,
49*4882a593Smuzhiyun (u64)cwqe_info);
50*4882a593Smuzhiyun cwqe_info->vq_wqe[i].qno = i;
51*4882a593Smuzhiyun cwqe_info->vq_wqe[i].cptvf = cptvf;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun cptvf->wqe_info = cwqe_info;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return 0;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
cleanup_worker_threads(struct cpt_vf * cptvf)59*4882a593Smuzhiyun static void cleanup_worker_threads(struct cpt_vf *cptvf)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun struct cptvf_wqe_info *cwqe_info;
62*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
63*4882a593Smuzhiyun int i;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun cwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info;
66*4882a593Smuzhiyun if (!cwqe_info)
67*4882a593Smuzhiyun return;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (cptvf->nr_queues) {
70*4882a593Smuzhiyun dev_info(&pdev->dev, "Cleaning VQ worker threads (%u)\n",
71*4882a593Smuzhiyun cptvf->nr_queues);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun for (i = 0; i < cptvf->nr_queues; i++)
75*4882a593Smuzhiyun tasklet_kill(&cwqe_info->vq_wqe[i].twork);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun kfree_sensitive(cwqe_info);
78*4882a593Smuzhiyun cptvf->wqe_info = NULL;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
free_pending_queues(struct pending_qinfo * pqinfo)81*4882a593Smuzhiyun static void free_pending_queues(struct pending_qinfo *pqinfo)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun int i;
84*4882a593Smuzhiyun struct pending_queue *queue;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun for_each_pending_queue(pqinfo, queue, i) {
87*4882a593Smuzhiyun if (!queue->head)
88*4882a593Smuzhiyun continue;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* free single queue */
91*4882a593Smuzhiyun kfree_sensitive((queue->head));
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun queue->front = 0;
94*4882a593Smuzhiyun queue->rear = 0;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun pqinfo->qlen = 0;
100*4882a593Smuzhiyun pqinfo->nr_queues = 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
alloc_pending_queues(struct pending_qinfo * pqinfo,u32 qlen,u32 nr_queues)103*4882a593Smuzhiyun static int alloc_pending_queues(struct pending_qinfo *pqinfo, u32 qlen,
104*4882a593Smuzhiyun u32 nr_queues)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun u32 i;
107*4882a593Smuzhiyun size_t size;
108*4882a593Smuzhiyun int ret;
109*4882a593Smuzhiyun struct pending_queue *queue = NULL;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun pqinfo->nr_queues = nr_queues;
112*4882a593Smuzhiyun pqinfo->qlen = qlen;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun size = (qlen * sizeof(struct pending_entry));
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun for_each_pending_queue(pqinfo, queue, i) {
117*4882a593Smuzhiyun queue->head = kzalloc((size), GFP_KERNEL);
118*4882a593Smuzhiyun if (!queue->head) {
119*4882a593Smuzhiyun ret = -ENOMEM;
120*4882a593Smuzhiyun goto pending_qfail;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun queue->front = 0;
124*4882a593Smuzhiyun queue->rear = 0;
125*4882a593Smuzhiyun atomic64_set((&queue->pending_count), (0));
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* init queue spin lock */
128*4882a593Smuzhiyun spin_lock_init(&queue->lock);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return 0;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun pending_qfail:
134*4882a593Smuzhiyun free_pending_queues(pqinfo);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun return ret;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
init_pending_queues(struct cpt_vf * cptvf,u32 qlen,u32 nr_queues)139*4882a593Smuzhiyun static int init_pending_queues(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
142*4882a593Smuzhiyun int ret;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (!nr_queues)
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun ret = alloc_pending_queues(&cptvf->pqinfo, qlen, nr_queues);
148*4882a593Smuzhiyun if (ret) {
149*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to setup pending queues (%u)\n",
150*4882a593Smuzhiyun nr_queues);
151*4882a593Smuzhiyun return ret;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun return 0;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
cleanup_pending_queues(struct cpt_vf * cptvf)157*4882a593Smuzhiyun static void cleanup_pending_queues(struct cpt_vf *cptvf)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (!cptvf->nr_queues)
162*4882a593Smuzhiyun return;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun dev_info(&pdev->dev, "Cleaning VQ pending queue (%u)\n",
165*4882a593Smuzhiyun cptvf->nr_queues);
166*4882a593Smuzhiyun free_pending_queues(&cptvf->pqinfo);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
free_command_queues(struct cpt_vf * cptvf,struct command_qinfo * cqinfo)169*4882a593Smuzhiyun static void free_command_queues(struct cpt_vf *cptvf,
170*4882a593Smuzhiyun struct command_qinfo *cqinfo)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun int i;
173*4882a593Smuzhiyun struct command_queue *queue = NULL;
174*4882a593Smuzhiyun struct command_chunk *chunk = NULL;
175*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
176*4882a593Smuzhiyun struct hlist_node *node;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* clean up for each queue */
179*4882a593Smuzhiyun for (i = 0; i < cptvf->nr_queues; i++) {
180*4882a593Smuzhiyun queue = &cqinfo->queue[i];
181*4882a593Smuzhiyun if (hlist_empty(&cqinfo->queue[i].chead))
182*4882a593Smuzhiyun continue;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun hlist_for_each_entry_safe(chunk, node, &cqinfo->queue[i].chead,
185*4882a593Smuzhiyun nextchunk) {
186*4882a593Smuzhiyun dma_free_coherent(&pdev->dev, chunk->size,
187*4882a593Smuzhiyun chunk->head,
188*4882a593Smuzhiyun chunk->dma_addr);
189*4882a593Smuzhiyun chunk->head = NULL;
190*4882a593Smuzhiyun chunk->dma_addr = 0;
191*4882a593Smuzhiyun hlist_del(&chunk->nextchunk);
192*4882a593Smuzhiyun kfree_sensitive(chunk);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun queue->nchunks = 0;
196*4882a593Smuzhiyun queue->idx = 0;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* common cleanup */
200*4882a593Smuzhiyun cqinfo->cmd_size = 0;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
alloc_command_queues(struct cpt_vf * cptvf,struct command_qinfo * cqinfo,size_t cmd_size,u32 qlen)203*4882a593Smuzhiyun static int alloc_command_queues(struct cpt_vf *cptvf,
204*4882a593Smuzhiyun struct command_qinfo *cqinfo, size_t cmd_size,
205*4882a593Smuzhiyun u32 qlen)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun int i;
208*4882a593Smuzhiyun size_t q_size;
209*4882a593Smuzhiyun struct command_queue *queue = NULL;
210*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /* common init */
213*4882a593Smuzhiyun cqinfo->cmd_size = cmd_size;
214*4882a593Smuzhiyun /* Qsize in dwords, needed for SADDR config, 1-next chunk pointer */
215*4882a593Smuzhiyun cptvf->qsize = min(qlen, cqinfo->qchunksize) *
216*4882a593Smuzhiyun CPT_NEXT_CHUNK_PTR_SIZE + 1;
217*4882a593Smuzhiyun /* Qsize in bytes to create space for alignment */
218*4882a593Smuzhiyun q_size = qlen * cqinfo->cmd_size;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /* per queue initialization */
221*4882a593Smuzhiyun for (i = 0; i < cptvf->nr_queues; i++) {
222*4882a593Smuzhiyun size_t c_size = 0;
223*4882a593Smuzhiyun size_t rem_q_size = q_size;
224*4882a593Smuzhiyun struct command_chunk *curr = NULL, *first = NULL, *last = NULL;
225*4882a593Smuzhiyun u32 qcsize_bytes = cqinfo->qchunksize * cqinfo->cmd_size;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun queue = &cqinfo->queue[i];
228*4882a593Smuzhiyun INIT_HLIST_HEAD(&cqinfo->queue[i].chead);
229*4882a593Smuzhiyun do {
230*4882a593Smuzhiyun curr = kzalloc(sizeof(*curr), GFP_KERNEL);
231*4882a593Smuzhiyun if (!curr)
232*4882a593Smuzhiyun goto cmd_qfail;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun c_size = (rem_q_size > qcsize_bytes) ? qcsize_bytes :
235*4882a593Smuzhiyun rem_q_size;
236*4882a593Smuzhiyun curr->head = (u8 *)dma_alloc_coherent(&pdev->dev,
237*4882a593Smuzhiyun c_size + CPT_NEXT_CHUNK_PTR_SIZE,
238*4882a593Smuzhiyun &curr->dma_addr,
239*4882a593Smuzhiyun GFP_KERNEL);
240*4882a593Smuzhiyun if (!curr->head) {
241*4882a593Smuzhiyun dev_err(&pdev->dev, "Command Q (%d) chunk (%d) allocation failed\n",
242*4882a593Smuzhiyun i, queue->nchunks);
243*4882a593Smuzhiyun kfree(curr);
244*4882a593Smuzhiyun goto cmd_qfail;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun curr->size = c_size;
248*4882a593Smuzhiyun if (queue->nchunks == 0) {
249*4882a593Smuzhiyun hlist_add_head(&curr->nextchunk,
250*4882a593Smuzhiyun &cqinfo->queue[i].chead);
251*4882a593Smuzhiyun first = curr;
252*4882a593Smuzhiyun } else {
253*4882a593Smuzhiyun hlist_add_behind(&curr->nextchunk,
254*4882a593Smuzhiyun &last->nextchunk);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun queue->nchunks++;
258*4882a593Smuzhiyun rem_q_size -= c_size;
259*4882a593Smuzhiyun if (last)
260*4882a593Smuzhiyun *((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun last = curr;
263*4882a593Smuzhiyun } while (rem_q_size);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /* Make the queue circular */
266*4882a593Smuzhiyun /* Tie back last chunk entry to head */
267*4882a593Smuzhiyun curr = first;
268*4882a593Smuzhiyun *((u64 *)(&last->head[last->size])) = (u64)curr->dma_addr;
269*4882a593Smuzhiyun queue->qhead = curr;
270*4882a593Smuzhiyun spin_lock_init(&queue->lock);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun return 0;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun cmd_qfail:
275*4882a593Smuzhiyun free_command_queues(cptvf, cqinfo);
276*4882a593Smuzhiyun return -ENOMEM;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
init_command_queues(struct cpt_vf * cptvf,u32 qlen)279*4882a593Smuzhiyun static int init_command_queues(struct cpt_vf *cptvf, u32 qlen)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
282*4882a593Smuzhiyun int ret;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* setup AE command queues */
285*4882a593Smuzhiyun ret = alloc_command_queues(cptvf, &cptvf->cqinfo, CPT_INST_SIZE,
286*4882a593Smuzhiyun qlen);
287*4882a593Smuzhiyun if (ret) {
288*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to allocate AE command queues (%u)\n",
289*4882a593Smuzhiyun cptvf->nr_queues);
290*4882a593Smuzhiyun return ret;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun return ret;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
cleanup_command_queues(struct cpt_vf * cptvf)296*4882a593Smuzhiyun static void cleanup_command_queues(struct cpt_vf *cptvf)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (!cptvf->nr_queues)
301*4882a593Smuzhiyun return;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun dev_info(&pdev->dev, "Cleaning VQ command queue (%u)\n",
304*4882a593Smuzhiyun cptvf->nr_queues);
305*4882a593Smuzhiyun free_command_queues(cptvf, &cptvf->cqinfo);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
cptvf_sw_cleanup(struct cpt_vf * cptvf)308*4882a593Smuzhiyun static void cptvf_sw_cleanup(struct cpt_vf *cptvf)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun cleanup_worker_threads(cptvf);
311*4882a593Smuzhiyun cleanup_pending_queues(cptvf);
312*4882a593Smuzhiyun cleanup_command_queues(cptvf);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
cptvf_sw_init(struct cpt_vf * cptvf,u32 qlen,u32 nr_queues)315*4882a593Smuzhiyun static int cptvf_sw_init(struct cpt_vf *cptvf, u32 qlen, u32 nr_queues)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
318*4882a593Smuzhiyun int ret = 0;
319*4882a593Smuzhiyun u32 max_dev_queues = 0;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun max_dev_queues = CPT_NUM_QS_PER_VF;
322*4882a593Smuzhiyun /* possible cpus */
323*4882a593Smuzhiyun nr_queues = min_t(u32, nr_queues, max_dev_queues);
324*4882a593Smuzhiyun cptvf->nr_queues = nr_queues;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun ret = init_command_queues(cptvf, qlen);
327*4882a593Smuzhiyun if (ret) {
328*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to setup command queues (%u)\n",
329*4882a593Smuzhiyun nr_queues);
330*4882a593Smuzhiyun return ret;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun ret = init_pending_queues(cptvf, qlen, nr_queues);
334*4882a593Smuzhiyun if (ret) {
335*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to setup pending queues (%u)\n",
336*4882a593Smuzhiyun nr_queues);
337*4882a593Smuzhiyun goto setup_pqfail;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* Create worker threads for BH processing */
341*4882a593Smuzhiyun ret = init_worker_threads(cptvf);
342*4882a593Smuzhiyun if (ret) {
343*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to setup worker threads\n");
344*4882a593Smuzhiyun goto init_work_fail;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun return 0;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun init_work_fail:
350*4882a593Smuzhiyun cleanup_worker_threads(cptvf);
351*4882a593Smuzhiyun cleanup_pending_queues(cptvf);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun setup_pqfail:
354*4882a593Smuzhiyun cleanup_command_queues(cptvf);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun return ret;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
cptvf_free_irq_affinity(struct cpt_vf * cptvf,int vec)359*4882a593Smuzhiyun static void cptvf_free_irq_affinity(struct cpt_vf *cptvf, int vec)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun irq_set_affinity_hint(pci_irq_vector(cptvf->pdev, vec), NULL);
362*4882a593Smuzhiyun free_cpumask_var(cptvf->affinity_mask[vec]);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
cptvf_write_vq_ctl(struct cpt_vf * cptvf,bool val)365*4882a593Smuzhiyun static void cptvf_write_vq_ctl(struct cpt_vf *cptvf, bool val)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun union cptx_vqx_ctl vqx_ctl;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun vqx_ctl.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0));
370*4882a593Smuzhiyun vqx_ctl.s.ena = val;
371*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_CTL(0, 0), vqx_ctl.u);
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
cptvf_write_vq_doorbell(struct cpt_vf * cptvf,u32 val)374*4882a593Smuzhiyun void cptvf_write_vq_doorbell(struct cpt_vf *cptvf, u32 val)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun union cptx_vqx_doorbell vqx_dbell;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun vqx_dbell.u = cpt_read_csr64(cptvf->reg_base,
379*4882a593Smuzhiyun CPTX_VQX_DOORBELL(0, 0));
380*4882a593Smuzhiyun vqx_dbell.s.dbell_cnt = val * 8; /* Num of Instructions * 8 words */
381*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DOORBELL(0, 0),
382*4882a593Smuzhiyun vqx_dbell.u);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
cptvf_write_vq_inprog(struct cpt_vf * cptvf,u8 val)385*4882a593Smuzhiyun static void cptvf_write_vq_inprog(struct cpt_vf *cptvf, u8 val)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun union cptx_vqx_inprog vqx_inprg;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun vqx_inprg.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0));
390*4882a593Smuzhiyun vqx_inprg.s.inflight = val;
391*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_INPROG(0, 0), vqx_inprg.u);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
cptvf_write_vq_done_numwait(struct cpt_vf * cptvf,u32 val)394*4882a593Smuzhiyun static void cptvf_write_vq_done_numwait(struct cpt_vf *cptvf, u32 val)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun union cptx_vqx_done_wait vqx_dwait;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun vqx_dwait.u = cpt_read_csr64(cptvf->reg_base,
399*4882a593Smuzhiyun CPTX_VQX_DONE_WAIT(0, 0));
400*4882a593Smuzhiyun vqx_dwait.s.num_wait = val;
401*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0),
402*4882a593Smuzhiyun vqx_dwait.u);
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
cptvf_write_vq_done_timewait(struct cpt_vf * cptvf,u16 time)405*4882a593Smuzhiyun static void cptvf_write_vq_done_timewait(struct cpt_vf *cptvf, u16 time)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun union cptx_vqx_done_wait vqx_dwait;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun vqx_dwait.u = cpt_read_csr64(cptvf->reg_base,
410*4882a593Smuzhiyun CPTX_VQX_DONE_WAIT(0, 0));
411*4882a593Smuzhiyun vqx_dwait.s.time_wait = time;
412*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_WAIT(0, 0),
413*4882a593Smuzhiyun vqx_dwait.u);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
cptvf_enable_swerr_interrupts(struct cpt_vf * cptvf)416*4882a593Smuzhiyun static void cptvf_enable_swerr_interrupts(struct cpt_vf *cptvf)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun union cptx_vqx_misc_ena_w1s vqx_misc_ena;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base,
421*4882a593Smuzhiyun CPTX_VQX_MISC_ENA_W1S(0, 0));
422*4882a593Smuzhiyun /* Set mbox(0) interupts for the requested vf */
423*4882a593Smuzhiyun vqx_misc_ena.s.swerr = 1;
424*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0),
425*4882a593Smuzhiyun vqx_misc_ena.u);
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
cptvf_enable_mbox_interrupts(struct cpt_vf * cptvf)428*4882a593Smuzhiyun static void cptvf_enable_mbox_interrupts(struct cpt_vf *cptvf)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun union cptx_vqx_misc_ena_w1s vqx_misc_ena;
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun vqx_misc_ena.u = cpt_read_csr64(cptvf->reg_base,
433*4882a593Smuzhiyun CPTX_VQX_MISC_ENA_W1S(0, 0));
434*4882a593Smuzhiyun /* Set mbox(0) interupts for the requested vf */
435*4882a593Smuzhiyun vqx_misc_ena.s.mbox = 1;
436*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_ENA_W1S(0, 0),
437*4882a593Smuzhiyun vqx_misc_ena.u);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
cptvf_enable_done_interrupts(struct cpt_vf * cptvf)440*4882a593Smuzhiyun static void cptvf_enable_done_interrupts(struct cpt_vf *cptvf)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun union cptx_vqx_done_ena_w1s vqx_done_ena;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun vqx_done_ena.u = cpt_read_csr64(cptvf->reg_base,
445*4882a593Smuzhiyun CPTX_VQX_DONE_ENA_W1S(0, 0));
446*4882a593Smuzhiyun /* Set DONE interrupt for the requested vf */
447*4882a593Smuzhiyun vqx_done_ena.s.done = 1;
448*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ENA_W1S(0, 0),
449*4882a593Smuzhiyun vqx_done_ena.u);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
cptvf_clear_dovf_intr(struct cpt_vf * cptvf)452*4882a593Smuzhiyun static void cptvf_clear_dovf_intr(struct cpt_vf *cptvf)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun union cptx_vqx_misc_int vqx_misc_int;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,
457*4882a593Smuzhiyun CPTX_VQX_MISC_INT(0, 0));
458*4882a593Smuzhiyun /* W1C for the VF */
459*4882a593Smuzhiyun vqx_misc_int.s.dovf = 1;
460*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),
461*4882a593Smuzhiyun vqx_misc_int.u);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
cptvf_clear_irde_intr(struct cpt_vf * cptvf)464*4882a593Smuzhiyun static void cptvf_clear_irde_intr(struct cpt_vf *cptvf)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun union cptx_vqx_misc_int vqx_misc_int;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,
469*4882a593Smuzhiyun CPTX_VQX_MISC_INT(0, 0));
470*4882a593Smuzhiyun /* W1C for the VF */
471*4882a593Smuzhiyun vqx_misc_int.s.irde = 1;
472*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),
473*4882a593Smuzhiyun vqx_misc_int.u);
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
cptvf_clear_nwrp_intr(struct cpt_vf * cptvf)476*4882a593Smuzhiyun static void cptvf_clear_nwrp_intr(struct cpt_vf *cptvf)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun union cptx_vqx_misc_int vqx_misc_int;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,
481*4882a593Smuzhiyun CPTX_VQX_MISC_INT(0, 0));
482*4882a593Smuzhiyun /* W1C for the VF */
483*4882a593Smuzhiyun vqx_misc_int.s.nwrp = 1;
484*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base,
485*4882a593Smuzhiyun CPTX_VQX_MISC_INT(0, 0), vqx_misc_int.u);
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
cptvf_clear_mbox_intr(struct cpt_vf * cptvf)488*4882a593Smuzhiyun static void cptvf_clear_mbox_intr(struct cpt_vf *cptvf)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun union cptx_vqx_misc_int vqx_misc_int;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,
493*4882a593Smuzhiyun CPTX_VQX_MISC_INT(0, 0));
494*4882a593Smuzhiyun /* W1C for the VF */
495*4882a593Smuzhiyun vqx_misc_int.s.mbox = 1;
496*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),
497*4882a593Smuzhiyun vqx_misc_int.u);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
cptvf_clear_swerr_intr(struct cpt_vf * cptvf)500*4882a593Smuzhiyun static void cptvf_clear_swerr_intr(struct cpt_vf *cptvf)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun union cptx_vqx_misc_int vqx_misc_int;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun vqx_misc_int.u = cpt_read_csr64(cptvf->reg_base,
505*4882a593Smuzhiyun CPTX_VQX_MISC_INT(0, 0));
506*4882a593Smuzhiyun /* W1C for the VF */
507*4882a593Smuzhiyun vqx_misc_int.s.swerr = 1;
508*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0),
509*4882a593Smuzhiyun vqx_misc_int.u);
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
cptvf_read_vf_misc_intr_status(struct cpt_vf * cptvf)512*4882a593Smuzhiyun static u64 cptvf_read_vf_misc_intr_status(struct cpt_vf *cptvf)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun return cpt_read_csr64(cptvf->reg_base, CPTX_VQX_MISC_INT(0, 0));
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
cptvf_misc_intr_handler(int irq,void * cptvf_irq)517*4882a593Smuzhiyun static irqreturn_t cptvf_misc_intr_handler(int irq, void *cptvf_irq)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq;
520*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
521*4882a593Smuzhiyun u64 intr;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun intr = cptvf_read_vf_misc_intr_status(cptvf);
524*4882a593Smuzhiyun /*Check for MISC interrupt types*/
525*4882a593Smuzhiyun if (likely(intr & CPT_VF_INTR_MBOX_MASK)) {
526*4882a593Smuzhiyun dev_dbg(&pdev->dev, "Mailbox interrupt 0x%llx on CPT VF %d\n",
527*4882a593Smuzhiyun intr, cptvf->vfid);
528*4882a593Smuzhiyun cptvf_handle_mbox_intr(cptvf);
529*4882a593Smuzhiyun cptvf_clear_mbox_intr(cptvf);
530*4882a593Smuzhiyun } else if (unlikely(intr & CPT_VF_INTR_DOVF_MASK)) {
531*4882a593Smuzhiyun cptvf_clear_dovf_intr(cptvf);
532*4882a593Smuzhiyun /*Clear doorbell count*/
533*4882a593Smuzhiyun cptvf_write_vq_doorbell(cptvf, 0);
534*4882a593Smuzhiyun dev_err(&pdev->dev, "Doorbell overflow error interrupt 0x%llx on CPT VF %d\n",
535*4882a593Smuzhiyun intr, cptvf->vfid);
536*4882a593Smuzhiyun } else if (unlikely(intr & CPT_VF_INTR_IRDE_MASK)) {
537*4882a593Smuzhiyun cptvf_clear_irde_intr(cptvf);
538*4882a593Smuzhiyun dev_err(&pdev->dev, "Instruction NCB read error interrupt 0x%llx on CPT VF %d\n",
539*4882a593Smuzhiyun intr, cptvf->vfid);
540*4882a593Smuzhiyun } else if (unlikely(intr & CPT_VF_INTR_NWRP_MASK)) {
541*4882a593Smuzhiyun cptvf_clear_nwrp_intr(cptvf);
542*4882a593Smuzhiyun dev_err(&pdev->dev, "NCB response write error interrupt 0x%llx on CPT VF %d\n",
543*4882a593Smuzhiyun intr, cptvf->vfid);
544*4882a593Smuzhiyun } else if (unlikely(intr & CPT_VF_INTR_SERR_MASK)) {
545*4882a593Smuzhiyun cptvf_clear_swerr_intr(cptvf);
546*4882a593Smuzhiyun dev_err(&pdev->dev, "Software error interrupt 0x%llx on CPT VF %d\n",
547*4882a593Smuzhiyun intr, cptvf->vfid);
548*4882a593Smuzhiyun } else {
549*4882a593Smuzhiyun dev_err(&pdev->dev, "Unhandled interrupt in CPT VF %d\n",
550*4882a593Smuzhiyun cptvf->vfid);
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun return IRQ_HANDLED;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
get_cptvf_vq_wqe(struct cpt_vf * cptvf,int qno)556*4882a593Smuzhiyun static inline struct cptvf_wqe *get_cptvf_vq_wqe(struct cpt_vf *cptvf,
557*4882a593Smuzhiyun int qno)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun struct cptvf_wqe_info *nwqe_info;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun if (unlikely(qno >= cptvf->nr_queues))
562*4882a593Smuzhiyun return NULL;
563*4882a593Smuzhiyun nwqe_info = (struct cptvf_wqe_info *)cptvf->wqe_info;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun return &nwqe_info->vq_wqe[qno];
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
cptvf_read_vq_done_count(struct cpt_vf * cptvf)568*4882a593Smuzhiyun static inline u32 cptvf_read_vq_done_count(struct cpt_vf *cptvf)
569*4882a593Smuzhiyun {
570*4882a593Smuzhiyun union cptx_vqx_done vqx_done;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun vqx_done.u = cpt_read_csr64(cptvf->reg_base, CPTX_VQX_DONE(0, 0));
573*4882a593Smuzhiyun return vqx_done.s.done;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
cptvf_write_vq_done_ack(struct cpt_vf * cptvf,u32 ackcnt)576*4882a593Smuzhiyun static inline void cptvf_write_vq_done_ack(struct cpt_vf *cptvf,
577*4882a593Smuzhiyun u32 ackcnt)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun union cptx_vqx_done_ack vqx_dack_cnt;
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun vqx_dack_cnt.u = cpt_read_csr64(cptvf->reg_base,
582*4882a593Smuzhiyun CPTX_VQX_DONE_ACK(0, 0));
583*4882a593Smuzhiyun vqx_dack_cnt.s.done_ack = ackcnt;
584*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_DONE_ACK(0, 0),
585*4882a593Smuzhiyun vqx_dack_cnt.u);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
cptvf_done_intr_handler(int irq,void * cptvf_irq)588*4882a593Smuzhiyun static irqreturn_t cptvf_done_intr_handler(int irq, void *cptvf_irq)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun struct cpt_vf *cptvf = (struct cpt_vf *)cptvf_irq;
591*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
592*4882a593Smuzhiyun /* Read the number of completions */
593*4882a593Smuzhiyun u32 intr = cptvf_read_vq_done_count(cptvf);
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun if (intr) {
596*4882a593Smuzhiyun struct cptvf_wqe *wqe;
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun /* Acknowledge the number of
599*4882a593Smuzhiyun * scheduled completions for processing
600*4882a593Smuzhiyun */
601*4882a593Smuzhiyun cptvf_write_vq_done_ack(cptvf, intr);
602*4882a593Smuzhiyun wqe = get_cptvf_vq_wqe(cptvf, 0);
603*4882a593Smuzhiyun if (unlikely(!wqe)) {
604*4882a593Smuzhiyun dev_err(&pdev->dev, "No work to schedule for VF (%d)",
605*4882a593Smuzhiyun cptvf->vfid);
606*4882a593Smuzhiyun return IRQ_NONE;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun tasklet_hi_schedule(&wqe->twork);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun return IRQ_HANDLED;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
cptvf_set_irq_affinity(struct cpt_vf * cptvf,int vec)614*4882a593Smuzhiyun static void cptvf_set_irq_affinity(struct cpt_vf *cptvf, int vec)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun struct pci_dev *pdev = cptvf->pdev;
617*4882a593Smuzhiyun int cpu;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (!zalloc_cpumask_var(&cptvf->affinity_mask[vec],
620*4882a593Smuzhiyun GFP_KERNEL)) {
621*4882a593Smuzhiyun dev_err(&pdev->dev, "Allocation failed for affinity_mask for VF %d",
622*4882a593Smuzhiyun cptvf->vfid);
623*4882a593Smuzhiyun return;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun cpu = cptvf->vfid % num_online_cpus();
627*4882a593Smuzhiyun cpumask_set_cpu(cpumask_local_spread(cpu, cptvf->node),
628*4882a593Smuzhiyun cptvf->affinity_mask[vec]);
629*4882a593Smuzhiyun irq_set_affinity_hint(pci_irq_vector(pdev, vec),
630*4882a593Smuzhiyun cptvf->affinity_mask[vec]);
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
cptvf_write_vq_saddr(struct cpt_vf * cptvf,u64 val)633*4882a593Smuzhiyun static void cptvf_write_vq_saddr(struct cpt_vf *cptvf, u64 val)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun union cptx_vqx_saddr vqx_saddr;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun vqx_saddr.u = val;
638*4882a593Smuzhiyun cpt_write_csr64(cptvf->reg_base, CPTX_VQX_SADDR(0, 0), vqx_saddr.u);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
cptvf_device_init(struct cpt_vf * cptvf)641*4882a593Smuzhiyun static void cptvf_device_init(struct cpt_vf *cptvf)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun u64 base_addr = 0;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun /* Disable the VQ */
646*4882a593Smuzhiyun cptvf_write_vq_ctl(cptvf, 0);
647*4882a593Smuzhiyun /* Reset the doorbell */
648*4882a593Smuzhiyun cptvf_write_vq_doorbell(cptvf, 0);
649*4882a593Smuzhiyun /* Clear inflight */
650*4882a593Smuzhiyun cptvf_write_vq_inprog(cptvf, 0);
651*4882a593Smuzhiyun /* Write VQ SADDR */
652*4882a593Smuzhiyun /* TODO: for now only one queue, so hard coded */
653*4882a593Smuzhiyun base_addr = (u64)(cptvf->cqinfo.queue[0].qhead->dma_addr);
654*4882a593Smuzhiyun cptvf_write_vq_saddr(cptvf, base_addr);
655*4882a593Smuzhiyun /* Configure timerhold / coalescence */
656*4882a593Smuzhiyun cptvf_write_vq_done_timewait(cptvf, CPT_TIMER_THOLD);
657*4882a593Smuzhiyun cptvf_write_vq_done_numwait(cptvf, 1);
658*4882a593Smuzhiyun /* Enable the VQ */
659*4882a593Smuzhiyun cptvf_write_vq_ctl(cptvf, 1);
660*4882a593Smuzhiyun /* Flag the VF ready */
661*4882a593Smuzhiyun cptvf->flags |= CPT_FLAG_DEVICE_READY;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
cptvf_probe(struct pci_dev * pdev,const struct pci_device_id * ent)664*4882a593Smuzhiyun static int cptvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun struct device *dev = &pdev->dev;
667*4882a593Smuzhiyun struct cpt_vf *cptvf;
668*4882a593Smuzhiyun int err;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun cptvf = devm_kzalloc(dev, sizeof(*cptvf), GFP_KERNEL);
671*4882a593Smuzhiyun if (!cptvf)
672*4882a593Smuzhiyun return -ENOMEM;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun pci_set_drvdata(pdev, cptvf);
675*4882a593Smuzhiyun cptvf->pdev = pdev;
676*4882a593Smuzhiyun err = pci_enable_device(pdev);
677*4882a593Smuzhiyun if (err) {
678*4882a593Smuzhiyun dev_err(dev, "Failed to enable PCI device\n");
679*4882a593Smuzhiyun pci_set_drvdata(pdev, NULL);
680*4882a593Smuzhiyun return err;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun err = pci_request_regions(pdev, DRV_NAME);
684*4882a593Smuzhiyun if (err) {
685*4882a593Smuzhiyun dev_err(dev, "PCI request regions failed 0x%x\n", err);
686*4882a593Smuzhiyun goto cptvf_err_disable_device;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun /* Mark as VF driver */
689*4882a593Smuzhiyun cptvf->flags |= CPT_FLAG_VF_DRIVER;
690*4882a593Smuzhiyun err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48));
691*4882a593Smuzhiyun if (err) {
692*4882a593Smuzhiyun dev_err(dev, "Unable to get usable DMA configuration\n");
693*4882a593Smuzhiyun goto cptvf_err_release_regions;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48));
697*4882a593Smuzhiyun if (err) {
698*4882a593Smuzhiyun dev_err(dev, "Unable to get 48-bit DMA for consistent allocations\n");
699*4882a593Smuzhiyun goto cptvf_err_release_regions;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun /* MAP PF's configuration registers */
703*4882a593Smuzhiyun cptvf->reg_base = pcim_iomap(pdev, 0, 0);
704*4882a593Smuzhiyun if (!cptvf->reg_base) {
705*4882a593Smuzhiyun dev_err(dev, "Cannot map config register space, aborting\n");
706*4882a593Smuzhiyun err = -ENOMEM;
707*4882a593Smuzhiyun goto cptvf_err_release_regions;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun cptvf->node = dev_to_node(&pdev->dev);
711*4882a593Smuzhiyun err = pci_alloc_irq_vectors(pdev, CPT_VF_MSIX_VECTORS,
712*4882a593Smuzhiyun CPT_VF_MSIX_VECTORS, PCI_IRQ_MSIX);
713*4882a593Smuzhiyun if (err < 0) {
714*4882a593Smuzhiyun dev_err(dev, "Request for #%d msix vectors failed\n",
715*4882a593Smuzhiyun CPT_VF_MSIX_VECTORS);
716*4882a593Smuzhiyun goto cptvf_err_release_regions;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC),
720*4882a593Smuzhiyun cptvf_misc_intr_handler, 0, "CPT VF misc intr",
721*4882a593Smuzhiyun cptvf);
722*4882a593Smuzhiyun if (err) {
723*4882a593Smuzhiyun dev_err(dev, "Request misc irq failed");
724*4882a593Smuzhiyun goto cptvf_free_vectors;
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun /* Enable mailbox interrupt */
728*4882a593Smuzhiyun cptvf_enable_mbox_interrupts(cptvf);
729*4882a593Smuzhiyun cptvf_enable_swerr_interrupts(cptvf);
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun /* Check ready with PF */
732*4882a593Smuzhiyun /* Gets chip ID / device Id from PF if ready */
733*4882a593Smuzhiyun err = cptvf_check_pf_ready(cptvf);
734*4882a593Smuzhiyun if (err) {
735*4882a593Smuzhiyun dev_err(dev, "PF not responding to READY msg");
736*4882a593Smuzhiyun goto cptvf_free_misc_irq;
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun /* CPT VF software resources initialization */
740*4882a593Smuzhiyun cptvf->cqinfo.qchunksize = CPT_CMD_QCHUNK_SIZE;
741*4882a593Smuzhiyun err = cptvf_sw_init(cptvf, CPT_CMD_QLEN, CPT_NUM_QS_PER_VF);
742*4882a593Smuzhiyun if (err) {
743*4882a593Smuzhiyun dev_err(dev, "cptvf_sw_init() failed");
744*4882a593Smuzhiyun goto cptvf_free_misc_irq;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun /* Convey VQ LEN to PF */
747*4882a593Smuzhiyun err = cptvf_send_vq_size_msg(cptvf);
748*4882a593Smuzhiyun if (err) {
749*4882a593Smuzhiyun dev_err(dev, "PF not responding to QLEN msg");
750*4882a593Smuzhiyun goto cptvf_free_misc_irq;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun /* CPT VF device initialization */
754*4882a593Smuzhiyun cptvf_device_init(cptvf);
755*4882a593Smuzhiyun /* Send msg to PF to assign currnet Q to required group */
756*4882a593Smuzhiyun cptvf->vfgrp = 1;
757*4882a593Smuzhiyun err = cptvf_send_vf_to_grp_msg(cptvf);
758*4882a593Smuzhiyun if (err) {
759*4882a593Smuzhiyun dev_err(dev, "PF not responding to VF_GRP msg");
760*4882a593Smuzhiyun goto cptvf_free_misc_irq;
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun cptvf->priority = 1;
764*4882a593Smuzhiyun err = cptvf_send_vf_priority_msg(cptvf);
765*4882a593Smuzhiyun if (err) {
766*4882a593Smuzhiyun dev_err(dev, "PF not responding to VF_PRIO msg");
767*4882a593Smuzhiyun goto cptvf_free_misc_irq;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun err = request_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE),
771*4882a593Smuzhiyun cptvf_done_intr_handler, 0, "CPT VF done intr",
772*4882a593Smuzhiyun cptvf);
773*4882a593Smuzhiyun if (err) {
774*4882a593Smuzhiyun dev_err(dev, "Request done irq failed\n");
775*4882a593Smuzhiyun goto cptvf_free_misc_irq;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun /* Enable mailbox interrupt */
779*4882a593Smuzhiyun cptvf_enable_done_interrupts(cptvf);
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun /* Set irq affinity masks */
782*4882a593Smuzhiyun cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC);
783*4882a593Smuzhiyun cptvf_set_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE);
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun err = cptvf_send_vf_up(cptvf);
786*4882a593Smuzhiyun if (err) {
787*4882a593Smuzhiyun dev_err(dev, "PF not responding to UP msg");
788*4882a593Smuzhiyun goto cptvf_free_irq_affinity;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun err = cvm_crypto_init(cptvf);
791*4882a593Smuzhiyun if (err) {
792*4882a593Smuzhiyun dev_err(dev, "Algorithm register failed\n");
793*4882a593Smuzhiyun goto cptvf_free_irq_affinity;
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun return 0;
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun cptvf_free_irq_affinity:
798*4882a593Smuzhiyun cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE);
799*4882a593Smuzhiyun cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC);
800*4882a593Smuzhiyun cptvf_free_misc_irq:
801*4882a593Smuzhiyun free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf);
802*4882a593Smuzhiyun cptvf_free_vectors:
803*4882a593Smuzhiyun pci_free_irq_vectors(cptvf->pdev);
804*4882a593Smuzhiyun cptvf_err_release_regions:
805*4882a593Smuzhiyun pci_release_regions(pdev);
806*4882a593Smuzhiyun cptvf_err_disable_device:
807*4882a593Smuzhiyun pci_disable_device(pdev);
808*4882a593Smuzhiyun pci_set_drvdata(pdev, NULL);
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun return err;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun
cptvf_remove(struct pci_dev * pdev)813*4882a593Smuzhiyun static void cptvf_remove(struct pci_dev *pdev)
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun struct cpt_vf *cptvf = pci_get_drvdata(pdev);
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun if (!cptvf) {
818*4882a593Smuzhiyun dev_err(&pdev->dev, "Invalid CPT-VF device\n");
819*4882a593Smuzhiyun return;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun /* Convey DOWN to PF */
823*4882a593Smuzhiyun if (cptvf_send_vf_down(cptvf)) {
824*4882a593Smuzhiyun dev_err(&pdev->dev, "PF not responding to DOWN msg");
825*4882a593Smuzhiyun } else {
826*4882a593Smuzhiyun cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_DONE);
827*4882a593Smuzhiyun cptvf_free_irq_affinity(cptvf, CPT_VF_INT_VEC_E_MISC);
828*4882a593Smuzhiyun free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_DONE), cptvf);
829*4882a593Smuzhiyun free_irq(pci_irq_vector(pdev, CPT_VF_INT_VEC_E_MISC), cptvf);
830*4882a593Smuzhiyun pci_free_irq_vectors(cptvf->pdev);
831*4882a593Smuzhiyun cptvf_sw_cleanup(cptvf);
832*4882a593Smuzhiyun pci_set_drvdata(pdev, NULL);
833*4882a593Smuzhiyun pci_release_regions(pdev);
834*4882a593Smuzhiyun pci_disable_device(pdev);
835*4882a593Smuzhiyun cvm_crypto_exit();
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun
cptvf_shutdown(struct pci_dev * pdev)839*4882a593Smuzhiyun static void cptvf_shutdown(struct pci_dev *pdev)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun cptvf_remove(pdev);
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun /* Supported devices */
845*4882a593Smuzhiyun static const struct pci_device_id cptvf_id_table[] = {
846*4882a593Smuzhiyun {PCI_VDEVICE(CAVIUM, CPT_81XX_PCI_VF_DEVICE_ID), 0},
847*4882a593Smuzhiyun { 0, } /* end of table */
848*4882a593Smuzhiyun };
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun static struct pci_driver cptvf_pci_driver = {
851*4882a593Smuzhiyun .name = DRV_NAME,
852*4882a593Smuzhiyun .id_table = cptvf_id_table,
853*4882a593Smuzhiyun .probe = cptvf_probe,
854*4882a593Smuzhiyun .remove = cptvf_remove,
855*4882a593Smuzhiyun .shutdown = cptvf_shutdown,
856*4882a593Smuzhiyun };
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun module_pci_driver(cptvf_pci_driver);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun MODULE_AUTHOR("George Cherian <george.cherian@cavium.com>");
861*4882a593Smuzhiyun MODULE_DESCRIPTION("Cavium Thunder CPT Virtual Function Driver");
862*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
863*4882a593Smuzhiyun MODULE_VERSION(DRV_VERSION);
864*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, cptvf_id_table);
865