Skip to content

Commit 71f814c

Browse files
Yinjun Zhangkuba-moo
authored andcommitted
nfp: fix schedule in atomic context when offloading sa
IPsec offloading callbacks may be called in atomic context, sleep is not allowed in the implementation. Now use workqueue mechanism to avoid this issue. Extend existing workqueue mechanism for multicast configuration only to universal use, so that all configuring through mailbox asynchronously can utilize it. Fixes: 859a497 ("nfp: implement xfrm callbacks and expose ipsec offload feature to upper layer") Signed-off-by: Yinjun Zhang <[email protected]> Signed-off-by: Simon Horman <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 7a13a2e commit 71f814c

File tree

3 files changed

+87
-70
lines changed

3 files changed

+87
-70
lines changed

drivers/net/ethernet/netronome/nfp/crypto/ipsec.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -129,25 +129,21 @@ struct nfp_ipsec_cfg_mssg {
129129
};
130130
};
131131

132-
static int nfp_ipsec_cfg_cmd_issue(struct nfp_net *nn, int type, int saidx,
133-
struct nfp_ipsec_cfg_mssg *msg)
132+
static int nfp_net_ipsec_cfg(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry)
134133
{
135134
unsigned int offset = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
135+
struct nfp_ipsec_cfg_mssg *msg = (struct nfp_ipsec_cfg_mssg *)entry->msg;
136136
int i, msg_size, ret;
137137

138138
ret = nfp_net_mbox_lock(nn, sizeof(*msg));
139139
if (ret)
140140
return ret;
141141

142-
msg->cmd = type;
143-
msg->sa_idx = saidx;
144-
msg->rsp = 0;
145142
msg_size = ARRAY_SIZE(msg->raw);
146-
147143
for (i = 0; i < msg_size; i++)
148144
nn_writel(nn, offset + 4 * i, msg->raw[i]);
149145

150-
ret = nfp_net_mbox_reconfig(nn, NFP_NET_CFG_MBOX_CMD_IPSEC);
146+
ret = nfp_net_mbox_reconfig(nn, entry->cmd);
151147
if (ret < 0) {
152148
nn_ctrl_bar_unlock(nn);
153149
return ret;
@@ -486,7 +482,10 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x)
486482
}
487483

488484
/* Allocate saidx and commit the SA */
489-
err = nfp_ipsec_cfg_cmd_issue(nn, NFP_IPSEC_CFG_MSSG_ADD_SA, saidx, &msg);
485+
msg.cmd = NFP_IPSEC_CFG_MSSG_ADD_SA;
486+
msg.sa_idx = saidx;
487+
err = nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_IPSEC, &msg,
488+
sizeof(msg), nfp_net_ipsec_cfg);
490489
if (err) {
491490
xa_erase(&nn->xa_ipsec, saidx);
492491
nn_err(nn, "Failed to issue IPsec command err ret=%d\n", err);
@@ -500,14 +499,17 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x)
500499

501500
static void nfp_net_xfrm_del_state(struct xfrm_state *x)
502501
{
502+
struct nfp_ipsec_cfg_mssg msg = {
503+
.cmd = NFP_IPSEC_CFG_MSSG_INV_SA,
504+
.sa_idx = x->xso.offload_handle - 1,
505+
};
503506
struct net_device *netdev = x->xso.dev;
504-
struct nfp_ipsec_cfg_mssg msg;
505507
struct nfp_net *nn;
506508
int err;
507509

508510
nn = netdev_priv(netdev);
509-
err = nfp_ipsec_cfg_cmd_issue(nn, NFP_IPSEC_CFG_MSSG_INV_SA,
510-
x->xso.offload_handle - 1, &msg);
511+
err = nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_IPSEC, &msg,
512+
sizeof(msg), nfp_net_ipsec_cfg);
511513
if (err)
512514
nn_warn(nn, "Failed to invalidate SA in hardware\n");
513515

