summaryrefslogtreecommitdiff
path: root/drivers/firewire/core-transaction.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-10-13 15:39:46 +0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-05-11 00:53:45 +0400
commit6ea9e7bbfc389a12d52646449a201fe933ccd663 (patch)
treef84e89a394d45db4f30e1286966f69be62f203da /drivers/firewire/core-transaction.c
parent13882a82ee1646336c3996c93b4a560a55d2a419 (diff)
downloadlinux-6ea9e7bbfc389a12d52646449a201fe933ccd663.tar.xz
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.c12
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 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <asm/byteorder.h>
@@ -1213,13 +1214,21 @@ static int __init fw_core_init(void)
{
int ret;
+ fw_wq = alloc_workqueue(KBUILD_MODNAME,
+ WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
+ if (!fw_wq)
+ return -ENOMEM;
+
ret = bus_register(&fw_bus_type);
- if (ret < 0)
+ if (ret < 0) {
+ destroy_workqueue(fw_wq);
return ret;
+ }
fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
if (fw_cdev_major < 0) {
bus_unregister(&fw_bus_type);
+ destroy_workqueue(fw_wq);
return fw_cdev_major;
}
@@ -1235,6 +1244,7 @@ static void __exit fw_core_cleanup(void)
{
unregister_chrdev(fw_cdev_major, "firewire");
bus_unregister(&fw_bus_type);
+ destroy_workqueue(fw_wq);
idr_destroy(&fw_device_idr);
}