Commit 159882f4 authored by David S. Miller's avatar David S. Miller

Merge branch 'nfp-flower-improve-flower-resilience'

Jakub Kicinski says:

====================
nfp: flower: improve flower resilience

This series contains mostly changes which improve nfp flower
offload's resilience, but are too large or risky to push into net.

Fred makes the driver waits for flower FW responses uninterruptible,
and a little longer (~40ms).

Pieter adds support for cards with multiple rule memories.

John reworks the MAC offloads.  He says:
> When potential tunnel end-point MACs are offloaded, they are assigned an
> index. This index may be associated with a port number meaning that if a
> packet matches an offloaded MAC address on the card, then the ingress
> port for that MAC can also be verified. In the case of shared MACs (e.g.
> on a linux bond) there may be situations where this index maps to only
> one of the ports that share the MAC.
>
> The idea of 'global' MAC indexes are supported that bypass the check on
> ingress port on the NFP. The patchset tracks shared MACs and assigns
> global indexes to these. It also ensures that port based indexes are
> re-applied if a single port becomes the only user of an offloaded MAC.
>
> Other patches in the set aim to tidy code without changing functionality.
> There is also a delete offload message introduced to ensure that MACs no
> longer in use in kernel space are removed from the firmware lookup tables.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bdbe8cc1 20cce886
......@@ -203,7 +203,7 @@ nfp_flower_cmsg_portreify_rx(struct nfp_app *app, struct sk_buff *skb)
}
atomic_inc(&priv->reify_replies);
wake_up_interruptible(&priv->reify_wait_queue);
wake_up(&priv->reify_wait_queue);
}
static void
......
......@@ -97,6 +97,9 @@
#define NFP_FLOWER_WORKQ_MAX_SKBS 30000
/* Cmesg reply (empirical) timeout*/
#define NFP_FL_REPLY_TIMEOUT msecs_to_jiffies(40)
#define nfp_flower_cmsg_warn(app, fmt, args...) \
do { \
if (net_ratelimit()) \
......
......@@ -32,6 +32,71 @@ static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app)
return DEVLINK_ESWITCH_MODE_SWITCHDEV;
}
static struct nfp_flower_non_repr_priv *
nfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev)
{
struct nfp_flower_priv *priv = app->priv;
struct nfp_flower_non_repr_priv *entry;
ASSERT_RTNL();
list_for_each_entry(entry, &priv->non_repr_priv, list)
if (entry->netdev == netdev)
return entry;
return NULL;
}
void
__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv)
{
non_repr_priv->ref_count++;
}
struct nfp_flower_non_repr_priv *
nfp_flower_non_repr_priv_get(struct nfp_app *app, struct net_device *netdev)
{
struct nfp_flower_priv *priv = app->priv;
struct nfp_flower_non_repr_priv *entry;
entry = nfp_flower_non_repr_priv_lookup(app, netdev);
if (entry)
goto inc_ref;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return NULL;
entry->netdev = netdev;
list_add(&entry->list, &priv->non_repr_priv);
inc_ref:
__nfp_flower_non_repr_priv_get(entry);
return entry;
}
void
__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv)
{
if (--non_repr_priv->ref_count)
return;
list_del(&non_repr_priv->list);
kfree(non_repr_priv);
}
void
nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev)
{
struct nfp_flower_non_repr_priv *entry;
entry = nfp_flower_non_repr_priv_lookup(app, netdev);
if (!entry)
return;
__nfp_flower_non_repr_priv_put(entry);
}
static enum nfp_repr_type
nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port)
{
......@@ -107,16 +172,14 @@ static int
nfp_flower_wait_repr_reify(struct nfp_app *app, atomic_t *replies, int tot_repl)
{
struct nfp_flower_priv *priv = app->priv;
int err;
if (!tot_repl)
return 0;
lockdep_assert_held(&app->pf->lock);
err = wait_event_interruptible_timeout(priv->reify_wait_queue,
atomic_read(replies) >= tot_repl,
msecs_to_jiffies(10));
if (err <= 0) {
if (!wait_event_timeout(priv->reify_wait_queue,
atomic_read(replies) >= tot_repl,
NFP_FL_REPLY_TIMEOUT)) {
nfp_warn(app->cpp, "Not all reprs responded to reify\n");
return -EIO;
}
......@@ -223,6 +286,7 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app,
nfp_repr = netdev_priv(repr);
nfp_repr->app_priv = repr_priv;
repr_priv->nfp_repr = nfp_repr;
/* For now we only support 1 PF */
WARN_ON(repr_type == NFP_REPR_TYPE_PF && i);
......@@ -337,6 +401,7 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv)
nfp_repr = netdev_priv(repr);
nfp_repr->app_priv = repr_priv;
repr_priv->nfp_repr = nfp_repr;
port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, repr);
if (IS_ERR(port)) {
......@@ -476,8 +541,8 @@ static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn)
static int nfp_flower_init(struct nfp_app *app)
{
u64 version, features, ctx_count, num_mems;
const struct nfp_pf *pf = app->pf;
u64 version, features, ctx_count;
struct nfp_flower_priv *app_priv;
int err;
......@@ -502,6 +567,23 @@ static int nfp_flower_init(struct nfp_app *app)
return err;
}
num_mems = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_SPLIT",
&err);
if (err) {
nfp_warn(app->cpp,
"FlowerNIC: unsupported host context memory: %d\n",
err);
err = 0;
num_mems = 1;
}
if (!FIELD_FIT(NFP_FL_STAT_ID_MU_NUM, num_mems) || !num_mems) {
nfp_warn(app->cpp,
"FlowerNIC: invalid host context memory: %llu\n",
num_mems);
return -EINVAL;
}
ctx_count = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_COUNT",
&err);
if (err) {
......@@ -522,6 +604,8 @@ static int nfp_flower_init(struct nfp_app *app)
if (!app_priv)
return -ENOMEM;
app_priv->total_mem_units = num_mems;
app_priv->active_mem_unit = 0;
app_priv->stats_ring_size = roundup_pow_of_two(ctx_count);
app->priv = app_priv;
app_priv->app = app;
......@@ -533,7 +617,7 @@ static int nfp_flower_init(struct nfp_app *app)
init_waitqueue_head(&app_priv->mtu_conf.wait_q);
spin_lock_init(&app_priv->mtu_conf.lock);
err = nfp_flower_metadata_init(app, ctx_count);
err = nfp_flower_metadata_init(app, ctx_count, num_mems);
if (err)
goto err_free_app_priv;
......@@ -558,6 +642,7 @@ static int nfp_flower_init(struct nfp_app *app)
}
INIT_LIST_HEAD(&app_priv->indr_block_cb_priv);
INIT_LIST_HEAD(&app_priv->non_repr_priv);
return 0;
......@@ -601,7 +686,7 @@ nfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev,
{
struct nfp_flower_priv *app_priv = app->priv;
struct nfp_repr *repr = netdev_priv(netdev);
int err, ack;
int err;
/* Only need to config FW for physical port MTU change. */
if (repr->port->type != NFP_PORT_PHYS_PORT)
......@@ -628,11 +713,9 @@ nfp_flower_repr_change_mtu(struct nfp_app *app, struct net_device *netdev,
}
/* Wait for fw to ack the change. */
ack = wait_event_timeout(app_priv->mtu_conf.wait_q,
nfp_flower_check_ack(app_priv),
msecs_to_jiffies(10));
if (!ack) {
if (!wait_event_timeout(app_priv->mtu_conf.wait_q,
nfp_flower_check_ack(app_priv),
NFP_FL_REPLY_TIMEOUT)) {
spin_lock_bh(&app_priv->mtu_conf.lock);
app_priv->mtu_conf.requested_val = 0;
spin_unlock_bh(&app_priv->mtu_conf.lock);
......
......@@ -20,6 +20,9 @@ struct nfp_fl_pre_lag;
struct net_device;
struct nfp_app;
#define NFP_FL_STAT_ID_MU_NUM GENMASK(31, 22)
#define NFP_FL_STAT_ID_STAT GENMASK(21, 0)
#define NFP_FL_STATS_ELEM_RS FIELD_SIZEOF(struct nfp_fl_stats_id, \
init_unalloc)
#define NFP_FLOWER_MASK_ENTRY_RS 256
......@@ -53,6 +56,26 @@ struct nfp_fl_stats_id {
u8 repeated_em_count;
};
/**
* struct nfp_fl_tunnel_offloads - priv data for tunnel offloads
* @offloaded_macs: Hashtable of the offloaded MAC addresses
* @ipv4_off_list: List of IPv4 addresses to offload
* @neigh_off_list: List of neighbour offloads
* @ipv4_off_lock: Lock for the IPv4 address list
* @neigh_off_lock: Lock for the neighbour address list
* @mac_off_ids: IDA to manage id assignment for offloaded MACs
* @neigh_nb: Notifier to monitor neighbour state
*/
struct nfp_fl_tunnel_offloads {
struct rhashtable offloaded_macs;
struct list_head ipv4_off_list;
struct list_head neigh_off_list;
struct mutex ipv4_off_lock;
spinlock_t neigh_off_lock;
struct ida mac_off_ids;
struct notifier_block neigh_nb;
};
/**
* struct nfp_mtu_conf - manage MTU setting
* @portnum: NFP port number of repr with requested MTU change
......@@ -113,23 +136,16 @@ struct nfp_fl_lag {
* processing
* @cmsg_skbs_low: List of lower priority skbs for control message
* processing
* @nfp_mac_off_list: List of MAC addresses to offload
* @nfp_mac_index_list: List of unique 8-bit indexes for non NFP netdevs
* @nfp_ipv4_off_list: List of IPv4 addresses to offload
* @nfp_neigh_off_list: List of neighbour offloads
* @nfp_mac_off_lock: Lock for the MAC address list
* @nfp_mac_index_lock: Lock for the MAC index list
* @nfp_ipv4_off_lock: Lock for the IPv4 address list
* @nfp_neigh_off_lock: Lock for the neighbour address list
* @nfp_mac_off_ids: IDA to manage id assignment for offloaded macs
* @nfp_mac_off_count: Number of MACs in address list
* @nfp_tun_neigh_nb: Notifier to monitor neighbour state
* @tun: Tunnel offload data
* @reify_replies: atomically stores the number of replies received
* from firmware for repr reify
* @reify_wait_queue: wait queue for repr reify response counting
* @mtu_conf: Configuration of repr MTU value
* @nfp_lag: Link aggregation data block
* @indr_block_cb_priv: List of priv data passed to indirect block cbs
* @non_repr_priv: List of offloaded non-repr ports and their priv data
* @active_mem_unit: Current active memory unit for flower rules
* @total_mem_units: Total number of available memory units for flower rules
*/
struct nfp_flower_priv {
struct nfp_app *app;
......@@ -147,30 +163,47 @@ struct nfp_flower_priv {
struct work_struct cmsg_work;
struct sk_buff_head cmsg_skbs_high;
struct sk_buff_head cmsg_skbs_low;
struct list_head nfp_mac_off_list;
struct list_head nfp_mac_index_list;
struct list_head nfp_ipv4_off_list;
struct list_head nfp_neigh_off_list;
struct mutex nfp_mac_off_lock;
struct mutex nfp_mac_index_lock;
struct mutex nfp_ipv4_off_lock;
spinlock_t nfp_neigh_off_lock;
struct ida nfp_mac_off_ids;
int nfp_mac_off_count;
struct notifier_block nfp_tun_neigh_nb;
struct nfp_fl_tunnel_offloads tun;
atomic_t reify_replies;
wait_queue_head_t reify_wait_queue;
struct nfp_mtu_conf mtu_conf;
struct nfp_fl_lag nfp_lag;
struct list_head indr_block_cb_priv;
struct list_head non_repr_priv;
unsigned int active_mem_unit;
unsigned int total_mem_units;
};
/**
* struct nfp_flower_repr_priv - Flower APP per-repr priv data
* @nfp_repr: Back pointer to nfp_repr
* @lag_port_flags: Extended port flags to record lag state of repr
* @mac_offloaded: Flag indicating a MAC address is offloaded for repr
* @offloaded_mac_addr: MAC address that has been offloaded for repr
* @mac_list: List entry of reprs that share the same offloaded MAC
*/
struct nfp_flower_repr_priv {
struct nfp_repr *nfp_repr;
unsigned long lag_port_flags;
bool mac_offloaded;
u8 offloaded_mac_addr[ETH_ALEN];
struct list_head mac_list;
};
/**
* struct nfp_flower_non_repr_priv - Priv data for non-repr offloaded ports
* @list: List entry of offloaded reprs
* @netdev: Pointer to non-repr net_device
* @ref_count: Number of references held for this priv data
* @mac_offloaded: Flag indicating a MAC address is offloaded for device
* @offloaded_mac_addr: MAC address that has been offloaded for dev
*/
struct nfp_flower_non_repr_priv {
struct list_head list;
struct net_device *netdev;
int ref_count;
bool mac_offloaded;
u8 offloaded_mac_addr[ETH_ALEN];
};
struct nfp_fl_key_ls {
......@@ -217,7 +250,8 @@ struct nfp_fl_stats_frame {
__be64 stats_cookie;
};
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count);
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
unsigned int host_ctx_split);
void nfp_flower_metadata_cleanup(struct nfp_app *app);
int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev,
......@@ -252,7 +286,6 @@ void nfp_tunnel_config_stop(struct nfp_app *app);
int nfp_tunnel_mac_event_handler(struct nfp_app *app,
struct net_device *netdev,
unsigned long event, void *ptr);
void nfp_tunnel_write_macs(struct nfp_app *app);
void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4);
void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4);
void nfp_tunnel_request_route(struct nfp_app *app, struct sk_buff *skb);
......@@ -273,4 +306,12 @@ int nfp_flower_reg_indir_block_handler(struct nfp_app *app,
struct net_device *netdev,
unsigned long event);
void
__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv);
struct nfp_flower_non_repr_priv *
nfp_flower_non_repr_priv_get(struct nfp_app *app, struct net_device *netdev);
void
__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv);
void
nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev);
#endif
......@@ -403,9 +403,6 @@ int nfp_flower_compile_flow_match(struct nfp_app *app,
ext += sizeof(struct nfp_flower_ipv4_udp_tun);
msk += sizeof(struct nfp_flower_ipv4_udp_tun);
/* Configure tunnel end point MAC. */
nfp_tunnel_write_macs(app);
/* Store the tunnel destination in the rule data.
* This must be present and be an exact match.
*/
......
......@@ -4,6 +4,7 @@
#include <linux/hash.h>
#include <linux/hashtable.h>
#include <linux/jhash.h>
#include <linux/math64.h>
#include <linux/vmalloc.h>
#include <net/pkt_cls.h>
......@@ -52,8 +53,17 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id)
freed_stats_id = priv->stats_ring_size;
/* Check for unallocated entries first. */
if (priv->stats_ids.init_unalloc > 0) {
*stats_context_id = priv->stats_ids.init_unalloc - 1;
priv->stats_ids.init_unalloc--;
if (priv->active_mem_unit == priv->total_mem_units) {
priv->stats_ids.init_unalloc--;
priv->active_mem_unit = 0;
}
*stats_context_id =
FIELD_PREP(NFP_FL_STAT_ID_STAT,
priv->stats_ids.init_unalloc - 1) |
FIELD_PREP(NFP_FL_STAT_ID_MU_NUM,
priv->active_mem_unit);
priv->active_mem_unit++;
return 0;
}
......@@ -381,10 +391,11 @@ const struct rhashtable_params nfp_flower_table_params = {
.automatic_shrinking = true,
};
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count)
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
unsigned int host_num_mems)
{
struct nfp_flower_priv *priv = app->priv;
int err;
int err, stats_size;
hash_init(priv->mask_table);
......@@ -417,10 +428,12 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count)
if (!priv->stats_ids.free_list.buf)
goto err_free_last_used;
priv->stats_ids.init_unalloc = host_ctx_count;
priv->stats_ids.init_unalloc = div_u64(host_ctx_count, host_num_mems);
priv->stats = kvmalloc_array(priv->stats_ring_size,
sizeof(struct nfp_fl_stats), GFP_KERNEL);
stats_size = FIELD_PREP(NFP_FL_STAT_ID_STAT, host_ctx_count) |
FIELD_PREP(NFP_FL_STAT_ID_MU_NUM, host_num_mems - 1);
priv->stats = kvmalloc_array(stats_size, sizeof(struct nfp_fl_stats),
GFP_KERNEL);
if (!priv->stats)
goto err_free_ring_buf;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment