mISDN: avmfritz use the bigger fifo of chip version 2

If we detect the latest hardware revision we should use the bigger fifo
to avoid TX underruns and have less interrupts.
TX underruns should be logged as warning.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Karsten Keil 2012-05-15 23:51:03 +00:00 committed by David S. Miller
parent 8bfddfbe21
commit 09e79a777a

View File

@ -30,7 +30,7 @@
#include "ipac.h"
#define AVMFRITZ_REV "2.1"
#define AVMFRITZ_REV "2.2"
static int AVM_cnt;
static int debug;
@ -69,6 +69,7 @@ enum {
#define HDLC_MODE_TRANS 0x02
#define HDLC_MODE_CCR_7 0x04
#define HDLC_MODE_CCR_16 0x08
#define HDLC_FIFO_SIZE_128 0x20
#define HDLC_MODE_TESTLOOP 0x80
#define HDLC_INT_XPR 0x80
@ -80,13 +81,16 @@ enum {
#define HDLC_STAT_RDO 0x10
#define HDLC_STAT_CRCVFRRAB 0x0E
#define HDLC_STAT_CRCVFR 0x06
#define HDLC_STAT_RML_MASK 0x3f00
#define HDLC_STAT_RML_MASK_V1 0x3f00
#define HDLC_STAT_RML_MASK_V2 0x7f00
#define HDLC_CMD_XRS 0x80
#define HDLC_CMD_XME 0x01
#define HDLC_CMD_RRS 0x20
#define HDLC_CMD_XML_MASK 0x3f00
#define HDLC_FIFO_SIZE 32
#define HDLC_FIFO_SIZE_V1 32
#define HDLC_FIFO_SIZE_V2 128
/* Fritz PCI v2.0 */
@ -346,11 +350,14 @@ modehdlc(struct bchannel *bch, int protocol)
{
struct fritzcard *fc = bch->hw;
struct hdlc_hw *hdlc;
u8 mode;
hdlc = &fc->hdlc[(bch->nr - 1) & 1];
pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name,
'@' + bch->nr, bch->state, protocol, bch->nr);
hdlc->ctrl.ctrl = 0;
mode = (fc->type == AVM_FRITZ_PCIV2) ? HDLC_FIFO_SIZE_128 : 0;
switch (protocol) {
case -1: /* used for init */
bch->state = -1;
@ -358,7 +365,7 @@ modehdlc(struct bchannel *bch, int protocol)
if (bch->state == ISDN_P_NONE)
break;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
write_ctrl(bch, 5);
bch->state = ISDN_P_NONE;
test_and_clear_bit(FLG_HDLC, &bch->Flags);
@ -367,7 +374,7 @@ modehdlc(struct bchannel *bch, int protocol)
case ISDN_P_B_RAW:
bch->state = protocol;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
hdlc->ctrl.sr.mode = mode | HDLC_MODE_TRANS;
write_ctrl(bch, 5);
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bch, 1);
@ -377,7 +384,7 @@ modehdlc(struct bchannel *bch, int protocol)
case ISDN_P_B_HDLC:
bch->state = protocol;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
hdlc->ctrl.sr.mode = mode | HDLC_MODE_ITF_FLG;
write_ctrl(bch, 5);
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bch, 1);
@ -416,7 +423,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
}
p = skb_put(bch->rx_skb, count);
ptr = (u32 *)p;
if (AVM_FRITZ_PCIV2 == fc->type)
if (fc->type == AVM_FRITZ_PCIV2)
addr = fc->addr + (bch->nr == 2 ?
AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
else {
@ -441,7 +448,7 @@ hdlc_fill_fifo(struct bchannel *bch)
{
struct fritzcard *fc = bch->hw;
struct hdlc_hw *hdlc;
int count, cnt = 0;
int count, fs, cnt = 0;
u8 *p;
u32 *ptr, val, addr;
@ -451,10 +458,12 @@ hdlc_fill_fifo(struct bchannel *bch)
count = bch->tx_skb->len - bch->tx_idx;
if (count <= 0)
return;
fs = (fc->type == AVM_FRITZ_PCIV2) ?
HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
p = bch->tx_skb->data + bch->tx_idx;
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
if (count > HDLC_FIFO_SIZE) {
count = HDLC_FIFO_SIZE;
if (count > fs) {
count = fs;
} else {
if (test_bit(FLG_HDLC, &bch->Flags))
hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
@ -463,8 +472,8 @@ hdlc_fill_fifo(struct bchannel *bch)
bch->tx_idx, bch->tx_skb->len);
ptr = (u32 *)p;
bch->tx_idx += count;
hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
if (AVM_FRITZ_PCIV2 == fc->type) {
hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
if (fc->type == AVM_FRITZ_PCIV2) {
__write_ctrl_pciv2(fc, hdlc, bch->nr);
addr = fc->addr + (bch->nr == 2 ?
AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
@ -502,13 +511,23 @@ static void
HDLC_irq(struct bchannel *bch, u32 stat)
{
struct fritzcard *fc = bch->hw;
int len;
int len, fs;
u32 rmlMask;
struct hdlc_hw *hdlc;
hdlc = &fc->hdlc[(bch->nr - 1) & 1];
pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
if (fc->type == AVM_FRITZ_PCIV2) {
rmlMask = HDLC_STAT_RML_MASK_V2;
fs = HDLC_FIFO_SIZE_V2;
} else {
rmlMask = HDLC_STAT_RML_MASK_V1;
fs = HDLC_FIFO_SIZE_V1;
}
if (stat & HDLC_INT_RPR) {
if (stat & HDLC_STAT_RDO) {
pr_warning("%s: ch%d stat %x RDO\n",
fc->name, bch->nr, stat);
hdlc->ctrl.sr.xml = 0;
hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
write_ctrl(bch, 1);
@ -517,21 +536,21 @@ HDLC_irq(struct bchannel *bch, u32 stat)
if (bch->rx_skb)
skb_trim(bch->rx_skb, 0);
} else {
len = (stat & HDLC_STAT_RML_MASK) >> 8;
len = (stat & rmlMask) >> 8;
if (!len)
len = 32;
len = fs;
hdlc_empty_fifo(bch, len);
if (!bch->rx_skb)
goto handle_tx;
if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT,
&bch->Flags)) {
if (test_bit(FLG_TRANSPARENT, &bch->Flags) ||
(stat & HDLC_STAT_RME)) {
if (((stat & HDLC_STAT_CRCVFRRAB) ==
HDLC_STAT_CRCVFR) ||
test_bit(FLG_TRANSPARENT, &bch->Flags)) {
recv_Bchannel(bch, 0);
} else {
pr_debug("%s: got invalid frame\n",
fc->name);
pr_warning("%s: got invalid frame\n",
fc->name);
skb_trim(bch->rx_skb, 0);
}
}
@ -543,13 +562,8 @@ handle_tx:
* restart transmitting the whole frame on HDLC
* in transparent mode we send the next data
*/
if (bch->tx_skb)
pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
fc->name, bch->nr, bch->tx_skb->len,
bch->tx_idx, bch->Flags);
else
pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n",
fc->name, bch->nr, bch->Flags);
pr_warning("%s: ch%d stat %x XDU %s\n", fc->name, bch->nr,
stat, bch->tx_skb ? "tx_skb" : "no tx_skb");
if (bch->tx_skb && bch->tx_skb->len) {
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
bch->tx_idx = 0;
@ -774,7 +788,7 @@ init_card(struct fritzcard *fc)
inithdlc(fc);
enable_hwirq(fc);
/* RESET Receiver and Transmitter */
if (AVM_FRITZ_PCIV2 == fc->type) {
if (fc->type == AVM_FRITZ_PCIV2) {
WriteISAC_V2(fc, ISACX_MASK, 0);
WriteISAC_V2(fc, ISACX_CMDRD, 0x41);
} else {