示例#1
0
/**
 * nfp_reset_soft() - Perform a soft reset of the NFP
 * @nfp:	NFP Device handle
 *
 * Return: 0, or -ERRNO
 */
int nfp_reset_soft(struct nfp_device *nfp)
{
	struct nfp_cpp *cpp = nfp_device_cpp(nfp);
	struct nfp_cpp_area *area;
	struct nfp_resource *res;
	u32 model;
	int i, err;

	model = nfp_cpp_model(cpp);

	/* Claim the nfp.nffw resource page */
	res = nfp_resource_acquire(nfp, NFP_RESOURCE_NFP_NFFW);
	if (IS_ERR(res)) {
		nfp_err(nfp, "Can't aquire %s resource\n",
			NFP_RESOURCE_NFP_NFFW);
		return -EBUSY;
	}

	if (NFP_CPP_MODEL_IS_3200(model))
		err = nfp3200_reset_soft(nfp);
	else if (NFP_CPP_MODEL_IS_6000(model))
		err = nfp6000_reset_soft(nfp);
	else
		err = -EINVAL;

	if (err < 0)
		goto exit;

	/* Clear all NFP NFFW page */
	area = nfp_cpp_area_alloc_acquire(cpp, nfp_resource_cpp_id(res),
					  nfp_resource_address(res),
					  nfp_resource_size(res));
	if (!area) {
		nfp_err(nfp, "Can't acquire area for %s resource\n",
			NFP_RESOURCE_NFP_NFFW);
		err = -ENOMEM;
		goto exit;
	}

	for (i = 0; i < nfp_resource_size(res); i += 8) {
		err = nfp_cpp_area_writeq(area, i, 0);
		if (err < 0)
			break;
	}
	nfp_cpp_area_release_free(area);

	if (err < 0) {
		nfp_err(nfp, "Can't erase area of %s resource\n",
			NFP_RESOURCE_NFP_NFFW);
		goto exit;
	}

	err = 0;

exit:
	nfp_resource_release(res);

	return err;
}
示例#2
0
static struct nfp_hwinfo *
hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size)
{
	struct nfp_hwinfo *header;
	struct nfp_resource *res;
	u64 cpp_addr;
	u32 cpp_id;
	int err;
	u8 *db;

	res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_HWINFO);
	if (!IS_ERR(res)) {
		cpp_id = nfp_resource_cpp_id(res);
		cpp_addr = nfp_resource_address(res);
		*cpp_size = nfp_resource_size(res);

		nfp_resource_release(res);

		if (*cpp_size < HWINFO_SIZE_MIN)
			return NULL;
	} else if (PTR_ERR(res) == -ENOENT) {
		/* Try getting the HWInfo table from the 'classic' location */
		cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU,
					   NFP_CPP_ACTION_RW, 0, 1);
		cpp_addr = 0x30000;
		*cpp_size = 0x0e000;
	} else {
		return NULL;
	}

	db = kmalloc(*cpp_size + 1, GFP_KERNEL);
	if (!db)
		return NULL;

	err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size);
	if (err != *cpp_size)
		goto exit_free;

	header = (void *)db;
	if (nfp_hwinfo_is_updating(header))
		goto exit_free;

	if (le32_to_cpu(header->version) != NFP_HWINFO_VERSION_2) {
		nfp_err(cpp, "Unknown HWInfo version: 0x%08x\n",
			le32_to_cpu(header->version));
		goto exit_free;
	}

	/* NULL-terminate for safety */
	db[*cpp_size] = '\0';

	return (void *)db;
exit_free:
	kfree(db);
	return NULL;
}
示例#3
0
/*
 * nfp_nffw_info_open() - Acquire the lock on the NFFW table
 * @cpp:	NFP CPP handle
 *
 * Return: 0, or -ERRNO
 */
struct nfp_nffw_info *
nfp_nffw_info_open(struct nfp_cpp *cpp)
{
	struct nfp_nffw_info_data *fwinf;
	struct nfp_nffw_info *state;
	uint32_t info_ver;
	int err;

	state = malloc(sizeof(*state));
	if (!state)
		return NULL;

	memset(state, 0, sizeof(*state));

	state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
	if (!state->res)
		goto err_free;

	fwinf = &state->fwinf;

	if (sizeof(*fwinf) > nfp_resource_size(state->res))
		goto err_release;

	err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
			   nfp_resource_address(state->res),
			   fwinf, sizeof(*fwinf));
	if (err < (int)sizeof(*fwinf))
		goto err_release;

	if (!nffw_res_flg_init_get(fwinf))
		goto err_release;

	info_ver = nffw_res_info_version_get(fwinf);
	if (info_ver > NFFW_INFO_VERSION_CURRENT)
		goto err_release;

	state->cpp = cpp;
	return state;

err_release:
	nfp_resource_release(state->res);
err_free:
	free(state);
	return NULL;
}
示例#4
0
/* Other debug dumps
 */
