1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. |
4 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/kernel.h> |
8 | #include <linux/errno.h> |
9 | #include <linux/types.h> |
10 | #include <linux/pci.h> |
11 | #include <linux/delay.h> |
12 | #include <linux/if_ether.h> |
13 | #include <linux/slab.h> |
14 | #include "vnic_resource.h" |
15 | #include "vnic_devcmd.h" |
16 | #include "vnic_dev.h" |
17 | #include "vnic_stats.h" |
18 | #include "vnic_wq.h" |
19 | |
20 | struct devcmd2_controller { |
21 | struct vnic_wq_ctrl *wq_ctrl; |
22 | struct vnic_dev_ring results_ring; |
23 | struct vnic_wq wq; |
24 | struct vnic_devcmd2 *cmd_ring; |
25 | struct devcmd2_result *result; |
26 | u16 next_result; |
27 | u16 result_size; |
28 | int color; |
29 | }; |
30 | |
31 | enum vnic_proxy_type { |
32 | PROXY_NONE, |
33 | PROXY_BY_BDF, |
34 | PROXY_BY_INDEX, |
35 | }; |
36 | |
37 | struct vnic_res { |
38 | void __iomem *vaddr; |
39 | unsigned int count; |
40 | }; |
41 | |
42 | struct vnic_dev { |
43 | void *priv; |
44 | struct pci_dev *pdev; |
45 | struct vnic_res res[RES_TYPE_MAX]; |
46 | enum vnic_dev_intr_mode intr_mode; |
47 | struct vnic_devcmd __iomem *devcmd; |
48 | struct vnic_devcmd_notify *notify; |
49 | struct vnic_devcmd_notify notify_copy; |
50 | dma_addr_t notify_pa; |
51 | u32 *linkstatus; |
52 | dma_addr_t linkstatus_pa; |
53 | struct vnic_stats *stats; |
54 | dma_addr_t stats_pa; |
55 | struct vnic_devcmd_fw_info *fw_info; |
56 | dma_addr_t fw_info_pa; |
57 | enum vnic_proxy_type proxy; |
58 | u32 proxy_index; |
59 | u64 args[VNIC_DEVCMD_NARGS]; |
60 | struct devcmd2_controller *devcmd2; |
61 | int (*devcmd_rtn)(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, |
62 | int wait); |
63 | }; |
64 | |
65 | #define VNIC_MAX_RES_HDR_SIZE \ |
66 | (sizeof(struct vnic_resource_header) + \ |
67 | sizeof(struct vnic_resource) * RES_TYPE_MAX) |
68 | #define VNIC_RES_STRIDE 128 |
69 | |
70 | void *vnic_dev_priv(struct vnic_dev *vdev) |
71 | { |
72 | return vdev->priv; |
73 | } |
74 | |
75 | static int vnic_dev_discover_res(struct vnic_dev *vdev, |
76 | struct vnic_dev_bar *bar) |
77 | { |
78 | struct vnic_resource_header __iomem *rh; |
79 | struct vnic_resource __iomem *r; |
80 | u8 type; |
81 | |
82 | if (bar->len < VNIC_MAX_RES_HDR_SIZE) { |
83 | printk(KERN_ERR "vNIC BAR0 res hdr length error\n" ); |
84 | return -EINVAL; |
85 | } |
86 | |
87 | rh = bar->vaddr; |
88 | if (!rh) { |
89 | printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n" ); |
90 | return -EINVAL; |
91 | } |
92 | |
93 | if (ioread32(&rh->magic) != VNIC_RES_MAGIC || |
94 | ioread32(&rh->version) != VNIC_RES_VERSION) { |
95 | printk(KERN_ERR "vNIC BAR0 res magic/version error " |
96 | "exp (%lx/%lx) curr (%x/%x)\n" , |
97 | VNIC_RES_MAGIC, VNIC_RES_VERSION, |
98 | ioread32(&rh->magic), ioread32(&rh->version)); |
99 | return -EINVAL; |
100 | } |
101 | |
102 | r = (struct vnic_resource __iomem *)(rh + 1); |
103 | |
104 | while ((type = ioread8(&r->type)) != RES_TYPE_EOL) { |
105 | |
106 | u8 bar_num = ioread8(&r->bar); |
107 | u32 bar_offset = ioread32(&r->bar_offset); |
108 | u32 count = ioread32(&r->count); |
109 | u32 len; |
110 | |
111 | r++; |
112 | |
113 | if (bar_num != 0) /* only mapping in BAR0 resources */ |
114 | continue; |
115 | |
116 | switch (type) { |
117 | case RES_TYPE_WQ: |
118 | case RES_TYPE_RQ: |
119 | case RES_TYPE_CQ: |
120 | case RES_TYPE_INTR_CTRL: |
121 | /* each count is stride bytes long */ |
122 | len = count * VNIC_RES_STRIDE; |
123 | if (len + bar_offset > bar->len) { |
124 | printk(KERN_ERR "vNIC BAR0 resource %d " |
125 | "out-of-bounds, offset 0x%x + " |
126 | "size 0x%x > bar len 0x%lx\n" , |
127 | type, bar_offset, |
128 | len, |
129 | bar->len); |
130 | return -EINVAL; |
131 | } |
132 | break; |
133 | case RES_TYPE_INTR_PBA_LEGACY: |
134 | case RES_TYPE_DEVCMD2: |
135 | case RES_TYPE_DEVCMD: |
136 | len = count; |
137 | break; |
138 | default: |
139 | continue; |
140 | } |
141 | |
142 | vdev->res[type].count = count; |
143 | vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; |
144 | } |
145 | |
146 | pr_info("res_type_wq: %d res_type_rq: %d res_type_cq: %d res_type_intr_ctrl: %d\n" , |
147 | vdev->res[RES_TYPE_WQ].count, vdev->res[RES_TYPE_RQ].count, |
148 | vdev->res[RES_TYPE_CQ].count, vdev->res[RES_TYPE_INTR_CTRL].count); |
149 | |
150 | return 0; |
151 | } |
152 | |
153 | unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, |
154 | enum vnic_res_type type) |
155 | { |
156 | return vdev->res[type].count; |
157 | } |
158 | |
159 | void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, |
160 | unsigned int index) |
161 | { |
162 | if (!vdev->res[type].vaddr) |
163 | return NULL; |
164 | |
165 | switch (type) { |
166 | case RES_TYPE_WQ: |
167 | case RES_TYPE_RQ: |
168 | case RES_TYPE_CQ: |
169 | case RES_TYPE_INTR_CTRL: |
170 | return (char __iomem *)vdev->res[type].vaddr + |
171 | index * VNIC_RES_STRIDE; |
172 | default: |
173 | return (char __iomem *)vdev->res[type].vaddr; |
174 | } |
175 | } |
176 | |
177 | unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, |
178 | unsigned int desc_count, |
179 | unsigned int desc_size) |
180 | { |
181 | /* The base address of the desc rings must be 512 byte aligned. |
182 | * Descriptor count is aligned to groups of 32 descriptors. A |
183 | * count of 0 means the maximum 4096 descriptors. Descriptor |
184 | * size is aligned to 16 bytes. |
185 | */ |
186 | |
187 | unsigned int count_align = 32; |
188 | unsigned int desc_align = 16; |
189 | |
190 | ring->base_align = 512; |
191 | |
192 | if (desc_count == 0) |
193 | desc_count = 4096; |
194 | |
195 | ring->desc_count = ALIGN(desc_count, count_align); |
196 | |
197 | ring->desc_size = ALIGN(desc_size, desc_align); |
198 | |
199 | ring->size = ring->desc_count * ring->desc_size; |
200 | ring->size_unaligned = ring->size + ring->base_align; |
201 | |
202 | return ring->size_unaligned; |
203 | } |
204 | |
205 | void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring) |
206 | { |
207 | memset(ring->descs, 0, ring->size); |
208 | } |
209 | |
210 | int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, |
211 | unsigned int desc_count, unsigned int desc_size) |
212 | { |
213 | vnic_dev_desc_ring_size(ring, desc_count, desc_size); |
214 | |
215 | ring->descs_unaligned = dma_alloc_coherent(dev: &vdev->pdev->dev, |
216 | size: ring->size_unaligned, |
217 | dma_handle: &ring->base_addr_unaligned, GFP_KERNEL); |
218 | |
219 | if (!ring->descs_unaligned) { |
220 | printk(KERN_ERR |
221 | "Failed to allocate ring (size=%d), aborting\n" , |
222 | (int)ring->size); |
223 | return -ENOMEM; |
224 | } |
225 | |
226 | ring->base_addr = ALIGN(ring->base_addr_unaligned, |
227 | ring->base_align); |
228 | ring->descs = (u8 *)ring->descs_unaligned + |
229 | (ring->base_addr - ring->base_addr_unaligned); |
230 | |
231 | vnic_dev_clear_desc_ring(ring); |
232 | |
233 | ring->desc_avail = ring->desc_count - 1; |
234 | |
235 | return 0; |
236 | } |
237 | |
238 | void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring) |
239 | { |
240 | if (ring->descs) { |
241 | dma_free_coherent(dev: &vdev->pdev->dev, |
242 | size: ring->size_unaligned, |
243 | cpu_addr: ring->descs_unaligned, |
244 | dma_handle: ring->base_addr_unaligned); |
245 | ring->descs = NULL; |
246 | } |
247 | } |
248 | |
249 | static int vnic_dev_cmd1(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, int wait) |
250 | { |
251 | struct vnic_devcmd __iomem *devcmd = vdev->devcmd; |
252 | int delay; |
253 | u32 status; |
254 | static const int dev_cmd_err[] = { |
255 | /* convert from fw's version of error.h to host's version */ |
256 | 0, /* ERR_SUCCESS */ |
257 | EINVAL, /* ERR_EINVAL */ |
258 | EFAULT, /* ERR_EFAULT */ |
259 | EPERM, /* ERR_EPERM */ |
260 | EBUSY, /* ERR_EBUSY */ |
261 | }; |
262 | int err; |
263 | u64 *a0 = &vdev->args[0]; |
264 | u64 *a1 = &vdev->args[1]; |
265 | |
266 | status = ioread32(&devcmd->status); |
267 | if (status & STAT_BUSY) { |
268 | printk(KERN_ERR "Busy devcmd %d\n" , _CMD_N(cmd)); |
269 | return -EBUSY; |
270 | } |
271 | |
272 | if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { |
273 | writeq(val: *a0, addr: &devcmd->args[0]); |
274 | writeq(val: *a1, addr: &devcmd->args[1]); |
275 | wmb(); |
276 | } |
277 | |
278 | iowrite32(cmd, &devcmd->cmd); |
279 | |
280 | if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) |
281 | return 0; |
282 | |
283 | for (delay = 0; delay < wait; delay++) { |
284 | |
285 | udelay(100); |
286 | |
287 | status = ioread32(&devcmd->status); |
288 | if (!(status & STAT_BUSY)) { |
289 | |
290 | if (status & STAT_ERROR) { |
291 | err = dev_cmd_err[(int)readq(addr: &devcmd->args[0])]; |
292 | printk(KERN_ERR "Error %d devcmd %d\n" , |
293 | err, _CMD_N(cmd)); |
294 | return -err; |
295 | } |
296 | |
297 | if (_CMD_DIR(cmd) & _CMD_DIR_READ) { |
298 | rmb(); |
299 | *a0 = readq(addr: &devcmd->args[0]); |
300 | *a1 = readq(addr: &devcmd->args[1]); |
301 | } |
302 | |
303 | return 0; |
304 | } |
305 | } |
306 | |
307 | printk(KERN_ERR "Timedout devcmd %d\n" , _CMD_N(cmd)); |
308 | return -ETIMEDOUT; |
309 | } |
310 | |
311 | static int vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, |
312 | int wait) |
313 | { |
314 | struct devcmd2_controller *dc2c = vdev->devcmd2; |
315 | struct devcmd2_result *result; |
316 | u8 color; |
317 | unsigned int i; |
318 | int delay; |
319 | int err; |
320 | u32 fetch_index; |
321 | u32 posted; |
322 | u32 new_posted; |
323 | |
324 | posted = ioread32(&dc2c->wq_ctrl->posted_index); |
325 | fetch_index = ioread32(&dc2c->wq_ctrl->fetch_index); |
326 | |
327 | if (posted == 0xFFFFFFFF || fetch_index == 0xFFFFFFFF) { |
328 | /* Hardware surprise removal: return error */ |
329 | pr_err("%s: devcmd2 invalid posted or fetch index on cmd %d\n" , |
330 | pci_name(vdev->pdev), _CMD_N(cmd)); |
331 | pr_err("%s: fetch index: %u, posted index: %u\n" , |
332 | pci_name(vdev->pdev), fetch_index, posted); |
333 | |
334 | return -ENODEV; |
335 | |
336 | } |
337 | |
338 | new_posted = (posted + 1) % DEVCMD2_RING_SIZE; |
339 | |
340 | if (new_posted == fetch_index) { |
341 | pr_err("%s: devcmd2 wq full while issuing cmd %d\n" , |
342 | pci_name(vdev->pdev), _CMD_N(cmd)); |
343 | pr_err("%s: fetch index: %u, posted index: %u\n" , |
344 | pci_name(vdev->pdev), fetch_index, posted); |
345 | return -EBUSY; |
346 | |
347 | } |
348 | dc2c->cmd_ring[posted].cmd = cmd; |
349 | dc2c->cmd_ring[posted].flags = 0; |
350 | |
351 | if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) |
352 | dc2c->cmd_ring[posted].flags |= DEVCMD2_FNORESULT; |
353 | if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { |
354 | for (i = 0; i < VNIC_DEVCMD_NARGS; i++) |
355 | dc2c->cmd_ring[posted].args[i] = vdev->args[i]; |
356 | |
357 | } |
358 | |
359 | /* Adding write memory barrier prevents compiler and/or CPU |
360 | * reordering, thus avoiding descriptor posting before |
361 | * descriptor is initialized. Otherwise, hardware can read |
362 | * stale descriptor fields. |
363 | */ |
364 | wmb(); |
365 | iowrite32(new_posted, &dc2c->wq_ctrl->posted_index); |
366 | |
367 | if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) |
368 | return 0; |
369 | |
370 | result = dc2c->result + dc2c->next_result; |
371 | color = dc2c->color; |
372 | |
373 | dc2c->next_result++; |
374 | if (dc2c->next_result == dc2c->result_size) { |
375 | dc2c->next_result = 0; |
376 | dc2c->color = dc2c->color ? 0 : 1; |
377 | } |
378 | |
379 | for (delay = 0; delay < wait; delay++) { |
380 | udelay(100); |
381 | if (result->color == color) { |
382 | if (result->error) { |
383 | err = -(int) result->error; |
384 | if (err != ERR_ECMDUNKNOWN || |
385 | cmd != CMD_CAPABILITY) |
386 | pr_err("%s:Error %d devcmd %d\n" , |
387 | pci_name(vdev->pdev), |
388 | err, _CMD_N(cmd)); |
389 | return err; |
390 | } |
391 | if (_CMD_DIR(cmd) & _CMD_DIR_READ) { |
392 | rmb(); /*prevent reorder while reding result*/ |
393 | for (i = 0; i < VNIC_DEVCMD_NARGS; i++) |
394 | vdev->args[i] = result->results[i]; |
395 | } |
396 | return 0; |
397 | } |
398 | } |
399 | |
400 | pr_err("%s:Timed out devcmd %d\n" , pci_name(vdev->pdev), _CMD_N(cmd)); |
401 | |
402 | return -ETIMEDOUT; |
403 | } |
404 | |
405 | |
406 | static int vnic_dev_init_devcmd1(struct vnic_dev *vdev) |
407 | { |
408 | vdev->devcmd = vnic_dev_get_res(vdev, type: RES_TYPE_DEVCMD, index: 0); |
409 | if (!vdev->devcmd) |
410 | return -ENODEV; |
411 | |
412 | vdev->devcmd_rtn = &vnic_dev_cmd1; |
413 | return 0; |
414 | } |
415 | |
416 | |
417 | static int vnic_dev_init_devcmd2(struct vnic_dev *vdev) |
418 | { |
419 | int err; |
420 | unsigned int fetch_index; |
421 | |
422 | if (vdev->devcmd2) |
423 | return 0; |
424 | |
425 | vdev->devcmd2 = kzalloc(size: sizeof(*vdev->devcmd2), GFP_ATOMIC); |
426 | if (!vdev->devcmd2) |
427 | return -ENOMEM; |
428 | |
429 | vdev->devcmd2->color = 1; |
430 | vdev->devcmd2->result_size = DEVCMD2_RING_SIZE; |
431 | err = vnic_wq_devcmd2_alloc(vdev, wq: &vdev->devcmd2->wq, |
432 | DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE); |
433 | if (err) |
434 | goto err_free_devcmd2; |
435 | |
436 | fetch_index = ioread32(&vdev->devcmd2->wq.ctrl->fetch_index); |
437 | if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */ |
438 | pr_err("error in devcmd2 init" ); |
439 | err = -ENODEV; |
440 | goto err_free_wq; |
441 | } |
442 | |
443 | /* |
444 | * Don't change fetch_index ever and |
445 | * set posted_index same as fetch_index |
446 | * when setting up the WQ for devcmd2. |
447 | */ |
448 | vnic_wq_init_start(wq: &vdev->devcmd2->wq, cq_index: 0, fetch_index, |
449 | posted_index: fetch_index, error_interrupt_enable: 0, error_interrupt_offset: 0); |
450 | |
451 | vnic_wq_enable(wq: &vdev->devcmd2->wq); |
452 | |
453 | err = vnic_dev_alloc_desc_ring(vdev, ring: &vdev->devcmd2->results_ring, |
454 | DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE); |
455 | if (err) |
456 | goto err_disable_wq; |
457 | |
458 | vdev->devcmd2->result = |
459 | (struct devcmd2_result *) vdev->devcmd2->results_ring.descs; |
460 | vdev->devcmd2->cmd_ring = |
461 | (struct vnic_devcmd2 *) vdev->devcmd2->wq.ring.descs; |
462 | vdev->devcmd2->wq_ctrl = vdev->devcmd2->wq.ctrl; |
463 | vdev->args[0] = (u64) vdev->devcmd2->results_ring.base_addr | |
464 | VNIC_PADDR_TARGET; |
465 | vdev->args[1] = DEVCMD2_RING_SIZE; |
466 | |
467 | err = vnic_dev_cmd2(vdev, cmd: CMD_INITIALIZE_DEVCMD2, wait: 1000); |
468 | if (err) |
469 | goto err_free_desc_ring; |
470 | |
471 | vdev->devcmd_rtn = &vnic_dev_cmd2; |
472 | |
473 | return 0; |
474 | |
475 | err_free_desc_ring: |
476 | vnic_dev_free_desc_ring(vdev, ring: &vdev->devcmd2->results_ring); |
477 | err_disable_wq: |
478 | vnic_wq_disable(wq: &vdev->devcmd2->wq); |
479 | err_free_wq: |
480 | vnic_wq_free(wq: &vdev->devcmd2->wq); |
481 | err_free_devcmd2: |
482 | kfree(objp: vdev->devcmd2); |
483 | vdev->devcmd2 = NULL; |
484 | |
485 | return err; |
486 | } |
487 | |
488 | |
489 | static void vnic_dev_deinit_devcmd2(struct vnic_dev *vdev) |
490 | { |
491 | vnic_dev_free_desc_ring(vdev, ring: &vdev->devcmd2->results_ring); |
492 | vnic_wq_disable(wq: &vdev->devcmd2->wq); |
493 | vnic_wq_free(wq: &vdev->devcmd2->wq); |
494 | kfree(objp: vdev->devcmd2); |
495 | vdev->devcmd2 = NULL; |
496 | vdev->devcmd_rtn = &vnic_dev_cmd1; |
497 | } |
498 | |
499 | |
500 | static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev, |
501 | enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait) |
502 | { |
503 | int err; |
504 | |
505 | vdev->args[0] = *a0; |
506 | vdev->args[1] = *a1; |
507 | |
508 | err = (*vdev->devcmd_rtn)(vdev, cmd, wait); |
509 | |
510 | *a0 = vdev->args[0]; |
511 | *a1 = vdev->args[1]; |
512 | |
513 | return err; |
514 | } |
515 | |
516 | |
517 | int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, |
518 | u64 *a0, u64 *a1, int wait) |
519 | { |
520 | memset(vdev->args, 0, sizeof(vdev->args)); |
521 | |
522 | switch (vdev->proxy) { |
523 | case PROXY_NONE: |
524 | default: |
525 | return vnic_dev_cmd_no_proxy(vdev, cmd, a0, a1, wait); |
526 | } |
527 | } |
528 | |
529 | |
530 | int vnic_dev_fw_info(struct vnic_dev *vdev, |
531 | struct vnic_devcmd_fw_info **fw_info) |
532 | { |
533 | u64 a0, a1 = 0; |
534 | int wait = 1000; |
535 | int err = 0; |
536 | |
537 | if (!vdev->fw_info) { |
538 | vdev->fw_info = dma_alloc_coherent(dev: &vdev->pdev->dev, |
539 | size: sizeof(struct vnic_devcmd_fw_info), |
540 | dma_handle: &vdev->fw_info_pa, GFP_KERNEL); |
541 | if (!vdev->fw_info) |
542 | return -ENOMEM; |
543 | |
544 | a0 = vdev->fw_info_pa; |
545 | |
546 | /* only get fw_info once and cache it */ |
547 | err = vnic_dev_cmd(vdev, cmd: CMD_MCPU_FW_INFO, a0: &a0, a1: &a1, wait); |
548 | } |
549 | |
550 | *fw_info = vdev->fw_info; |
551 | |
552 | return err; |
553 | } |
554 | |
555 | int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, |
556 | void *value) |
557 | { |
558 | u64 a0, a1; |
559 | int wait = 1000; |
560 | int err; |
561 | |
562 | a0 = offset; |
563 | a1 = size; |
564 | |
565 | err = vnic_dev_cmd(vdev, cmd: CMD_DEV_SPEC, a0: &a0, a1: &a1, wait); |
566 | |
567 | switch (size) { |
568 | case 1: |
569 | *(u8 *)value = (u8)a0; |
570 | break; |
571 | case 2: |
572 | *(u16 *)value = (u16)a0; |
573 | break; |
574 | case 4: |
575 | *(u32 *)value = (u32)a0; |
576 | break; |
577 | case 8: |
578 | *(u64 *)value = a0; |
579 | break; |
580 | default: |
581 | BUG(); |
582 | break; |
583 | } |
584 | |
585 | return err; |
586 | } |
587 | |
588 | int vnic_dev_stats_clear(struct vnic_dev *vdev) |
589 | { |
590 | u64 a0 = 0, a1 = 0; |
591 | int wait = 1000; |
592 | return vnic_dev_cmd(vdev, cmd: CMD_STATS_CLEAR, a0: &a0, a1: &a1, wait); |
593 | } |
594 | |
595 | int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) |
596 | { |
597 | u64 a0, a1; |
598 | int wait = 1000; |
599 | |
600 | if (!vdev->stats) { |
601 | vdev->stats = dma_alloc_coherent(dev: &vdev->pdev->dev, |
602 | size: sizeof(struct vnic_stats), dma_handle: &vdev->stats_pa, GFP_KERNEL); |
603 | if (!vdev->stats) |
604 | return -ENOMEM; |
605 | } |
606 | |
607 | *stats = vdev->stats; |
608 | a0 = vdev->stats_pa; |
609 | a1 = sizeof(struct vnic_stats); |
610 | |
611 | return vnic_dev_cmd(vdev, cmd: CMD_STATS_DUMP, a0: &a0, a1: &a1, wait); |
612 | } |
613 | |
614 | int vnic_dev_close(struct vnic_dev *vdev) |
615 | { |
616 | u64 a0 = 0, a1 = 0; |
617 | int wait = 1000; |
618 | return vnic_dev_cmd(vdev, cmd: CMD_CLOSE, a0: &a0, a1: &a1, wait); |
619 | } |
620 | |
621 | int vnic_dev_enable(struct vnic_dev *vdev) |
622 | { |
623 | u64 a0 = 0, a1 = 0; |
624 | int wait = 1000; |
625 | return vnic_dev_cmd(vdev, cmd: CMD_ENABLE, a0: &a0, a1: &a1, wait); |
626 | } |
627 | |
628 | int vnic_dev_disable(struct vnic_dev *vdev) |
629 | { |
630 | u64 a0 = 0, a1 = 0; |
631 | int wait = 1000; |
632 | return vnic_dev_cmd(vdev, cmd: CMD_DISABLE, a0: &a0, a1: &a1, wait); |
633 | } |
634 | |
635 | int vnic_dev_open(struct vnic_dev *vdev, int arg) |
636 | { |
637 | u64 a0 = (u32)arg, a1 = 0; |
638 | int wait = 1000; |
639 | return vnic_dev_cmd(vdev, cmd: CMD_OPEN, a0: &a0, a1: &a1, wait); |
640 | } |
641 | |
642 | int vnic_dev_open_done(struct vnic_dev *vdev, int *done) |
643 | { |
644 | u64 a0 = 0, a1 = 0; |
645 | int wait = 1000; |
646 | int err; |
647 | |
648 | *done = 0; |
649 | |
650 | err = vnic_dev_cmd(vdev, cmd: CMD_OPEN_STATUS, a0: &a0, a1: &a1, wait); |
651 | if (err) |
652 | return err; |
653 | |
654 | *done = (a0 == 0); |
655 | |
656 | return 0; |
657 | } |
658 | |
659 | int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg) |
660 | { |
661 | u64 a0 = (u32)arg, a1 = 0; |
662 | int wait = 1000; |
663 | return vnic_dev_cmd(vdev, cmd: CMD_SOFT_RESET, a0: &a0, a1: &a1, wait); |
664 | } |
665 | |
666 | int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done) |
667 | { |
668 | u64 a0 = 0, a1 = 0; |
669 | int wait = 1000; |
670 | int err; |
671 | |
672 | *done = 0; |
673 | |
674 | err = vnic_dev_cmd(vdev, cmd: CMD_SOFT_RESET_STATUS, a0: &a0, a1: &a1, wait); |
675 | if (err) |
676 | return err; |
677 | |
678 | *done = (a0 == 0); |
679 | |
680 | return 0; |
681 | } |
682 | |
683 | int vnic_dev_hang_notify(struct vnic_dev *vdev) |
684 | { |
685 | u64 a0 = 0, a1 = 0; |
686 | int wait = 1000; |
687 | return vnic_dev_cmd(vdev, cmd: CMD_HANG_NOTIFY, a0: &a0, a1: &a1, wait); |
688 | } |
689 | |
690 | int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) |
691 | { |
692 | u64 a[2] = {}; |
693 | int wait = 1000; |
694 | int err, i; |
695 | |
696 | for (i = 0; i < ETH_ALEN; i++) |
697 | mac_addr[i] = 0; |
698 | |
699 | err = vnic_dev_cmd(vdev, cmd: CMD_MAC_ADDR, a0: &a[0], a1: &a[1], wait); |
700 | if (err) |
701 | return err; |
702 | |
703 | for (i = 0; i < ETH_ALEN; i++) |
704 | mac_addr[i] = ((u8 *)&a)[i]; |
705 | |
706 | return 0; |
707 | } |
708 | |
709 | void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, |
710 | int broadcast, int promisc, int allmulti) |
711 | { |
712 | u64 a0, a1 = 0; |
713 | int wait = 1000; |
714 | int err; |
715 | |
716 | a0 = (directed ? CMD_PFILTER_DIRECTED : 0) | |
717 | (multicast ? CMD_PFILTER_MULTICAST : 0) | |
718 | (broadcast ? CMD_PFILTER_BROADCAST : 0) | |
719 | (promisc ? CMD_PFILTER_PROMISCUOUS : 0) | |
720 | (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0); |
721 | |
722 | err = vnic_dev_cmd(vdev, cmd: CMD_PACKET_FILTER, a0: &a0, a1: &a1, wait); |
723 | if (err) |
724 | printk(KERN_ERR "Can't set packet filter\n" ); |
725 | } |
726 | |
727 | void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) |
728 | { |
729 | u64 a[2] = {}; |
730 | int wait = 1000; |
731 | int err; |
732 | int i; |
733 | |
734 | for (i = 0; i < ETH_ALEN; i++) |
735 | ((u8 *)&a)[i] = addr[i]; |
736 | |
737 | err = vnic_dev_cmd(vdev, cmd: CMD_ADDR_ADD, a0: &a[0], a1: &a[1], wait); |
738 | if (err) |
739 | pr_err("Can't add addr [%pM], %d\n" , addr, err); |
740 | } |
741 | |
742 | void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) |
743 | { |
744 | u64 a[2] = {}; |
745 | int wait = 1000; |
746 | int err; |
747 | int i; |
748 | |
749 | for (i = 0; i < ETH_ALEN; i++) |
750 | ((u8 *)&a)[i] = addr[i]; |
751 | |
752 | err = vnic_dev_cmd(vdev, cmd: CMD_ADDR_DEL, a0: &a[0], a1: &a[1], wait); |
753 | if (err) |
754 | pr_err("Can't del addr [%pM], %d\n" , addr, err); |
755 | } |
756 | |
757 | int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) |
758 | { |
759 | u64 a0, a1; |
760 | int wait = 1000; |
761 | |
762 | if (!vdev->notify) { |
763 | vdev->notify = dma_alloc_coherent(dev: &vdev->pdev->dev, |
764 | size: sizeof(struct vnic_devcmd_notify), |
765 | dma_handle: &vdev->notify_pa, GFP_KERNEL); |
766 | if (!vdev->notify) |
767 | return -ENOMEM; |
768 | } |
769 | |
770 | a0 = vdev->notify_pa; |
771 | a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; |
772 | a1 += sizeof(struct vnic_devcmd_notify); |
773 | |
774 | return vnic_dev_cmd(vdev, cmd: CMD_NOTIFY, a0: &a0, a1: &a1, wait); |
775 | } |
776 | |
777 | void vnic_dev_notify_unset(struct vnic_dev *vdev) |
778 | { |
779 | u64 a0, a1; |
780 | int wait = 1000; |
781 | |
782 | a0 = 0; /* paddr = 0 to unset notify buffer */ |
783 | a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */ |
784 | a1 += sizeof(struct vnic_devcmd_notify); |
785 | |
786 | vnic_dev_cmd(vdev, cmd: CMD_NOTIFY, a0: &a0, a1: &a1, wait); |
787 | } |
788 | |
789 | static int vnic_dev_notify_ready(struct vnic_dev *vdev) |
790 | { |
791 | u32 *words; |
792 | unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; |
793 | unsigned int i; |
794 | u32 csum; |
795 | |
796 | if (!vdev->notify) |
797 | return 0; |
798 | |
799 | do { |
800 | csum = 0; |
801 | memcpy(&vdev->notify_copy, vdev->notify, |
802 | sizeof(struct vnic_devcmd_notify)); |
803 | words = (u32 *)&vdev->notify_copy; |
804 | for (i = 1; i < nwords; i++) |
805 | csum += words[i]; |
806 | } while (csum != words[0]); |
807 | |
808 | return 1; |
809 | } |
810 | |
811 | int vnic_dev_init(struct vnic_dev *vdev, int arg) |
812 | { |
813 | u64 a0 = (u32)arg, a1 = 0; |
814 | int wait = 1000; |
815 | return vnic_dev_cmd(vdev, cmd: CMD_INIT, a0: &a0, a1: &a1, wait); |
816 | } |
817 | |
818 | u16 vnic_dev_set_default_vlan(struct vnic_dev *vdev, u16 new_default_vlan) |
819 | { |
820 | u64 a0 = new_default_vlan, a1 = 0; |
821 | int wait = 1000; |
822 | int old_vlan = 0; |
823 | |
824 | old_vlan = vnic_dev_cmd(vdev, cmd: CMD_SET_DEFAULT_VLAN, a0: &a0, a1: &a1, wait); |
825 | return (u16)old_vlan; |
826 | } |
827 | |
828 | int vnic_dev_link_status(struct vnic_dev *vdev) |
829 | { |
830 | if (vdev->linkstatus) |
831 | return *vdev->linkstatus; |
832 | |
833 | if (!vnic_dev_notify_ready(vdev)) |
834 | return 0; |
835 | |
836 | return vdev->notify_copy.link_state; |
837 | } |
838 | |
839 | u32 vnic_dev_port_speed(struct vnic_dev *vdev) |
840 | { |
841 | if (!vnic_dev_notify_ready(vdev)) |
842 | return 0; |
843 | |
844 | return vdev->notify_copy.port_speed; |
845 | } |
846 | |
847 | u32 vnic_dev_msg_lvl(struct vnic_dev *vdev) |
848 | { |
849 | if (!vnic_dev_notify_ready(vdev)) |
850 | return 0; |
851 | |
852 | return vdev->notify_copy.msglvl; |
853 | } |
854 | |
855 | u32 vnic_dev_mtu(struct vnic_dev *vdev) |
856 | { |
857 | if (!vnic_dev_notify_ready(vdev)) |
858 | return 0; |
859 | |
860 | return vdev->notify_copy.mtu; |
861 | } |
862 | |
863 | u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev) |
864 | { |
865 | if (!vnic_dev_notify_ready(vdev)) |
866 | return 0; |
867 | |
868 | return vdev->notify_copy.link_down_cnt; |
869 | } |
870 | |
871 | void vnic_dev_set_intr_mode(struct vnic_dev *vdev, |
872 | enum vnic_dev_intr_mode intr_mode) |
873 | { |
874 | vdev->intr_mode = intr_mode; |
875 | } |
876 | |
877 | enum vnic_dev_intr_mode vnic_dev_get_intr_mode( |
878 | struct vnic_dev *vdev) |
879 | { |
880 | return vdev->intr_mode; |
881 | } |
882 | |
883 | void vnic_dev_unregister(struct vnic_dev *vdev) |
884 | { |
885 | if (vdev) { |
886 | if (vdev->notify) |
887 | dma_free_coherent(dev: &vdev->pdev->dev, |
888 | size: sizeof(struct vnic_devcmd_notify), |
889 | cpu_addr: vdev->notify, |
890 | dma_handle: vdev->notify_pa); |
891 | if (vdev->linkstatus) |
892 | dma_free_coherent(dev: &vdev->pdev->dev, |
893 | size: sizeof(u32), |
894 | cpu_addr: vdev->linkstatus, |
895 | dma_handle: vdev->linkstatus_pa); |
896 | if (vdev->stats) |
897 | dma_free_coherent(dev: &vdev->pdev->dev, |
898 | size: sizeof(struct vnic_stats), |
899 | cpu_addr: vdev->stats, dma_handle: vdev->stats_pa); |
900 | if (vdev->fw_info) |
901 | dma_free_coherent(dev: &vdev->pdev->dev, |
902 | size: sizeof(struct vnic_devcmd_fw_info), |
903 | cpu_addr: vdev->fw_info, dma_handle: vdev->fw_info_pa); |
904 | if (vdev->devcmd2) |
905 | vnic_dev_deinit_devcmd2(vdev); |
906 | kfree(objp: vdev); |
907 | } |
908 | } |
909 | |
910 | struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, |
911 | void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) |
912 | { |
913 | if (!vdev) { |
914 | vdev = kzalloc(size: sizeof(struct vnic_dev), GFP_KERNEL); |
915 | if (!vdev) |
916 | return NULL; |
917 | } |
918 | |
919 | vdev->priv = priv; |
920 | vdev->pdev = pdev; |
921 | |
922 | if (vnic_dev_discover_res(vdev, bar)) |
923 | goto err_out; |
924 | |
925 | return vdev; |
926 | |
927 | err_out: |
928 | vnic_dev_unregister(vdev); |
929 | return NULL; |
930 | } |
931 | |
932 | int vnic_dev_cmd_init(struct vnic_dev *vdev) |
933 | { |
934 | int err; |
935 | void *p; |
936 | |
937 | p = vnic_dev_get_res(vdev, type: RES_TYPE_DEVCMD2, index: 0); |
938 | if (p) { |
939 | pr_err("fnic: DEVCMD2 resource found!\n" ); |
940 | err = vnic_dev_init_devcmd2(vdev); |
941 | } else { |
942 | pr_err("fnic: DEVCMD2 not found, fall back to Devcmd\n" ); |
943 | err = vnic_dev_init_devcmd1(vdev); |
944 | } |
945 | |
946 | return err; |
947 | } |
948 | |