[dahdi-commits] dahdi/linux.git branch "master" updated.

SVN commits to the DAHDI project dahdi-commits at lists.digium.com
Fri Jun 20 13:01:47 CDT 2014


branch "master" has been updated
       via  71867c3de734f6d556ea66b67c25216c9a477a84 (commit)
       via  61aeaf13ae2054c757f106aac92c7b0d445a3626 (commit)
       via  f35e8aafb0af4f3cb791fe83a306a815590fe5ae (commit)
       via  b3a6b9185852958a35a1754ece550f59356e23f9 (commit)
       via  2e33bdc7b55a30c0ad9a05705c23297a897e0e2c (commit)
       via  3755ec9bf293a559ebc1f036a7694d3b3db232db (commit)
       via  47f0fde0f16a3d54da4610e400605bd6e7be5bf3 (commit)
       via  180a17a39c0152b5e72c72d4fa710057df7031f1 (commit)
       via  d1afa1b101aef9dfb9640bcad1ac21ef8c372cb3 (commit)
       via  b4941f35ad57df4ccce70478b782727a30d4ec20 (commit)
       via  a3578ca156a68970ea419e8da4d2f7a96c820c73 (commit)
       via  761e02da5267f1d6a516469b240da2b37f871c88 (commit)
      from  cb50ae150040465faa5e6e57e32ba8d8b6de3947 (commit)

Summary of changes:
 drivers/dahdi/dahdi-base.c                         |  120 +++++++++++---------
 .../oct612x/include/oct6100api/oct6100_apiud.h     |    2 +-
 drivers/dahdi/oct612x/oct612x-user.c               |   19 +++-
 drivers/dahdi/tor2.c                               |   12 --
 drivers/dahdi/wcb4xxp/base.c                       |   11 +-
 drivers/dahdi/wcfxo.c                              |   12 +-
 drivers/dahdi/wct4xxp/base.c                       |   49 ++++----
 drivers/dahdi/wct4xxp/vpm450m.c                    |   19 ++--
 drivers/dahdi/wct4xxp/wct4xxp.h                    |    7 --
 drivers/dahdi/wctdm.c                              |   12 +-
 drivers/dahdi/wcte11xp.c                           |   12 +-
 drivers/dahdi/wcte13xp-base.c                      |   69 +++++++++--
 drivers/dahdi/wcte43x-base.c                       |   94 +++++++++++----
 drivers/dahdi/xpp/xpp_dahdi.c                      |   14 ++-
 include/dahdi/kernel.h                             |    1 +
 15 files changed, 304 insertions(+), 149 deletions(-)


- Log -----------------------------------------------------------------
commit 71867c3de734f6d556ea66b67c25216c9a477a84
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue Jun 17 10:34:00 2014 -0500

    wcte43x: Do not get stuck in "Not Open" state when DAHDI_CONFIG_NOTOPEN is set.
    
    This is the same change for the wcte13xp driver but applied to the other
    xbus-based digital card.
    
    If dahdi_cfg set the DAHDI_CONFIG_NOTOPEN setting on the span, which it does
    when the "yellow" flag is added to the span config line, then it was possible
    for the span to get stuck with DAHDI_ALARM_NOTOPEN (NOP).
    
    This is because the driver only updates the alarm state when the framer reports
    that the span alarm has changed. Therefore, unless the framer goes through an
    alarm transition, the fact that channels are opened was never noticed by alarm
    handling routine.
    
    Now check the alarm state directly when the first channel is opened, and the
    last channel is closed.
    
    Internal-Issue-ID: DAHDI-1103
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wcte43x-base.c b/drivers/dahdi/wcte43x-base.c
index 38dbbf7..ab9ecb0 100644
--- a/drivers/dahdi/wcte43x-base.c
+++ b/drivers/dahdi/wcte43x-base.c
@@ -91,8 +91,9 @@ struct t43x;
 struct t43x_span {
 	struct t43x *owner;
 	struct dahdi_span span;
-#define NMF_FLAGBIT		1
-#define SENDINGYELLOW_FLAGBIT	2
+#define NMF_FLAGBIT			1
+#define SENDINGYELLOW_FLAGBIT		2
+#define HAVE_OPEN_CHANNELS_FLAGBIT	3
 	unsigned long bit_flags;
 	unsigned char txsigs[16];	/* Copy of tx sig registers */
 	unsigned long lofalarmtimer;
@@ -1719,10 +1720,21 @@ static void t43x_configure_e1(struct t43x *wc, int span_idx, int lineconfig)
 			framing, line, crc4);
 }
 
+static bool have_open_channels(const struct t43x_span *ts)
+{
+	int x, j;
+	for (x = 0, j = 0; x < ts->span.channels; x++) {
+		const struct dahdi_chan *chan = ts->span.chans[x];
+		if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags) ||
+		    dahdi_have_netdev(chan))
+			return true;
+	}
+	return false;
+}
+
 static void t43x_framer_start(struct t43x *wc)
 {
 	int unit;
-	struct t43x_span *ts;
 	unsigned long flags;
 	int res;
 
@@ -1739,7 +1751,7 @@ static void t43x_framer_start(struct t43x *wc)
 		dev_warn(&wc->xb.pdev->dev, "DMA engine did not stop.\n");
 
 	for (unit = 0; unit < wc->numspans; unit++) {
-		ts = wc->tspans[unit];
+		struct t43x_span *ts = wc->tspans[unit];
 		if (dahdi_is_e1_span(&ts->span)) {
 			t43x_configure_e1(wc, unit, ts->span.lineconfig);
 		} else { /* is a T1 card */
@@ -1753,6 +1765,15 @@ static void t43x_framer_start(struct t43x *wc)
 
 	for (unit = 0; unit < wc->numspans; unit++) {
 		/* Get this party started */
+		struct t43x_span *ts = wc->tspans[unit];
+
+		/* Check for "open channels" here in case some channels have
+		 * netdev. */
+		if (have_open_channels(ts))
+			clear_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags);
+		else
+			set_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags);
+
 		local_irq_save(flags);
 		t43x_check_alarms(wc, unit);
 		t43x_check_sigbits(wc, unit);
@@ -1774,7 +1795,7 @@ static void t43x_framer_start(struct t43x *wc)
 
 	/* Clear all counters */
 	for (unit = 0; unit < wc->numspans; unit++) {
-		ts = wc->tspans[unit];
+		struct t43x_span *ts = wc->tspans[unit];
 		memset(&ts->span.count, 0, sizeof(ts->span.count));
 	}
 
@@ -2657,7 +2678,6 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
 	struct t43x_span *ts = wc->tspans[span_idx];
 	unsigned char c, d;
 	int alarms;
-	int x, j;
 	int fidx = (wc->numspans == 2) ? span_idx+1 : span_idx;
 
 	if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &ts->span.flags)))
