Skip to content

Commit

Permalink
Merge branch 'mlxsw-SPAN-cleanups'
Browse files Browse the repository at this point in the history
Jiri Pirko says:

====================
mlxsw: SPAN cleanups

In patch one of this short series, a misplaced pointer star is moved to
the correct place.

In the second patch, we observe that if SPAN entries carry their
reference count anyway, it's redundant to also carry a "used" flag.

In the third patch, SPAN support code is moved to a separate module.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 13, 2018
2 parents 439ccd8 + a629ef2 commit d520d58
Show file tree
Hide file tree
Showing 6 changed files with 433 additions and 351 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/mellanox/mlxsw/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_cnt.o spectrum_fid.o \
spectrum_ipip.o spectrum_acl_flex_actions.o \
spectrum_mr.o spectrum_mr_tcam.o \
spectrum_qdisc.o
spectrum_qdisc.o spectrum_span.o
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
mlxsw_spectrum-$(CONFIG_NET_DEVLINK) += spectrum_dpipe.o
obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o
Expand Down
322 changes: 1 addition & 321 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
#include "spectrum_cnt.h"
#include "spectrum_dpipe.h"
#include "spectrum_acl_flex_actions.h"
#include "spectrum_span.h"
#include "../mlxfw/mlxfw.h"

#define MLXSW_FWREV_MAJOR 13
Expand Down Expand Up @@ -487,327 +488,6 @@ static int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp)
return 0;
}

static int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
{
int i;

if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN))
return -EIO;

mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core,
MAX_SPAN);
mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count,
sizeof(struct mlxsw_sp_span_entry),
GFP_KERNEL);
if (!mlxsw_sp->span.entries)
return -ENOMEM;

for (i = 0; i < mlxsw_sp->span.entries_count; i++)
INIT_LIST_HEAD(&mlxsw_sp->span.entries[i].bound_ports_list);

return 0;
}

static void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp)
{
int i;

for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];

WARN_ON_ONCE(!list_empty(&curr->bound_ports_list));
}
kfree(mlxsw_sp->span.entries);
}

static struct mlxsw_sp_span_entry *
mlxsw_sp_span_entry_create(struct mlxsw_sp_port *port)
{
struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
struct mlxsw_sp_span_entry *span_entry;
char mpat_pl[MLXSW_REG_MPAT_LEN];
u8 local_port = port->local_port;
int index;
int i;
int err;

/* find a free entry to use */
index = -1;
for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
if (!mlxsw_sp->span.entries[i].used) {
index = i;
span_entry = &mlxsw_sp->span.entries[i];
break;
}
}
if (index < 0)
return NULL;

/* create a new port analayzer entry for local_port */
mlxsw_reg_mpat_pack(mpat_pl, index, local_port, true);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
if (err)
return NULL;

span_entry->used = true;
span_entry->id = index;
span_entry->ref_count = 1;
span_entry->local_port = local_port;
return span_entry;
}

static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_span_entry *span_entry)
{
u8 local_port = span_entry->local_port;
char mpat_pl[MLXSW_REG_MPAT_LEN];
int pa_id = span_entry->id;

mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
span_entry->used = false;
}

struct mlxsw_sp_span_entry *
mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port)
{
int i;

for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];

if (curr->used && curr->local_port == local_port)
return curr;
}
return NULL;
}

static struct mlxsw_sp_span_entry
*mlxsw_sp_span_entry_get(struct mlxsw_sp_port *port)
{
struct mlxsw_sp_span_entry *span_entry;

span_entry = mlxsw_sp_span_entry_find(port->mlxsw_sp,
port->local_port);
if (span_entry) {
/* Already exists, just take a reference */
span_entry->ref_count++;
return span_entry;
}

return mlxsw_sp_span_entry_create(port);
}

static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_span_entry *span_entry)
{
WARN_ON(!span_entry->ref_count);
if (--span_entry->ref_count == 0)
mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry);
return 0;
}

static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port)
{
struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
struct mlxsw_sp_span_inspected_port *p;
int i;

for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];

list_for_each_entry(p, &curr->bound_ports_list, list)
if (p->local_port == port->local_port &&
p->type == MLXSW_SP_SPAN_EGRESS)
return true;
}

return false;
}

static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp,
int mtu)
{
return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1;
}

static int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu)
{
struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
char sbib_pl[MLXSW_REG_SBIB_LEN];
int err;

/* If port is egress mirrored, the shared buffer size should be
* updated according to the mtu value
*/
if (mlxsw_sp_span_is_egress_mirror(port)) {
u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu);

mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
if (err) {
netdev_err(port->dev, "Could not update shared buffer for mirroring\n");
return err;
}
}

return 0;
}

