From 9a449e1df5edc16fda2c47afe68e8e5cf54026ee Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Thu, 25 Feb 2010 17:33:53 +0000 Subject: wctdm24xxp: Provide option to initialize boards in parallel on kernels > 2.6.30 The 2.6.30 kernel provides support for asynchronous initialization. If running on a kernel that supports this feature, let's add an option to use it in order to speed up driver load times. Keep it off by default. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8094 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/voicebus/voicebus.c | 17 +++++++++- drivers/dahdi/wctdm24xxp/base.c | 66 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/drivers/dahdi/voicebus/voicebus.c b/drivers/dahdi/voicebus/voicebus.c index 064e664..368060b 100644 --- a/drivers/dahdi/voicebus/voicebus.c +++ b/drivers/dahdi/voicebus/voicebus.c @@ -1656,6 +1656,7 @@ int vpmadtreg_loadfirmware(struct voicebus *vb) struct vpmadt_loader *loader; int ret = 0; int loader_present = 0; + unsigned long stop; might_sleep(); /* First check to see if a loader is already loaded into memory. */ @@ -1664,9 +1665,23 @@ int vpmadtreg_loadfirmware(struct voicebus *vb) spin_unlock(&loader_list_lock); if (!loader_present) { - ret = request_module("dahdi_vpmadt032_loader"); + /* If we use the blocking 'request_module' here and we are + * loading the client boards with async_schedule we will hang + * here. The module loader will wait for our asynchronous tasks + * to finish, but we can't because we're waiting for the load + * the finish. */ + ret = request_module_nowait("dahdi_vpmadt032_loader"); if (ret) return ret; + stop = jiffies + HZ; + while (time_after(stop, jiffies)) { + spin_lock(&loader_list_lock); + loader_present = !(list_empty(&binary_loader_list)); + spin_unlock(&loader_list_lock); + if (loader_present) + break; + msleep(10); + } } spin_lock(&loader_list_lock); diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c index cbe826e..8990d70 100644 --- a/drivers/dahdi/wctdm24xxp/base.c +++ b/drivers/dahdi/wctdm24xxp/base.c @@ -52,6 +52,16 @@ Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db #include #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) +/* Define this if you would like to load the modules in parallel. While this + * can speed up loads when multiple cards handled by this driver are installed, + * it also makes it impossible to abort module loads with ctrl-c */ +#undef USE_ASYNC_INIT +#include +#else +#undef USE_ASYNC_INIT +#endif + #include #include @@ -3743,7 +3753,18 @@ static const struct voicebus_operations voicebus_operations = { .handle_transmit = handle_transmit, }; -static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +#ifdef USE_ASYNC_INIT +struct async_data { + struct pci_dev *pdev; + const struct pci_device_id *ent; +}; +static int __devinit +__wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent, + async_cookie_t cookie) +#else +static int __devinit +__wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +#endif { struct wctdm *wc; int i; @@ -3836,6 +3857,10 @@ static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_devic /* Final initialization */ wctdm_post_initialize(wc); +#ifdef USE_ASYNC_INIT + async_synchronize_cookie(cookie); +#endif + /* We should be ready for DAHDI to come in now. */ if (dahdi_register(&wc->span, 0)) { dev_info(&wc->vb.pdev->dev, @@ -3854,6 +3879,41 @@ static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_devic return 0; } +#ifdef USE_ASYNC_INIT +static __devinit void +wctdm_init_one_async(void *data, async_cookie_t cookie) +{ + struct async_data *dat = data; + __wctdm_init_one(dat->pdev, dat->ent, cookie); + kfree(dat); +} + +static int __devinit +wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct async_data *dat; + + dat = kmalloc(sizeof(*dat), GFP_KERNEL); + /* If we can't allocate the memory for the async_data, odds are we won't + * be able to initialize the device either, but let's try synchronously + * anyway... */ + if (!dat) + return __wctdm_init_one(pdev, ent, 0); + + dat->pdev = pdev; + dat->ent = ent; + async_schedule(wctdm_init_one_async, dat); + return 0; +} +#else +static int __devinit +wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + return __wctdm_init_one(pdev, ent); +} +#endif + + static void wctdm_release(struct wctdm *wc) { int i; @@ -3965,6 +4025,10 @@ static int __init wctdm_init(void) res = dahdi_pci_module(&wctdm_driver); if (res) return -ENODEV; + +#ifdef USE_ASYNC_INIT + async_synchronize_full(); +#endif return 0; } -- cgit v1.2.3