Commit e43ea83c authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-dsa-replace-routing-tables-with-a-list'



Vivien Didelot says:

====================
net: dsa: replace routing tables with a list

This branch gets rid of the ds->rtable static arrays in favor of
a single dst->rtable list. This allows us to move away from the
DSA_MAX_SWITCHES limitation and simplify the switch fabric setup.

Changes in v2:
  - fix the reverse christmas for David
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5c26c1d6 fcee85f1
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -1143,6 +1143,7 @@ static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)

static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
{
	struct dsa_switch *ds = chip->ds;
	int target, port;
	int err;

@@ -1151,10 +1152,9 @@ static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)

	/* Initialize the routing port to the 32 possible target devices */
	for (target = 0; target < 32; target++) {
		port = dsa_routing_port(ds, target);
		if (port == ds->num_ports)
			port = 0x1f;
		if (target < DSA_MAX_SWITCHES)
			if (chip->ds->rtable[target] != DSA_RTABLE_NONE)
				port = chip->ds->rtable[target];

		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
		if (err)
+27 −12
Original line number Diff line number Diff line
@@ -123,10 +123,8 @@ struct dsa_switch_tree {
	/* List of switch ports */
	struct list_head ports;

	/*
	 * Data for the individual switch chips.
	 */
	struct dsa_switch	*ds[DSA_MAX_SWITCHES];
	/* List of DSA links composing the routing table */
	struct list_head rtable;
};

/* TC matchall action types, only mirroring for now */
@@ -214,6 +212,17 @@ struct dsa_port {
	bool setup;
};

/* TODO: ideally DSA ports would have a single dp->link_dp member,
 * and no dst->rtable nor this struct dsa_link would be needed,
 * but this would require some more complex tree walking,
 * so keep it stupid at the moment and list them all.
 */
struct dsa_link {
	struct dsa_port *dp;
	struct dsa_port *link_dp;
	struct list_head list;
};

struct dsa_switch {
	bool setup;

@@ -244,13 +253,6 @@ struct dsa_switch {
	 */
	const struct dsa_switch_ops	*ops;

	/*
	 * An array of which element [a] indicates which port on this
	 * switch should be used to send packets to that are destined
	 * for switch a. Can be NULL if there is only one switch chip.
	 */
	s8		rtable[DSA_MAX_SWITCHES];

	/*
	 * Slave mii_bus and devices for the individual ports.
	 */
@@ -324,6 +326,19 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds)
	return mask;
}

/* Return the local port used to reach an arbitrary switch device */
static inline unsigned int dsa_routing_port(struct dsa_switch *ds, int device)
{
	struct dsa_switch_tree *dst = ds->dst;
	struct dsa_link *dl;

	list_for_each_entry(dl, &dst->rtable, list)
		if (dl->dp->ds == ds && dl->link_dp->ds->index == device)
			return dl->dp->index;

	return ds->num_ports;
}

/* Return the local port used to reach an arbitrary switch port */
static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device,
					    int port)
@@ -331,7 +346,7 @@ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device,
	if (device == ds->index)
		return port;
	else
		return ds->rtable[device];
		return dsa_routing_port(ds, device);
}

/* Return the local port used to reach the dedicated CPU port */
+52 −69
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index)

	dst->index = index;

	INIT_LIST_HEAD(&dst->rtable);

	INIT_LIST_HEAD(&dst->ports);

	INIT_LIST_HEAD(&dst->list);
@@ -122,6 +124,31 @@ static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst,
	return NULL;
}

struct dsa_link *dsa_link_touch(struct dsa_port *dp, struct dsa_port *link_dp)
{
	struct dsa_switch *ds = dp->ds;
	struct dsa_switch_tree *dst;
	struct dsa_link *dl;

	dst = ds->dst;

	list_for_each_entry(dl, &dst->rtable, list)
		if (dl->dp == dp && dl->link_dp == link_dp)
			return dl;

	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
	if (!dl)
		return NULL;

	dl->dp = dp;
	dl->link_dp = link_dp;

	INIT_LIST_HEAD(&dl->list);
	list_add_tail(&dl->list, &dst->rtable);

	return dl;
}

static bool dsa_port_setup_routing_table(struct dsa_port *dp)
{
	struct dsa_switch *ds = dp->ds;
@@ -129,6 +156,7 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp)
	struct device_node *dn = dp->dn;
	struct of_phandle_iterator it;
	struct dsa_port *link_dp;
	struct dsa_link *dl;
	int err;

	of_for_each_phandle(&it, err, dn, "link", NULL, 0) {
@@ -138,24 +166,23 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp)
			return false;
		}

		ds->rtable[link_dp->ds->index] = dp->index;
		dl = dsa_link_touch(dp, link_dp);
		if (!dl) {
			of_node_put(it.node);
			return false;
		}
	}

	return true;
}

static bool dsa_switch_setup_routing_table(struct dsa_switch *ds)
static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst)
{
	struct dsa_switch_tree *dst = ds->dst;
	bool complete = true;
	struct dsa_port *dp;
	int i;

	for (i = 0; i < DSA_MAX_SWITCHES; i++)
		ds->rtable[i] = DSA_RTABLE_NONE;

	list_for_each_entry(dp, &dst->ports, list) {
		if (dp->ds == ds && dsa_port_is_dsa(dp)) {
		if (dsa_port_is_dsa(dp)) {
			complete = dsa_port_setup_routing_table(dp);
			if (!complete)
				break;
@@ -165,25 +192,6 @@ static bool dsa_switch_setup_routing_table(struct dsa_switch *ds)
	return complete;
}

static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst)
{
	struct dsa_switch *ds;
	bool complete = true;
	int device;

	for (device = 0; device < DSA_MAX_SWITCHES; device++) {
		ds = dst->ds[device];
		if (!ds)
			continue;

		complete = dsa_switch_setup_routing_table(ds);
		if (!complete)
			break;
	}

	return complete;
}

static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
{
	struct dsa_port *dp;
@@ -544,6 +552,8 @@ teardown_default_cpu:

static void dsa_tree_teardown(struct dsa_switch_tree *dst)
{
	struct dsa_link *dl, *next;

	if (!dst->setup)
		return;

@@ -553,39 +563,14 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst)

	dsa_tree_teardown_default_cpu(dst);

	pr_info("DSA: tree %d torn down\n", dst->index);

	dst->setup = false;
	list_for_each_entry_safe(dl, next, &dst->rtable, list) {
		list_del(&dl->list);
		kfree(dl);
	}

static void dsa_tree_remove_switch(struct dsa_switch_tree *dst,
				   unsigned int index)
{
	dsa_tree_teardown(dst);

	dst->ds[index] = NULL;
	dsa_tree_put(dst);
}

static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
			       struct dsa_switch *ds)
{
	unsigned int index = ds->index;
	int err;

	if (dst->ds[index])
		return -EBUSY;

	dsa_tree_get(dst);
	dst->ds[index] = ds;

	err = dsa_tree_setup(dst);
	if (err) {
		dst->ds[index] = NULL;
		dsa_tree_put(dst);
	}
	pr_info("DSA: tree %d torn down\n", dst->index);

	return err;
	dst->setup = false;
}

static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
@@ -726,8 +711,6 @@ static int dsa_switch_parse_member_of(struct dsa_switch *ds,
		return sz;

	ds->index = m[1];
	if (ds->index >= DSA_MAX_SWITCHES)
		return -EINVAL;

	ds->dst = dsa_tree_touch(m[0]);
	if (!ds->dst)
@@ -838,15 +821,9 @@ static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd)
	return dsa_switch_parse_ports(ds, cd);
}

static int dsa_switch_add(struct dsa_switch *ds)
{
	struct dsa_switch_tree *dst = ds->dst;

	return dsa_tree_add_switch(dst, ds);
}

static int dsa_switch_probe(struct dsa_switch *ds)
{
	struct dsa_switch_tree *dst;
	struct dsa_chip_data *pdata;
	struct device_node *np;
	int err;
@@ -870,7 +847,13 @@ static int dsa_switch_probe(struct dsa_switch *ds)
	if (err)
		return err;

	return dsa_switch_add(ds);
	dst = ds->dst;
	dsa_tree_get(dst);
	err = dsa_tree_setup(dst);
	if (err)
		dsa_tree_put(dst);

	return err;
}

int dsa_register_switch(struct dsa_switch *ds)
@@ -889,7 +872,6 @@ EXPORT_SYMBOL_GPL(dsa_register_switch);
static void dsa_switch_remove(struct dsa_switch *ds)
{
	struct dsa_switch_tree *dst = ds->dst;
	unsigned int index = ds->index;
	struct dsa_port *dp, *next;

	list_for_each_entry_safe(dp, next, &dst->ports, list) {
@@ -897,7 +879,8 @@ static void dsa_switch_remove(struct dsa_switch *ds)
		kfree(dp);
	}

	dsa_tree_remove_switch(dst, index);
	dsa_tree_teardown(dst);
	dsa_tree_put(dst);
}

void dsa_unregister_switch(struct dsa_switch *ds)
+2 −3
Original line number Diff line number Diff line
@@ -31,15 +31,14 @@
 *	Must be transmitted as zero and ignored on receive.
 *
 * SWITCH_ID - VID[8:6]:
 *	Index of switch within DSA tree. Must be between 0 and
 *	DSA_MAX_SWITCHES - 1.
 *	Index of switch within DSA tree. Must be between 0 and 7.
 *
 * RSV - VID[5:4]:
 *	To be used for further expansion of PORT or for other purposes.
 *	Must be transmitted as zero and ignored on receive.
 *
 * PORT - VID[3:0]:
 *	Index of switch port. Must be between 0 and DSA_MAX_PORTS - 1.
 *	Index of switch port. Must be between 0 and 15.
 */

#define DSA_8021Q_DIR_SHIFT		10