Blame view
drivers/firewire/core-topology.c
14.9 KB
c781c06d1 firewire: Clean u... |
1 2 |
/* * Incremental bus scan, based on bus topology |
3038e353c firewire: Add cor... |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
* * 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. */ |
e8ca97021 firewire: clean u... |
20 |
#include <linux/bug.h> |
3038e353c firewire: Add cor... |
21 |
#include <linux/errno.h> |
77c9a5daa firewire: reorgan... |
22 23 |
#include <linux/firewire.h> #include <linux/firewire-constants.h> |
e8ca97021 firewire: clean u... |
24 25 26 27 28 29 |
#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/spinlock.h> |
e8ca97021 firewire: clean u... |
30 |
|
60063497a atomic: use <linu... |
31 |
#include <linux/atomic.h> |
cb7c96da3 firewire: core: o... |
32 |
#include <asm/byteorder.h> |
b5d2a5e04 firewire: enforce... |
33 |
#include <asm/system.h> |
e8ca97021 firewire: clean u... |
34 |
|
77c9a5daa firewire: reorgan... |
35 |
#include "core.h" |
3038e353c firewire: Add cor... |
36 |
|
a77754a75 firewire: Upperca... |
37 38 39 40 41 42 43 44 |
#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) |
3038e353c firewire: Add cor... |
45 |
|
a77754a75 firewire: Upperca... |
46 |
#define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07) |
3038e353c firewire: Add cor... |
47 |
|
77c9a5daa firewire: reorgan... |
48 49 50 51 |
#define SELFID_PORT_CHILD 0x3 #define SELFID_PORT_PARENT 0x2 #define SELFID_PORT_NCONN 0x1 #define SELFID_PORT_NONE 0x0 |
3038e353c firewire: Add cor... |
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
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) { |
a77754a75 firewire: Upperca... |
78 |
if (!SELF_ID_MORE_PACKETS(q)) |
3038e353c firewire: Add cor... |
79 80 81 82 83 |
return sid + 1; shift = 16; sid++; q = *sid; |
c781c06d1 firewire: Clean u... |
84 85 |
/* * Check that the extra packets actually are |
3038e353c firewire: Add cor... |
86 87 |
* extended self ID packets and that the * sequence numbers in the extended self ID |
c781c06d1 firewire: Clean u... |
88 89 |
* packets increase as expected. */ |
3038e353c firewire: Add cor... |
90 |
|
a77754a75 firewire: Upperca... |
91 92 |
if (!SELF_ID_EXTENDED(q) || seq != SELF_ID_EXT_SEQUENCE(q)) |
3038e353c firewire: Add cor... |
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
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; } |
95688e97c firewire: cleanups |
108 |
static struct fw_node *fw_node_create(u32 sid, int port_count, int color) |
3038e353c firewire: Add cor... |
109 110 |
{ struct fw_node *node; |
2d826cc5c firewire: Always ... |
111 |
node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]), |
3038e353c firewire: Add cor... |
112 113 114 115 116 |
GFP_ATOMIC); if (node == NULL) return NULL; node->color = color; |
a77754a75 firewire: Upperca... |
117 118 119 |
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); |
c9755e14a firewire: reread ... |
120 |
node->initiated_reset = SELF_ID_PHY_INITIATOR(sid); |
3038e353c firewire: Add cor... |
121 122 123 124 125 126 127 |
node->port_count = port_count; atomic_set(&node->ref_count, 1); INIT_LIST_HEAD(&node->link); return node; } |
c781c06d1 firewire: Clean u... |
128 129 |
/* * Compute the maximum hop count for this node and it's children. The |
83db801ce firewire: Impleme... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
* 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++) { |
dae1a3aa8 firewire: simplif... |
149 |
if (node->ports[i] == NULL) |
83db801ce firewire: Impleme... |
150 |
continue; |
dae1a3aa8 firewire: simplif... |
151 152 |
if (node->ports[i]->max_hops > max_child_hops) max_child_hops = node->ports[i]->max_hops; |
83db801ce firewire: Impleme... |
153 |
|
dae1a3aa8 firewire: simplif... |
154 |
if (node->ports[i]->max_depth > depths[0]) { |
83db801ce firewire: Impleme... |
155 |
depths[1] = depths[0]; |
dae1a3aa8 firewire: simplif... |
156 157 158 |
depths[0] = node->ports[i]->max_depth; } else if (node->ports[i]->max_depth > depths[1]) depths[1] = node->ports[i]->max_depth; |
83db801ce firewire: Impleme... |
159 160 161 162 163 |
} node->max_depth = depths[0] + 1; node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2); } |
e5f84f82b firewire: a heade... |
164 165 166 167 |
static inline struct fw_node *fw_node(struct list_head *l) { return list_entry(l, struct fw_node, link); } |
83db801ce firewire: Impleme... |
168 |
|
656b7afd4 firewire: core: f... |
169 |
/* |
3038e353c firewire: Add cor... |
170 171 172 |
* 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 |
af901ca18 tree-wide: fix as... |
173 |
* internally consistent. On success this function returns the |
3038e353c firewire: Add cor... |
174 175 |
* fw_node corresponding to the local card otherwise NULL. */ |
473d28c73 firewire: Impleme... |
176 177 |
static struct fw_node *build_tree(struct fw_card *card, u32 *sid, int self_id_count) |
3038e353c firewire: Add cor... |
178 |
{ |
93e4fd455 firewire: Don't s... |
179 |
struct fw_node *node, *child, *local_node, *irm_node; |
3038e353c firewire: Add cor... |
180 |
struct list_head stack, *h; |
473d28c73 firewire: Impleme... |
181 |
u32 *next_sid, *end, q; |
3038e353c firewire: Add cor... |
182 |
int i, port_count, child_port_count, phy_id, parent_count, stack_depth; |
24d40125f firewire: optimiz... |
183 184 |
int gap_count; bool beta_repeaters_present; |
3038e353c firewire: Add cor... |
185 186 187 188 189 |
local_node = NULL; node = NULL; INIT_LIST_HEAD(&stack); stack_depth = 0; |
473d28c73 firewire: Impleme... |
190 |
end = sid + self_id_count; |
3038e353c firewire: Add cor... |
191 |
phy_id = 0; |
93e4fd455 firewire: Don't s... |
192 |
irm_node = NULL; |
a77754a75 firewire: Upperca... |
193 |
gap_count = SELF_ID_GAP_COUNT(*sid); |
24d40125f firewire: optimiz... |
194 |
beta_repeaters_present = false; |
3038e353c firewire: Add cor... |
195 196 197 198 199 200 201 202 203 204 205 |
while (sid < end) { next_sid = count_ports(sid, &port_count, &child_port_count); if (next_sid == NULL) { fw_error("Inconsistent extended self IDs. "); return NULL; } q = *sid; |
a77754a75 firewire: Upperca... |
206 |
if (phy_id != SELF_ID_PHY_ID(q)) { |
3038e353c firewire: Add cor... |
207 208 |
fw_error("PHY ID mismatch in self ID: %d != %d. ", |
a77754a75 firewire: Upperca... |
209 |
phy_id, SELF_ID_PHY_ID(q)); |
3038e353c firewire: Add cor... |
210 211 212 213 214 215 216 217 |
return NULL; } if (child_port_count > stack_depth) { fw_error("Topology stack underflow "); return NULL; } |
c781c06d1 firewire: Clean u... |
218 219 220 221 |
/* * Seek back from the top of our stack to find the * start of the child nodes for this node. */ |
3038e353c firewire: Add cor... |
222 223 |
for (i = 0, h = &stack; i < child_port_count; i++) h = h->prev; |
c1b91ce49 firewire: in-code... |
224 225 226 227 |
/* * When the stack is empty, this yields an invalid value, * but that pointer will never be dereferenced. */ |
3038e353c firewire: Add cor... |
228 229 230 231 |
child = fw_node(h); node = fw_node_create(q, port_count, card->color); if (node == NULL) { |
8a8cea273 firewire: missing... |
232 233 |
fw_error("Out of memory while building topology. "); |
3038e353c firewire: Add cor... |
234 235 236 237 238 |
return NULL; } if (phy_id == (card->node_id & 0x3f)) local_node = node; |
a77754a75 firewire: Upperca... |
239 |
if (SELF_ID_CONTENDER(q)) |
93e4fd455 firewire: Don't s... |
240 |
irm_node = node; |
3038e353c firewire: Add cor... |
241 242 243 244 245 246 |
parent_count = 0; for (i = 0; i < port_count; i++) { switch (get_port_type(sid, i)) { case SELFID_PORT_PARENT: |
c781c06d1 firewire: Clean u... |
247 248 |
/* * Who's your daddy? We dont know the |
3038e353c firewire: Add cor... |
249 250 251 252 253 254 255 256 257 258 259 260 261 |
* 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: |
dae1a3aa8 firewire: simplif... |
262 |
node->ports[i] = child; |
c781c06d1 firewire: Clean u... |
263 264 265 266 |
/* * Fix up parent reference for this * child node. */ |
dae1a3aa8 firewire: simplif... |
267 |
child->ports[child->color] = node; |
3038e353c firewire: Add cor... |
268 269 270 271 272 |
child->color = card->color; child = fw_node(child->link.next); break; } } |
c781c06d1 firewire: Clean u... |
273 274 |
/* * Check that the node reports exactly one parent |
3038e353c firewire: Add cor... |
275 |
* port, except for the root, which of course should |
c781c06d1 firewire: Clean u... |
276 277 |
* have no parents. */ |
3038e353c firewire: Add cor... |
278 279 280 281 282 283 284 285 286 287 288 289 |
if ((next_sid == end && parent_count != 0) || (next_sid < end && parent_count != 1)) { fw_error("Parent port inconsistency for node %d: " "parent_count=%d ", 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; |
24d40125f firewire: optimiz... |
290 291 292 |
if (node->phy_speed == SCODE_BETA && parent_count + child_port_count > 1) beta_repeaters_present = true; |
c781c06d1 firewire: Clean u... |
293 |
/* |
25b1c3d88 firewire: fix syn... |
294 295 |
* If PHYs report different gap counts, set an invalid count * which will force a gap count reconfiguration and a reset. |
c781c06d1 firewire: Clean u... |
296 |
*/ |
a77754a75 firewire: Upperca... |
297 |
if (SELF_ID_GAP_COUNT(q) != gap_count) |
25b1c3d88 firewire: fix syn... |
298 |
gap_count = 0; |
83db801ce firewire: Impleme... |
299 300 |
update_hop_count(node); |
3038e353c firewire: Add cor... |
301 302 303 304 305 |
sid = next_sid; phy_id++; } card->root_node = node; |
93e4fd455 firewire: Don't s... |
306 |
card->irm_node = irm_node; |
83db801ce firewire: Impleme... |
307 |
card->gap_count = gap_count; |
24d40125f firewire: optimiz... |
308 |
card->beta_repeaters_present = beta_repeaters_present; |
3038e353c firewire: Add cor... |
309 310 311 |
return local_node; } |
a98e27198 firewire: Coding ... |
312 313 314 |
typedef void (*fw_node_callback_t)(struct fw_card * card, struct fw_node * node, struct fw_node * parent); |
3038e353c firewire: Add cor... |
315 |
|
53dca5117 firewire: remove ... |
316 317 |
static void for_each_fw_node(struct fw_card *card, struct fw_node *root, fw_node_callback_t callback) |
3038e353c firewire: Add cor... |
318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
{ 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++) { |
dae1a3aa8 firewire: simplif... |
332 |
child = node->ports[i]; |
3038e353c firewire: Add cor... |
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
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); } |
53dca5117 firewire: remove ... |
349 350 |
static void report_lost_node(struct fw_card *card, struct fw_node *node, struct fw_node *parent) |
3038e353c firewire: Add cor... |
351 352 353 |
{ fw_node_event(card, node, FW_NODE_DESTROYED); fw_node_put(node); |
d6f95a3d1 firewire: fix res... |
354 355 356 |
/* Topology has changed - reset bus manager retry counter */ card->bm_retries = 0; |
3038e353c firewire: Add cor... |
357 |
} |
53dca5117 firewire: remove ... |
358 359 |
static void report_found_node(struct fw_card *card, struct fw_node *node, struct fw_node *parent) |
3038e353c firewire: Add cor... |
360 361 362 363 |
{ int b_path = (node->phy_speed == SCODE_BETA); if (parent != NULL) { |
748086eb5 firewire: fix com... |
364 365 366 |
/* 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; |
3038e353c firewire: Add cor... |
367 368 369 370 371 372 373 |
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); |
d6f95a3d1 firewire: fix res... |
374 375 376 |
/* Topology has changed - reset bus manager retry counter */ card->bm_retries = 0; |
3038e353c firewire: Add cor... |
377 378 379 380 381 382 383 384 385 386 |
} 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); |
15803478f firewire: potenti... |
387 |
card->local_node = NULL; |
3038e353c firewire: Add cor... |
388 389 390 391 392 393 394 |
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; |
dae1a3aa8 firewire: simplif... |
395 396 |
tree = node1->ports[port]; node0->ports[port] = tree; |
3038e353c firewire: Add cor... |
397 |
for (i = 0; i < tree->port_count; i++) { |
dae1a3aa8 firewire: simplif... |
398 399 |
if (tree->ports[i] == node1) { tree->ports[i] = node0; |
3038e353c firewire: Add cor... |
400 401 402 403 |
break; } } } |
656b7afd4 firewire: core: f... |
404 405 406 407 |
/* * 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. |
3038e353c firewire: Add cor... |
408 |
*/ |
53dca5117 firewire: remove ... |
409 |
static void update_tree(struct fw_card *card, struct fw_node *root) |
3038e353c firewire: Add cor... |
410 411 |
{ struct list_head list0, list1; |
77e557191 firewire: fix str... |
412 |
struct fw_node *node0, *node1, *next1; |
3038e353c firewire: Add cor... |
413 414 415 416 417 418 419 420 421 |
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); |
3038e353c firewire: Add cor... |
422 423 |
while (&node0->link != &list0) { |
a2cdebe33 firewire: warn on... |
424 |
WARN_ON(node0->port_count != node1->port_count); |
3038e353c firewire: Add cor... |
425 |
|
3038e353c firewire: Add cor... |
426 427 428 429 |
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; |
c9755e14a firewire: reread ... |
430 431 |
else if (node1->initiated_reset && node1->link_on) event = FW_NODE_INITIATED_RESET; |
3038e353c firewire: Add cor... |
432 433 434 435 436 437 438 |
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; |
83db801ce firewire: Impleme... |
439 |
node0->max_hops = node1->max_hops; |
3038e353c firewire: Add cor... |
440 441 442 443 444 445 446 447 448 |
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++) { |
dae1a3aa8 firewire: simplif... |
449 |
if (node0->ports[i] && node1->ports[i]) { |
c781c06d1 firewire: Clean u... |
450 451 |
/* * This port didn't change, queue the |
3038e353c firewire: Add cor... |
452 |
* connected node for further |
c781c06d1 firewire: Clean u... |
453 454 |
* investigation. */ |
dae1a3aa8 firewire: simplif... |
455 |
if (node0->ports[i]->color == card->color) |
3038e353c firewire: Add cor... |
456 |
continue; |
dae1a3aa8 firewire: simplif... |
457 458 459 |
list_add_tail(&node0->ports[i]->link, &list0); list_add_tail(&node1->ports[i]->link, &list1); } else if (node0->ports[i]) { |
c781c06d1 firewire: Clean u... |
460 461 |
/* * The nodes connected here were |
3038e353c firewire: Add cor... |
462 463 |
* unplugged; unref the lost nodes and * queue FW_NODE_LOST callbacks for |
c781c06d1 firewire: Clean u... |
464 465 |
* them. */ |
3038e353c firewire: Add cor... |
466 |
|
dae1a3aa8 firewire: simplif... |
467 |
for_each_fw_node(card, node0->ports[i], |
3038e353c firewire: Add cor... |
468 |
report_lost_node); |
dae1a3aa8 firewire: simplif... |
469 470 |
node0->ports[i] = NULL; } else if (node1->ports[i]) { |
c781c06d1 firewire: Clean u... |
471 472 |
/* * One or more node were connected to |
3038e353c firewire: Add cor... |
473 474 |
* this port. Move the new nodes into * the tree and queue FW_NODE_CREATED |
c781c06d1 firewire: Clean u... |
475 476 |
* callbacks for them. */ |
3038e353c firewire: Add cor... |
477 |
move_tree(node0, node1, i); |
dae1a3aa8 firewire: simplif... |
478 |
for_each_fw_node(card, node0->ports[i], |
3038e353c firewire: Add cor... |
479 |
report_found_node); |
3038e353c firewire: Add cor... |
480 481 482 483 |
} } node0 = fw_node(node0->link.next); |
77e557191 firewire: fix str... |
484 485 486 |
next1 = fw_node(node1->link.next); fw_node_put(node1); node1 = next1; |
3038e353c firewire: Add cor... |
487 488 |
} } |
53dca5117 firewire: remove ... |
489 490 |
static void update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count) |
473d28c73 firewire: Impleme... |
491 |
{ |
cb7c96da3 firewire: core: o... |
492 493 494 495 496 497 498 499 500 |
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++); |
473d28c73 firewire: Impleme... |
501 |
|
e175569c4 firewire: Use lib... |
502 |
fw_compute_block_crc(card->topology_map); |
473d28c73 firewire: Impleme... |
503 |
} |
53dca5117 firewire: remove ... |
504 |
void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, |
c8a94ded5 firewire: normali... |
505 |
int self_id_count, u32 *self_ids, bool bm_abdicate) |
3038e353c firewire: Add cor... |
506 507 508 |
{ struct fw_node *local_node; unsigned long flags; |
3038e353c firewire: Add cor... |
509 |
|
a5c7f4710 firewire: insist ... |
510 511 512 513 514 |
/* * If the selfID buffer is not the immediate successor of the * previously processed one, we cannot reliably compare the * old and new topologies. */ |
8cd0bbbdf firewire: unneces... |
515 |
if (!is_next_generation(generation, card->generation) && |
a5c7f4710 firewire: insist ... |
516 517 518 519 520 521 |
card->local_node != NULL) { fw_notify("skipped bus generations, destroying all nodes "); fw_destroy_nodes(card); card->bm_retries = 0; } |
3038e353c firewire: Add cor... |
522 |
spin_lock_irqsave(&card->lock, flags); |
db3c9cc10 firewire: replace... |
523 |
card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated; |
3038e353c firewire: Add cor... |
524 |
card->node_id = node_id; |
b5d2a5e04 firewire: enforce... |
525 526 527 528 529 |
/* * Update node_id before generation to prevent anybody from using * a stale node_id together with a current generation. */ smp_wmb(); |
3038e353c firewire: Add cor... |
530 |
card->generation = generation; |
e71084af5 firewire: core: f... |
531 |
card->reset_jiffies = get_jiffies_64(); |
250b2b6dd firewire: cdev: f... |
532 |
card->bm_node_id = 0xffff; |
c8a94ded5 firewire: normali... |
533 |
card->bm_abdicate = bm_abdicate; |
0fa1986f3 firewire: improve... |
534 |
fw_schedule_bm_work(card, 0); |
3038e353c firewire: Add cor... |
535 |
|
473d28c73 firewire: Impleme... |
536 537 538 |
local_node = build_tree(card, self_ids, self_id_count); update_topology_map(card, self_ids, self_id_count); |
3038e353c firewire: Add cor... |
539 540 541 542 543 544 545 546 547 548 549 |
card->color++; if (local_node == NULL) { fw_error("topology build failed "); /* 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 { |
83db801ce firewire: Impleme... |
550 |
update_tree(card, local_node); |
3038e353c firewire: Add cor... |
551 552 553 554 |
} spin_unlock_irqrestore(&card->lock, flags); } |
3038e353c firewire: Add cor... |
555 |
EXPORT_SYMBOL(fw_core_handle_bus_reset); |