summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
diff options
context:
space:
mode:
authorJakub Kicinski2017-04-23 05:17:56 +0200
committerDavid S. Miller2017-04-24 20:35:44 +0200
commit90fdc561b08ce292f1d39a62f70012f150583b98 (patch)
treee91b5255668df358acb2eda390f902ecd99fce60 /drivers/net/ethernet/netronome/nfp/nfp_net_main.c
parentnfp: fix free list buffer size reporting (diff)
downloadkernel-qcow2-linux-90fdc561b08ce292f1d39a62f70012f150583b98.tar.gz
kernel-qcow2-linux-90fdc561b08ce292f1d39a62f70012f150583b98.tar.xz
kernel-qcow2-linux-90fdc561b08ce292f1d39a62f70012f150583b98.zip
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: 172f638c93dd ("nfp: add port state refresh") Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/netronome/nfp/nfp_net_main.c')
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_main.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index 4c6863a072d3..8cb87cbe1120 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -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 &eth_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,31 +539,36 @@ 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();
+ schedule_work(&pf->port_refresh_work);
+}
- old_table = pf->eth_tbl;
+int nfp_net_refresh_eth_port(struct nfp_net *nn)
+{
+ struct nfp_eth_table_port *eth_port;
+ struct nfp_eth_table *eth_table;
- list_for_each_entry(nn, &pf->ports, port_list)
- nfp_net_link_changed_read_clear(nn);
+ eth_table = nfp_eth_read_ports(nn->cpp);
+ if (!eth_table) {
+ nn_err(nn, "Error refreshing port state table!\n");
+ return -EIO;
+ }
- 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;
+ 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;
}
- list_for_each_entry(nn, &pf->ports, port_list)
- nn->eth_port = nfp_net_find_port(pf, nn->eth_port->eth_index);
+ memcpy(nn->eth_port, eth_port, sizeof(*eth_port));
- kfree(old_table);
+ kfree(eth_table);
- schedule_work(&pf->port_refresh_work);
+ return 0;
}
/*