Commit 62305823 authored by Stefan Richter's avatar Stefan Richter

firewire: core: fix sleep in atomic context due to driver core change

Due to commit 2831fe6f, "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: default avatarJay Fenlason <fenlason@redhat.com>
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent 73d59314
......@@ -209,6 +209,8 @@ fw_card_bm_work(struct work_struct *work)
unsigned long flags;
int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
bool do_reset = false;
bool root_device_is_running;
bool root_device_is_cmc;
__be32 lock_data[2];
spin_lock_irqsave(&card->lock, flags);
......@@ -224,8 +226,9 @@ fw_card_bm_work(struct work_struct *work)
generation = card->generation;
root_device = root_node->data;
if (root_device)
fw_device_get(root_device);
root_device_is_running = root_device &&
atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
root_device_is_cmc = root_device && root_device->cmc;
root_id = root_node->node_id;
grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
......@@ -308,14 +311,14 @@ fw_card_bm_work(struct work_struct *work)
* config rom. In either case, pick another root.
*/
new_root_id = local_node->node_id;
} else if (atomic_read(&root_device->state) != FW_DEVICE_RUNNING) {
} else if (!root_device_is_running) {
/*
* If we haven't probed this device yet, bail out now
* and let's try again once that's done.
*/
spin_unlock_irqrestore(&card->lock, flags);
goto out;
} else if (root_device->cmc) {
} else if (root_device_is_cmc) {
/*
* FIXME: I suppose we should set the cmstr bit in the
* STATE_CLEAR register of this node, as described in
......@@ -362,8 +365,6 @@ fw_card_bm_work(struct work_struct *work)
fw_core_initiate_bus_reset(card, 1);
}
out:
if (root_device)
fw_device_put(root_device);
fw_node_put(root_node);
fw_node_put(local_node);
out_put_card:
......
......@@ -159,7 +159,8 @@ static void fw_device_release(struct device *dev)
/*
* Take the card lock so we don't set this to NULL while a
* FW_NODE_UPDATED callback is being handled.
* FW_NODE_UPDATED callback is being handled or while the
* bus manager work looks at this node.
*/
spin_lock_irqsave(&card->lock, flags);
device->node->data = NULL;
......@@ -695,12 +696,13 @@ static void fw_device_init(struct work_struct *work)
return;
}
err = -ENOMEM;
device_initialize(&device->device);
fw_device_get(device);
down_write(&fw_device_rwsem);
if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
err = idr_get_new(&fw_device_idr, device, &minor);
err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
idr_get_new(&fw_device_idr, device, &minor) :
-ENOMEM;
up_write(&fw_device_rwsem);
if (err < 0)
......@@ -911,13 +913,14 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
/*
* Do minimal intialization of the device here, the
* rest will happen in fw_device_init(). We need the
* card and node so we can read the config rom and we
* need to do device_initialize() now so
* device_for_each_child() in FW_NODE_UPDATED is
* doesn't freak out.
* rest will happen in fw_device_init().
*
* Attention: A lot of things, even fw_device_get(),
* cannot be done before fw_device_init() finished!
* You can basically just check device->state and
* schedule work until then, but only while holding
* card->lock.
*/
device_initialize(&device->device);
atomic_set(&device->state, FW_DEVICE_INITIALIZING);
device->card = fw_card_get(card);
device->node = fw_node_get(node);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment