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/module.h>
35 #include <linux/pci.h>
38 #include "vnic_resource.h"
39 #include "usnic_log.h"
40 #include "usnic_vnic.h"
43 struct vnic_dev
*vdev
;
44 struct vnic_dev_bar bar
[PCI_NUM_RESOURCES
];
45 struct usnic_vnic_res_chunk chunks
[USNIC_VNIC_RES_TYPE_MAX
];
49 static enum vnic_res_type
_to_vnic_res_type(enum usnic_vnic_res_type res_type
)
51 #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
53 #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
55 static enum vnic_res_type usnic_vnic_type_2_vnic_type
[] = {
56 USNIC_VNIC_RES_TYPES
};
57 #undef DEFINE_USNIC_VNIC_RES
58 #undef DEFINE_USNIC_VNIC_RES_AT
60 if (res_type
>= USNIC_VNIC_RES_TYPE_MAX
)
63 return usnic_vnic_type_2_vnic_type
[res_type
];
66 const char *usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type
)
68 #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
70 #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
72 static const char * const usnic_vnic_res_type_desc
[] = {
73 USNIC_VNIC_RES_TYPES
};
74 #undef DEFINE_USNIC_VNIC_RES
75 #undef DEFINE_USNIC_VNIC_RES_AT
77 if (res_type
>= USNIC_VNIC_RES_TYPE_MAX
)
80 return usnic_vnic_res_type_desc
[res_type
];
84 const char *usnic_vnic_pci_name(struct usnic_vnic
*vnic
)
86 return pci_name(usnic_vnic_get_pdev(vnic
));
89 int usnic_vnic_dump(struct usnic_vnic
*vnic
, char *buf
,
92 int (*printtitle
)(void *, char*, int),
93 int (*printcols
)(char *, int),
94 int (*printrow
)(void *, char *, int))
96 struct usnic_vnic_res_chunk
*chunk
;
97 struct usnic_vnic_res
*res
;
98 struct vnic_dev_bar
*bar0
;
102 bar0
= usnic_vnic_get_bar(vnic
, 0);
103 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
104 "VF:%hu BAR0 bus_addr=%pa vaddr=0x%p size=%ld ",
105 usnic_vnic_get_index(vnic
),
107 bar0
->vaddr
, bar0
->len
);
109 offset
+= printtitle(hdr_obj
, buf
+ offset
, buf_sz
- offset
);
110 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
, "\n");
111 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
112 "|RES\t|CTRL_PIN\t\t|IN_USE\t");
114 offset
+= printcols(buf
+ offset
, buf_sz
- offset
);
115 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
, "\n");
117 spin_lock(&vnic
->res_lock
);
118 for (i
= 0; i
< ARRAY_SIZE(vnic
->chunks
); i
++) {
119 chunk
= &vnic
->chunks
[i
];
120 for (j
= 0; j
< chunk
->cnt
; j
++) {
122 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
123 "|%s[%u]\t|0x%p\t|%u\t",
124 usnic_vnic_res_type_to_str(res
->type
),
125 res
->vnic_idx
, res
->ctrl
, !!res
->owner
);
127 offset
+= printrow(res
->owner
, buf
+ offset
,
130 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
134 spin_unlock(&vnic
->res_lock
);
138 void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec
*spec
,
139 enum usnic_vnic_res_type trgt_type
,
144 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
145 if (spec
->resources
[i
].type
== trgt_type
) {
146 spec
->resources
[i
].cnt
= cnt
;
154 int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec
*min_spec
,
155 struct usnic_vnic_res_spec
*res_spec
)
159 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
162 for (j
= 0; j
< USNIC_VNIC_RES_TYPE_MAX
; j
++) {
163 if (res_spec
->resources
[i
].type
!=
164 min_spec
->resources
[i
].type
)
167 if (min_spec
->resources
[i
].cnt
>
168 res_spec
->resources
[i
].cnt
)
179 int usnic_vnic_spec_dump(char *buf
, int buf_sz
,
180 struct usnic_vnic_res_spec
*res_spec
)
182 enum usnic_vnic_res_type res_type
;
187 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
188 res_type
= res_spec
->resources
[i
].type
;
189 res_cnt
= res_spec
->resources
[i
].cnt
;
190 offset
+= scnprintf(buf
+ offset
, buf_sz
- offset
,
192 usnic_vnic_res_type_to_str(res_type
),
199 int usnic_vnic_check_room(struct usnic_vnic
*vnic
,
200 struct usnic_vnic_res_spec
*res_spec
)
203 enum usnic_vnic_res_type res_type
;
206 for (i
= 0; i
< USNIC_VNIC_RES_TYPE_MAX
; i
++) {
207 res_type
= res_spec
->resources
[i
].type
;
208 res_cnt
= res_spec
->resources
[i
].cnt
;
210 if (res_type
== USNIC_VNIC_RES_TYPE_EOL
)
213 if (res_cnt
> usnic_vnic_res_free_cnt(vnic
, res_type
))
220 int usnic_vnic_res_cnt(struct usnic_vnic
*vnic
,
221 enum usnic_vnic_res_type type
)
223 return vnic
->chunks
[type
].cnt
;
226 int usnic_vnic_res_free_cnt(struct usnic_vnic
*vnic
,
227 enum usnic_vnic_res_type type
)
229 return vnic
->chunks
[type
].free_cnt
;
232 struct usnic_vnic_res_chunk
*
233 usnic_vnic_get_resources(struct usnic_vnic
*vnic
, enum usnic_vnic_res_type type
,
234 int cnt
, void *owner
)
236 struct usnic_vnic_res_chunk
*src
, *ret
;
237 struct usnic_vnic_res
*res
;
240 if (usnic_vnic_res_free_cnt(vnic
, type
) < cnt
|| cnt
< 0 || !owner
)
241 return ERR_PTR(-EINVAL
);
243 ret
= kzalloc(sizeof(*ret
), GFP_ATOMIC
);
245 usnic_err("Failed to allocate chunk for %s - Out of memory\n",
246 usnic_vnic_pci_name(vnic
));
247 return ERR_PTR(-ENOMEM
);
251 ret
->res
= kcalloc(cnt
, sizeof(*(ret
->res
)), GFP_ATOMIC
);
253 usnic_err("Failed to allocate resources for %s. Out of memory\n",
254 usnic_vnic_pci_name(vnic
));
256 return ERR_PTR(-ENOMEM
);
259 spin_lock(&vnic
->res_lock
);
260 src
= &vnic
->chunks
[type
];
261 for (i
= 0; i
< src
->cnt
&& ret
->cnt
< cnt
; i
++) {
266 ret
->res
[ret
->cnt
++] = res
;
270 spin_unlock(&vnic
->res_lock
);
274 WARN_ON(ret
->cnt
!= cnt
);
279 void usnic_vnic_put_resources(struct usnic_vnic_res_chunk
*chunk
)
282 struct usnic_vnic_res
*res
;
284 struct usnic_vnic
*vnic
= chunk
->vnic
;
286 if (chunk
->cnt
> 0) {
287 spin_lock(&vnic
->res_lock
);
288 while ((i
= --chunk
->cnt
) >= 0) {
290 chunk
->res
[i
] = NULL
;
292 vnic
->chunks
[res
->type
].free_cnt
++;
294 spin_unlock(&vnic
->res_lock
);
301 u16
usnic_vnic_get_index(struct usnic_vnic
*vnic
)
303 return usnic_vnic_get_pdev(vnic
)->devfn
- 1;
306 static int usnic_vnic_alloc_res_chunk(struct usnic_vnic
*vnic
,
307 enum usnic_vnic_res_type type
,
308 struct usnic_vnic_res_chunk
*chunk
)
311 struct usnic_vnic_res
*res
;
313 cnt
= vnic_dev_get_res_count(vnic
->vdev
, _to_vnic_res_type(type
));
317 chunk
->cnt
= chunk
->free_cnt
= cnt
;
318 chunk
->res
= kzalloc(sizeof(*(chunk
->res
))*cnt
, GFP_KERNEL
);
322 for (i
= 0; i
< cnt
; i
++) {
323 res
= kzalloc(sizeof(*res
), GFP_KERNEL
);
331 res
->ctrl
= vnic_dev_get_res(vnic
->vdev
,
332 _to_vnic_res_type(type
), i
);
339 for (i
--; i
>= 0; i
--)
340 kfree(chunk
->res
[i
]);
345 static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk
*chunk
)
348 for (i
= 0; i
< chunk
->cnt
; i
++)
349 kfree(chunk
->res
[i
]);
353 static int usnic_vnic_discover_resources(struct pci_dev
*pdev
,
354 struct usnic_vnic
*vnic
)
356 enum usnic_vnic_res_type res_type
;
360 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
361 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
363 vnic
->bar
[i
].len
= pci_resource_len(pdev
, i
);
364 vnic
->bar
[i
].vaddr
= pci_iomap(pdev
, i
, vnic
->bar
[i
].len
);
365 if (!vnic
->bar
[i
].vaddr
) {
366 usnic_err("Cannot memory-map BAR %d, aborting\n",
371 vnic
->bar
[i
].bus_addr
= pci_resource_start(pdev
, i
);
374 vnic
->vdev
= vnic_dev_register(NULL
, pdev
, pdev
, vnic
->bar
,
375 ARRAY_SIZE(vnic
->bar
));
377 usnic_err("Failed to register device %s\n",
383 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
384 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++) {
385 err
= usnic_vnic_alloc_res_chunk(vnic
, res_type
,
386 &vnic
->chunks
[res_type
]);
388 usnic_err("Failed to alloc res %s with err %d\n",
389 usnic_vnic_res_type_to_str(res_type
),
391 goto out_clean_chunks
;
398 for (res_type
--; res_type
> USNIC_VNIC_RES_TYPE_EOL
; res_type
--)
399 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
400 vnic_dev_unregister(vnic
->vdev
);
402 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
403 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
405 if (!vnic
->bar
[i
].vaddr
)
408 iounmap(vnic
->bar
[i
].vaddr
);
414 struct pci_dev
*usnic_vnic_get_pdev(struct usnic_vnic
*vnic
)
416 return vnic_dev_get_pdev(vnic
->vdev
);
419 struct vnic_dev_bar
*usnic_vnic_get_bar(struct usnic_vnic
*vnic
,
422 return (bar_num
< ARRAY_SIZE(vnic
->bar
)) ? &vnic
->bar
[bar_num
] : NULL
;
425 static void usnic_vnic_release_resources(struct usnic_vnic
*vnic
)
428 struct pci_dev
*pdev
;
429 enum usnic_vnic_res_type res_type
;
431 pdev
= usnic_vnic_get_pdev(vnic
);
433 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
434 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++)
435 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
437 vnic_dev_unregister(vnic
->vdev
);
439 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
440 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
442 iounmap(vnic
->bar
[i
].vaddr
);
446 struct usnic_vnic
*usnic_vnic_alloc(struct pci_dev
*pdev
)
448 struct usnic_vnic
*vnic
;
451 if (!pci_is_enabled(pdev
)) {
452 usnic_err("PCI dev %s is disabled\n", pci_name(pdev
));
453 return ERR_PTR(-EINVAL
);
456 vnic
= kzalloc(sizeof(*vnic
), GFP_KERNEL
);
458 usnic_err("Failed to alloc vnic for %s - out of memory\n",
460 return ERR_PTR(-ENOMEM
);
463 spin_lock_init(&vnic
->res_lock
);
465 err
= usnic_vnic_discover_resources(pdev
, vnic
);
467 usnic_err("Failed to discover %s resources with err %d\n",
468 pci_name(pdev
), err
);
472 usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic
));
482 void usnic_vnic_free(struct usnic_vnic
*vnic
)
484 usnic_vnic_release_resources(vnic
);