1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This software is available to you under a choice of one of two
5*4882a593Smuzhiyun * licenses. You may choose to be licensed under the terms of the GNU
6*4882a593Smuzhiyun * General Public License (GPL) Version 2, available from the file
7*4882a593Smuzhiyun * COPYING in the main directory of this source tree, or the
8*4882a593Smuzhiyun * BSD license below:
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or
11*4882a593Smuzhiyun * without modification, are permitted provided that the following
12*4882a593Smuzhiyun * conditions are met:
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * - Redistributions of source code must retain the above
15*4882a593Smuzhiyun * copyright notice, this list of conditions and the following
16*4882a593Smuzhiyun * disclaimer.
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * - Redistributions in binary form must reproduce the above
19*4882a593Smuzhiyun * copyright notice, this list of conditions and the following
20*4882a593Smuzhiyun * disclaimer in the documentation and/or other materials
21*4882a593Smuzhiyun * provided with the distribution.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27*4882a593Smuzhiyun * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28*4882a593Smuzhiyun * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29*4882a593Smuzhiyun * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30*4882a593Smuzhiyun * SOFTWARE.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun */
33*4882a593Smuzhiyun #include <linux/errno.h>
34*4882a593Smuzhiyun #include <linux/module.h>
35*4882a593Smuzhiyun #include <linux/pci.h>
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include "usnic_ib.h"
38*4882a593Smuzhiyun #include "vnic_resource.h"
39*4882a593Smuzhiyun #include "usnic_log.h"
40*4882a593Smuzhiyun #include "usnic_vnic.h"
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct usnic_vnic {
43*4882a593Smuzhiyun struct vnic_dev *vdev;
44*4882a593Smuzhiyun struct vnic_dev_bar bar[PCI_NUM_RESOURCES];
45*4882a593Smuzhiyun struct usnic_vnic_res_chunk chunks[USNIC_VNIC_RES_TYPE_MAX];
46*4882a593Smuzhiyun spinlock_t res_lock;
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
_to_vnic_res_type(enum usnic_vnic_res_type res_type)49*4882a593Smuzhiyun static enum vnic_res_type _to_vnic_res_type(enum usnic_vnic_res_type res_type)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
52*4882a593Smuzhiyun vnic_res_type,
53*4882a593Smuzhiyun #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
54*4882a593Smuzhiyun vnic_res_type,
55*4882a593Smuzhiyun static enum vnic_res_type usnic_vnic_type_2_vnic_type[] = {
56*4882a593Smuzhiyun USNIC_VNIC_RES_TYPES};
57*4882a593Smuzhiyun #undef DEFINE_USNIC_VNIC_RES
58*4882a593Smuzhiyun #undef DEFINE_USNIC_VNIC_RES_AT
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun if (res_type >= USNIC_VNIC_RES_TYPE_MAX)
61*4882a593Smuzhiyun return RES_TYPE_MAX;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun return usnic_vnic_type_2_vnic_type[res_type];
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type)66*4882a593Smuzhiyun const char *usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
69*4882a593Smuzhiyun desc,
70*4882a593Smuzhiyun #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
71*4882a593Smuzhiyun desc,
72*4882a593Smuzhiyun static const char * const usnic_vnic_res_type_desc[] = {
73*4882a593Smuzhiyun USNIC_VNIC_RES_TYPES};
74*4882a593Smuzhiyun #undef DEFINE_USNIC_VNIC_RES
75*4882a593Smuzhiyun #undef DEFINE_USNIC_VNIC_RES_AT
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (res_type >= USNIC_VNIC_RES_TYPE_MAX)
78*4882a593Smuzhiyun return "unknown";
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun return usnic_vnic_res_type_desc[res_type];
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
usnic_vnic_pci_name(struct usnic_vnic * vnic)84*4882a593Smuzhiyun const char *usnic_vnic_pci_name(struct usnic_vnic *vnic)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun return pci_name(usnic_vnic_get_pdev(vnic));
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
usnic_vnic_dump(struct usnic_vnic * vnic,char * buf,int buf_sz,void * hdr_obj,int (* printtitle)(void *,char *,int),int (* printcols)(char *,int),int (* printrow)(void *,char *,int))89*4882a593Smuzhiyun int usnic_vnic_dump(struct usnic_vnic *vnic, char *buf,
90*4882a593Smuzhiyun int buf_sz,
91*4882a593Smuzhiyun void *hdr_obj,
92*4882a593Smuzhiyun int (*printtitle)(void *, char*, int),
93*4882a593Smuzhiyun int (*printcols)(char *, int),
94*4882a593Smuzhiyun int (*printrow)(void *, char *, int))
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun struct usnic_vnic_res_chunk *chunk;
97*4882a593Smuzhiyun struct usnic_vnic_res *res;
98*4882a593Smuzhiyun struct vnic_dev_bar *bar0;
99*4882a593Smuzhiyun int i, j, offset;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun offset = 0;
102*4882a593Smuzhiyun bar0 = usnic_vnic_get_bar(vnic, 0);
103*4882a593Smuzhiyun offset += scnprintf(buf + offset, buf_sz - offset,
104*4882a593Smuzhiyun "VF:%hu BAR0 bus_addr=%pa vaddr=0x%p size=%ld ",
105*4882a593Smuzhiyun usnic_vnic_get_index(vnic),
106*4882a593Smuzhiyun &bar0->bus_addr,
107*4882a593Smuzhiyun bar0->vaddr, bar0->len);
108*4882a593Smuzhiyun if (printtitle)
109*4882a593Smuzhiyun offset += printtitle(hdr_obj, buf + offset, buf_sz - offset);
110*4882a593Smuzhiyun offset += scnprintf(buf + offset, buf_sz - offset, "\n");
111*4882a593Smuzhiyun offset += scnprintf(buf + offset, buf_sz - offset,
112*4882a593Smuzhiyun "|RES\t|CTRL_PIN\t\t|IN_USE\t");
113*4882a593Smuzhiyun if (printcols)
114*4882a593Smuzhiyun offset += printcols(buf + offset, buf_sz - offset);
115*4882a593Smuzhiyun offset += scnprintf(buf + offset, buf_sz - offset, "\n");
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun spin_lock(&vnic->res_lock);
118*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vnic->chunks); i++) {
119*4882a593Smuzhiyun chunk = &vnic->chunks[i];
120*4882a593Smuzhiyun for (j = 0; j < chunk->cnt; j++) {
121*4882a593Smuzhiyun res = chunk->res[j];
122*4882a593Smuzhiyun offset += scnprintf(buf + offset, buf_sz - offset,
123*4882a593Smuzhiyun "|%s[%u]\t|0x%p\t|%u\t",
124*4882a593Smuzhiyun usnic_vnic_res_type_to_str(res->type),
125*4882a593Smuzhiyun res->vnic_idx, res->ctrl, !!res->owner);
126*4882a593Smuzhiyun if (printrow) {
127*4882a593Smuzhiyun offset += printrow(res->owner, buf + offset,
128*4882a593Smuzhiyun buf_sz - offset);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun offset += scnprintf(buf + offset, buf_sz - offset,
131*4882a593Smuzhiyun "\n");
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun spin_unlock(&vnic->res_lock);
135*4882a593Smuzhiyun return offset;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
usnic_vnic_res_spec_update(struct usnic_vnic_res_spec * spec,enum usnic_vnic_res_type trgt_type,u16 cnt)138*4882a593Smuzhiyun void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec *spec,
139*4882a593Smuzhiyun enum usnic_vnic_res_type trgt_type,
140*4882a593Smuzhiyun u16 cnt)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun int i;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
145*4882a593Smuzhiyun if (spec->resources[i].type == trgt_type) {
146*4882a593Smuzhiyun spec->resources[i].cnt = cnt;
147*4882a593Smuzhiyun return;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun WARN_ON(1);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec * min_spec,struct usnic_vnic_res_spec * res_spec)154*4882a593Smuzhiyun int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec *min_spec,
155*4882a593Smuzhiyun struct usnic_vnic_res_spec *res_spec)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun int found, i, j;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
160*4882a593Smuzhiyun found = 0;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun for (j = 0; j < USNIC_VNIC_RES_TYPE_MAX; j++) {
163*4882a593Smuzhiyun if (res_spec->resources[i].type !=
164*4882a593Smuzhiyun min_spec->resources[i].type)
165*4882a593Smuzhiyun continue;
166*4882a593Smuzhiyun found = 1;
167*4882a593Smuzhiyun if (min_spec->resources[i].cnt >
168*4882a593Smuzhiyun res_spec->resources[i].cnt)
169*4882a593Smuzhiyun return -EINVAL;
170*4882a593Smuzhiyun break;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun if (!found)
174*4882a593Smuzhiyun return -EINVAL;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun return 0;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
usnic_vnic_spec_dump(char * buf,int buf_sz,struct usnic_vnic_res_spec * res_spec)179*4882a593Smuzhiyun int usnic_vnic_spec_dump(char *buf, int buf_sz,
180*4882a593Smuzhiyun struct usnic_vnic_res_spec *res_spec)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun enum usnic_vnic_res_type res_type;
183*4882a593Smuzhiyun int res_cnt;
184*4882a593Smuzhiyun int i;
185*4882a593Smuzhiyun int offset = 0;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
188*4882a593Smuzhiyun res_type = res_spec->resources[i].type;
189*4882a593Smuzhiyun res_cnt = res_spec->resources[i].cnt;
190*4882a593Smuzhiyun offset += scnprintf(buf + offset, buf_sz - offset,
191*4882a593Smuzhiyun "Res: %s Cnt: %d ",
192*4882a593Smuzhiyun usnic_vnic_res_type_to_str(res_type),
193*4882a593Smuzhiyun res_cnt);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun return offset;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
usnic_vnic_check_room(struct usnic_vnic * vnic,struct usnic_vnic_res_spec * res_spec)199*4882a593Smuzhiyun int usnic_vnic_check_room(struct usnic_vnic *vnic,
200*4882a593Smuzhiyun struct usnic_vnic_res_spec *res_spec)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun int i;
203*4882a593Smuzhiyun enum usnic_vnic_res_type res_type;
204*4882a593Smuzhiyun int res_cnt;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
207*4882a593Smuzhiyun res_type = res_spec->resources[i].type;
208*4882a593Smuzhiyun res_cnt = res_spec->resources[i].cnt;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (res_type == USNIC_VNIC_RES_TYPE_EOL)
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (res_cnt > usnic_vnic_res_free_cnt(vnic, res_type))
214*4882a593Smuzhiyun return -EBUSY;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
usnic_vnic_res_cnt(struct usnic_vnic * vnic,enum usnic_vnic_res_type type)220*4882a593Smuzhiyun int usnic_vnic_res_cnt(struct usnic_vnic *vnic,
221*4882a593Smuzhiyun enum usnic_vnic_res_type type)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun return vnic->chunks[type].cnt;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
usnic_vnic_res_free_cnt(struct usnic_vnic * vnic,enum usnic_vnic_res_type type)226*4882a593Smuzhiyun int usnic_vnic_res_free_cnt(struct usnic_vnic *vnic,
227*4882a593Smuzhiyun enum usnic_vnic_res_type type)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun return vnic->chunks[type].free_cnt;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun struct usnic_vnic_res_chunk *
usnic_vnic_get_resources(struct usnic_vnic * vnic,enum usnic_vnic_res_type type,int cnt,void * owner)233*4882a593Smuzhiyun usnic_vnic_get_resources(struct usnic_vnic *vnic, enum usnic_vnic_res_type type,
234*4882a593Smuzhiyun int cnt, void *owner)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct usnic_vnic_res_chunk *src, *ret;
237*4882a593Smuzhiyun struct usnic_vnic_res *res;
238*4882a593Smuzhiyun int i;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun if (usnic_vnic_res_free_cnt(vnic, type) < cnt || cnt < 0 || !owner)
241*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun ret = kzalloc(sizeof(*ret), GFP_ATOMIC);
244*4882a593Smuzhiyun if (!ret)
245*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun if (cnt > 0) {
248*4882a593Smuzhiyun ret->res = kcalloc(cnt, sizeof(*(ret->res)), GFP_ATOMIC);
249*4882a593Smuzhiyun if (!ret->res) {
250*4882a593Smuzhiyun kfree(ret);
251*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun spin_lock(&vnic->res_lock);
255*4882a593Smuzhiyun src = &vnic->chunks[type];
256*4882a593Smuzhiyun for (i = 0; i < src->cnt && ret->cnt < cnt; i++) {
257*4882a593Smuzhiyun res = src->res[i];
258*4882a593Smuzhiyun if (!res->owner) {
259*4882a593Smuzhiyun src->free_cnt--;
260*4882a593Smuzhiyun res->owner = owner;
261*4882a593Smuzhiyun ret->res[ret->cnt++] = res;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun spin_unlock(&vnic->res_lock);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun ret->type = type;
268*4882a593Smuzhiyun ret->vnic = vnic;
269*4882a593Smuzhiyun WARN_ON(ret->cnt != cnt);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun return ret;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
usnic_vnic_put_resources(struct usnic_vnic_res_chunk * chunk)274*4882a593Smuzhiyun void usnic_vnic_put_resources(struct usnic_vnic_res_chunk *chunk)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun struct usnic_vnic_res *res;
278*4882a593Smuzhiyun int i;
279*4882a593Smuzhiyun struct usnic_vnic *vnic = chunk->vnic;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (chunk->cnt > 0) {
282*4882a593Smuzhiyun spin_lock(&vnic->res_lock);
283*4882a593Smuzhiyun while ((i = --chunk->cnt) >= 0) {
284*4882a593Smuzhiyun res = chunk->res[i];
285*4882a593Smuzhiyun chunk->res[i] = NULL;
286*4882a593Smuzhiyun res->owner = NULL;
287*4882a593Smuzhiyun vnic->chunks[res->type].free_cnt++;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun spin_unlock(&vnic->res_lock);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun kfree(chunk->res);
293*4882a593Smuzhiyun kfree(chunk);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
usnic_vnic_get_index(struct usnic_vnic * vnic)296*4882a593Smuzhiyun u16 usnic_vnic_get_index(struct usnic_vnic *vnic)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun return usnic_vnic_get_pdev(vnic)->devfn - 1;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
usnic_vnic_alloc_res_chunk(struct usnic_vnic * vnic,enum usnic_vnic_res_type type,struct usnic_vnic_res_chunk * chunk)301*4882a593Smuzhiyun static int usnic_vnic_alloc_res_chunk(struct usnic_vnic *vnic,
302*4882a593Smuzhiyun enum usnic_vnic_res_type type,
303*4882a593Smuzhiyun struct usnic_vnic_res_chunk *chunk)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun int cnt, err, i;
306*4882a593Smuzhiyun struct usnic_vnic_res *res;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun cnt = vnic_dev_get_res_count(vnic->vdev, _to_vnic_res_type(type));
309*4882a593Smuzhiyun if (cnt < 1) {
310*4882a593Smuzhiyun usnic_err("Wrong res count with cnt %d\n", cnt);
311*4882a593Smuzhiyun return -EINVAL;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun chunk->cnt = chunk->free_cnt = cnt;
315*4882a593Smuzhiyun chunk->res = kcalloc(cnt, sizeof(*(chunk->res)), GFP_KERNEL);
316*4882a593Smuzhiyun if (!chunk->res)
317*4882a593Smuzhiyun return -ENOMEM;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun for (i = 0; i < cnt; i++) {
320*4882a593Smuzhiyun res = kzalloc(sizeof(*res), GFP_KERNEL);
321*4882a593Smuzhiyun if (!res) {
322*4882a593Smuzhiyun err = -ENOMEM;
323*4882a593Smuzhiyun goto fail;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun res->type = type;
326*4882a593Smuzhiyun res->vnic_idx = i;
327*4882a593Smuzhiyun res->vnic = vnic;
328*4882a593Smuzhiyun res->ctrl = vnic_dev_get_res(vnic->vdev,
329*4882a593Smuzhiyun _to_vnic_res_type(type), i);
330*4882a593Smuzhiyun chunk->res[i] = res;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun chunk->vnic = vnic;
334*4882a593Smuzhiyun return 0;
335*4882a593Smuzhiyun fail:
336*4882a593Smuzhiyun for (i--; i >= 0; i--)
337*4882a593Smuzhiyun kfree(chunk->res[i]);
338*4882a593Smuzhiyun kfree(chunk->res);
339*4882a593Smuzhiyun return err;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk * chunk)342*4882a593Smuzhiyun static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk *chunk)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun int i;
345*4882a593Smuzhiyun for (i = 0; i < chunk->cnt; i++)
346*4882a593Smuzhiyun kfree(chunk->res[i]);
347*4882a593Smuzhiyun kfree(chunk->res);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
usnic_vnic_discover_resources(struct pci_dev * pdev,struct usnic_vnic * vnic)350*4882a593Smuzhiyun static int usnic_vnic_discover_resources(struct pci_dev *pdev,
351*4882a593Smuzhiyun struct usnic_vnic *vnic)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun enum usnic_vnic_res_type res_type;
354*4882a593Smuzhiyun int i;
355*4882a593Smuzhiyun int err = 0;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
358*4882a593Smuzhiyun if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
359*4882a593Smuzhiyun continue;
360*4882a593Smuzhiyun vnic->bar[i].len = pci_resource_len(pdev, i);
361*4882a593Smuzhiyun vnic->bar[i].vaddr = pci_iomap(pdev, i, vnic->bar[i].len);
362*4882a593Smuzhiyun if (!vnic->bar[i].vaddr) {
363*4882a593Smuzhiyun usnic_err("Cannot memory-map BAR %d, aborting\n",
364*4882a593Smuzhiyun i);
365*4882a593Smuzhiyun err = -ENODEV;
366*4882a593Smuzhiyun goto out_clean_bar;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun vnic->bar[i].bus_addr = pci_resource_start(pdev, i);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun vnic->vdev = vnic_dev_register(NULL, pdev, pdev, vnic->bar,
372*4882a593Smuzhiyun ARRAY_SIZE(vnic->bar));
373*4882a593Smuzhiyun if (!vnic->vdev) {
374*4882a593Smuzhiyun usnic_err("Failed to register device %s\n",
375*4882a593Smuzhiyun pci_name(pdev));
376*4882a593Smuzhiyun err = -EINVAL;
377*4882a593Smuzhiyun goto out_clean_bar;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1;
381*4882a593Smuzhiyun res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) {
382*4882a593Smuzhiyun err = usnic_vnic_alloc_res_chunk(vnic, res_type,
383*4882a593Smuzhiyun &vnic->chunks[res_type]);
384*4882a593Smuzhiyun if (err)
385*4882a593Smuzhiyun goto out_clean_chunks;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun return 0;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun out_clean_chunks:
391*4882a593Smuzhiyun for (res_type--; res_type > USNIC_VNIC_RES_TYPE_EOL; res_type--)
392*4882a593Smuzhiyun usnic_vnic_free_res_chunk(&vnic->chunks[res_type]);
393*4882a593Smuzhiyun vnic_dev_unregister(vnic->vdev);
394*4882a593Smuzhiyun out_clean_bar:
395*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
396*4882a593Smuzhiyun if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
397*4882a593Smuzhiyun continue;
398*4882a593Smuzhiyun if (!vnic->bar[i].vaddr)
399*4882a593Smuzhiyun break;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun iounmap(vnic->bar[i].vaddr);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun return err;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
usnic_vnic_get_pdev(struct usnic_vnic * vnic)407*4882a593Smuzhiyun struct pci_dev *usnic_vnic_get_pdev(struct usnic_vnic *vnic)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun return vnic_dev_get_pdev(vnic->vdev);
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
usnic_vnic_get_bar(struct usnic_vnic * vnic,int bar_num)412*4882a593Smuzhiyun struct vnic_dev_bar *usnic_vnic_get_bar(struct usnic_vnic *vnic,
413*4882a593Smuzhiyun int bar_num)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun return (bar_num < ARRAY_SIZE(vnic->bar)) ? &vnic->bar[bar_num] : NULL;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
usnic_vnic_release_resources(struct usnic_vnic * vnic)418*4882a593Smuzhiyun static void usnic_vnic_release_resources(struct usnic_vnic *vnic)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun int i;
421*4882a593Smuzhiyun struct pci_dev *pdev;
422*4882a593Smuzhiyun enum usnic_vnic_res_type res_type;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun pdev = usnic_vnic_get_pdev(vnic);
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1;
427*4882a593Smuzhiyun res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++)
428*4882a593Smuzhiyun usnic_vnic_free_res_chunk(&vnic->chunks[res_type]);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun vnic_dev_unregister(vnic->vdev);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
433*4882a593Smuzhiyun if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
434*4882a593Smuzhiyun continue;
435*4882a593Smuzhiyun iounmap(vnic->bar[i].vaddr);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun
usnic_vnic_alloc(struct pci_dev * pdev)439*4882a593Smuzhiyun struct usnic_vnic *usnic_vnic_alloc(struct pci_dev *pdev)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun struct usnic_vnic *vnic;
442*4882a593Smuzhiyun int err = 0;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (!pci_is_enabled(pdev)) {
445*4882a593Smuzhiyun usnic_err("PCI dev %s is disabled\n", pci_name(pdev));
446*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun vnic = kzalloc(sizeof(*vnic), GFP_KERNEL);
450*4882a593Smuzhiyun if (!vnic)
451*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun spin_lock_init(&vnic->res_lock);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun err = usnic_vnic_discover_resources(pdev, vnic);
456*4882a593Smuzhiyun if (err) {
457*4882a593Smuzhiyun usnic_err("Failed to discover %s resources with err %d\n",
458*4882a593Smuzhiyun pci_name(pdev), err);
459*4882a593Smuzhiyun goto out_free_vnic;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic));
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun return vnic;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun out_free_vnic:
467*4882a593Smuzhiyun kfree(vnic);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun return ERR_PTR(err);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
usnic_vnic_free(struct usnic_vnic * vnic)472*4882a593Smuzhiyun void usnic_vnic_free(struct usnic_vnic *vnic)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun usnic_vnic_release_resources(vnic);
475*4882a593Smuzhiyun kfree(vnic);
476*4882a593Smuzhiyun }
477