Commit d0005e76 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'mlxsw-refactor-reference-counting-code'

Petr Machata says:

====================
mlxsw: Refactor reference counting code

Amit Cohen writes:

This set converts all reference counters defined as 'unsigned int' to
refcount_t type. The reference counting of LAGs can be simplified, so first
refactor the related code and then change the type of the reference
counter.

Patch set overview:
Patches #1-#4 are preparations for LAG refactor
Patch #5 refactors LAG code and change the type of reference counter
Patch #6 converts the remaining reference counters in mlxsw driver
====================

Link: https://lore.kernel.org/r/cover.1706293430.git.petrm@nvidia.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 4acf4e62 1267f722
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ struct mlxsw_afa_set {
		      */
	   has_trap:1,
	   has_police:1;
	unsigned int ref_count;
	refcount_t ref_count;
	struct mlxsw_afa_set *next; /* Pointer to the next set. */
	struct mlxsw_afa_set *prev; /* Pointer to the previous set,
				     * note that set may have multiple
@@ -120,7 +120,7 @@ struct mlxsw_afa_fwd_entry {
	struct rhash_head ht_node;
	struct mlxsw_afa_fwd_entry_ht_key ht_key;
	u32 kvdl_index;
	unsigned int ref_count;
	refcount_t ref_count;
};

static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = {
@@ -282,7 +282,7 @@ static struct mlxsw_afa_set *mlxsw_afa_set_create(bool is_first)
	/* Need to initialize the set to pass by default */
	mlxsw_afa_set_goto_set(set, MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0);
	set->ht_key.is_first = is_first;
	set->ref_count = 1;
	refcount_set(&set->ref_count, 1);
	return set;
}

@@ -330,7 +330,7 @@ static void mlxsw_afa_set_unshare(struct mlxsw_afa *mlxsw_afa,
static void mlxsw_afa_set_put(struct mlxsw_afa *mlxsw_afa,
			      struct mlxsw_afa_set *set)
{
	if (--set->ref_count)
	if (!refcount_dec_and_test(&set->ref_count))
		return;
	if (set->shared)
		mlxsw_afa_set_unshare(mlxsw_afa, set);
@@ -350,7 +350,7 @@ static struct mlxsw_afa_set *mlxsw_afa_set_get(struct mlxsw_afa *mlxsw_afa,
	set = rhashtable_lookup_fast(&mlxsw_afa->set_ht, &orig_set->ht_key,
				     mlxsw_afa_set_ht_params);
	if (set) {
		set->ref_count++;
		refcount_inc(&set->ref_count);
		mlxsw_afa_set_put(mlxsw_afa, orig_set);
	} else {
		set = orig_set;
@@ -564,7 +564,7 @@ mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u16 local_port)
	if (!fwd_entry)
		return ERR_PTR(-ENOMEM);
	fwd_entry->ht_key.local_port = local_port;
	fwd_entry->ref_count = 1;
	refcount_set(&fwd_entry->ref_count, 1);

	err = rhashtable_insert_fast(&mlxsw_afa->fwd_entry_ht,
				     &fwd_entry->ht_node,
@@ -607,7 +607,7 @@ mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port)
	fwd_entry = rhashtable_lookup_fast(&mlxsw_afa->fwd_entry_ht, &ht_key,
					   mlxsw_afa_fwd_entry_ht_params);
	if (fwd_entry) {
		fwd_entry->ref_count++;
		refcount_inc(&fwd_entry->ref_count);
		return fwd_entry;
	}
	return mlxsw_afa_fwd_entry_create(mlxsw_afa, local_port);
@@ -616,7 +616,7 @@ mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port)
static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa,
				    struct mlxsw_afa_fwd_entry *fwd_entry)
{
	if (--fwd_entry->ref_count)
	if (!refcount_dec_and_test(&fwd_entry->ref_count))
		return;
	mlxsw_afa_fwd_entry_destroy(mlxsw_afa, fwd_entry);
}
+5 −4
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/refcount.h>

#include "item.h"
#include "core_acl_flex_keys.h"
@@ -107,7 +108,7 @@ EXPORT_SYMBOL(mlxsw_afk_destroy);

struct mlxsw_afk_key_info {
	struct list_head list;
	unsigned int ref_count;
	refcount_t ref_count;
	unsigned int blocks_count;
	int element_to_block[MLXSW_AFK_ELEMENT_MAX]; /* index is element, value
						      * is index inside "blocks"
@@ -334,7 +335,7 @@ mlxsw_afk_key_info_create(struct mlxsw_afk *mlxsw_afk,
	if (err)
		goto err_picker;
	list_add(&key_info->list, &mlxsw_afk->key_info_list);
	key_info->ref_count = 1;
	refcount_set(&key_info->ref_count, 1);
	return key_info;

err_picker:
@@ -356,7 +357,7 @@ mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk,

	key_info = mlxsw_afk_key_info_find(mlxsw_afk, elusage);
	if (key_info) {
		key_info->ref_count++;
		refcount_inc(&key_info->ref_count);
		return key_info;
	}
	return mlxsw_afk_key_info_create(mlxsw_afk, elusage);
@@ -365,7 +366,7 @@ EXPORT_SYMBOL(mlxsw_afk_key_info_get);

void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info)
{
	if (--key_info->ref_count)
	if (!refcount_dec_and_test(&key_info->ref_count))
		return;
	mlxsw_afk_key_info_destroy(key_info);
}
+87 −73
Original line number Diff line number Diff line
@@ -2695,23 +2695,18 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp)
{
	char sgcr_pl[MLXSW_REG_SGCR_LEN];
	u16 max_lag;
	int err;

	if (mlxsw_core_lag_mode(mlxsw_sp->core) !=
	    MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW)
		return 0;

	err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
	if (err)
		return err;

	/* In DDD mode, which we by default use, each LAG entry is 8 PGT
	 * entries. The LAG table address needs to be 8-aligned, but that ought
	 * to be the case, since the LAG table is allocated first.
	 */
	err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &mlxsw_sp->lag_pgt_base,
					   max_lag * 8);
					   mlxsw_sp->max_lag * 8);
	if (err)
		return err;
	if (WARN_ON_ONCE(mlxsw_sp->lag_pgt_base % 8)) {
@@ -2728,33 +2723,31 @@ static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp)