static struct mlxsw_sp_span_inspected_port *
mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port,
struct mlxsw_sp_span_entry *span_entry)
{
struct mlxsw_sp_span_inspected_port *p;

list_for_each_entry(p, &span_entry->bound_ports_list, list)
if (port->local_port == p->local_port)
return p;
return NULL;
}

static int
mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port,
struct mlxsw_sp_span_entry *span_entry,
enum mlxsw_sp_span_type type,
bool bind)
{
struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
char mpar_pl[MLXSW_REG_MPAR_LEN];
int pa_id = span_entry->id;

/* bind the port to the SPAN entry */
mlxsw_reg_mpar_pack(mpar_pl, port->local_port,
(enum mlxsw_reg_mpar_i_e) type, bind, pa_id);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl);
}

static int
mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port,
struct mlxsw_sp_span_entry *span_entry,
enum mlxsw_sp_span_type type,
bool bind)
{
struct mlxsw_sp_span_inspected_port *inspected_port;
struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
char sbib_pl[MLXSW_REG_SBIB_LEN];
int err;

/* if it is an egress SPAN, bind a shared buffer to it */
if (type == MLXSW_SP_SPAN_EGRESS) {
u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp,
port->dev->mtu);

mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
if (err) {
netdev_err(port->dev, "Could not create shared buffer for mirroring\n");
return err;
}
}

if (bind) {
err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
true);
if (err)
goto err_port_bind;
}

inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL);
if (!inspected_port) {
err = -ENOMEM;
goto err_inspected_port_alloc;
}
inspected_port->local_port = port->local_port;
inspected_port->type = type;
list_add_tail(&inspected_port->list, &span_entry->bound_ports_list);

return 0;

err_inspected_port_alloc:
if (bind)
mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
false);
err_port_bind:
if (type == MLXSW_SP_SPAN_EGRESS) {
mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
}
return err;
}

static void
mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port,
struct mlxsw_sp_span_entry *span_entry,
enum mlxsw_sp_span_type type,
bool bind)
{
struct mlxsw_sp_span_inspected_port *inspected_port;
struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
char sbib_pl[MLXSW_REG_SBIB_LEN];

inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry);
if (!inspected_port)
return;

if (bind)
mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
false);
/* remove the SBIB buffer if it was egress SPAN */
if (type == MLXSW_SP_SPAN_EGRESS) {
mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
}

mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);

list_del(&inspected_port->list);
kfree(inspected_port);
}

int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
struct mlxsw_sp_port *to,
enum mlxsw_sp_span_type type, bool bind)
{
struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp;
struct mlxsw_sp_span_entry *span_entry;
int err;

span_entry = mlxsw_sp_span_entry_get(to);
if (!span_entry)
return -ENOENT;

netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n",
span_entry->id);

err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind);
if (err)
goto err_port_bind;

return 0;

err_port_bind:
mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
return err;
}

void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port,
enum mlxsw_sp_span_type type, bool bind)
{
struct mlxsw_sp_span_entry *span_entry;

span_entry = mlxsw_sp_span_entry_find(from->mlxsw_sp,
destination_port);
if (!span_entry) {
netdev_err(from->dev, "no span entry found\n");
return;
}

netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n",
span_entry->id);
mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind);
}

static int mlxsw_sp_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port,
bool enable, u32 rate)
{
Expand Down
30 changes: 1 addition & 29 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ enum mlxsw_sp_resource_id {

struct mlxsw_sp_port;
struct mlxsw_sp_rif;
struct mlxsw_sp_span_entry;

struct mlxsw_sp_upper {
struct net_device *dev;
Expand Down Expand Up @@ -111,25 +112,6 @@ struct mlxsw_sp_mid {
unsigned long *ports_in_mid; /* bits array */
};

enum mlxsw_sp_span_type {
MLXSW_SP_SPAN_EGRESS,
MLXSW_SP_SPAN_INGRESS
};

struct mlxsw_sp_span_inspected_port {
struct list_head list;
enum mlxsw_sp_span_type type;
u8 local_port;
};

struct mlxsw_sp_span_entry {
u8 local_port;
bool used;
struct list_head bound_ports_list;
int ref_count;
int id;
};

enum mlxsw_sp_port_mall_action_type {
MLXSW_SP_PORT_MALL_MIRROR,
MLXSW_SP_PORT_MALL_SAMPLE,
Expand Down Expand Up @@ -396,16 +378,6 @@ struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev);
struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port);
struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev);
int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
struct mlxsw_sp_port *to,
enum mlxsw_sp_span_type type,
bool bind);
void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from,
u8 destination_port,
enum mlxsw_sp_span_type type,
bool bind);
struct mlxsw_sp_span_entry *
mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port);

/* spectrum_dcb.c */
#ifdef CONFIG_MLXSW_SPECTRUM_DCB
Expand Down
Loading

0 comments on commit d520d58

Please sign in to comment.