net/hsr: Use list_head (and rcu) instead of array for slave devices.

Signed-off-by: Arvid Brodin <arvid.brodin@alten.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
index 3666f94..c9b78c5 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -27,12 +27,11 @@
 	struct list_head	mac_list;
 	unsigned char		MacAddressA[ETH_ALEN];
 	unsigned char		MacAddressB[ETH_ALEN];
-	enum hsr_dev_idx	AddrB_if;/* The local slave through which AddrB
-					  * frames are received from this node
-					  */
-	unsigned long		time_in[HSR_MAX_SLAVE];
-	bool			time_in_stale[HSR_MAX_SLAVE];
-	u16			seq_out[HSR_MAX_DEV];
+	/* Local slave through which AddrB frames are received from this node */
+	enum hsr_port_type	AddrB_port;
+	unsigned long		time_in[HSR_PT_PORTS];
+	bool			time_in_stale[HSR_PT_PORTS];
+	u16			seq_out[HSR_PT_PORTS];
 	struct rcu_head		rcu_head;
 };
 
@@ -154,11 +153,10 @@
  * We also need to detect if the sender's SlaveA and SlaveB cables have been
  * swapped.
  */
-struct hsr_node *hsr_merge_node(struct hsr_priv *hsr,
-				struct hsr_node *node,
-				struct sk_buff *skb,
-				enum hsr_dev_idx dev_idx)
+struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb,
+				struct hsr_port *port)
 {
+	struct hsr_priv *hsr;
 	struct hsr_sup_payload *hsr_sp;
 	struct hsr_ethhdr_sp *hsr_ethsup;
 	int i;
@@ -166,6 +164,7 @@
 
 	hsr_ethsup = (struct hsr_ethhdr_sp *) skb_mac_header(skb);
 	hsr_sp = (struct hsr_sup_payload *) skb->data;
+	hsr = port->hsr;
 
 	if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) {
 		/* Node has changed its AddrA, frame was received from SlaveB */
@@ -174,7 +173,7 @@
 		node = NULL;
 	}
 
-	if (node && (dev_idx == node->AddrB_if) &&
+	if (node && (port->type == node->AddrB_port) &&
 	    !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) {
 		/* Cables have been swapped */
 		list_del_rcu(&node->mac_list);
@@ -182,8 +181,8 @@
 		node = NULL;
 	}
 
-	if (node && (dev_idx != node->AddrB_if) &&
-	    (node->AddrB_if != HSR_DEV_NONE) &&
+	if (node && (port->type != node->AddrB_port) &&
+	    (node->AddrB_port != HSR_PT_NONE) &&
 	    !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) {
 		/* Cables have been swapped */
 		list_del_rcu(&node->mac_list);
@@ -200,7 +199,7 @@
 		 * address. Node is PICS_SUBS capable; merge its AddrB.
 		 */
 		ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source);
-		node->AddrB_if = dev_idx;
+		node->AddrB_port = port->type;
 		return node;
 	}
 
@@ -211,17 +210,15 @@
 	ether_addr_copy(node->MacAddressA, hsr_sp->MacAddressA);
 	ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source);
 	if (!ether_addr_equal(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source))
-		node->AddrB_if = dev_idx;
-	else
-		node->AddrB_if = HSR_DEV_NONE;
+		node->AddrB_port = port->type;
 
 	/* We are only interested in time diffs here, so use current jiffies
 	 * as initialization. (0 could trigger an spurious ring error warning).
 	 */
 	now = jiffies;
-	for (i = 0; i < HSR_MAX_SLAVE; i++)
+	for (i = 0; i < HSR_PT_PORTS; i++)
 		node->time_in[i] = now;
-	for (i = 0; i < HSR_MAX_DEV; i++)
+	for (i = 0; i < HSR_PT_PORTS; i++)
 		node->seq_out[i] = ntohs(hsr_ethsup->hsr_sup.sequence_nr) - 1;
 
 	list_add_tail_rcu(&node->mac_list, &hsr->node_db);
@@ -265,13 +262,13 @@
  * which "side" the different interfaces are.
  */
 void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr,
