mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	firewire: core: use helper functions for self ID sequence
This commit replaces the existing implementation with the helper functions for self ID sequence. Link: https://lore.kernel.org/r/20240605235155.116468-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
This commit is contained in:
		
							parent
							
								
									e404cacfc5
								
							
						
					
					
						commit
						24b7f8e5cd
					
				
					 1 changed files with 69 additions and 120 deletions
				
			
		| 
						 | 
					@ -20,80 +20,15 @@
 | 
				
			||||||
#include <asm/byteorder.h>
 | 
					#include <asm/byteorder.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core.h"
 | 
					#include "core.h"
 | 
				
			||||||
 | 
					#include "phy-packet-definitions.h"
 | 
				
			||||||
#include <trace/events/firewire.h>
 | 
					#include <trace/events/firewire.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SELF_ID_PHY_ID(q)		(((q) >> 24) & 0x3f)
 | 
					#define SELF_ID_PHY_ID(q)		(((q) >> 24) & 0x3f)
 | 
				
			||||||
#define SELF_ID_EXTENDED(q)		(((q) >> 23) & 0x01)
 | 
					 | 
				
			||||||
#define SELF_ID_LINK_ON(q)		(((q) >> 22) & 0x01)
 | 
					#define SELF_ID_LINK_ON(q)		(((q) >> 22) & 0x01)
 | 
				
			||||||
#define SELF_ID_GAP_COUNT(q)		(((q) >> 16) & 0x3f)
 | 
					#define SELF_ID_GAP_COUNT(q)		(((q) >> 16) & 0x3f)
 | 
				
			||||||
#define SELF_ID_PHY_SPEED(q)		(((q) >> 14) & 0x03)
 | 
					#define SELF_ID_PHY_SPEED(q)		(((q) >> 14) & 0x03)
 | 
				
			||||||
#define SELF_ID_CONTENDER(q)		(((q) >> 11) & 0x01)
 | 
					#define SELF_ID_CONTENDER(q)		(((q) >> 11) & 0x01)
 | 
				
			||||||
#define SELF_ID_PHY_INITIATOR(q)	(((q) >>  1) & 0x01)
 | 
					#define SELF_ID_PHY_INITIATOR(q)	(((q) >>  1) & 0x01)
 | 
				
			||||||
#define SELF_ID_MORE_PACKETS(q)		(((q) >>  0) & 0x01)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SELF_ID_EXT_SEQUENCE(q)		(((q) >> 20) & 0x07)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SELFID_PORT_CHILD	0x3
 | 
					 | 
				
			||||||
#define SELFID_PORT_PARENT	0x2
 | 
					 | 
				
			||||||
#define SELFID_PORT_NCONN	0x1
 | 
					 | 
				
			||||||
