diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-10-13 07:39:46 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-05-10 16:53:45 -0400 |
commit | 6ea9e7bbfc389a12d52646449a201fe933ccd663 (patch) | |
tree | f84e89a394d45db4f30e1286966f69be62f203da /drivers/firewire/core-transaction.c | |
parent | 13882a82ee1646336c3996c93b4a560a55d2a419 (diff) |
firewire: core: use non-reentrant workqueue with rescuer
firewire-core manages the following types of work items:
fw_card.br_work:
- resets the bus on a card and possibly sends a PHY packet before that
- does not sleep for long or not at all
- is scheduled via fw_schedule_bus_reset() by
- firewire-ohci's pci_probe method
- firewire-ohci's set_config_rom method, called by kernelspace
protocol drivers and userspace drivers which add/remove
Configuration ROM descriptors
- userspace drivers which use the bus reset ioctl
- itself if the last reset happened less than 2 seconds ago
fw_card.bm_work:
- performs bus management duties
- usually does not (but may in corner cases) sleep for long
- is scheduled via fw_schedule_bm_work() by
- firewire-ohci's self-ID-complete IRQ handler tasklet
- firewire-core's fw_device.work instances whenever the root node
device was (successfully or unsuccessfully) discovered,
refreshed, or rediscovered
- itself in case of resource allocation failures or in order to
obey the 125ms bus manager arbitration interval
fw_device.work:
- performs node probe, update, shutdown, revival, removal; including
kernel driver probe, update, shutdown and bus reset notification to
userspace drivers
- usually sleeps moderately long, in corner cases very long
- is scheduled by
- firewire-ohci's self-ID-complete IRQ handler tasklet via the
core's fw_node_event
- firewire-ohci's pci_remove method via core's fw_destroy_nodes/
fw_node_event
- itself during retries, e.g. while a node is powering up
iso_resource.work:
- accesses registers at the Isochronous Resource Manager node
- usually does not (but may in corner cases) sleep for long
- is scheduled via schedule_iso_resource() by
- the owning userspace driver at addition and removal of the
resource
- firewire-core's fw_device.work instances after bus reset
- itself in case of resource allocation if necessary to obey the
1000ms reallocation period after bus reset
fw_card.br_work instances should not, and instances of the others must
not, be executed in parallel by multiple CPUs -- but were not protected
against that. Hence allocate a non-reentrant workqueue for them.
fw_device.work may be used in the memory reclaim path in case of SBP-2
device updates. Hence we need a workqueue with rescuer and cannot use
system_nrt_wq.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Reviewed-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r-- | drivers/firewire/core-transaction.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 77275fdf6c1f..d4c28a217b2c 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/string.h> | 36 | #include <linux/string.h> |
37 | #include <linux/timer.h> | 37 | #include <linux/timer.h> |
38 | #include <linux/types.h> | 38 | #include <linux/types.h> |
39 | #include <linux/workqueue.h> | ||
39 | 40 | ||
40 | #include <asm/byteorder.h> | 41 | #include <asm/byteorder.h> |
41 | 42 | ||
@@ -1213,13 +1214,21 @@ static int __init fw_core_init(void) | |||
1213 | { | 1214 | { |
1214 | int ret; | 1215 | int ret; |
1215 | 1216 | ||
1217 | fw_wq = alloc_workqueue(KBUILD_MODNAME, | ||
1218 | WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); | ||
1219 | if (!fw_wq) | ||
1220 | return -ENOMEM; | ||
1221 | |||
1216 | ret = bus_register(&fw_bus_type); | 1222 | ret = bus_register(&fw_bus_type); |
1217 | if (ret < 0) | 1223 | if (ret < 0) { |
1224 | destroy_workqueue(fw_wq); | ||
1218 | return ret; | 1225 | return ret; |
1226 | } | ||
1219 | 1227 | ||
1220 | fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); | 1228 | fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); |
1221 | if (fw_cdev_major < 0) { | 1229 | if (fw_cdev_major < 0) { |
1222 | bus_unregister(&fw_bus_type); | 1230 | bus_unregister(&fw_bus_type); |
1231 | destroy_workqueue(fw_wq); | ||
1223 | return fw_cdev_major; | 1232 | return fw_cdev_major; |
1224 | } | 1233 | } |
1225 | 1234 | ||
@@ -1235,6 +1244,7 @@ static void __exit fw_core_cleanup(void) | |||
1235 | { | 1244 | { |
1236 | unregister_chrdev(fw_cdev_major, "firewire"); | 1245 | unregister_chrdev(fw_cdev_major, "firewire"); |
1237 | bus_unregister(&fw_bus_type); | 1246 | bus_unregister(&fw_bus_type); |
1247 | destroy_workqueue(fw_wq); | ||
1238 | idr_destroy(&fw_device_idr); | 1248 | idr_destroy(&fw_device_idr); |
1239 | } | 1249 | } |
1240 | 1250 | ||