mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-29 07:34:06 +08:00
nfp: remove the refresh of all ports optimization
The code refreshing the eth port state was trying to update state
of all ports of the card. Unfortunately to safely walk the port
list we would have to hold the port lock, which we can't due to
lock ordering constraints against rtnl.
Make the per-port sync refresh and async refresh of all ports
completely separate routines.
Fixes: 172f638c93
("nfp: add port state refresh")
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ee200a7377
commit
90fdc561b0
@ -819,7 +819,8 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn);
|
||||
int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new);
|
||||
|
||||
bool nfp_net_link_changed_read_clear(struct nfp_net *nn);
|
||||
void nfp_net_refresh_port_config(struct nfp_net *nn);
|
||||
int nfp_net_refresh_eth_port(struct nfp_net *nn);
|
||||
void nfp_net_refresh_port_table(struct nfp_net *nn);
|
||||
|
||||
#ifdef CONFIG_NFP_DEBUG
|
||||
void nfp_net_debugfs_create(void);
|
||||
|
@ -211,10 +211,15 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
|
||||
return 0;
|
||||
|
||||
/* Use link speed from ETH table if available, otherwise try the BAR */
|
||||
if (nn->eth_port && nfp_net_link_changed_read_clear(nn))
|
||||
nfp_net_refresh_port_config(nn);
|
||||
/* Separate if - on FW error the port could've disappeared from table */
|
||||
if (nn->eth_port) {
|
||||
int err;
|
||||
|
||||
if (nfp_net_link_changed_read_clear(nn)) {
|
||||
err = nfp_net_refresh_eth_port(nn);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
cmd->base.port = nn->eth_port->port_type;
|
||||
cmd->base.speed = nn->eth_port->speed;
|
||||
cmd->base.duplex = DUPLEX_FULL;
|
||||
@ -273,7 +278,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
|
||||
if (err > 0)
|
||||
return 0; /* no change */
|
||||
|
||||
nfp_net_refresh_port_config(nn);
|
||||
nfp_net_refresh_port_table(nn);
|
||||
|
||||
return err;
|
||||
|
||||
|
@ -176,13 +176,13 @@ nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id)
|
||||
}
|
||||
|
||||
static struct nfp_eth_table_port *
|
||||
nfp_net_find_port(struct nfp_pf *pf, unsigned int id)
|
||||
nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; pf->eth_tbl && i < pf->eth_tbl->count; i++)
|
||||
if (pf->eth_tbl->ports[i].eth_index == id)
|
||||
return &pf->eth_tbl->ports[i];
|
||||
for (i = 0; eth_tbl && i < eth_tbl->count; i++)
|
||||
if (eth_tbl->ports[i].eth_index == id)
|
||||
return ð_tbl->ports[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -367,7 +367,7 @@ nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar,
|
||||
prev_tx_base = tgt_tx_base;
|
||||
prev_rx_base = tgt_rx_base;
|
||||
|
||||
eth_port = nfp_net_find_port(pf, i);
|
||||
eth_port = nfp_net_find_port(pf->eth_tbl, i);
|
||||
if (eth_port && eth_port->override_changed) {
|
||||
nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i);
|
||||
} else {
|
||||
@ -485,6 +485,7 @@ static void nfp_net_refresh_netdevs(struct work_struct *work)
|
||||
{
|
||||
struct nfp_pf *pf = container_of(work, struct nfp_pf,
|
||||
port_refresh_work);
|
||||
struct nfp_eth_table *eth_table;
|
||||
struct nfp_net *nn, *next;
|
||||
|
||||
mutex_lock(&pf->port_lock);
|
||||
@ -493,6 +494,27 @@ static void nfp_net_refresh_netdevs(struct work_struct *work)
|
||||
if (list_empty(&pf->ports))
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(nn, &pf->ports, port_list)
|
||||
nfp_net_link_changed_read_clear(nn);
|
||||
|
||||
eth_table = nfp_eth_read_ports(pf->cpp);
|
||||
if (!eth_table) {
|
||||
nfp_err(pf->cpp, "Error refreshing port config!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
list_for_each_entry(nn, &pf->ports, port_list) {
|
||||
if (!nn->eth_port)
|
||||
continue;
|
||||
nn->eth_port = nfp_net_find_port(eth_table,
|
||||
nn->eth_port->eth_index);
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
kfree(pf->eth_tbl);
|
||||
pf->eth_tbl = eth_table;
|
||||
|
||||
list_for_each_entry_safe(nn, next, &pf->ports, port_list) {
|
||||
if (!nn->eth_port) {
|
||||
nfp_warn(pf->cpp, "Warning: port not present after reconfig\n");
|
||||
@ -517,33 +539,38 @@ out:
|
||||
mutex_unlock(&pf->port_lock);
|
||||
}
|
||||
|
||||
void nfp_net_refresh_port_config(struct nfp_net *nn)
|
||||
void nfp_net_refresh_port_table(struct nfp_net *nn)
|
||||
{
|
||||
struct nfp_pf *pf = pci_get_drvdata(nn->pdev);
|
||||
struct nfp_eth_table *old_table;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
old_table = pf->eth_tbl;
|
||||
|
||||
list_for_each_entry(nn, &pf->ports, port_list)
|
||||
nfp_net_link_changed_read_clear(nn);
|
||||
|
||||
pf->eth_tbl = nfp_eth_read_ports(pf->cpp);
|
||||
if (!pf->eth_tbl) {
|
||||
pf->eth_tbl = old_table;
|
||||
nfp_err(pf->cpp, "Error refreshing port config!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(nn, &pf->ports, port_list)
|
||||
nn->eth_port = nfp_net_find_port(pf, nn->eth_port->eth_index);
|
||||
|
||||
kfree(old_table);
|
||||
|
||||
schedule_work(&pf->port_refresh_work);
|
||||
}
|
||||
|
||||
int nfp_net_refresh_eth_port(struct nfp_net *nn)
|
||||
{
|
||||
struct nfp_eth_table_port *eth_port;
|
||||
struct nfp_eth_table *eth_table;
|
||||
|
||||
eth_table = nfp_eth_read_ports(nn->cpp);
|
||||
if (!eth_table) {
|
||||
nn_err(nn, "Error refreshing port state table!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
eth_port = nfp_net_find_port(eth_table, nn->eth_port->eth_index);
|
||||
if (!eth_port) {
|
||||
nn_err(nn, "Error finding state of the port!\n");
|
||||
kfree(eth_table);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(nn->eth_port, eth_port, sizeof(*eth_port));
|
||||
|
||||
kfree(eth_table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PCI device functions
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user