aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-card.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-08 10:09:06 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-13 03:58:27 -0400
commit02d37bed188c500ee7afb0a2dc6b65a80704c58e (patch)
treea019891672a1505e35eb15fa2621caffecff2c80 /drivers/firewire/core-card.c
parent8b4f70ba4967cae90d128857af1382026a24230a (diff)
firewire: core: integrate software-forced bus resets with bus management
Bus resets which are triggered - by the kernel drivers after updates of the local nodes' config ROM, - by userspace software via ioctl shall be deferred until after >=2 seconds after the last bus reset. If multiple modifications of the local nodes' config ROM happen in a row, only a single bus reset should happen after them. When the local node's link goes from inactive to active or vice versa, and at the two occasions of bus resets mentioned above --- and if the current gap count differs from 63 --- the bus reset should be preceded by a PHY configuration packet that reaffirms the gap count. Otherwise a bus manager would have to reset the bus again right after that. This is necessary to promote bus stability, e.g. leave grace periods for allocations and reallocations of isochronous channels and bandwidth, SBP-2 reconnections etc.; see IEEE 1394 clause 8.2.1. This change implements all of the above by moving bus reset initiation into a delayed work (except for bus resets which are triggered by the bus manager workqueue job and are performed there immediately). It comes with a necessary addition to the card driver methods that allows to get the current gap count from PHY registers. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/core-card.c')
-rw-r--r--drivers/firewire/core-card.c68
1 files changed, 52 insertions, 16 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 6c316cfe70c4..2bb5c036e806 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -204,6 +204,45 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
204} 204}
205EXPORT_SYMBOL(fw_core_remove_descriptor); 205EXPORT_SYMBOL(fw_core_remove_descriptor);
206 206
207static int reset_bus(struct fw_card *card, bool short_reset)
208{
209 int reg = short_reset ? 5 : 1;
210 int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
211
212 return card->driver->update_phy_reg(card, reg, 0, bit);
213}
214
215void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset)
216{
217 /* We don't try hard to sort out requests of long vs. short resets. */
218 card->br_short = short_reset;
219
220 /* Use an arbitrary short delay to combine multiple reset requests. */
221 fw_card_get(card);
222 if (!schedule_delayed_work(&card->br_work,
223 delayed ? DIV_ROUND_UP(HZ, 100) : 0))
224 fw_card_put(card);
225}
226EXPORT_SYMBOL(fw_schedule_bus_reset);
227
228static void br_work(struct work_struct *work)
229{
230 struct fw_card *card = container_of(work, struct fw_card, br_work.work);
231
232 /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
233 if (card->reset_jiffies != 0 &&
234 time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) {
235 if (!schedule_delayed_work(&card->br_work, 2 * HZ))
236 fw_card_put(card);
237 return;
238 }
239
240 fw_send_phy_config(card, FW_PHY_CONFIG_NO_NODE_ID, card->generation,
241 FW_PHY_CONFIG_CURRENT_GAP_COUNT);
242 reset_bus(card, card->br_short);
243 fw_card_put(card);
244}
245
207static void allocate_broadcast_channel(struct fw_card *card, int generation) 246static void allocate_broadcast_channel(struct fw_card *card, int generation)
208{ 247{
209 int channel, bandwidth = 0; 248 int channel, bandwidth = 0;
@@ -230,13 +269,13 @@ static const char gap_count_table[] = {
230void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) 269void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
231{ 270{
232 fw_card_get(card); 271 fw_card_get(card);
233 if (!schedule_delayed_work(&card->work, delay)) 272 if (!schedule_delayed_work(&card->bm_work, delay))
234 fw_card_put(card); 273 fw_card_put(card);
235} 274}
236 275
237static void fw_card_bm_work(struct work_struct *work) 276static void bm_work(struct work_struct *work)
238{ 277{
239 struct fw_card *card = container_of(work, struct fw_card, work.work); 278 struct fw_card *card = container_of(work, struct fw_card, bm_work.work);
240 struct fw_device *root_device; 279 struct fw_device *root_device;
241 struct fw_node *root_node; 280 struct fw_node *root_node;
242 int root_id, new_root_id, irm_id, bm_id, local_id; 281 int root_id, new_root_id, irm_id, bm_id, local_id;
@@ -413,7 +452,7 @@ static void fw_card_bm_work(struct work_struct *work)
413 fw_notify("phy config: card %d, new root=%x, gap_count=%d\n", 452 fw_notify("phy config: card %d, new root=%x, gap_count=%d\n",
414 card->index, new_root_id, gap_count); 453 card->index, new_root_id, gap_count);
415 fw_send_phy_config(card, new_root_id, generation, gap_count); 454 fw_send_phy_config(card, new_root_id, generation, gap_count);
416 fw_core_initiate_bus_reset(card, 1); 455 reset_bus(card, true);
417 /* Will allocate broadcast channel after the reset. */ 456 /* Will allocate broadcast channel after the reset. */
418 goto out; 457 goto out;
419 } 458 }
@@ -465,7 +504,8 @@ void fw_card_initialize(struct fw_card *card,
465 504
466 card->local_node = NULL; 505 card->local_node = NULL;
467 506
468 INIT_DELAYED_WORK(&card->work, fw_card_bm_work); 507 INIT_DELAYED_WORK(&card->br_work, br_work);
508 INIT_DELAYED_WORK(&card->bm_work, bm_work);
469} 509}
470EXPORT_SYMBOL(fw_card_initialize); 510EXPORT_SYMBOL(fw_card_initialize);
471 511
@@ -491,7 +531,6 @@ int fw_card_add(struct fw_card *card,
491} 531}
492EXPORT_SYMBOL(fw_card_add); 532EXPORT_SYMBOL(fw_card_add);
493 533
494
495/* 534/*
496 * The next few functions implement a dummy driver that is used once a card 535 * The next few functions implement a dummy driver that is used once a card
497 * driver shuts down an fw_card. This allows the driver to cleanly unload, 536 * driver shuts down an fw_card. This allows the driver to cleanly unload,
@@ -507,6 +546,11 @@ static int dummy_enable(struct fw_card *card,
507 return -1; 546 return -1;
508} 547}
509 548
549static int dummy_read_phy_reg(struct fw_card *card, int address)
550{
551 return -ENODEV;
552}
553
510static int dummy_update_phy_reg(struct fw_card *card, int address, 554static int dummy_update_phy_reg(struct fw_card *card, int address,
511 int clear_bits, int set_bits) 555 int clear_bits, int set_bits)
512{ 556{
@@ -547,6 +591,7 @@ static int dummy_enable_phys_dma(struct fw_card *card,
547 591
548static const struct fw_card_driver dummy_driver_template = { 592static const struct fw_card_driver dummy_driver_template = {
549 .enable = dummy_enable, 593 .enable = dummy_enable,
594 .read_phy_reg = dummy_read_phy_reg,
550 .update_phy_reg = dummy_update_phy_reg, 595 .update_phy_reg = dummy_update_phy_reg,
551 .set_config_rom = dummy_set_config_rom, 596 .set_config_rom = dummy_set_config_rom,
552 .send_request = dummy_send_request, 597 .send_request = dummy_send_request,
@@ -568,7 +613,7 @@ void fw_core_remove_card(struct fw_card *card)
568 613
569 card->driver->update_phy_reg(card, 4, 614 card->driver->update_phy_reg(card, 4,
570 PHY_LINK_ACTIVE | PHY_CONTENDER, 0); 615 PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
571 fw_core_initiate_bus_reset(card, 1); 616 fw_schedule_bus_reset(card, false, true);
572 617
573 mutex_lock(&card_mutex); 618 mutex_lock(&card_mutex);
574 list_del_init(&card->link); 619 list_del_init(&card->link);
@@ -588,12 +633,3 @@ void fw_core_remove_card(struct fw_card *card)
588 WARN_ON(!list_empty(&card->transaction_list)); 633 WARN_ON(!list_empty(&card->transaction_list));
589} 634}
590EXPORT_SYMBOL(fw_core_remove_card); 635EXPORT_SYMBOL(fw_core_remove_card);
591
592int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
593{
594 int reg = short_reset ? 5 : 1;
595 int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
596
597 return card->driver->update_phy_reg(card, reg, 0, bit);
598}
599EXPORT_SYMBOL(fw_core_initiate_bus_reset);