diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-01-09 14:49:37 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-01-09 17:22:32 -0500 |
commit | 6230582320b721e6cf2581d048cb688dca97f504 (patch) | |
tree | 2babcf29c086cf77b8df9fbe54303214b1be01ad | |
parent | 73d59314e6ed268d6f322ae1bdd723b23fa5a4ed (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.c | 13 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 23 |
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); |