Exemplo n.º 1
0
static int __nfp_resource_entry_init(struct nfp_cpp *cpp, int entry,
				     const struct nfp_resource_entry_region
				     *region,
				     struct nfp_cpp_mutex **resource_mutex)
{
	struct nfp_cpp_mutex *mutex;
	int target, entries;
	size_t size;
	u32 cpp_id;
	u32 key;
	int err;
	u64 base;

	entries = nfp_cpp_resource_table(cpp, &target, &base, &size);
	if (entries < 0)
		return entries;

	if (entry >= entries)
		return -EINVAL;

	base += sizeof(struct nfp_resource_entry) * entry;

	if (entry == 0)
		key = NFP_RESOURCE_TABLE_KEY;
	else
		key = crc32_posix(region->name, 8);

	err = nfp_cpp_mutex_init(cpp, target, base, key);
	if (err < 0)
		return err;

	/* We already own the initialized lock */
	mutex = nfp_cpp_mutex_alloc(cpp, target, base, key);
	if (!mutex)
		return -ENOMEM;

	/* Mutex Owner and Key are already set */
	cpp_id = NFP_CPP_ID(target, 4, 0);  /* Atomic write */

	err = nfp_cpp_write(cpp, cpp_id, base +
			offsetof(struct nfp_resource_entry, region),
			region, sizeof(*region));
	if (err < 0) {
		/* Try to unlock in the face of adversity */
		nfp_cpp_mutex_unlock(mutex);
		nfp_cpp_mutex_free(mutex);
		return err;
	}

	if (resource_mutex) {
		*resource_mutex = mutex;
	} else {
		nfp_cpp_mutex_unlock(mutex);
		nfp_cpp_mutex_free(mutex);
	}

	return 0;
}
Exemplo n.º 2
0
/**
 * nfp_resource_acquire() - Acquire a resource handle
 * @cpp:	NFP CPP handle
 * @name:	Name of the resource
 *
 * NOTE: This function locks the acquired resource
 *
 * Return: NFP Resource handle, or ERR_PTR()
 */
struct nfp_resource *
nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
{
	unsigned long warn_at = jiffies + 15 * HZ;
	struct nfp_cpp_mutex *dev_mutex;
	struct nfp_resource *res;
	int err;

	res = kzalloc(sizeof(*res), GFP_KERNEL);
	if (!res)
		return ERR_PTR(-ENOMEM);

	strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);

	dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
					NFP_RESOURCE_TBL_BASE,
					NFP_RESOURCE_TBL_KEY);
	if (!dev_mutex) {
		kfree(res);
		return ERR_PTR(-ENOMEM);
	}

	for (;;) {
		err = nfp_resource_try_acquire(cpp, res, dev_mutex);
		if (!err)
			break;
		if (err != -EBUSY)
			goto err_free;

		err = msleep_interruptible(1);
		if (err != 0) {
			err = -ERESTARTSYS;
			goto err_free;
		}

		if (time_is_before_eq_jiffies(warn_at)) {
			warn_at = jiffies + 60 * HZ;
			nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
				 name);
		}
	}

	nfp_cpp_mutex_free(dev_mutex);

	return res;

err_free:
	nfp_cpp_mutex_free(dev_mutex);
	kfree(res);
	return ERR_PTR(err);
}
Exemplo n.º 3
0
static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
{
	char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {};
	struct nfp_resource_entry entry;
	u32 cpp_id, key;
	int ret, i;

	cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */

	strncpy(name_pad, res->name, sizeof(name_pad));

	/* Search for a matching entry */
	key = NFP_RESOURCE_TBL_KEY;
	if (memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8))
		key = crc32_posix(name_pad, sizeof(name_pad));

	for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
		u64 addr = NFP_RESOURCE_TBL_BASE +
			sizeof(struct nfp_resource_entry) * i;

		ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
		if (ret != sizeof(entry))
			return -EIO;

		if (entry.mutex.key != key)
			continue;

		/* Found key! */
		res->mutex =
			nfp_cpp_mutex_alloc(cpp,
					    NFP_RESOURCE_TBL_TARGET, addr, key);
		res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
					 entry.region.cpp_action,
					 entry.region.cpp_token);
		res->addr = (u64)entry.region.page_offset << 8;
		res->size = (u64)entry.region.page_size << 8;

		return 0;
	}

	return -ENOENT;
}
Exemplo n.º 4
0
static int nfp_cpp_resource_acquire(struct nfp_cpp *cpp, const char *name,
				    u32 *r_cpp, u64 *r_addr, u64 *r_size,
				    struct nfp_cpp_mutex **resource_mutex)
{
	struct nfp_resource_entry_region region;
	struct nfp_resource_entry tmp;
	struct nfp_cpp_mutex *mutex;
	int target, err, i, entries;
	u64 base;
	u32 key;
	u32 cpp_id;

	for (i = 0; i < sizeof(region.name); i++) {
		if (*name != 0)
			region.name[i] = *(name++);
		else
			region.name[i] = 0;
	}

	entries = nfp_cpp_resource_table(cpp, &target, &base, NULL);
	if (entries < 0)
		return entries;

	cpp_id = NFP_CPP_ID(target, 3, 0);  /* Atomic read */

