cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

usnic_vnic.c (11736B)


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