err_mid_alloc_range:
	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base,
				    max_lag * 8);
				    mlxsw_sp->max_lag * 8);
	return err;
}

static void mlxsw_sp_lag_pgt_fini(struct mlxsw_sp *mlxsw_sp)
{
	u16 max_lag;
	int err;

	if (mlxsw_core_lag_mode(mlxsw_sp->core) !=
	    MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW)
		return;

	err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
	if (err)
		return;

	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base,
				    max_lag * 8);
				    mlxsw_sp->max_lag * 8);
}

#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe

struct mlxsw_sp_lag {
	struct net_device *dev;
	refcount_t ref_count;
	u16 lag_id;
};

static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
{
	char slcr_pl[MLXSW_REG_SLCR_LEN];
	u16 max_lag;
	u32 seed;
	int err;

@@ -2773,7 +2766,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
	if (err)
		return err;

	err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
	err = mlxsw_core_max_lag(mlxsw_sp->core, &mlxsw_sp->max_lag);
	if (err)
		return err;

@@ -2784,7 +2777,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
	if (err)
		return err;

	mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_upper),
	mlxsw_sp->lags = kcalloc(mlxsw_sp->max_lag, sizeof(struct mlxsw_sp_lag),
				 GFP_KERNEL);
	if (!mlxsw_sp->lags) {
		err = -ENOMEM;
@@ -4269,19 +4262,48 @@ mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port,
	}
}

static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
static struct mlxsw_sp_lag *
mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev,
		    struct netlink_ext_ack *extack)
{
	char sldr_pl[MLXSW_REG_SLDR_LEN];
	struct mlxsw_sp_lag *lag;
	u16 lag_id;
	int i, err;

	for (i = 0; i < mlxsw_sp->max_lag; i++) {
		if (!mlxsw_sp->lags[i].dev)
			break;
	}

	if (i == mlxsw_sp->max_lag) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Exceeded number of supported LAG devices");
		return ERR_PTR(-EBUSY);
	}

	lag_id = i;
	mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id);
	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
	if (err)
		return ERR_PTR(err);

	lag = &mlxsw_sp->lags[lag_id];
	lag->lag_id = lag_id;
	lag->dev = lag_dev;
	refcount_set(&lag->ref_count, 1);

	return lag;
}