	key = NFP_RESOURCE_TABLE_KEY;
	mutex = nfp_cpp_mutex_alloc(cpp, target, base, key);
	if (!mutex)
		return -ENOMEM;

	/* Wait for the lock.. */
	err = nfp_cpp_mutex_lock(mutex);
	if (err < 0) {
		nfp_cpp_mutex_free(mutex);
		return err;
	}

	/* Search for a matching entry */
	if (memcmp(region.name,
		   NFP_RESOURCE_TABLE_NAME "\0\0\0\0\0\0\0\0", 8) != 0)
		key = crc32_posix(&region.name[0], sizeof(region.name));
	for (i = 0; i < entries; i++) {
		u64 addr = base + sizeof(struct nfp_resource_entry) * i;

		err = nfp_cpp_read(cpp, cpp_id, addr, &tmp, sizeof(tmp));
		if (err < 0) {
			/* Unlikely to work if the read failed,
			 * but we should at least try... */
			nfp_cpp_mutex_unlock(mutex);
			nfp_cpp_mutex_free(mutex);
			return err;
		}

		if (tmp.mutex.key == key) {
			/* Found key! */
			if (resource_mutex)
				*resource_mutex = nfp_cpp_mutex_alloc(cpp,
							target, addr, key);

			if (r_cpp)
				*r_cpp = NFP_CPP_ID(tmp.region.cpp_target,
						tmp.region.cpp_action,
						tmp.region.cpp_token);

			if (r_addr)
				*r_addr = (u64)tmp.region.page_offset << 8;

			if (r_size)
				*r_size = (u64)tmp.region.page_size << 8;

			nfp_cpp_mutex_unlock(mutex);
			nfp_cpp_mutex_free(mutex);

			return 0;
		}
	}

	nfp_cpp_mutex_unlock(mutex);
	nfp_cpp_mutex_free(mutex);

	return -ENOENT;
}
Exemplo n.º 5
0
/**
 * nfp_cpp_resource_add() - Construct a new NFP Resource entry
 * @cpp:		NFP CPP handle
 * @name:		Name of the resource
 * @cpp_id:		NFP CPP ID of the resource
 * @address:		NFP CPP address of the resource
 * @size:		Size, in bytes, of the resource area
 * @resource_mutex:	Location to place the resource's mutex
 *
 * NOTE: If resource_mutex is NULL, the mutex of the resource is
 * implictly unlocked.
 *
 * Return: 0, or -ERRNO
 */
int nfp_cpp_resource_add(struct nfp_cpp *cpp, const char *name,
			 u32 cpp_id, u64 address, u64 size,
			 struct nfp_cpp_mutex **resource_mutex)
{
	int target, err, i, entries, minfree;
	u64 base;
	u32 key;
	struct nfp_resource_entry_region region = {
		.cpp_action = NFP_CPP_ID_ACTION_of(cpp_id),
		.cpp_token  = NFP_CPP_ID_TOKEN_of(cpp_id),
		.cpp_target = NFP_CPP_ID_TARGET_of(cpp_id),
		.page_offset = (u32)(address >> 8),
		.page_size  = (u32)(size >> 8),
	};
	struct nfp_cpp_mutex *mutex;
	u32 tmp;

	for (i = 0; i < sizeof(region.name); i++) {
		if (*name != 0)
			region.name[i] = *(name++);
		else
			region.name[i] = 0;
	}

	entries = nfp_cpp_resource_table(cpp, &target, &base, NULL);
	if (entries < 0)
		return entries;

	cpp_id = NFP_CPP_ID(target, 3, 0);  /* Atomic read */

	key = NFP_RESOURCE_TABLE_KEY;
	mutex = nfp_cpp_mutex_alloc(cpp, target, base, key);
	if (!mutex)
		return -ENOMEM;

	/* Wait for the lock.. */
	err = nfp_cpp_mutex_lock(mutex);
	if (err < 0) {
		nfp_cpp_mutex_free(mutex);
		return err;
	}

	/* Search for a free entry, or a duplicate */
	minfree = 0;
	key = crc32_posix(name, 8);
	for (i = 1; i < entries; i++) {
		u64 addr = base + sizeof(struct nfp_resource_entry) * i;

		err = nfp_cpp_readl(cpp, cpp_id, addr +
				offsetof(struct nfp_resource_entry, mutex.key),
				&tmp);
		if (err < 0) {
			/* Unlikely to work if the read failed,
			 * but we should at least try... */
			nfp_cpp_mutex_unlock(mutex);
			nfp_cpp_mutex_free(mutex);
			return err;
		}

		if (tmp == key) {
			/* Duplicate key! */
			nfp_cpp_mutex_unlock(mutex);
			nfp_cpp_mutex_free(mutex);
			return -EEXIST;
		}

		if (tmp == 0 && minfree == 0)
			minfree = i;
	}

	/* No available space in the table! */
	if (minfree == 0)
		return -ENOSPC;

	err = __nfp_resource_entry_init(cpp, minfree, &region, resource_mutex);
	nfp_cpp_mutex_unlock(mutex);
	nfp_cpp_mutex_free(mutex);

	return err;
}