core-topology.c 15.1 KB
Newer Older
1 2
/*
 * Incremental bus scan, based on bus topology
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

S
Stefan Richter 已提交
21
#include <linux/bug.h>
22
#include <linux/errno.h>
23 24
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
S
Stefan Richter 已提交
25 26 27 28 29 30 31 32
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>

#include <asm/atomic.h>
33
#include <asm/byteorder.h>
34
#include <asm/system.h>
S
Stefan Richter 已提交
35

36
#include "core.h"
37

38 39 40 41 42 43 44 45
#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_GAP_COUNT(q)		(((q) >> 16) & 0x3f)
#define SELF_ID_PHY_SPEED(q)		(((q) >> 14) & 0x03)
#define SELF_ID_CONTENDER(q)		(((q) >> 11) & 0x01)
#define SELF_ID_PHY_INITIATOR(q)	(((q) >>  1) & 0x01)
#define SELF_ID_MORE_PACKETS(q)		(((q) >>  0) & 0x01)
46

47
#define SELF_ID_EXT_SEQUENCE(q)		(((q) >> 20) & 0x07)
48

49 50 51 52 53
#define SELFID_PORT_CHILD	0x3
#define SELFID_PORT_PARENT	0x2
#define SELFID_PORT_NCONN	0x1
#define SELFID_PORT_NONE	0x0

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
{
	u32 q;
	int port_type, shift, seq;

	*total_port_count = 0;
	*child_port_count = 0;

	shift = 6;
	q = *sid;
	seq = 0;

	while (1) {
		port_type = (q >> shift) & 0x03;
		switch (port_type) {
		case SELFID_PORT_CHILD:
			(*child_port_count)++;
		case SELFID_PORT_PARENT:
		case SELFID_PORT_NCONN:
			(*total_port_count)++;
		case SELFID_PORT_NONE:
			break;
		}

		shift -= 2;
		if (shift == 0) {
80
			if (!SELF_ID_MORE_PACKETS(q))
81 82 83 84 85 86
				return sid + 1;

			shift = 16;
			sid++;
			q = *sid;

87 88
			/*
			 * Check that the extra packets actually are
89 90
			 * extended self ID packets and that the
			 * sequence numbers in the extended self ID
91 92
			 * packets increase as expected.
			 */
93

94 95
			if (!SELF_ID_EXTENDED(q) ||
			    seq != SELF_ID_EXT_SEQUENCE(q))
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
				return NULL;

			seq++;
		}
	}
}

static int get_port_type(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;
}

A
Adrian Bunk 已提交
112
static struct fw_node *fw_node_create(u32 sid, int port_count, int color)
113 114 115
{
	struct fw_node *node;

116
	node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]),
117 118 119 120 121
		       GFP_ATOMIC);
	if (node == NULL)
		return NULL;

	node->color = color;
122 123 124
	node->node_id = LOCAL_BUS | SELF_ID_PHY_ID(sid);
	node->link_on = SELF_ID_LINK_ON(sid);
	node->phy_speed = SELF_ID_PHY_SPEED(sid);
125
	node->initiated_reset = SELF_ID_PHY_INITIATOR(sid);
126 127 128 129 130 131 132 133
	node->port_count = port_count;

	atomic_set(&node->ref_count, 1);
	INIT_LIST_HEAD(&node->link);

	return node;
}

134 135
/*
 * Compute the maximum hop count for this node and it's children.  The
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
 * maximum hop count is the maximum number of connections between any
 * two nodes in the subtree rooted at this node.  We need this for
 * setting the gap count.  As we build the tree bottom up in
 * build_tree() below, this is fairly easy to do: for each node we
 * maintain the max hop count and the max depth, ie the number of hops
 * to the furthest leaf.  Computing the max hop count breaks down into
 * two cases: either the path goes through this node, in which case
 * the hop count is the sum of the two biggest child depths plus 2.
 * Or it could be the case that the max hop path is entirely
 * containted in a child tree, in which case the max hop count is just
 * the max hop count of this child.
 */
static void update_hop_count(struct fw_node *node)
{
	int depths[2] = { -1, -1 };
	int max_child_hops = 0;
	int i;

	for (i = 0; i < node->port_count; i++) {
155
		if (node->ports[i] == NULL)
156 157
			continue;

158 159
		if (node->ports[i]->max_hops > max_child_hops)
			max_child_hops = node->ports[i]->max_hops;
160

161
		if (node->ports[i]->max_depth > depths[0]) {
162
			depths[1] = depths[0];
163 164 165
			depths[0] = node->ports[i]->max_depth;
		} else if (node->ports[i]->max_depth > depths[1])
			depths[1] = node->ports[i]->max_depth;
166 167 168 169 170 171
	}

	node->max_depth = depths[0] + 1;
	node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2);
}