-			 enum hsr_dev_idx dev_idx)
+			 struct hsr_port *port)
 {
 	struct hsr_node *node;
 
 	rcu_read_lock();
 	node = find_node_by_AddrA(&hsr->node_db, ethhdr->h_dest);
-	if (node && (node->AddrB_if == dev_idx))
+	if (node && (node->AddrB_port == port->type))
 		ether_addr_copy(ethhdr->h_dest, node->MacAddressB);
 	rcu_read_unlock();
 }
@@ -295,14 +292,10 @@
 #define seq_nr_before_or_eq(a, b)	(!seq_nr_after((a), (b)))
 
 
-void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx)
+void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port)
 {
-	if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) {
-		WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx);
-		return;
-	}
-	node->time_in[dev_idx] = jiffies;
-	node->time_in_stale[dev_idx] = false;
+	node->time_in[port->type] = jiffies;
+	node->time_in_stale[port->type] = false;
 }
 
 
@@ -314,16 +307,12 @@
  *	 0 otherwise, or
  *	 negative error code on error
  */
-int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx,
+int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port,
 			   struct sk_buff *skb)
 {
 	struct hsr_ethhdr *hsr_ethhdr;
 	u16 sequence_nr;
 
-	if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) {
-		WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx);
-		return -EINVAL;
-	}
 	if (!skb_mac_header_was_set(skb)) {
 		WARN_ONCE(1, "%s: Mac header not set\n", __func__);
 		return -EINVAL;
@@ -331,35 +320,32 @@
 	hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb);
 
 	sequence_nr = ntohs(hsr_ethhdr->hsr_tag.sequence_nr);
-	if (seq_nr_before_or_eq(sequence_nr, node->seq_out[dev_idx]))
+	if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type]))
 		return 1;
 
-	node->seq_out[dev_idx] = sequence_nr;
+	node->seq_out[port->type] = sequence_nr;
 	return 0;
 }
 
 
-
-static bool is_late(struct hsr_node *node, enum hsr_dev_idx dev_idx)
+static struct hsr_port *get_late_port(struct hsr_priv *hsr,
+				      struct hsr_node *node)
 {
-	enum hsr_dev_idx other;
+	if (node->time_in_stale[HSR_PT_SLAVE_A])
+		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
+	if (node->time_in_stale[HSR_PT_SLAVE_B])
+		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
 
-	if (node->time_in_stale[dev_idx])
-		return true;
+	if (time_after(node->time_in[HSR_PT_SLAVE_B],
+		       node->time_in[HSR_PT_SLAVE_A] +
+					msecs_to_jiffies(MAX_SLAVE_DIFF)))
+		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
+	if (time_after(node->time_in[HSR_PT_SLAVE_A],
+		       node->time_in[HSR_PT_SLAVE_B] +
+					msecs_to_jiffies(MAX_SLAVE_DIFF)))
+		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
 
-	if (dev_idx == HSR_DEV_SLAVE_A)
-		other = HSR_DEV_SLAVE_B;
-	else
-		other = HSR_DEV_SLAVE_A;
-
-	if (node->time_in_stale[other])
-		return false;
-
-	if (time_after(node->time_in[other], node->time_in[dev_idx] +
-		       msecs_to_jiffies(MAX_SLAVE_DIFF)))
-		return true;
-
-	return false;
+	return NULL;
 }
 
 
