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 return ERR_PTR(-ENOMEM
);
248 ret
->res
= kcalloc(cnt
, sizeof(*(ret
->res
)), GFP_ATOMIC
);
251 return ERR_PTR(-ENOMEM
);
254 spin_lock(&vnic
->res_lock
);
255 src
= &vnic
->chunks
[type
];
256 for (i
= 0; i
< src
->cnt
&& ret
->cnt
< cnt
; i
++) {
261 ret
->res
[ret
->cnt
++] = res
;
265 spin_unlock(&vnic
->res_lock
);
269 WARN_ON(ret
->cnt
!= cnt
);
274 void usnic_vnic_put_resources(struct usnic_vnic_res_chunk
*chunk
)
277 struct usnic_vnic_res
*res
;
279 struct usnic_vnic
*vnic
= chunk
->vnic
;
281 if (chunk
->cnt
> 0) {
282 spin_lock(&vnic
->res_lock
);
283 while ((i
= --chunk
->cnt
) >= 0) {
285 chunk
->res
[i
] = NULL
;
287 vnic
->chunks
[res
->type
].free_cnt
++;
289 spin_unlock(&vnic
->res_lock
);
296 u16
usnic_vnic_get_index(struct usnic_vnic
*vnic
)
298 return usnic_vnic_get_pdev(vnic
)->devfn
- 1;
301 static int usnic_vnic_alloc_res_chunk(struct usnic_vnic
*vnic
,
302 enum usnic_vnic_res_type type
,
303 struct usnic_vnic_res_chunk
*chunk
)
306 struct usnic_vnic_res
*res
;
308 cnt
= vnic_dev_get_res_count(vnic
->vdev
, _to_vnic_res_type(type
));
310 usnic_err("Wrong res count with cnt %d\n", cnt
);
314 chunk
->cnt
= chunk
->free_cnt
= cnt
;
315 chunk
->res
= kcalloc(cnt
, sizeof(*(chunk
->res
)), GFP_KERNEL
);
319 for (i
= 0; i
< cnt
; i
++) {
320 res
= kzalloc(sizeof(*res
), GFP_KERNEL
);
328 res
->ctrl
= vnic_dev_get_res(vnic
->vdev
,
329 _to_vnic_res_type(type
), i
);
336 for (i
--; i
>= 0; i
--)
337 kfree(chunk
->res
[i
]);
342 static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk
*chunk
)
345 for (i
= 0; i
< chunk
->cnt
; i
++)
346 kfree(chunk
->res
[i
]);
350 static int usnic_vnic_discover_resources(struct pci_dev
*pdev
,
351 struct usnic_vnic
*vnic
)
353 enum usnic_vnic_res_type res_type
;
357 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
358 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
360 vnic
->bar
[i
].len
= pci_resource_len(pdev
, i
);
361 vnic
->bar
[i
].vaddr
= pci_iomap(pdev
, i
, vnic
->bar
[i
].len
);
362 if (!vnic
->bar
[i
].vaddr
) {
363 usnic_err("Cannot memory-map BAR %d, aborting\n",
368 vnic
->bar
[i
].bus_addr
= pci_resource_start(pdev
, i
);
371 vnic
->vdev
= vnic_dev_register(NULL
, pdev
, pdev
, vnic
->bar
,
372 ARRAY_SIZE(vnic
->bar
));
374 usnic_err("Failed to register device %s\n",
380 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
381 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++) {
382 err
= usnic_vnic_alloc_res_chunk(vnic
, res_type
,
383 &vnic
->chunks
[res_type
]);
385 goto out_clean_chunks
;
391 for (res_type
--; res_type
> USNIC_VNIC_RES_TYPE_EOL
; res_type
--)
392 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
393 vnic_dev_unregister(vnic
->vdev
);
395 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
396 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
398 if (!vnic
->bar
[i
].vaddr
)
401 iounmap(vnic
->bar
[i
].vaddr
);
407 struct pci_dev
*usnic_vnic_get_pdev(struct usnic_vnic
*vnic
)
409 return vnic_dev_get_pdev(vnic
->vdev
);
412 struct vnic_dev_bar
*usnic_vnic_get_bar(struct usnic_vnic
*vnic
,
415 return (bar_num
< ARRAY_SIZE(vnic
->bar
)) ? &vnic
->bar
[bar_num
] : NULL
;
418 static void usnic_vnic_release_resources(struct usnic_vnic
*vnic
)
421 struct pci_dev
*pdev
;
422 enum usnic_vnic_res_type res_type
;
424 pdev
= usnic_vnic_get_pdev(vnic
);
426 for (res_type
= USNIC_VNIC_RES_TYPE_EOL
+ 1;
427 res_type
< USNIC_VNIC_RES_TYPE_MAX
; res_type
++)
428 usnic_vnic_free_res_chunk(&vnic
->chunks
[res_type
]);
430 vnic_dev_unregister(vnic
->vdev
);
432 for (i
= 0; i
< ARRAY_SIZE(vnic
->bar
); i
++) {
433 if (!(pci_resource_flags(pdev
, i
) & IORESOURCE_MEM
))
435 iounmap(vnic
->bar
[i
].vaddr
);
439 struct usnic_vnic
*usnic_vnic_alloc(struct pci_dev
*pdev
)
441 struct usnic_vnic
*vnic
;
444 if (!pci_is_enabled(pdev
)) {
445 usnic_err("PCI dev %s is disabled\n", pci_name(pdev
));
446 return ERR_PTR(-EINVAL
);
449 vnic
= kzalloc(sizeof(*vnic
), GFP_KERNEL
);
451 return ERR_PTR(-ENOMEM
);
453 spin_lock_init(&vnic
->res_lock
);
455 err
= usnic_vnic_discover_resources(pdev
, vnic
);
457 usnic_err("Failed to discover %s resources with err %d\n",
458 pci_name(pdev
), err
);
462 usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic
));
472 void usnic_vnic_free(struct usnic_vnic
*vnic
)
474 usnic_vnic_release_resources(vnic
);