Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26 553 lines 15 kB view raw
1/* 2 * Incremental bus scan, based on bus topology 3 * 4 * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software Foundation, 18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 */ 20 21#include <linux/module.h> 22#include <linux/wait.h> 23#include <linux/errno.h> 24#include <asm/bug.h> 25#include <asm/system.h> 26#include "fw-transaction.h" 27#include "fw-topology.h" 28 29#define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f) 30#define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01) 31#define SELF_ID_LINK_ON(q) (((q) >> 22) & 0x01) 32#define SELF_ID_GAP_COUNT(q) (((q) >> 16) & 0x3f) 33#define SELF_ID_PHY_SPEED(q) (((q) >> 14) & 0x03) 34#define SELF_ID_CONTENDER(q) (((q) >> 11) & 0x01) 35#define SELF_ID_PHY_INITIATOR(q) (((q) >> 1) & 0x01) 36#define SELF_ID_MORE_PACKETS(q) (((q) >> 0) & 0x01) 37 38#define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07) 39 40static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count) 41{ 42 u32 q; 43 int port_type, shift, seq; 44 45 *total_port_count = 0; 46 *child_port_count = 0; 47 48 shift = 6; 49 q = *sid; 50 seq = 0; 51 52 while (1) { 53 port_type = (q >> shift) & 0x03; 54 switch (port_type) { 55 case SELFID_PORT_CHILD: 56 (*child_port_count)++; 57 case SELFID_PORT_PARENT: 58 case SELFID_PORT_NCONN: 59 (*total_port_count)++; 60 case SELFID_PORT_NONE: 61 break; 62 } 63 64 shift -= 2; 65 if (shift == 0) { 66 if (!SELF_ID_MORE_PACKETS(q)) 67 return sid + 1; 68 69 shift = 16; 70 sid++; 71 q = *sid; 72 73 /* 74 * Check that the extra packets actually are 75 * extended self ID packets and that the 76 * sequence numbers in the extended self ID 77 * packets increase as expected. 78 */ 79 80 if (!SELF_ID_EXTENDED(q) || 81 seq != SELF_ID_EXT_SEQUENCE(q)) 82 return NULL; 83 84 seq++; 85 } 86 } 87} 88 89static int get_port_type(u32 *sid, int port_index) 90{ 91 int index, shift; 92 93 index = (port_index + 5) / 8; 94 shift = 16 - ((port_index + 5) & 7) * 2; 95 return (sid[index] >> shift) & 0x03; 96} 97 98static struct fw_node *fw_node_create(u32 sid, int port_count, int color) 99{ 100 struct fw_node *node; 101 102 node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]), 103 GFP_ATOMIC); 104 if (node == NULL) 105 return NULL; 106 107 node->color = color; 108 node->node_id = LOCAL_BUS | SELF_ID_PHY_ID(sid); 109 node->link_on = SELF_ID_LINK_ON(sid); 110 node->phy_speed = SELF_ID_PHY_SPEED(sid); 111 node->initiated_reset = SELF_ID_PHY_INITIATOR(sid); 112 node->port_count = port_count; 113 114 atomic_set(&node->ref_count, 1); 115 INIT_LIST_HEAD(&node->link); 116 117 return node; 118} 119 120/* 121 * Compute the maximum hop count for this node and it's children. The 122 * maximum hop count is the maximum number of connections between any 123 * two nodes in the subtree rooted at this node. We need this for 124 * setting the gap count. As we build the tree bottom up in 125 * build_tree() below, this is fairly easy to do: for each node we 126 * maintain the max hop count and the max depth, ie the number of hops 127 * to the furthest leaf. Computing the max hop count breaks down into 128 * two cases: either the path goes through this node, in which case 129 * the hop count is the sum of the two biggest child depths plus 2. 130 * Or it could be the case that the max hop path is entirely 131 * containted in a child tree, in which case the max hop count is just 132 * the max hop count of this child. 133 */ 134static void update_hop_count(struct fw_node *node) 135{ 136 int depths[2] = { -1, -1 }; 137 int max_child_hops = 0; 138 int i; 139 140 for (i = 0; i < node->port_count; i++) { 141 if (node->ports[i] == NULL) 142 continue; 143 144 if (node->ports[i]->max_hops > max_child_hops) 145 max_child_hops = node->ports[i]->max_hops; 146 147 if (node->ports[i]->max_depth > depths[0]) { 148 depths[1] = depths[0]; 149 depths[0] = node->ports[i]->max_depth; 150 } else if (node->ports[i]->max_depth > depths[1]) 151 depths[1] = node->ports[i]->max_depth; 152 } 153 154 node->max_depth = depths[0] + 1; 155 node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2); 156} 157 158static inline struct fw_node *fw_node(struct list_head *l) 159{ 160 return list_entry(l, struct fw_node, link); 161} 162 163/** 164 * build_tree - Build the tree representation of the topology 165 * @self_ids: array of self IDs to create the tree from 166 * @self_id_count: the length of the self_ids array 167 * @local_id: the node ID of the local node 168 * 169 * This function builds the tree representation of the topology given 170 * by the self IDs from the latest bus reset. During the construction 171 * of the tree, the function checks that the self IDs are valid and 172 * internally consistent. On succcess this function returns the 173 * fw_node corresponding to the local card otherwise NULL. 174 */ 175static struct fw_node *build_tree(struct fw_card *card, 176 u32 *sid, int self_id_count) 177{ 178 struct fw_node *node, *child, *local_node, *irm_node; 179 struct list_head stack, *h; 180 u32 *next_sid, *end, q; 181 int i, port_count, child_port_count, phy_id, parent_count, stack_depth; 182 int gap_count; 183 bool beta_repeaters_present; 184 185 local_node = NULL; 186 node = NULL; 187 INIT_LIST_HEAD(&stack); 188 stack_depth = 0; 189 end = sid + self_id_count; 190 phy_id = 0; 191 irm_node = NULL; 192 gap_count = SELF_ID_GAP_COUNT(*sid); 193 beta_repeaters_present = false; 194 195 while (sid < end) { 196 next_sid = count_ports(sid, &port_count, &child_port_count); 197 198 if (next_sid == NULL) { 199 fw_error("Inconsistent extended self IDs.\n"); 200 return NULL; 201 } 202 203 q = *sid; 204 if (phy_id != SELF_ID_PHY_ID(q)) { 205 fw_error("PHY ID mismatch in self ID: %d != %d.\n", 206 phy_id, SELF_ID_PHY_ID(q)); 207 return NULL; 208 } 209 210 if (child_port_count > stack_depth) { 211 fw_error("Topology stack underflow\n"); 212 return NULL; 213 } 214 215 /* 216 * Seek back from the top of our stack to find the 217 * start of the child nodes for this node. 218 */ 219 for (i = 0, h = &stack; i < child_port_count; i++) 220 h = h->prev; 221 /* 222 * When the stack is empty, this yields an invalid value, 223 * but that pointer will never be dereferenced. 224 */ 225 child = fw_node(h); 226 227 node = fw_node_create(q, port_count, card->color); 228 if (node == NULL) { 229 fw_error("Out of memory while building topology.\n"); 230 return NULL; 231 } 232 233 if (phy_id == (card->node_id & 0x3f)) 234 local_node = node; 235 236 if (SELF_ID_CONTENDER(q)) 237 irm_node = node; 238 239 parent_count = 0; 240 241 for (i = 0; i < port_count; i++) { 242 switch (get_port_type(sid, i)) { 243 case SELFID_PORT_PARENT: 244 /* 245 * Who's your daddy? We dont know the 246 * parent node at this time, so we 247 * temporarily abuse node->color for 248 * remembering the entry in the 249 * node->ports array where the parent 250 * node should be. Later, when we 251 * handle the parent node, we fix up 252 * the reference. 253 */ 254 parent_count++; 255 node->color = i; 256 break; 257 258 case SELFID_PORT_CHILD: 259 node->ports[i] = child; 260 /* 261 * Fix up parent reference for this 262 * child node. 263 */ 264 child->ports[child->color] = node; 265 child->color = card->color; 266 child = fw_node(child->link.next); 267 break; 268 } 269 } 270 271 /* 272 * Check that the node reports exactly one parent 273 * port, except for the root, which of course should 274 * have no parents. 275 */ 276 if ((next_sid == end && parent_count != 0) || 277 (next_sid < end && parent_count != 1)) { 278 fw_error("Parent port inconsistency for node %d: " 279 "parent_count=%d\n", phy_id, parent_count); 280 return NULL; 281 } 282 283 /* Pop the child nodes off the stack and push the new node. */ 284 __list_del(h->prev, &stack); 285 list_add_tail(&node->link, &stack); 286 stack_depth += 1 - child_port_count; 287 288 if (node->phy_speed == SCODE_BETA && 289 parent_count + child_port_count > 1) 290 beta_repeaters_present = true; 291 292 /* 293 * If PHYs report different gap counts, set an invalid count 294 * which will force a gap count reconfiguration and a reset. 295 */ 296 if (SELF_ID_GAP_COUNT(q) != gap_count) 297 gap_count = 0; 298 299 update_hop_count(node); 300 301 sid = next_sid; 302 phy_id++; 303 } 304 305 card->root_node = node; 306 card->irm_node = irm_node; 307 card->gap_count = gap_count; 308 card->beta_repeaters_present = beta_repeaters_present; 309 310 return local_node; 311} 312 313typedef void (*fw_node_callback_t)(struct fw_card * card, 314 struct fw_node * node, 315 struct fw_node * parent); 316 317static void 318for_each_fw_node(struct fw_card *card, struct fw_node *root, 319 fw_node_callback_t callback) 320{ 321 struct list_head list; 322 struct fw_node *node, *next, *child, *parent; 323 int i; 324 325 INIT_LIST_HEAD(&list); 326 327 fw_node_get(root); 328 list_add_tail(&root->link, &list); 329 parent = NULL; 330 list_for_each_entry(node, &list, link) { 331 node->color = card->color; 332 333 for (i = 0; i < node->port_count; i++) { 334 child = node->ports[i]; 335 if (!child) 336 continue; 337 if (child->color == card->color) 338 parent = child; 339 else { 340 fw_node_get(child); 341 list_add_tail(&child->link, &list); 342 } 343 } 344 345 callback(card, node, parent); 346 } 347 348 list_for_each_entry_safe(node, next, &list, link) 349 fw_node_put(node); 350} 351 352static void 353report_lost_node(struct fw_card *card, 354 struct fw_node *node, struct fw_node *parent) 355{ 356 fw_node_event(card, node, FW_NODE_DESTROYED); 357 fw_node_put(node); 358} 359 360static void 361report_found_node(struct fw_card *card, 362 struct fw_node *node, struct fw_node *parent) 363{ 364 int b_path = (node->phy_speed == SCODE_BETA); 365 366 if (parent != NULL) { 367 /* min() macro doesn't work here with gcc 3.4 */ 368 node->max_speed = parent->max_speed < node->phy_speed ? 369 parent->max_speed : node->phy_speed; 370 node->b_path = parent->b_path && b_path; 371 } else { 372 node->max_speed = node->phy_speed; 373 node->b_path = b_path; 374 } 375 376 fw_node_event(card, node, FW_NODE_CREATED); 377} 378 379void fw_destroy_nodes(struct fw_card *card) 380{ 381 unsigned long flags; 382 383 spin_lock_irqsave(&card->lock, flags); 384 card->color++; 385 if (card->local_node != NULL) 386 for_each_fw_node(card, card->local_node, report_lost_node); 387 card->local_node = NULL; 388 spin_unlock_irqrestore(&card->lock, flags); 389} 390 391static void move_tree(struct fw_node *node0, struct fw_node *node1, int port) 392{ 393 struct fw_node *tree; 394 int i; 395 396 tree = node1->ports[port]; 397 node0->ports[port] = tree; 398 for (i = 0; i < tree->port_count; i++) { 399 if (tree->ports[i] == node1) { 400 tree->ports[i] = node0; 401 break; 402 } 403 } 404} 405 406/** 407 * update_tree - compare the old topology tree for card with the new 408 * one specified by root. Queue the nodes and mark them as either 409 * found, lost or updated. Update the nodes in the card topology tree 410 * as we go. 411 */ 412static void 413update_tree(struct fw_card *card, struct fw_node *root) 414{ 415 struct list_head list0, list1; 416 struct fw_node *node0, *node1; 417 int i, event; 418 419 INIT_LIST_HEAD(&list0); 420 list_add_tail(&card->local_node->link, &list0); 421 INIT_LIST_HEAD(&list1); 422 list_add_tail(&root->link, &list1); 423 424 node0 = fw_node(list0.next); 425 node1 = fw_node(list1.next); 426 427 while (&node0->link != &list0) { 428 WARN_ON(node0->port_count != node1->port_count); 429 430 if (node0->link_on && !node1->link_on) 431 event = FW_NODE_LINK_OFF; 432 else if (!node0->link_on && node1->link_on) 433 event = FW_NODE_LINK_ON; 434 else if (node1->initiated_reset && node1->link_on) 435 event = FW_NODE_INITIATED_RESET; 436 else 437 event = FW_NODE_UPDATED; 438 439 node0->node_id = node1->node_id; 440 node0->color = card->color; 441 node0->link_on = node1->link_on; 442 node0->initiated_reset = node1->initiated_reset; 443 node0->max_hops = node1->max_hops; 444 node1->color = card->color; 445 fw_node_event(card, node0, event); 446 447 if (card->root_node == node1) 448 card->root_node = node0; 449 if (card->irm_node == node1) 450 card->irm_node = node0; 451 452 for (i = 0; i < node0->port_count; i++) { 453 if (node0->ports[i] && node1->ports[i]) { 454 /* 455 * This port didn't change, queue the 456 * connected node for further 457 * investigation. 458 */ 459 if (node0->ports[i]->color == card->color) 460 continue; 461 list_add_tail(&node0->ports[i]->link, &list0); 462 list_add_tail(&node1->ports[i]->link, &list1); 463 } else if (node0->ports[i]) { 464 /* 465 * The nodes connected here were 466 * unplugged; unref the lost nodes and 467 * queue FW_NODE_LOST callbacks for 468 * them. 469 */ 470 471 for_each_fw_node(card, node0->ports[i], 472 report_lost_node); 473 node0->ports[i] = NULL; 474 } else if (node1->ports[i]) { 475 /* 476 * One or more node were connected to 477 * this port. Move the new nodes into 478 * the tree and queue FW_NODE_CREATED 479 * callbacks for them. 480 */ 481 move_tree(node0, node1, i); 482 for_each_fw_node(card, node0->ports[i], 483 report_found_node); 484 } 485 } 486 487 node0 = fw_node(node0->link.next); 488 node1 = fw_node(node1->link.next); 489 } 490} 491 492static void 493update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count) 494{ 495 int node_count; 496 497 card->topology_map[1]++; 498 node_count = (card->root_node->node_id & 0x3f) + 1; 499 card->topology_map[2] = (node_count << 16) | self_id_count; 500 card->topology_map[0] = (self_id_count + 2) << 16; 501 memcpy(&card->topology_map[3], self_ids, self_id_count * 4); 502 fw_compute_block_crc(card->topology_map); 503} 504 505void 506fw_core_handle_bus_reset(struct fw_card *card, 507 int node_id, int generation, 508 int self_id_count, u32 * self_ids) 509{ 510 struct fw_node *local_node; 511 unsigned long flags; 512 513 fw_flush_transactions(card); 514 515 spin_lock_irqsave(&card->lock, flags); 516 517 /* 518 * If the new topology has a different self_id_count the topology 519 * changed, either nodes were added or removed. In that case we 520 * reset the IRM reset counter. 521 */ 522 if (card->self_id_count != self_id_count) 523 card->bm_retries = 0; 524 525 card->node_id = node_id; 526 /* 527 * Update node_id before generation to prevent anybody from using 528 * a stale node_id together with a current generation. 529 */ 530 smp_wmb(); 531 card->generation = generation; 532 card->reset_jiffies = jiffies; 533 schedule_delayed_work(&card->work, 0); 534 535 local_node = build_tree(card, self_ids, self_id_count); 536 537 update_topology_map(card, self_ids, self_id_count); 538 539 card->color++; 540 541 if (local_node == NULL) { 542 fw_error("topology build failed\n"); 543 /* FIXME: We need to issue a bus reset in this case. */ 544 } else if (card->local_node == NULL) { 545 card->local_node = local_node; 546 for_each_fw_node(card, local_node, report_found_node); 547 } else { 548 update_tree(card, local_node); 549 } 550 551 spin_unlock_irqrestore(&card->lock, flags); 552} 553EXPORT_SYMBOL(fw_core_handle_bus_reset);