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>
This commit is contained in:
parent
73d59314e6
commit
6230582320
@ -209,6 +209,8 @@ fw_card_bm_work(struct work_struct *work)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
|
int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
|
||||||
bool do_reset = false;
|
bool do_reset = false;
|
||||||
|
bool root_device_is_running;
|
||||||
|
bool root_device_is_cmc;
|
||||||
__be32 lock_data[2];
|
__be32 lock_data[2];
|
||||||
|
|
||||||
spin_lock_irqsave(&card->lock, flags);
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
@ -224,8 +226,9 @@ fw_card_bm_work(struct work_struct *work)
|
|||||||
|
|
||||||
generation = card->generation;
|
generation = card->generation;
|
||||||
root_device = root_node->data;
|
root_device = root_node->data;
|
||||||
if (root_device)
|
root_device_is_running = root_device &&
|
||||||
fw_device_get(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;
|
root_id = root_node->node_id;
|
||||||
grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
|
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.
|
* config rom. In either case, pick another root.
|
||||||
*/
|
*/
|
||||||
new_root_id = local_node->node_id;
|
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
|
* If we haven't probed this device yet, bail out now
|
||||||
* and let's try again once that's done.
|
* and let's try again once that's done.
|
||||||
*/
|
*/
|
||||||
spin_unlock_irqrestore(&card->lock, flags);
|
spin_unlock_irqrestore(&card->lock, flags);
|
||||||
goto out;
|
goto out;
|
||||||
} else if (root_device->cmc) {
|
} else if (root_device_is_cmc) {
|
||||||
/*
|
/*
|
||||||
* FIXME: I suppose we should set the cmstr bit in the
|
* FIXME: I suppose we should set the cmstr bit in the
|
||||||
* STATE_CLEAR register of this node, as described in
|
* 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);
|
fw_core_initiate_bus_reset(card, 1);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
if (root_device)
|
|
||||||
fw_device_put(root_device);
|
|
||||||
fw_node_put(root_node);
|
fw_node_put(root_node);
|
||||||
fw_node_put(local_node);
|
fw_node_put(local_node);
|
||||||
out_put_card:
|
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
|
* 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);
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
device->node->data = NULL;
|
device->node->data = NULL;
|
||||||
@ -695,12 +696,13 @@ static void fw_device_init(struct work_struct *work)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -ENOMEM;
|
device_initialize(&device->device);
|
||||||
|
|
||||||
fw_device_get(device);
|
fw_device_get(device);
|
||||||
down_write(&fw_device_rwsem);
|
down_write(&fw_device_rwsem);
|
||||||
if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
|
err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
|
||||||
err = idr_get_new(&fw_device_idr, device, &minor);
|
idr_get_new(&fw_device_idr, device, &minor) :
|
||||||
|
-ENOMEM;
|
||||||
up_write(&fw_device_rwsem);
|
up_write(&fw_device_rwsem);
|
||||||
|
|
||||||
if (err < 0)
|
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
|
* Do minimal intialization of the device here, the
|
||||||
* rest will happen in fw_device_init(). We need the
|
* rest will happen in fw_device_init().
|
||||||
* card and node so we can read the config rom and we
|
*
|
||||||
* need to do device_initialize() now so
|
* Attention: A lot of things, even fw_device_get(),
|
||||||
* device_for_each_child() in FW_NODE_UPDATED is
|
* cannot be done before fw_device_init() finished!
|
||||||
* doesn't freak out.
|
* 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);
|
atomic_set(&device->state, FW_DEVICE_INITIALIZING);
|
||||||
device->card = fw_card_get(card);
|
device->card = fw_card_get(card);
|
||||||
device->node = fw_node_get(node);
|
device->node = fw_node_get(node);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user