forked from mirrors/linux
		
	net: dsa: list DSA links in the fabric
Implement a new list of DSA links in the switch fabric itself, to provide an alterative to the ds->rtable static arrays. At the same time, provide a new dsa_routing_port() helper to abstract the usage of ds->rtable in drivers. If there's no port to reach a given device, return the first invalid port, ds->num_ports. This avoids potential signedness errors or the need to define special values. Signed-off-by: Vivien Didelot <vivien.didelot@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									5c26c1d6df
								
							
						
					
					
						commit
						c5f51765a1
					
				
					 3 changed files with 72 additions and 6 deletions
				
			
		|  | @ -1143,6 +1143,7 @@ static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) | ||||||
| 
 | 
 | ||||||
| static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) | static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) | ||||||
| { | { | ||||||
|  | 	struct dsa_switch *ds = chip->ds; | ||||||
| 	int target, port; | 	int target, port; | ||||||
| 	int err; | 	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 */ | 	/* Initialize the routing port to the 32 possible target devices */ | ||||||
| 	for (target = 0; target < 32; target++) { | 	for (target = 0; target < 32; target++) { | ||||||
| 		port = 0x1f; | 		port = dsa_routing_port(ds, target); | ||||||
| 		if (target < DSA_MAX_SWITCHES) | 		if (port == ds->num_ports) | ||||||
| 			if (chip->ds->rtable[target] != DSA_RTABLE_NONE) | 			port = 0x1f; | ||||||
| 				port = chip->ds->rtable[target]; |  | ||||||
| 
 | 
 | ||||||
| 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port); | 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port); | ||||||
| 		if (err) | 		if (err) | ||||||
|  |  | ||||||
|  | @ -123,6 +123,9 @@ struct dsa_switch_tree { | ||||||
| 	/* List of switch ports */ | 	/* List of switch ports */ | ||||||
| 	struct list_head ports; | 	struct list_head ports; | ||||||
| 
 | 
 | ||||||
|  | 	/* List of DSA links composing the routing table */ | ||||||
|  | 	struct list_head rtable; | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Data for the individual switch chips. | 	 * Data for the individual switch chips. | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -214,6 +217,17 @@ struct dsa_port { | ||||||
| 	bool setup; | 	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 { | struct dsa_switch { | ||||||
| 	bool setup; | 	bool setup; | ||||||
| 
 | 
 | ||||||
|  | @ -324,6 +338,19 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds) | ||||||
| 	return mask; | 	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 */ | /* Return the local port used to reach an arbitrary switch port */ | ||||||
| static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, | static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, | ||||||
| 					    int port) | 					    int port) | ||||||
|  | @ -331,7 +358,7 @@ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, | ||||||
| 	if (device == ds->index) | 	if (device == ds->index) | ||||||
| 		return port; | 		return port; | ||||||
| 	else | 	else | ||||||
| 		return ds->rtable[device]; | 		return dsa_routing_port(ds, device); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Return the local port used to reach the dedicated CPU port */ | /* Return the local port used to reach the dedicated CPU port */ | ||||||
|  |  | ||||||
|  | @ -45,6 +45,8 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index) | ||||||
| 
 | 
 | ||||||
| 	dst->index = index; | 	dst->index = index; | ||||||
| 
 | 
 | ||||||
|  | 	INIT_LIST_HEAD(&dst->rtable); | ||||||
|  | 
 | ||||||
| 	INIT_LIST_HEAD(&dst->ports); | 	INIT_LIST_HEAD(&dst->ports); | ||||||
| 
 | 
 | ||||||
| 	INIT_LIST_HEAD(&dst->list); | 	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; | 	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) | static bool dsa_port_setup_routing_table(struct dsa_port *dp) | ||||||
| { | { | ||||||
| 	struct dsa_switch *ds = dp->ds; | 	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 device_node *dn = dp->dn; | ||||||
| 	struct of_phandle_iterator it; | 	struct of_phandle_iterator it; | ||||||
| 	struct dsa_port *link_dp; | 	struct dsa_port *link_dp; | ||||||
|  | 	struct dsa_link *dl; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	of_for_each_phandle(&it, err, dn, "link", NULL, 0) { | 	of_for_each_phandle(&it, err, dn, "link", NULL, 0) { | ||||||
|  | @ -138,7 +166,11 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) | ||||||
| 			return false; | 			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; | 	return true; | ||||||
|  | @ -544,6 +576,8 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst) | ||||||
| 
 | 
 | ||||||
| static void dsa_tree_teardown(struct dsa_switch_tree *dst) | static void dsa_tree_teardown(struct dsa_switch_tree *dst) | ||||||
| { | { | ||||||
|  | 	struct dsa_link *dl, *next; | ||||||
|  | 
 | ||||||
| 	if (!dst->setup) | 	if (!dst->setup) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | @ -553,6 +587,11 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst) | ||||||
| 
 | 
 | ||||||
| 	dsa_tree_teardown_default_cpu(dst); | 	dsa_tree_teardown_default_cpu(dst); | ||||||
| 
 | 
 | ||||||
|  | 	list_for_each_entry_safe(dl, next, &dst->rtable, list) { | ||||||
|  | 		list_del(&dl->list); | ||||||
|  | 		kfree(dl); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	pr_info("DSA: tree %d torn down\n", dst->index); | 	pr_info("DSA: tree %d torn down\n", dst->index); | ||||||
| 
 | 
 | ||||||
| 	dst->setup = false; | 	dst->setup = false; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Vivien Didelot
						Vivien Didelot