Branch data Line data Source code
1 : : /*
2 : : * Copyright 2014 Cisco Systems, Inc. All rights reserved.
3 : : *
4 : : * This program is free software; you may redistribute it and/or modify
5 : : * it under the terms of the GNU General Public License as published by
6 : : * the Free Software Foundation; version 2 of the License.
7 : : *
8 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 : : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 : : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11 : : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12 : : * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13 : : * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 : : * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15 : : * SOFTWARE.
16 : : */
17 : :
18 : : #include <linux/errno.h>
19 : : #include <linux/types.h>
20 : : #include <linux/pci.h>
21 : : #include <linux/delay.h>
22 : : #include <linux/slab.h>
23 : : #include "vnic_dev.h"
24 : : #include "vnic_wq.h"
25 : :
26 : 0 : static inline int vnic_wq_get_ctrl(struct vnic_dev *vdev, struct vnic_wq *wq,
27 : : unsigned int index, enum vnic_res_type res_type)
28 : : {
29 : 0 : wq->ctrl = svnic_dev_get_res(vdev, res_type, index);
30 [ # # # # ]: 0 : if (!wq->ctrl)
31 : 0 : return -EINVAL;
32 : :
33 : : return 0;
34 : : }
35 : :
36 : 0 : static inline int vnic_wq_alloc_ring(struct vnic_dev *vdev, struct vnic_wq *wq,
37 : : unsigned int index, unsigned int desc_count, unsigned int desc_size)
38 : : {
39 : 0 : return svnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count,
40 : : desc_size);
41 : : }
42 : :
43 : 0 : static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
44 : : {
45 : 0 : struct vnic_wq_buf *buf;
46 : 0 : unsigned int i, j, count = wq->ring.desc_count;
47 : 0 : unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count);
48 : :
49 [ # # ]: 0 : for (i = 0; i < blks; i++) {
50 : 0 : wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
51 [ # # ]: 0 : if (!wq->bufs[i]) {
52 : 0 : pr_err("Failed to alloc wq_bufs\n");
53 : :
54 : 0 : return -ENOMEM;
55 : : }
56 : : }
57 : :
58 [ # # ]: 0 : for (i = 0; i < blks; i++) {
59 : 0 : buf = wq->bufs[i];
60 [ # # ]: 0 : for (j = 0; j < VNIC_WQ_BUF_DFLT_BLK_ENTRIES; j++) {
61 : 0 : buf->index = i * VNIC_WQ_BUF_DFLT_BLK_ENTRIES + j;
62 : 0 : buf->desc = (u8 *)wq->ring.descs +
63 : 0 : wq->ring.desc_size * buf->index;
64 [ # # ]: 0 : if (buf->index + 1 == count) {
65 : 0 : buf->next = wq->bufs[0];
66 : 0 : break;
67 [ # # ]: 0 : } else if (j + 1 == VNIC_WQ_BUF_DFLT_BLK_ENTRIES) {
68 : 0 : buf->next = wq->bufs[i + 1];
69 : : } else {
70 : 0 : buf->next = buf + 1;
71 : 0 : buf++;
72 : : }
73 : : }
74 : : }
75 : :
76 : 0 : wq->to_use = wq->to_clean = wq->bufs[0];
77 : :
78 : 0 : return 0;
79 : : }
80 : :
81 : 0 : void svnic_wq_free(struct vnic_wq *wq)
82 : : {
83 : 0 : struct vnic_dev *vdev;
84 : 0 : unsigned int i;
85 : :
86 : 0 : vdev = wq->vdev;
87 : :
88 : 0 : svnic_dev_free_desc_ring(vdev, &wq->ring);
89 : :
90 [ # # ]: 0 : for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
91 : 0 : kfree(wq->bufs[i]);
92 : 0 : wq->bufs[i] = NULL;
93 : : }
94 : :
95 : 0 : wq->ctrl = NULL;
96 : :
97 : 0 : }
98 : :
99 : 0 : int vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
100 : : unsigned int desc_count, unsigned int desc_size)
101 : : {
102 : 0 : int err;
103 : :
104 : 0 : wq->index = 0;
105 : 0 : wq->vdev = vdev;
106 : :
107 : 0 : err = vnic_wq_get_ctrl(vdev, wq, 0, RES_TYPE_DEVCMD2);
108 : 0 : if (err) {
109 : 0 : pr_err("Failed to get devcmd2 resource\n");
110 : :
111 : 0 : return err;
112 : : }
113 : :
114 : 0 : svnic_wq_disable(wq);
115 : :
116 : 0 : err = vnic_wq_alloc_ring(vdev, wq, 0, desc_count, desc_size);
117 [ # # ]: 0 : if (err)
118 : 0 : return err;
119 : :
120 : : return 0;
121 : : }
122 : :
123 : 0 : int svnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
124 : : unsigned int index, unsigned int desc_count, unsigned int desc_size)
125 : : {
126 : 0 : int err;
127 : :
128 : 0 : wq->index = index;
129 : 0 : wq->vdev = vdev;
130 : :
131 : 0 : err = vnic_wq_get_ctrl(vdev, wq, index, RES_TYPE_WQ);
132 : 0 : if (err) {
133 : 0 : pr_err("Failed to hook WQ[%d] resource\n", index);
134 : :
135 : 0 : return err;
136 : : }
137 : :
138 : 0 : svnic_wq_disable(wq);
139 : :
140 : 0 : err = vnic_wq_alloc_ring(vdev, wq, index, desc_count, desc_size);
141 [ # # ]: 0 : if (err)
142 : : return err;
143 : :
144 : 0 : err = vnic_wq_alloc_bufs(wq);
145 [ # # ]: 0 : if (err) {
146 : 0 : svnic_wq_free(wq);
147 : :
148 : 0 : return err;
149 : : }
150 : :
151 : : return 0;
152 : : }
153 : :
154 : 0 : void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
155 : : unsigned int fetch_index, unsigned int posted_index,
156 : : unsigned int error_interrupt_enable,
157 : : unsigned int error_interrupt_offset)
158 : : {
159 : 0 : u64 paddr;
160 : 0 : unsigned int count = wq->ring.desc_count;
161 : :
162 : 0 : paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
163 : 0 : writeq(paddr, &wq->ctrl->ring_base);
164 : 0 : iowrite32(count, &wq->ctrl->ring_size);
165 : 0 : iowrite32(fetch_index, &wq->ctrl->fetch_index);
166 : 0 : iowrite32(posted_index, &wq->ctrl->posted_index);
167 : 0 : iowrite32(cq_index, &wq->ctrl->cq_index);
168 : 0 : iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
169 : 0 : iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
170 : 0 : iowrite32(0, &wq->ctrl->error_status);
171 : :
172 : 0 : wq->to_use = wq->to_clean =
173 [ # # ]: 0 : &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)]
174 : 0 : [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)];
175 : 0 : }
176 : :
177 : 0 : void svnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
178 : : unsigned int error_interrupt_enable,
179 : : unsigned int error_interrupt_offset)
180 : : {
181 : 0 : vnic_wq_init_start(wq, cq_index, 0, 0, error_interrupt_enable,
182 : : error_interrupt_offset);
183 : 0 : }
184 : :
185 : 0 : unsigned int svnic_wq_error_status(struct vnic_wq *wq)
186 : : {
187 : 0 : return ioread32(&wq->ctrl->error_status);
188 : : }
189 : :
190 : 0 : void svnic_wq_enable(struct vnic_wq *wq)
191 : : {
192 : 0 : iowrite32(1, &wq->ctrl->enable);
193 : 0 : }
194 : :
195 : 0 : int svnic_wq_disable(struct vnic_wq *wq)
196 : : {
197 : 0 : unsigned int wait;
198 : :
199 : 0 : iowrite32(0, &wq->ctrl->enable);
200 : :
201 : : /* Wait for HW to ACK disable request */
202 [ # # ]: 0 : for (wait = 0; wait < 100; wait++) {
203 [ # # ]: 0 : if (!(ioread32(&wq->ctrl->running)))
204 : : return 0;
205 : 0 : udelay(1);
206 : : }
207 : :
208 : 0 : pr_err("Failed to disable WQ[%d]\n", wq->index);
209 : :
210 : 0 : return -ETIMEDOUT;
211 : : }
212 : :
213 : 0 : void svnic_wq_clean(struct vnic_wq *wq,
214 : : void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf))
215 : : {
216 : 0 : struct vnic_wq_buf *buf;
217 : :
218 [ # # ]: 0 : BUG_ON(ioread32(&wq->ctrl->enable));
219 : :
220 : 0 : buf = wq->to_clean;
221 : :
222 [ # # ]: 0 : while (svnic_wq_desc_used(wq) > 0) {
223 : :
224 : 0 : (*buf_clean)(wq, buf);
225 : :
226 : 0 : buf = wq->to_clean = buf->next;
227 : 0 : wq->ring.desc_avail++;
228 : : }
229 : :
230 : 0 : wq->to_use = wq->to_clean = wq->bufs[0];
231 : :
232 : 0 : iowrite32(0, &wq->ctrl->fetch_index);
233 : 0 : iowrite32(0, &wq->ctrl->posted_index);
234 : 0 : iowrite32(0, &wq->ctrl->error_status);
235 : :
236 : 0 : svnic_dev_clear_desc_ring(&wq->ring);
237 : 0 : }
|