static int mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
static int
mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag)
{
	char sldr_pl[MLXSW_REG_SLDR_LEN];

	mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag_id);
	lag->dev = NULL;

	mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag->lag_id);
	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
}

@@ -4329,34 +4351,44 @@ static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port,
	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
}

static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp,
				  struct net_device *lag_dev,
				  u16 *p_lag_id)
static struct mlxsw_sp_lag *
mlxsw_sp_lag_find(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev)
{
	struct mlxsw_sp_upper *lag;
	int free_lag_id = -1;
	u16 max_lag;
	int err, i;
	int i;

	err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
	if (err)
		return err;
	for (i = 0; i < mlxsw_sp->max_lag; i++) {
		if (!mlxsw_sp->lags[i].dev)
			continue;

	for (i = 0; i < max_lag; i++) {
		lag = mlxsw_sp_lag_get(mlxsw_sp, i);
		if (lag->ref_count) {
			if (lag->dev == lag_dev) {
				*p_lag_id = i;
				return 0;
		if (mlxsw_sp->lags[i].dev == lag_dev)
			return &mlxsw_sp->lags[i];
	}
		} else if (free_lag_id < 0) {
			free_lag_id = i;

	return NULL;
}

static struct mlxsw_sp_lag *
mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev,
		 struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_lag *lag;

	lag = mlxsw_sp_lag_find(mlxsw_sp, lag_dev);
	if (lag) {
		refcount_inc(&lag->ref_count);
		return lag;
	}
	if (free_lag_id < 0)
		return -EBUSY;
	*p_lag_id = free_lag_id;
	return 0;

	return mlxsw_sp_lag_create(mlxsw_sp, lag_dev, extack);
}

static void
mlxsw_sp_lag_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag)
{
	if (!refcount_dec_and_test(&lag->ref_count))
		return;

	mlxsw_sp_lag_destroy(mlxsw_sp, lag);
}

static bool
@@ -4365,12 +4397,6 @@ mlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp,
			  struct netdev_lag_upper_info *lag_upper_info,
			  struct netlink_ext_ack *extack)
{
	u16 lag_id;

	if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) {
		NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices");
		return false;
	}
	if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
		NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type");
		return false;
@@ -4482,22 +4508,16 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
				  struct netlink_ext_ack *extack)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	struct mlxsw_sp_upper *lag;
	struct mlxsw_sp_lag *lag;
	u16 lag_id;
	u8 port_index;
	int err;

	err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id);
	if (err)
		return err;
	lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id);
	if (!lag->ref_count) {
		err = mlxsw_sp_lag_create(mlxsw_sp, lag_id);
		if (err)
			return err;
		lag->dev = lag_dev;
	}
	lag = mlxsw_sp_lag_get(mlxsw_sp, lag_dev, extack);
	if (IS_ERR(lag))
		return PTR_ERR(lag);

	lag_id = lag->lag_id;
	err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index);
	if (err)
		return err;
@@ -4515,7 +4535,6 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
				   mlxsw_sp_port->local_port);
	mlxsw_sp_port->lag_id = lag_id;
	mlxsw_sp_port->lagged = 1;
	lag->ref_count++;

	err = mlxsw_sp_fid_port_join_lag(mlxsw_sp_port);
	if (err)
@@ -4542,7 +4561,6 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
err_router_join:
	mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port);
err_fid_port_join_lag:
	lag->ref_count--;
	mlxsw_sp_port->lagged = 0;
	mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,
				     mlxsw_sp_port->local_port);
@@ -4550,8 +4568,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
err_col_port_add:
	mlxsw_sp_lag_uppers_bridge_leave(mlxsw_sp_port, lag_dev);
err_lag_uppers_bridge_join:
	if (!lag->ref_count)
		mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
	mlxsw_sp_lag_put(mlxsw_sp, lag);
	return err;
}

@@ -4560,12 +4577,11 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	u16 lag_id = mlxsw_sp_port->lag_id;
	struct mlxsw_sp_upper *lag;
	struct mlxsw_sp_lag *lag;

	if (!mlxsw_sp_port->lagged)
		return;
	lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id);
	WARN_ON(lag->ref_count == 0);
	lag = &mlxsw_sp->lags[lag_id];

	mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);

