diff options
author | Karsten Keil <kkeil@linux-pingi.de> | 2012-05-15 19:51:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-16 15:23:28 -0400 |
commit | 7206e659f689558b41aa058c3040b081cb281d03 (patch) | |
tree | 2be5bdef5a0bbb9c5763b8c1b1e6fe04b7184cc5 /drivers | |
parent | 37952cfa3afdfa5cec39d9d76e80bc3a0e6a910c (diff) |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/isdn/hardware/mISDN/avmfritz.c | 18 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/hfcmulti.c | 61 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/hfcpci.c | 11 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/hfcsusb.c | 52 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/mISDNipac.c | 20 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/mISDNisar.c | 37 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/netjet.c | 79 | ||||
-rw-r--r-- | drivers/isdn/hardware/mISDN/w6692.c | 20 | ||||
-rw-r--r-- | drivers/isdn/mISDN/hwchannel.c | 75 |
9 files changed, 185 insertions, 188 deletions
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index cc782646886c..808136735f32 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c | |||
@@ -404,21 +404,14 @@ hdlc_empty_fifo(struct bchannel *bch, int count) | |||
404 | u32 *ptr; | 404 | u32 *ptr; |
405 | u8 *p; | 405 | u8 *p; |
406 | u32 val, addr; | 406 | u32 val, addr; |
407 | int cnt = 0; | 407 | int cnt; |
408 | struct fritzcard *fc = bch->hw; | 408 | struct fritzcard *fc = bch->hw; |
409 | 409 | ||
410 | pr_debug("%s: %s %d\n", fc->name, __func__, count); | 410 | pr_debug("%s: %s %d\n", fc->name, __func__, count); |
411 | if (!bch->rx_skb) { | 411 | cnt = bchannel_get_rxbuf(bch, count); |
412 | bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); | 412 | if (cnt < 0) { |
413 | if (!bch->rx_skb) { | 413 | pr_warning("%s.B%d: No bufferspace for %d bytes\n", |
414 | pr_info("%s: B receive out of memory\n", | 414 | fc->name, bch->nr, count); |
415 | fc->name); | ||
416 | return; | ||
417 | } | ||
418 | } | ||
419 | if ((bch->rx_skb->len + count) > bch->maxlen) { | ||
420 | pr_debug("%s: overrun %d\n", fc->name, | ||
421 | bch->rx_skb->len + count); | ||
422 | return; | 415 | return; |
423 | } | 416 | } |
424 | p = skb_put(bch->rx_skb, count); | 417 | p = skb_put(bch->rx_skb, count); |
@@ -430,6 +423,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count) | |||
430 | addr = fc->addr + CHIP_WINDOW; | 423 | addr = fc->addr + CHIP_WINDOW; |
431 | outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); | 424 | outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); |
432 | } | 425 | } |
426 | cnt = 0; | ||
433 | while (cnt < count) { | 427 | while (cnt < count) { |
434 | val = le32_to_cpu(inl(addr)); | 428 | val = le32_to_cpu(inl(addr)); |
435 | put_unaligned(val, ptr); | 429 | put_unaligned(val, ptr); |
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index ab3d2983e3ad..60dd6efa1879 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c | |||
@@ -2196,24 +2196,20 @@ hfcmulti_rx(struct hfc_multi *hc, int ch) | |||
2196 | int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ | 2196 | int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ |
2197 | int again = 0; | 2197 | int again = 0; |
2198 | struct bchannel *bch; | 2198 | struct bchannel *bch; |
2199 | struct dchannel *dch; | 2199 | struct dchannel *dch = NULL; |
2200 | struct sk_buff *skb, **sp = NULL; | 2200 | struct sk_buff *skb, **sp = NULL; |
2201 | int maxlen; | 2201 | int maxlen; |
2202 | 2202 | ||
2203 | bch = hc->chan[ch].bch; | 2203 | bch = hc->chan[ch].bch; |
2204 | dch = hc->chan[ch].dch; | 2204 | if (bch) { |
2205 | if ((!dch) && (!bch)) | 2205 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) |
2206 | return; | 2206 | return; |
2207 | if (dch) { | 2207 | } else if (hc->chan[ch].dch) { |
2208 | dch = hc->chan[ch].dch; | ||
2208 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) | 2209 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) |
2209 | return; | 2210 | return; |
2210 | sp = &dch->rx_skb; | ||
2211 | maxlen = dch->maxlen; | ||
2212 | } else { | 2211 | } else { |
2213 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) | 2212 | return; |
2214 | return; | ||
2215 | sp = &bch->rx_skb; | ||
2216 | maxlen = bch->maxlen; | ||
2217 | } | 2213 | } |
2218 | next_frame: | 2214 | next_frame: |
2219 | /* on first AND before getting next valid frame, R_FIFO must be written | 2215 | /* on first AND before getting next valid frame, R_FIFO must be written |
@@ -2260,13 +2256,26 @@ next_frame: | |||
2260 | if (Zsize <= 0) | 2256 | if (Zsize <= 0) |
2261 | return; | 2257 | return; |
2262 | 2258 | ||
2263 | if (*sp == NULL) { | 2259 | if (bch) { |
2264 | *sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC); | 2260 | maxlen = bchannel_get_rxbuf(bch, Zsize); |
2265 | if (*sp == NULL) { | 2261 | if (maxlen < 0) { |
2266 | printk(KERN_DEBUG "%s: No mem for rx_skb\n", | 2262 | pr_warning("card%d.B%d: No bufferspace for %d bytes\n", |
2267 | __func__); | 2263 | hc->id + 1, bch->nr, Zsize); |
2268 | return; | 2264 | return; |
2269 | } | 2265 | } |
2266 | sp = &bch->rx_skb; | ||
2267 | maxlen = bch->maxlen; | ||
2268 | } else { /* Dchannel */ | ||
2269 | sp = &dch->rx_skb; | ||
2270 | maxlen = dch->maxlen + 3; | ||
2271 | if (*sp == NULL) { | ||
2272 | *sp = mI_alloc_skb(maxlen, GFP_ATOMIC); | ||
2273 | if (*sp == NULL) { | ||
2274 | pr_warning("card%d: No mem for dch rx_skb\n", | ||
2275 | hc->id + 1); | ||
2276 | return; | ||
2277 | } | ||
2278 | } | ||
2270 | } | 2279 | } |
2271 | /* show activity */ | 2280 | /* show activity */ |
2272 | if (dch) | 2281 | if (dch) |
@@ -2281,7 +2290,7 @@ next_frame: | |||
2281 | Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", | 2290 | Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", |
2282 | f1, f2, Zsize + (*sp)->len, again); | 2291 | f1, f2, Zsize + (*sp)->len, again); |
2283 | /* HDLC */ | 2292 | /* HDLC */ |
2284 | if ((Zsize + (*sp)->len) > (maxlen + 3)) { | 2293 | if ((Zsize + (*sp)->len) > maxlen) { |
2285 | if (debug & DEBUG_HFCMULTI_FIFO) | 2294 | if (debug & DEBUG_HFCMULTI_FIFO) |
2286 | printk(KERN_DEBUG | 2295 | printk(KERN_DEBUG |
2287 | "%s(card %d): hdlc-frame too large.\n", | 2296 | "%s(card %d): hdlc-frame too large.\n", |
@@ -2351,24 +2360,7 @@ next_frame: | |||
2351 | /* there is an incomplete frame */ | 2360 | /* there is an incomplete frame */ |
2352 | } else { | 2361 | } else { |
2353 | /* transparent */ | 2362 | /* transparent */ |
2354 | if (Zsize > skb_tailroom(*sp)) | ||
2355 | Zsize = skb_tailroom(*sp); | ||
2356 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); | 2363 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); |
2357 | if (((*sp)->len) < MISDN_COPY_SIZE) { | ||
2358 | skb = *sp; | ||
2359 | *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); | ||
2360 | if (*sp) { | ||
2361 | memcpy(skb_put(*sp, skb->len), | ||
2362 | skb->data, skb->len); | ||
2363 | skb_trim(skb, 0); | ||
2364 | } else { | ||
2365 | printk(KERN_DEBUG "%s: No mem\n", __func__); | ||
2366 | *sp = skb; | ||
2367 | skb = NULL; | ||
2368 | } | ||
2369 | } else { | ||
2370 | skb = NULL; | ||
2371 | } | ||
2372 | if (debug & DEBUG_HFCMULTI_FIFO) | 2364 | if (debug & DEBUG_HFCMULTI_FIFO) |
2373 | printk(KERN_DEBUG | 2365 | printk(KERN_DEBUG |
2374 | "%s(card %d): fifo(%d) reading %d bytes " | 2366 | "%s(card %d): fifo(%d) reading %d bytes " |
@@ -2376,7 +2368,6 @@ next_frame: | |||
2376 | __func__, hc->id + 1, ch, Zsize, z1, z2); | 2368 | __func__, hc->id + 1, ch, Zsize, z1, z2); |
2377 | /* only bch is transparent */ | 2369 | /* only bch is transparent */ |
2378 | recv_Bchannel(bch, hc->chan[ch].Zfill); | 2370 | recv_Bchannel(bch, hc->chan[ch].Zfill); |
2379 | *sp = skb; | ||
2380 | } | 2371 | } |
2381 | } | 2372 | } |
2382 | 2373 | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 123e8e5e57be..0622e05ae066 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c | |||
@@ -577,8 +577,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, | |||
577 | fcnt_tx = B_FIFO_SIZE - fcnt_tx; | 577 | fcnt_tx = B_FIFO_SIZE - fcnt_tx; |
578 | /* remaining bytes to send (bytes in tx-fifo) */ | 578 | /* remaining bytes to send (bytes in tx-fifo) */ |
579 | 579 | ||
580 | bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC); | 580 | maxlen = bchannel_get_rxbuf(bch, fcnt_rx); |
581 | if (bch->rx_skb) { | 581 | if (maxlen < 0) { |
582 | pr_warning("B%d: No bufferspace for %d bytes\n", | ||
583 | bch->nr, fcnt_rx); | ||
584 | } else { | ||
582 | ptr = skb_put(bch->rx_skb, fcnt_rx); | 585 | ptr = skb_put(bch->rx_skb, fcnt_rx); |
583 | if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) | 586 | if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) |
584 | maxlen = fcnt_rx; /* complete transfer */ | 587 | maxlen = fcnt_rx; /* complete transfer */ |
@@ -597,9 +600,7 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, | |||
597 | memcpy(ptr, ptr1, fcnt_rx); /* rest */ | 600 | memcpy(ptr, ptr1, fcnt_rx); /* rest */ |
598 | } | 601 | } |
599 | recv_Bchannel(bch, fcnt_tx); /* bch, id */ | 602 | recv_Bchannel(bch, fcnt_tx); /* bch, id */ |
600 | } else | 603 | } |
601 | printk(KERN_WARNING "HFCPCI: receive out of memory\n"); | ||
602 | |||
603 | *z2r = cpu_to_le16(new_z2); /* new position */ | 604 | *z2r = cpu_to_le16(new_z2); /* new position */ |
604 | } | 605 | } |
605 | 606 | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 919ecccb9939..6bb689b8d66f 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c | |||
@@ -860,7 +860,16 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, | |||
860 | hdlc = 1; | 860 | hdlc = 1; |
861 | } | 861 | } |
862 | if (fifo->bch) { | 862 | if (fifo->bch) { |
863 | maxlen = bchannel_get_rxbuf(fifo->bch, len); | ||
863 | rx_skb = fifo->bch->rx_skb; | 864 | rx_skb = fifo->bch->rx_skb; |
865 | if (maxlen < 0) { | ||
866 | if (rx_skb) | ||
867 | skb_trim(rx_skb, 0); | ||
868 | pr_warning("%s.B%d: No bufferspace for %d bytes\n", | ||
869 | hw->name, fifo->bch->nr, len); | ||
870 | spin_unlock(&hw->lock); | ||
871 | return; | ||
872 | } | ||
864 | maxlen = fifo->bch->maxlen; | 873 | maxlen = fifo->bch->maxlen; |
865 | hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); | 874 | hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); |
866 | } | 875 | } |
@@ -870,25 +879,22 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, | |||
870 | hdlc = 1; | 879 | hdlc = 1; |
871 | } | 880 | } |
872 | 881 | ||
873 | if (!rx_skb) { | ||
874 | rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); | ||
875 | if (rx_skb) { | ||
876 | if (fifo->dch) | ||
877 | fifo->dch->rx_skb = rx_skb; | ||
878 | if (fifo->bch) | ||
879 | fifo->bch->rx_skb = rx_skb; | ||
880 | if (fifo->ech) | ||
881 | fifo->ech->rx_skb = rx_skb; | ||
882 | skb_trim(rx_skb, 0); | ||
883 | } else { | ||
884 | printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", | ||
885 | hw->name, __func__); | ||
886 | spin_unlock(&hw->lock); | ||
887 | return; | ||
888 | } | ||
889 | } | ||
890 | |||
891 | if (fifo->dch || fifo->ech) { | 882 | if (fifo->dch || fifo->ech) { |
883 | if (!rx_skb) { | ||
884 | rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); | ||
885 | if (rx_skb) { | ||
886 | if (fifo->dch) | ||
887 | fifo->dch->rx_skb = rx_skb; | ||
888 | if (fifo->ech) | ||
889 | fifo->ech->rx_skb = rx_skb; | ||
890 | skb_trim(rx_skb, 0); | ||
891 | } else { | ||
892 | printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", | ||
893 | hw->name, __func__); | ||
894 | spin_unlock(&hw->lock); | ||
895 | return; | ||
896 | } | ||
897 | } | ||
892 | /* D/E-Channel SKB range check */ | 898 | /* D/E-Channel SKB range check */ |
893 | if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { | 899 | if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { |
894 | printk(KERN_DEBUG "%s: %s: sbk mem exceeded " | 900 | printk(KERN_DEBUG "%s: %s: sbk mem exceeded " |
@@ -898,16 +904,6 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, | |||
898 | spin_unlock(&hw->lock); | 904 | spin_unlock(&hw->lock); |
899 | return; | 905 | return; |
900 | } | 906 | } |
901 | } else if (fifo->bch) { | ||
902 | /* B-Channel SKB range check */ | ||
903 | if ((rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) { | ||
904 | printk(KERN_DEBUG "%s: %s: sbk mem exceeded " | ||
905 | "for fifo(%d) HFCUSB_B_RX\n", | ||
906 | hw->name, __func__, fifon); | ||
907 | skb_trim(rx_skb, 0); | ||
908 | spin_unlock(&hw->lock); | ||
909 | return; | ||
910 | } | ||
911 | } | 907 | } |
912 | 908 | ||
913 | memcpy(skb_put(rx_skb, len), data, len); | 909 | memcpy(skb_put(rx_skb, len), data, len); |
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index e4b6d8d51aae..7d109ed35366 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c | |||
@@ -933,22 +933,16 @@ static void | |||
933 | hscx_empty_fifo(struct hscx_hw *hscx, u8 count) | 933 | hscx_empty_fifo(struct hscx_hw *hscx, u8 count) |
934 | { | 934 | { |
935 | u8 *p; | 935 | u8 *p; |
936 | int maxlen; | ||
936 | 937 | ||
937 | pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); | 938 | pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); |
938 | if (!hscx->bch.rx_skb) { | 939 | maxlen = bchannel_get_rxbuf(&hscx->bch, count); |
939 | hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC); | 940 | if (maxlen < 0) { |
940 | if (!hscx->bch.rx_skb) { | ||
941 | pr_info("%s: B receive out of memory\n", | ||
942 | hscx->ip->name); | ||
943 | hscx_cmdr(hscx, 0x80); /* RMC */ | ||
944 | return; | ||
945 | } | ||
946 | } | ||
947 | if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) { | ||
948 | pr_debug("%s: overrun %d\n", hscx->ip->name, | ||
949 | hscx->bch.rx_skb->len + count); | ||
950 | skb_trim(hscx->bch.rx_skb, 0); | ||
951 | hscx_cmdr(hscx, 0x80); /* RMC */ | 941 | hscx_cmdr(hscx, 0x80); /* RMC */ |
942 | if (hscx->bch.rx_skb) | ||
943 | skb_trim(hscx->bch.rx_skb, 0); | ||
944 | pr_warning("%s.B%d: No bufferspace for %d bytes\n", | ||
945 | hscx->ip->name, hscx->bch.nr, count); | ||
952 | return; | 946 | return; |
953 | } | 947 | } |
954 | p = skb_put(hscx->bch.rx_skb, count); | 948 | p = skb_put(hscx->bch.rx_skb, count); |
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 9deea88c994e..4169bb2db19c 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c | |||
@@ -421,7 +421,8 @@ deliver_status(struct isar_ch *ch, int status) | |||
421 | static inline void | 421 | static inline void |
422 | isar_rcv_frame(struct isar_ch *ch) | 422 | isar_rcv_frame(struct isar_ch *ch) |
423 | { | 423 | { |
424 | u8 *ptr; | 424 | u8 *ptr; |
425 | int maxlen; | ||
425 | 426 | ||
426 | if (!ch->is->clsb) { | 427 | if (!ch->is->clsb) { |
427 | pr_debug("%s; ISAR zero len frame\n", ch->is->name); | 428 | pr_debug("%s; ISAR zero len frame\n", ch->is->name); |
@@ -437,36 +438,22 @@ isar_rcv_frame(struct isar_ch *ch) | |||
437 | case ISDN_P_B_RAW: | 438 | case ISDN_P_B_RAW: |
438 | case ISDN_P_B_L2DTMF: | 439 | case ISDN_P_B_L2DTMF: |
439 | case ISDN_P_B_MODEM_ASYNC: | 440 | case ISDN_P_B_MODEM_ASYNC: |
440 | if (!ch->bch.rx_skb) { | 441 | maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); |
441 | ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, | 442 | if (maxlen < 0) { |
442 | GFP_ATOMIC); | 443 | pr_warning("%s.B%d: No bufferspace for %d bytes\n", |
443 | if (unlikely(!ch->bch.rx_skb)) { | 444 | ch->is->name, ch->bch.nr, ch->is->clsb); |
444 | pr_info("%s: B receive out of memory\n", | 445 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); |
445 | ch->is->name); | 446 | break; |
446 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
447 | break; | ||
448 | } | ||
449 | } | 447 | } |
450 | rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); | 448 | rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); |
451 | recv_Bchannel(&ch->bch, 0); | 449 | recv_Bchannel(&ch->bch, 0); |
452 | break; | 450 | break; |
453 | case ISDN_P_B_HDLC: | 451 | case ISDN_P_B_HDLC: |
454 | if (!ch->bch.rx_skb) { | 452 | maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); |
455 | ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, | 453 | if (maxlen < 0) { |
456 | GFP_ATOMIC); | 454 | pr_warning("%s.B%d: No bufferspace for %d bytes\n", |
457 | if (unlikely(!ch->bch.rx_skb)) { | 455 | ch->is->name, ch->bch.nr, ch->is->clsb); |
458 | pr_info("%s: B receive out of memory\n", | ||
459 | ch->is->name); | ||
460 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | ||
461 | break; | ||
462 | } | ||
463 | } | ||
464 | if ((ch->bch.rx_skb->len + ch->is->clsb) > | ||
465 | (ch->bch.maxlen + 2)) { | ||
466 | pr_debug("%s: incoming packet too large\n", | ||
467 | ch->is->name); | ||
468 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); | 456 | ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); |
469 | skb_trim(ch->bch.rx_skb, 0); | ||
470 | break; | 457 | break; |
471 | } | 458 | } |
472 | if (ch->is->cmsb & HDLC_ERROR) { | 459 | if (ch->is->cmsb & HDLC_ERROR) { |
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index da13b07cd856..3f28057e725e 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c | |||
@@ -386,24 +386,16 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) | |||
386 | bc->bch.nr, idx); | 386 | bc->bch.nr, idx); |
387 | } | 387 | } |
388 | bc->lastrx = idx; | 388 | bc->lastrx = idx; |
389 | if (!bc->bch.rx_skb) { | 389 | stat = bchannel_get_rxbuf(&bc->bch, cnt); |
390 | bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC); | 390 | /* only transparent use the count here, HDLC overun is detected later */ |
391 | if (!bc->bch.rx_skb) { | 391 | if (stat == ENOMEM) { |
392 | pr_info("%s: B%1d receive out of memory\n", | 392 | pr_warning("%s.B%d: No memory for %d bytes\n", |
393 | card->name, bc->bch.nr); | 393 | card->name, bc->bch.nr, cnt); |
394 | return; | 394 | return; |
395 | } | ||
396 | } | 395 | } |
397 | 396 | if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) | |
398 | if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { | ||
399 | if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) { | ||
400 | pr_debug("%s: B%1d overrun %d\n", card->name, | ||
401 | bc->bch.nr, bc->bch.rx_skb->len + cnt); | ||
402 | skb_trim(bc->bch.rx_skb, 0); | ||
403 | return; | ||
404 | } | ||
405 | p = skb_put(bc->bch.rx_skb, cnt); | 397 | p = skb_put(bc->bch.rx_skb, cnt); |
406 | } else | 398 | else |
407 | p = bc->hrbuf; | 399 | p = bc->hrbuf; |
408 | 400 | ||
409 | for (i = 0; i < cnt; i++) { | 401 | for (i = 0; i < cnt; i++) { |
@@ -414,48 +406,45 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) | |||
414 | idx = 0; | 406 | idx = 0; |
415 | p[i] = val & 0xff; | 407 | p[i] = val & 0xff; |
416 | } | 408 | } |
409 | |||
410 | if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { | ||
411 | recv_Bchannel(&bc->bch, 0); | ||
412 | return; | ||
413 | } | ||
414 | |||
417 | pn = bc->hrbuf; | 415 | pn = bc->hrbuf; |
418 | next_frame: | 416 | while (cnt > 0) { |
419 | if (test_bit(FLG_HDLC, &bc->bch.Flags)) { | ||
420 | stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, | 417 | stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, |
421 | bc->bch.rx_skb->data, bc->bch.maxlen); | 418 | bc->bch.rx_skb->data, bc->bch.maxlen); |
422 | if (stat > 0) /* valid frame received */ | 419 | if (stat > 0) { /* valid frame received */ |
423 | p = skb_put(bc->bch.rx_skb, stat); | 420 | p = skb_put(bc->bch.rx_skb, stat); |
424 | else if (stat == -HDLC_CRC_ERROR) | 421 | if (debug & DEBUG_HW_BFIFO) { |
422 | snprintf(card->log, LOG_SIZE, | ||
423 | "B%1d-recv %s %d ", bc->bch.nr, | ||
424 | card->name, stat); | ||
425 | print_hex_dump_bytes(card->log, | ||
426 | DUMP_PREFIX_OFFSET, p, | ||
427 | stat); | ||
428 | } | ||
429 | recv_Bchannel(&bc->bch, 0); | ||
430 | stat = bchannel_get_rxbuf(&bc->bch, bc->bch.maxlen); | ||
431 | if (stat < 0) { | ||
432 | pr_warning("%s.B%d: No memory for %d bytes\n", | ||
433 | card->name, bc->bch.nr, cnt); | ||
434 | return; | ||
435 | } | ||
436 | } else if (stat == -HDLC_CRC_ERROR) { | ||
425 | pr_info("%s: B%1d receive frame CRC error\n", | 437 | pr_info("%s: B%1d receive frame CRC error\n", |
426 | card->name, bc->bch.nr); | 438 | card->name, bc->bch.nr); |
427 | else if (stat == -HDLC_FRAMING_ERROR) | 439 | } else if (stat == -HDLC_FRAMING_ERROR) { |
428 | pr_info("%s: B%1d receive framing error\n", | 440 | pr_info("%s: B%1d receive framing error\n", |
429 | card->name, bc->bch.nr); | 441 | card->name, bc->bch.nr); |
430 | else if (stat == -HDLC_LENGTH_ERROR) | 442 | } else if (stat == -HDLC_LENGTH_ERROR) { |
431 | pr_info("%s: B%1d receive frame too long (> %d)\n", | 443 | pr_info("%s: B%1d receive frame too long (> %d)\n", |
432 | card->name, bc->bch.nr, bc->bch.maxlen); | 444 | card->name, bc->bch.nr, bc->bch.maxlen); |
433 | } else | ||
434 | stat = cnt; | ||
435 | |||
436 | if (stat > 0) { | ||
437 | if (debug & DEBUG_HW_BFIFO) { | ||
438 | snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ", | ||
439 | bc->bch.nr, card->name, stat); | ||
440 | print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, | ||
441 | p, stat); | ||
442 | } | 445 | } |
443 | recv_Bchannel(&bc->bch, 0); | ||
444 | } | ||
445 | if (test_bit(FLG_HDLC, &bc->bch.Flags)) { | ||
446 | pn += i; | 446 | pn += i; |
447 | cnt -= i; | 447 | cnt -= i; |
448 | if (!bc->bch.rx_skb) { | ||
449 | bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, | ||
450 | GFP_ATOMIC); | ||
451 | if (!bc->bch.rx_skb) { | ||
452 | pr_info("%s: B%1d receive out of memory\n", | ||
453 | card->name, bc->bch.nr); | ||
454 | return; | ||
455 | } | ||
456 | } | ||
457 | if (cnt > 0) | ||
458 | goto next_frame; | ||
459 | } | 448 | } |
460 | } | 449 | } |
461 | 450 | ||
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index f1c0bf1ac689..8324b20c7f16 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c | |||
@@ -465,6 +465,7 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) | |||
465 | { | 465 | { |
466 | struct w6692_hw *card = wch->bch.hw; | 466 | struct w6692_hw *card = wch->bch.hw; |
467 | u8 *ptr; | 467 | u8 *ptr; |
468 | int maxlen; | ||
468 | 469 | ||
469 | pr_debug("%s: empty_Bfifo %d\n", card->name, count); | 470 | pr_debug("%s: empty_Bfifo %d\n", card->name, count); |
470 | if (unlikely(wch->bch.state == ISDN_P_NONE)) { | 471 | if (unlikely(wch->bch.state == ISDN_P_NONE)) { |
@@ -474,20 +475,13 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) | |||
474 | skb_trim(wch->bch.rx_skb, 0); | 475 | skb_trim(wch->bch.rx_skb, 0); |
475 | return; | 476 | return; |
476 | } | 477 | } |
477 | if (!wch->bch.rx_skb) { | 478 | maxlen = bchannel_get_rxbuf(&wch->bch, count); |
478 | wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); | 479 | if (maxlen < 0) { |
479 | if (unlikely(!wch->bch.rx_skb)) { | ||
480 | pr_info("%s: B receive out of memory\n", card->name); | ||
481 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | | ||
482 | W_B_CMDR_RACT); | ||
483 | return; | ||
484 | } | ||
485 | } | ||
486 | if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { | ||
487 | pr_debug("%s: empty_Bfifo incoming packet too large\n", | ||
488 | card->name); | ||
489 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); | 480 | WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); |
490 | skb_trim(wch->bch.rx_skb, 0); | 481 | if (wch->bch.rx_skb) |
482 | skb_trim(wch->bch.rx_skb, 0); | ||
483 | pr_warning("%s.B%d: No bufferspace for %d bytes\n", | ||
484 | card->name, wch->bch.nr, count); | ||
491 | return; | 485 | return; |
492 | } | 486 | } |
493 | ptr = skb_put(wch->bch.rx_skb, count); | 487 | ptr = skb_put(wch->bch.rx_skb, count); |
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 5c5ab478f66a..3c2145d8c3f8 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c | |||
@@ -201,20 +201,30 @@ recv_Bchannel(struct bchannel *bch, unsigned int id) | |||
201 | { | 201 | { |
202 | struct mISDNhead *hh; | 202 | struct mISDNhead *hh; |
203 | 203 | ||
204 | hh = mISDN_HEAD_P(bch->rx_skb); | 204 | /* if allocation did fail upper functions still may call us */ |
205 | hh->prim = PH_DATA_IND; | 205 | if (unlikely(!bch->rx_skb)) |
206 | hh->id = id; | ||
207 | if (bch->rcount >= 64) { | ||
208 | printk(KERN_WARNING "B-channel %p receive queue overflow, " | ||
209 | "flushing!\n", bch); | ||
210 | skb_queue_purge(&bch->rqueue); | ||
211 | bch->rcount = 0; | ||
212 | return; | 206 | return; |
207 | if (unlikely(!bch->rx_skb->len)) { | ||
208 | /* we have no data to send - this may happen after recovery | ||
209 | * from overflow or too small allocation. | ||
210 | * We need to free the buffer here */ | ||
211 | dev_kfree_skb(bch->rx_skb); | ||
212 | bch->rx_skb = NULL; | ||
213 | } else { | ||
214 | hh = mISDN_HEAD_P(bch->rx_skb); | ||
215 | hh->prim = PH_DATA_IND; | ||
216 | hh->id = id; | ||
217 | if (bch->rcount >= 64) { | ||
218 | printk(KERN_WARNING | ||
219 | "B%d receive queue overflow - flushing!\n", | ||
220 | bch->nr); | ||
221 | skb_queue_purge(&bch->rqueue); | ||
222 | } | ||
223 | bch->rcount++; | ||
224 | skb_queue_tail(&bch->rqueue, bch->rx_skb); | ||
225 | bch->rx_skb = NULL; | ||
226 | schedule_event(bch, FLG_RECVQUEUE); | ||
213 | } | 227 | } |
214 | bch->rcount++; | ||
215 | skb_queue_tail(&bch->rqueue, bch->rx_skb); | ||
216 | bch->rx_skb = NULL; | ||
217 | schedule_event(bch, FLG_RECVQUEUE); | ||
218 | } | 228 | } |
219 | EXPORT_SYMBOL(recv_Bchannel); | 229 | EXPORT_SYMBOL(recv_Bchannel); |
220 | 230 | ||
@@ -399,3 +409,44 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) | |||
399 | } | 409 | } |
400 | } | 410 | } |
401 | EXPORT_SYMBOL(bchannel_senddata); | 411 | EXPORT_SYMBOL(bchannel_senddata); |
412 | |||
413 | /* The function allocates a new receive skb on demand with a size for the | ||
414 | * requirements of the current protocol. It returns the tailroom of the | ||
415 | * receive skb or an error. | ||
416 | */ | ||
417 | int | ||
418 | bchannel_get_rxbuf(struct bchannel *bch, int reqlen) | ||
419 | { | ||
420 | int len; | ||
421 | |||
422 | if (bch->rx_skb) { | ||
423 | len = skb_tailroom(bch->rx_skb); | ||
424 | if (len < reqlen) { | ||
425 | pr_warning("B%d no space for %d (only %d) bytes\n", | ||
426 | bch->nr, reqlen, len); | ||
427 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { | ||
428 | /* send what we have now and try a new buffer */ | ||
429 | recv_Bchannel(bch, 0); | ||
430 | } else { | ||
431 | /* on HDLC we have to drop too big frames */ | ||
432 | return -EMSGSIZE; | ||
433 | } | ||
434 | } else { | ||
435 | return len; | ||
436 | } | ||
437 | } | ||
438 | if (unlikely(reqlen > bch->maxlen)) | ||
439 | return -EMSGSIZE; | ||
440 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
441 | len = reqlen; | ||
442 | else /* with HDLC we do not know the length yet */ | ||
443 | len = bch->maxlen; | ||
444 | bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
445 | if (!bch->rx_skb) { | ||
446 | pr_warning("B%d receive no memory for %d bytes\n", | ||
447 | bch->nr, len); | ||
448 | len = -ENOMEM; | ||
449 | } | ||
450 | return len; | ||
451 | } | ||
452 | EXPORT_SYMBOL(bchannel_get_rxbuf); | ||