Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30a02921 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

nfp: allow multi-stage NSP configuration



NSP commands may be slow to respond, we should try to avoid doing
a command-per-item when user requested to change multiple parameters
for instance with an ethtool .set_settings() command.

Introduce a way of internal NSP code to carry state in NSP structure
and add start/finish calls to perform the initialization and kick off
of the configuration request, with potentially many parameters being
modified in between.

nfp_eth_set_mod_enable() will make use of the new code internally,
other "set" functions to follow.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ce22f5a2
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -52,6 +52,14 @@ const char *nfp_hwinfo_lookup(struct nfp_cpp *cpp, const char *lookup);

struct nfp_nsp;

struct nfp_cpp *nfp_nsp_cpp(struct nfp_nsp *state);
bool nfp_nsp_config_modified(struct nfp_nsp *state);
void nfp_nsp_config_set_modified(struct nfp_nsp *state, bool modified);
void *nfp_nsp_config_entries(struct nfp_nsp *state);
unsigned int nfp_nsp_config_idx(struct nfp_nsp *state);
void nfp_nsp_config_set_state(struct nfp_nsp *state, void *entries,
			      unsigned int idx);
void nfp_nsp_config_clear_state(struct nfp_nsp *state);
int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size);
int nfp_nsp_write_eth_table(struct nfp_nsp *state,
			    const void *buf, unsigned int size);
+43 −0
Original line number Diff line number Diff line
@@ -104,8 +104,51 @@ struct nfp_nsp {
		u16 major;
		u16 minor;
	} ver;

	/* Eth table config state */
	bool modified;
	unsigned int idx;
	void *entries;
};

struct nfp_cpp *nfp_nsp_cpp(struct nfp_nsp *state)
{
	return state->cpp;
}

bool nfp_nsp_config_modified(struct nfp_nsp *state)
{
	return state->modified;
}

void nfp_nsp_config_set_modified(struct nfp_nsp *state, bool modified)
{
	state->modified = modified;
}

void *nfp_nsp_config_entries(struct nfp_nsp *state)
{
	return state->entries;
}

unsigned int nfp_nsp_config_idx(struct nfp_nsp *state)
{
	return state->idx;
}

void
nfp_nsp_config_set_state(struct nfp_nsp *state, void *entries, unsigned int idx)
{
	state->entries = entries;
	state->idx = idx;
}

void nfp_nsp_config_clear_state(struct nfp_nsp *state)
{
	state->entries = NULL;
	state->idx = 0;
}

static int nfp_nsp_check(struct nfp_nsp *state)
{
	struct nfp_cpp *cpp = state->cpp;
+4 −0
Original line number Diff line number Diff line
@@ -136,4 +136,8 @@ struct nfp_eth_table *
__nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp);
int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable);

struct nfp_nsp *nfp_eth_config_start(struct nfp_cpp *cpp, unsigned int idx);
int nfp_eth_config_commit_end(struct nfp_nsp *nsp);
void nfp_eth_config_cleanup_end(struct nfp_nsp *nsp);

#endif
+83 −31
Original line number Diff line number Diff line
@@ -268,63 +268,115 @@ __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp)
	return NULL;
}

/**
 * nfp_eth_set_mod_enable() - set PHY module enable control bit
 * @cpp:	NFP CPP handle
 * @idx:	NFP chip-wide port index
 * @enable:	Desired state
 *
 * Enable or disable PHY module (this usually means setting the TX lanes
 * disable bits).
 *
 * Return: 0 or -ERRNO.
 */
int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
struct nfp_nsp *nfp_eth_config_start(struct nfp_cpp *cpp, unsigned int idx)
{
	struct eth_table_entry *entries;
	struct nfp_nsp *nsp;
	u64 reg;
	int ret;

	entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL);
	if (!entries)
		return -ENOMEM;
		return ERR_PTR(-ENOMEM);

	nsp = nfp_nsp_open(cpp);
	if (IS_ERR(nsp)) {
		kfree(entries);
		return PTR_ERR(nsp);
		return nsp;
	}

	ret = nfp_nsp_read_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
	if (ret < 0) {
		nfp_err(cpp, "reading port table failed %d\n", ret);
		goto exit_close_nsp;
		goto err;
	}

	if (!(entries[idx].port & NSP_ETH_PORT_LANES_MASK)) {
		nfp_warn(cpp, "trying to set port state on disabled port %d\n",
			 idx);
		ret = -EINVAL;
		goto exit_close_nsp;
		goto err;
	}

	/* Check if we are already in requested state */
	reg = le64_to_cpu(entries[idx].state);
	if (enable == FIELD_GET(NSP_ETH_CTRL_ENABLED, reg)) {
		ret = 0;
		goto exit_close_nsp;
	nfp_nsp_config_set_state(nsp, entries, idx);
	return nsp;

err:
	nfp_nsp_close(nsp);
	kfree(entries);
	return ERR_PTR(-EIO);
}

void nfp_eth_config_cleanup_end(struct nfp_nsp *nsp)
{
	struct eth_table_entry *entries = nfp_nsp_config_entries(nsp);

	nfp_nsp_config_set_modified(nsp, false);
	nfp_nsp_config_clear_state(nsp);
	nfp_nsp_close(nsp);
	kfree(entries);
}

/**
 * nfp_eth_config_commit_end() - perform recorded configuration changes
 * @nsp:	NFP NSP handle returned from nfp_eth_config_start()
 *
 * Perform the configuration which was requested with __nfp_eth_set_*()
 * helpers and recorded in @nsp state.  If device was already configured
 * as requested or no __nfp_eth_set_*() operations were made no NSP command
 * will be performed.
 *
 * Return:
 * 0 - configuration successful;
 * 1 - no changes were needed;
 * -ERRNO - configuration failed.
 */
int nfp_eth_config_commit_end(struct nfp_nsp *nsp)
{
	struct eth_table_entry *entries = nfp_nsp_config_entries(nsp);
	int ret = 1;

	if (nfp_nsp_config_modified(nsp)) {
		ret = nfp_nsp_write_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
		ret = ret < 0 ? ret : 0;
	}

	nfp_eth_config_cleanup_end(nsp);

	return ret;
}

/**
 * nfp_eth_set_mod_enable() - set PHY module enable control bit
 * @cpp:	NFP CPP handle
 * @idx:	NFP chip-wide port index
 * @enable:	Desired state
 *
 * Enable or disable PHY module (this usually means setting the TX lanes
 * disable bits).
 *
 * Return: 0 or -ERRNO.
 */
int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
{
	struct eth_table_entry *entries;
	struct nfp_nsp *nsp;
	u64 reg;

	nsp = nfp_eth_config_start(cpp, idx);
	if (IS_ERR(nsp))
		return PTR_ERR(nsp);

	entries = nfp_nsp_config_entries(nsp);

	/* Check if we are already in requested state */
	reg = le64_to_cpu(entries[idx].state);
	if (enable != FIELD_GET(NSP_ETH_CTRL_ENABLED, reg)) {
		reg = le64_to_cpu(entries[idx].control);
		reg &= ~NSP_ETH_CTRL_ENABLED;
		reg |= FIELD_PREP(NSP_ETH_CTRL_ENABLED, enable);
		entries[idx].control = cpu_to_le64(reg);

	ret = nfp_nsp_write_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
exit_close_nsp:
	nfp_nsp_close(nsp);
	kfree(entries);
		nfp_nsp_config_set_modified(nsp, true);
	}

	return ret < 0 ? ret : 0;
	return nfp_eth_config_commit_end(nsp);
}