@@ -4579,13 +4595,11 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,

	mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port);

	if (lag->ref_count == 1)
		mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
	mlxsw_sp_lag_put(mlxsw_sp, lag);

	mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,
				     mlxsw_sp_port->local_port);
	mlxsw_sp_port->lagged = 0;
	lag->ref_count--;

	/* Make sure untagged frames are allowed to ingress */
	mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID,
+3 −12
Original line number Diff line number Diff line
@@ -78,11 +78,6 @@ struct mlxsw_sp_span_entry;
enum mlxsw_sp_l3proto;
union mlxsw_sp_l3addr;

struct mlxsw_sp_upper {
	struct net_device *dev;
	unsigned int ref_count;
};

enum mlxsw_sp_rif_type {
	MLXSW_SP_RIF_TYPE_SUBPORT,
	MLXSW_SP_RIF_TYPE_VLAN,
@@ -136,6 +131,7 @@ struct mlxsw_sp_span_ops;
struct mlxsw_sp_qdisc_state;
struct mlxsw_sp_mall_entry;
struct mlxsw_sp_pgt;
struct mlxsw_sp_lag;

struct mlxsw_sp_port_mapping {
	u8 module;
@@ -164,7 +160,8 @@ struct mlxsw_sp {
	const struct mlxsw_bus_info *bus_info;
	unsigned char base_mac[ETH_ALEN];
	const unsigned char *mac_mask;
	struct mlxsw_sp_upper *lags;
	struct mlxsw_sp_lag *lags;
	u16 max_lag;
	struct mlxsw_sp_port_mapping *port_mapping;
	struct mlxsw_sp_port_mapping_events port_mapping_events;
	struct rhashtable sample_trigger_ht;
@@ -257,12 +254,6 @@ struct mlxsw_sp_fid_core_ops {
	void (*fini)(struct mlxsw_sp *mlxsw_sp);
};

static inline struct mlxsw_sp_upper *
mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
{
	return &mlxsw_sp->lags[lag_id];
}

struct mlxsw_sp_port_pcpu_stats {
	u64			rx_packets;
	u64			rx_bytes;
+6 −5
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/rhashtable.h>
#include <linux/netdevice.h>
#include <linux/mutex.h>
#include <linux/refcount.h>
#include <net/net_namespace.h>
#include <net/tc_act/tc_vlan.h>

@@ -55,7 +56,7 @@ struct mlxsw_sp_acl_ruleset {
	struct rhash_head ht_node; /* Member of acl HT */
	struct mlxsw_sp_acl_ruleset_ht_key ht_key;
	struct rhashtable rule_ht;
	unsigned int ref_count;
	refcount_t ref_count;
	unsigned int min_prio;
	unsigned int max_prio;
	unsigned long priv[];
@@ -99,7 +100,7 @@ static bool
mlxsw_sp_acl_ruleset_is_singular(const struct mlxsw_sp_acl_ruleset *ruleset)
{
	/* We hold a reference on ruleset ourselves */
	return ruleset->ref_count == 2;
	return refcount_read(&ruleset->ref_count) == 2;
}

int mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp,
@@ -176,7 +177,7 @@ mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp,
	ruleset = kzalloc(alloc_size, GFP_KERNEL);
	if (!ruleset)
		return ERR_PTR(-ENOMEM);
	ruleset->ref_count = 1;
	refcount_set(&ruleset->ref_count, 1);
	ruleset->ht_key.block = block;
	ruleset->ht_key.chain_index = chain_index;
	ruleset->ht_key.ops = ops;
@@ -222,13 +223,13 @@ static void mlxsw_sp_acl_ruleset_destroy(struct mlxsw_sp *mlxsw_sp,

static void mlxsw_sp_acl_ruleset_ref_inc(struct mlxsw_sp_acl_ruleset *ruleset)
{
	ruleset->ref_count++;
	refcount_inc(&ruleset->ref_count);
}

static void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp *mlxsw_sp,
					 struct mlxsw_sp_acl_ruleset *ruleset)
{
	if (--ruleset->ref_count)
	if (!refcount_dec_and_test(&ruleset->ref_count))
		return;
	mlxsw_sp_acl_ruleset_destroy(mlxsw_sp, ruleset);
}
Loading