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

SVN commits to the DAHDI project dahdi-commits at lists.digium.com
Mon Mar 30 05:18:29 CDT 2015


branch "master" has been updated
       via  a008cc03b7bbd9965fec17949672d4f2daad02c8 (commit)
       via  ae5fa08abd1b898c0c080927e75c7249b3982c2d (commit)
      from  62879540871bd5837359f3525499912346563a1b (commit)

Summary of changes:
 drivers/dahdi/firmware/Makefile |    8 +-
 drivers/dahdi/wcaxx-base.c      |    4 +-
 drivers/dahdi/wcb4xxp/base.c    |  699 ++++++++++++++++++++++++++++++---------
 drivers/dahdi/wcb4xxp/wcb4xxp.h |   10 +-
 drivers/dahdi/wcte13xp-base.c   |    2 +-
 drivers/dahdi/wcte43x-base.c    |    2 +-
 drivers/dahdi/wcxb.c            |   54 +--
 drivers/dahdi/wcxb.h            |    7 +-
 8 files changed, 577 insertions(+), 209 deletions(-)


- Log -----------------------------------------------------------------
commit a008cc03b7bbd9965fec17949672d4f2daad02c8
Author: Russ Meyerriecks <rmeyerriecks at digium.com>
Date:   Fri Dec 19 13:50:01 2014 -0600

    wcb4xxp: Add support for zarlink echocan
    
    Introduces support for new series b43x cards which make use of the zarlink echo
    canceller. Made as few changes to the b410 operation as possible, but the
    critical region had some cleanups, so it may be a bit more performant.
    
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wcb4xxp/base.c b/drivers/dahdi/wcb4xxp/base.c
index 5538660..daf6b30 100644
--- a/drivers/dahdi/wcb4xxp/base.c
+++ b/drivers/dahdi/wcb4xxp/base.c
@@ -128,7 +128,10 @@ struct devtype {
 	enum cards_ids card_type;	/* Card type - Digium B410P, ... */
 };
 
-static struct devtype wcb4xxp =  {"Wildcard B410P", .ports = 4, .card_type = B410P  };
+static struct devtype wcb41xp = {"Wildcard B410P", .ports = 4,
+					.card_type = B410P};
+static struct devtype wcb43xp = {"Wildcard B430P", .ports = 4,
+					.card_type = B430P};
 static struct devtype hfc2s =	 {"HFC-2S Junghanns.NET duoBRI PCI", .ports = 2, .card_type = DUOBRI };
 static struct devtype hfc4s =	 {"HFC-4S Junghanns.NET quadBRI PCI", .ports = 4, .card_type = QUADBRI };
 static struct devtype hfc8s =	 {"HFC-8S Junghanns.NET octoBRI PCI", .ports = 8, .card_type = OCTOBRI };
@@ -142,9 +145,12 @@ static struct devtype hfc4s_SW = {"Swyx 4xS0 SX2 QuadBri", .ports = 4, .card_typ
 static struct devtype hfc4s_EV = {"CCD HFC-4S Eval. Board", .ports = 4,
 					.card_type = QUADBRI_EVAL };
 
-#define CARD_HAS_EC(card) ((card)->card_type == B410P)
+#define IS_B430P(card) ((card)->card_type == B430P)
+#define IS_B410P(card) ((card)->card_type == B410P)
+#define CARD_HAS_EC(card) (IS_B410P(card) || IS_B430P(card))
 
 static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);
