2 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
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.
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
18 #include <linux/errno.h>
19 #include <linux/module.h>
20 #include <linux/pci.h>
23 #include "vnic_resource.h"
24 #include "usnic_log.h"
25 #include "usnic_vnic.h"
28 struct vnic_dev
*vdev
;
29 struct vnic_dev_bar bar
[PCI_NUM_RESOURCES
];
30 struct usnic_vnic_res_chunk chunks
[USNIC_VNIC_RES_TYPE_MAX
];
34 static enum vnic_res_type
_to_vnic_res_type(enum usnic_vnic_res_type res_type
)
36 #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
38 #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
40 static enum vnic_res_type usnic_vnic_type_2_vnic_type
[] = {
41 USNIC_VNIC_RES_TYPES
};
42 #undef DEFINE_USNIC_VNIC_RES
43 #undef DEFINE_USNIC_VNIC_RES_AT
45 if (res_type
>= USNIC_VNIC_RES_TYPE_MAX
)
48 return usnic_vnic_type_2_vnic_type
[res_type
];
51 const char *usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type
)
53 #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
55 #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
57 static const char * const usnic_vnic_res_type_desc
[] = {
58 USNIC_VNIC_RES_TYPES
};
59 #undef DEFINE_USNIC_VNIC_RES
60 #undef DEFINE_USNIC_VNIC_RES_AT
62 if (res_type
>= USNIC_VNIC_RES_TYPE_MAX
)
65 return usnic_vnic_res_type_desc
[res_type
];
69 const char *usnic_vnic_pci_name(struct usnic_vnic
*vnic
)
71 return pci_name(usnic_vnic_get_pdev(vnic
));
74 int usnic_vnic_dump(struct usnic_vnic
*vnic
, char *buf
,
77 int (*printtitle
)(void *, char*, int),
78 int (*printcols
)(char *, int),
79 int (*printrow
)(void *, char *, int))
81 struct usnic_vnic_res_chunk
*chunk
;
82 struct usnic_vnic_res
*res
;
83 struct vnic_dev_bar
*bar0
;
87 bar0
= usnic_vnic_get_bar(vnic
, 0);
88 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
89 "VF:%hu BAR0 bus_addr=%pa vaddr=0x%p size=%ld ",
90 usnic_vnic_get_index(vnic
),
92 bar0
->vaddr
, bar0
->len
);
94 offset
+= printtitle(hdr_obj
, buf
+ offset
, buf_sz
- offset
);
95 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
, "\n");
96 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
97 "|RES\t|CTRL_PIN\t\t|IN_USE\t");
99 offset
+= printcols(buf
+ offset
, buf_sz
- offset
);
100 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
, "\n");
102 spin_lock(&vnic
->res_lock
);
103 for (i
= 0; i
< ARRAY_SIZE(vnic
->chunks
); i
++) {
104 chunk
= &vnic
->chunks
[i
];
105 for (j
= 0; j
< chunk
->cnt
; j
++) {
107 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
108 "|%s[%u]\t|0x%p\t|%u\t",
109 usnic_vnic_res_type_to_str(res
->type
),
110 res
->vnic_idx
, res
->ctrl
, !!res
->owner
);
112 offset
+= printrow(res
->owner
, buf
+ offset
,
115 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
119 spin_unlock(&vnic
->res_lock
);
123 void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec
*spec
,
124 enum usnic_vnic_res_type trgt_type
,
129 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
130 if (spec
->resources
[i
].type
== trgt_type
) {
131 spec
->resources
[i
].cnt
= cnt
;
139 int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec
*min_spec
,
140 struct usnic_vnic_res_spec
*res_spec
)
144 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
147 for (j
= 0; j
< USNIC_VNIC_RES_TYPE_MAX
; j
++) {
148 if (res_spec
->resources
[i
].type
!=
149 min_spec
->resources
[i
].type
)
152 if (min_spec
->resources
[i
].cnt
>
153 res_spec
->resources
[i
].cnt
)
164 int usnic_vnic_spec_dump(char *buf
, int buf_sz
,
165 struct usnic_vnic_res_spec
*res_spec
)
167 enum usnic_vnic_res_type res_type
;
172 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
173 res_type
= res_spec
->resources
[i
].type
;
174 res_cnt
= res_spec
->resources
[i
].cnt
;
175 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
177 usnic_vnic_res_type_to_str(res_type
),
184 int usnic_vnic_check_room(struct usnic_vnic
*vnic
,
185 struct usnic_vnic_res_spec
*res_spec
)
188 enum usnic_vnic_res_type res_type
;
191 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
192 res_type
= res_spec
->resources
[i
].type
;
193 res_cnt
= res_spec
->resources
[i
].cnt
;
195 if (res_type
== USNIC_VNIC_RES_TYPE_EOL
)
198 if (res_cnt
> usnic_vnic_res_free_cnt(vnic
, res_type
))
205 int usnic_vnic_res_cnt(struct usnic_vnic
*vnic
,
206 enum usnic_vnic_res_type type
)
208 return vnic
->chunks
[type
].cnt
;
211 int usnic_vnic_res_free_cnt(struct usnic_vnic
*vnic
,
212 enum usnic_vnic_res_type type
)
214 return vnic
->chunks
[type
].free_cnt
;
217 struct usnic_vnic_res_chunk
*
218 usnic_vnic_get_resources(struct usnic_vnic
*vnic
, enum usnic_vnic_res_type type
,
219 int cnt
, void *owner
)
221 struct usnic_vnic_res_chunk
*src
, *ret
;
222 struct usnic_vnic_res
*res
;
225 if (usnic_vnic_res_free_cnt(vnic
, type
) < cnt
|| cnt
< 1 || !owner
)
226 return ERR_PTR(-EINVAL
);
228 ret
= kzalloc(sizeof(*ret
), GFP_ATOMIC
);
230 usnic_err("Failed to allocate chunk for %s - Out of memory\n",
231 usnic_vnic_pci_name(vnic
));
232 return ERR_PTR(-ENOMEM
);
235 ret
->res
= kzalloc(sizeof(*(ret
->res
))*cnt
, GFP_ATOMIC
);
237 usnic_err("Failed to allocate resources for %s. Out of memory\n",
238 usnic_vnic_pci_name(vnic
));
240 return ERR_PTR(-ENOMEM
);
243 spin_lock(&vnic
->res_lock
);
244 src
= &vnic
->chunks
[type
];
245 for (i
= 0; i
< src
->cnt
&& ret
->cnt
< cnt
; i
++) {
250 ret
->res
[ret
->cnt
++] = res
;
254 spin_unlock(&vnic
->res_lock
);
257 WARN_ON(ret
->cnt
!= cnt
);
262 void usnic_vnic_put_resources(struct usnic_vnic_res_chunk
*chunk
)
265 struct usnic_vnic_res
*res
;
267 struct usnic_vnic
*vnic
= chunk
->vnic
;
269 spin_lock(&vnic
->res_lock
);
270 while ((i
= --chunk
->cnt
) >= 0) {
272 chunk
->res
[i
] = NULL
;
274 vnic
->chunks
[res
->type
].free_cnt
++;
276 spin_unlock(&vnic
->res_lock
);
282 u16
usnic_vnic_get_index(struct usnic_vnic
*vnic
)
284 return usnic_vnic_get_pdev(vnic
)->devfn
- 1;
287 static int usnic_vnic_alloc_res_chunk(struct usnic_vnic
*vnic
,
288 enum usnic_vnic_res_type type
,
289 struct usnic_vnic_res_chunk
*chunk
)
292 struct usnic_vnic_res
*res
;
294 cnt
= vnic_dev_get_res_count(vnic
->vdev
, _to_vnic_res_type(type
));
298 chunk
->cnt
= chunk
->free_cnt
= cnt
;
299 chunk
->res
= kzalloc(sizeof(*(chunk
->res
))*cnt
, GFP_KERNEL
);
303 for (i
= 0; i
< cnt
; i
++) {
304 res
= kzalloc(sizeof(*res
), GFP_KERNEL
);
312 res
->ctrl
= vnic_dev_get_res(vnic
->vdev
,
313 _to_vnic_res_type(type
), i
);
320 for (i
--; i
>= 0; i
--)
321 kfree(chunk
->res
[i
]);
326 static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk
*chunk
)
329 for (i
= 0; i
< chunk
->cnt
; i
++)
330 kfree(chunk
->res
[i
]);
334 static int usnic_vnic_discover_resources(struct pci_dev
*pdev
,
335 struct usnic_vnic
*vnic
)
337 enum usnic_vnic_res_type res_type
;
341 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
342 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
344 vnic
->bar
[i
].len
= pci_resource_len(pdev
, i
);
345 vnic
->bar
[i
].vaddr
= pci_iomap(pdev
, i
, vnic
->bar
[i
].len
);
346 if (!vnic
->bar
[i
].vaddr
) {
347 usnic_err("Cannot memory-map BAR %d, aborting\n",
352 vnic
->bar
[i
].bus_addr
= pci_resource_start(pdev
, i
);
355 vnic
->vdev
= vnic_dev_register(NULL
, pdev
, pdev
, vnic
->bar
,
356 ARRAY_SIZE(vnic
->bar
));
358 usnic_err("Failed to register device %s\n",
364 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
365 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++) {
366 err
= usnic_vnic_alloc_res_chunk(vnic
, res_type
,
367 &vnic
->chunks
[res_type
]);
369 usnic_err("Failed to alloc res %s with err %d\n",
370 usnic_vnic_res_type_to_str(res_type
),
372 goto out_clean_chunks
;
379 for (res_type
--; res_type
> USNIC_VNIC_RES_TYPE_EOL
; res_type
--)
380 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
381 vnic_dev_unregister(vnic
->vdev
);
383 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
384 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
386 if (!vnic
->bar
[i
].vaddr
)
389 iounmap(vnic
->bar
[i
].vaddr
);
395 struct pci_dev
*usnic_vnic_get_pdev(struct usnic_vnic
*vnic
)
397 return vnic_dev_get_pdev(vnic
->vdev
);
400 struct vnic_dev_bar
*usnic_vnic_get_bar(struct usnic_vnic
*vnic
,
403 return (bar_num
< ARRAY_SIZE(vnic
->bar
)) ? &vnic
->bar
[bar_num
] : NULL
;
406 static void usnic_vnic_release_resources(struct usnic_vnic
*vnic
)
409 struct pci_dev
*pdev
;
410 enum usnic_vnic_res_type res_type
;
412 pdev
= usnic_vnic_get_pdev(vnic
);
414 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
415 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++)
416 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
418 vnic_dev_unregister(vnic
->vdev
);
420 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
421 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
423 iounmap(vnic
->bar
[i
].vaddr
);
427 struct usnic_vnic
*usnic_vnic_alloc(struct pci_dev
*pdev
)
429 struct usnic_vnic
*vnic
;
432 if (!pci_is_enabled(pdev
)) {
433 usnic_err("PCI dev %s is disabled\n", pci_name(pdev
));
434 return ERR_PTR(-EINVAL
);
437 vnic
= kzalloc(sizeof(*vnic
), GFP_KERNEL
);
439 usnic_err("Failed to alloc vnic for %s - out of memory\n",
441 return ERR_PTR(-ENOMEM
);
444 spin_lock_init(&vnic
->res_lock
);
446 err
= usnic_vnic_discover_resources(pdev
, vnic
);
448 usnic_err("Failed to discover %s resources with err %d\n",
449 pci_name(pdev
), err
);
453 usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic
));
463 void usnic_vnic_free(struct usnic_vnic
*vnic
)
465 usnic_vnic_release_resources(vnic
);