drivers/net/ethernet/netronome/nfp/nfp_net.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -617,9 +617,10 @@ struct nfp_net_dp {
617617
* @vnic_no_name: For non-port PF vNIC make ndo_get_phys_port_name return
618618
* -EOPNOTSUPP to keep backwards compatibility (set by app)
619619
* @port: Pointer to nfp_port structure if vNIC is a port
620-
* @mc_lock: Protect mc_addrs list
621-
* @mc_addrs: List of mc addrs to add/del to HW
622-
* @mc_work: Work to update mc addrs
620+
* @mbox_amsg: Asynchronously processed message via mailbox
621+
* @mbox_amsg.lock: Protect message list
622+
* @mbox_amsg.list: List of message to process
623+
* @mbox_amsg.work: Work to process message asynchronously
623624
* @app_priv: APP private data for this vNIC
624625
*/
625626
struct nfp_net {
@@ -721,13 +722,25 @@ struct nfp_net {
721722

722723
struct nfp_port *port;
723724

724-
spinlock_t mc_lock;
725-
struct list_head mc_addrs;
726-
struct work_struct mc_work;
725+
struct {
726+
spinlock_t lock;
727+
struct list_head list;
728+
struct work_struct work;
729+
} mbox_amsg;
727730

728731
void *app_priv;
729732
};
730733

734+
struct nfp_mbox_amsg_entry {
735+
struct list_head list;
736+
int (*cfg)(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry);
737+
u32 cmd;
738+
char msg[];
739+
};
740+
741+
int nfp_net_sched_mbox_amsg_work(struct nfp_net *nn, u32 cmd, const void *data, size_t len,
742+
int (*cb)(struct nfp_net *, struct nfp_mbox_amsg_entry *));
743+
731744
/* Functions to read/write from/to a BAR
732745
* Performs any endian conversion necessary.
733746
*/

drivers/net/ethernet/netronome/nfp/nfp_net_common.c

Lines changed: 55 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,14 +1334,54 @@ int nfp_ctrl_open(struct nfp_net *nn)
13341334
return err;
13351335
}
13361336

1337-
struct nfp_mc_addr_entry {
1338-
u8 addr[ETH_ALEN];
1339-
u32 cmd;
1340-
struct list_head list;
1341-
};
1337+
int nfp_net_sched_mbox_amsg_work(struct nfp_net *nn, u32 cmd, const void *data, size_t len,
1338+
int (*cb)(struct nfp_net *, struct nfp_mbox_amsg_entry *))
1339+
{
1340+
struct nfp_mbox_amsg_entry *entry;
1341+
1342+
entry = kmalloc(sizeof(*entry) + len, GFP_ATOMIC);
1343+
if (!entry)
1344+
return -ENOMEM;
1345+
1346+
memcpy(entry->msg, data, len);
1347+
entry->cmd = cmd;
1348+
entry->cfg = cb;
1349+
1350+
spin_lock_bh(&nn->mbox_amsg.lock);
1351+
list_add_tail(&entry->list, &nn->mbox_amsg.list);
1352+
spin_unlock_bh(&nn->mbox_amsg.lock);
1353+
1354+
schedule_work(&nn->mbox_amsg.work);
1355+
1356+
return 0;
1357+
}
1358+
1359+
static void nfp_net_mbox_amsg_work(struct work_struct *work)
1360+
{
1361+
struct nfp_net *nn = container_of(work, struct nfp_net, mbox_amsg.work);
1362+
struct nfp_mbox_amsg_entry *entry, *tmp;
1363+
struct list_head tmp_list;
1364+
1365+
INIT_LIST_HEAD(&tmp_list);
1366+
1367+
spin_lock_bh(&nn->mbox_amsg.lock);
1368+
list_splice_init(&nn->mbox_amsg.list, &tmp_list);
1369+
spin_unlock_bh(&nn->mbox_amsg.lock);
1370+
1371+
list_for_each_entry_safe(entry, tmp, &tmp_list, list) {
1372+
int err = entry->cfg(nn, entry);
1373+
1374+
if (err)
1375+
nn_err(nn, "Config cmd %d to HW failed %d.\n", entry->cmd, err);
1376+
1377+
list_del(&entry->list);
1378+
kfree(entry);
1379+
}
1380+
}
13421381

1343-
static int nfp_net_mc_cfg(struct nfp_net *nn, const unsigned char *addr, const u32 cmd)
1382+
static int nfp_net_mc_cfg(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry)
13441383
{
1384+
unsigned char *addr = entry->msg;
13451385
int ret;
13461386

13471387
ret = nfp_net_mbox_lock(nn, NFP_NET_CFG_MULTICAST_SZ);
@@ -1353,26 +1393,7 @@ static int nfp_net_mc_cfg(struct nfp_net *nn, const unsigned char *addr, const u
13531393
nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MULTICAST_MAC_LO,
13541394
get_unaligned_be16(addr + 4));
13551395

1356-
return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
1357-
}
1358-
1359-
static int nfp_net_mc_prep(struct nfp_net *nn, const unsigned char *addr, const u32 cmd)
1360-
{
1361-
struct nfp_mc_addr_entry *entry;
1362-
1363-
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
1364-
if (!entry)
1365-
return -ENOMEM;
1366-
1367-
ether_addr_copy(entry->addr, addr);
1368-
entry->cmd = cmd;
1369-
spin_lock_bh(&nn->mc_lock);
1370-
list_add_tail(&entry->list, &nn->mc_addrs);
1371-
spin_unlock_bh(&nn->mc_lock);
1372-
1373-
schedule_work(&nn->mc_work);
1374-
1375-
return 0;
1396+
return nfp_net_mbox_reconfig_and_unlock(nn, entry->cmd);
13761397
}
13771398

13781399
static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr)
@@ -1385,35 +1406,16 @@ static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr)
13851406
return -EINVAL;
13861407
}
13871408