+static void b4xxp_update_leds(struct b4xxp *b4);
 
 static const struct dahdi_echocan_features my_ec_features = {
 	.NLP_automatic = 1,
@@ -156,11 +162,6 @@ static const struct dahdi_echocan_ops my_ec_ops = {
 	.echocan_free = echocan_free,
 };
 
-#if 0
-static const char *wcb4xxp_rcsdata = "$RCSfile: base.c,v $ $Revision$";
-static const char *build_stamp = "" __DATE__ " " __TIME__ "";
-#endif
-
 /*
  * lowlevel PCI access functions
  * These are simply wrappers for the normal PCI access functions that the kernel provides,
@@ -410,6 +411,17 @@ static unsigned char b4xxp_getreg_ra(struct b4xxp *b4, unsigned char r, unsigned
 	return val;
 }
 
+/* This gpio register set wrapper protects bit 0 on b430 devices from being
+ * cleared, as it's used for reset */
+static void hfc_gpio_set(struct b4xxp *b4, unsigned char bits)
+{
+	if (IS_B430P(b4)) {
+		b4xxp_setreg8(b4, R_GPIO_OUT1, bits | 0x01);
+		flush_pci();
+	} else {
+		b4xxp_setreg8(b4, R_GPIO_OUT1, bits);
+	}
+}
 
 /*
  * HFC-4S GPIO routines
@@ -431,13 +443,18 @@ static void hfc_gpio_init(struct b4xxp *b4)
 
 	spin_lock_irqsave(&b4->seqlock, irq_flags);
 
-	flush_pci();				/* flush any pending PCI writes */
-
+	flush_pci();
 	mb();
 
-	b4xxp_setreg8(b4, R_GPIO_EN0, 0x00);	/* GPIO0..7 input */
-	b4xxp_setreg8(b4, R_GPIO_EN1, 0xf7);	/* GPIO8..10,12..15 outputs, GPIO11 input */
-	b4xxp_setreg8(b4, R_GPIO_OUT1, 0x00);	/* disable power, CPLD reg 0 */
+	/* GPIO0..7 input */
+	b4xxp_setreg8(b4, R_GPIO_EN0, 0x00);
+
+	if (IS_B430P(b4))
+		b4xxp_setreg8(b4, R_GPIO_EN1, 0xf1);
+	else
+		b4xxp_setreg8(b4, R_GPIO_EN1, 0xf7);
+
+	hfc_gpio_set(b4, 0x00);
 
 	mb();
 
@@ -540,7 +557,7 @@ static inline void writepcibridge(struct b4xxp *b4, unsigned char address, unsig
 /* CPLD access code, more or less copied verbatim from code provided by mattf. */
 static inline void cpld_select_reg(struct b4xxp *b4, unsigned char reg)
 {
-	b4xxp_setreg8(b4, R_GPIO_OUT1, reg);
+	hfc_gpio_set(b4, reg);
 	flush_pci();
 }
 
@@ -590,6 +607,76 @@ static inline unsigned short ec_read_data(struct b4xxp *b4)
 	return addr & 0x1ff;
 }
 
+static unsigned char hfc_sram_read(struct b4xxp *b4)
+{
+	unsigned char data;
+
+	enablepcibridge(b4);
+	data = readpcibridge(b4, 1);
+	disablepcibridge(b4);
+	cpld_select_reg(b4, 0);
+
+	return data;
+}
+
+static void hfc_sram_write(struct b4xxp *b4, char data)
+{
+	enablepcibridge(b4);
+	writepcibridge(b4, 1, data);
+	cpld_select_reg(b4, 0);
+	disablepcibridge(b4);
+}
+
+static void set_dsp_address(struct b4xxp *b4, unsigned short addr, bool dir)
+{
+	hfc_gpio_set(b4, 0x30);
+	hfc_sram_write(b4, 0xff & addr);
+	hfc_gpio_set(b4, 0x40);
+	/* dir = 1 write */
+	if (dir)
+		hfc_sram_write(b4, 0x03 & (addr >> 8));
+	else
+		hfc_sram_write(b4, 0x80 | (0x03 & (addr >> 8)));
+}
+
+/* Read from zarlink echocan without locks */
+static unsigned char __zl_read(struct b4xxp *b4, unsigned short addr)
+{
+	unsigned char data;
+
+	set_dsp_address(b4, addr, 0);
+	hfc_gpio_set(b4, ((addr & 0x0400) >> 3) | 0x50);
+	data = hfc_sram_read(b4);
+	hfc_gpio_set(b4, 0x00);
+
+	return data;
+}
+
+/* Write to zarlink echocan unlocked */
+static void __zl_write(struct b4xxp *b4, unsigned short addr,
+			unsigned char data)
+{
+	unsigned char val;
+
+	hfc_gpio_set(b4, 0x00);
+	set_dsp_address(b4, addr, 1);
+	hfc_sram_write(b4, data);
+	val = ((addr & 0x0400) >> 3);
+	val = (val | 0x50);
+	hfc_gpio_set(b4, val);
+	hfc_gpio_set(b4, 0x00);
+}
+
+/* Write to zarlink echocan locked */
+static void zl_write(struct b4xxp *b4, unsigned short addr, unsigned char data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&b4->seqlock, flags);
+	__zl_write(b4, addr, data);
+	spin_unlock_irqrestore(&b4->seqlock, flags);
+}
+
 static inline unsigned char ec_read(struct b4xxp *b4, int which, unsigned short addr)
 {
 	unsigned char data;
@@ -648,19 +735,95 @@ static inline void ec_write(struct b4xxp *b4, int which, unsigned short addr, un
 #define NUM_EC 2
 #define MAX_TDM_CHAN 32
 
-#if 0
-void ec_set_dtmf_threshold(struct b4xxp *b4, int threshold)
+static void zl_init(struct b4xxp *b4)
 {
-        unsigned int x;
+	int i, offset;
+	int group_addr[4] = {0x00, 0x40, 0x80, 0xc0};
 
-        for (x = 0; x < NUM_EC; x++) {
-                ec_write(b4, x, 0xC4, (threshold >> 8) & 0xFF);
-                ec_write(b4, x, 0xC5, (threshold & 0xFF));
-        }
-        printk("VPM: DTMF threshold set to %d\n", threshold);
-}
-#endif
+	dev_info(&b4->pdev->dev, "Initializing Zarlink echocan\n");
+
+	/* There are 4 "groups" of echocans with two channels in each */
+	/* Main group control reg 0-3 */
+
+	/* Hardware Reset Sequence */
+	b4xxp_setreg8(b4, R_GPIO_OUT1, 0x00);
+	udelay(100);
+	b4xxp_setreg8(b4, R_GPIO_OUT1, 0x01);
+	udelay(500);
 
+	/* Software reset sequence */
+	zl_write(b4, 0x400, 0x41);
+	zl_write(b4, 0x401, 0x01);
+	zl_write(b4, 0x402, 0x01);
+	zl_write(b4, 0x403, 0x01);
+	udelay(250);
+	zl_write(b4, 0x400, 0x40);
+	zl_write(b4, 0x401, 0x00);
+	zl_write(b4, 0x402, 0x00);
+	zl_write(b4, 0x403, 0x00);
+	udelay(500);
+
+	/* Power up & Configure echo can gruops */
+	if (!strcasecmp(companding, "alaw")) {
+		zl_write(b4, 0x400, 0x47);
+		zl_write(b4, 0x401, 0x07);
+		zl_write(b4, 0x402, 0x07);
+		zl_write(b4, 0x403, 0x07);
+	} else {
+		zl_write(b4, 0x400, 0x45);
+		zl_write(b4, 0x401, 0x05);
+		zl_write(b4, 0x402, 0x05);
+		zl_write(b4, 0x403, 0x05);
+	}
+	udelay(250);
+
+	for (i = 0; i <= 3; i++) {
+		int group = group_addr[i];
+		/* Control reg 1, bank A & B, channel bypass mode */
+		zl_write(b4, group + 0x00, 0x08);
+		/* Control reg 1 on bank B must be written twicer as */
+		/* per the datasheet */
+		zl_write(b4, group + 0x20, 0x0a);
+		zl_write(b4, group + 0x20, 0x0a);
+
+		/* Two channels of the echocan must be set separately,
+		   one at offset 0x00 and one at offset 0x20 */
+		for (offset = group; offset <= (group + 0x20); offset += 0x20) {
+			/* Control reg 2 */
+			zl_write(b4, offset + 0x01, 0x00);
+			/* Flat Delay */
+			zl_write(b4, offset + 0x04, 0x00);
+			/* Decay Step Size Reg */
+			zl_write(b4, offset + 0x06, 0x04);
+			/* Decay Step Number */
+			zl_write(b4, offset + 0x07, 0x00);
+			/* Control reg 3 */
+			zl_write(b4, offset + 0x08, 0xfb);
+			/* Control reg 4 */
+			zl_write(b4, offset + 0x09, 0x54);
+			/* Noise Scaling */
+			zl_write(b4, offset + 0x0a, 0x16);
+			/* Noise Control */
+			zl_write(b4, offset + 0x0b, 0x45);
+			/* DTDT Reg 1*/
+			zl_write(b4, offset + 0x14, 0x00);
+			/* DTDT Reg 2*/
+			zl_write(b4, offset + 0x15, 0x48);
+			/* NLPTHR reg 1*/
+			zl_write(b4, offset + 0x18, 0xe0);
+			/* NLPTHR reg 2*/
+			zl_write(b4, offset + 0x19, 0x0c);
+			/* Step Size, MU reg 1*/
+			zl_write(b4, offset + 0x1a, 0x00);
+			/* Step Size, MU reg 2*/
+			zl_write(b4, offset + 0x1b, 0x40);
+			/* Gains reg 1*/
+			zl_write(b4, offset + 0x1c, 0x44);
+			/* Gains reg 2*/
+			zl_write(b4, offset + 0x1d, 0x44);
+		}
+	}
+}
 
 static void ec_init(struct b4xxp *b4)
 {
@@ -670,6 +833,12 @@ static void ec_init(struct b4xxp *b4)
 	if (!CARD_HAS_EC(b4))
 		return;
 
+	/* Short circuit to the new zarlink echocan logic */
+	if (IS_B430P(b4)) {
+		zl_init(b4);
+		return;
+	}
+
 /* Setup GPIO */
 	for (i=0; i < NUM_EC; i++) {
 		b = ec_read(b4, i, 0x1a0);
@@ -716,12 +885,6 @@ static void ec_init(struct b4xxp *b4)
 		if (DBG)
 			dev_info(&b4->pdev->dev, "reg 0x20 is 0x%02x\n", b);
 
-//		ec_write(b4, i, 0x20, 0x38);
-
-#if 0
-		ec_write(b4, i, 0x24, 0x02);
-		b = ec_read(b4, i, 0x24);
-#endif
 		if (DBG) {
 			dev_info(&b4->pdev->dev,
 				 "NLP threshold is set to %d (0x%02x)\n", b, b);
@@ -748,43 +911,29 @@ static void ec_init(struct b4xxp *b4)
 				ec_write(b4, i, 0x78 + j, 0x01);
 		}
 	}
-
-#if 0
-	ec_set_dtmf_threshold(b4, 1250);
-#endif
 }
 
 /* performs a register write and then waits for the HFC "busy" bit to clear */
 static void hfc_setreg_waitbusy(struct b4xxp *b4, const unsigned int reg, const unsigned int val)
 {
-	int timeout = 0;
-	unsigned long start;
-	const int TIMEOUT = HZ/4; /* 250ms */
-
-	start = jiffies;
-	while (unlikely((b4xxp_getreg8(b4, R_STATUS) & V_BUSY))) {
-		if (time_after(jiffies, start + TIMEOUT)) {
-			timeout = 1;
-			break;
-		}
-	};
+	/* V_BUSY is not supposed to take longer than 1us */
+	/* Since this func can be called with interrupts locked
+	 * we should just a regular loop, as jiffies may not update
+	 */
+	int TIMEOUT = 0.002 * 3000000;
+	int x = 0;
 
-	mb();
 	b4xxp_setreg8(b4, reg, val);
-	mb();
 
-	start = jiffies;
-	while (likely((b4xxp_getreg8(b4, R_STATUS) & V_BUSY))) {
-		if (time_after(jiffies, start + TIMEOUT)) {
-			timeout = 1;
-			break;
+	while (b4xxp_getreg8(b4, R_STATUS) & V_BUSY) {
+		if (x++ > TIMEOUT) {
+			if (printk_ratelimit()) {
+				dev_info(&b4->pdev->dev,
+					 "hfc_setreg_waitbusy(write 0x%02x to 0x%02x) timed out waiting for busy flag to clear!\n",
+				val, reg);
+			}
+			return;
 		}
-	};
-
-	if (timeout && printk_ratelimit()) {
-		dev_warn(&b4->pdev->dev,
-			 "hfc_setreg_waitbusy(write 0x%02x to 0x%02x) timed "
-			 "out waiting for busy flag to clear!\n", val, reg);
 	}
 }
 
@@ -880,7 +1029,11 @@ static void hfc_reset(struct b4xxp *b4)
 	b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1);
 	flush_pci();
 
-	b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048);
+	if (IS_B430P(b4))
+		b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_4096);
+	else
+		b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048);
+
 	flush_pci();
 
 /* now wait for R_F0_CNTL to reach at least 2 before continuing */
