aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2014-02-20 12:55:55 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-02-20 15:53:20 -0500
commit1eb43018673e735ea9cd756970f4e71ca01a5f21 (patch)
treef07937918d7aada114b113c422dc7722420995c7
parent21f8aaee0c62708654988ce092838aa7df4d25d8 (diff)
brcmfmac: fix txglomming scatter-gather packet transfers
The driver concatenates multiple packets in one MMC transfer. For scatter-gather to work the total length need to be multiple of 512 bytes. A pre-allocated buffer was used to add padding to accomplish that. However, the length was not properly set and it was freed after the first transfer causing a crash. Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c14
1 files changed, 4 insertions, 10 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 3e991897d7ca..119ee6eaf1c3 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -457,7 +457,6 @@ struct brcmf_sdio {
457 457
458 u8 tx_hdrlen; /* sdio bus header length for tx packet */ 458 u8 tx_hdrlen; /* sdio bus header length for tx packet */
459 bool txglom; /* host tx glomming enable flag */ 459 bool txglom; /* host tx glomming enable flag */
460 struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */
461 u16 head_align; /* buffer pointer alignment */ 460 u16 head_align; /* buffer pointer alignment */
462 u16 sgentry_align; /* scatter-gather buffer alignment */ 461 u16 sgentry_align; /* scatter-gather buffer alignment */
463}; 462};
@@ -1944,9 +1943,8 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
1944 if (lastfrm && chain_pad) 1943 if (lastfrm && chain_pad)
1945 tail_pad += blksize - chain_pad; 1944 tail_pad += blksize - chain_pad;
1946 if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { 1945 if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
1947 pkt_pad = bus->txglom_sgpad; 1946 pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
1948 if (pkt_pad == NULL) 1947 bus->head_align);
1949 brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
1950 if (pkt_pad == NULL) 1948 if (pkt_pad == NULL)
1951 return -ENOMEM; 1949 return -ENOMEM;
1952 ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); 1950 ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
@@ -1957,6 +1955,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
1957 tail_chop); 1955 tail_chop);
1958 *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; 1956 *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
1959 skb_trim(pkt, pkt->len - tail_chop); 1957 skb_trim(pkt, pkt->len - tail_chop);
1958 skb_trim(pkt_pad, tail_pad + tail_chop);
1960 __skb_queue_after(pktq, pkt, pkt_pad); 1959 __skb_queue_after(pktq, pkt, pkt_pad);
1961 } else { 1960 } else {
1962 ntail = pkt->data_len + tail_pad - 1961 ntail = pkt->data_len + tail_pad -
@@ -2011,7 +2010,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
2011 return ret; 2010 return ret;
2012 head_pad = (u16)ret; 2011 head_pad = (u16)ret;
2013 if (head_pad) 2012 if (head_pad)
2014 memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen); 2013 memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
2015 2014
2016 total_len += pkt_next->len; 2015 total_len += pkt_next->len;
2017 2016
@@ -3486,10 +3485,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
3486 bus->txglom = false; 3485 bus->txglom = false;
3487 value = 1; 3486 value = 1;
3488 pad_size = bus->sdiodev->func[2]->cur_blksize << 1; 3487 pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
3489 bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
3490 if (!bus->txglom_sgpad)
3491 brcmf_err("allocating txglom padding skb failed, reduced performance\n");
3492
3493 err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", 3488 err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
3494 &value, sizeof(u32)); 3489 &value, sizeof(u32));
3495 if (err < 0) { 3490 if (err < 0) {
@@ -4053,7 +4048,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
4053 brcmf_sdio_chip_detach(&bus->ci); 4048 brcmf_sdio_chip_detach(&bus->ci);
4054 } 4049 }
4055 4050
4056 brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
4057 kfree(bus->rxbuf); 4051 kfree(bus->rxbuf);
4058 kfree(bus->hdrbuf); 4052 kfree(bus->hdrbuf);
4059 kfree(bus); 4053 kfree(bus);