Skip to content

Commit 6e16e67

Browse files
committed
Merge branch 'nfp-fix-schedule-in-atomic-context-when-offloading-sa'
Simon Horman says: ==================== nfp: fix schedule in atomic context when offloading sa Yinjun Zhang says: 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 asynchoronously can utilize it. Also fix another two incorrect use of mailbox in IPsec: 1. Need lock for race condition when accessing mbox 2. Offset of mbox access should depends on tlv caps ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents d61615c + 71f814c commit 6e16e67

File tree

4 files changed

+99
-74
lines changed

4 files changed

+99
-74
lines changed

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

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,26 +129,31 @@ 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
{
134+
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;
135136
int i, msg_size, ret;
136137

137-
msg->cmd = type;
138-
msg->sa_idx = saidx;
139-
msg->rsp = 0;
140-
msg_size = ARRAY_SIZE(msg->raw);
138+
ret = nfp_net_mbox_lock(nn, sizeof(*msg));
139+
if (ret)
140+
return ret;
141141

142+
msg_size = ARRAY_SIZE(msg->raw);
142143
for (i = 0; i < msg_size; i++)
143-
nn_writel(nn, NFP_NET_CFG_MBOX_VAL + 4 * i, msg->raw[i]);
144+
nn_writel(nn, offset + 4 * i, msg->raw[i]);
144145

145-
ret = nfp_net_mbox_reconfig(nn, NFP_NET_CFG_MBOX_CMD_IPSEC);
146-
if (ret < 0)
146+
ret = nfp_net_mbox_reconfig(nn, entry->cmd);
147+
if (ret < 0) {
148+
nn_ctrl_bar_unlock(nn);
147149
return ret;
150+
}
148151

149152
/* For now we always read the whole message response back */
150153
for (i = 0; i < msg_size; i++)
151-
msg->raw[i] = nn_readl(nn, NFP_NET_CFG_MBOX_VAL + 4 * i);
154+
msg->raw[i] = nn_readl(nn, offset + 4 * i);
155+
156+
nn_ctrl_bar_unlock(nn);
152157

153158
switch (msg->rsp) {
154159
case NFP_IPSEC_CFG_MSSG_OK:
@@ -477,7 +482,10 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x)
477482
}
478483

479484
/* Allocate saidx and commit the SA */
480-
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);
481489
if (err) {
482490
xa_erase(&nn->xa_ipsec, saidx);
483491
nn_err(nn, "Failed to issue IPsec command err ret=%d\n", err);
@@ -491,14 +499,17 @@ static int nfp_net_xfrm_add_state(struct xfrm_state *x)
491499

492500
static void nfp_net_xfrm_del_state(struct xfrm_state *x)
493501
{
502+
struct nfp_ipsec_cfg_mssg msg = {
503+
.cmd = NFP_IPSEC_CFG_MSSG_INV_SA,
504+
.sa_idx = x->xso.offload_handle - 1,
505+
};
494506
struct net_device *netdev = x->xso.dev;
495-
struct nfp_ipsec_cfg_mssg msg;
496507
struct nfp_net *nn;
497508
int err;
498509

499510
nn = netdev_priv(netdev);
500-
err = nfp_ipsec_cfg_cmd_issue(nn, NFP_IPSEC_CFG_MSSG_INV_SA,
501-
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);
502513
if (err)
503514
nn_warn(nn, "Failed to invalidate SA in hardware\n");
504515

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
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,6 @@
403403
*/
404404
#define NFP_NET_CFG_MBOX_BASE 0x1800
405405
#define NFP_NET_CFG_MBOX_VAL_MAX_SZ 0x1F8
406-
#define NFP_NET_CFG_MBOX_VAL 0x1808
407406
#define NFP_NET_CFG_MBOX_SIMPLE_CMD 0x0
408407
#define NFP_NET_CFG_MBOX_SIMPLE_RET 0x4
409408
#define NFP_NET_CFG_MBOX_SIMPLE_VAL 0x8

0 commit comments

Comments
 (0)