@@ -370,6 +356,7 @@
 {
 	struct hsr_priv *hsr;
 	struct hsr_node *node;
+	struct hsr_port *port;
 	unsigned long timestamp;
 	unsigned long time_a, time_b;
 
@@ -378,35 +365,33 @@
 	rcu_read_lock();
 	list_for_each_entry_rcu(node, &hsr->node_db, mac_list) {
 		/* Shorthand */
-		time_a = node->time_in[HSR_DEV_SLAVE_A];
-		time_b = node->time_in[HSR_DEV_SLAVE_B];
+		time_a = node->time_in[HSR_PT_SLAVE_A];
+		time_b = node->time_in[HSR_PT_SLAVE_B];
 
 		/* Check for timestamps old enough to risk wrap-around */
 		if (time_after(jiffies, time_a + MAX_JIFFY_OFFSET/2))
-			node->time_in_stale[HSR_DEV_SLAVE_A] = true;
+			node->time_in_stale[HSR_PT_SLAVE_A] = true;
 		if (time_after(jiffies, time_b + MAX_JIFFY_OFFSET/2))
-			node->time_in_stale[HSR_DEV_SLAVE_B] = true;
+			node->time_in_stale[HSR_PT_SLAVE_B] = true;
 
 		/* Get age of newest frame from node.
 		 * At least one time_in is OK here; nodes get pruned long
 		 * before both time_ins can get stale
 		 */
 		timestamp = time_a;
-		if (node->time_in_stale[HSR_DEV_SLAVE_A] ||
-		    (!node->time_in_stale[HSR_DEV_SLAVE_B] &&
+		if (node->time_in_stale[HSR_PT_SLAVE_A] ||
+		    (!node->time_in_stale[HSR_PT_SLAVE_B] &&
 		    time_after(time_b, time_a)))
 			timestamp = time_b;
 
 		/* Warn of ring error only as long as we get frames at all */
 		if (time_is_after_jiffies(timestamp +
 					msecs_to_jiffies(1.5*MAX_SLAVE_DIFF))) {
-
-			if (is_late(node, HSR_DEV_SLAVE_A))
-				hsr_nl_ringerror(hsr, node->MacAddressA,
-						 HSR_DEV_SLAVE_A);
-			else if (is_late(node, HSR_DEV_SLAVE_B))
-				hsr_nl_ringerror(hsr, node->MacAddressA,
-						 HSR_DEV_SLAVE_B);
+			rcu_read_lock();
+			port = get_late_port(hsr, node);
+			if (port != NULL)
+				hsr_nl_ringerror(hsr, node->MacAddressA, port);
+			rcu_read_unlock();
 		}
 
 		/* Prune old entries */
@@ -455,7 +440,7 @@
 		      u16 *if2_seq)
 {
 	struct hsr_node *node;
-	struct net_device *slave;
+	struct hsr_port *port;
 	unsigned long tdiff;
 
 
@@ -468,8 +453,8 @@
 
 	ether_addr_copy(addr_b, node->MacAddressB);
 
-	tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_A];
-	if (node->time_in_stale[HSR_DEV_SLAVE_A])
+	tdiff = jiffies - node->time_in[HSR_PT_SLAVE_A];
+	if (node->time_in_stale[HSR_PT_SLAVE_A])
 		*if1_age = INT_MAX;
 #if HZ <= MSEC_PER_SEC
 	else if (tdiff > msecs_to_jiffies(INT_MAX))
@@ -478,8 +463,8 @@
 	else
 		*if1_age = jiffies_to_msecs(tdiff);
 
-	tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_B];
-	if (node->time_in_stale[HSR_DEV_SLAVE_B])
+	tdiff = jiffies - node->time_in[HSR_PT_SLAVE_B];
+	if (node->time_in_stale[HSR_PT_SLAVE_B])
 		*if2_age = INT_MAX;
 #if HZ <= MSEC_PER_SEC
 	else if (tdiff > msecs_to_jiffies(INT_MAX))
@@ -489,14 +474,15 @@
 		*if2_age = jiffies_to_msecs(tdiff);
 
 	/* Present sequence numbers as if they were incoming on interface */
-	*if1_seq = node->seq_out[HSR_DEV_SLAVE_B];
-	*if2_seq = node->seq_out[HSR_DEV_SLAVE_A];
+	*if1_seq = node->seq_out[HSR_PT_SLAVE_B];
+	*if2_seq = node->seq_out[HSR_PT_SLAVE_A];
 
-	slave = hsr->slave[node->AddrB_if];
-	if ((node->AddrB_if != HSR_DEV_NONE) && slave)
-		*addr_b_ifindex = slave->ifindex;
-	else
+	if (node->AddrB_port != HSR_PT_NONE) {
+		port = hsr_port_get_hsr(hsr, node->AddrB_port);
+		*addr_b_ifindex = port->dev->ifindex;
+	} else {
 		*addr_b_ifindex = -1;
+	}
 
 	rcu_read_unlock();