S
Stefan Richter 已提交
172 173 174 175
static inline struct fw_node *fw_node(struct list_head *l)
{
	return list_entry(l, struct fw_node, link);
}
176

177 178 179 180 181 182 183 184 185
/**
 * build_tree - Build the tree representation of the topology
 * @self_ids: array of self IDs to create the tree from
 * @self_id_count: the length of the self_ids array
 * @local_id: the node ID of the local node
 *
 * This function builds the tree representation of the topology given
 * by the self IDs from the latest bus reset.  During the construction
 * of the tree, the function checks that the self IDs are valid and
186
 * internally consistent.  On success this function returns the
187 188
 * fw_node corresponding to the local card otherwise NULL.
 */
189 190
static struct fw_node *build_tree(struct fw_card *card,
				  u32 *sid, int self_id_count)
191
{
192
	struct fw_node *node, *child, *local_node, *irm_node;
193
	struct list_head stack, *h;
194
	u32 *next_sid, *end, q;
195
	int i, port_count, child_port_count, phy_id, parent_count, stack_depth;
196 197
	int gap_count;
	bool beta_repeaters_present;
198 199 200 201 202

	local_node = NULL;
	node = NULL;
	INIT_LIST_HEAD(&stack);
	stack_depth = 0;
203
	end = sid + self_id_count;
204
	phy_id = 0;
205
	irm_node = NULL;
206
	gap_count = SELF_ID_GAP_COUNT(*sid);
207
	beta_repeaters_present = false;
208 209 210 211 212 213 214 215 216 217

	while (sid < end) {
		next_sid = count_ports(sid, &port_count, &child_port_count);

		if (next_sid == NULL) {
			fw_error("Inconsistent extended self IDs.\n");
			return NULL;
		}

		q = *sid;
218
		if (phy_id != SELF_ID_PHY_ID(q)) {
219
			fw_error("PHY ID mismatch in self ID: %d != %d.\n",
220
				 phy_id, SELF_ID_PHY_ID(q));
221 222 223 224 225 226 227 228
			return NULL;
		}

		if (child_port_count > stack_depth) {
			fw_error("Topology stack underflow\n");
			return NULL;
		}

229 230 231 232
		/*
		 * Seek back from the top of our stack to find the
		 * start of the child nodes for this node.
		 */
233 234
		for (i = 0, h = &stack; i < child_port_count; i++)
			h = h->prev;
Y
Yann Dirson 已提交
235 236 237 238
		/*
		 * When the stack is empty, this yields an invalid value,
		 * but that pointer will never be dereferenced.
		 */
239 240 241 242
		child = fw_node(h);

		node = fw_node_create(q, port_count, card->color);
		if (node == NULL) {
243
			fw_error("Out of memory while building topology.\n");
244 245 246 247 248 249
			return NULL;
		}

		if (phy_id == (card->node_id & 0x3f))
			local_node = node;

250
		if (SELF_ID_CONTENDER(q))
251
			irm_node = node;
252 253 254 255 256 257

		parent_count = 0;

		for (i = 0; i < port_count; i++) {
			switch (get_port_type(sid, i)) {
			case SELFID_PORT_PARENT:
258 259
				/*
				 * Who's your daddy?  We dont know the
260 261 262 263 264 265 266 267 268 269 270 271 272
				 * parent node at this time, so we
				 * temporarily abuse node->color for
				 * remembering the entry in the
				 * 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;
				break;

			case SELFID_PORT_CHILD:
273
				node->ports[i] = child;
274 275 276 277
				/*
				 * Fix up parent reference for this
				 * child node.
				 */
278
				child->ports[child->color] = node;
279 280 281 282 283 284
				child->color = card->color;
				child = fw_node(child->link.next);
				break;
			}
		}

285 286
		/*
		 * Check that the node reports exactly one parent
287
		 * port, except for the root, which of course should
288 289
		 * have no parents.
		 */
290 291 292 293 294 295 296 297 298 299 300 301
		if ((next_sid == end && parent_count != 0) ||
		    (next_sid < end && parent_count != 1)) {
			fw_error("Parent port inconsistency for node %d: "
				 "parent_count=%d\n", phy_id, parent_count);
			return NULL;
		}

		/* Pop the child nodes off the stack and push the new node. */
		__list_del(h->prev, &stack);
		list_add_tail(&node->link, &stack);
		stack_depth += 1 - child_port_count;

302 303 304 305
		if (node->phy_speed == SCODE_BETA &&
		    parent_count + child_port_count > 1)
			beta_repeaters_present = true;

306
		/*
307 308
		 * If PHYs report different gap counts, set an invalid count
		 * which will force a gap count reconfiguration and a reset.
309
		 */
310
		if (SELF_ID_GAP_COUNT(q) != gap_count)
311
			gap_count = 0;
312 313 314

		update_hop_count(node);

315 316 317 318 319
		sid = next_sid;
		phy_id++;
	}

	card->root_node = node;
320
	card->irm_node = irm_node;
321
	card->gap_count = gap_count;
322
	card->beta_repeaters_present = beta_repeaters_present;
323 324 325 326

	return local_node;
}