1388-
return nfp_net_mc_prep(nn, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD);
1409+
return nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD, addr,
1410+
NFP_NET_CFG_MULTICAST_SZ, nfp_net_mc_cfg);
13891411
}
13901412

13911413
static int nfp_net_mc_unsync(struct net_device *netdev, const unsigned char *addr)
13921414
{
13931415
struct nfp_net *nn = netdev_priv(netdev);
13941416

1395-
return nfp_net_mc_prep(nn, addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL);
1396-
}
1397-
1398-
static void nfp_net_mc_addr_config(struct work_struct *work)
1399-
{
1400-
struct nfp_net *nn = container_of(work, struct nfp_net, mc_work);
1401-
struct nfp_mc_addr_entry *entry, *tmp;
1402-
struct list_head tmp_list;
1403-
1404-
INIT_LIST_HEAD(&tmp_list);
1405-
1406-
spin_lock_bh(&nn->mc_lock);
1407-
list_splice_init(&nn->mc_addrs, &tmp_list);
1408-
spin_unlock_bh(&nn->mc_lock);
1409-
1410-
list_for_each_entry_safe(entry, tmp, &tmp_list, list) {
1411-
if (nfp_net_mc_cfg(nn, entry->addr, entry->cmd))
1412-
nn_err(nn, "Config mc address to HW failed.\n");
1413-
1414-
list_del(&entry->list);
1415-
kfree(entry);
1416-
}
1417+
return nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL, addr,
1418+
NFP_NET_CFG_MULTICAST_SZ, nfp_net_mc_cfg);
14171419
}
14181420

14191421
static void nfp_net_set_rx_mode(struct net_device *netdev)
@@ -2681,9 +2683,9 @@ int nfp_net_init(struct nfp_net *nn)
26812683
if (!nn->dp.netdev)
26822684
return 0;
26832685

2684-
spin_lock_init(&nn->mc_lock);
2685-
INIT_LIST_HEAD(&nn->mc_addrs);
2686-
INIT_WORK(&nn->mc_work, nfp_net_mc_addr_config);
2686+
spin_lock_init(&nn->mbox_amsg.lock);
2687+
INIT_LIST_HEAD(&nn->mbox_amsg.list);
2688+
INIT_WORK(&nn->mbox_amsg.work, nfp_net_mbox_amsg_work);
26872689

26882690
return register_netdev(nn->dp.netdev);
26892691

@@ -2704,6 +2706,6 @@ void nfp_net_clean(struct nfp_net *nn)
27042706
unregister_netdev(nn->dp.netdev);
27052707
nfp_net_ipsec_clean(nn);
27062708
nfp_ccm_mbox_clean(nn);
2707-
flush_work(&nn->mc_work);
2709+
flush_work(&nn->mbox_amsg.work);
27082710
nfp_net_reconfig_wait_posted(nn);
27092711
}

0 commit comments

Comments
 (0)