2 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <linux/errno.h>
34 #include <linux/pci.h>
37 #include "vnic_resource.h"
38 #include "usnic_log.h"
39 #include "usnic_vnic.h"
42 struct vnic_dev
*vdev
;
43 struct vnic_dev_bar bar
[PCI_NUM_RESOURCES
];
44 struct usnic_vnic_res_chunk chunks
[USNIC_VNIC_RES_TYPE_MAX
];
48 static enum vnic_res_type
_to_vnic_res_type(enum usnic_vnic_res_type res_type
)
50 #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
52 #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
54 static enum vnic_res_type usnic_vnic_type_2_vnic_type
[] = {
55 USNIC_VNIC_RES_TYPES
};
56 #undef DEFINE_USNIC_VNIC_RES
57 #undef DEFINE_USNIC_VNIC_RES_AT
59 if (res_type
>= USNIC_VNIC_RES_TYPE_MAX
)
62 return usnic_vnic_type_2_vnic_type
[res_type
];
65 const char *usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type
)
67 #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
69 #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
71 static const char * const usnic_vnic_res_type_desc
[] = {
72 USNIC_VNIC_RES_TYPES
};
73 #undef DEFINE_USNIC_VNIC_RES
74 #undef DEFINE_USNIC_VNIC_RES_AT
76 if (res_type
>= USNIC_VNIC_RES_TYPE_MAX
)
79 return usnic_vnic_res_type_desc
[res_type
];
83 const char *usnic_vnic_pci_name(struct usnic_vnic
*vnic
)
85 return pci_name(usnic_vnic_get_pdev(vnic
));
88 int usnic_vnic_dump(struct usnic_vnic
*vnic
, char *buf
,
91 int (*printtitle
)(void *, char*, int),
92 int (*printcols
)(char *, int),
93 int (*printrow
)(void *, char *, int))
95 struct usnic_vnic_res_chunk
*chunk
;
96 struct usnic_vnic_res
*res
;
97 struct vnic_dev_bar
*bar0
;
101 bar0
= usnic_vnic_get_bar(vnic
, 0);
102 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
103 "VF:%hu BAR0 bus_addr=%pa vaddr=0x%p size=%ld ",
104 usnic_vnic_get_index(vnic
),
106 bar0
->vaddr
, bar0
->len
);
108 offset
+= printtitle(hdr_obj
, buf
+ offset
, buf_sz
- offset
);
109 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
, "\n");
110 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
111 "|RES\t|CTRL_PIN\t\t|IN_USE\t");
113 offset
+= printcols(buf
+ offset
, buf_sz
- offset
);
114 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
, "\n");
116 spin_lock(&vnic
->res_lock
);
117 for (i
= 0; i
< ARRAY_SIZE(vnic
->chunks
); i
++) {
118 chunk
= &vnic
->chunks
[i
];
119 for (j
= 0; j
< chunk
->cnt
; j
++) {
121 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
122 "|%s[%u]\t|0x%p\t|%u\t",
123 usnic_vnic_res_type_to_str(res
->type
),
124 res
->vnic_idx
, res
->ctrl
, !!res
->owner
);
126 offset
+= printrow(res
->owner
, buf
+ offset
,
129 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
133 spin_unlock(&vnic
->res_lock
);
137 void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec
*spec
,
138 enum usnic_vnic_res_type trgt_type
,
143 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
144 if (spec
->resources
[i
].type
== trgt_type
) {
145 spec
->resources
[i
].cnt
= cnt
;
153 int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec
*min_spec
,
154 struct usnic_vnic_res_spec
*res_spec
)
158 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
161 for (j
= 0; j
< USNIC_VNIC_RES_TYPE_MAX
; j
++) {
162 if (res_spec
->resources
[i
].type
!=
163 min_spec
->resources
[i
].type
)
166 if (min_spec
->resources
[i
].cnt
>
167 res_spec
->resources
[i
].cnt
)
178 int usnic_vnic_spec_dump(char *buf
, int buf_sz
,
179 struct usnic_vnic_res_spec
*res_spec
)
181 enum usnic_vnic_res_type res_type
;
186 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
187 res_type
= res_spec
->resources
[i
].type
;
188 res_cnt
= res_spec
->resources
[i
].cnt
;
189 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
191 usnic_vnic_res_type_to_str(res_type
),
198 int usnic_vnic_check_room(struct usnic_vnic
*vnic
,
199 struct usnic_vnic_res_spec
*res_spec
)
202 enum usnic_vnic_res_type res_type
;
205 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
206 res_type
= res_spec
->resources
[i
].type
;
207 res_cnt
= res_spec
->resources
[i
].cnt
;
209 if (res_type
== USNIC_VNIC_RES_TYPE_EOL
)
212 if (res_cnt
> usnic_vnic_res_free_cnt(vnic
, res_type
))
219 int usnic_vnic_res_cnt(struct usnic_vnic
*vnic
,
220 enum usnic_vnic_res_type type
)
222 return vnic
->chunks
[type
].cnt
;
225 int usnic_vnic_res_free_cnt(struct usnic_vnic
*vnic
,
226 enum usnic_vnic_res_type type
)
228 return vnic
->chunks
[type
].free_cnt
;
231 struct usnic_vnic_res_chunk
*
232 usnic_vnic_get_resources(struct usnic_vnic
*vnic
, enum usnic_vnic_res_type type
,
233 int cnt
, void *owner
)
235 struct usnic_vnic_res_chunk
*src
, *ret
;
236 struct usnic_vnic_res
*res
;
239 if (usnic_vnic_res_free_cnt(vnic
, type
) < cnt
|| cnt
< 0 || !owner
)
240 return ERR_PTR(-EINVAL
);
242 ret
= kzalloc(sizeof(*ret
), GFP_ATOMIC
);
244 return ERR_PTR(-ENOMEM
);
247 ret
->res
= kcalloc(cnt
, sizeof(*(ret
->res
)), GFP_ATOMIC
);
250 return ERR_PTR(-ENOMEM
);
253 spin_lock(&vnic
->res_lock
);
254 src
= &vnic
->chunks
[type
];
255 for (i
= 0; i
< src
->cnt
&& ret
->cnt
< cnt
; i
++) {
260 ret
->res
[ret
->cnt
++] = res
;
264 spin_unlock(&vnic
->res_lock
);
268 WARN_ON(ret
->cnt
!= cnt
);
273 void usnic_vnic_put_resources(struct usnic_vnic_res_chunk
*chunk
)
276 struct usnic_vnic_res
*res
;
278 struct usnic_vnic
*vnic
= chunk
->vnic
;
280 if (chunk
->cnt
> 0) {
281 spin_lock(&vnic
->res_lock
);
282 while ((i
= --chunk
->cnt
) >= 0) {
284 chunk
->res
[i
] = NULL
;
286 vnic
->chunks
[res
->type
].free_cnt
++;
288 spin_unlock(&vnic
->res_lock
);
295 u16
usnic_vnic_get_index(struct usnic_vnic
*vnic
)
297 return usnic_vnic_get_pdev(vnic
)->devfn
- 1;
300 static int usnic_vnic_alloc_res_chunk(struct usnic_vnic
*vnic
,
301 enum usnic_vnic_res_type type
,
302 struct usnic_vnic_res_chunk
*chunk
)
305 struct usnic_vnic_res
*res
;
307 cnt
= vnic_dev_get_res_count(vnic
->vdev
, _to_vnic_res_type(type
));
309 usnic_err("Wrong res count with cnt %d\n", cnt
);
313 chunk
->cnt
= chunk
->free_cnt
= cnt
;
314 chunk
->res
= kcalloc(cnt
, sizeof(*(chunk
->res
)), GFP_KERNEL
);
318 for (i
= 0; i
< cnt
; i
++) {
319 res
= kzalloc(sizeof(*res
), GFP_KERNEL
);
327 res
->ctrl
= vnic_dev_get_res(vnic
->vdev
,
328 _to_vnic_res_type(type
), i
);
335 for (i
--; i
>= 0; i
--)
336 kfree(chunk
->res
[i
]);
341 static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk
*chunk
)
344 for (i
= 0; i
< chunk
->cnt
; i
++)
345 kfree(chunk
->res
[i
]);
349 static int usnic_vnic_discover_resources(struct pci_dev
*pdev
,
350 struct usnic_vnic
*vnic
)
352 enum usnic_vnic_res_type res_type
;
356 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
357 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
359 vnic
->bar
[i
].len
= pci_resource_len(pdev
, i
);
360 vnic
->bar
[i
].vaddr
= pci_iomap(pdev
, i
, vnic
->bar
[i
].len
);
361 if (!vnic
->bar
[i
].vaddr
) {
362 usnic_err("Cannot memory-map BAR %d, aborting\n",
367 vnic
->bar
[i
].bus_addr
= pci_resource_start(pdev
, i
);
370 vnic
->vdev
= vnic_dev_register(NULL
, pdev
, pdev
, vnic
->bar
,
371 ARRAY_SIZE(vnic
->bar
));
373 usnic_err("Failed to register device %s\n",
379 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
380 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++) {
381 err
= usnic_vnic_alloc_res_chunk(vnic
, res_type
,
382 &vnic
->chunks
[res_type
]);
384 goto out_clean_chunks
;
390 for (res_type
--; res_type
> USNIC_VNIC_RES_TYPE_EOL
; res_type
--)
391 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
392 vnic_dev_unregister(vnic
->vdev
);
394 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
395 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
397 if (!vnic
->bar
[i
].vaddr
)
400 iounmap(vnic
->bar
[i
].vaddr
);
406 struct pci_dev
*usnic_vnic_get_pdev(struct usnic_vnic
*vnic
)
408 return vnic_dev_get_pdev(vnic
->vdev
);
411 struct vnic_dev_bar
*usnic_vnic_get_bar(struct usnic_vnic
*vnic
,
414 return (bar_num
< ARRAY_SIZE(vnic
->bar
)) ? &vnic
->bar
[bar_num
] : NULL
;
417 static void usnic_vnic_release_resources(struct usnic_vnic
*vnic
)
420 struct pci_dev
*pdev
;
421 enum usnic_vnic_res_type res_type
;
423 pdev
= usnic_vnic_get_pdev(vnic
);
425 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
426 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++)
427 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
429 vnic_dev_unregister(vnic
->vdev
);
431 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
432 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
434 iounmap(vnic
->bar
[i
].vaddr
);
438 struct usnic_vnic
*usnic_vnic_alloc(struct pci_dev
*pdev
)
440 struct usnic_vnic
*vnic
;
443 if (!pci_is_enabled(pdev
)) {
444 usnic_err("PCI dev %s is disabled\n", pci_name(pdev
));
445 return ERR_PTR(-EINVAL
);
448 vnic
= kzalloc(sizeof(*vnic
), GFP_KERNEL
);
450 return ERR_PTR(-ENOMEM
);
452 spin_lock_init(&vnic
->res_lock
);
454 err
= usnic_vnic_discover_resources(pdev
, vnic
);
456 usnic_err("Failed to discover %s resources with err %d\n",
457 pci_name(pdev
), err
);
461 usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic
));
471 void usnic_vnic_free(struct usnic_vnic
*vnic
)
473 usnic_vnic_release_resources(vnic
);