xref: /OK3568_Linux_fs/kernel/drivers/crypto/cavium/cpt/cptvf_main.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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