1/*
2 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3 *
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
8 * BSD license below:
9 *
10 *     Redistribution and use in source and binary forms, with or
11 *     without modification, are permitted provided that the following
12 *     conditions are met:
13 *
14 *      - Redistributions of source code must retain the above
15 *        copyright notice, this list of conditions and the following
16 *        disclaimer.
17 *
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.
22 *
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
30 * SOFTWARE.
31 *
32 */
33#include <linux/errno.h>
34#include <linux/module.h>
35#include <linux/pci.h>
36
37#include "usnic_ib.h"
38#include "vnic_resource.h"
39#include "usnic_log.h"
40#include "usnic_vnic.h"
41
42struct usnic_vnic {
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];
46	spinlock_t			res_lock;
47};
48
49static enum vnic_res_type _to_vnic_res_type(enum usnic_vnic_res_type res_type)
50{
51#define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
52		vnic_res_type,
53#define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
54		vnic_res_type,
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
59
60	if (res_type >= USNIC_VNIC_RES_TYPE_MAX)
61		return RES_TYPE_MAX;
62
63	return usnic_vnic_type_2_vnic_type[res_type];
64}
65
66const char *usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type)
67{
68#define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \
69		desc,
70#define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \
71		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
76
77	if (res_type >= USNIC_VNIC_RES_TYPE_MAX)
78		return "unknown";
79
80	return usnic_vnic_res_type_desc[res_type];
81
82}
83
84const char *usnic_vnic_pci_name(struct usnic_vnic *vnic)
85{
86	return pci_name(usnic_vnic_get_pdev(vnic));
87}
88
89int usnic_vnic_dump(struct usnic_vnic *vnic, char *buf,
90			int buf_sz,
91			void *hdr_obj,
92			int (*printtitle)(void *, char*, int),
93			int (*printcols)(char *, int),
94			int (*printrow)(void *, char *, int))
95{
96	struct usnic_vnic_res_chunk *chunk;
97	struct usnic_vnic_res *res;
98	struct vnic_dev_bar *bar0;
99	int i, j, offset;
100
101	offset = 0;
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),
106			&bar0->bus_addr,
107			bar0->vaddr, bar0->len);
108	if (printtitle)
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");
113	if (printcols)
114		offset += printcols(buf + offset, buf_sz - offset);
115	offset += scnprintf(buf + offset, buf_sz - offset, "\n");
116
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++) {
121			res = chunk->res[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);
126			if (printrow) {
127				offset += printrow(res->owner, buf + offset,
128							buf_sz - offset);
129			}
130			offset += scnprintf(buf + offset, buf_sz - offset,
131						"\n");
132		}
133	}
134	spin_unlock(&vnic->res_lock);
135	return offset;
136}
137
138void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec *spec,
139				enum usnic_vnic_res_type trgt_type,
140				u16 cnt)
141{
142	int i;
143
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;
147			return;
148		}
149	}
150
151	WARN_ON(1);
152}
153
154int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec *min_spec,
155					struct usnic_vnic_res_spec *res_spec)
156{
157	int found, i, j;
158
159	for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) {
160		found = 0;
161
162		for (j = 0; j < USNIC_VNIC_RES_TYPE_MAX; j++) {
163			if (res_spec->resources[i].type !=
164				min_spec->resources[i].type)
165				continue;
166			found = 1;
167			if (min_spec->resources[i].cnt >
168					res_spec->resources[i].cnt)
169				return -EINVAL;
170			break;
171		}
172
173		if (!found)
174			return -EINVAL;
175	}
176	return 0;
177}
178
179int usnic_vnic_spec_dump(char *buf, int buf_sz,
180				struct usnic_vnic_res_spec *res_spec)
181{
182	enum usnic_vnic_res_type res_type;
183	int res_cnt;
184	int i;
185	int offset = 0;
186
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,
191				"Res: %s Cnt: %d ",
192				usnic_vnic_res_type_to_str(res_type),
193				res_cnt);
194	}
195
196	return offset;
197}
198
199int usnic_vnic_check_room(struct usnic_vnic *vnic,
200				struct usnic_vnic_res_spec *res_spec)
201{
202	int i;
203	enum usnic_vnic_res_type res_type;
204	int res_cnt;
205
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;
209
210		if (res_type == USNIC_VNIC_RES_TYPE_EOL)
211			break;
212
213		if (res_cnt > usnic_vnic_res_free_cnt(vnic, res_type))
214			return -EBUSY;
215	}
216
217	return 0;
218}
219
220int usnic_vnic_res_cnt(struct usnic_vnic *vnic,
221				enum usnic_vnic_res_type type)
222{
223	return vnic->chunks[type].cnt;
224}
225
226int usnic_vnic_res_free_cnt(struct usnic_vnic *vnic,
227				enum usnic_vnic_res_type type)
228{
229	return vnic->chunks[type].free_cnt;
230}
231
232struct usnic_vnic_res_chunk *
233usnic_vnic_get_resources(struct usnic_vnic *vnic, enum usnic_vnic_res_type type,
234				int cnt, void *owner)
235{
236	struct usnic_vnic_res_chunk *src, *ret;
237	struct usnic_vnic_res *res;
238	int i;
239
240	if (usnic_vnic_res_free_cnt(vnic, type) < cnt || cnt < 0 || !owner)
241		return ERR_PTR(-EINVAL);
242
243	ret = kzalloc(sizeof(*ret), GFP_ATOMIC);
244	if (!ret)
245		return ERR_PTR(-ENOMEM);
246
247	if (cnt > 0) {
248		ret->res = kcalloc(cnt, sizeof(*(ret->res)), GFP_ATOMIC);
249		if (!ret->res) {
250			kfree(ret);
251			return ERR_PTR(-ENOMEM);
252		}
253
254		spin_lock(&vnic->res_lock);
255		src = &vnic->chunks[type];
256		for (i = 0; i < src->cnt && ret->cnt < cnt; i++) {
257			res = src->res[i];
258			if (!res->owner) {
259				src->free_cnt--;
260				res->owner = owner;
261				ret->res[ret->cnt++] = res;
262			}
263		}
264
265		spin_unlock(&vnic->res_lock);
266	}
267	ret->type = type;
268	ret->vnic = vnic;
269	WARN_ON(ret->cnt != cnt);
270
271	return ret;
272}
273
274void usnic_vnic_put_resources(struct usnic_vnic_res_chunk *chunk)
275{
276
277	struct usnic_vnic_res *res;
278	int i;
279	struct usnic_vnic *vnic = chunk->vnic;
280
281	if (chunk->cnt > 0) {
282		spin_lock(&vnic->res_lock);
283		while ((i = --chunk->cnt) >= 0) {
284			res = chunk->res[i];
285			chunk->res[i] = NULL;
286			res->owner = NULL;
287			vnic->chunks[res->type].free_cnt++;
288		}
289		spin_unlock(&vnic->res_lock);
290	}
291
292	kfree(chunk->res);
293	kfree(chunk);
294}
295
296u16 usnic_vnic_get_index(struct usnic_vnic *vnic)
297{
298	return usnic_vnic_get_pdev(vnic)->devfn - 1;
299}
300
301static int usnic_vnic_alloc_res_chunk(struct usnic_vnic *vnic,
302					enum usnic_vnic_res_type type,
303					struct usnic_vnic_res_chunk *chunk)
304{
305	int cnt, err, i;
306	struct usnic_vnic_res *res;
307
308	cnt = vnic_dev_get_res_count(vnic->vdev, _to_vnic_res_type(type));
309	if (cnt < 1) {
310		usnic_err("Wrong res count with cnt %d\n", cnt);
311		return -EINVAL;
312	}
313
314	chunk->cnt = chunk->free_cnt = cnt;
315	chunk->res = kcalloc(cnt, sizeof(*(chunk->res)), GFP_KERNEL);
316	if (!chunk->res)
317		return -ENOMEM;
318
319	for (i = 0; i < cnt; i++) {
320		res = kzalloc(sizeof(*res), GFP_KERNEL);
321		if (!res) {
322			err = -ENOMEM;
323			goto fail;
324		}
325		res->type = type;
326		res->vnic_idx = i;
327		res->vnic = vnic;
328		res->ctrl = vnic_dev_get_res(vnic->vdev,
329						_to_vnic_res_type(type), i);
330		chunk->res[i] = res;
331	}
332
333	chunk->vnic = vnic;
334	return 0;
335fail:
336	for (i--; i >= 0; i--)
337		kfree(chunk->res[i]);
338	kfree(chunk->res);
339	return err;
340}
341
342static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk *chunk)
343{
344	int i;
345	for (i = 0; i < chunk->cnt; i++)
346		kfree(chunk->res[i]);
347	kfree(chunk->res);
348}
349
350static int usnic_vnic_discover_resources(struct pci_dev *pdev,
351						struct usnic_vnic *vnic)
352{
353	enum usnic_vnic_res_type res_type;
354	int i;
355	int err = 0;
356
357	for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
358		if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
359			continue;
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",
364					i);
365			err = -ENODEV;
366			goto out_clean_bar;
367		}
368		vnic->bar[i].bus_addr = pci_resource_start(pdev, i);
369	}
370
371	vnic->vdev = vnic_dev_register(NULL, pdev, pdev, vnic->bar,
372			ARRAY_SIZE(vnic->bar));
373	if (!vnic->vdev) {
374		usnic_err("Failed to register device %s\n",
375				pci_name(pdev));
376		err = -EINVAL;
377		goto out_clean_bar;
378	}
379
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]);
384		if (err)
385			goto out_clean_chunks;
386	}
387
388	return 0;
389
390out_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);
394out_clean_bar:
395	for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
396		if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
397			continue;
398		if (!vnic->bar[i].vaddr)
399			break;
400
401		iounmap(vnic->bar[i].vaddr);
402	}
403
404	return err;
405}
406
407struct pci_dev *usnic_vnic_get_pdev(struct usnic_vnic *vnic)
408{
409	return vnic_dev_get_pdev(vnic->vdev);
410}
411
412struct vnic_dev_bar *usnic_vnic_get_bar(struct usnic_vnic *vnic,
413				int bar_num)
414{
415	return (bar_num < ARRAY_SIZE(vnic->bar)) ? &vnic->bar[bar_num] : NULL;
416}
417
418static void usnic_vnic_release_resources(struct usnic_vnic *vnic)
419{
420	int i;
421	struct pci_dev *pdev;
422	enum usnic_vnic_res_type res_type;
423
424	pdev = usnic_vnic_get_pdev(vnic);
425
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]);
429
430	vnic_dev_unregister(vnic->vdev);
431
432	for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) {
433		if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
434			continue;
435		iounmap(vnic->bar[i].vaddr);
436	}
437}
438
439struct usnic_vnic *usnic_vnic_alloc(struct pci_dev *pdev)
440{
441	struct usnic_vnic *vnic;
442	int err = 0;
443
444	if (!pci_is_enabled(pdev)) {
445		usnic_err("PCI dev %s is disabled\n", pci_name(pdev));
446		return ERR_PTR(-EINVAL);
447	}
448
449	vnic = kzalloc(sizeof(*vnic), GFP_KERNEL);
450	if (!vnic)
451		return ERR_PTR(-ENOMEM);
452
453	spin_lock_init(&vnic->res_lock);
454
455	err = usnic_vnic_discover_resources(pdev, vnic);
456	if (err) {
457		usnic_err("Failed to discover %s resources with err %d\n",
458				pci_name(pdev), err);
459		goto out_free_vnic;
460	}
461
462	usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic));
463
464	return vnic;
465
466out_free_vnic:
467	kfree(vnic);
468
469	return ERR_PTR(err);
470}
471
472void usnic_vnic_free(struct usnic_vnic *vnic)
473{
474	usnic_vnic_release_resources(vnic);
475	kfree(vnic);
476}
477