mISDN: Reduce RX buffer allocation for transparent data
We did allways allocate maxsize buffers, but for transparent data we know the actual size. Use a common function to calculate size and detect overflows. Signed-off-by: Karsten Keil <kkeil@linux-pingi.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
37952cfa3a
commit
7206e659f6
10 changed files with 193 additions and 195 deletions
|
@ -404,21 +404,14 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
|
||||||
u32 *ptr;
|
u32 *ptr;
|
||||||
u8 *p;
|
u8 *p;
|
||||||
u32 val, addr;
|
u32 val, addr;
|
||||||
int cnt = 0;
|
int cnt;
|
||||||
struct fritzcard *fc = bch->hw;
|
struct fritzcard *fc = bch->hw;
|
||||||
|
|
||||||
pr_debug("%s: %s %d\n", fc->name, __func__, count);
|
pr_debug("%s: %s %d\n", fc->name, __func__, count);
|
||||||
if (!bch->rx_skb) {
|
cnt = bchannel_get_rxbuf(bch, count);
|
||||||
bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC);
|
if (cnt < 0) {
|
||||||
if (!bch->rx_skb) {
|
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
|
||||||
pr_info("%s: B receive out of memory\n",
|
fc->name, bch->nr, count);
|
||||||
fc->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((bch->rx_skb->len + count) > bch->maxlen) {
|
|
||||||
pr_debug("%s: overrun %d\n", fc->name,
|
|
||||||
bch->rx_skb->len + count);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p = skb_put(bch->rx_skb, count);
|
p = skb_put(bch->rx_skb, count);
|
||||||
|
@ -430,6 +423,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
|
||||||
addr = fc->addr + CHIP_WINDOW;
|
addr = fc->addr + CHIP_WINDOW;
|
||||||
outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
|
outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
|
||||||
}
|
}
|
||||||
|
cnt = 0;
|
||||||
while (cnt < count) {
|
while (cnt < count) {
|
||||||
val = le32_to_cpu(inl(addr));
|
val = le32_to_cpu(inl(addr));
|
||||||
put_unaligned(val, ptr);
|
put_unaligned(val, ptr);
|
||||||
|
|
|
@ -2196,24 +2196,20 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
|
||||||
int f1 = 0, f2 = 0; /* = 0, to make GCC happy */
|
int f1 = 0, f2 = 0; /* = 0, to make GCC happy */
|
||||||
int again = 0;
|
int again = 0;
|
||||||
struct bchannel *bch;
|
struct bchannel *bch;
|
||||||
struct dchannel *dch;
|
struct dchannel *dch = NULL;
|
||||||
struct sk_buff *skb, **sp = NULL;
|
struct sk_buff *skb, **sp = NULL;
|
||||||
int maxlen;
|
int maxlen;
|
||||||
|
|
||||||
bch = hc->chan[ch].bch;
|
bch = hc->chan[ch].bch;
|
||||||
dch = hc->chan[ch].dch;
|
if (bch) {
|
||||||
if ((!dch) && (!bch))
|
|
||||||
return;
|
|
||||||
if (dch) {
|
|
||||||
if (!test_bit(FLG_ACTIVE, &dch->Flags))
|
|
||||||
return;
|
|
||||||
sp = &dch->rx_skb;
|
|
||||||
maxlen = dch->maxlen;
|
|
||||||
} else {
|
|
||||||
if (!test_bit(FLG_ACTIVE, &bch->Flags))
|
if (!test_bit(FLG_ACTIVE, &bch->Flags))
|
||||||
return;
|
return;
|
||||||
sp = &bch->rx_skb;
|
} else if (hc->chan[ch].dch) {
|
||||||
maxlen = bch->maxlen;
|
dch = hc->chan[ch].dch;
|
||||||
|
if (!test_bit(FLG_ACTIVE, &dch->Flags))
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
next_frame:
|
next_frame:
|
||||||
/* on first AND before getting next valid frame, R_FIFO must be written
|
/* on first AND before getting next valid frame, R_FIFO must be written
|
||||||
|
@ -2260,13 +2256,26 @@ next_frame:
|
||||||
if (Zsize <= 0)
|
if (Zsize <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*sp == NULL) {
|
if (bch) {
|
||||||
*sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC);
|
maxlen = bchannel_get_rxbuf(bch, Zsize);
|
||||||
if (*sp == NULL) {
|
if (maxlen < 0) {
|
||||||
printk(KERN_DEBUG "%s: No mem for rx_skb\n",
|
pr_warning("card%d.B%d: No bufferspace for %d bytes\n",
|
||||||
__func__);
|
hc->id + 1, bch->nr, Zsize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
sp = &bch->rx_skb;
|
||||||
|
maxlen = bch->maxlen;
|
||||||
|
} else { /* Dchannel */
|
||||||
|
sp = &dch->rx_skb;
|
||||||
|
maxlen = dch->maxlen + 3;
|
||||||
|
if (*sp == NULL) {
|
||||||
|
*sp = mI_alloc_skb(maxlen, GFP_ATOMIC);
|
||||||
|
if (*sp == NULL) {
|
||||||
|
pr_warning("card%d: No mem for dch rx_skb\n",
|
||||||
|
hc->id + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* show activity */
|
/* show activity */
|
||||||
if (dch)
|
if (dch)
|
||||||
|
@ -2281,7 +2290,7 @@ next_frame:
|
||||||
Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
|
Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
|
||||||
f1, f2, Zsize + (*sp)->len, again);
|
f1, f2, Zsize + (*sp)->len, again);
|
||||||
/* HDLC */
|
/* HDLC */
|
||||||
if ((Zsize + (*sp)->len) > (maxlen + 3)) {
|
if ((Zsize + (*sp)->len) > maxlen) {
|
||||||
if (debug & DEBUG_HFCMULTI_FIFO)
|
if (debug & DEBUG_HFCMULTI_FIFO)
|
||||||
printk(KERN_DEBUG
|
printk(KERN_DEBUG
|
||||||
"%s(card %d): hdlc-frame too large.\n",
|
"%s(card %d): hdlc-frame too large.\n",
|
||||||
|
@ -2351,24 +2360,7 @@ next_frame:
|
||||||
/* there is an incomplete frame */
|
/* there is an incomplete frame */
|
||||||
} else {
|
} else {
|
||||||
/* transparent */
|
/* transparent */
|
||||||
if (Zsize > skb_tailroom(*sp))
|
|
||||||
Zsize = skb_tailroom(*sp);
|
|
||||||
hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
|
hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
|
||||||
if (((*sp)->len) < MISDN_COPY_SIZE) {
|
|
||||||
skb = *sp;
|
|
||||||
*sp = mI_alloc_skb(skb->len, GFP_ATOMIC);
|
|
||||||
if (*sp) {
|
|
||||||
memcpy(skb_put(*sp, skb->len),
|
|
||||||
skb->data, skb->len);
|
|
||||||
skb_trim(skb, 0);
|
|
||||||
} else {
|
|
||||||
printk(KERN_DEBUG "%s: No mem\n", __func__);
|
|
||||||
*sp = skb;
|
|
||||||
skb = NULL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
skb = NULL;
|
|
||||||
}
|
|
||||||
if (debug & DEBUG_HFCMULTI_FIFO)
|
if (debug & DEBUG_HFCMULTI_FIFO)
|
||||||
printk(KERN_DEBUG
|
printk(KERN_DEBUG
|
||||||
"%s(card %d): fifo(%d) reading %d bytes "
|
"%s(card %d): fifo(%d) reading %d bytes "
|
||||||
|
@ -2376,7 +2368,6 @@ next_frame:
|
||||||
__func__, hc->id + 1, ch, Zsize, z1, z2);
|
__func__, hc->id + 1, ch, Zsize, z1, z2);
|
||||||
/* only bch is transparent */
|
/* only bch is transparent */
|
||||||
recv_Bchannel(bch, hc->chan[ch].Zfill);
|
recv_Bchannel(bch, hc->chan[ch].Zfill);
|
||||||
*sp = skb;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -577,8 +577,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
|
||||||
fcnt_tx = B_FIFO_SIZE - fcnt_tx;
|
fcnt_tx = B_FIFO_SIZE - fcnt_tx;
|
||||||
/* remaining bytes to send (bytes in tx-fifo) */
|
/* remaining bytes to send (bytes in tx-fifo) */
|
||||||
|
|
||||||
bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC);
|
maxlen = bchannel_get_rxbuf(bch, fcnt_rx);
|
||||||
if (bch->rx_skb) {
|
if (maxlen < 0) {
|
||||||
|
pr_warning("B%d: No bufferspace for %d bytes\n",
|
||||||
|
bch->nr, fcnt_rx);
|
||||||
|
} else {
|
||||||
ptr = skb_put(bch->rx_skb, fcnt_rx);
|
ptr = skb_put(bch->rx_skb, fcnt_rx);
|
||||||
if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
|
if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
|
||||||
maxlen = fcnt_rx; /* complete transfer */
|
maxlen = fcnt_rx; /* complete transfer */
|
||||||
|
@ -597,9 +600,7 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
|
||||||
memcpy(ptr, ptr1, fcnt_rx); /* rest */
|
memcpy(ptr, ptr1, fcnt_rx); /* rest */
|
||||||
}
|
}
|
||||||
recv_Bchannel(bch, fcnt_tx); /* bch, id */
|
recv_Bchannel(bch, fcnt_tx); /* bch, id */
|
||||||
} else
|
}
|
||||||
printk(KERN_WARNING "HFCPCI: receive out of memory\n");
|
|
||||||
|
|
||||||
*z2r = cpu_to_le16(new_z2); /* new position */
|
*z2r = cpu_to_le16(new_z2); /* new position */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -860,7 +860,16 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
|
||||||
hdlc = 1;
|
hdlc = 1;
|
||||||
}
|
}
|
||||||
if (fifo->bch) {
|
if (fifo->bch) {
|
||||||
|
maxlen = bchannel_get_rxbuf(fifo->bch, len);
|
||||||
rx_skb = fifo->bch->rx_skb;
|
rx_skb = fifo->bch->rx_skb;
|
||||||
|
if (maxlen < 0) {
|
||||||
|
if (rx_skb)
|
||||||
|
skb_trim(rx_skb, 0);
|
||||||
|
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
|
||||||
|
hw->name, fifo->bch->nr, len);
|
||||||
|
spin_unlock(&hw->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
maxlen = fifo->bch->maxlen;
|
maxlen = fifo->bch->maxlen;
|
||||||
hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
|
hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
|
||||||
}
|
}
|
||||||
|
@ -870,25 +879,22 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
|
||||||
hdlc = 1;
|
hdlc = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rx_skb) {
|
|
||||||
rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC);
|
|
||||||
if (rx_skb) {
|
|
||||||
if (fifo->dch)
|
|
||||||
fifo->dch->rx_skb = rx_skb;
|
|
||||||
if (fifo->bch)
|
|
||||||
fifo->bch->rx_skb = rx_skb;
|
|
||||||
if (fifo->ech)
|
|
||||||
fifo->ech->rx_skb = rx_skb;
|
|
||||||
skb_trim(rx_skb, 0);
|
|
||||||
} else {
|
|
||||||
printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n",
|
|
||||||
hw->name, __func__);
|
|
||||||
spin_unlock(&hw->lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fifo->dch || fifo->ech) {
|
if (fifo->dch || fifo->ech) {
|
||||||
|
if (!rx_skb) {
|
||||||
|
rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC);
|
||||||
|
if (rx_skb) {
|
||||||
|
if (fifo->dch)
|
||||||
|
fifo->dch->rx_skb = rx_skb;
|
||||||
|
if (fifo->ech)
|
||||||
|
fifo->ech->rx_skb = rx_skb;
|
||||||
|
skb_trim(rx_skb, 0);
|
||||||
|
} else {
|
||||||
|
printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n",
|
||||||
|
hw->name, __func__);
|
||||||
|
spin_unlock(&hw->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* D/E-Channel SKB range check */
|
/* D/E-Channel SKB range check */
|
||||||
if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) {
|
if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) {
|
||||||
printk(KERN_DEBUG "%s: %s: sbk mem exceeded "
|
printk(KERN_DEBUG "%s: %s: sbk mem exceeded "
|
||||||
|
@ -898,16 +904,6 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
|
||||||
spin_unlock(&hw->lock);
|
spin_unlock(&hw->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (fifo->bch) {
|
|
||||||
/* B-Channel SKB range check */
|
|
||||||
if ((rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) {
|
|
||||||
printk(KERN_DEBUG "%s: %s: sbk mem exceeded "
|
|
||||||
"for fifo(%d) HFCUSB_B_RX\n",
|
|
||||||
hw->name, __func__, fifon);
|
|
||||||
skb_trim(rx_skb, 0);
|
|
||||||
spin_unlock(&hw->lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(skb_put(rx_skb, len), data, len);
|
memcpy(skb_put(rx_skb, len), data, len);
|
||||||
|
|
|
@ -933,22 +933,16 @@ static void
|
||||||
hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
|
hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
|
||||||
{
|
{
|
||||||
u8 *p;
|
u8 *p;
|
||||||
|
int maxlen;
|
||||||
|
|
||||||
pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
|
pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
|
||||||
if (!hscx->bch.rx_skb) {
|
maxlen = bchannel_get_rxbuf(&hscx->bch, count);
|
||||||
hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC);
|
if (maxlen < 0) {
|
||||||
if (!hscx->bch.rx_skb) {
|
|
||||||
pr_info("%s: B receive out of memory\n",
|
|
||||||
hscx->ip->name);
|
|
||||||
hscx_cmdr(hscx, 0x80); /* RMC */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) {
|
|
||||||
pr_debug("%s: overrun %d\n", hscx->ip->name,
|
|
||||||
hscx->bch.rx_skb->len + count);
|
|
||||||
skb_trim(hscx->bch.rx_skb, 0);
|
|
||||||
hscx_cmdr(hscx, 0x80); /* RMC */
|
hscx_cmdr(hscx, 0x80); /* RMC */
|
||||||
|
if (hscx->bch.rx_skb)
|
||||||
|
skb_trim(hscx->bch.rx_skb, 0);
|
||||||
|
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
|
||||||
|
hscx->ip->name, hscx->bch.nr, count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p = skb_put(hscx->bch.rx_skb, count);
|
p = skb_put(hscx->bch.rx_skb, count);
|
||||||
|
|
|
@ -421,7 +421,8 @@ deliver_status(struct isar_ch *ch, int status)
|
||||||
static inline void
|
static inline void
|
||||||
isar_rcv_frame(struct isar_ch *ch)
|
isar_rcv_frame(struct isar_ch *ch)
|
||||||
{
|
{
|
||||||
u8 *ptr;
|
u8 *ptr;
|
||||||
|
int maxlen;
|
||||||
|
|
||||||
if (!ch->is->clsb) {
|
if (!ch->is->clsb) {
|
||||||
pr_debug("%s; ISAR zero len frame\n", ch->is->name);
|
pr_debug("%s; ISAR zero len frame\n", ch->is->name);
|
||||||
|
@ -437,36 +438,22 @@ isar_rcv_frame(struct isar_ch *ch)
|
||||||
case ISDN_P_B_RAW:
|
case ISDN_P_B_RAW:
|
||||||
case ISDN_P_B_L2DTMF:
|
case ISDN_P_B_L2DTMF:
|
||||||
case ISDN_P_B_MODEM_ASYNC:
|
case ISDN_P_B_MODEM_ASYNC:
|
||||||
if (!ch->bch.rx_skb) {
|
maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb);
|
||||||
ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
|
if (maxlen < 0) {
|
||||||
GFP_ATOMIC);
|
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
|
||||||
if (unlikely(!ch->bch.rx_skb)) {
|
ch->is->name, ch->bch.nr, ch->is->clsb);
|
||||||
pr_info("%s: B receive out of memory\n",
|
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
|
||||||
ch->is->name);
|
break;
|
||||||
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
|
rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
|
||||||
recv_Bchannel(&ch->bch, 0);
|
recv_Bchannel(&ch->bch, 0);
|
||||||
break;
|
break;
|
||||||
case ISDN_P_B_HDLC:
|
case ISDN_P_B_HDLC:
|
||||||
if (!ch->bch.rx_skb) {
|
maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb);
|
||||||
ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
|
if (maxlen < 0) {
|
||||||
GFP_ATOMIC);
|
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
|
||||||
if (unlikely(!ch->bch.rx_skb)) {
|
ch->is->name, ch->bch.nr, ch->is->clsb);
|
||||||
pr_info("%s: B receive out of memory\n",
|
|
||||||
ch->is->name);
|
|
||||||
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((ch->bch.rx_skb->len + ch->is->clsb) >
|
|
||||||
(ch->bch.maxlen + 2)) {
|
|
||||||
pr_debug("%s: incoming packet too large\n",
|
|
||||||
ch->is->name);
|
|
||||||
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
|
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
|
||||||
skb_trim(ch->bch.rx_skb, 0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ch->is->cmsb & HDLC_ERROR) {
|
if (ch->is->cmsb & HDLC_ERROR) {
|
||||||
|
|
|
@ -386,24 +386,16 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt)
|
||||||
bc->bch.nr, idx);
|
bc->bch.nr, idx);
|
||||||
}
|
}
|
||||||
bc->lastrx = idx;
|
bc->lastrx = idx;
|
||||||
if (!bc->bch.rx_skb) {
|
stat = bchannel_get_rxbuf(&bc->bch, cnt);
|
||||||
bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC);
|
/* only transparent use the count here, HDLC overun is detected later */
|
||||||
if (!bc->bch.rx_skb) {
|
if (stat == ENOMEM) {
|
||||||
pr_info("%s: B%1d receive out of memory\n",
|
pr_warning("%s.B%d: No memory for %d bytes\n",
|
||||||
card->name, bc->bch.nr);
|
card->name, bc->bch.nr, cnt);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))
|
||||||
if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {
|
|
||||||
if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) {
|
|
||||||
pr_debug("%s: B%1d overrun %d\n", card->name,
|
|
||||||
bc->bch.nr, bc->bch.rx_skb->len + cnt);
|
|
||||||
skb_trim(bc->bch.rx_skb, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p = skb_put(bc->bch.rx_skb, cnt);
|
p = skb_put(bc->bch.rx_skb, cnt);
|
||||||
} else
|
else
|
||||||
p = bc->hrbuf;
|
p = bc->hrbuf;
|
||||||
|
|
||||||
for (i = 0; i < cnt; i++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
|
@ -414,48 +406,45 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt)
|
||||||
idx = 0;
|
idx = 0;
|
||||||
p[i] = val & 0xff;
|
p[i] = val & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {
|
||||||
|
recv_Bchannel(&bc->bch, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pn = bc->hrbuf;
|
pn = bc->hrbuf;
|
||||||
next_frame:
|
while (cnt > 0) {
|
||||||
if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
|
|
||||||
stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,
|
stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,
|
||||||
bc->bch.rx_skb->data, bc->bch.maxlen);
|
bc->bch.rx_skb->data, bc->bch.maxlen);
|
||||||
if (stat > 0) /* valid frame received */
|
if (stat > 0) { /* valid frame received */
|
||||||
p = skb_put(bc->bch.rx_skb, stat);
|
p = skb_put(bc->bch.rx_skb, stat);
|
||||||
else if (stat == -HDLC_CRC_ERROR)
|
if (debug & DEBUG_HW_BFIFO) {
|
||||||
pr_info("%s: B%1d receive frame CRC error\n",
|
snprintf(card->log, LOG_SIZE,
|
||||||
card->name, bc->bch.nr);
|
"B%1d-recv %s %d ", bc->bch.nr,
|
||||||
else if (stat == -HDLC_FRAMING_ERROR)
|
card->name, stat);
|
||||||
pr_info("%s: B%1d receive framing error\n",
|
print_hex_dump_bytes(card->log,
|
||||||
card->name, bc->bch.nr);
|
DUMP_PREFIX_OFFSET, p,
|
||||||
else if (stat == -HDLC_LENGTH_ERROR)
|
stat);
|
||||||
pr_info("%s: B%1d receive frame too long (> %d)\n",
|
}
|
||||||
card->name, bc->bch.nr, bc->bch.maxlen);
|
recv_Bchannel(&bc->bch, 0);
|
||||||
} else
|
stat = bchannel_get_rxbuf(&bc->bch, bc->bch.maxlen);
|
||||||
stat = cnt;
|
if (stat < 0) {
|
||||||
|
pr_warning("%s.B%d: No memory for %d bytes\n",
|
||||||
if (stat > 0) {
|
card->name, bc->bch.nr, cnt);
|
||||||
if (debug & DEBUG_HW_BFIFO) {
|
|
||||||
snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ",
|
|
||||||
bc->bch.nr, card->name, stat);
|
|
||||||
print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET,
|
|
||||||
p, stat);
|
|
||||||
}
|
|
||||||
recv_Bchannel(&bc->bch, 0);
|
|
||||||
}
|
|
||||||
if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
|
|
||||||
pn += i;
|
|
||||||
cnt -= i;
|
|
||||||
if (!bc->bch.rx_skb) {
|
|
||||||
bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen,
|
|
||||||
GFP_ATOMIC);
|
|
||||||
if (!bc->bch.rx_skb) {
|
|
||||||
pr_info("%s: B%1d receive out of memory\n",
|
|
||||||
card->name, bc->bch.nr);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (stat == -HDLC_CRC_ERROR) {
|
||||||
|
pr_info("%s: B%1d receive frame CRC error\n",
|
||||||
|
card->name, bc->bch.nr);
|
||||||
|
} else if (stat == -HDLC_FRAMING_ERROR) {
|
||||||
|
pr_info("%s: B%1d receive framing error\n",
|
||||||
|
card->name, bc->bch.nr);
|
||||||
|
} else if (stat == -HDLC_LENGTH_ERROR) {
|
||||||
|
pr_info("%s: B%1d receive frame too long (> %d)\n",
|
||||||
|
card->name, bc->bch.nr, bc->bch.maxlen);
|
||||||
}
|
}
|
||||||
if (cnt > 0)
|
pn += i;
|
||||||
goto next_frame;
|
cnt -= i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -465,6 +465,7 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count)
|
||||||
{
|
{
|
||||||
struct w6692_hw *card = wch->bch.hw;
|
struct w6692_hw *card = wch->bch.hw;
|
||||||
u8 *ptr;
|
u8 *ptr;
|
||||||
|
int maxlen;
|
||||||
|
|
||||||
pr_debug("%s: empty_Bfifo %d\n", card->name, count);
|
pr_debug("%s: empty_Bfifo %d\n", card->name, count);
|
||||||
if (unlikely(wch->bch.state == ISDN_P_NONE)) {
|
if (unlikely(wch->bch.state == ISDN_P_NONE)) {
|
||||||
|
@ -474,20 +475,13 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count)
|
||||||
skb_trim(wch->bch.rx_skb, 0);
|
skb_trim(wch->bch.rx_skb, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!wch->bch.rx_skb) {
|
maxlen = bchannel_get_rxbuf(&wch->bch, count);
|
||||||
wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC);
|
if (maxlen < 0) {
|
||||||
if (unlikely(!wch->bch.rx_skb)) {
|
|
||||||
pr_info("%s: B receive out of memory\n", card->name);
|
|
||||||
WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
|
|
||||||
W_B_CMDR_RACT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wch->bch.rx_skb->len + count > wch->bch.maxlen) {
|
|
||||||
pr_debug("%s: empty_Bfifo incoming packet too large\n",
|
|
||||||
card->name);
|
|
||||||
WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
|
WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
|
||||||
skb_trim(wch->bch.rx_skb, 0);
|
if (wch->bch.rx_skb)
|
||||||
|
skb_trim(wch->bch.rx_skb, 0);
|
||||||
|
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
|
||||||
|
card->name, wch->bch.nr, count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ptr = skb_put(wch->bch.rx_skb, count);
|
ptr = skb_put(wch->bch.rx_skb, count);
|
||||||
|
|
|
@ -201,20 +201,30 @@ recv_Bchannel(struct bchannel *bch, unsigned int id)
|
||||||
{
|
{
|
||||||
struct mISDNhead *hh;
|
struct mISDNhead *hh;
|
||||||
|
|
||||||
hh = mISDN_HEAD_P(bch->rx_skb);
|
/* if allocation did fail upper functions still may call us */
|
||||||
hh->prim = PH_DATA_IND;
|
if (unlikely(!bch->rx_skb))
|
||||||
hh->id = id;
|
|
||||||
if (bch->rcount >= 64) {
|
|
||||||
printk(KERN_WARNING "B-channel %p receive queue overflow, "
|
|
||||||
"flushing!\n", bch);
|
|
||||||
skb_queue_purge(&bch->rqueue);
|
|
||||||
bch->rcount = 0;
|
|
||||||
return;
|
return;
|
||||||
|
if (unlikely(!bch->rx_skb->len)) {
|
||||||
|
/* we have no data to send - this may happen after recovery
|
||||||
|
* from overflow or too small allocation.
|
||||||
|
* We need to free the buffer here */
|
||||||
|
dev_kfree_skb(bch->rx_skb);
|
||||||
|
bch->rx_skb = NULL;
|
||||||
|
} else {
|
||||||
|
hh = mISDN_HEAD_P(bch->rx_skb);
|
||||||
|
hh->prim = PH_DATA_IND;
|
||||||
|
hh->id = id;
|
||||||
|
if (bch->rcount >= 64) {
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"B%d receive queue overflow - flushing!\n",
|
||||||
|
bch->nr);
|
||||||
|
skb_queue_purge(&bch->rqueue);
|
||||||
|
}
|
||||||
|
bch->rcount++;
|
||||||
|
skb_queue_tail(&bch->rqueue, bch->rx_skb);
|
||||||
|
bch->rx_skb = NULL;
|
||||||
|
schedule_event(bch, FLG_RECVQUEUE);
|
||||||
}
|
}
|
||||||
bch->rcount++;
|
|
||||||
skb_queue_tail(&bch->rqueue, bch->rx_skb);
|
|
||||||
bch->rx_skb = NULL;
|
|
||||||
schedule_event(bch, FLG_RECVQUEUE);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(recv_Bchannel);
|
EXPORT_SYMBOL(recv_Bchannel);
|
||||||
|
|
||||||
|
@ -399,3 +409,44 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bchannel_senddata);
|
EXPORT_SYMBOL(bchannel_senddata);
|
||||||
|
|
||||||
|
/* The function allocates a new receive skb on demand with a size for the
|
||||||
|
* requirements of the current protocol. It returns the tailroom of the
|
||||||
|
* receive skb or an error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
bchannel_get_rxbuf(struct bchannel *bch, int reqlen)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (bch->rx_skb) {
|
||||||
|
len = skb_tailroom(bch->rx_skb);
|
||||||
|
if (len < reqlen) {
|
||||||
|
pr_warning("B%d no space for %d (only %d) bytes\n",
|
||||||
|
bch->nr, reqlen, len);
|
||||||
|
if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
|
||||||
|
/* send what we have now and try a new buffer */
|
||||||
|
recv_Bchannel(bch, 0);
|
||||||
|
} else {
|
||||||
|
/* on HDLC we have to drop too big frames */
|
||||||
|
return -EMSGSIZE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unlikely(reqlen > bch->maxlen))
|
||||||
|
return -EMSGSIZE;
|
||||||
|
if (test_bit(FLG_TRANSPARENT, &bch->Flags))
|
||||||
|
len = reqlen;
|
||||||
|
else /* with HDLC we do not know the length yet */
|
||||||
|
len = bch->maxlen;
|
||||||
|
bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC);
|
||||||
|
if (!bch->rx_skb) {
|
||||||
|
pr_warning("B%d receive no memory for %d bytes\n",
|
||||||
|
bch->nr, len);
|
||||||
|
len = -ENOMEM;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(bchannel_get_rxbuf);
|
||||||
|
|
|
@ -177,6 +177,7 @@ extern void queue_ch_frame(struct mISDNchannel *, u_int,
|
||||||
int, struct sk_buff *);
|
int, struct sk_buff *);
|
||||||
extern int dchannel_senddata(struct dchannel *, struct sk_buff *);
|
extern int dchannel_senddata(struct dchannel *, struct sk_buff *);
|
||||||
extern int bchannel_senddata(struct bchannel *, struct sk_buff *);
|
extern int bchannel_senddata(struct bchannel *, struct sk_buff *);
|
||||||
|
extern int bchannel_get_rxbuf(struct bchannel *, int);
|
||||||
extern void recv_Dchannel(struct dchannel *);
|
extern void recv_Dchannel(struct dchannel *);
|
||||||
extern void recv_Echannel(struct dchannel *, struct dchannel *);
|
extern void recv_Echannel(struct dchannel *, struct dchannel *);
|
||||||
extern void recv_Bchannel(struct bchannel *, unsigned int id);
|
extern void recv_Bchannel(struct bchannel *, unsigned int id);
|
||||||
|
|
Loading…
Add table
Reference in a new issue