22 #include <linux/errno.h>
26 #include <linux/kernel.h>
27 #include <linux/list.h>
28 #include <linux/module.h>
29 #include <linux/slab.h>
33 #include <asm/byteorder.h>
37 #define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f)
38 #define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01)
39 #define SELF_ID_LINK_ON(q) (((q) >> 22) & 0x01)
40 #define SELF_ID_GAP_COUNT(q) (((q) >> 16) & 0x3f)
41 #define SELF_ID_PHY_SPEED(q) (((q) >> 14) & 0x03)
42 #define SELF_ID_CONTENDER(q) (((q) >> 11) & 0x01)
43 #define SELF_ID_PHY_INITIATOR(q) (((q) >> 1) & 0x01)
44 #define SELF_ID_MORE_PACKETS(q) (((q) >> 0) & 0x01)
46 #define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07)
48 #define SELFID_PORT_CHILD 0x3
49 #define SELFID_PORT_PARENT 0x2
50 #define SELFID_PORT_NCONN 0x1
51 #define SELFID_PORT_NONE 0x0
53 static u32 *count_ports(
u32 *
sid,
int *total_port_count,
int *child_port_count)
58 *total_port_count = 0;
59 *child_port_count = 0;
66 port_type = (q >> shift) & 0x03;
69 (*child_port_count)++;
72 (*total_port_count)++;
102 static int get_port_type(
u32 *
sid,
int port_index)
106 index = (port_index + 5) / 8;
107 shift = 16 - ((port_index + 5) & 7) * 2;
108 return (sid[index] >> shift) & 0x03;
115 node = kzalloc(
sizeof(*node) + port_count *
sizeof(node->
ports[0]),
128 INIT_LIST_HEAD(&node->
link);
147 static void update_hop_count(
struct fw_node *node)
149 int depths[2] = { -1, -1 };
150 int max_child_hops = 0;
157 if (node->
ports[i]->max_hops > max_child_hops)
158 max_child_hops = node->
ports[
i]->max_hops;
160 if (node->
ports[i]->max_depth > depths[0]) {
161 depths[1] = depths[0];
162 depths[0] = node->
ports[
i]->max_depth;
163 }
else if (node->
ports[i]->max_depth > depths[1])
164 depths[1] = node->
ports[
i]->max_depth;
168 node->
max_hops =
max(max_child_hops, depths[0] + depths[1] + 2);
184 u32 *sid,
int self_id_count)
191 bool beta_repeaters_present;
195 INIT_LIST_HEAD(&
stack);
197 end = sid + self_id_count;
201 beta_repeaters_present =
false;
204 next_sid = count_ports(sid, &port_count, &child_port_count);
206 if (next_sid ==
NULL) {
207 fw_err(card,
"inconsistent extended self IDs\n");
213 fw_err(card,
"PHY ID mismatch in self ID: %d != %d\n",
218 if (child_port_count > stack_depth) {
219 fw_err(card,
"topology stack underflow\n");
227 for (i = 0, h = &
stack; i < child_port_count; i++)
235 node = fw_node_create(q, port_count, card->
color);
237 fw_err(card,
"out of memory while building topology\n");
241 if (phy_id == (card->
node_id & 0x3f))
250 switch (get_port_type(sid, i)) {
284 if ((next_sid == end && parent_count != 0) ||
285 (next_sid < end && parent_count != 1)) {
286 fw_err(card,
"parent port inconsistency for node %d: "
287 "parent_count=%d\n", phy_id, parent_count);
294 stack_depth += 1 - child_port_count;
297 parent_count + child_port_count > 1)
298 beta_repeaters_present =
true;
307 update_hop_count(node);
325 static void for_each_fw_node(
struct fw_card *card,
struct fw_node *root,
332 INIT_LIST_HEAD(&list);
359 static void report_lost_node(
struct fw_card *card,
369 static void report_found_node(
struct fw_card *card,
374 if (parent !=
NULL) {
397 for_each_fw_node(card, card->
local_node, report_lost_node);
399 spin_unlock_irqrestore(&card->
lock, flags);
410 if (tree->
ports[i] == node1) {
422 static void update_tree(
struct fw_card *card,
struct fw_node *root)
425 struct fw_node *node0, *node1, *next1;
428 INIT_LIST_HEAD(&list0);
430 INIT_LIST_HEAD(&list1);
436 while (&node0->
link != &list0) {
472 }
else if (node0->
ports[i]) {
480 for_each_fw_node(card, node0->
ports[i],
483 }
else if (node1->
ports[i]) {
490 move_tree(node0, node1, i);
491 for_each_fw_node(card, node0->
ports[i],
503 static void update_topology_map(
struct fw_card *card,
504 u32 *self_ids,
int self_id_count)
506 int node_count = (card->
root_node->node_id & 0x3f) + 1;
511 *map++ =
cpu_to_be32((node_count << 16) | self_id_count);
513 while (self_id_count--)
520 int self_id_count,
u32 *self_ids,
bool bm_abdicate)
530 if (!is_next_generation(generation, card->
generation) &&
551 local_node = build_tree(card, self_ids, self_id_count);
553 update_topology_map(card, self_ids, self_id_count);
557 if (local_node ==
NULL) {
558 fw_err(card,
"topology build failed\n");
562 for_each_fw_node(card, local_node, report_found_node);
564 update_tree(card, local_node);
567 spin_unlock_irqrestore(&card->
lock, flags);