aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2009-01-09 14:49:37 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-01-09 17:22:32 -0500
commit6230582320b721e6cf2581d048cb688dca97f504 (patch)
tree2babcf29c086cf77b8df9fbe54303214b1be01ad
parent73d59314e6ed268d6f322ae1bdd723b23fa5a4ed (diff)
firewire: core: fix sleep in atomic context due to driver core change
Due to commit 2831fe6f9cc4e16c103504ee09a47a084297c0f3, "driver core: create a private portion of struct device", device_initialize() can no longer be called from atomic contexts. We now defer it until after config ROM probing. This requires changes to the bus manager code because this may use a device before it was probed. Reported-by: Jay Fenlason <fenlason@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/fw-card.c13
-rw-r--r--drivers/firewire/fw-device.c23
2 files changed, 20 insertions, 16 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index 799f94424c8a..6bd91a15d5e6 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -209,6 +209,8 @@ fw_card_bm_work(struct work_struct *work)
209 unsigned long flags; 209 unsigned long flags;
210 int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode; 210 int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
211 bool do_reset = false; 211 bool do_reset = false;
212 bool root_device_is_running;
213 bool root_device_is_cmc;
212 __be32 lock_data[2]; 214 __be32 lock_data[2];
213 215
214 spin_lock_irqsave(&card->lock, flags); 216 spin_lock_irqsave(&card->lock, flags);
@@ -224,8 +226,9 @@ fw_card_bm_work(struct work_struct *work)
224 226
225 generation = card->generation; 227 generation = card->generation;
226 root_device = root_node->data; 228 root_device = root_node->data;
227 if (root_device) 229 root_device_is_running = root_device &&
228 fw_device_get(root_device); 230 atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
231 root_device_is_cmc = root_device && root_device->cmc;
229 root_id = root_node->node_id; 232 root_id = root_node->node_id;
230 grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); 233 grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
231 234
@@ -308,14 +311,14 @@ fw_card_bm_work(struct work_struct *work)
308 * config rom. In either case, pick another root. 311 * config rom. In either case, pick another root.
309 */ 312 */
310 new_root_id = local_node->node_id; 313 new_root_id = local_node->node_id;
311 } else if (atomic_read(&root_device->state) != FW_DEVICE_RUNNING) { 314 } else if (!root_device_is_running) {
312 /* 315 /*
313 * If we haven't probed this device yet, bail out now 316 * If we haven't probed this device yet, bail out now
314 * and let's try again once that's done. 317 * and let's try again once that's done.
315 */ 318 */
316 spin_unlock_irqrestore(&card->lock, flags); 319 spin_unlock_irqrestore(&card->lock, flags);
317 goto out; 320 goto out;
318 } else if (root_device->cmc) { 321 } else if (root_device_is_cmc) {
319 /* 322 /*
320 * FIXME: I suppose we should set the cmstr bit in the 323 * FIXME: I suppose we should set the cmstr bit in the
321 * STATE_CLEAR register of this node, as described in 324 * STATE_CLEAR register of this node, as described in
@@ -362,8 +365,6 @@ fw_card_bm_work(struct work_struct *work)
362 fw_core_initiate_bus_reset(card, 1); 365 fw_core_initiate_bus_reset(card, 1);
363 } 366 }
364 out: 367 out:
365 if (root_device)
366 fw_device_put(root_device);
367 fw_node_put(root_node); 368 fw_node_put(root_node);
368 fw_node_put(local_node); 369 fw_node_put(local_node);
369 out_put_card: 370 out_put_card:
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index c173be383725..2af5a8d1e012 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -159,7 +159,8 @@ static void fw_device_release(struct device *dev)
159 159
160 /* 160 /*
161 * Take the card lock so we don't set this to NULL while a 161 * Take the card lock so we don't set this to NULL while a
162 * FW_NODE_UPDATED callback is being handled. 162 * FW_NODE_UPDATED callback is being handled or while the
163 * bus manager work looks at this node.
163 */ 164 */
164 spin_lock_irqsave(&card->lock, flags); 165 spin_lock_irqsave(&card->lock, flags);
165 device->node->data = NULL; 166 device->node->data = NULL;
@@ -695,12 +696,13 @@ static void fw_device_init(struct work_struct *work)
695 return; 696 return;
696 } 697 }
697 698
698 err = -ENOMEM; 699 device_initialize(&device->device);
699 700
700 fw_device_get(device); 701 fw_device_get(device);
701 down_write(&fw_device_rwsem); 702 down_write(&fw_device_rwsem);
702 if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) 703 err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
703 err = idr_get_new(&fw_device_idr, device, &minor); 704 idr_get_new(&fw_device_idr, device, &minor) :
705 -ENOMEM;
704 up_write(&fw_device_rwsem); 706 up_write(&fw_device_rwsem);
705 707
706 if (err < 0) 708 if (err < 0)
@@ -911,13 +913,14 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
911 913
912 /* 914 /*
913 * Do minimal intialization of the device here, the 915 * Do minimal intialization of the device here, the
914 * rest will happen in fw_device_init(). We need the 916 * rest will happen in fw_device_init().
915 * card and node so we can read the config rom and we 917 *
916 * need to do device_initialize() now so 918 * Attention: A lot of things, even fw_device_get(),
917 * device_for_each_child() in FW_NODE_UPDATED is 919 * cannot be done before fw_device_init() finished!
918 * doesn't freak out. 920 * You can basically just check device->state and
921 * schedule work until then, but only while holding
922 * card->lock.
919 */ 923 */
920 device_initialize(&device->device);
921 atomic_set(&device->state, FW_DEVICE_INITIALIZING); 924 atomic_set(&device->state, FW_DEVICE_INITIALIZING);
922 device->card = fw_card_get(card); 925 device->card = fw_card_get(card);
923 device->node = fw_node_get(node); 926 device->node = fw_node_get(node);