@@ -2699,11 +2719,7 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
 	}
 
 	if (ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN) {
-		for (x = 0, j = 0; x < ts->span.channels; x++)
-			if ((ts->chans[x]->flags & DAHDI_FLAG_OPEN) ||
-			    dahdi_have_netdev(ts->chans[x]))
-				j++;
-		if (!j)
+		if (!test_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags))
 			alarms |= DAHDI_ALARM_NOTOPEN;
 		else
 			alarms &= ~DAHDI_ALARM_NOTOPEN;
@@ -3157,6 +3173,45 @@ static void t43x_timer(unsigned long data)
 	return;
 }
 
+static int t43x_open(struct dahdi_chan *chan)
+{
+	struct t43x *wc = chan->pvt;
+	struct t43x_span *ts = container_of(chan->span, struct t43x_span, span);
+	unsigned long flags;
+
+	if (!(ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
+		return 0;
+
+	if (!test_and_set_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags)) {
+		local_irq_save(flags);
+		t43x_check_alarms(wc, ts->span.offset);
+		local_irq_restore(flags);
+	}
+
+	return 0;
+}
+
+static int t43x_close(struct dahdi_chan *chan)
+{
+	struct t43x *wc = chan->pvt;
+	struct t43x_span *ts = container_of(chan->span, struct t43x_span, span);
+	unsigned long flags;
+
+	if (!(ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
+		return 0;
+
+	if (have_open_channels(ts))
+		return 0;
+
+	if (!test_and_set_bit(HAVE_OPEN_CHANNELS_FLAGBIT, &ts->bit_flags)) {
+		local_irq_save(flags);
+		t43x_check_alarms(wc, ts->span.offset);
+		local_irq_restore(flags);
+	}
+
+	return 0;
+}
+
 static const struct dahdi_span_ops t43x_span_ops = {
 	.owner = THIS_MODULE,
 	.spanconfig = t43x_spanconfig,
@@ -3169,6 +3224,8 @@ static const struct dahdi_span_ops t43x_span_ops = {
 	.set_spantype = t43x_set_linemode,
 	.echocan_create = t43x_echocan_create,
 	.echocan_name = t43x_echocan_name,
+	.open = t43x_open,
+	.close = t43x_close,
 };
 
 /**

commit 61aeaf13ae2054c757f106aac92c7b0d445a3626
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue Jun 17 10:34:00 2014 -0500

    wcte43x: Change span flags to atomic bitfield.
    
    This will facilitate adding another flag for open channels on a span without
    needing to add a lock on the span, or taking the global lock. Currently the span
    flags are protected by the global reglock. This is not longer required.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wcte43x-base.c b/drivers/dahdi/wcte43x-base.c
index 34dd74b..38dbbf7 100644
--- a/drivers/dahdi/wcte43x-base.c
+++ b/drivers/dahdi/wcte43x-base.c
@@ -91,10 +91,9 @@ struct t43x;
 struct t43x_span {
 	struct t43x *owner;
 	struct dahdi_span span;
-	struct {
-		unsigned int nmf:1;
-		unsigned int sendingyellow:1;
-	} flags;
+#define NMF_FLAGBIT		1
+#define SENDINGYELLOW_FLAGBIT	2
+	unsigned long bit_flags;
 	unsigned char txsigs[16];	/* Copy of tx sig registers */
 	unsigned long lofalarmtimer;
 	unsigned long losalarmtimer;
@@ -2677,10 +2676,9 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
 			/* No multiframe found, force RAI high after 400ms only
 			 * if we haven't found a multiframe since last loss of
 			 * frame */
-			if (!ts->flags.nmf) {
+			if (!test_and_set_bit(NMF_FLAGBIT, &ts->bit_flags)) {
 				/* LIM0: Force RAI High */
 				__t43x_framer_set(wc, fidx, 0x20, 0x9f | 0x20);
-				ts->flags.nmf = 1;
 				dev_info(&wc->xb.pdev->dev,
 					 "NMF workaround on!\n");
 			}
@@ -2691,10 +2689,9 @@ static void t43x_check_alarms(struct t43x *wc, int span_idx)
 			/* Force Resync */
 			__t43x_framer_set(wc, fidx, 0x1c, 0xf0);
 		} else if (!(c & 0x02)) {
-			if (ts->flags.nmf) {
+			if (test_and_clear_bit(NMF_FLAGBIT, &ts->bit_flags)) {
 				/* LIM0: Clear forced RAI */
 				__t43x_framer_set(wc, fidx, 0x20, 0x9f);
-				ts->flags.nmf = 0;
 				dev_info(&wc->xb.pdev->dev,
 						"NMF workaround off!\n");
 			}
@@ -2868,21 +2865,19 @@ static void t43x_debounce_alarms(struct t43x *wc, int span_idx)
 	/* If receiving alarms (except Yellow), go into Yellow alarm state */
 	if (alarms & (DAHDI_ALARM_RED|DAHDI_ALARM_BLUE|
 				DAHDI_ALARM_NOTOPEN|DAHDI_ALARM_RECOVER)) {
-		if (!ts->flags.sendingyellow) {
+		if (!test_and_set_bit(SENDINGYELLOW_FLAGBIT, &ts->bit_flags)) {
 			dev_info(&wc->xb.pdev->dev, "Setting yellow alarm\n");
 			/* We manually do yellow alarm to handle RECOVER
 			 * and NOTOPEN, otherwise it's auto anyway */
 			fmr4 = __t43x_framer_get(wc, fidx, 0x20);
 			__t43x_framer_set(wc, fidx, 0x20, fmr4 | 0x20);
-			ts->flags.sendingyellow = 1;
 		}
 	} else {
-		if (ts->flags.sendingyellow) {
+		if (test_and_clear_bit(SENDINGYELLOW_FLAGBIT, &ts->bit_flags)) {
 			dev_info(&wc->xb.pdev->dev, "Clearing yellow alarm\n");
 			/* We manually do yellow alarm to handle RECOVER  */
 			fmr4 = __t43x_framer_get(wc, fidx, 0x20);
 			__t43x_framer_set(wc, fidx, 0x20, fmr4 & ~0x20);
-			ts->flags.sendingyellow = 0;
 		}
 	}
 

commit f35e8aafb0af4f3cb791fe83a306a815590fe5ae
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue Jun 17 00:42:44 2014 -0500

    wcte13xp: Do not get stuck in "Not Open" state when DAHDI_CONFIG_NOTOPEN is set.
    
    If dahdi_cfg set the DAHDI_CONFIG_NOTOPEN setting on the span, which it does
    when the "yellow" flag is added to the span config line, then it was possible
    for the span to get stuck with DAHDI_ALARM_NOTOPEN (NOP).
    
    This is because the wcte13xp driver only updates the alarm state when the framer
    reports that the span alarm has changed. Therefore, unless the framer goes
    through an alarm transition, the fact that channels are opened was never noticed
    by alarm handling routine.
    
    Now check the alarm state directly when the first channel is opened, and the
    last channel is closed.
    
    Internal-Issue-ID: DAHDI-1103
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wcte13xp-base.c b/drivers/dahdi/wcte13xp-base.c
index 74d8883..d5ec958 100644
--- a/drivers/dahdi/wcte13xp-base.c
+++ b/drivers/dahdi/wcte13xp-base.c
@@ -92,9 +92,10 @@ struct t13x {
 	unsigned long loopuptimer;
 	unsigned long loopdntimer;
 	const char *name;
-#define INITIALIZED    1
-#define SHUTDOWN       2
-#define READY	       3
+#define INITIALIZED		1
+#define SHUTDOWN		2
+#define READY			3
+#define HAVE_OPEN_CHANNELS	4
 	unsigned long bit_flags;
 	u32 ledstate;
 	struct dahdi_device *ddev;
@@ -1285,6 +1286,18 @@ static int te13xp_check_for_interrupts(struct t13x *wc)
 	return 0;
 }
 
+static bool have_open_channels(const struct t13x *wc)
+{
+	int x, j;
+	for (x = 0, j = 0; x < wc->span.channels; x++) {
+		const struct dahdi_chan *chan = wc->span.chans[x];
+		if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags) ||
+		    dahdi_have_netdev(chan))
+			return true;
+	}
+	return false;
+}
+
 static int t13x_startup(struct file *file, struct dahdi_span *span)
 {
 	struct t13x *wc = container_of(span, struct t13x, span);
@@ -1315,6 +1328,12 @@ static int t13x_startup(struct file *file, struct dahdi_span *span)
 	dev_info(&wc->xb.pdev->dev,
 			"Calling startup (flags is %lu)\n", span->flags);
 
+	/* Check for "open channels" here in case some channels have netdev. */
+	if (have_open_channels(wc))
+		clear_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags);
+	else
+		set_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags);
+
 	/* Get this party started */
 	local_irq_save(flags);
 	t13x_check_alarms(wc);
@@ -1904,7 +1923,6 @@ static void t13x_check_alarms(struct t13x *wc)
 {
 	unsigned char c, d;
 	int alarms;
-	int x, j;
 
 	if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags)))
 		return;
@@ -1943,11 +1961,7 @@ static void t13x_check_alarms(struct t13x *wc)
 	}
 
 	if (wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN) {
-		for (x = 0, j = 0; x < wc->span.channels; x++)
-			if ((wc->span.chans[x]->flags & DAHDI_FLAG_OPEN) ||
-			    dahdi_have_netdev(wc->span.chans[x]))
-				j++;
-		if (!j)
+		if (!test_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags))
 			alarms |= DAHDI_ALARM_NOTOPEN;
 		else
 			alarms &= ~DAHDI_ALARM_NOTOPEN;
@@ -2348,6 +2362,41 @@ static void te13xp_timer(unsigned long data)
 static inline void create_sysfs_files(struct t13x *wc) { return; }
 static inline void remove_sysfs_files(struct t13x *wc) { return; }
 
+static int t13x_open(struct dahdi_chan *chan)
+{
+	struct t13x *wc = chan->pvt;
+	unsigned long flags;
+
+	if (!(wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
+		return 0;
+
+	if (!test_and_set_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags)) {
+		local_irq_save(flags);
+		t13x_check_alarms(wc);
+		local_irq_restore(flags);
+	}
+
+	return 0;
+}
+
+static int t13x_close(struct dahdi_chan *chan)
+{
+	struct t13x *wc = chan->pvt;
+	unsigned long flags;
+
+	if (!(wc->span.lineconfig & DAHDI_CONFIG_NOTOPEN))
+		return 0;
+
+	if (!have_open_channels(wc)) {
+		if (test_and_clear_bit(HAVE_OPEN_CHANNELS, &wc->bit_flags)) {
+			local_irq_save(flags);
+			t13x_check_alarms(wc);
+			local_irq_restore(flags);
+		}
+	}
+	return 0;
+}
+
 static const struct dahdi_span_ops t13x_span_ops = {
 	.owner = THIS_MODULE,
 	.spanconfig = t13x_spanconfig,
@@ -2359,6 +2408,8 @@ static const struct dahdi_span_ops t13x_span_ops = {
 	.set_spantype = t13x_set_linemode,
 	.echocan_create = t13x_echocan_create,
 	.echocan_name = t13x_echocan_name,
+	.open = t13x_open,
+	.close = t13x_close,
 };
 
 #define SPI_BASE 0x200

commit b3a6b9185852958a35a1754ece550f59356e23f9
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue Jun 17 02:11:40 2014 -0500

    Do not call dahdi_span_ops.open with spinlock held.
    
    This makes the open symmetrical with the close. It is also considered good
    practice to not call through callbacks with spinlocks held.
    
    I modified all the drivers where I could not tell whether it was necessary to
    hold the chan->lock with interrupts disabled to simply take the lock inside the
    callback.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 41ea4e5..40131a4 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -3057,57 +3057,64 @@ static const struct file_operations dahdi_chan_fops;
 
 static int dahdi_specchan_open(struct file *file)
 {
-	int res = 0;
+	int res = -ENXIO;
 	struct dahdi_chan *const chan = chan_from_file(file);
 
-	if (chan && chan->sig) {
-		/* Make sure we're not already open, a net device, or a slave device */
-		if (dahdi_have_netdev(chan))
-			res = -EBUSY;
-		else if (chan->master != chan)
-			res = -EBUSY;
-		else if ((chan->sig & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS)
-			res = -EBUSY;
-		else if (!test_and_set_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) {
-			unsigned long flags;
-			res = initialize_channel(chan);
+	if (!chan || !chan->sig)
+		return -ENXIO;
+
+	/* Make sure we're not already open, a net device, or a slave
+	 * device */
+	if (dahdi_have_netdev(chan))
+		res = -EBUSY;
+	else if (chan->master != chan)
+		res = -EBUSY;
+	else if ((chan->sig & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS)
+		res = -EBUSY;
+	else if (!test_and_set_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) {
+		unsigned long flags;
+		const struct dahdi_span_ops *const ops =
+		       (!is_pseudo_chan(chan)) ? chan->span->ops : NULL;
+
+		if (ops && !try_module_get(ops->owner)) {
+			clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
+			return -ENXIO;
+		}
+
+		res = initialize_channel(chan);
+		if (res) {
+			/* Reallocbufs must have failed */
+			clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
+			return res;
+		}
+
+		spin_lock_irqsave(&chan->lock, flags);
+		if (is_pseudo_chan(chan))
+			chan->flags |= DAHDI_FLAG_AUDIO;
+		chan->file = file;
+		file->private_data = chan;
+		/* Since we know we're a channel now, we can
+		 * update the f_op pointer and bypass a few of
+		 * the checks on the minor number. */
+		file->f_op = &dahdi_chan_fops;
+		spin_unlock_irqrestore(&chan->lock, flags);
+
+		if (ops && ops->open) {
+			res = ops->open(chan);
 			if (res) {
-				/* Reallocbufs must have failed */
-				clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
-				return res;
-			}
-			spin_lock_irqsave(&chan->lock, flags);
-			if (is_pseudo_chan(chan))
-				chan->flags |= DAHDI_FLAG_AUDIO;
-			if (chan->span) {
-				const struct dahdi_span_ops *const ops =
-								chan->span->ops;
-				if (!try_module_get(ops->owner)) {
-					res = -ENXIO;
-				} else if (ops->open) {
-					res = ops->open(chan);
-					if (res)
-						module_put(ops->owner);
-				}
-			}
-			if (!res) {
-				chan->file = file;
-				file->private_data = chan;
-				/* Since we know we're a channel now, we can
-				 * update the f_op pointer and bypass a few of
-				 * the checks on the minor number. */
-				file->f_op = &dahdi_chan_fops;
-				spin_unlock_irqrestore(&chan->lock, flags);
-			} else {
+				spin_lock_irqsave(&chan->lock, flags);
+				chan->file = NULL;
+				file->private_data = NULL;
 				spin_unlock_irqrestore(&chan->lock, flags);
+				module_put(ops->owner);
 				close_channel(chan);
-				clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
+				clear_bit(DAHDI_FLAGBIT_OPEN,
+					  &chan->flags);
 			}
-		} else {
-			res = -EBUSY;
 		}
-	} else
-		res = -ENXIO;
+	} else {
+		res = -EBUSY;
+	}
 	return res;
 }
 
diff --git a/drivers/dahdi/wcb4xxp/base.c b/drivers/dahdi/wcb4xxp/base.c
index 218611c..5538660 100644
--- a/drivers/dahdi/wcb4xxp/base.c
+++ b/drivers/dahdi/wcb4xxp/base.c
@@ -2430,7 +2430,7 @@ b4xxp_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype)
 	return 0;
 }
 
-static int b4xxp_open(struct dahdi_chan *chan)
+static int _b4xxp_open(struct dahdi_chan *chan)
 {
 	struct b4xxp *b4 = chan->pvt;
 	struct b4xxp_span *bspan = &b4->spans[chan->span->offset];
@@ -2444,6 +2444,15 @@ static int b4xxp_open(struct dahdi_chan *chan)
 	return 0;
 }
 
+static int b4xxp_open(struct dahdi_chan *chan)
+{
+	unsigned long flags;
+	int res;
+	spin_lock_irqsave(&chan->lock, flags);
+	res = _b4xxp_open(chan);
+	spin_unlock_irqrestore(&chan->lock, flags);
+	return res;
+}
 
 static int b4xxp_close(struct dahdi_chan *chan)
 {
diff --git a/drivers/dahdi/wcfxo.c b/drivers/dahdi/wcfxo.c
index 63f5749..ad74137 100644
--- a/drivers/dahdi/wcfxo.c
+++ b/drivers/dahdi/wcfxo.c
@@ -570,7 +570,7 @@ static inline struct wcfxo *wcfxo_from_span(struct dahdi_span *span)
 	return container_of(span, struct wcfxo, span);
 }
 
-static int wcfxo_open(struct dahdi_chan *chan)
+static int _wcfxo_open(struct dahdi_chan *chan)
 {
 	struct wcfxo *wc = chan->pvt;
 	if (wc->dead)
@@ -579,6 +579,16 @@ static int wcfxo_open(struct dahdi_chan *chan)
 	return 0;
 }
 
+static int wcfxo_open(struct dahdi_chan *chan)
+{
+	int res;
+	unsigned long flags;
+	spin_lock_irqsave(&chan->lock, flags);
+	res = _wcfxo_open(chan);
+	spin_unlock_irqrestore(&chan->lock, flags);
+	return res;
+}
+
 static int wcfxo_watchdog(struct dahdi_span *span, int event)
 {
 	printk(KERN_INFO "FXO: Restarting DMA\n");
diff --git a/drivers/dahdi/wctdm.c b/drivers/dahdi/wctdm.c
index 52302ea..f82bc6d 100644
--- a/drivers/dahdi/wctdm.c
+++ b/drivers/dahdi/wctdm.c
@@ -2144,7 +2144,7 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long
 
 }
 
-static int wctdm_open(struct dahdi_chan *chan)
+static int _wctdm_open(struct dahdi_chan *chan)
 {
 	struct wctdm *wc = chan->pvt;
 	if (!(wc->cardflag & (1 << (chan->chanpos - 1))))
@@ -2155,6 +2155,16 @@ static int wctdm_open(struct dahdi_chan *chan)
 	return 0;
 }
 
+static int wctdm_open(struct dahdi_chan *chan)
+{
+	unsigned long flags;
+	int res;
+	spin_lock_irqsave(&chan->lock, flags);
+	res = _wctdm_open(chan);
+	spin_unlock_irqrestore(&chan->lock, flags);
+	return res;
+}
+
 static inline struct wctdm *wctdm_from_span(struct dahdi_span *span)
 {
 	return container_of(span, struct wctdm, span);
diff --git a/drivers/dahdi/wcte11xp.c b/drivers/dahdi/wcte11xp.c
index b5db12c..eac62e3 100644
--- a/drivers/dahdi/wcte11xp.c
+++ b/drivers/dahdi/wcte11xp.c
@@ -225,7 +225,7 @@ static inline void __select_control(struct t1 *wc)
 	}
 }
 
-static int t1xxp_open(struct dahdi_chan *chan)
+static int _t1xxp_open(struct dahdi_chan *chan)
 {
 	struct t1 *wc = chan->pvt;
 	if (wc->dead)
@@ -235,6 +235,16 @@ static int t1xxp_open(struct dahdi_chan *chan)
 	return 0;
 }
 
+static int t1xxp_open(struct dahdi_chan *chan)
+{
+	unsigned long flags;
+	int res;
+	spin_lock_irqsave(&chan->lock, flags);
+	res = _t1xxp_open(chan);
+	spin_unlock_irqrestore(&chan->lock, flags);
+	return res;
+}
+
 static int __control_set_reg(struct t1 *wc, int reg, unsigned char val)
 {
 	__select_control(wc);
diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c
index 8e6523d..9b5c42a 100644
--- a/drivers/dahdi/xpp/xpp_dahdi.c
+++ b/drivers/dahdi/xpp/xpp_dahdi.c
@@ -714,10 +714,10 @@ EXPORT_SYMBOL(hookstate_changed);
 /*------------------------- Dahdi Interfaces -----------------------*/
 
 /*
- * Called from dahdi with spinlock held on chan. Must not call back
+ * Called with spinlock held on chan. Must not call back
  * dahdi functions.
  */
-int xpp_open(struct dahdi_chan *chan)
+static int _xpp_open(struct dahdi_chan *chan)
 {
 	xpd_t *xpd;
 	xbus_t *xbus;
@@ -750,6 +750,16 @@ int xpp_open(struct dahdi_chan *chan)
 		CALL_PHONE_METHOD(card_open, xpd, pos);
 	return 0;
 }
+
+int xpp_open(struct dahdi_chan *chan)
+{
+	unsigned long flags;
+	int res;
+	spin_lock_irqsave(&chan->lock, flags);
+	res = _xpp_open(chan);
+	spin_unlock_irqrestore(&chan->lock, flags);
+	return res;
+}
 EXPORT_SYMBOL(xpp_open);
 
 int xpp_close(struct dahdi_chan *chan)

commit 2e33bdc7b55a30c0ad9a05705c23297a897e0e2c
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue Jun 17 02:09:32 2014 -0500

    tor2: Remove unused open/close callbacks.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/tor2.c b/drivers/dahdi/tor2.c
index f0ad710..5d2f37e 100644
--- a/drivers/dahdi/tor2.c
+++ b/drivers/dahdi/tor2.c
@@ -254,16 +254,6 @@ static int tor2_chanconfig(struct file *file,
 	return 0;
 }
 
-static int tor2_open(struct dahdi_chan *chan)
-{
-	return 0;
-}
-
-static int tor2_close(struct dahdi_chan *chan)
-{
-	return 0;
-}
-
 static const struct dahdi_span_ops tor2_span_ops = {
 	.owner = THIS_MODULE,
 	.spanconfig = tor2_spanconfig,
@@ -272,8 +262,6 @@ static const struct dahdi_span_ops tor2_span_ops = {
 	.shutdown = tor2_shutdown,
 	.rbsbits = tor2_rbsbits,
 	.maint = tor2_maint,
-	.open = tor2_open,
-	.close  = tor2_close,
 	.ioctl = tor2_ioctl,
 };
 

commit 3755ec9bf293a559ebc1f036a7694d3b3db232db
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue Jun 17 01:33:15 2014 -0500

    wct4xxp: Remove unused open/close span_ops callbacks.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
index e2b4a90..983e448 100644
--- a/drivers/dahdi/wct4xxp/base.c
+++ b/drivers/dahdi/wct4xxp/base.c
@@ -1832,16 +1832,6 @@ t4_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype)
 	return 0;
 }
 
-static int t4_open(struct dahdi_chan *chan)
-{
-	return 0;
-}
-
-static int t4_close(struct dahdi_chan *chan)
-{
-	return 0;
-}
-
 static int set_span_devicetype(struct t4 *wc)
 {
 #ifdef VPM_SUPPORT
@@ -2334,8 +2324,6 @@ static const struct dahdi_span_ops t4_gen1_span_ops = {
 	.shutdown = t4_shutdown,
 	.rbsbits = t4_rbsbits,
 	.maint = t4_maint,
-	.open = t4_open,
-	.close  = t4_close,
 	.ioctl = t4_ioctl,
 	.hdlc_hard_xmit = t4_hdlc_hard_xmit,
 	.assigned = t4_span_assigned,
@@ -2350,8 +2338,6 @@ static const struct dahdi_span_ops t4_gen2_span_ops = {
 	.shutdown = t4_shutdown,
 	.rbsbits = t4_rbsbits,
 	.maint = t4_maint,
-	.open = t4_open,
-	.close  = t4_close,
 	.ioctl = t4_ioctl,
 	.hdlc_hard_xmit = t4_hdlc_hard_xmit,
 	.dacs = t4_dacs,

commit 47f0fde0f16a3d54da4610e400605bd6e7be5bf3
Author: Doug Bailey <dbailey at digium.com>
Date:   Tue Jun 17 17:23:35 2014 -0500

    wct4xxp: AMI w/CAS errata applies to octal card as well.
    
    Fixes inability to reliably get CAS (robbed-bits) when using AMI line encoding
    on the TE820 card.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
index 98d2587..e2b4a90 100644
--- a/drivers/dahdi/wct4xxp/base.c
+++ b/drivers/dahdi/wct4xxp/base.c
@@ -2724,7 +2724,7 @@ static void __t4_configure_t1(struct t4 *wc, int unit, int lineconfig, int txlev
 	if (lineconfig & DAHDI_CONFIG_AMI) {
 		line = "AMI";
 		/* workaround for errata #2 in ES v3 09-10-16 */
-		fmr0 = (wc->falc31) ? 0xb0 : 0xa0;
+		fmr0 = (is_octal(wc) || wc->falc31) ? 0xb0 : 0xa0;
 	} else {
 		line = "B8ZS";
 		fmr0 = 0xf0;
@@ -2823,7 +2823,7 @@ static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig)
 	if (lineconfig & DAHDI_CONFIG_AMI) {
 		line = "AMI";
 		/* workaround for errata #2 in ES v3 09-10-16 */
-		fmr0 = (wc->falc31) ? 0xb0 : 0xa0;
+		fmr0 = (is_octal(wc) || wc->falc31) ? 0xb0 : 0xa0;
 	} else {
 		line = "HDB3";
 		fmr0 = 0xf0;

commit 180a17a39c0152b5e72c72d4fa710057df7031f1
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue Jun 17 14:51:39 2014 -0500

    wct4xxp: Trivial kmalloc + memset -> kzalloc.
    
    Just a minor cleanup.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wct4xxp/vpm450m.c b/drivers/dahdi/wct4xxp/vpm450m.c
index 4118880..82a0463 100644
--- a/drivers/dahdi/wct4xxp/vpm450m.c
+++ b/drivers/dahdi/wct4xxp/vpm450m.c
@@ -239,7 +239,7 @@ static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode)
 
 	if (vpm450m->ecmode[channel] == mode)
 		return;
-	modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC);
+	modify = kzalloc(sizeof(*modify), GFP_ATOMIC);
 	if (!modify) {
 		printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setec!\n");
 		return;
@@ -269,7 +269,7 @@ void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute)
 		return;
 	}
 
-	modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL);
+	modify = kzalloc(sizeof(*modify), GFP_KERNEL);
 	if (!modify) {
 		printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setdtmf!\n");
 		return;
@@ -454,28 +454,27 @@ struct vpm450m *init_vpm450m(struct device *device, int *isalaw,
 	struct vpm450m *vpm450m;
 	int x,y,law;
 	
-	if (!(vpm450m = kmalloc(sizeof(struct vpm450m), GFP_KERNEL)))
+	vpm450m = kzalloc(sizeof(*vpm450m), GFP_KERNEL);
+	if (!vpm450m)
 		return NULL;
 
-	memset(vpm450m, 0, sizeof(struct vpm450m));
 	vpm450m->context.dev = device;
 	vpm450m->context.ops = &wct4xxp_oct612x_ops;
 
-	if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) {
+	ChipOpen = kzalloc(sizeof(*ChipOpen), GFP_KERNEL);
+	if (!ChipOpen) {
+		kfree(vpm450m);
 		kfree(vpm450m);
 		return NULL;
 	}
 
-	memset(ChipOpen, 0, sizeof(tOCT6100_CHIP_OPEN));
-
-	if (!(ChannelOpen = kmalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL))) {
+	ChannelOpen = kzalloc(sizeof(*ChannelOpen), GFP_KERNEL);
+	if (!ChannelOpen) {
 		kfree(vpm450m);
 		kfree(ChipOpen);
 		return NULL;
 	}
 
-	memset(ChannelOpen, 0, sizeof(tOCT6100_CHANNEL_OPEN));
-
 	for (x = 0; x < ARRAY_SIZE(vpm450m->ecmode); x++)
 		vpm450m->ecmode[x] = -1;
 

commit d1afa1b101aef9dfb9640bcad1ac21ef8c372cb3
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Wed Jun 18 13:03:42 2014 -0500

    oct612x: Implement the SerializationObject callbacks.
    
    When originally implemented, the octasic calls where protected by the big kernel
    lock. This change now allows the octasic library to control it's synchronization
    as originally intended.
    
    It would still be worthwhile to completely make the oct612x library
    kernel-compliant.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/oct612x/include/oct6100api/oct6100_apiud.h b/drivers/dahdi/oct612x/include/oct6100api/oct6100_apiud.h
index feff93e..8bee548 100644
--- a/drivers/dahdi/oct612x/include/oct6100api/oct6100_apiud.h
+++ b/drivers/dahdi/oct612x/include/oct6100api/oct6100_apiud.h
@@ -129,7 +129,7 @@ $Octasic_Revision: 16 $
 /*****************************  TYPES  ***************************************/
 
 /*Change this type if your platform uses 64bits semaphores/locks */ 
-typedef UINT32 tOCT6100_USER_SERIAL_OBJECT;
+typedef void* tOCT6100_USER_SERIAL_OBJECT;
 
 typedef struct _OCT6100_GET_TIME_
 {
diff --git a/drivers/dahdi/oct612x/oct612x-user.c b/drivers/dahdi/oct612x/oct612x-user.c
index b5a845a..4ee5981 100644
--- a/drivers/dahdi/oct612x/oct612x-user.c
+++ b/drivers/dahdi/oct612x/oct612x-user.c
@@ -59,29 +59,38 @@ UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource,
 UINT32 Oct6100UserCreateSerializeObject(
 			tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate)
 {
+	struct oct612x_context *context = f_pCreate->pProcessContext;
+	struct mutex *lock = kzalloc(sizeof(*lock), GFP_KERNEL);
+	if (!lock) {
+		dev_err(context->dev, "Out of memory in %s.\n", __func__);
+		return cOCT6100_ERR_BASE;
+	}
+	mutex_init(lock);
+	f_pCreate->ulSerialObjHndl = lock;
 	return cOCT6100_ERR_OK;
 }
 
 UINT32 Oct6100UserDestroySerializeObject(
 			tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy)
 {
-#ifdef OCTASIC_DEBUG
-	pr_debug("I should never be called! (destroy serialize object)\n");
-#endif
+	struct mutex *lock = f_pDestroy->ulSerialObjHndl;
+	kfree(lock);
 	return cOCT6100_ERR_OK;
 }
 
 UINT32 Oct6100UserSeizeSerializeObject(
 		tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize)
 {
-	/* Not needed */
+	struct mutex *lock = f_pSeize->ulSerialObjHndl;
+	mutex_lock(lock);
 	return cOCT6100_ERR_OK;
 }
 
 UINT32 Oct6100UserReleaseSerializeObject(
 		tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease)
 {
-	/* Not needed */
+	struct mutex *lock = f_pRelease->ulSerialObjHndl;
+	mutex_unlock(lock);
 	return cOCT6100_ERR_OK;
 }
 

commit b4941f35ad57df4ccce70478b782727a30d4ec20
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri Jun 20 12:02:49 2014 -0500

    wct4xxp: Move bottom half processing from tasklet to workqueue.
    
    I am primarily making this change in order that the oct612x API can use a mutex as
    a synchronization primitive. Mutexes can only be aquired in process context and
    the wct4xxp driver calls the Oct61000InterruptServiceRoutine (which grabs a
    serialization object) when tone detection is enabled.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
index ebcdf03..98d2587 100644
--- a/drivers/dahdi/wct4xxp/base.c
+++ b/drivers/dahdi/wct4xxp/base.c
@@ -371,9 +371,14 @@ struct t4 {
 	dma_addr_t	writedma;
 	void __iomem	*membase;	/* Base address of card */
 
-	/* Flags for our bottom half */
+#define T4_CHECK_VPM		0
+#define T4_LOADING_FW		1
+#define T4_STOP_DMA		2
+#define T4_CHECK_TIMING		3
+#define T4_CHANGE_LATENCY	4
+#define T4_IGNORE_LATENCY	5
 	unsigned long checkflag;
-	struct tasklet_struct t4_tlet;
+	struct work_struct  bh_work;
 	/* Latency related additions */
 	unsigned char rxident;
 	unsigned char lastindex;
@@ -549,8 +554,6 @@ static void t4_check_sigbits(struct t4 *wc, int span);
 
 #define MAX_T4_CARDS 64
 
-static void t4_isr_bh(unsigned long data);
-
 static struct t4 *cards[MAX_T4_CARDS];
 
 struct t8_firm_header {
@@ -2116,6 +2119,8 @@ static void free_wc(struct t4 *wc)
 {
 	unsigned int x, y;
 
+	flush_scheduled_work();
+
 	for (x = 0; x < ARRAY_SIZE(wc->tspans); x++) {
 		if (!wc->tspans[x])
 			continue;
@@ -4056,9 +4061,15 @@ static void t4_increase_latency(struct t4 *wc, int newlatency)
 
 }
 
-static void t4_isr_bh(unsigned long data)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void t4_work_func(void *data)
+{
+	struct t4 *wc = data;
+#else
+static void t4_work_func(struct work_struct *work)
 {
-	struct t4 *wc = (struct t4 *)data;
+	struct t4 *wc = container_of(work, struct t4, bh_work);
+#endif
 
 	if (test_bit(T4_CHANGE_LATENCY, &wc->checkflag)) {
 		if (wc->needed_latency != wc->numbufs) {
@@ -4265,7 +4276,7 @@ static irqreturn_t _t4_interrupt_gen2(int irq, void *dev_id)
 
 out:
 	if (unlikely(test_bit(T4_CHANGE_LATENCY, &wc->checkflag) || test_bit(T4_CHECK_VPM, &wc->checkflag)))
-		tasklet_schedule(&wc->t4_tlet);
+		schedule_work(&wc->bh_work);
 
 #ifndef ENABLE_WORKQUEUES
 	__t4_pci_out(wc, WC_INTR, 0);
@@ -5146,7 +5157,11 @@ static int __devinit t4_launch(struct t4 *wc)
 			      &wc->ddev->spans);
 	}
 
-	tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	INIT_WORK(&wc->bh_work, t4_work_func, wc);
+#else
+	INIT_WORK(&wc->bh_work, t4_work_func);
+#endif
 
 	res = dahdi_register_device(wc->ddev, &wc->dev->dev);
 	if (res) {
diff --git a/drivers/dahdi/wct4xxp/wct4xxp.h b/drivers/dahdi/wct4xxp/wct4xxp.h
index 0546160..13d5ad6 100644
--- a/drivers/dahdi/wct4xxp/wct4xxp.h
+++ b/drivers/dahdi/wct4xxp/wct4xxp.h
@@ -131,13 +131,6 @@ struct t4_reg {
 	unsigned int val;
 };
 
-#define T4_CHECK_VPM		0
-#define T4_LOADING_FW		1
-#define T4_STOP_DMA		2
-#define T4_CHECK_TIMING		3
-#define T4_CHANGE_LATENCY	4
-#define T4_IGNORE_LATENCY	5
-
 #define WCT4_GET_REGS	_IOW(DAHDI_CODE, 60, struct t4_regs)
 #define WCT4_GET_REG	_IOW(DAHDI_CODE, 61, struct t4_reg)
 #define WCT4_SET_REG	_IOW(DAHDI_CODE, 62, struct t4_reg)

commit a3578ca156a68970ea419e8da4d2f7a96c820c73
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Thu Jun 19 16:45:41 2014 -0500

    dahdi: dahdi_chan.ec_factory can be protected with the mutex.
    
    This is never accessed or modified in interrupt context. This closes a potential
    race if the echocan is being changed on a channel while enabling disabling is
    hapening on another thread.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 0e2ab22..41ea4e5 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -991,10 +991,13 @@ static int dahdi_seq_show(struct seq_file *sfile, void *data)
 
 		seq_fill_alarm_string(sfile, chan->chan_alarms);
 
-		if (chan->ec_factory)
+		mutex_lock(&chan->mutex);
+		if (chan->ec_factory) {
 			seq_printf(sfile, "(EC: %s - %s) ",
 					chan->ec_factory->get_name(chan),
 					chan->ec_state ? "ACTIVE" : "INACTIVE");
+		}
+		mutex_unlock(&chan->mutex);
 
 		seq_printf(sfile, "\n");
 	}
@@ -1489,14 +1492,13 @@ static const struct dahdi_echocan_factory hwec_factory = {
 static int dahdi_enable_hw_preechocan(struct dahdi_chan *chan)
 {
 	int res;
-	unsigned long flags;
 
-	spin_lock_irqsave(&chan->lock, flags);
+	mutex_lock(&chan->mutex);
 	if (chan->ec_factory != &hwec_factory)
 		res = -ENODEV;
 	else
 		res = 0;
-	spin_unlock_irqrestore(&chan->lock, flags);
+	mutex_unlock(&chan->mutex);
 
 	if (-ENODEV == res)
 		return 0;
@@ -2303,10 +2305,10 @@ static void dahdi_chan_unreg(struct dahdi_chan *chan)
 		 */
 	}
 
-	spin_lock_irqsave(&chan->lock, flags);
+	mutex_lock(&chan->mutex);
 	release_echocan(chan->ec_factory);
 	chan->ec_factory = NULL;
-	spin_unlock_irqrestore(&chan->lock, flags);
+	mutex_unlock(&chan->mutex);
 
 #ifdef CONFIG_DAHDI_NET
 	if (dahdi_have_netdev(chan)) {
@@ -5227,7 +5229,6 @@ static bool dahdi_is_hwec_available(const struct dahdi_chan *chan)
 
 static int dahdi_ioctl_attach_echocan(unsigned long data)
 {
-	unsigned long flags;
 	struct dahdi_chan *chan;
 	struct dahdi_attach_echocan ae;
 	const struct dahdi_echocan_factory *new = NULL, *old;
@@ -5269,10 +5270,10 @@ static int dahdi_ioctl_attach_echocan(unsigned long data)
 		}
 	}
 
-	spin_lock_irqsave(&chan->lock, flags);
+	mutex_lock(&chan->mutex);
 	old = chan->ec_factory;
 	chan->ec_factory = new;
-	spin_unlock_irqrestore(&chan->lock, flags);
+	mutex_unlock(&chan->mutex);
 
 	if (old)
 		release_echocan(old);

commit 761e02da5267f1d6a516469b240da2b37f871c88
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Thu Jun 19 16:40:01 2014 -0500

    dahdi: Protect echocan creation/destruction with mutex.
    
    This closes a reference and memory leak when multiple CPUs are enabling echocan
    on a single channel in parallel.
    
    The essential problem is that the call to try_module_get() is not serialized.
    Two separate threads can come into ioctl_echocan() on the same channel, they
    coordinate via the dahdi_chan.lock to release any current echocan, but then both
    create a new echocan state, bump the reference on the module, and the last one
    through will actually attach the new state to the channel. The earlier reference
    / memory is leaked.
    
    I tried to conceive of a way to fix this leak without adding a new lock, but the
    choices where calling throught the function pointers with dahdi_chan.lock.
    Otherwise I needed to change the semantics of echocan_create /free which would
    ripple through the hardware echocan modules.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index c49f465..0e2ab22 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -1884,6 +1884,7 @@ static void __dahdi_init_chan(struct dahdi_chan *chan)
 	might_sleep();
 
 	spin_lock_init(&chan->lock);
+	mutex_init(&chan->mutex);
 	init_waitqueue_head(&chan->waitq);
 	if (!chan->master)
 		chan->master = chan;
@@ -6331,6 +6332,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
 
 	if (ecp->tap_length == 0) {
 		/* disable mode, don't need to inspect params */
+		mutex_lock(&chan->mutex);
 		spin_lock_irqsave(&chan->lock, flags);
 		ec_state = chan->ec_state;
 		chan->ec_state = NULL;
@@ -6341,7 +6343,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
 			ec_state->ops->echocan_free(chan, ec_state);
 			release_echocan(ec_current);
 		}
-
+		mutex_unlock(&chan->mutex);
 		return 0;
 	}
 
@@ -6358,6 +6360,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
 		goto exit_with_free;
 	}
 
+	mutex_lock(&chan->mutex);
 	/* free any echocan that may be on the channel already */
 	spin_lock_irqsave(&chan->lock, flags);
 	ec_state = chan->ec_state;
@@ -6428,6 +6431,7 @@ ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
 	}
 
 exit_with_free:
+	mutex_unlock(&chan->mutex);
 	kfree(params);
 
 	return ret;
diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h
index aed5286..831ea5f 100644
--- a/include/dahdi/kernel.h
+++ b/include/dahdi/kernel.h
@@ -425,6 +425,7 @@ struct dahdi_chan {
 	int lastnumbufs;
 #endif
 	spinlock_t lock;
+	struct mutex mutex;
 	char name[40];
 	/* Specified by DAHDI */
 	/*! \brief DAHDI channel number */

-----------------------------------------------------------------------


-- 
dahdi/linux.git



More information about the dahdi-commits mailing list