From 9521077178a3568713477ab8e0b80646cadffa0e Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Wed, 24 Mar 2010 15:39:05 +0000 Subject: wcte12xp: t1xxp_maint is also called with interrupts disabled from dahdi_ioctl So just push all the maintenance mode processing off to the workqueue. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8415 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/wcte12xp/base.c | 117 +++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 42 deletions(-) diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c index b7f2c9d..f56f3b5 100644 --- a/drivers/dahdi/wcte12xp/base.c +++ b/drivers/dahdi/wcte12xp/base.c @@ -1114,54 +1114,28 @@ static inline void t1_check_sigbits(struct t1 *wc) } } -struct maint_loopstop_work { +struct maint_work_struct { struct work_struct work; struct t1 *wc; + int cmd; struct dahdi_span *span; }; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -static void t1xxp_maint_loopstop_work(void *data) +static void t1xxp_maint_work(void *data) { - struct maint_loopstop_work *w = data; + struct maint_work_struct *w = data; #else static void t1xxp_maint_loopstop_work(struct work_struct *work) { - struct maint_loopstop_work *w = container_of(work, struct maint_loopstop_work, work); + struct maint_work_struct *w = container_of(work, + struct maint_work_struct, work); #endif - t1xxp_clear_maint(w->span); - t1_setreg(w->wc, 0x21, 0x40); - kfree(w); -} - -static void t1xxp_maint_loopstop(struct t1 *wc, struct dahdi_span *span) -{ - struct maint_loopstop_work *work; - - work = kmalloc(sizeof(*work), GFP_ATOMIC); - if (!work) { - t1_info(wc, "Failed to allocate memory for DAHDI_MAINT_LOOPSTOP\n"); - return; - } - - work->span = span; - work->wc = wc; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) - INIT_WORK(&work->work, t1xxp_maint_loopstop_work, work); -#else - INIT_WORK(&work->work, t1xxp_maint_loopstop_work); -#endif - schedule_work(&work->work); -} -static int t1xxp_maint(struct dahdi_span *span, int cmd) -{ - struct t1 *wc = span->pvt; + struct t1 *wc = w->wc; + struct dahdi_span *span = w->span; int reg = 0; - - if (DAHDI_MAINT_LOOPSTOP != cmd) - might_sleep(); + int cmd = w->cmd; if (wc->spantype == TYPE_E1) { switch (cmd) { @@ -1173,7 +1147,7 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd) t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM0); if (reg < 0) - return -EIO; + goto cleanup; t1_setreg(wc, LIM0, reg | LIM0_LL); break; case DAHDI_MAINT_REMOTELOOP: @@ -1181,10 +1155,10 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd) case DAHDI_MAINT_LOOPDOWN: case DAHDI_MAINT_LOOPSTOP: t1_info(wc, "Only local loop supported in E1 mode\n"); - return -ENOSYS; + goto cleanup; default: t1_info(wc, "Unknown E1 maint command: %d\n", cmd); - return -ENOSYS; + goto cleanup; } } else { switch (cmd) { @@ -1195,21 +1169,21 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd) t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM0); if (reg < 0) - return -EIO; + goto cleanup; t1_setreg(wc, LIM0, reg | LIM0_LL); break; case DAHDI_MAINT_NETWORKLINELOOP: t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM1); if (reg < 0) - return -EIO; + goto cleanup; t1_setreg(wc, LIM1, reg | LIM1_RL); break; case DAHDI_MAINT_NETWORKPAYLOADLOOP: t1xxp_clear_maint(span); reg = t1_getreg(wc, LIM1); if (reg < 0) - return -EIO; + goto cleanup; t1_setreg(wc, LIM1, reg | (LIM1_RL | LIM1_JATT)); break; case DAHDI_MAINT_LOOPUP: @@ -1221,7 +1195,49 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd) t1_setreg(wc, 0x21, 0x60); break; case DAHDI_MAINT_LOOPSTOP: - t1xxp_maint_loopstop(wc, span); + t1xxp_clear_maint(w->span); + t1_setreg(w->wc, 0x21, 0x40); + break; + default: + t1_info(wc, "Unknown T1 maint command: %d\n", cmd); + return; + } + } + +cleanup: + kfree(w); + return; +} + +static int t1xxp_maint(struct dahdi_span *span, int cmd) +{ + struct maint_work_struct *work; + struct t1 *wc = span->pvt; + + if (wc->spantype == TYPE_E1) { + switch (cmd) { + case DAHDI_MAINT_NONE: + case DAHDI_MAINT_LOCALLOOP: + break; + case DAHDI_MAINT_REMOTELOOP: + case DAHDI_MAINT_LOOPUP: + case DAHDI_MAINT_LOOPDOWN: + case DAHDI_MAINT_LOOPSTOP: + t1_info(wc, "Only local loop supported in E1 mode\n"); + return -ENOSYS; + default: + t1_info(wc, "Unknown E1 maint command: %d\n", cmd); + return -ENOSYS; + } + } else { + switch (cmd) { + case DAHDI_MAINT_NONE: + case DAHDI_MAINT_LOCALLOOP: + case DAHDI_MAINT_NETWORKLINELOOP: + case DAHDI_MAINT_NETWORKPAYLOADLOOP: + case DAHDI_MAINT_LOOPUP: + case DAHDI_MAINT_LOOPDOWN: + case DAHDI_MAINT_LOOPSTOP: break; default: t1_info(wc, "Unknown T1 maint command: %d\n", cmd); @@ -1229,6 +1245,23 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd) } } + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + t1_info(wc, "Failed to allocate memory for " + "DAHDI_MAINT_LOOPSTOP\n"); + return -ENOMEM; + } + + work->span = span; + work->wc = wc; + work->cmd = cmd; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_WORK(&work->work, t1xxp_maint_work, work); +#else + INIT_WORK(&work->work, t1xxp_maint_work); +#endif + schedule_work(&work->work); return 0; } -- cgit v1.2.3