nfp: fix schedule in atomic context when sync mc address
The callback `.ndo_set_rx_mode` is called in atomic context, sleep
is not allowed in the implementation. Now use workqueue mechanism
to avoid this issue.
Fixes: de62486449
("nfp: add support for multicast filter")
Signed-off-by: Yinjun Zhang <yinjun.zhang@corigine.com>
Reviewed-by: Louis Peens <louis.peens@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
Link: https://lore.kernel.org/r/20221220152100.1042774-1-simon.horman@corigine.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
3d8f2c4269
commit
e20aa071cd
2 changed files with 64 additions and 4 deletions
|
@ -617,6 +617,9 @@ struct nfp_net_dp {
|
||||||
* @vnic_no_name: For non-port PF vNIC make ndo_get_phys_port_name return
|
* @vnic_no_name: For non-port PF vNIC make ndo_get_phys_port_name return
|
||||||
* -EOPNOTSUPP to keep backwards compatibility (set by app)
|
* -EOPNOTSUPP to keep backwards compatibility (set by app)
|
||||||
* @port: Pointer to nfp_port structure if vNIC is a port
|
* @port: Pointer to nfp_port structure if vNIC is a port
|
||||||
|
* @mc_lock: Protect mc_addrs list
|
||||||
|
* @mc_addrs: List of mc addrs to add/del to HW
|
||||||
|
* @mc_work: Work to update mc addrs
|
||||||
* @app_priv: APP private data for this vNIC
|
* @app_priv: APP private data for this vNIC
|
||||||
*/
|
*/
|
||||||
struct nfp_net {
|
struct nfp_net {
|
||||||
|
@ -718,6 +721,10 @@ struct nfp_net {
|
||||||
|
|
||||||
struct nfp_port *port;
|
struct nfp_port *port;
|
||||||
|
|
||||||
|
spinlock_t mc_lock;
|
||||||
|
struct list_head mc_addrs;
|
||||||
|
struct work_struct mc_work;
|
||||||
|
|
||||||
void *app_priv;
|
void *app_priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1334,9 +1334,14 @@ err_unlock:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfp_net_mc_cfg(struct net_device *netdev, const unsigned char *addr, const u32 cmd)
|
struct nfp_mc_addr_entry {
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
u32 cmd;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int nfp_net_mc_cfg(struct nfp_net *nn, const unsigned char *addr, const u32 cmd)
|
||||||
{
|
{
|
||||||
struct nfp_net *nn = netdev_priv(netdev);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nfp_net_mbox_lock(nn, NFP_NET_CFG_MULTICAST_SZ);
|
ret = nfp_net_mbox_lock(nn, NFP_NET_CFG_MULTICAST_SZ);
|
||||||
|
@ -1351,6 +1356,25 @@ static int nfp_net_mc_cfg(struct net_device *netdev, const unsigned char *addr,
|
||||||
return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
|
return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nfp_net_mc_prep(struct nfp_net *nn, const unsigned char *addr, const u32 cmd)
|
||||||
|
{
|
||||||
|
struct nfp_mc_addr_entry *entry;
|
||||||
|
|
||||||
|
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
||||||
|
if (!entry)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ether_addr_copy(entry->addr, addr);
|
||||||
|
entry->cmd = cmd;
|
||||||
|
spin_lock_bh(&nn->mc_lock);
|
||||||
|
list_add_tail(&entry->list, &nn->mc_addrs);
|
||||||
|
spin_unlock_bh(&nn->mc_lock);
|
||||||
|
|
||||||
|
schedule_work(&nn->mc_work);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr)
|
static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr)
|
||||||
{
|
{
|
||||||
struct nfp_net *nn = netdev_priv(netdev);
|
struct nfp_net *nn = netdev_priv(netdev);
|
||||||
|
@ -1361,12 +1385,35 @@ static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nfp_net_mc_cfg(netdev, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD);
|
return nfp_net_mc_prep(nn, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfp_net_mc_unsync(struct net_device *netdev, const unsigned char *addr)
|
static int nfp_net_mc_unsync(struct net_device *netdev, const unsigned char *addr)
|
||||||
{
|
{
|
||||||
return nfp_net_mc_cfg(netdev, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL);
|
struct nfp_net *nn = netdev_priv(netdev);
|
||||||
|
|
||||||
|
return nfp_net_mc_prep(nn, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfp_net_mc_addr_config(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct nfp_net *nn = container_of(work, struct nfp_net, mc_work);
|
||||||
|
struct nfp_mc_addr_entry *entry, *tmp;
|
||||||
|
struct list_head tmp_list;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&tmp_list);
|
||||||
|
|
||||||
|
spin_lock_bh(&nn->mc_lock);
|
||||||
|
list_splice_init(&nn->mc_addrs, &tmp_list);
|
||||||
|
spin_unlock_bh(&nn->mc_lock);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(entry, tmp, &tmp_list, list) {
|
||||||
|
if (nfp_net_mc_cfg(nn, entry->addr, entry->cmd))
|
||||||
|
nn_err(nn, "Config mc address to HW failed.\n");
|
||||||
|
|
||||||
|
list_del(&entry->list);
|
||||||
|
kfree(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfp_net_set_rx_mode(struct net_device *netdev)
|
static void nfp_net_set_rx_mode(struct net_device *netdev)
|
||||||
|
@ -2633,6 +2680,11 @@ int nfp_net_init(struct nfp_net *nn)
|
||||||
|
|
||||||
if (!nn->dp.netdev)
|
if (!nn->dp.netdev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
spin_lock_init(&nn->mc_lock);
|
||||||
|
INIT_LIST_HEAD(&nn->mc_addrs);
|
||||||
|
INIT_WORK(&nn->mc_work, nfp_net_mc_addr_config);
|
||||||
|
|
||||||
return register_netdev(nn->dp.netdev);
|
return register_netdev(nn->dp.netdev);
|
||||||
|
|
||||||
err_clean_mbox:
|
err_clean_mbox:
|
||||||
|
@ -2652,5 +2704,6 @@ void nfp_net_clean(struct nfp_net *nn)
|
||||||
unregister_netdev(nn->dp.netdev);
|
unregister_netdev(nn->dp.netdev);
|
||||||
nfp_net_ipsec_clean(nn);
|
nfp_net_ipsec_clean(nn);
|
||||||
nfp_ccm_mbox_clean(nn);
|
nfp_ccm_mbox_clean(nn);
|
||||||
|
flush_work(&nn->mc_work);
|
||||||
nfp_net_reconfig_wait_posted(nn);
|
nfp_net_reconfig_wait_posted(nn);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue