aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2011-05-01 14:50:31 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-05-10 16:53:46 -0400
commit105e53f863c04e1d9e5bb34bf753c9fdbce6a60c (patch)
tree63500c7cb130348b70279cdbfdfb278de6fc83ad
parent81bf52d8622f05cfe89893fd5c1101efd85f855b (diff)
firewire: sbp2: parallelize login, reconnect, logout
The struct sbp2_logical_unit.work items can all be executed in parallel but are not reentrant. Furthermore, reconnect or re-login work must be executed in a WQ_MEM_RECLAIM workqueue. Hence replace the old single-threaded firewire-sbp2 workqueue by a concurrency-managed but non-reentrant workqueue with rescuer. firewire-core already maintains one, hence use this one. In earlier versions of this change, I observed occasional failures of parallel INQUIRY to an Initio INIC-2430 FireWire 800 to dual IDE bridge. More testing indicates that parallel INQUIRY is not actually a problem, but too quick successions of logout and login + INQUIRY, e.g. a quick sequence of cable plugout and plugin, can result in failed INQUIRY. This does not seem to be something that should or could be addressed by serialization. Another dual-LU device to which I currently have access to, an OXUF924DSB FireWire 800 to dual SATA bridge with firmware from MacPower, has been successfully tested with this too. This change is beneficial to environments with two or more FireWire storage devices, especially if they are located on the same bus. Management tasks that should be performed as soon and as quickly as possible, especially reconnect, are no longer held up by tasks on other devices that may take a long time, especially login with INQUIRY and sd or sr driver probe. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/core-card.c4
-rw-r--r--drivers/firewire/core-cdev.c2
-rw-r--r--drivers/firewire/core-device.c5
-rw-r--r--drivers/firewire/core-transaction.c12
-rw-r--r--drivers/firewire/core.h2
-rw-r--r--drivers/firewire/sbp2.c9
-rw-r--r--include/linux/firewire.h2
7 files changed, 15 insertions, 21 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index bb8c4d22b03e..29d2423fae6d 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -228,7 +228,7 @@ void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset)
228 228
229 /* Use an arbitrary short delay to combine multiple reset requests. */ 229 /* Use an arbitrary short delay to combine multiple reset requests. */
230 fw_card_get(card); 230 fw_card_get(card);
231 if (!queue_delayed_work(fw_wq, &card->br_work, 231 if (!queue_delayed_work(fw_workqueue, &card->br_work,
232 delayed ? DIV_ROUND_UP(HZ, 100) : 0)) 232 delayed ? DIV_ROUND_UP(HZ, 100) : 0))
233 fw_card_put(card); 233 fw_card_put(card);
234} 234}
@@ -241,7 +241,7 @@ static void br_work(struct work_struct *work)
241 /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ 241 /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
242 if (card->reset_jiffies != 0 && 242 if (card->reset_jiffies != 0 &&
243 time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { 243 time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) {
244 if (!queue_delayed_work(fw_wq, &card->br_work, 2 * HZ)) 244 if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ))
245 fw_card_put(card); 245 fw_card_put(card);
246 return; 246 return;
247 } 247 }
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index aa1131d26e30..b1c11775839c 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -149,7 +149,7 @@ static void release_iso_resource(struct client *, struct client_resource *);
149static void schedule_iso_resource(struct iso_resource *r, unsigned long delay) 149static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
150{ 150{
151 client_get(r->client); 151 client_get(r->client);
152 if (!queue_delayed_work(fw_wq, &r->work, delay)) 152 if (!queue_delayed_work(fw_workqueue, &r->work, delay))
153 client_put(r->client); 153 client_put(r->client);
154} 154}
155 155
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index ef900d923f15..95a471401892 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -725,12 +725,13 @@ struct fw_device *fw_device_get_by_devt(dev_t devt)
725 return device; 725 return device;
726} 726}
727 727
728struct workqueue_struct *fw_wq; 728struct workqueue_struct *fw_workqueue;
729EXPORT_SYMBOL(fw_workqueue);
729 730
730static void fw_schedule_device_work(struct fw_device *device, 731static void fw_schedule_device_work(struct fw_device *device,
731 unsigned long delay) 732 unsigned long delay)
732{ 733{
733 queue_delayed_work(fw_wq, &device->work, delay); 734 queue_delayed_work(fw_workqueue, &device->work, delay);
734} 735}
735 736
736/* 737/*
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index d4c28a217b2c..334b82a3542c 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -1214,21 +1214,21 @@ static int __init fw_core_init(void)
1214{ 1214{
1215 int ret; 1215 int ret;
1216 1216
1217 fw_wq = alloc_workqueue(KBUILD_MODNAME, 1217 fw_workqueue = alloc_workqueue("firewire",
1218 WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); 1218 WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
1219 if (!fw_wq) 1219 if (!fw_workqueue)
1220 return -ENOMEM; 1220 return -ENOMEM;
1221 1221
1222 ret = bus_register(&fw_bus_type); 1222 ret = bus_register(&fw_bus_type);
1223 if (ret < 0) { 1223 if (ret < 0) {
1224 destroy_workqueue(fw_wq); 1224 destroy_workqueue(fw_workqueue);
1225 return ret; 1225 return ret;
1226 } 1226 }
1227 1227
1228 fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); 1228 fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
1229 if (fw_cdev_major < 0) { 1229 if (fw_cdev_major < 0) {
1230 bus_unregister(&fw_bus_type); 1230 bus_unregister(&fw_bus_type);
1231 destroy_workqueue(fw_wq); 1231 destroy_workqueue(fw_workqueue);
1232 return fw_cdev_major; 1232 return fw_cdev_major;
1233 } 1233 }
1234 1234
@@ -1244,7 +1244,7 @@ static void __exit fw_core_cleanup(void)
1244{ 1244{
1245 unregister_chrdev(fw_cdev_major, "firewire"); 1245 unregister_chrdev(fw_cdev_major, "firewire");
1246 bus_unregister(&fw_bus_type); 1246 bus_unregister(&fw_bus_type);
1247 destroy_workqueue(fw_wq); 1247 destroy_workqueue(fw_workqueue);
1248 idr_destroy(&fw_device_idr); 1248 idr_destroy(&fw_device_idr);
1249} 1249}
1250 1250
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 00ea7730c6a7..0fe4e4e6eda7 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -140,8 +140,6 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p);
140extern struct rw_semaphore fw_device_rwsem; 140extern struct rw_semaphore fw_device_rwsem;
141extern struct idr fw_device_idr; 141extern struct idr fw_device_idr;
142extern int fw_cdev_major; 142extern int fw_cdev_major;
143struct workqueue_struct;
144extern struct workqueue_struct *fw_wq;
145 143
146struct fw_device *fw_device_get_by_devt(dev_t devt); 144struct fw_device *fw_device_get_by_devt(dev_t devt);
147int fw_device_set_broadcast_channel(struct device *dev, void *gen); 145int fw_device_set_broadcast_channel(struct device *dev, void *gen);
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 2aafc614ae14..41841a3e3f99 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -826,8 +826,6 @@ static void sbp2_target_put(struct sbp2_target *tgt)
826 kref_put(&tgt->kref, sbp2_release_target); 826 kref_put(&tgt->kref, sbp2_release_target);
827} 827}
828 828
829static struct workqueue_struct *sbp2_wq;
830
831/* 829/*
832 * Always get the target's kref when scheduling work on one its units. 830 * Always get the target's kref when scheduling work on one its units.
833 * Each workqueue job is responsible to call sbp2_target_put() upon return. 831 * Each workqueue job is responsible to call sbp2_target_put() upon return.
@@ -835,7 +833,7 @@ static struct workqueue_struct *sbp2_wq;
835static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) 833static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
836{ 834{
837 sbp2_target_get(lu->tgt); 835 sbp2_target_get(lu->tgt);
838 if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) 836 if (!queue_delayed_work(fw_workqueue, &lu->work, delay))
839 sbp2_target_put(lu->tgt); 837 sbp2_target_put(lu->tgt);
840} 838}
841 839
@@ -1645,17 +1643,12 @@ MODULE_ALIAS("sbp2");
1645 1643
1646static int __init sbp2_init(void) 1644static int __init sbp2_init(void)
1647{ 1645{
1648 sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME);
1649 if (!sbp2_wq)
1650 return -ENOMEM;
1651
1652 return driver_register(&sbp2_driver.driver); 1646 return driver_register(&sbp2_driver.driver);
1653} 1647}
1654 1648
1655static void __exit sbp2_cleanup(void) 1649static void __exit sbp2_cleanup(void)
1656{ 1650{
1657 driver_unregister(&sbp2_driver.driver); 1651 driver_unregister(&sbp2_driver.driver);
1658 destroy_workqueue(sbp2_wq);
1659} 1652}
1660 1653
1661module_init(sbp2_init); 1654module_init(sbp2_init);
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index c0fb405bb435..5e6f42789afe 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -449,4 +449,6 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
449 u64 channels_mask, int *channel, int *bandwidth, 449 u64 channels_mask, int *channel, int *bandwidth,
450 bool allocate); 450 bool allocate);
451 451
452extern struct workqueue_struct *fw_workqueue;
453
452#endif /* _LINUX_FIREWIRE_H */ 454#endif /* _LINUX_FIREWIRE_H */