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/kernel.h>
19 : : #include <linux/errno.h>
20 : : #include <linux/types.h>
21 : : #include <linux/pci.h>
22 : : #include <linux/delay.h>
23 : : #include <linux/if_ether.h>
24 : : #include <linux/slab.h>
25 : : #include "vnic_resource.h"
26 : : #include "vnic_devcmd.h"
27 : : #include "vnic_dev.h"
28 : : #include "vnic_stats.h"
29 : : #include "vnic_wq.h"
30 : :
31 : : #define VNIC_DVCMD_TMO 10000 /* Devcmd Timeout value */
32 : : #define VNIC_NOTIFY_INTR_MASK 0x0000ffff00000000ULL
33 : :
34 : : struct devcmd2_controller {
35 : : struct vnic_wq_ctrl __iomem *wq_ctrl;
36 : : struct vnic_dev_ring results_ring;
37 : : struct vnic_wq wq;
38 : : struct vnic_devcmd2 *cmd_ring;
39 : : struct devcmd2_result *result;
40 : : u16 next_result;
41 : : u16 result_size;
42 : : int color;
43 : : };
44 : :
45 : : struct vnic_res {
46 : : void __iomem *vaddr;
47 : : unsigned int count;
48 : : };
49 : :
50 : : struct vnic_dev {
51 : : void *priv;
52 : : struct pci_dev *pdev;
53 : : struct vnic_res res[RES_TYPE_MAX];
54 : : enum vnic_dev_intr_mode intr_mode;
55 : : struct vnic_devcmd __iomem *devcmd;
56 : : struct vnic_devcmd_notify *notify;
57 : : struct vnic_devcmd_notify notify_copy;
58 : : dma_addr_t notify_pa;
59 : : u32 *linkstatus;
60 : : dma_addr_t linkstatus_pa;
61 : : struct vnic_stats *stats;
62 : : dma_addr_t stats_pa;
63 : : struct vnic_devcmd_fw_info *fw_info;
64 : : dma_addr_t fw_info_pa;
65 : : u64 args[VNIC_DEVCMD_NARGS];
66 : : struct devcmd2_controller *devcmd2;
67 : :
68 : : int (*devcmd_rtn)(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
69 : : int wait);
70 : : };
71 : :
72 : : #define VNIC_MAX_RES_HDR_SIZE \
73 : : (sizeof(struct vnic_resource_header) + \
74 : : sizeof(struct vnic_resource) * RES_TYPE_MAX)
75 : : #define VNIC_RES_STRIDE 128
76 : :
77 : 0 : void *svnic_dev_priv(struct vnic_dev *vdev)
78 : : {
79 : 0 : return vdev->priv;
80 : : }
81 : :
82 : 11 : static int vnic_dev_discover_res(struct vnic_dev *vdev,
83 : : struct vnic_dev_bar *bar, unsigned int num_bars)
84 : : {
85 : 11 : struct vnic_resource_header __iomem *rh;
86 : 11 : struct vnic_resource __iomem *r;
87 : 11 : u8 type;
88 : :
89 [ + - ]: 11 : if (num_bars == 0)
90 : : return -EINVAL;
91 : :
92 [ - + ]: 11 : if (bar->len < VNIC_MAX_RES_HDR_SIZE) {
93 : 0 : pr_err("vNIC BAR0 res hdr length error\n");
94 : :
95 : 0 : return -EINVAL;
96 : : }
97 : :
98 : 11 : rh = bar->vaddr;
99 [ - + ]: 11 : if (!rh) {
100 : 0 : pr_err("vNIC BAR0 res hdr not mem-mapped\n");
101 : :
102 : 0 : return -EINVAL;
103 : : }
104 : :
105 [ + - + + ]: 22 : if (ioread32(&rh->magic) != VNIC_RES_MAGIC ||
106 : 11 : ioread32(&rh->version) != VNIC_RES_VERSION) {
107 : 1 : pr_err("vNIC BAR0 res magic/version error exp (%lx/%lx) curr (%x/%x)\n",
108 : : VNIC_RES_MAGIC, VNIC_RES_VERSION,
109 : : ioread32(&rh->magic), ioread32(&rh->version));
110 : :
111 : 1 : return -EINVAL;
112 : : }
113 : :
114 : 10 : r = (struct vnic_resource __iomem *)(rh + 1);
115 : :
116 [ + + ]: 3034 : while ((type = ioread8(&r->type)) != RES_TYPE_EOL) {
117 : :
118 : 3027 : u8 bar_num = ioread8(&r->bar);
119 : 3027 : u32 bar_offset = ioread32(&r->bar_offset);
120 : 3027 : u32 count = ioread32(&r->count);
121 : 3027 : u32 len;
122 : :
123 : 3027 : r++;
124 : :
125 [ + + ]: 3027 : if (bar_num >= num_bars)
126 : 3020 : continue;
127 : :
128 [ + - - + ]: 7 : if (!bar[bar_num].len || !bar[bar_num].vaddr)
129 : 0 : continue;
130 : :
131 [ + + + ]: 7 : switch (type) {
132 : 3 : case RES_TYPE_WQ:
133 : : case RES_TYPE_RQ:
134 : : case RES_TYPE_CQ:
135 : : case RES_TYPE_INTR_CTRL:
136 : : /* each count is stride bytes long */
137 : 3 : len = count * VNIC_RES_STRIDE;
138 [ + - ]: 3 : if (len + bar_offset > bar->len) {
139 : 3 : pr_err("vNIC BAR0 resource %d out-of-bounds, offset 0x%x + size 0x%x > bar len 0x%lx\n",
140 : : type, bar_offset,
141 : : len,
142 : : bar->len);
143 : :
144 : 3 : return -EINVAL;
145 : : }
146 : : break;
147 : :
148 : : case RES_TYPE_INTR_PBA_LEGACY:
149 : : case RES_TYPE_DEVCMD:
150 : : case RES_TYPE_DEVCMD2:
151 : : len = count;
152 : : break;
153 : :
154 : 3 : default:
155 : 3 : continue;
156 : : }
157 : :
158 : 1 : vdev->res[type].count = count;
159 : 1 : vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset;
160 : : }
161 : :
162 : : return 0;
163 : : }
164 : :
165 : 0 : unsigned int svnic_dev_get_res_count(struct vnic_dev *vdev,
166 : : enum vnic_res_type type)
167 : : {
168 : 0 : return vdev->res[type].count;
169 : : }
170 : :
171 : 7 : void __iomem *svnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
172 : : unsigned int index)
173 : : {
174 [ # # ]: 0 : if (!vdev->res[type].vaddr)
175 : : return NULL;
176 : :
177 [ # # ]: 0 : switch (type) {
178 : 0 : case RES_TYPE_WQ:
179 : : case RES_TYPE_RQ:
180 : : case RES_TYPE_CQ:
181 : : case RES_TYPE_INTR_CTRL:
182 : 0 : return (char __iomem *)vdev->res[type].vaddr +
183 : 0 : index * VNIC_RES_STRIDE;
184 : :
185 : : default:
186 : : return (char __iomem *)vdev->res[type].vaddr;
187 : : }
188 : : }
189 : :
190 : 0 : unsigned int svnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
191 : : unsigned int desc_count,
192 : : unsigned int desc_size)
193 : : {
194 : : /* The base address of the desc rings must be 512 byte aligned.
195 : : * Descriptor count is aligned to groups of 32 descriptors. A
196 : : * count of 0 means the maximum 4096 descriptors. Descriptor
197 : : * size is aligned to 16 bytes.
198 : : */
199 : :
200 : 0 : unsigned int count_align = 32;
201 : 0 : unsigned int desc_align = 16;
202 : :
203 : 0 : ring->base_align = 512;
204 : :
205 [ # # ]: 0 : if (desc_count == 0)
206 : 0 : desc_count = 4096;
207 : :
208 : 0 : ring->desc_count = ALIGN(desc_count, count_align);
209 : :
210 : 0 : ring->desc_size = ALIGN(desc_size, desc_align);
211 : :
212 : 0 : ring->size = ring->desc_count * ring->desc_size;
213 : 0 : ring->size_unaligned = ring->size + ring->base_align;
214 : :
215 : 0 : return ring->size_unaligned;
216 : : }
217 : :
218 : 0 : void svnic_dev_clear_desc_ring(struct vnic_dev_ring *ring)
219 : : {
220 : 0 : memset(ring->descs, 0, ring->size);
221 : 0 : }
222 : :
223 : 0 : int svnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
224 : : unsigned int desc_count, unsigned int desc_size)
225 : : {
226 [ # # ]: 0 : svnic_dev_desc_ring_size(ring, desc_count, desc_size);
227 : :
228 : 0 : ring->descs_unaligned = dma_alloc_coherent(&vdev->pdev->dev,
229 : : ring->size_unaligned, &ring->base_addr_unaligned,
230 : : GFP_KERNEL);
231 [ # # ]: 0 : if (!ring->descs_unaligned) {
232 : 0 : pr_err("Failed to allocate ring (size=%d), aborting\n",
233 : : (int)ring->size);
234 : :
235 : 0 : return -ENOMEM;
236 : : }
237 : :
238 : 0 : ring->base_addr = ALIGN(ring->base_addr_unaligned,
239 : : ring->base_align);
240 : 0 : ring->descs = (u8 *)ring->descs_unaligned +
241 : 0 : (ring->base_addr - ring->base_addr_unaligned);
242 : :
243 : 0 : svnic_dev_clear_desc_ring(ring);
244 : :
245 : 0 : ring->desc_avail = ring->desc_count - 1;
246 : :
247 : 0 : return 0;
248 : : }
249 : :
250 : 0 : void svnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring)
251 : : {
252 [ # # ]: 0 : if (ring->descs) {
253 : 0 : dma_free_coherent(&vdev->pdev->dev,
254 : : ring->size_unaligned,
255 : : ring->descs_unaligned,
256 : : ring->base_addr_unaligned);
257 : 0 : ring->descs = NULL;
258 : : }
259 : 0 : }
260 : :
261 : 0 : static int _svnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
262 : : int wait)
263 : : {
264 : 0 : struct devcmd2_controller *dc2c = vdev->devcmd2;
265 : 0 : struct devcmd2_result *result = NULL;
266 : 0 : unsigned int i;
267 : 0 : int delay;
268 : 0 : int err;
269 : 0 : u32 posted;
270 : 0 : u32 fetch_idx;
271 : 0 : u32 new_posted;
272 : 0 : u8 color;
273 : :
274 : 0 : fetch_idx = ioread32(&dc2c->wq_ctrl->fetch_index);
275 [ # # ]: 0 : if (fetch_idx == 0xFFFFFFFF) { /* check for hardware gone */
276 : : /* Hardware surprise removal: return error */
277 : : return -ENODEV;
278 : : }
279 : :
280 : 0 : posted = ioread32(&dc2c->wq_ctrl->posted_index);
281 : :
282 [ # # ]: 0 : if (posted == 0xFFFFFFFF) { /* check for hardware gone */
283 : : /* Hardware surprise removal: return error */
284 : : return -ENODEV;
285 : : }
286 : :
287 : 0 : new_posted = (posted + 1) % DEVCMD2_RING_SIZE;
288 [ # # ]: 0 : if (new_posted == fetch_idx) {
289 [ # # ]: 0 : pr_err("%s: wq is full while issuing devcmd2 command %d, fetch index: %u, posted index: %u\n",
290 : : pci_name(vdev->pdev), _CMD_N(cmd), fetch_idx, posted);
291 : :
292 : 0 : return -EBUSY;
293 : : }
294 : :
295 : 0 : dc2c->cmd_ring[posted].cmd = cmd;
296 : 0 : dc2c->cmd_ring[posted].flags = 0;
297 : :
298 [ # # ]: 0 : if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT))
299 : 0 : dc2c->cmd_ring[posted].flags |= DEVCMD2_FNORESULT;
300 : :
301 [ # # ]: 0 : if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) {
302 [ # # ]: 0 : for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
303 : 0 : dc2c->cmd_ring[posted].args[i] = vdev->args[i];
304 : : }
305 : : /* Adding write memory barrier prevents compiler and/or CPU
306 : : * reordering, thus avoiding descriptor posting before
307 : : * descriptor is initialized. Otherwise, hardware can read
308 : : * stale descriptor fields.
309 : : */
310 : 0 : wmb();
311 : 0 : iowrite32(new_posted, &dc2c->wq_ctrl->posted_index);
312 : :
313 [ # # ]: 0 : if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT)
314 : : return 0;
315 : :
316 : 0 : result = dc2c->result + dc2c->next_result;
317 : 0 : color = dc2c->color;
318 : :
319 : : /*
320 : : * Increment next_result, after posting the devcmd, irrespective of
321 : : * devcmd result, and it should be done only once.
322 : : */
323 : 0 : dc2c->next_result++;
324 [ # # ]: 0 : if (dc2c->next_result == dc2c->result_size) {
325 : 0 : dc2c->next_result = 0;
326 : 0 : dc2c->color = dc2c->color ? 0 : 1;
327 : : }
328 : :
329 [ # # ]: 0 : for (delay = 0; delay < wait; delay++) {
330 : 0 : udelay(100);
331 [ # # ]: 0 : if (result->color == color) {
332 [ # # ]: 0 : if (result->error) {
333 : 0 : err = (int) result->error;
334 [ # # # # ]: 0 : if (err != ERR_ECMDUNKNOWN ||
335 : : cmd != CMD_CAPABILITY)
336 : 0 : pr_err("Error %d devcmd %d\n",
337 : : err, _CMD_N(cmd));
338 : :
339 : 0 : return err;
340 : : }
341 [ # # ]: 0 : if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
342 [ # # ]: 0 : for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
343 : 0 : vdev->args[i] = result->results[i];
344 : : }
345 : :
346 : 0 : return 0;
347 : : }
348 : : }
349 : :
350 : 0 : pr_err("Timed out devcmd %d\n", _CMD_N(cmd));
351 : :
352 : 0 : return -ETIMEDOUT;
353 : : }
354 : :
355 : 0 : static int svnic_dev_init_devcmd2(struct vnic_dev *vdev)
356 : : {
357 : 0 : struct devcmd2_controller *dc2c = NULL;
358 : 0 : unsigned int fetch_idx;
359 : 0 : int ret;
360 : 0 : void __iomem *p;
361 : :
362 [ # # ]: 0 : if (vdev->devcmd2)
363 : : return 0;
364 : :
365 [ # # ]: 0 : p = svnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0);
366 : 0 : if (!p)
367 : : return -ENODEV;
368 : :
369 : 0 : dc2c = kzalloc(sizeof(*dc2c), GFP_ATOMIC);
370 [ # # ]: 0 : if (!dc2c)
371 : : return -ENOMEM;
372 : :
373 : 0 : vdev->devcmd2 = dc2c;
374 : :
375 : 0 : dc2c->color = 1;
376 : 0 : dc2c->result_size = DEVCMD2_RING_SIZE;
377 : :
378 : 0 : ret = vnic_wq_devcmd2_alloc(vdev,
379 : : &dc2c->wq,
380 : : DEVCMD2_RING_SIZE,
381 : : DEVCMD2_DESC_SIZE);
382 [ # # ]: 0 : if (ret)
383 : 0 : goto err_free_devcmd2;
384 : :
385 : 0 : fetch_idx = ioread32(&dc2c->wq.ctrl->fetch_index);
386 [ # # ]: 0 : if (fetch_idx == 0xFFFFFFFF) { /* check for hardware gone */
387 : : /* Hardware surprise removal: reset fetch_index */
388 : 0 : fetch_idx = 0;
389 : : }
390 : :
391 : : /*
392 : : * Don't change fetch_index ever and
393 : : * set posted_index same as fetch_index
394 : : * when setting up the WQ for devcmd2.
395 : : */
396 : 0 : vnic_wq_init_start(&dc2c->wq, 0, fetch_idx, fetch_idx, 0, 0);
397 : 0 : svnic_wq_enable(&dc2c->wq);
398 : 0 : ret = svnic_dev_alloc_desc_ring(vdev,
399 : : &dc2c->results_ring,
400 : : DEVCMD2_RING_SIZE,
401 : : DEVCMD2_DESC_SIZE);
402 [ # # ]: 0 : if (ret)
403 : 0 : goto err_free_wq;
404 : :
405 : 0 : dc2c->result = (struct devcmd2_result *) dc2c->results_ring.descs;
406 : 0 : dc2c->cmd_ring = (struct vnic_devcmd2 *) dc2c->wq.ring.descs;
407 : 0 : dc2c->wq_ctrl = dc2c->wq.ctrl;
408 : 0 : vdev->args[0] = (u64) dc2c->results_ring.base_addr | VNIC_PADDR_TARGET;
409 : 0 : vdev->args[1] = DEVCMD2_RING_SIZE;
410 : :
411 : 0 : ret = _svnic_dev_cmd2(vdev, CMD_INITIALIZE_DEVCMD2, VNIC_DVCMD_TMO);
412 [ # # ]: 0 : if (ret < 0)
413 : 0 : goto err_free_desc_ring;
414 : :
415 : 0 : vdev->devcmd_rtn = &_svnic_dev_cmd2;
416 : 0 : pr_info("DEVCMD2 Initialized.\n");
417 : :
418 : 0 : return ret;
419 : :
420 : : err_free_desc_ring:
421 : 0 : svnic_dev_free_desc_ring(vdev, &dc2c->results_ring);
422 : :
423 : 0 : err_free_wq:
424 : 0 : svnic_wq_disable(&dc2c->wq);
425 : 0 : svnic_wq_free(&dc2c->wq);
426 : :
427 : 0 : err_free_devcmd2:
428 : 0 : kfree(dc2c);
429 : 0 : vdev->devcmd2 = NULL;
430 : :
431 : 0 : return ret;
432 : : } /* end of svnic_dev_init_devcmd2 */
433 : :
434 : 0 : static void vnic_dev_deinit_devcmd2(struct vnic_dev *vdev)
435 : : {
436 : 0 : struct devcmd2_controller *dc2c = vdev->devcmd2;
437 : :
438 : 0 : vdev->devcmd2 = NULL;
439 : 0 : vdev->devcmd_rtn = NULL;
440 : :
441 : 0 : svnic_dev_free_desc_ring(vdev, &dc2c->results_ring);
442 : 0 : svnic_wq_disable(&dc2c->wq);
443 : 0 : svnic_wq_free(&dc2c->wq);
444 : 0 : kfree(dc2c);
445 : 0 : }
446 : :
447 : 0 : int svnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
448 : : u64 *a0, u64 *a1, int wait)
449 : : {
450 : 0 : int err;
451 : :
452 : 0 : memset(vdev->args, 0, sizeof(vdev->args));
453 : 0 : vdev->args[0] = *a0;
454 : 0 : vdev->args[1] = *a1;
455 : :
456 : 0 : err = (*vdev->devcmd_rtn)(vdev, cmd, wait);
457 : :
458 : 0 : *a0 = vdev->args[0];
459 : 0 : *a1 = vdev->args[1];
460 : :
461 : 0 : return err;
462 : : }
463 : :
464 : 0 : int svnic_dev_fw_info(struct vnic_dev *vdev,
465 : : struct vnic_devcmd_fw_info **fw_info)
466 : : {
467 : 0 : u64 a0, a1 = 0;
468 : 0 : int wait = VNIC_DVCMD_TMO;
469 : 0 : int err = 0;
470 : :
471 [ # # ]: 0 : if (!vdev->fw_info) {
472 : 0 : vdev->fw_info = dma_alloc_coherent(&vdev->pdev->dev,
473 : : sizeof(struct vnic_devcmd_fw_info),
474 : : &vdev->fw_info_pa, GFP_KERNEL);
475 [ # # ]: 0 : if (!vdev->fw_info)
476 : : return -ENOMEM;
477 : :
478 : 0 : a0 = vdev->fw_info_pa;
479 : :
480 : : /* only get fw_info once and cache it */
481 : 0 : err = svnic_dev_cmd(vdev, CMD_MCPU_FW_INFO, &a0, &a1, wait);
482 : : }
483 : :
484 : 0 : *fw_info = vdev->fw_info;
485 : :
486 : 0 : return err;
487 : : }
488 : :
489 : 0 : int svnic_dev_spec(struct vnic_dev *vdev, unsigned int offset,
490 : : unsigned int size, void *value)
491 : : {
492 : 0 : u64 a0, a1;
493 : 0 : int wait = VNIC_DVCMD_TMO;
494 : 0 : int err;
495 : :
496 : 0 : a0 = offset;
497 : 0 : a1 = size;
498 : :
499 : 0 : err = svnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait);
500 : :
501 [ # # # # : 0 : switch (size) {
# ]
502 : 0 : case 1:
503 : 0 : *(u8 *)value = (u8)a0;
504 : 0 : break;
505 : 0 : case 2:
506 : 0 : *(u16 *)value = (u16)a0;
507 : 0 : break;
508 : 0 : case 4:
509 : 0 : *(u32 *)value = (u32)a0;
510 : 0 : break;
511 : 0 : case 8:
512 : 0 : *(u64 *)value = a0;
513 : 0 : break;
514 : 0 : default:
515 : 0 : BUG();
516 : 0 : break;
517 : : }
518 : :
519 : 0 : return err;
520 : : }
521 : :
522 : 0 : int svnic_dev_stats_clear(struct vnic_dev *vdev)
523 : : {
524 : 0 : u64 a0 = 0, a1 = 0;
525 : 0 : int wait = VNIC_DVCMD_TMO;
526 : :
527 : 0 : return svnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait);
528 : : }
529 : :
530 : 0 : int svnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
531 : : {
532 : 0 : u64 a0, a1;
533 : 0 : int wait = VNIC_DVCMD_TMO;
534 : :
535 [ # # ]: 0 : if (!vdev->stats) {
536 : 0 : vdev->stats = dma_alloc_coherent(&vdev->pdev->dev,
537 : : sizeof(struct vnic_stats), &vdev->stats_pa, GFP_KERNEL);
538 [ # # ]: 0 : if (!vdev->stats)
539 : : return -ENOMEM;
540 : : }
541 : :
542 : 0 : *stats = vdev->stats;
543 : 0 : a0 = vdev->stats_pa;
544 : 0 : a1 = sizeof(struct vnic_stats);
545 : :
546 : 0 : return svnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait);
547 : : }
548 : :
549 : 0 : int svnic_dev_close(struct vnic_dev *vdev)
550 : : {
551 : 0 : u64 a0 = 0, a1 = 0;
552 : 0 : int wait = VNIC_DVCMD_TMO;
553 : :
554 : 0 : return svnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait);
555 : : }
556 : :
557 : 0 : int svnic_dev_enable_wait(struct vnic_dev *vdev)
558 : : {
559 : 0 : u64 a0 = 0, a1 = 0;
560 : 0 : int wait = VNIC_DVCMD_TMO;
561 : 0 : int err = 0;
562 : :
563 : 0 : err = svnic_dev_cmd(vdev, CMD_ENABLE_WAIT, &a0, &a1, wait);
564 [ # # ]: 0 : if (err == ERR_ECMDUNKNOWN)
565 : 0 : return svnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
566 : :
567 : : return err;
568 : : }
569 : :
570 : 0 : int svnic_dev_disable(struct vnic_dev *vdev)
571 : : {
572 : 0 : u64 a0 = 0, a1 = 0;
573 : 0 : int wait = VNIC_DVCMD_TMO;
574 : :
575 : 0 : return svnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait);
576 : : }
577 : :
578 : 0 : int svnic_dev_open(struct vnic_dev *vdev, int arg)
579 : : {
580 : 0 : u64 a0 = (u32)arg, a1 = 0;
581 : 0 : int wait = VNIC_DVCMD_TMO;
582 : :
583 : 0 : return svnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait);
584 : : }
585 : :
586 : 0 : int svnic_dev_open_done(struct vnic_dev *vdev, int *done)
587 : : {
588 : 0 : u64 a0 = 0, a1 = 0;
589 : 0 : int wait = VNIC_DVCMD_TMO;
590 : 0 : int err;
591 : :
592 : 0 : *done = 0;
593 : :
594 : 0 : err = svnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait);
595 [ # # ]: 0 : if (err)
596 : : return err;
597 : :
598 : 0 : *done = (a0 == 0);
599 : :
600 : 0 : return 0;
601 : : }
602 : :
603 : 0 : int svnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
604 : : {
605 : 0 : u64 a0, a1;
606 : 0 : int wait = VNIC_DVCMD_TMO;
607 : :
608 [ # # ]: 0 : if (!vdev->notify) {
609 : 0 : vdev->notify = dma_alloc_coherent(&vdev->pdev->dev,
610 : : sizeof(struct vnic_devcmd_notify),
611 : : &vdev->notify_pa, GFP_KERNEL);
612 [ # # ]: 0 : if (!vdev->notify)
613 : : return -ENOMEM;
614 : : }
615 : :
616 : 0 : a0 = vdev->notify_pa;
617 : 0 : a1 = ((u64)intr << 32) & VNIC_NOTIFY_INTR_MASK;
618 : 0 : a1 += sizeof(struct vnic_devcmd_notify);
619 : :
620 : 0 : return svnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
621 : : }
622 : :
623 : 0 : void svnic_dev_notify_unset(struct vnic_dev *vdev)
624 : : {
625 : 0 : u64 a0, a1;
626 : 0 : int wait = VNIC_DVCMD_TMO;
627 : :
628 : 0 : a0 = 0; /* paddr = 0 to unset notify buffer */
629 : 0 : a1 = VNIC_NOTIFY_INTR_MASK; /* intr num = -1 to unreg for intr */
630 : 0 : a1 += sizeof(struct vnic_devcmd_notify);
631 : :
632 : 0 : svnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
633 : 0 : }
634 : :
635 : 0 : static int vnic_dev_notify_ready(struct vnic_dev *vdev)
636 : : {
637 : 0 : u32 *words;
638 : 0 : unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4;
639 : 0 : unsigned int i;
640 : 0 : u32 csum;
641 : :
642 [ # # ]: 0 : if (!vdev->notify)
643 : : return 0;
644 : :
645 : 0 : do {
646 : 0 : csum = 0;
647 : 0 : memcpy(&vdev->notify_copy, vdev->notify,
648 : : sizeof(struct vnic_devcmd_notify));
649 : 0 : words = (u32 *)&vdev->notify_copy;
650 [ # # ]: 0 : for (i = 1; i < nwords; i++)
651 : 0 : csum += words[i];
652 [ # # ]: 0 : } while (csum != words[0]);
653 : :
654 : : return 1;
655 : : }
656 : :
657 : 0 : int svnic_dev_init(struct vnic_dev *vdev, int arg)
658 : : {
659 : 0 : u64 a0 = (u32)arg, a1 = 0;
660 : 0 : int wait = VNIC_DVCMD_TMO;
661 : :
662 : 0 : return svnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
663 : : }
664 : :
665 : 0 : int svnic_dev_link_status(struct vnic_dev *vdev)
666 : : {
667 [ # # ]: 0 : if (vdev->linkstatus)
668 : 0 : return *vdev->linkstatus;
669 : :
670 [ # # ]: 0 : if (!vnic_dev_notify_ready(vdev))
671 : : return 0;
672 : :
673 : 0 : return vdev->notify_copy.link_state;
674 : : }
675 : :
676 : 0 : u32 svnic_dev_link_down_cnt(struct vnic_dev *vdev)
677 : : {
678 [ # # ]: 0 : if (!vnic_dev_notify_ready(vdev))
679 : : return 0;
680 : :
681 : 0 : return vdev->notify_copy.link_down_cnt;
682 : : }
683 : :
684 : 0 : void svnic_dev_set_intr_mode(struct vnic_dev *vdev,
685 : : enum vnic_dev_intr_mode intr_mode)
686 : : {
687 : 0 : vdev->intr_mode = intr_mode;
688 : 0 : }
689 : :
690 : 0 : enum vnic_dev_intr_mode svnic_dev_get_intr_mode(struct vnic_dev *vdev)
691 : : {
692 : 0 : return vdev->intr_mode;
693 : : }
694 : :
695 : 11 : void svnic_dev_unregister(struct vnic_dev *vdev)
696 : : {
697 [ + - ]: 11 : if (vdev) {
698 [ - + ]: 11 : if (vdev->notify)
699 : 0 : dma_free_coherent(&vdev->pdev->dev,
700 : : sizeof(struct vnic_devcmd_notify),
701 : : vdev->notify,
702 : : vdev->notify_pa);
703 [ - + ]: 11 : if (vdev->linkstatus)
704 : 0 : dma_free_coherent(&vdev->pdev->dev,
705 : : sizeof(u32),
706 : : vdev->linkstatus,
707 : : vdev->linkstatus_pa);
708 [ - + ]: 11 : if (vdev->stats)
709 : 0 : dma_free_coherent(&vdev->pdev->dev,
710 : : sizeof(struct vnic_stats),
711 : : vdev->stats, vdev->stats_pa);
712 [ - + ]: 11 : if (vdev->fw_info)
713 : 0 : dma_free_coherent(&vdev->pdev->dev,
714 : : sizeof(struct vnic_devcmd_fw_info),
715 : : vdev->fw_info, vdev->fw_info_pa);
716 [ - + ]: 11 : if (vdev->devcmd2)
717 : 0 : vnic_dev_deinit_devcmd2(vdev);
718 : 11 : kfree(vdev);
719 : : }
720 : 11 : }
721 : :
722 : 11 : struct vnic_dev *svnic_dev_alloc_discover(struct vnic_dev *vdev,
723 : : void *priv,
724 : : struct pci_dev *pdev,
725 : : struct vnic_dev_bar *bar,
726 : : unsigned int num_bars)
727 : : {
728 [ + - ]: 11 : if (!vdev) {
729 : 11 : vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC);
730 [ + - ]: 11 : if (!vdev)
731 : : return NULL;
732 : : }
733 : :
734 : 11 : vdev->priv = priv;
735 : 11 : vdev->pdev = pdev;
736 : :
737 [ + + ]: 11 : if (vnic_dev_discover_res(vdev, bar, num_bars))
738 : 4 : goto err_out;
739 : :
740 : : return vdev;
741 : :
742 : : err_out:
743 : 4 : svnic_dev_unregister(vdev);
744 : :
745 : 4 : return NULL;
746 : : } /* end of svnic_dev_alloc_discover */
747 : :
748 : : /*
749 : : * fallback option is left to keep the interface common for other vnics.
750 : : */
751 : 7 : int svnic_dev_cmd_init(struct vnic_dev *vdev, int fallback)
752 : : {
753 : 7 : int err = -ENODEV;
754 : 7 : void __iomem *p;
755 : :
756 [ - + ]: 7 : p = svnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0);
757 : 7 : if (p)
758 : 0 : err = svnic_dev_init_devcmd2(vdev);
759 : : else
760 : 7 : pr_err("DEVCMD2 resource not found.\n");
761 : :
762 : 7 : return err;
763 : : } /* end of svnic_dev_cmd_init */
|