static int
nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer)
{
	struct nfp_resource *res;
	int ret;

	if (!nn->cpp)
		return -EOPNOTSUPP;

	dump->version = 1;
	dump->flag = NFP_DUMP_NSP_DIAG;

	res = nfp_resource_acquire(nn->cpp, NFP_RESOURCE_NSP_DIAG);
	if (IS_ERR(res))
		return PTR_ERR(res);

	if (buffer) {
		if (dump->len != nfp_resource_size(res)) {
			ret = -EINVAL;
			goto exit_release;
		}

		ret = nfp_cpp_read(nn->cpp, nfp_resource_cpp_id(res),
				   nfp_resource_address(res),
				   buffer, dump->len);
		if (ret != dump->len)
			ret = ret < 0 ? ret : -EIO;
		else
			ret = 0;
	} else {
		dump->len = nfp_resource_size(res);
		ret = 0;
	}
exit_release:
	nfp_resource_release(res);

	return ret;
}
示例#5
0
/**
 * nfp_nsp_command() - Execute a command on the NFP Service Processor
 * @nfp:	NFP Device handle
 * @code:	NSP Command Code
 *
 * Return: 0 for success with no result
 *
 *         1..255 for NSP completion with a result code
 *
 *         -EAGAIN if the NSP is not yet present
 *
 *         -ENODEV if the NSP is not a supported model
 *
 *         -EBUSY if the NSP is stuck
 *
 *         -EINTR if interrupted while waiting for completion
 *
 *         -ETIMEDOUT if the NSP took longer than 30 seconds to complete
 */
int nfp_nsp_command(struct nfp_device *nfp, uint16_t code, u32 option,
		    u32 buff_cpp, u64 buff_addr)
{
	struct nfp_cpp *cpp = nfp_device_cpp(nfp);
	struct nfp_nsp *nsp;
	u32 nsp_cpp;
	u64 nsp_base;
	u64 nsp_status;
	u64 nsp_command;
	u64 nsp_buffer;
	int err, ok;
	u64 tmp;
	int timeout = 30 * 10;	/* 30 seconds total */

	nsp = nfp_device_private(nfp, nfp_nsp_con);
	if (!nsp)
		return -EAGAIN;

	nsp_cpp = nfp_resource_cpp_id(nsp->res);
	nsp_base = nfp_resource_address(nsp->res);
	nsp_status = nsp_base + NSP_STATUS;
	nsp_command = nsp_base + NSP_COMMAND;
	nsp_buffer = nsp_base + NSP_BUFFER;

	err = nfp_cpp_readq(cpp, nsp_cpp, nsp_status, &tmp);
	if (err < 0)
		return err;

	if (NSP_MAGIC != NSP_STATUS_MAGIC_of(tmp)) {
		nfp_err(nfp, "NSP: Cannot detect NFP Service Processor\n");
		return -ENODEV;
	}

	ok = NSP_STATUS_MAJOR_of(tmp) == NSP_CODE_MAJOR_of(code) &&
	     NSP_STATUS_MINOR_of(tmp) >= NSP_CODE_MINOR_of(code);
	if (!ok) {
		nfp_err(nfp, "NSP: Code 0x%04x not supported (ABI %d.%d)\n",
			code,
			(int)NSP_STATUS_MAJOR_of(tmp),
			(int)NSP_STATUS_MINOR_of(tmp));
		return -EINVAL;
	}

	if (tmp & NSP_STATUS_BUSY) {
		nfp_err(nfp, "NSP: Service processor busy!\n");
		return -EBUSY;
	}

	err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer,
			     NSP_BUFFER_CPP(buff_cpp) |
			     NSP_BUFFER_ADDRESS(buff_addr));
	if (err < 0)
		return err;

	err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command,
			     NSP_COMMAND_OPTION(option) |
			     NSP_COMMAND_CODE(code) | NSP_COMMAND_START);
	if (err < 0)
		return err;

	/* Wait for NSP_COMMAND_START to go to 0 */
	for (; timeout > 0; timeout--) {
		err = nfp_cpp_readq(cpp, nsp_cpp, nsp_command, &tmp);
		if (err < 0)
			return err;

		if (!(tmp & NSP_COMMAND_START))
			break;

		if (msleep_interruptible(100) > 0) {
			nfp_warn(nfp, "NSP: Interrupt waiting for code 0x%04x to start\n",
				 code);
			return -EINTR;
		}
	}

	if (timeout < 0) {
		nfp_warn(nfp, "NSP: Timeout waiting for code 0x%04x to start\n",
			 code);
		return -ETIMEDOUT;
	}

	/* Wait for NSP_STATUS_BUSY to go to 0 */
	for (; timeout > 0; timeout--) {
		err = nfp_cpp_readq(cpp, nsp_cpp, nsp_status, &tmp);
		if (err < 0)
			return err;

		if (!(tmp & NSP_STATUS_BUSY))
			break;

		if (msleep_interruptible(100) > 0) {
			nfp_warn(nfp, "NSP: Interrupt waiting for code 0x%04x to complete\n",
				 code);
			return -EINTR;
		}
	}

	if (timeout < 0) {
		nfp_warn(nfp, "NSP: Timeout waiting for code 0x%04x to complete\n",
			 code);
		return -ETIMEDOUT;
	}

	err = NSP_STATUS_RESULT_of(tmp);
	if (err > 0)
		return -err;

	err = nfp_cpp_readq(cpp, nsp_cpp, nsp_command, &tmp);
	if (err < 0)
		return err;

	return NSP_COMMAND_OPTION_of(tmp);
}