Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7206e659 authored by Karsten Keil's avatar Karsten Keil Committed by David S. Miller
Browse files

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: default avatarKarsten Keil <kkeil@linux-pingi.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 37952cfa
Loading
Loading
Loading
Loading
+6 −12
Original line number Diff line number Diff line
@@ -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);
@@ -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);
+26 −35
Original line number Diff line number Diff line
@@ -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))
	if (bch) {
		if (!test_bit(FLG_ACTIVE, &bch->Flags))
			return;
	if (dch) {
	} 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;
	}
next_frame:
	/* on first AND before getting next valid frame, R_FIFO must be written
@@ -2260,14 +2256,27 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
	if (Zsize <= 0)
		return;

	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 + 3, GFP_ATOMIC);
			*sp = mI_alloc_skb(maxlen, GFP_ATOMIC);
			if (*sp == NULL) {
			printk(KERN_DEBUG "%s: No mem for rx_skb\n",
			       __func__);
				pr_warning("card%d: No mem for dch rx_skb\n",
					   hc->id + 1);
				return;
			}
		}
	}
	/* show activity */
	if (dch)
		hc->activity_rx |= 1 << hc->chan[ch].port;
@@ -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",
@@ -2351,24 +2360,7 @@ 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 "
@@ -2376,7 +2368,6 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
			       __func__, hc->id + 1, ch, Zsize, z1, z2);
		/* only bch is transparent */
		recv_Bchannel(bch, hc->chan[ch].Zfill);
		*sp = skb;
	}
}

+6 −5
Original line number Diff line number Diff line
@@ -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 */
@@ -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 */
}

+24 −28
Original line number Diff line number Diff line
@@ -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);
	}
@@ -870,13 +879,12 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
		hdlc = 1;
	}

	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->bch)
				fifo->bch->rx_skb = rx_skb;
				if (fifo->ech)
					fifo->ech->rx_skb = rx_skb;
				skb_trim(rx_skb, 0);
@@ -887,8 +895,6 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
				return;
			}
		}

	if (fifo->dch || fifo->ech) {
		/* D/E-Channel SKB range check */
		if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) {
			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);
			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);
+7 −13
Original line number Diff line number Diff line
@@ -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);
	maxlen = bchannel_get_rxbuf(&hscx->bch, count);
	if (maxlen < 0) {
		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);
		if (hscx->bch.rx_skb)
			skb_trim(hscx->bch.rx_skb, 0);
		hscx_cmdr(hscx, 0x80); /* RMC */
		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);
Loading