327 328 329
typedef void (*fw_node_callback_t)(struct fw_card * card,
				   struct fw_node * node,
				   struct fw_node * parent);
330

331 332
static void for_each_fw_node(struct fw_card *card, struct fw_node *root,
			     fw_node_callback_t callback)
333 334 335 336 337 338 339 340 341 342 343 344 345 346
{
	struct list_head list;
	struct fw_node *node, *next, *child, *parent;
	int i;

	INIT_LIST_HEAD(&list);

	fw_node_get(root);
	list_add_tail(&root->link, &list);
	parent = NULL;
	list_for_each_entry(node, &list, link) {
		node->color = card->color;

		for (i = 0; i < node->port_count; i++) {
347
			child = node->ports[i];
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
			if (!child)
				continue;
			if (child->color == card->color)
				parent = child;
			else {
				fw_node_get(child);
				list_add_tail(&child->link, &list);
			}
		}

		callback(card, node, parent);
	}

	list_for_each_entry_safe(node, next, &list, link)
		fw_node_put(node);
}

365 366
static void report_lost_node(struct fw_card *card,
			     struct fw_node *node, struct fw_node *parent)
367 368 369
{
	fw_node_event(card, node, FW_NODE_DESTROYED);
	fw_node_put(node);
370 371 372

	/* Topology has changed - reset bus manager retry counter */
	card->bm_retries = 0;
373 374
}

375 376
static void report_found_node(struct fw_card *card,
			      struct fw_node *node, struct fw_node *parent)
377 378 379 380
{
	int b_path = (node->phy_speed == SCODE_BETA);

	if (parent != NULL) {
381 382 383
		/* min() macro doesn't work here with gcc 3.4 */
		node->max_speed = parent->max_speed < node->phy_speed ?
					parent->max_speed : node->phy_speed;
384 385 386 387 388 389 390
		node->b_path = parent->b_path && b_path;
	} else {
		node->max_speed = node->phy_speed;
		node->b_path = b_path;
	}

	fw_node_event(card, node, FW_NODE_CREATED);
391 392 393

	/* Topology has changed - reset bus manager retry counter */
	card->bm_retries = 0;
394 395 396 397 398 399 400 401 402 403
}

void fw_destroy_nodes(struct fw_card *card)
{
	unsigned long flags;

	spin_lock_irqsave(&card->lock, flags);
	card->color++;
	if (card->local_node != NULL)
		for_each_fw_node(card, card->local_node, report_lost_node);
404
	card->local_node = NULL;
405 406 407 408 409 410 411 412
	spin_unlock_irqrestore(&card->lock, flags);
}

static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
{
	struct fw_node *tree;
	int i;

413 414
	tree = node1->ports[port];
	node0->ports[port] = tree;
415
	for (i = 0; i < tree->port_count; i++) {
416 417
		if (tree->ports[i] == node1) {
			tree->ports[i] = node0;
418 419 420 421 422 423 424 425 426 427 428
			break;
		}
	}
}

/**
 * update_tree - compare the old topology tree for card with the new
 * one specified by root.  Queue the nodes and mark them as either
 * found, lost or updated.  Update the nodes in the card topology tree
 * as we go.
 */