#define SELFID_PORT_NONE	0x0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const u32 *count_ports(const u32 *sid, int *total_port_count, int *child_port_count)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u32 q;
 | 
					 | 
				
			||||||
	int port_type, shift, seq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	shift = 6;
 | 
					 | 
				
			||||||
	q = *sid;
 | 
					 | 
				
			||||||
	seq = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (1) {
 | 
					 | 
				
			||||||
		port_type = (q >> shift) & 0x03;
 | 
					 | 
				
			||||||
		switch (port_type) {
 | 
					 | 
				
			||||||
		case SELFID_PORT_CHILD:
 | 
					 | 
				
			||||||
			(*child_port_count)++;
 | 
					 | 
				
			||||||
			fallthrough;
 | 
					 | 
				
			||||||
		case SELFID_PORT_PARENT:
 | 
					 | 
				
			||||||
		case SELFID_PORT_NCONN:
 | 
					 | 
				
			||||||
			(*total_port_count)++;
 | 
					 | 
				
			||||||
			fallthrough;
 | 
					 | 
				
			||||||
		case SELFID_PORT_NONE:
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		shift -= 2;
 | 
					 | 
				
			||||||
		if (shift == 0) {
 | 
					 | 
				
			||||||
			if (!SELF_ID_MORE_PACKETS(q))
 | 
					 | 
				
			||||||
				return sid + 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			shift = 16;
 | 
					 | 
				
			||||||
			sid++;
 | 
					 | 
				
			||||||
			q = *sid;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * Check that the extra packets actually are
 | 
					 | 
				
			||||||
			 * extended self ID packets and that the
 | 
					 | 
				
			||||||
			 * sequence numbers in the extended self ID
 | 
					 | 
				
			||||||
			 * packets increase as expected.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (!SELF_ID_EXTENDED(q) ||
 | 
					 | 
				
			||||||
			    seq != SELF_ID_EXT_SEQUENCE(q))
 | 
					 | 
				
			||||||
				return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			seq++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int get_port_type(const u32 *sid, int port_index)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int index, shift;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	index = (port_index + 5) / 8;
 | 
					 | 
				
			||||||
	shift = 16 - ((port_index + 5) & 7) * 2;
 | 
					 | 
				
			||||||
	return (sid[index] >> shift) & 0x03;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct fw_node *fw_node_create(u32 sid, int port_count, int color)
 | 
					static struct fw_node *fw_node_create(u32 sid, int port_count, int color)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -168,9 +103,12 @@ static inline struct fw_node *fw_node(struct list_head *l)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self_id_count)
 | 
					static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self_id_count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct self_id_sequence_enumerator enumerator = {
 | 
				
			||||||
 | 
							.cursor = sid,
 | 
				
			||||||
 | 
							.quadlet_count = self_id_count,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
	struct fw_node *node, *child, *local_node, *irm_node;
 | 
						struct fw_node *node, *child, *local_node, *irm_node;
 | 
				
			||||||
	struct list_head stack;
 | 
						struct list_head stack;
 | 
				
			||||||
	const u32 *end;
 | 
					 | 
				
			||||||
	int phy_id, stack_depth;
 | 
						int phy_id, stack_depth;
 | 
				
			||||||
	int gap_count;
 | 
						int gap_count;
 | 
				
			||||||
	bool beta_repeaters_present;
 | 
						bool beta_repeaters_present;
 | 
				
			||||||
| 
						 | 
					@ -179,31 +117,54 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
 | 
				
			||||||
	node = NULL;
 | 
						node = NULL;
 | 
				
			||||||
	INIT_LIST_HEAD(&stack);
 | 
						INIT_LIST_HEAD(&stack);
 | 
				
			||||||
	stack_depth = 0;
 | 
						stack_depth = 0;
 | 
				
			||||||
	end = sid + self_id_count;
 | 
					 | 
				
			||||||
	phy_id = 0;
 | 
						phy_id = 0;
 | 
				
			||||||
	irm_node = NULL;
 | 
						irm_node = NULL;
 | 
				
			||||||
	gap_count = SELF_ID_GAP_COUNT(*sid);
 | 
						gap_count = SELF_ID_GAP_COUNT(*sid);
 | 
				
			||||||
	beta_repeaters_present = false;
 | 
						beta_repeaters_present = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (sid < end) {
 | 
						while (enumerator.quadlet_count > 0) {
 | 
				
			||||||
		int port_count = 0;
 | 
							unsigned int child_port_count = 0;
 | 
				
			||||||
		int child_port_count = 0;
 | 
							unsigned int total_port_count = 0;
 | 
				
			||||||
		int parent_count = 0;
 | 
							unsigned int parent_count = 0;
 | 
				
			||||||
		const u32 *next_sid;
 | 
							unsigned int quadlet_count;
 | 
				
			||||||
		u32 q;
 | 
							const u32 *self_id_sequence;
 | 
				
			||||||
 | 
							unsigned int port_capacity;
 | 
				
			||||||
 | 
							enum phy_packet_self_id_port_status port_status;
 | 
				
			||||||
 | 
							unsigned int port_index;
 | 
				
			||||||
		struct list_head *h;
 | 
							struct list_head *h;
 | 
				
			||||||
		int i;
 | 
							int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		next_sid = count_ports(sid, &port_count, &child_port_count);
 | 
							self_id_sequence = self_id_sequence_enumerator_next(&enumerator, &quadlet_count);
 | 
				
			||||||
		if (next_sid == NULL) {
 | 
							if (IS_ERR(self_id_sequence)) {
 | 
				
			||||||
			fw_err(card, "inconsistent extended self IDs\n");
 | 
								if (PTR_ERR(self_id_sequence) != -ENODATA) {
 | 
				
			||||||
			return NULL;
 | 
									fw_err(card, "inconsistent extended self IDs: %ld\n",
 | 
				
			||||||
 | 
									       PTR_ERR(self_id_sequence));
 | 
				
			||||||
 | 
									return NULL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		q = *sid;
 | 
							port_capacity = self_id_sequence_get_port_capacity(quadlet_count);
 | 
				
			||||||
		if (phy_id != SELF_ID_PHY_ID(q)) {
 | 
							for (port_index = 0; port_index < port_capacity; ++port_index) {
 | 
				
			||||||
 | 
								port_status = self_id_sequence_get_port_status(self_id_sequence, quadlet_count,
 | 
				
			||||||
 | 
													       port_index);
 | 
				
			||||||
 | 
								switch (port_status) {
 | 
				
			||||||
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_CHILD:
 | 
				
			||||||
 | 
									++child_port_count;
 | 
				
			||||||
 | 
									fallthrough;
 | 
				
			||||||
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_PARENT:
 | 
				
			||||||
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_NCONN:
 | 
				
			||||||
 | 
									++total_port_count;
 | 
				
			||||||
 | 
									fallthrough;
 | 
				
			||||||
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_NONE:
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (phy_id != SELF_ID_PHY_ID(self_id_sequence[0])) {
 | 
				
			||||||
			fw_err(card, "PHY ID mismatch in self ID: %d != %d\n",
 | 
								fw_err(card, "PHY ID mismatch in self ID: %d != %d\n",
 | 
				
			||||||
			       phy_id, SELF_ID_PHY_ID(q));
 | 
								       phy_id, SELF_ID_PHY_ID(self_id_sequence[0]));
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,7 +185,7 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		child = fw_node(h);
 | 
							child = fw_node(h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		node = fw_node_create(q, port_count, card->color);
 | 
							node = fw_node_create(self_id_sequence[0], total_port_count, card->color);
 | 
				
			||||||
		if (node == NULL) {
 | 
							if (node == NULL) {
 | 
				
			||||||
			fw_err(card, "out of memory while building topology\n");
 | 
								fw_err(card, "out of memory while building topology\n");
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
| 
						 | 
					@ -233,48 +194,40 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
 | 
				
			||||||
		if (phy_id == (card->node_id & 0x3f))
 | 
							if (phy_id == (card->node_id & 0x3f))
 | 
				
			||||||
			local_node = node;
 | 
								local_node = node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (SELF_ID_CONTENDER(q))
 | 
							if (SELF_ID_CONTENDER(self_id_sequence[0]))
 | 
				
			||||||
			irm_node = node;
 | 
								irm_node = node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		parent_count = 0;
 | 
							for (port_index = 0; port_index < total_port_count; ++port_index) {
 | 
				
			||||||
 | 
								port_status = self_id_sequence_get_port_status(self_id_sequence, quadlet_count,
 | 
				
			||||||
		for (i = 0; i < port_count; i++) {
 | 
													       port_index);
 | 
				
			||||||
			switch (get_port_type(sid, i)) {
 | 
								switch (port_status) {
 | 
				
			||||||
			case SELFID_PORT_PARENT:
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_PARENT:
 | 
				
			||||||
				/*
 | 
									// Who's your daddy?  We dont know the parent node at this time, so
 | 
				
			||||||
				 * Who's your daddy?  We dont know the
 | 
									// we temporarily abuse node->color for remembering the entry in
 | 
				
			||||||
				 * parent node at this time, so we
 | 
									// the node->ports array where the parent node should be.  Later,
 | 
				
			||||||
				 * temporarily abuse node->color for
 | 
									// when we handle the parent node, we fix up the reference.
 | 
				
			||||||
				 * remembering the entry in the
 | 
									++parent_count;
 | 
				
			||||||
				 * node->ports array where the parent
 | 
					 | 
				
			||||||
				 * node should be.  Later, when we
 | 
					 | 
				
			||||||
				 * handle the parent node, we fix up
 | 
					 | 
				
			||||||
				 * the reference.
 | 
					 | 
				
			||||||
				 */
 | 
					 | 
				
			||||||
				parent_count++;
 | 
					 | 
				
			||||||
				node->color = i;
 | 
									node->color = i;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case SELFID_PORT_CHILD:
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_CHILD:
 | 
				
			||||||
				node->ports[i] = child;
 | 
									node->ports[port_index] = child;
 | 
				
			||||||
				/*
 | 
									// Fix up parent reference for this child node.
 | 
				
			||||||
				 * Fix up parent reference for this
 | 
					 | 
				
			||||||
				 * child node.
 | 
					 | 
				
			||||||
				 */
 | 
					 | 
				
			||||||
				child->ports[child->color] = node;
 | 
									child->ports[child->color] = node;
 | 
				
			||||||
				child->color = card->color;
 | 
									child->color = card->color;
 | 
				
			||||||
				child = fw_node(child->link.next);
 | 
									child = fw_node(child->link.next);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_NCONN:
 | 
				
			||||||
 | 
								case PHY_PACKET_SELF_ID_PORT_STATUS_NONE:
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							// Check that the node reports exactly one parent port, except for the root, which
 | 
				
			||||||
		 * Check that the node reports exactly one parent
 | 
							// of course should have no parents.
 | 
				
			||||||
		 * port, except for the root, which of course should
 | 
							if ((enumerator.quadlet_count == 0 && parent_count != 0) ||
 | 
				
			||||||
		 * have no parents.
 | 
							    (enumerator.quadlet_count > 0 && parent_count != 1)) {
 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if ((next_sid == end && parent_count != 0) ||
 | 
					 | 
				
			||||||
		    (next_sid < end && parent_count != 1)) {
 | 
					 | 
				
			||||||
			fw_err(card, "parent port inconsistency for node %d: "
 | 
								fw_err(card, "parent port inconsistency for node %d: "
 | 
				
			||||||
			       "parent_count=%d\n", phy_id, parent_count);
 | 
								       "parent_count=%d\n", phy_id, parent_count);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
| 
						 | 
					@ -285,20 +238,16 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
 | 
				
			||||||
		list_add_tail(&node->link, &stack);
 | 
							list_add_tail(&node->link, &stack);
 | 
				
			||||||
		stack_depth += 1 - child_port_count;
 | 
							stack_depth += 1 - child_port_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (node->phy_speed == SCODE_BETA &&
 | 
							if (node->phy_speed == SCODE_BETA && parent_count + child_port_count > 1)
 | 
				
			||||||
		    parent_count + child_port_count > 1)
 | 
					 | 
				
			||||||
			beta_repeaters_present = true;
 | 
								beta_repeaters_present = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							// If PHYs report different gap counts, set an invalid count which will force a gap
 | 
				
			||||||
		 * If PHYs report different gap counts, set an invalid count
 | 
							// count reconfiguration and a reset.
 | 
				
			||||||
		 * which will force a gap count reconfiguration and a reset.
 | 
							if (SELF_ID_GAP_COUNT(self_id_sequence[0]) != gap_count)
 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (SELF_ID_GAP_COUNT(q) != gap_count)
 | 
					 | 
				
			||||||
			gap_count = 0;
 | 
								gap_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		update_hop_count(node);
 | 
							update_hop_count(node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sid = next_sid;
 | 
					 | 
				
			||||||
		phy_id++;
 | 
							phy_id++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue