diff options
author | Arend van Spriel <arend@broadcom.com> | 2014-02-20 12:55:55 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-02-20 15:53:20 -0500 |
commit | 1eb43018673e735ea9cd756970f4e71ca01a5f21 (patch) | |
tree | f07937918d7aada114b113c422dc7722420995c7 | |
parent | 21f8aaee0c62708654988ce092838aa7df4d25d8 (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.c | 14 |
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); |