429
static void update_tree(struct fw_card *card, struct fw_node *root)
430 431
{
	struct list_head list0, list1;
432
	struct fw_node *node0, *node1, *next1;
433 434 435 436 437 438 439 440 441 442 443
	int i, event;

	INIT_LIST_HEAD(&list0);
	list_add_tail(&card->local_node->link, &list0);
	INIT_LIST_HEAD(&list1);
	list_add_tail(&root->link, &list1);

	node0 = fw_node(list0.next);
	node1 = fw_node(list1.next);

	while (&node0->link != &list0) {
444
		WARN_ON(node0->port_count != node1->port_count);
445 446 447 448 449

		if (node0->link_on && !node1->link_on)
			event = FW_NODE_LINK_OFF;
		else if (!node0->link_on && node1->link_on)
			event = FW_NODE_LINK_ON;
450 451
		else if (node1->initiated_reset && node1->link_on)
			event = FW_NODE_INITIATED_RESET;
452 453 454 455 456 457 458
		else
			event = FW_NODE_UPDATED;

		node0->node_id = node1->node_id;
		node0->color = card->color;
		node0->link_on = node1->link_on;
		node0->initiated_reset = node1->initiated_reset;
459
		node0->max_hops = node1->max_hops;
460 461 462 463 464 465 466 467 468
		node1->color = card->color;
		fw_node_event(card, node0, event);

		if (card->root_node == node1)
			card->root_node = node0;
		if (card->irm_node == node1)
			card->irm_node = node0;

		for (i = 0; i < node0->port_count; i++) {
469
			if (node0->ports[i] && node1->ports[i]) {
470 471
				/*
				 * This port didn't change, queue the
472
				 * connected node for further
473 474
				 * investigation.
				 */
475
				if (node0->ports[i]->color == card->color)
476
					continue;
477 478 479
				list_add_tail(&node0->ports[i]->link, &list0);
				list_add_tail(&node1->ports[i]->link, &list1);
			} else if (node0->ports[i]) {
480 481
				/*
				 * The nodes connected here were
482 483
				 * unplugged; unref the lost nodes and
				 * queue FW_NODE_LOST callbacks for
484 485
				 * them.
				 */
486

487
				for_each_fw_node(card, node0->ports[i],
488
						 report_lost_node);
489 490
				node0->ports[i] = NULL;
			} else if (node1->ports[i]) {
491 492
				/*
				 * One or more node were connected to
493 494
				 * this port. Move the new nodes into
				 * the tree and queue FW_NODE_CREATED
495 496
				 * callbacks for them.
				 */
497
				move_tree(node0, node1, i);
498
				for_each_fw_node(card, node0->ports[i],
499 500 501 502 503
						 report_found_node);
			}
		}

		node0 = fw_node(node0->link.next);
504 505 506
		next1 = fw_node(node1->link.next);
		fw_node_put(node1);
		node1 = next1;
507 508 509
	}
}

510 511
static void update_topology_map(struct fw_card *card,
				u32 *self_ids, int self_id_count)
512
{
513 514 515 516 517 518 519 520 521
	int node_count = (card->root_node->node_id & 0x3f) + 1;
	__be32 *map = card->topology_map;

	*map++ = cpu_to_be32((self_id_count + 2) << 16);
	*map++ = cpu_to_be32(be32_to_cpu(card->topology_map[1]) + 1);
	*map++ = cpu_to_be32((node_count << 16) | self_id_count);

	while (self_id_count--)
		*map++ = cpu_to_be32p(self_ids++);
522

523
	fw_compute_block_crc(card->topology_map);
524 525
}

526
void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
527
			      int self_id_count, u32 *self_ids, bool bm_abdicate)
528 529 530 531
{
	struct fw_node *local_node;
	unsigned long flags;

532 533 534 535 536
	/*
	 * If the selfID buffer is not the immediate successor of the
	 * previously processed one, we cannot reliably compare the
	 * old and new topologies.
	 */
537
	if (!is_next_generation(generation, card->generation) &&
538 539 540 541 542 543
	    card->local_node != NULL) {
		fw_notify("skipped bus generations, destroying all nodes\n");
		fw_destroy_nodes(card);
		card->bm_retries = 0;
	}

544 545
	spin_lock_irqsave(&card->lock, flags);

546
	card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated;
547
	card->node_id = node_id;
548 549 550 551 552
	/*
	 * Update node_id before generation to prevent anybody from using
	 * a stale node_id together with a current generation.
	 */
	smp_wmb();
553
	card->generation = generation;
554
	card->reset_jiffies = jiffies;
555
	card->bm_abdicate = bm_abdicate;
556
	fw_schedule_bm_work(card, 0);
557

558 559 560
	local_node = build_tree(card, self_ids, self_id_count);

	update_topology_map(card, self_ids, self_id_count);
561 562 563 564 565 566 567 568 569 570

	card->color++;

	if (local_node == NULL) {
		fw_error("topology build failed\n");
		/* FIXME: We need to issue a bus reset in this case. */
	} else if (card->local_node == NULL) {
		card->local_node = local_node;
		for_each_fw_node(card, local_node, report_found_node);
	} else {
571
		update_tree(card, local_node);
572 573 574 575 576
	}

	spin_unlock_irqrestore(&card->lock, flags);
}
EXPORT_SYMBOL(fw_core_handle_bus_reset);