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

nfp_resource.c (8803B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
      2/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
      3
      4/*
      5 * nfp_resource.c
      6 * Author: Jakub Kicinski <jakub.kicinski@netronome.com>
      7 *         Jason McMullan <jason.mcmullan@netronome.com>
      8 */
      9#include <linux/delay.h>
     10#include <linux/kernel.h>
     11#include <linux/slab.h>
     12
     13#include "crc32.h"
     14#include "nfp.h"
     15#include "nfp_cpp.h"
     16#include "nfp6000/nfp6000.h"
     17
     18#define NFP_RESOURCE_TBL_TARGET		NFP_CPP_TARGET_MU
     19#define NFP_RESOURCE_TBL_BASE		0x8100000000ULL
     20
     21/* NFP Resource Table self-identifier */
     22#define NFP_RESOURCE_TBL_NAME		"nfp.res"
     23#define NFP_RESOURCE_TBL_KEY		0x00000000 /* Special key for entry 0 */
     24
     25#define NFP_RESOURCE_ENTRY_NAME_SZ	8
     26
     27/**
     28 * struct nfp_resource_entry - Resource table entry
     29 * @mutex:	NFP CPP Lock
     30 * @mutex.owner:	NFP CPP Lock, interface owner
     31 * @mutex.key:		NFP CPP Lock, posix_crc32(name, 8)
     32 * @region:	Memory region descriptor
     33 * @region.name:	ASCII, zero padded name
     34 * @region.reserved:	padding
     35 * @region.cpp_action:	CPP Action
     36 * @region.cpp_token:	CPP Token
     37 * @region.cpp_target:	CPP Target ID
     38 * @region.page_offset:	256-byte page offset into target's CPP address
     39 * @region.page_size:	size, in 256-byte pages
     40 */
     41struct nfp_resource_entry {
     42	struct nfp_resource_entry_mutex {
     43		u32 owner;
     44		u32 key;
     45	} mutex;
     46	struct nfp_resource_entry_region {
     47		u8  name[NFP_RESOURCE_ENTRY_NAME_SZ];
     48		u8  reserved[5];
     49		u8  cpp_action;
     50		u8  cpp_token;
     51		u8  cpp_target;
     52		u32 page_offset;
     53		u32 page_size;
     54	} region;
     55};
     56
     57#define NFP_RESOURCE_TBL_SIZE		4096
     58#define NFP_RESOURCE_TBL_ENTRIES	(NFP_RESOURCE_TBL_SIZE /	\
     59					 sizeof(struct nfp_resource_entry))
     60
     61struct nfp_resource {
     62	char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
     63	u32 cpp_id;
     64	u64 addr;
     65	u64 size;
     66	struct nfp_cpp_mutex *mutex;
     67};
     68
     69static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
     70{
     71	struct nfp_resource_entry entry;
     72	u32 cpp_id, key;
     73	int ret, i;
     74
     75	cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */
     76
     77	/* Search for a matching entry */
     78	if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) {
     79		nfp_err(cpp, "Grabbing device lock not supported\n");
     80		return -EOPNOTSUPP;
     81	}
     82	key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ);
     83
     84	for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
     85		u64 addr = NFP_RESOURCE_TBL_BASE +
     86			sizeof(struct nfp_resource_entry) * i;
     87
     88		ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
     89		if (ret != sizeof(entry))
     90			return -EIO;
     91
     92		if (entry.mutex.key != key)
     93			continue;
     94
     95		/* Found key! */
     96		res->mutex =
     97			nfp_cpp_mutex_alloc(cpp,
     98					    NFP_RESOURCE_TBL_TARGET, addr, key);
     99		res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
    100					 entry.region.cpp_action,
    101					 entry.region.cpp_token);
    102		res->addr = (u64)entry.region.page_offset << 8;
    103		res->size = (u64)entry.region.page_size << 8;
    104
    105		return 0;
    106	}
    107
    108	return -ENOENT;
    109}
    110
    111static int
    112nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
    113			 struct nfp_cpp_mutex *dev_mutex)
    114{
    115	int err;
    116
    117	if (nfp_cpp_mutex_lock(dev_mutex))
    118		return -EINVAL;
    119
    120	err = nfp_cpp_resource_find(cpp, res);
    121	if (err)
    122		goto err_unlock_dev;
    123
    124	err = nfp_cpp_mutex_trylock(res->mutex);
    125	if (err)
    126		goto err_res_mutex_free;
    127
    128	nfp_cpp_mutex_unlock(dev_mutex);
    129
    130	return 0;
    131
    132err_res_mutex_free:
    133	nfp_cpp_mutex_free(res->mutex);
    134err_unlock_dev:
    135	nfp_cpp_mutex_unlock(dev_mutex);
    136
    137	return err;
    138}
    139
    140/**
    141 * nfp_resource_acquire() - Acquire a resource handle
    142 * @cpp:	NFP CPP handle
    143 * @name:	Name of the resource
    144 *
    145 * NOTE: This function locks the acquired resource
    146 *
    147 * Return: NFP Resource handle, or ERR_PTR()
    148 */
    149struct nfp_resource *
    150nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
    151{
    152	unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
    153	unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ;
    154	struct nfp_cpp_mutex *dev_mutex;
    155	struct nfp_resource *res;
    156	int err;
    157
    158	res = kzalloc(sizeof(*res), GFP_KERNEL);
    159	if (!res)
    160		return ERR_PTR(-ENOMEM);
    161
    162	strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
    163
    164	dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
    165					NFP_RESOURCE_TBL_BASE,
    166					NFP_RESOURCE_TBL_KEY);
    167	if (!dev_mutex) {
    168		kfree(res);
    169		return ERR_PTR(-ENOMEM);
    170	}
    171
    172	for (;;) {
    173		err = nfp_resource_try_acquire(cpp, res, dev_mutex);
    174		if (!err)
    175			break;
    176		if (err != -EBUSY)
    177			goto err_free;
    178
    179		err = msleep_interruptible(1);
    180		if (err != 0) {
    181			err = -ERESTARTSYS;
    182			goto err_free;
    183		}
    184
    185		if (time_is_before_eq_jiffies(warn_at)) {
    186			warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
    187			nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
    188				 name);
    189		}
    190		if (time_is_before_eq_jiffies(err_at)) {
    191			nfp_err(cpp, "Error: resource %s timed out\n", name);
    192			err = -EBUSY;
    193			goto err_free;
    194		}
    195	}
    196
    197	nfp_cpp_mutex_free(dev_mutex);
    198
    199	return res;
    200
    201err_free:
    202	nfp_cpp_mutex_free(dev_mutex);
    203	kfree(res);
    204	return ERR_PTR(err);
    205}
    206
    207/**
    208 * nfp_resource_release() - Release a NFP Resource handle
    209 * @res:	NFP Resource handle
    210 *
    211 * NOTE: This function implictly unlocks the resource handle
    212 */
    213void nfp_resource_release(struct nfp_resource *res)
    214{
    215	nfp_cpp_mutex_unlock(res->mutex);
    216	nfp_cpp_mutex_free(res->mutex);
    217	kfree(res);
    218}
    219
    220/**
    221 * nfp_resource_wait() - Wait for resource to appear
    222 * @cpp:	NFP CPP handle
    223 * @name:	Name of the resource
    224 * @secs:	Number of seconds to wait
    225 *
    226 * Wait for resource to appear in the resource table, grab and release
    227 * its lock.  The wait is jiffies-based, don't expect fine granularity.
    228 *
    229 * Return: 0 on success, errno otherwise.
    230 */
    231int nfp_resource_wait(struct nfp_cpp *cpp, const char *name, unsigned int secs)
    232{
    233	unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
    234	unsigned long err_at = jiffies + secs * HZ;
    235	struct nfp_resource *res;
    236
    237	while (true) {
    238		res = nfp_resource_acquire(cpp, name);
    239		if (!IS_ERR(res)) {
    240			nfp_resource_release(res);
    241			return 0;
    242		}
    243
    244		if (PTR_ERR(res) != -ENOENT) {
    245			nfp_err(cpp, "error waiting for resource %s: %ld\n",
    246				name, PTR_ERR(res));
    247			return PTR_ERR(res);
    248		}
    249		if (time_is_before_eq_jiffies(err_at)) {
    250			nfp_err(cpp, "timeout waiting for resource %s\n", name);
    251			return -ETIMEDOUT;
    252		}
    253		if (time_is_before_eq_jiffies(warn_at)) {
    254			warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
    255			nfp_info(cpp, "waiting for NFP resource %s\n", name);
    256		}
    257		if (msleep_interruptible(10)) {
    258			nfp_err(cpp, "wait for resource %s interrupted\n",
    259				name);
    260			return -ERESTARTSYS;
    261		}
    262	}
    263}
    264
    265/**
    266 * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
    267 * @res:	NFP Resource handle
    268 *
    269 * Return: NFP CPP ID
    270 */
    271u32 nfp_resource_cpp_id(struct nfp_resource *res)
    272{
    273	return res->cpp_id;
    274}
    275
    276/**
    277 * nfp_resource_name() - Return the name of a resource handle
    278 * @res:	NFP Resource handle
    279 *
    280 * Return: const char pointer to the name of the resource
    281 */
    282const char *nfp_resource_name(struct nfp_resource *res)
    283{
    284	return res->name;
    285}
    286
    287/**
    288 * nfp_resource_address() - Return the address of a resource handle
    289 * @res:	NFP Resource handle
    290 *
    291 * Return: Address of the resource
    292 */
    293u64 nfp_resource_address(struct nfp_resource *res)
    294{
    295	return res->addr;
    296}
    297
    298/**
    299 * nfp_resource_size() - Return the size in bytes of a resource handle
    300 * @res:	NFP Resource handle
    301 *
    302 * Return: Size of the resource in bytes
    303 */
    304u64 nfp_resource_size(struct nfp_resource *res)
    305{
    306	return res->size;
    307}
    308
    309/**
    310 * nfp_resource_table_init() - Run initial checks on the resource table
    311 * @cpp:	NFP CPP handle
    312 *
    313 * Start-of-day init procedure for resource table.  Must be called before
    314 * any local resource table users may exist.
    315 *
    316 * Return: 0 on success, -errno on failure
    317 */
    318int nfp_resource_table_init(struct nfp_cpp *cpp)
    319{
    320	struct nfp_cpp_mutex *dev_mutex;
    321	int i, err;
    322
    323	err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET,
    324				    NFP_RESOURCE_TBL_BASE);
    325	if (err < 0) {
    326		nfp_err(cpp, "Error: failed to reclaim resource table mutex\n");
    327		return err;
    328	}
    329	if (err)
    330		nfp_warn(cpp, "Warning: busted main resource table mutex\n");
    331
    332	dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
    333					NFP_RESOURCE_TBL_BASE,
    334					NFP_RESOURCE_TBL_KEY);
    335	if (!dev_mutex)
    336		return -ENOMEM;
    337
    338	if (nfp_cpp_mutex_lock(dev_mutex)) {
    339		nfp_err(cpp, "Error: failed to claim resource table mutex\n");
    340		nfp_cpp_mutex_free(dev_mutex);
    341		return -EINVAL;
    342	}
    343
    344	/* Resource 0 is the dev_mutex, start from 1 */
    345	for (i = 1; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
    346		u64 addr = NFP_RESOURCE_TBL_BASE +
    347			sizeof(struct nfp_resource_entry) * i;
    348
    349		err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET, addr);
    350		if (err < 0) {
    351			nfp_err(cpp,
    352				"Error: failed to reclaim resource %d mutex\n",
    353				i);
    354			goto err_unlock;
    355		}
    356		if (err)
    357			nfp_warn(cpp, "Warning: busted resource %d mutex\n", i);
    358	}
    359
    360	err = 0;
    361err_unlock:
    362	nfp_cpp_mutex_unlock(dev_mutex);
    363	nfp_cpp_mutex_free(dev_mutex);
    364
    365	return err;
    366}