Skip to content

Commit

Permalink
nfp: add a mutex lock for the vNIC ctrl BAR
Browse files Browse the repository at this point in the history
Soon we will try to write to the vNIC mailbox without RTNL held.
Add a new mutex to protect access to specific parts of the PCI
control BAR.

Move the mailbox size checking to the mailbox lock() helper, where
it can be more effective (happen prior to potential overwrite of
other data).

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jakub Kicinski authored and David S. Miller committed Apr 13, 2019
1 parent e647182 commit dd5b249
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 23 deletions.
8 changes: 6 additions & 2 deletions drivers/net/ethernet/netronome/nfp/abm/ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,15 @@ int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm)

int nfp_abm_ctrl_prio_map_update(struct nfp_abm_link *alink, u32 *packed)
{
const u32 cmd = NFP_NET_CFG_MBOX_CMD_PCI_DSCP_PRIOMAP_SET;
struct nfp_net *nn = alink->vnic;
unsigned int i;
int err;

err = nfp_net_mbox_lock(nn, alink->abm->prio_map_len);
if (err)
return err;

/* Write data_len and wipe reserved */
nn_writeq(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATALEN,
alink->abm->prio_map_len);
Expand All @@ -273,8 +278,7 @@ int nfp_abm_ctrl_prio_map_update(struct nfp_abm_link *alink, u32 *packed)
nn_writel(nn, nn->tlv_caps.mbox_off + NFP_NET_ABM_MBOX_DATA + i,
packed[i / sizeof(u32)]);

err = nfp_net_reconfig_mbox(nn,
NFP_NET_CFG_MBOX_CMD_PCI_DSCP_PRIOMAP_SET);
err = nfp_net_mbox_reconfig_and_unlock(nn, cmd);
if (err)
nfp_err(alink->abm->app->cpp,
"setting DSCP -> VQ map failed with error %d\n", err);
Expand Down
23 changes: 21 additions & 2 deletions drivers/net/ethernet/netronome/nfp/nfp_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,12 +539,17 @@ struct nfp_net_dp {
* @shared_handler: Handler for shared interrupts
* @shared_name: Name for shared interrupt
* @me_freq_mhz: ME clock_freq (MHz)
* @reconfig_lock: Protects HW reconfiguration request regs/machinery
* @reconfig_lock: Protects @reconfig_posted, @reconfig_timer_active,
* @reconfig_sync_present and HW reconfiguration request
* regs/machinery from async requests (sync must take
* @bar_lock)
* @reconfig_posted: Pending reconfig bits coming from async sources
* @reconfig_timer_active: Timer for reading reconfiguration results is pending
* @reconfig_sync_present: Some thread is performing synchronous reconfig
* @reconfig_timer: Timer for async reading of reconfig results
* @reconfig_in_progress_update: Update FW is processing now (debug only)
* @bar_lock: vNIC config BAR access lock, protects: update,
* mailbox area
* @link_up: Is the link up?
* @link_status_lock: Protects @link_* and ensures atomicity with BAR reading
* @rx_coalesce_usecs: RX interrupt moderation usecs delay parameter
Expand Down Expand Up @@ -615,6 +620,8 @@ struct nfp_net {
struct timer_list reconfig_timer;
u32 reconfig_in_progress_update;

struct mutex bar_lock;

u32 rx_coalesce_usecs;
u32 rx_coalesce_max_frames;
u32 tx_coalesce_usecs;
Expand Down Expand Up @@ -839,6 +846,16 @@ static inline void nfp_ctrl_unlock(struct nfp_net *nn)
spin_unlock_bh(&nn->r_vecs[0].lock);
}

static inline void nn_ctrl_bar_lock(struct nfp_net *nn)
{
mutex_lock(&nn->bar_lock);
}

static inline void nn_ctrl_bar_unlock(struct nfp_net *nn)
{
mutex_unlock(&nn->bar_lock);
}

/* Globals */
extern const char nfp_driver_version[];

Expand Down Expand Up @@ -871,7 +888,9 @@ unsigned int nfp_net_rss_key_sz(struct nfp_net *nn);
void nfp_net_rss_write_itbl(struct nfp_net *nn);
void nfp_net_rss_write_key(struct nfp_net *nn);
void nfp_net_coalesce_write_cfg(struct nfp_net *nn);
int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd);
int nfp_net_mbox_lock(struct nfp_net *nn, unsigned int data_size);
int nfp_net_mbox_reconfig(struct nfp_net *nn, u32 mbox_cmd);
int nfp_net_mbox_reconfig_and_unlock(struct nfp_net *nn, u32 mbox_cmd);

unsigned int
nfp_net_irqs_alloc(struct pci_dev *pdev, struct msix_entry *irq_entries,
Expand Down
72 changes: 60 additions & 12 deletions drivers/net/ethernet/netronome/nfp/nfp_net_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/lockdep.h>
#include <linux/mm.h>
#include <linux/overflow.h>
#include <linux/page_ref.h>
Expand Down Expand Up @@ -260,7 +261,7 @@ static void nfp_net_reconfig_wait_posted(struct nfp_net *nn)
}

/**
* nfp_net_reconfig() - Reconfigure the firmware
* __nfp_net_reconfig() - Reconfigure the firmware
* @nn: NFP Net device to reconfigure
* @update: The value for the update field in the BAR config
*
Expand All @@ -270,10 +271,12 @@ static void nfp_net_reconfig_wait_posted(struct nfp_net *nn)
*
* Return: Negative errno on error, 0 on success
*/
int nfp_net_reconfig(struct nfp_net *nn, u32 update)
static int __nfp_net_reconfig(struct nfp_net *nn, u32 update)
{
int ret;

lockdep_assert_held(&nn->bar_lock);

nfp_net_reconfig_sync_enter(nn);

nfp_net_reconfig_start(nn, update);
Expand All @@ -291,28 +294,47 @@ int nfp_net_reconfig(struct nfp_net *nn, u32 update)
return ret;
}

int nfp_net_reconfig(struct nfp_net *nn, u32 update)
{
int ret;

nn_ctrl_bar_lock(nn);
ret = __nfp_net_reconfig(nn, update);
nn_ctrl_bar_unlock(nn);

return ret;
}

int nfp_net_mbox_lock(struct nfp_net *nn, unsigned int data_size)
{
if (nn->tlv_caps.mbox_len < NFP_NET_CFG_MBOX_SIMPLE_VAL + data_size) {
nn_err(nn, "mailbox too small for %u of data (%u)\n",
data_size, nn->tlv_caps.mbox_len);
return -EIO;
}

nn_ctrl_bar_lock(nn);
return 0;
}

/**
* nfp_net_reconfig_mbox() - Reconfigure the firmware via the mailbox
* nfp_net_mbox_reconfig() - Reconfigure the firmware via the mailbox
* @nn: NFP Net device to reconfigure
* @mbox_cmd: The value for the mailbox command
*
* Helper function for mailbox updates
*
* Return: Negative errno on error, 0 on success
*/
int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd)
int nfp_net_mbox_reconfig(struct nfp_net *nn, u32 mbox_cmd)
{
u32 mbox = nn->tlv_caps.mbox_off;
int ret;

if (!nfp_net_has_mbox(&nn->tlv_caps)) {
nn_err(nn, "no mailbox present, command: %u\n", mbox_cmd);
return -EIO;
}

lockdep_assert_held(&nn->bar_lock);
nn_writeq(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_CMD, mbox_cmd);

ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MBOX);
ret = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MBOX);
if (ret) {
nn_err(nn, "Mailbox update error\n");
return ret;
Expand All @@ -321,6 +343,15 @@ int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd)
return -nn_readl(nn, mbox + NFP_NET_CFG_MBOX_SIMPLE_RET);
}