@@ -1019,6 +1172,102 @@ static void hfc_assign_bchan_fifo_ec(struct b4xxp *b4, int port, int bchan)
 	spin_unlock_irqrestore(&b4->fifolock, irq_flags);
 }
 
+static void hfc_assign_fifo_zl(struct b4xxp *b4, int port, int bchan)
+{
+	int fifo, hfc_chan, ts;
+	unsigned long irq_flags;
+	static int first = 1;
+
+	if (first) {
+		first = 0;
+		dev_info(&b4->pdev->dev, "Zarlink echo cancellation enabled.\n");
+	}
+
+	fifo = port * 2;
+	hfc_chan = port * 4;
+	ts = port * 8;
+
+	if (bchan) {
+		fifo += 1;
+		hfc_chan += 1;
+		ts += 4;
+	}
+
+	/* record the host's FIFO # in the span fifo array */
+	b4->spans[3-port].fifos[bchan] = fifo;
+	spin_lock_irqsave(&b4->fifolock, irq_flags);
+
+	if (DBG) {
+		dev_info(&b4->pdev->dev,
+			 "port %d, B channel %d\n\tS/T -> PCM ts %d uses HFC chan %d via FIFO %d\n",
+			 port, bchan, ts + 1, hfc_chan, 16 + fifo);
+	}
+
+	/* S/T RX -> PCM TX FIFO, transparent mode, no IRQ. */
+	hfc_setreg_waitbusy(b4, R_FIFO, ((16 + fifo) << V_FIFO_NUM_SHIFT));
+	b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_110);
+	b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT));
+	b4xxp_setreg8(b4, R_SLOT, (((fifo * 2)+1) << V_SL_NUM_SHIFT));
+	b4xxp_setreg8(b4,
+		A_SL_CFG, V_ROUT_TX_STIO1 | (hfc_chan << V_CH_SNUM_SHIFT));
+	hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO);
+
+	if (DBG) {
+		pr_info("\tPCM ts %d -> host uses HFC chan %d via FIFO %d\n",
+			ts + 1, 16 + hfc_chan, fifo);
+	}
+
+	/* PCM RX -> Host TX FIFO, transparent mode, enable IRQ. */
+	hfc_setreg_waitbusy(b4, R_FIFO,
+			(fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR);
+	b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_001);
+	b4xxp_setreg8(b4, A_CHANNEL,
+			((16 + hfc_chan) << V_CH_FNUM_SHIFT) | V_CH_FDIR);
+	b4xxp_setreg8(b4, R_SLOT,
+			(((fifo * 2) + 4) << V_SL_NUM_SHIFT) | V_SL_DIR);
+	b4xxp_setreg8(b4, A_SL_CFG,
+		V_ROUT_RX_STIO2 | ((16 + hfc_chan) << V_CH_SNUM_SHIFT) |
+		V_CH_SDIR);
+	hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO);
+
+	if (DBG) {
+		pr_info("\thost -> PCM ts %d uses HFC chan %d via FIFO %d\n",
+			ts, 16 + hfc_chan, fifo);
+	}
+
+	/* Host FIFO -> PCM TX */
+	hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT));
+	b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_001);
+	b4xxp_setreg8(b4, A_CHANNEL, ((16 + hfc_chan) << V_CH_FNUM_SHIFT));
+	b4xxp_setreg8(b4, R_SLOT, ((fifo * 2) << V_SL_NUM_SHIFT));
+	b4xxp_setreg8(b4, A_SL_CFG,
+		V_ROUT_TX_STIO1 | ((16 + hfc_chan) << V_CH_SNUM_SHIFT));
+	hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO);
+
+	if (DBG) {
+		pr_info("\tPCM ts %d -> S/T uses HFC chan %d via FIFO %d\n",
+			ts, hfc_chan, 16 + fifo);
+	}
+
+	/* PCM -> S/T */
+	hfc_setreg_waitbusy(b4, R_FIFO,
+			((16 + fifo) << V_FIFO_NUM_SHIFT) | V_FIFO_DIR);
+	b4xxp_setreg8(b4, A_CON_HDLC, V_IFF | V_HDLC_TRP | V_DATA_FLOW_110);
+	b4xxp_setreg8(b4, A_CHANNEL, (hfc_chan << V_CH_FNUM_SHIFT) | V_CH_FDIR);
+	b4xxp_setreg8(b4, R_SLOT, (((fifo*2)+3)  << V_SL_NUM_SHIFT) | V_SL_DIR);
+	b4xxp_setreg8(b4, A_SL_CFG,
+		V_ROUT_RX_STIO2 | (hfc_chan << V_CH_SNUM_SHIFT) | V_CH_SDIR);
+	hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_RES_FIFO);
+
+	if (DBG) {
+		pr_info("\tPCM ts %d -> S/T uses HFC chan %d via FIFO %d\n",
+			ts, hfc_chan, 16 + fifo);
+	}
+
+	flush_pci();
+	spin_unlock_irqrestore(&b4->fifolock, irq_flags);
+}
+
 static void hfc_assign_bchan_fifo_noec(struct b4xxp *b4, int port, int bchan)
 {
 	int fifo, hfc_chan, ts;
@@ -1096,7 +1345,10 @@ static void hfc_assign_dchan_fifo(struct b4xxp *b4, int port)
 	hfc_chan = (port * 4) + 2;
 
 /* record the host's FIFO # in the span fifo array */
-	b4->spans[port].fifos[2] = fifo;
+	if (IS_B430P(b4))
+		b4->spans[3-port].fifos[2] = fifo;
+	else
+		b4->spans[port].fifos[2] = fifo;
 
 	if (DBG) {
 		dev_info(&b4->pdev->dev,
@@ -1157,10 +1409,6 @@ static void b4xxp_set_sync_src(struct b4xxp *b4, int port)
 {
 	int b;
 
-#if 0
-	printk("Setting sync to be port %d\n", (port >= 0) ? port + 1 : port);
-#endif
-
 	if (port == -1) 		/* automatic */
 		b = 0;
 	else
@@ -1329,10 +1577,10 @@ static void hfc_timer_expire(struct b4xxp_span *s, int t_no)
 
 	switch(t_no) {
 	case HFC_T1:					/* switch to G4 (pending deact.), resume auto mode */
-		hfc_force_st_state(b4, s->port, 4, 1);
+		hfc_force_st_state(b4, s->phy_port, 4, 1);
 		break;
 	case HFC_T2:					/* switch to G1 (deactivated), resume auto mode */
-		hfc_force_st_state(b4, s->port, 1, 1);
+		hfc_force_st_state(b4, s->phy_port, 1, 1);
 		break;
 	case HFC_T3:					/* switch to F3 (deactivated), resume auto mode */
 		hfc_stop_st(s);
@@ -1403,16 +1651,17 @@ static void hfc_handle_state(struct b4xxp_span *s)
 	b4 = s->parent;
 	nt = !s->te_mode;
 
-	state = b4xxp_getreg_ra(b4, R_ST_SEL, s->port, A_ST_RD_STA);
+	state = b4xxp_getreg_ra(b4, R_ST_SEL, s->phy_port, A_ST_RD_STA);
+
 	sta = (state & V_ST_STA_MASK);
 
 	if (DBG_ST) {
 		char *x;
 
-		x = hfc_decode_st_state(b4, s->port, state, 1);
+		x = hfc_decode_st_state(b4, s->phy_port, state, 1);
 		dev_info(&b4->pdev->dev,
-			 "port %d A_ST_RD_STA old=0x%02x now=0x%02x, "
-			 "decoded: %s\n", s->port + 1, s->oldstate, state, x);
+			 "port %d phy_port %d A_ST_RD_STA old=0x%02x now=0x%02x, decoded: %s\n",
+			s->port + 1, s->phy_port, s->oldstate, state, x);
 		kfree(x);
 	}
 
@@ -1512,7 +1761,7 @@ static void hfc_stop_st(struct b4xxp_span *s)
 
 	hfc_stop_all_timers(s);
 
-	b4xxp_setreg_ra(b4, R_ST_SEL, s->port, A_ST_WR_STA,
+	b4xxp_setreg_ra(b4, R_ST_SEL, s->phy_port, A_ST_WR_STA,
 			V_ST_ACT_DEACTIVATE);
 }
 
@@ -1529,7 +1778,7 @@ static void hfc_reset_st(struct b4xxp_span *s)
 	hfc_stop_st(s);
 
 /* force state G0/F0 (reset), then force state 1/2 (deactivated/sensing) */
-	b4xxp_setreg_ra(b4, R_ST_SEL, s->port, A_ST_WR_STA, V_ST_LD_STA);
+	b4xxp_setreg_ra(b4, R_ST_SEL, s->phy_port, A_ST_WR_STA, V_ST_LD_STA);
 	flush_pci();			/* make sure write hit hardware */
 
 	s->span.alarms = DAHDI_ALARM_RED;
@@ -1547,6 +1796,7 @@ static void hfc_reset_st(struct b4xxp_span *s)
 	b4xxp_setreg8(b4, A_ST_CLK_DLY, b);
 
 /* set TE/NT mode, enable B and D channels. */
+
 	b4xxp_setreg8(b4, A_ST_CTRL0, V_B1_EN | V_B2_EN | (s->te_mode ? 0 : V_ST_MD));
 	b4xxp_setreg8(b4, A_ST_CTRL1, V_G2_G3_EN | V_E_IGNO);
 	b4xxp_setreg8(b4, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN);
@@ -1562,7 +1812,8 @@ static void hfc_start_st(struct b4xxp_span *s)
 {
 	struct b4xxp *b4 = s->parent;
 
-	b4xxp_setreg_ra(b4, R_ST_SEL, s->port, A_ST_WR_STA, V_ST_ACT_ACTIVATE);
+	b4xxp_setreg_ra(b4, R_ST_SEL, s->phy_port, A_ST_WR_STA,
+				V_ST_ACT_ACTIVATE);
 
 /* start T1 if in NT mode, T3 if in TE mode */
 	if (s->te_mode) {
@@ -1597,25 +1848,52 @@ static void hfc_start_st(struct b4xxp_span *s)
  */
 static void hfc_init_all_st(struct b4xxp *b4)
 {
-	int i, gpio, nt;
+	int gpio = 0;
+	int i, nt;
 	struct b4xxp_span *s;
 
-	gpio = b4xxp_getreg8(b4, R_GPI_IN3);
+	/* All other cards supported by this driver read jumpers for modes */
+	if (!IS_B430P(b4))
+		gpio = b4xxp_getreg8(b4, R_GPI_IN3);
 
 	for (i=0; i < b4->numspans; i++) {
 		s = &b4->spans[i];
 		s->parent = b4;
-		s->port = i;
+
+		if (IS_B430P(b4)) {
+			/* The physical ports are reversed on the b430 */
+			/* Port 0-3 in b4->spans[] are physically ports 3-0 */
+			s->phy_port = b4->numspans-1-i;
+			s->port = i;
+		} else {
+			s->phy_port = i;
+			s->port = i;
+		}
 
 		/* The way the Digium B410P card reads the NT/TE mode
 		 * jumper is the oposite of how other HFC-4S cards do:
 		 * - In B410P: GPIO=0: NT
 		 * - In Junghanns: GPIO=0: TE
 		 */
-		if (b4->card_type == B410P)
+		if (IS_B410P(b4)) {
 			nt = ((gpio & (1 << (i + 4))) == 0);
-		else
+		} else if (IS_B430P(b4)) {
+			/* Read default digital lineconfig reg on B430 */
+			int reg;
+			unsigned long flags;
+
+			spin_lock_irqsave(&b4->seqlock, flags);
+			hfc_gpio_set(b4, 0x20);
+			reg = hfc_sram_read(b4);
+			spin_unlock_irqrestore(&b4->seqlock, flags);
+
+			if (reg & (1 << (4 + s->phy_port)))
+				nt = 1;
+			else
+				nt = 0;
+		} else {
 			nt = ((gpio & (1 << (i + 4))) != 0);
+		}
 
 		s->te_mode = !nt;
 
@@ -1694,10 +1972,6 @@ static int hfc_poll_fifos(struct b4xxp *b4)
 			continue;
 
 /* TODO: Make sure S/T port is in active state */
-#if 0
-		if (span_not_active(s))
-			continue;
-#endif
 		ret = hfc_poll_one_bchan_fifo(&b4->spans[span], 0);
 		ret |= hfc_poll_one_bchan_fifo(&b4->spans[span], 1);
 	}
@@ -1990,11 +2264,15 @@ static void b4xxp_init_stage1(struct b4xxp *b4)
 	 * incoming clock.
 	 */
 
-	if ((b4->card_type == B410P) || (b4->card_type == QUADBRI_EVAL))
+	if (IS_B410P(b4) || IS_B430P(b4) || (b4->card_type == QUADBRI_EVAL))
 		b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02);
 	else
 		b4xxp_setreg8(b4, R_BRG_PCM_CFG, V_PCM_CLK);
 
+	/* Reset LED state */
+	b4->ledreg = 0;
+	b4xxp_update_leds(b4);
+
 	flush_pci();
 
 	udelay(100);				/* wait a bit for clock to settle */
@@ -2021,10 +2299,16 @@ static void b4xxp_init_stage2(struct b4xxp *b4)
  */
 	b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1);
 	flush_pci();
-	b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048);
 
-	b4xxp_setreg8(b4, R_PWM_MD, 0xa0);
-	b4xxp_setreg8(b4, R_PWM0, 0x1b);
+	if (IS_B430P(b4)) {
+		b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_4096);
+		b4xxp_setreg8(b4, R_PWM_MD, 0x50);
+		b4xxp_setreg8(b4, R_PWM0, 0x38);
+	} else {
+		b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048);
+		b4xxp_setreg8(b4, R_PWM_MD, 0xa0);
+		b4xxp_setreg8(b4, R_PWM0, 0x1b);
+	}
 
 /*
  * set up the flow controller.
@@ -2071,14 +2355,20 @@ static void b4xxp_init_stage2(struct b4xxp *b4)
  * D channel FIFOs are operated in HDLC mode and interrupt on end of frame.
  */
 	for (span=0; span < b4->numspans; span++) {
-		if ((vpmsupport) && (CARD_HAS_EC(b4))) {
-			hfc_assign_bchan_fifo_ec(b4, span, 0);
-			hfc_assign_bchan_fifo_ec(b4, span, 1);
+		if (IS_B430P(b4)) {
+			hfc_assign_fifo_zl(b4, span, 0);
+			hfc_assign_fifo_zl(b4, span, 1);
+			hfc_assign_dchan_fifo(b4, span);
 		} else {
-			hfc_assign_bchan_fifo_noec(b4, span, 0);
-			hfc_assign_bchan_fifo_noec(b4, span, 1);
+			if ((vpmsupport) && (CARD_HAS_EC(b4))) {
+				hfc_assign_bchan_fifo_ec(b4, span, 0);
+				hfc_assign_bchan_fifo_ec(b4, span, 1);
+			} else {
+				hfc_assign_bchan_fifo_noec(b4, span, 0);
+				hfc_assign_bchan_fifo_noec(b4, span, 1);
+			}
+			hfc_assign_dchan_fifo(b4, span);
 		}
-		hfc_assign_dchan_fifo(b4, span);
 	}
 
 /* set up the timer interrupt for 1ms intervals */
@@ -2163,7 +2453,7 @@ static void b4xxp_update_leds_hfc(struct b4xxp *b4)
 	   For green: in both R_GPIO_EN1 and R_GPIO_OUT1. */
 	leds |= green_leds;
 	b4xxp_setreg8(b4, R_GPIO_EN1, leds);
-	b4xxp_setreg8(b4, R_GPIO_OUT1, green_leds);
+	hfc_gpio_set(b4, green_leds);
 
 	if (b4->blinktimer == 0xff)
 		b4->blinktimer = -1;
@@ -2171,14 +2461,27 @@ static void b4xxp_update_leds_hfc(struct b4xxp *b4)
 
 static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val)
 {
-	int shift, spanmask;
+	if (IS_B430P(b4)) {
+		unsigned long flags;
 
-	shift = span << 1;
-	spanmask = ~(0x03 << shift);
+		b4->ledreg &= ~(0x03 << span*2);
+		b4->ledreg |= (val << span*2);
 
-	b4->ledreg &= spanmask;
-	b4->ledreg |= (val << shift);
-	b4xxp_setleds(b4, b4->ledreg);
+		spin_lock_irqsave(&b4->seqlock, flags);
+		/* Set multiplexer for led R/W */
+		hfc_gpio_set(b4, 0x10);
+		hfc_sram_write(b4, b4->ledreg);
+		spin_unlock_irqrestore(&b4->seqlock, flags);
+	} else {
+		int shift, spanmask;
+
+		shift = span << 1;
+		spanmask = ~(0x03 << shift);
+
+		b4->ledreg &= spanmask;
+		b4->ledreg |= (val << shift);
+		b4xxp_setleds(b4, b4->ledreg);
+	}
 }
 
 static void b4xxp_update_leds(struct b4xxp *b4)
@@ -2192,7 +2495,7 @@ static void b4xxp_update_leds(struct b4xxp *b4)
 		return;
 	}
 
-	if (b4->card_type != B410P) {
+	if (!IS_B410P(b4) && !IS_B430P(b4)) {
 		/* Use the alternative function for non-Digium HFC-4S cards */
 		b4xxp_update_leds_hfc(b4);
 		return;
@@ -2233,8 +2536,15 @@ static const char *b4xxp_echocan_name(const struct dahdi_chan *chan)
 {
 	struct b4xxp_span *bspan = container_of(chan->span, struct b4xxp_span,
 						span);
-	if (vpmsupport && (B410P == bspan->parent->card_type))
+	if (!vpmsupport)
+		return NULL;
+
+	if (IS_B410P(bspan->parent))
 		return "LASVEGAS2";
+
+	if (IS_B430P(bspan->parent))
+		return "ZARLINK";
+
 	return NULL;
 }
 
@@ -2268,7 +2578,22 @@ static int b4xxp_echocan_create(struct dahdi_chan *chan,
 
 	channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1;
 	
-	ec_write(bspan->parent, chan->chanpos - 1, channel, 0x7e);
+	if (IS_B430P(bspan->parent)) {
+		/* Zarlink has 4 groups of 2 channel echo cancelers */
+		/* Each channel has it's own individual control reg */
+		int group = (3 - chan->span->offset) * 0x40;
+		int chan_offset = (chan->chanpos % 2) ? 0x00 : 0x20;
+		int reg;
+		unsigned long flags;
+
+		spin_lock_irqsave(&bspan->parent->seqlock, flags);
+		reg = __zl_read(bspan->parent, group + chan_offset);
+		reg &= ~(1 << 3);
+		__zl_write(bspan->parent, group + chan_offset, reg);
+		spin_unlock_irqrestore(&bspan->parent->seqlock, flags);
+	} else {
+		ec_write(bspan->parent, chan->chanpos - 1, channel, 0x7e);
+	}
 
 	return 0;
 }
@@ -2285,7 +2610,22 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec
 
 	channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1;
 
-	ec_write(bspan->parent, chan->chanpos - 1, channel, 0x01);
+	if (IS_B430P(bspan->parent)) {
+		/* Zarlink has 4 groups of 2 channel echo cancelers */
+		/* Each channel has it's own individual control reg */
+		int group = (3 - chan->span->offset) * 0x40;
+		int chan_offset = (chan->chanpos % 2) ? 0x00 : 0x20;
+		int reg;
+		unsigned long flags;
+
+		spin_lock_irqsave(&bspan->parent->seqlock, flags);
+		reg = __zl_read(bspan->parent, group + chan_offset);
+		reg |= (1 << 3);
+		__zl_write(bspan->parent, group + chan_offset, reg);
+		spin_unlock_irqrestore(&bspan->parent->seqlock, flags);
+	} else {
+		ec_write(bspan->parent, chan->chanpos - 1, channel, 0x01);
+	}
 }
 
 /*
@@ -2344,14 +2684,6 @@ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span,
 	if (DBG)
 		dev_info(&b4->pdev->dev, "Configuring span %d offset %d to be sync %d\n", span->spanno, span->offset, lc->sync);
 
-#if 0
-	if (lc->sync > 0 && !bspan->te_mode) {
-		dev_info(&b4->pdev->dev, "Span %d is not in NT mode, removing "
-			 "from sync source list\n", span->spanno);
-		lc->sync = 0;
-	}
-#endif
-
 	if (lc->sync < 0 || lc->sync > 4) {
 		dev_info(&b4->pdev->dev,
 			 "Span %d has invalid sync priority (%d), removing "
@@ -2369,6 +2701,54 @@ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span,
 	if (lc->sync)
 		b4->spans[lc->sync - 1].sync = (span->offset + 1);
 
+	/* B430 sets TE/NT and Termination resistance modes via dahdi_cfg */
+	if (IS_B430P(b4)) {
+		int te_mode, term, reg;
+		unsigned long flags;
+
+		te_mode = (lc->lineconfig & DAHDI_CONFIG_NTTE) ? 0 : 1;
+		term = (lc->lineconfig & DAHDI_CONFIG_TERM) ? 1 : 0;
+		dev_info(&b4->pdev->dev,
+			"Configuring span %d in %s mode with termination resistance %s\n",
+			bspan->port+1, (te_mode) ? "TE" : "NT",
+			(term) ? "ENABLED" : "DISABLED");
+
+		if (!te_mode && lc->sync) {
+			dev_info(&b4->pdev->dev,
+				"NT Spans cannot be timing sources. Changing priority to 0\n");
+			lc->sync = 0;
+		}
+
+		/* Setup NT/TE */
+		/* Bits 7 downto 5 correspond to spans 4-1 */
+		/* 1 sets NT mode, 0 sets TE mode */
+		spin_lock_irqsave(&b4->seqlock, flags);
+		hfc_gpio_set(b4, 0x20);
+		reg = hfc_sram_read(b4);
+
+		if (te_mode)
+			reg &= ~(1 << (4 + bspan->port));
+		else
+			reg |= (1 << (4 + bspan->port));
+
+		/* Setup Termination resistance */
+		/* Bits 4 downto 0 correspond to spans 4-1 */
+		/* 1 sets resistance mode, 0 sets no resistance */
+		if (term)
+			reg |= (1 << (bspan->port));
+		else
+			reg &= ~(1 << (bspan->port));
+
+		hfc_gpio_set(b4, 0x20);
+		hfc_sram_write(b4, reg);
+		spin_unlock_irqrestore(&b4->seqlock, flags);
+
+		bspan->te_mode = te_mode;
+		bspan->span.spantype = (bspan->te_mode)
+			? SPANTYPE_DIGITAL_BRI_TE
+			: SPANTYPE_DIGITAL_BRI_NT;
+	}
+
 	hfc_reset_st(bspan);
 	if (persistentlayer1)
 		hfc_start_st(bspan);
@@ -2532,7 +2912,8 @@ static void init_spans(struct b4xxp *b4)
 		bspan->span.linecompat = DAHDI_CONFIG_AMI | 
 			DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | 
 			DAHDI_CONFIG_ESF | DAHDI_CONFIG_HDB3 |
-			DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4;
+			DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4 |
+			DAHDI_CONFIG_NTTE | DAHDI_CONFIG_TERM;
 
 		sprintf(bspan->span.name, "B4/%d/%d", b4->cardno, i+1);
 		sprintf(bspan->span.desc, "B4XXP (PCI) Card %d Span %d", b4->cardno, i+1);
@@ -2673,7 +3054,10 @@ static void b4xxp_bottom_half(unsigned long data)
  * Yuck.  It works well, but yuck.
  */
 					do {
-						k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]);
+						if (IS_B430P(b4))
+							k = hdlc_tx_frame(&b4->spans[3-(fifo - fifo_low)]);
+						else
+							k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]);
 					}  while (k);
 				} else {
 					if (printk_ratelimit())
@@ -2690,7 +3074,10 @@ static void b4xxp_bottom_half(unsigned long data)
  * i.e. I get an int when F1 changes, not when F1 != F2.
  */
 					do {
-						k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]);
+						if (IS_B430P(b4))
+							k = hdlc_rx_frame(&b4->spans[3-(fifo - fifo_low)]);
+						else 
+							k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]);
 					} while (k);
 				} else {
 					if (printk_ratelimit())
@@ -2722,13 +3109,18 @@ static void b4xxp_bottom_half(unsigned long data)
 
 		b4xxp_update_leds(b4);
 
-/* every 100ms or so, look at the S/T interfaces to see if they changed state */
+		/* Poll interface state at 100ms interval */
 		if (!(b4->ticks % 100)) {
 			b = b4xxp_getreg8(b4, R_SCI);
 			if (b) {
 				for (i=0; i < b4->numspans; i++) {
-					if (b & (1 << i))
-						hfc_handle_state(&b4->spans[i]);
+					if (b & (1 << i)) {
+						/* physical spans are reversed for b430 */
+						if (IS_B430P(b4))
+							hfc_handle_state(&b4->spans[b4->numspans-1-i]);
+						else
+							hfc_handle_state(&b4->spans[i]);
+					}
 				}
 			}
 		}
@@ -2919,7 +3311,6 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id
 		use_flag_somehow();
 */
 
-/* TODO: determine whether this is a 2, 4 or 8 port card */
 	b4->numspans = dt->ports;
 	b4->syncspan = -1;		/* sync span is unknown */
 	if (b4->numspans > MAX_SPANS_PER_CARD) {
@@ -2949,6 +3340,18 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id
 
 	b4xxp_init_stage1(b4);
 
+	if (IS_B430P(b4)) {
+		int version;
+		unsigned long flags;
+
+		spin_lock_irqsave(&b4->seqlock, flags);
+		hfc_gpio_set(b4, 0x60);
+		version = hfc_sram_read(b4);
+		spin_unlock_irqrestore(&b4->seqlock, flags);
+
+		dev_info(&b4->pdev->dev, "CPLD ver: %x\n", version);
+	}
+
 	create_sysfs_files(b4);
 
 	if (request_irq(pdev->irq, b4xxp_interrupt, DAHDI_IRQ_SHARED_DISABLED, "b4xxp", b4)) {
@@ -2990,29 +3393,7 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id
 		goto err_out_unreg_spans;
 	}
 
-
-
-#if 0
-	/* Launch cards as appropriate */
-	for (;;) {
-		/* Find a card to activate */
-		f = 0;
-		for (x=0; cards[x]; x++) {
-			if (cards[x]->order <= highestorder) {
-				b4_launch(cards[x]);
-				if (cards[x]->order == highestorder)
-					f = 1;
-			}
-		}
-		/* If we found at least one, increment the highest order and search again, otherwise stop */
-		if (f)
-			highestorder++;
-		else
-			break;
-	}
-#else
 	dev_info(&b4->pdev->dev, "Did not do the highestorder stuff\n");
-#endif
 
 	ret = b4xxp_startdefaultspan(b4);
 	if (ret)
@@ -3090,25 +3471,27 @@ static void __devexit b4xxp_remove(struct pci_dev *pdev)
 
 static DEFINE_PCI_DEVICE_TABLE(b4xx_ids) =
 {
-	{ 0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb4xxp },
-	{ 0x1397, 0x16b8, 0x1397, 0xb552, 0, 0, (unsigned long)&hfc8s },
-	{ 0x1397, 0x16b8, 0x1397, 0xb55b, 0, 0, (unsigned long)&hfc8s },
-	{ 0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s },
-	{ 0x1397, 0x08b4, 0x1397, 0xb550, 0, 0, (unsigned long)&hfc4s },
-	{ 0x1397, 0x08b4, 0x1397, 0xb752, 0, 0, (unsigned long)&hfc4s },
-	{ 0x1397, 0x08b4, 0x1397, 0xb556, 0, 0, (unsigned long)&hfc2s },
-	{ 0x1397, 0x08b4, 0x1397, 0xe884, 0, 0, (unsigned long)&hfc2s_OV },
-	{ 0x1397, 0x08b4, 0x1397, 0xe888, 0, 0, (unsigned long)&hfc4s_OV },
-	{ 0x1397, 0x16b8, 0x1397, 0xe998, 0, 0, (unsigned long)&hfc8s_OV },
-	{ 0x1397, 0x08b4, 0x1397, 0xb566, 0, 0, (unsigned long)&hfc2s_BN },
-	{ 0x1397, 0x08b4, 0x1397, 0xb761, 0, 0, (unsigned long)&hfc2s_BN },
-	{ 0x1397, 0x08b4, 0x1397, 0xb560, 0, 0, (unsigned long)&hfc4s_BN },
-	{ 0x1397, 0x08b4, 0x1397, 0xb550, 0, 0, (unsigned long)&hfc4s_BN },
-	{ 0x1397, 0x08b4, 0x1397, 0xb762, 0, 0, (unsigned long)&hfc4s_BN },
-	{ 0x1397, 0x16b8, 0x1397, 0xb562, 0, 0, (unsigned long)&hfc8s_BN },
-	{ 0x1397, 0x16b8, 0x1397, 0xb56b, 0, 0, (unsigned long)&hfc8s_BN },
-	{ 0x1397, 0x08b4, 0x1397, 0xb540, 0, 0, (unsigned long)&hfc4s_SW },
-	{ 0x1397, 0x08b4, 0x1397, 0x08b4, 0, 0, (unsigned long)&hfc4s_EV },
+	{0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb41xp},
+	{0xd161, 0x8014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb43xp},
+	{0xd161, 0x8015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb43xp},
+	{0x1397, 0x16b8, 0x1397, 0xb552, 0, 0, (unsigned long)&hfc8s},
+	{0x1397, 0x16b8, 0x1397, 0xb55b, 0, 0, (unsigned long)&hfc8s},
+	{0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s},
+	{0x1397, 0x08b4, 0x1397, 0xb550, 0, 0, (unsigned long)&hfc4s},
+	{0x1397, 0x08b4, 0x1397, 0xb752, 0, 0, (unsigned long)&hfc4s},
+	{0x1397, 0x08b4, 0x1397, 0xb556, 0, 0, (unsigned long)&hfc2s},
+	{0x1397, 0x08b4, 0x1397, 0xe884, 0, 0, (unsigned long)&hfc2s_OV},
+	{0x1397, 0x08b4, 0x1397, 0xe888, 0, 0, (unsigned long)&hfc4s_OV},
+	{0x1397, 0x16b8, 0x1397, 0xe998, 0, 0, (unsigned long)&hfc8s_OV},
+	{0x1397, 0x08b4, 0x1397, 0xb566, 0, 0, (unsigned long)&hfc2s_BN},
+	{0x1397, 0x08b4, 0x1397, 0xb761, 0, 0, (unsigned long)&hfc2s_BN},
+	{0x1397, 0x08b4, 0x1397, 0xb560, 0, 0, (unsigned long)&hfc4s_BN},
+	{0x1397, 0x08b4, 0x1397, 0xb550, 0, 0, (unsigned long)&hfc4s_BN},
+	{0x1397, 0x08b4, 0x1397, 0xb762, 0, 0, (unsigned long)&hfc4s_BN},
+	{0x1397, 0x16b8, 0x1397, 0xb562, 0, 0, (unsigned long)&hfc8s_BN},
+	{0x1397, 0x16b8, 0x1397, 0xb56b, 0, 0, (unsigned long)&hfc8s_BN},
+	{0x1397, 0x08b4, 0x1397, 0xb540, 0, 0, (unsigned long)&hfc4s_SW},
+	{0x1397, 0x08b4, 0x1397, 0x08b4, 0, 0, (unsigned long)&hfc4s_EV},
 	{0, }
 
 };
diff --git a/drivers/dahdi/wcb4xxp/wcb4xxp.h b/drivers/dahdi/wcb4xxp/wcb4xxp.h
index c35c5dd..4e8c29c 100644
--- a/drivers/dahdi/wcb4xxp/wcb4xxp.h
+++ b/drivers/dahdi/wcb4xxp/wcb4xxp.h
@@ -248,8 +248,8 @@
 #define V_ROUT_TX_STIO2		(0x3 << 6)	/* output data to STIO2 */
 #define V_ROUT_RX_DIS		(0x0 << 6)	/* disabled, input data ignored */
 #define V_ROUT_RX_LOOP		(0x1 << 6)	/* internally looped, input data ignored */
-#define V_ROUT_RX_STIO2		(0x2 << 6)	/* channel data comes from STIO1 */
-#define V_ROUT_RX_STIO1		(0x3 << 6)	/* channel data comes from STIO2 */
+#define V_ROUT_RX_STIO2		(0x2 << 6)	/* channel data from STIO2 */
+#define V_ROUT_RX_STIO1		(0x3 << 6)	/* channel data from STIO1 */
 
 #define V_CH_SNUM_SHIFT		(1)
 #define V_CH_SNUM_MASK		(31 << 1)
@@ -385,7 +385,8 @@
 
 struct b4xxp_span {
 	struct b4xxp *parent;
-	int port;				/* which S/T port this span belongs to */
+	int port;				/* virtual port */
+	int phy_port;				/* physical port */
 
 	unsigned char writechunk[WCB4XXP_CHANNELS_PER_SPAN * DAHDI_CHUNKSIZE];
 	unsigned char readchunk[WCB4XXP_CHANNELS_PER_SPAN * DAHDI_CHUNKSIZE];
@@ -426,7 +427,8 @@ enum cards_ids {	/* Cards ==> Brand & Model 		*/
 	BN4S0,		/* Beronet BN4S0			*/
 	BN8S0,		/* BeroNet BN8S0			*/
 	BSWYX_SX2,	/* Swyx 4xS0 SX2 QuadBri		*/
-	QUADBRI_EVAL	/* HFC-4S CCD Eval. Board		*/
+	QUADBRI_EVAL,	/* HFC-4S CCD Eval. Board		*/
+	B430P		/* Digium B430P				*/
 	};
 
 /* This structure exists one per card */

commit ae5fa08abd1b898c0c080927e75c7249b3982c2d
Author: John Sloan <jsloan256 at gmail.com>
Date:   Fri Feb 13 14:46:22 2015 -0600

    wcxb: Fix "I/O error reported by firmware" followed by underruns
    
    The cards affected include the TE131/3, TE235/435, A4B, and A8B.
    
    Update all PCIe cards' firmware to increase the incoming and outgoing TDM FIFOs
    to 16ms. The FIFOs will only be filled to a depth equal to the driver's latency
    setting (ie. 3ms default). The total system latency is not effected. The
    firmware and driver now also report the maximum DMA transaction time when in
    DEBUG mode to aid in determining if the system is experiencing long PCIe
    transactions (ie. TLP completion timeouts).
    
    Decreased the maximum latency to from 20 to 12ms
    
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/firmware/Makefile b/drivers/dahdi/firmware/Makefile
index e93347e..fbd6582 100644
--- a/drivers/dahdi/firmware/Makefile
+++ b/drivers/dahdi/firmware/Makefile
@@ -31,14 +31,14 @@ VPMADT032_VERSION:=1.25.0
 HX8_VERSION:=2.06
 VPMOCT032_VERSION:=1.12.0
 WCT820_VERSION:=1.76
-TE133_VERSION:=780019
+TE133_VERSION:=7a001e
 TE134_VERSION:=780017
-TE435_VERSION:=e0019
+TE435_VERSION:=13001e
 TE436_VERSION:=10017
 A8A_VERSION:=1d0017
-A8B_VERSION:=1d0019
+A8B_VERSION:=1f001e
 A4A_VERSION:=a0017
-A4B_VERSION:=b0019
+A4B_VERSION:=d001e
 
 FIRMWARE_URL:=http://downloads.digium.com/pub/telephony/firmware/releases
 
diff --git a/drivers/dahdi/wcaxx-base.c b/drivers/dahdi/wcaxx-base.c
index 3d3329f..00c2d21 100644
--- a/drivers/dahdi/wcaxx-base.c
+++ b/drivers/dahdi/wcaxx-base.c
@@ -3886,9 +3886,9 @@ static int wcaxx_check_firmware(struct wcaxx *wc)
 	u32 firmware_version;
 	const bool force_firmware = false;
 	const unsigned int A4A_VERSION = 0x0a0017;
-	const unsigned int A4B_VERSION = 0x0b0019;
+	const unsigned int A4B_VERSION = 0x0d001e;
 	const unsigned int A8A_VERSION = 0x1d0017;
-	const unsigned int A8B_VERSION = 0x1d0019;
+	const unsigned int A8B_VERSION = 0x1f001e;
 
 	if (wc->desc == &device_a8a) {
 		firmware_version = A8A_VERSION;
diff --git a/drivers/dahdi/wcte13xp-base.c b/drivers/dahdi/wcte13xp-base.c
index 1917583..c5ebe9d 100644
--- a/drivers/dahdi/wcte13xp-base.c
+++ b/drivers/dahdi/wcte13xp-base.c
@@ -45,7 +45,7 @@
 
 static const char *TE133_FW_FILENAME = "dahdi-fw-te133.bin";
 static const char *TE134_FW_FILENAME = "dahdi-fw-te134.bin";
-static const u32 TE133_FW_VERSION = 0x780019;
+static const u32 TE133_FW_VERSION = 0x7a001e;
 static const u32 TE134_FW_VERSION = 0x780017;
 
 #define WC_MAX_IFACES 8
diff --git a/drivers/dahdi/wcte43x-base.c b/drivers/dahdi/wcte43x-base.c
index a718393..3f00c5d 100644
--- a/drivers/dahdi/wcte43x-base.c
+++ b/drivers/dahdi/wcte43x-base.c
@@ -66,7 +66,7 @@ static inline int delayed_work_pending(struct work_struct *work)
 
 static const char *TE435_FW_FILENAME = "dahdi-fw-te435.bin";
 static const char *TE436_FW_FILENAME = "dahdi-fw-te436.bin";
-static const u32 TE435_VERSION = 0xe0019;
+static const u32 TE435_VERSION = 0x13001e;
 static const u32 TE436_VERSION = 0x10017;
 
 /* #define RPC_RCLK */
diff --git a/drivers/dahdi/wcxb.c b/drivers/dahdi/wcxb.c
index 9ab53c8..f45125a 100644
--- a/drivers/dahdi/wcxb.c
+++ b/drivers/dahdi/wcxb.c
@@ -66,7 +66,6 @@
 #define DRING_SIZE_MASK		(DRING_SIZE-1)
 #define DESC_EOR		(1 << 0)
 #define DESC_INT		(1 << 1)
-#define DESC_IO_ERROR		(1 << 30)
 #define DESC_OWN		(1 << 31)
 #define DESC_DEFAULT_STATUS	0xdeadbe00
 #define DMA_CHAN_SIZE		128
@@ -358,45 +357,25 @@ static void _wcxb_reset_dring(struct wcxb *xb)
 	hdesc->control |= cpu_to_be32(DESC_EOR);
 #ifdef DEBUG
 	xb->last_retry_count = 0;
+	xb->max_retry_count = 0;
+	xb->last_dma_time = 0;
+	xb->max_dma_time = 0;
 #endif
 	iowrite32be(xb->hw_dring_phys, xb->membase + TDM_DRING_ADDR);
 }
 
 static void wcxb_handle_dma(struct wcxb *xb)
 {
-#ifdef DEBUG
-	bool did_retry_dma = false;
-	u8 retry;
-#endif
 	struct wcxb_meta_desc *mdesc;
 	struct wcxb_hw_desc *tail = &(xb->hw_dring[xb->dma_tail]);
 
 	while (!(tail->control & cpu_to_be32(DESC_OWN))) {
 		u_char *frame;
 
-		if (tail->control & cpu_to_be32(DESC_IO_ERROR)) {
-			u32 ier;
-			unsigned long flags;
-
-			/* The firmware detected an error condition on the bus.
-			 * Force an underrun by disabling the descriptor
-			 * complete interrupt. When the driver processes the
-			 * underrun it will reset the TDM engine. */
-			xb->flags.io_error = 1;
-
-			spin_lock_irqsave(&xb->lock, flags);
-			ier = ioread32be(xb->membase + IER);
-			iowrite32be(ier & ~DESC_COMPLETE, xb->membase + IER);
-			spin_unlock_irqrestore(&xb->lock, flags);
-			return;
-		}
-
 #ifdef DEBUG
-		retry = be32_to_cpu(tail->status) & 0xff;
-		if (xb->last_retry_count != retry) {
-			xb->last_retry_count = retry;
-			did_retry_dma = true;
-		}
+		xb->last_retry_count =
+			((be32_to_cpu(tail->control) & 0x0000ff00) >> 8);
+		xb->last_dma_time = (be32_to_cpu(tail->status));
 #endif
 
 		mdesc = &xb->meta_dring[xb->dma_tail];
@@ -420,9 +399,17 @@ static void wcxb_handle_dma(struct wcxb *xb)
 	}
 
 #ifdef DEBUG
-	if (did_retry_dma) {
+	if (xb->last_retry_count > xb->max_retry_count) {
+		xb->max_retry_count = xb->last_retry_count;
+		dev_info(&xb->pdev->dev,
+			"New DMA max retries detected: %d\n",
+			xb->max_retry_count);
+	}
+	if (xb->last_dma_time > xb->max_dma_time) {
+		xb->max_dma_time = xb->last_dma_time;
 		dev_info(&xb->pdev->dev,
-			 "DMA retries detected: %d\n", xb->last_retry_count);
+			"New DMA max transfer time detected: %d\n",
+			xb->max_dma_time);
 	}
 #endif
 }
@@ -451,14 +438,7 @@ static irqreturn_t _wcxb_isr(int irq, void *dev_id)
 
 			spin_lock(&xb->lock);
 
-			if (xb->flags.io_error) {
-				/* Since an IO error is not necessarily because
-				 * the host could not keep up, we do not want to
-				 * bump the latency. */
-				xb->flags.io_error = 0;
-				dev_warn(&xb->pdev->dev,
-					 "IO error reported by firmware.\n");
-			} else if (!xb->flags.latency_locked) {
+			if (!xb->flags.latency_locked) {
 				/* bump latency */
 
 				xb->latency = min(xb->latency + 1,
diff --git a/drivers/dahdi/wcxb.h b/drivers/dahdi/wcxb.h
index 3a0f8d3..d23c89f 100644
--- a/drivers/dahdi/wcxb.h
+++ b/drivers/dahdi/wcxb.h
@@ -24,7 +24,7 @@
 #define __WCXB_H__
 
 #define WCXB_DEFAULT_LATENCY	3U
-#define WCXB_DEFAULT_MAXLATENCY 20U
+#define WCXB_DEFAULT_MAXLATENCY 12U
 #define WCXB_DMA_CHAN_SIZE	128
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
@@ -66,7 +66,7 @@ struct wcxb {
 #ifdef WCXB_PCI_DEV_DOES_NOT_HAVE_IS_PCIE
 		u32	is_pcie:1;
 #endif
-		u32	io_error:1;
+		u32	dma_ins:1;
 	} flags;
 	void __iomem			*membase;
 	struct wcxb_meta_desc		*meta_dring;
@@ -78,6 +78,9 @@ struct wcxb {
 	unsigned long			framecount;
 #ifdef DEBUG
 	u8				last_retry_count;
+	u8				max_retry_count;
+	u32				last_dma_time;
+	u32				max_dma_time;
 #endif
 };
 

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


-- 
dahdi/linux.git



More information about the dahdi-commits mailing list