xref: /linux/drivers/scsi/snic/vnic_wq.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*dfb99b05SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2*dfb99b05SThomas Gleixner // Copyright 2014 Cisco Systems, Inc.  All rights reserved.
3c8806b6cSNarsimhulu Musini 
4c8806b6cSNarsimhulu Musini #include <linux/errno.h>
5c8806b6cSNarsimhulu Musini #include <linux/types.h>
6c8806b6cSNarsimhulu Musini #include <linux/pci.h>
7c8806b6cSNarsimhulu Musini #include <linux/delay.h>
8c8806b6cSNarsimhulu Musini #include <linux/slab.h>
9c8806b6cSNarsimhulu Musini #include "vnic_dev.h"
10c8806b6cSNarsimhulu Musini #include "vnic_wq.h"
11c8806b6cSNarsimhulu Musini 
vnic_wq_get_ctrl(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int index,enum vnic_res_type res_type)12c8806b6cSNarsimhulu Musini static inline int vnic_wq_get_ctrl(struct vnic_dev *vdev, struct vnic_wq *wq,
13c8806b6cSNarsimhulu Musini 	unsigned int index, enum vnic_res_type res_type)
14c8806b6cSNarsimhulu Musini {
15c8806b6cSNarsimhulu Musini 	wq->ctrl = svnic_dev_get_res(vdev, res_type, index);
16c8806b6cSNarsimhulu Musini 	if (!wq->ctrl)
17c8806b6cSNarsimhulu Musini 		return -EINVAL;
18c8806b6cSNarsimhulu Musini 
19c8806b6cSNarsimhulu Musini 	return 0;
20c8806b6cSNarsimhulu Musini }
21c8806b6cSNarsimhulu Musini 
vnic_wq_alloc_ring(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int index,unsigned int desc_count,unsigned int desc_size)22c8806b6cSNarsimhulu Musini static inline int vnic_wq_alloc_ring(struct vnic_dev *vdev, struct vnic_wq *wq,
23c8806b6cSNarsimhulu Musini 	unsigned int index, unsigned int desc_count, unsigned int desc_size)
24c8806b6cSNarsimhulu Musini {
25c8806b6cSNarsimhulu Musini 	return svnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count,
26c8806b6cSNarsimhulu Musini 					 desc_size);
27c8806b6cSNarsimhulu Musini }
28c8806b6cSNarsimhulu Musini 
vnic_wq_alloc_bufs(struct vnic_wq * wq)29c8806b6cSNarsimhulu Musini static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
30c8806b6cSNarsimhulu Musini {
31c8806b6cSNarsimhulu Musini 	struct vnic_wq_buf *buf;
32c8806b6cSNarsimhulu Musini 	unsigned int i, j, count = wq->ring.desc_count;
33c8806b6cSNarsimhulu Musini 	unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count);
34c8806b6cSNarsimhulu Musini 
35c8806b6cSNarsimhulu Musini 	for (i = 0; i < blks; i++) {
36c8806b6cSNarsimhulu Musini 		wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
37c8806b6cSNarsimhulu Musini 		if (!wq->bufs[i]) {
38c8806b6cSNarsimhulu Musini 			pr_err("Failed to alloc wq_bufs\n");
39c8806b6cSNarsimhulu Musini 
40c8806b6cSNarsimhulu Musini 			return -ENOMEM;
41c8806b6cSNarsimhulu Musini 		}
42c8806b6cSNarsimhulu Musini 	}
43c8806b6cSNarsimhulu Musini 
44c8806b6cSNarsimhulu Musini 	for (i = 0; i < blks; i++) {
45c8806b6cSNarsimhulu Musini 		buf = wq->bufs[i];
46c8806b6cSNarsimhulu Musini 		for (j = 0; j < VNIC_WQ_BUF_DFLT_BLK_ENTRIES; j++) {
47c8806b6cSNarsimhulu Musini 			buf->index = i * VNIC_WQ_BUF_DFLT_BLK_ENTRIES + j;
48c8806b6cSNarsimhulu Musini 			buf->desc = (u8 *)wq->ring.descs +
49c8806b6cSNarsimhulu Musini 				wq->ring.desc_size * buf->index;
50c8806b6cSNarsimhulu Musini 			if (buf->index + 1 == count) {
51c8806b6cSNarsimhulu Musini 				buf->next = wq->bufs[0];
52c8806b6cSNarsimhulu Musini 				break;
53c8806b6cSNarsimhulu Musini 			} else if (j + 1 == VNIC_WQ_BUF_DFLT_BLK_ENTRIES) {
54c8806b6cSNarsimhulu Musini 				buf->next = wq->bufs[i + 1];
55c8806b6cSNarsimhulu Musini 			} else {
56c8806b6cSNarsimhulu Musini 				buf->next = buf + 1;
57c8806b6cSNarsimhulu Musini 				buf++;
58c8806b6cSNarsimhulu Musini 			}
59c8806b6cSNarsimhulu Musini 		}
60c8806b6cSNarsimhulu Musini 	}
61c8806b6cSNarsimhulu Musini 
62c8806b6cSNarsimhulu Musini 	wq->to_use = wq->to_clean = wq->bufs[0];
63c8806b6cSNarsimhulu Musini 
64c8806b6cSNarsimhulu Musini 	return 0;
65c8806b6cSNarsimhulu Musini }
66c8806b6cSNarsimhulu Musini 
svnic_wq_free(struct vnic_wq * wq)67c8806b6cSNarsimhulu Musini void svnic_wq_free(struct vnic_wq *wq)
68c8806b6cSNarsimhulu Musini {
69c8806b6cSNarsimhulu Musini 	struct vnic_dev *vdev;
70c8806b6cSNarsimhulu Musini 	unsigned int i;
71c8806b6cSNarsimhulu Musini 
72c8806b6cSNarsimhulu Musini 	vdev = wq->vdev;
73c8806b6cSNarsimhulu Musini 
74c8806b6cSNarsimhulu Musini 	svnic_dev_free_desc_ring(vdev, &wq->ring);
75c8806b6cSNarsimhulu Musini 
76c8806b6cSNarsimhulu Musini 	for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
77c8806b6cSNarsimhulu Musini 		kfree(wq->bufs[i]);
78c8806b6cSNarsimhulu Musini 		wq->bufs[i] = NULL;
79c8806b6cSNarsimhulu Musini 	}
80c8806b6cSNarsimhulu Musini 
81c8806b6cSNarsimhulu Musini 	wq->ctrl = NULL;
82c8806b6cSNarsimhulu Musini 
83c8806b6cSNarsimhulu Musini }
84c8806b6cSNarsimhulu Musini 
vnic_wq_devcmd2_alloc(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int desc_count,unsigned int desc_size)85c8806b6cSNarsimhulu Musini int vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
86c8806b6cSNarsimhulu Musini 	unsigned int desc_count, unsigned int desc_size)
87c8806b6cSNarsimhulu Musini {
88c8806b6cSNarsimhulu Musini 	int err;
89c8806b6cSNarsimhulu Musini 
90c8806b6cSNarsimhulu Musini 	wq->index = 0;
91c8806b6cSNarsimhulu Musini 	wq->vdev = vdev;
92c8806b6cSNarsimhulu Musini 
93c8806b6cSNarsimhulu Musini 	err = vnic_wq_get_ctrl(vdev, wq, 0, RES_TYPE_DEVCMD2);
94c8806b6cSNarsimhulu Musini 	if (err) {
95c8806b6cSNarsimhulu Musini 		pr_err("Failed to get devcmd2 resource\n");
96c8806b6cSNarsimhulu Musini 
97c8806b6cSNarsimhulu Musini 		return err;
98c8806b6cSNarsimhulu Musini 	}
99c8806b6cSNarsimhulu Musini 
100c8806b6cSNarsimhulu Musini 	svnic_wq_disable(wq);
101c8806b6cSNarsimhulu Musini 
102c8806b6cSNarsimhulu Musini 	err = vnic_wq_alloc_ring(vdev, wq, 0, desc_count, desc_size);
103c8806b6cSNarsimhulu Musini 	if (err)
104c8806b6cSNarsimhulu Musini 		return err;
105c8806b6cSNarsimhulu Musini 
106c8806b6cSNarsimhulu Musini 	return 0;
107c8806b6cSNarsimhulu Musini }
108c8806b6cSNarsimhulu Musini 
svnic_wq_alloc(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int index,unsigned int desc_count,unsigned int desc_size)109c8806b6cSNarsimhulu Musini int svnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
110c8806b6cSNarsimhulu Musini 	unsigned int index, unsigned int desc_count, unsigned int desc_size)
111c8806b6cSNarsimhulu Musini {
112c8806b6cSNarsimhulu Musini 	int err;
113c8806b6cSNarsimhulu Musini 
114c8806b6cSNarsimhulu Musini 	wq->index = index;
115c8806b6cSNarsimhulu Musini 	wq->vdev = vdev;
116c8806b6cSNarsimhulu Musini 
117c8806b6cSNarsimhulu Musini 	err = vnic_wq_get_ctrl(vdev, wq, index, RES_TYPE_WQ);
118c8806b6cSNarsimhulu Musini 	if (err) {
119c8806b6cSNarsimhulu Musini 		pr_err("Failed to hook WQ[%d] resource\n", index);
120c8806b6cSNarsimhulu Musini 
121c8806b6cSNarsimhulu Musini 		return err;
122c8806b6cSNarsimhulu Musini 	}
123c8806b6cSNarsimhulu Musini 
124c8806b6cSNarsimhulu Musini 	svnic_wq_disable(wq);
125c8806b6cSNarsimhulu Musini 
126c8806b6cSNarsimhulu Musini 	err = vnic_wq_alloc_ring(vdev, wq, index, desc_count, desc_size);
127c8806b6cSNarsimhulu Musini 	if (err)
128c8806b6cSNarsimhulu Musini 		return err;
129c8806b6cSNarsimhulu Musini 
130c8806b6cSNarsimhulu Musini 	err = vnic_wq_alloc_bufs(wq);
131c8806b6cSNarsimhulu Musini 	if (err) {
132c8806b6cSNarsimhulu Musini 		svnic_wq_free(wq);
133c8806b6cSNarsimhulu Musini 
134c8806b6cSNarsimhulu Musini 		return err;
135c8806b6cSNarsimhulu Musini 	}
136c8806b6cSNarsimhulu Musini 
137c8806b6cSNarsimhulu Musini 	return 0;
138c8806b6cSNarsimhulu Musini }
139c8806b6cSNarsimhulu Musini 
vnic_wq_init_start(struct vnic_wq * wq,unsigned int cq_index,unsigned int fetch_index,unsigned int posted_index,unsigned int error_interrupt_enable,unsigned int error_interrupt_offset)140c8806b6cSNarsimhulu Musini void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
141c8806b6cSNarsimhulu Musini 	unsigned int fetch_index, unsigned int posted_index,
142c8806b6cSNarsimhulu Musini 	unsigned int error_interrupt_enable,
143c8806b6cSNarsimhulu Musini 	unsigned int error_interrupt_offset)
144c8806b6cSNarsimhulu Musini {
145c8806b6cSNarsimhulu Musini 	u64 paddr;
146c8806b6cSNarsimhulu Musini 	unsigned int count = wq->ring.desc_count;
147c8806b6cSNarsimhulu Musini 
148c8806b6cSNarsimhulu Musini 	paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
149c8806b6cSNarsimhulu Musini 	writeq(paddr, &wq->ctrl->ring_base);
150c8806b6cSNarsimhulu Musini 	iowrite32(count, &wq->ctrl->ring_size);
151c8806b6cSNarsimhulu Musini 	iowrite32(fetch_index, &wq->ctrl->fetch_index);
152c8806b6cSNarsimhulu Musini 	iowrite32(posted_index, &wq->ctrl->posted_index);
153c8806b6cSNarsimhulu Musini 	iowrite32(cq_index, &wq->ctrl->cq_index);
154c8806b6cSNarsimhulu Musini 	iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
155c8806b6cSNarsimhulu Musini 	iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
156c8806b6cSNarsimhulu Musini 	iowrite32(0, &wq->ctrl->error_status);
157c8806b6cSNarsimhulu Musini 
158c8806b6cSNarsimhulu Musini 	wq->to_use = wq->to_clean =
159c8806b6cSNarsimhulu Musini 		&wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)]
160c8806b6cSNarsimhulu Musini 			[fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)];
161c8806b6cSNarsimhulu Musini }
162c8806b6cSNarsimhulu Musini 
svnic_wq_init(struct vnic_wq * wq,unsigned int cq_index,unsigned int error_interrupt_enable,unsigned int error_interrupt_offset)163c8806b6cSNarsimhulu Musini void svnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
164c8806b6cSNarsimhulu Musini 	unsigned int error_interrupt_enable,
165c8806b6cSNarsimhulu Musini 	unsigned int error_interrupt_offset)
166c8806b6cSNarsimhulu Musini {
167c8806b6cSNarsimhulu Musini 	vnic_wq_init_start(wq, cq_index, 0, 0, error_interrupt_enable,
168c8806b6cSNarsimhulu Musini 			   error_interrupt_offset);
169c8806b6cSNarsimhulu Musini }
170c8806b6cSNarsimhulu Musini 
svnic_wq_error_status(struct vnic_wq * wq)171c8806b6cSNarsimhulu Musini unsigned int svnic_wq_error_status(struct vnic_wq *wq)
172c8806b6cSNarsimhulu Musini {
173c8806b6cSNarsimhulu Musini 	return ioread32(&wq->ctrl->error_status);
174c8806b6cSNarsimhulu Musini }
175c8806b6cSNarsimhulu Musini 
svnic_wq_enable(struct vnic_wq * wq)176c8806b6cSNarsimhulu Musini void svnic_wq_enable(struct vnic_wq *wq)
177c8806b6cSNarsimhulu Musini {
178c8806b6cSNarsimhulu Musini 	iowrite32(1, &wq->ctrl->enable);
179c8806b6cSNarsimhulu Musini }
180c8806b6cSNarsimhulu Musini 
svnic_wq_disable(struct vnic_wq * wq)181c8806b6cSNarsimhulu Musini int svnic_wq_disable(struct vnic_wq *wq)
182c8806b6cSNarsimhulu Musini {
183c8806b6cSNarsimhulu Musini 	unsigned int wait;
184c8806b6cSNarsimhulu Musini 
185c8806b6cSNarsimhulu Musini 	iowrite32(0, &wq->ctrl->enable);
186c8806b6cSNarsimhulu Musini 
187c8806b6cSNarsimhulu Musini 	/* Wait for HW to ACK disable request */
188c8806b6cSNarsimhulu Musini 	for (wait = 0; wait < 100; wait++) {
189c8806b6cSNarsimhulu Musini 		if (!(ioread32(&wq->ctrl->running)))
190c8806b6cSNarsimhulu Musini 			return 0;
191c8806b6cSNarsimhulu Musini 		udelay(1);
192c8806b6cSNarsimhulu Musini 	}
193c8806b6cSNarsimhulu Musini 
194c8806b6cSNarsimhulu Musini 	pr_err("Failed to disable WQ[%d]\n", wq->index);
195c8806b6cSNarsimhulu Musini 
196c8806b6cSNarsimhulu Musini 	return -ETIMEDOUT;
197c8806b6cSNarsimhulu Musini }
198c8806b6cSNarsimhulu Musini 
svnic_wq_clean(struct vnic_wq * wq,void (* buf_clean)(struct vnic_wq * wq,struct vnic_wq_buf * buf))199c8806b6cSNarsimhulu Musini void svnic_wq_clean(struct vnic_wq *wq,
200c8806b6cSNarsimhulu Musini 	void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf))
201c8806b6cSNarsimhulu Musini {
202c8806b6cSNarsimhulu Musini 	struct vnic_wq_buf *buf;
203c8806b6cSNarsimhulu Musini 
204c8806b6cSNarsimhulu Musini 	BUG_ON(ioread32(&wq->ctrl->enable));
205c8806b6cSNarsimhulu Musini 
206c8806b6cSNarsimhulu Musini 	buf = wq->to_clean;
207c8806b6cSNarsimhulu Musini 
208c8806b6cSNarsimhulu Musini 	while (svnic_wq_desc_used(wq) > 0) {
209c8806b6cSNarsimhulu Musini 
210c8806b6cSNarsimhulu Musini 		(*buf_clean)(wq, buf);
211c8806b6cSNarsimhulu Musini 
212c8806b6cSNarsimhulu Musini 		buf = wq->to_clean = buf->next;
213c8806b6cSNarsimhulu Musini 		wq->ring.desc_avail++;
214c8806b6cSNarsimhulu Musini 	}
215c8806b6cSNarsimhulu Musini 
216c8806b6cSNarsimhulu Musini 	wq->to_use = wq->to_clean = wq->bufs[0];
217c8806b6cSNarsimhulu Musini 
218c8806b6cSNarsimhulu Musini 	iowrite32(0, &wq->ctrl->fetch_index);
219c8806b6cSNarsimhulu Musini 	iowrite32(0, &wq->ctrl->posted_index);
220c8806b6cSNarsimhulu Musini 	iowrite32(0, &wq->ctrl->error_status);
221c8806b6cSNarsimhulu Musini 
222c8806b6cSNarsimhulu Musini 	svnic_dev_clear_desc_ring(&wq->ring);
223c8806b6cSNarsimhulu Musini }
224