xref: /OK3568_Linux_fs/kernel/drivers/infiniband/hw/usnic/usnic_vnic.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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