Skip to content

Commit

Permalink
mISDN: Reduce RX buffer allocation for transparent data
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Karsten Keil authored and David S. Miller committed May 16, 2012
1 parent 37952cf commit 7206e65
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 188 deletions.
18 changes: 6 additions & 12 deletions drivers/isdn/hardware/mISDN/avmfritz.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,21 +404,14 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
u32 *ptr;
u8 *p;
u32 val, addr;
int cnt = 0;
int cnt;
struct fritzcard *fc = bch->hw;

pr_debug("%s: %s %d\n", fc->name, __func__, count);
if (!bch->rx_skb) {
bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC);
if (!bch->rx_skb) {
pr_info("%s: B receive out of memory\n",
fc->name);
return;
}
}
if ((bch->rx_skb->len + count) > bch->maxlen) {
pr_debug("%s: overrun %d\n", fc->name,
bch->rx_skb->len + count);
cnt = bchannel_get_rxbuf(bch, count);
if (cnt < 0) {
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
fc->name, bch->nr, count);
return;
}
p = skb_put(bch->rx_skb, count);
Expand All @@ -430,6 +423,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
addr = fc->addr + CHIP_WINDOW;
outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
}
cnt = 0;
while (cnt < count) {
val = le32_to_cpu(inl(addr));
put_unaligned(val, ptr);
Expand Down
61 changes: 26 additions & 35 deletions drivers/isdn/hardware/mISDN/hfcmulti.c
Original file line number Diff line number Diff line change
Expand Up @@ -2196,24 +2196,20 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
int f1 = 0, f2 = 0; /* = 0, to make GCC happy */
int again = 0;
struct bchannel *bch;
struct dchannel *dch;
struct dchannel *dch = NULL;
struct sk_buff *skb, **sp = NULL;
int maxlen;

bch = hc->chan[ch].bch;
dch = hc->chan[ch].dch;
if ((!dch) && (!bch))
return;
if (dch) {
if (bch) {
if (!test_bit(FLG_ACTIVE, &bch->Flags))
return;
} else if (hc->chan[ch].dch) {
dch = hc->chan[ch].dch;
if (!test_bit(FLG_ACTIVE, &dch->Flags))
return;
sp = &dch->rx_skb;
maxlen = dch->maxlen;
} else {
if (!test_bit(FLG_ACTIVE, &bch->Flags))
return;
sp = &bch->rx_skb;
maxlen = bch->maxlen;
return;
}
next_frame:
/* on first AND before getting next valid frame, R_FIFO must be written
Expand Down Expand Up @@ -2260,13 +2256,26 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
if (Zsize <= 0)
return;

if (*sp == NULL) {
*sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC);
if (*sp == NULL) {
printk(KERN_DEBUG "%s: No mem for rx_skb\n",
__func__);
if (bch) {
maxlen = bchannel_get_rxbuf(bch, Zsize);
if (maxlen < 0) {
pr_warning("card%d.B%d: No bufferspace for %d bytes\n",
hc->id + 1, bch->nr, Zsize);
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 */
if (dch)
Expand All @@ -2281,7 +2290,7 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
f1, f2, Zsize + (*sp)->len, again);
/* HDLC */
if ((Zsize + (*sp)->len) > (maxlen + 3)) {
if ((Zsize + (*sp)->len) > maxlen) {
if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG
"%s(card %d): hdlc-frame too large.\n",
Expand Down Expand Up @@ -2351,32 +2360,14 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
/* there is an incomplete frame */
} else {
/* transparent */
if (Zsize > skb_tailroom(*sp))
Zsize = skb_tailroom(*sp);
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)
printk(KERN_DEBUG
"%s(card %d): fifo(%d) reading %d bytes "
"(z1=%04x, z2=%04x) TRANS\n",
__func__, hc->id + 1, ch, Zsize, z1, z2);
/* only bch is transparent */
recv_Bchannel(bch, hc->chan[ch].Zfill);
*sp = skb;
}
}

Expand Down
11 changes: 6 additions & 5 deletions drivers/isdn/hardware/mISDN/hfcpci.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
fcnt_tx = B_FIFO_SIZE - fcnt_tx;
/* remaining bytes to send (bytes in tx-fifo) */

bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC);
if (bch->rx_skb) {
maxlen = bchannel_get_rxbuf(bch, fcnt_rx);
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);
if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
maxlen = fcnt_rx; /* complete transfer */
Expand All @@ -597,9 +600,7 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
memcpy(ptr, ptr1, fcnt_rx); /* rest */
}
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 */
}

Expand Down
52 changes: 24 additions & 28 deletions drivers/isdn/hardware/mISDN/hfcsusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,16 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
hdlc = 1;
}
if (fifo->bch) {
maxlen = bchannel_get_rxbuf(fifo->bch, len);
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;
hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
}
Expand All @@ -870,25 +879,22 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
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 (!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 */
if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) {
printk(KERN_DEBUG "%s: %s: sbk mem exceeded "
Expand All @@ -898,16 +904,6 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
spin_unlock(&hw->lock);
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);
Expand Down
20 changes: 7 additions & 13 deletions drivers/isdn/hardware/mISDN/mISDNipac.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,22 +933,16 @@ static void
hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
{
u8 *p;
int maxlen;

pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
if (!hscx->bch.rx_skb) {
hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC);
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);
maxlen = bchannel_get_rxbuf(&hscx->bch, count);
if (maxlen < 0) {
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;
}
p = skb_put(hscx->bch.rx_skb, count);
Expand Down
37 changes: 12 additions & 25 deletions drivers/isdn/hardware/mISDN/mISDNisar.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ deliver_status(struct isar_ch *ch, int status)
static inline void
isar_rcv_frame(struct isar_ch *ch)
{
u8 *ptr;
u8 *ptr;
int maxlen;

if (!ch->is->clsb) {
pr_debug("%s; ISAR zero len frame\n", ch->is->name);
Expand All @@ -437,36 +438,22 @@ isar_rcv_frame(struct isar_ch *ch)
case ISDN_P_B_RAW:
case ISDN_P_B_L2DTMF:
case ISDN_P_B_MODEM_ASYNC:
if (!ch->bch.rx_skb) {
ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
GFP_ATOMIC);
if (unlikely(!ch->bch.rx_skb)) {
pr_info("%s: B receive out of memory\n",
ch->is->name);
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
break;
}
maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb);
if (maxlen < 0) {
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
ch->is->name, ch->bch.nr, ch->is->clsb);
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
break;
}
rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
recv_Bchannel(&ch->bch, 0);
break;
case ISDN_P_B_HDLC:
if (!ch->bch.rx_skb) {
ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
GFP_ATOMIC);
if (unlikely(!ch->bch.rx_skb)) {
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);
maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb);
if (maxlen < 0) {
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
ch->is->name, ch->bch.nr, ch->is->clsb);
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
skb_trim(ch->bch.rx_skb, 0);
break;
}
if (ch->is->cmsb & HDLC_ERROR) {
Expand Down
Loading

0 comments on commit 7206e65

Please sign in to comment.