int nfp_net_mbox_reconfig_and_unlock(struct nfp_net *nn, u32 mbox_cmd)
{
int ret;

ret = nfp_net_mbox_reconfig(nn, mbox_cmd);
nn_ctrl_bar_unlock(nn);
return ret;
}

/* Interrupt configuration and handling
*/

Expand Down Expand Up @@ -3128,37 +3159,49 @@ static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu)
static int
nfp_net_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
const u32 cmd = NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD;
struct nfp_net *nn = netdev_priv(netdev);
int err;

/* Priority tagged packets with vlan id 0 are processed by the
* NFP as untagged packets
*/
if (!vid)
return 0;

err = nfp_net_mbox_lock(nn, NFP_NET_CFG_VLAN_FILTER_SZ);
if (err)
return err;

nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_VID, vid);
nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_PROTO,
ETH_P_8021Q);

return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD);
return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
}

static int
nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
const u32 cmd = NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL;
struct nfp_net *nn = netdev_priv(netdev);
int err;

/* Priority tagged packets with vlan id 0 are processed by the
* NFP as untagged packets
*/
if (!vid)
return 0;

err = nfp_net_mbox_lock(nn, NFP_NET_CFG_VLAN_FILTER_SZ);
if (err)
return err;

nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_VID, vid);
nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_VLAN_FILTER_PROTO,
ETH_P_8021Q);

return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL);
return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
}

static void nfp_net_stat64(struct net_device *netdev,
Expand Down Expand Up @@ -3650,6 +3693,8 @@ nfp_net_alloc(struct pci_dev *pdev, void __iomem *ctrl_bar, bool needs_netdev,
nn->dp.txd_cnt = NFP_NET_TX_DESCS_DEFAULT;
nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT;

mutex_init(&nn->bar_lock);

spin_lock_init(&nn->reconfig_lock);
spin_lock_init(&nn->link_status_lock);

Expand Down Expand Up @@ -3677,6 +3722,9 @@ nfp_net_alloc(struct pci_dev *pdev, void __iomem *ctrl_bar, bool needs_netdev,
void nfp_net_free(struct nfp_net *nn)
{
WARN_ON(timer_pending(&nn->reconfig_timer) || nn->reconfig_posted);

mutex_destroy(&nn->bar_lock);

if (nn->dp.netdev)
free_netdev(nn->dp.netdev);
else
Expand Down
7 changes: 0 additions & 7 deletions drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,6 @@
#define NFP_NET_CFG_MBOX_SIMPLE_CMD 0x0
#define NFP_NET_CFG_MBOX_SIMPLE_RET 0x4
#define NFP_NET_CFG_MBOX_SIMPLE_VAL 0x8
#define NFP_NET_CFG_MBOX_SIMPLE_LEN 12

#define NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD 1
#define NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL 2
Expand Down Expand Up @@ -495,10 +494,4 @@ struct nfp_net_tlv_caps {

int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
struct nfp_net_tlv_caps *caps);

static inline bool nfp_net_has_mbox(struct nfp_net_tlv_caps *caps)
{
return caps->mbox_len >= NFP_NET_CFG_MBOX_SIMPLE_LEN;
}

#endif /* _NFP_NET_CTRL_H_ */

0 comments on commit dd5b249

Please sign in to comment.