diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-03-04 13:05:12 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-03-04 13:05:12 -0500 |
commit | f3b6a488a670f1be2666ab97e31dcfc0b1648884 (patch) | |
tree | d8d2431f21d4371c907dec075926e86840e86d1e | |
parent | c14c5d99a453af6b86f15aca8fe9005b2b8f3b26 (diff) | |
parent | adb07df1e039e9fe43e66aeea8b4771f83659dbb (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
Conflicts:
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/mwifiex/pcie.c
33 files changed, 303 insertions, 178 deletions
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index d6bc7cb61bfb..1a2973b7acf2 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -110,7 +110,7 @@ ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) | |||
110 | ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); | 110 | ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); |
111 | 111 | ||
112 | if (ah->ah_version == AR5K_AR5210) { | 112 | if (ah->ah_version == AR5K_AR5210) { |
113 | srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; | 113 | srev = (ath5k_hw_reg_read(ah, AR5K_PHY(256)) >> 28) & 0xf; |
114 | ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; | 114 | ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; |
115 | } else { | 115 | } else { |
116 | srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; | 116 | srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 1cc13569b17b..1b6b4d0cfa97 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h | |||
@@ -57,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { | |||
57 | {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e}, | 57 | {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e}, |
58 | {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 58 | {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
59 | {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, | 59 | {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, |
60 | {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, | 60 | {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5}, |
61 | {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, | 61 | {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, |
62 | {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, | 62 | {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, |
63 | {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, | 63 | {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, |
@@ -96,7 +96,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { | |||
96 | {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, | 96 | {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, |
97 | {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 97 | {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
98 | {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, | 98 | {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, |
99 | {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, | 99 | {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa}, |
100 | {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, | 100 | {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, |
101 | }; | 101 | }; |
102 | 102 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5db01b4212c8..2509c2ff0828 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -1533,7 +1533,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav); | |||
1533 | bool ath9k_hw_check_alive(struct ath_hw *ah) | 1533 | bool ath9k_hw_check_alive(struct ath_hw *ah) |
1534 | { | 1534 | { |
1535 | int count = 50; | 1535 | int count = 50; |
1536 | u32 reg; | 1536 | u32 reg, last_val; |
1537 | 1537 | ||
1538 | if (AR_SREV_9300(ah)) | 1538 | if (AR_SREV_9300(ah)) |
1539 | return !ath9k_hw_detect_mac_hang(ah); | 1539 | return !ath9k_hw_detect_mac_hang(ah); |
@@ -1541,9 +1541,13 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) | |||
1541 | if (AR_SREV_9285_12_OR_LATER(ah)) | 1541 | if (AR_SREV_9285_12_OR_LATER(ah)) |
1542 | return true; | 1542 | return true; |
1543 | 1543 | ||
1544 | last_val = REG_READ(ah, AR_OBS_BUS_1); | ||
1544 | do { | 1545 | do { |
1545 | reg = REG_READ(ah, AR_OBS_BUS_1); | 1546 | reg = REG_READ(ah, AR_OBS_BUS_1); |
1547 | if (reg != last_val) | ||
1548 | return true; | ||
1546 | 1549 | ||
1550 | last_val = reg; | ||
1547 | if ((reg & 0x7E7FFFEF) == 0x00702400) | 1551 | if ((reg & 0x7E7FFFEF) == 0x00702400) |
1548 | continue; | 1552 | continue; |
1549 | 1553 | ||
@@ -1555,6 +1559,8 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) | |||
1555 | default: | 1559 | default: |
1556 | return true; | 1560 | return true; |
1557 | } | 1561 | } |
1562 | |||
1563 | udelay(1); | ||
1558 | } while (count-- > 0); | 1564 | } while (count-- > 0); |
1559 | 1565 | ||
1560 | return false; | 1566 | return false; |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 076dae1e5ab7..6c9accdb52e4 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc, | |||
732 | return NULL; | 732 | return NULL; |
733 | 733 | ||
734 | /* | 734 | /* |
735 | * mark descriptor as zero-length and set the 'more' | 735 | * Re-check previous descriptor, in case it has been filled |
736 | * flag to ensure that both buffers get discarded | 736 | * in the mean time. |
737 | */ | 737 | */ |
738 | rs->rs_datalen = 0; | 738 | ret = ath9k_hw_rxprocdesc(ah, ds, rs); |
739 | rs->rs_more = true; | 739 | if (ret == -EINPROGRESS) { |
740 | /* | ||
741 | * mark descriptor as zero-length and set the 'more' | ||
742 | * flag to ensure that both buffers get discarded | ||
743 | */ | ||
744 | rs->rs_datalen = 0; | ||
745 | rs->rs_more = true; | ||
746 | } | ||
740 | } | 747 | } |
741 | 748 | ||
742 | list_del(&bf->list); | 749 | list_del(&bf->list); |
@@ -787,32 +794,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
787 | struct ath_common *common = ath9k_hw_common(ah); | 794 | struct ath_common *common = ath9k_hw_common(ah); |
788 | struct ieee80211_hdr *hdr; | 795 | struct ieee80211_hdr *hdr; |
789 | bool discard_current = sc->rx.discard_next; | 796 | bool discard_current = sc->rx.discard_next; |
790 | int ret = 0; | ||
791 | 797 | ||
792 | /* | 798 | /* |
793 | * Discard corrupt descriptors which are marked in | 799 | * Discard corrupt descriptors which are marked in |
794 | * ath_get_next_rx_buf(). | 800 | * ath_get_next_rx_buf(). |
795 | */ | 801 | */ |
796 | sc->rx.discard_next = rx_stats->rs_more; | ||
797 | if (discard_current) | 802 | if (discard_current) |
798 | return -EINVAL; | 803 | goto corrupt; |
804 | |||
805 | sc->rx.discard_next = false; | ||
799 | 806 | ||
800 | /* | 807 | /* |
801 | * Discard zero-length packets. | 808 | * Discard zero-length packets. |
802 | */ | 809 | */ |
803 | if (!rx_stats->rs_datalen) { | 810 | if (!rx_stats->rs_datalen) { |
804 | RX_STAT_INC(rx_len_err); | 811 | RX_STAT_INC(rx_len_err); |
805 | return -EINVAL; | 812 | goto corrupt; |
806 | } | 813 | } |
807 | 814 | ||
808 | /* | 815 | /* |
809 | * rs_status follows rs_datalen so if rs_datalen is too large | 816 | * rs_status follows rs_datalen so if rs_datalen is too large |
810 | * we can take a hint that hardware corrupted it, so ignore | 817 | * we can take a hint that hardware corrupted it, so ignore |
811 | * those frames. | 818 | * those frames. |
812 | */ | 819 | */ |
813 | if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { | 820 | if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { |
814 | RX_STAT_INC(rx_len_err); | 821 | RX_STAT_INC(rx_len_err); |
815 | return -EINVAL; | 822 | goto corrupt; |
816 | } | 823 | } |
817 | 824 | ||
818 | /* Only use status info from the last fragment */ | 825 | /* Only use status info from the last fragment */ |
@@ -826,10 +833,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
826 | * This is different from the other corrupt descriptor | 833 | * This is different from the other corrupt descriptor |
827 | * condition handled above. | 834 | * condition handled above. |
828 | */ | 835 | */ |
829 | if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) { | 836 | if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) |
830 | ret = -EINVAL; | 837 | goto corrupt; |
831 | goto exit; | ||
832 | } | ||
833 | 838 | ||
834 | hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); | 839 | hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); |
835 | 840 | ||
@@ -845,18 +850,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
845 | if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) | 850 | if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) |
846 | RX_STAT_INC(rx_spectral); | 851 | RX_STAT_INC(rx_spectral); |
847 | 852 | ||
848 | ret = -EINVAL; | 853 | return -EINVAL; |
849 | goto exit; | ||
850 | } | 854 | } |
851 | 855 | ||
852 | /* | 856 | /* |
853 | * everything but the rate is checked here, the rate check is done | 857 | * everything but the rate is checked here, the rate check is done |
854 | * separately to avoid doing two lookups for a rate for each frame. | 858 | * separately to avoid doing two lookups for a rate for each frame. |
855 | */ | 859 | */ |
856 | if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) { | 860 | if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) |
857 | ret = -EINVAL; | 861 | return -EINVAL; |
858 | goto exit; | ||
859 | } | ||
860 | 862 | ||
861 | if (ath_is_mybeacon(common, hdr)) { | 863 | if (ath_is_mybeacon(common, hdr)) { |
862 | RX_STAT_INC(rx_beacons); | 864 | RX_STAT_INC(rx_beacons); |
@@ -866,10 +868,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
866 | /* | 868 | /* |
867 | * This shouldn't happen, but have a safety check anyway. | 869 | * This shouldn't happen, but have a safety check anyway. |
868 | */ | 870 | */ |
869 | if (WARN_ON(!ah->curchan)) { | 871 | if (WARN_ON(!ah->curchan)) |
870 | ret = -EINVAL; | 872 | return -EINVAL; |
871 | goto exit; | ||
872 | } | ||
873 | 873 | ||
874 | if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { | 874 | if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { |
875 | /* | 875 | /* |
@@ -879,8 +879,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
879 | ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", | 879 | ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", |
880 | rx_stats->rs_rate); | 880 | rx_stats->rs_rate); |
881 | RX_STAT_INC(rx_rate_err); | 881 | RX_STAT_INC(rx_rate_err); |
882 | ret =-EINVAL; | 882 | return -EINVAL; |
883 | goto exit; | ||
884 | } | 883 | } |
885 | 884 | ||
886 | ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); | 885 | ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); |
@@ -896,9 +895,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
896 | sc->rx.num_pkts++; | 895 | sc->rx.num_pkts++; |
897 | #endif | 896 | #endif |
898 | 897 | ||
899 | exit: | 898 | return 0; |
900 | sc->rx.discard_next = false; | 899 | |
901 | return ret; | 900 | corrupt: |
901 | sc->rx.discard_next = rx_stats->rs_more; | ||
902 | return -EINVAL; | ||
902 | } | 903 | } |
903 | 904 | ||
904 | /* | 905 | /* |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 306ea322c65d..fafacfed44ea 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -1445,14 +1445,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, | |||
1445 | for (tidno = 0, tid = &an->tid[tidno]; | 1445 | for (tidno = 0, tid = &an->tid[tidno]; |
1446 | tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { | 1446 | tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { |
1447 | 1447 | ||
1448 | if (!tid->sched) | ||
1449 | continue; | ||
1450 | |||
1451 | ac = tid->ac; | 1448 | ac = tid->ac; |
1452 | txq = ac->txq; | 1449 | txq = ac->txq; |
1453 | 1450 | ||
1454 | ath_txq_lock(sc, txq); | 1451 | ath_txq_lock(sc, txq); |
1455 | 1452 | ||
1453 | if (!tid->sched) { | ||
1454 | ath_txq_unlock(sc, txq); | ||
1455 | continue; | ||
1456 | } | ||
1457 | |||
1456 | buffered = ath_tid_has_buffered(tid); | 1458 | buffered = ath_tid_has_buffered(tid); |
1457 | 1459 | ||
1458 | tid->sched = false; | 1460 | tid->sched = false; |
@@ -2185,14 +2187,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
2185 | txq->stopped = true; | 2187 | txq->stopped = true; |
2186 | } | 2188 | } |
2187 | 2189 | ||
2190 | if (txctl->an) | ||
2191 | tid = ath_get_skb_tid(sc, txctl->an, skb); | ||
2192 | |||
2188 | if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { | 2193 | if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { |
2189 | ath_txq_unlock(sc, txq); | 2194 | ath_txq_unlock(sc, txq); |
2190 | txq = sc->tx.uapsdq; | 2195 | txq = sc->tx.uapsdq; |
2191 | ath_txq_lock(sc, txq); | 2196 | ath_txq_lock(sc, txq); |
2192 | } else if (txctl->an && | 2197 | } else if (txctl->an && |
2193 | ieee80211_is_data_present(hdr->frame_control)) { | 2198 | ieee80211_is_data_present(hdr->frame_control)) { |
2194 | tid = ath_get_skb_tid(sc, txctl->an, skb); | ||
2195 | |||
2196 | WARN_ON(tid->ac->txq != txctl->txq); | 2199 | WARN_ON(tid->ac->txq != txctl->txq); |
2197 | 2200 | ||
2198 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) | 2201 | if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index b5ded8a57cb0..5c2706e50775 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |||
@@ -482,7 +482,6 @@ struct brcmf_sdio { | |||
482 | 482 | ||
483 | u8 tx_hdrlen; /* sdio bus header length for tx packet */ | 483 | u8 tx_hdrlen; /* sdio bus header length for tx packet */ |
484 | bool txglom; /* host tx glomming enable flag */ | 484 | bool txglom; /* host tx glomming enable flag */ |
485 | struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */ | ||
486 | u16 head_align; /* buffer pointer alignment */ | 485 | u16 head_align; /* buffer pointer alignment */ |
487 | u16 sgentry_align; /* scatter-gather buffer alignment */ | 486 | u16 sgentry_align; /* scatter-gather buffer alignment */ |
488 | }; | 487 | }; |
@@ -2113,9 +2112,8 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, | |||
2113 | if (lastfrm && chain_pad) | 2112 | if (lastfrm && chain_pad) |
2114 | tail_pad += blksize - chain_pad; | 2113 | tail_pad += blksize - chain_pad; |
2115 | if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { | 2114 | if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { |
2116 | pkt_pad = bus->txglom_sgpad; | 2115 | pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop + |
2117 | if (pkt_pad == NULL) | 2116 | bus->head_align); |
2118 | brcmu_pkt_buf_get_skb(tail_pad + tail_chop); | ||
2119 | if (pkt_pad == NULL) | 2117 | if (pkt_pad == NULL) |
2120 | return -ENOMEM; | 2118 | return -ENOMEM; |
2121 | ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); | 2119 | ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); |
@@ -2126,6 +2124,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, | |||
2126 | tail_chop); | 2124 | tail_chop); |
2127 | *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; | 2125 | *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; |
2128 | skb_trim(pkt, pkt->len - tail_chop); | 2126 | skb_trim(pkt, pkt->len - tail_chop); |
2127 | skb_trim(pkt_pad, tail_pad + tail_chop); | ||
2129 | __skb_queue_after(pktq, pkt, pkt_pad); | 2128 | __skb_queue_after(pktq, pkt, pkt_pad); |
2130 | } else { | 2129 | } else { |
2131 | ntail = pkt->data_len + tail_pad - | 2130 | ntail = pkt->data_len + tail_pad - |
@@ -2180,7 +2179,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, | |||
2180 | return ret; | 2179 | return ret; |
2181 | head_pad = (u16)ret; | 2180 | head_pad = (u16)ret; |
2182 | if (head_pad) | 2181 | if (head_pad) |
2183 | memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen); | 2182 | memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad); |
2184 | 2183 | ||
2185 | total_len += pkt_next->len; | 2184 | total_len += pkt_next->len; |
2186 | 2185 | ||
@@ -3441,10 +3440,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev) | |||
3441 | bus->txglom = false; | 3440 | bus->txglom = false; |
3442 | value = 1; | 3441 | value = 1; |
3443 | pad_size = bus->sdiodev->func[2]->cur_blksize << 1; | 3442 | pad_size = bus->sdiodev->func[2]->cur_blksize << 1; |
3444 | bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size); | ||
3445 | if (!bus->txglom_sgpad) | ||
3446 | brcmf_err("allocating txglom padding skb failed, reduced performance\n"); | ||
3447 | |||
3448 | err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", | 3443 | err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", |
3449 | &value, sizeof(u32)); | 3444 | &value, sizeof(u32)); |
3450 | if (err < 0) { | 3445 | if (err < 0) { |
@@ -4167,7 +4162,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) | |||
4167 | brcmf_chip_detach(bus->ci); | 4162 | brcmf_chip_detach(bus->ci); |
4168 | } | 4163 | } |
4169 | 4164 | ||
4170 | brcmu_pkt_buf_free_skb(bus->txglom_sgpad); | ||
4171 | kfree(bus->rxbuf); | 4165 | kfree(bus->rxbuf); |
4172 | kfree(bus->hdrbuf); | 4166 | kfree(bus->hdrbuf); |
4173 | kfree(bus); | 4167 | kfree(bus); |
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index d36e252d2ccb..596525528f50 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c | |||
@@ -147,7 +147,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) | |||
147 | 147 | ||
148 | if (!sta->ap && sta->u.sta.challenge) | 148 | if (!sta->ap && sta->u.sta.challenge) |
149 | kfree(sta->u.sta.challenge); | 149 | kfree(sta->u.sta.challenge); |
150 | del_timer(&sta->timer); | 150 | del_timer_sync(&sta->timer); |
151 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | 151 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ |
152 | 152 | ||
153 | kfree(sta); | 153 | kfree(sta); |
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index aa7ad3a7a69b..4e5c0f8c9496 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c | |||
@@ -496,7 +496,7 @@ void hostap_init_proc(local_info_t *local) | |||
496 | 496 | ||
497 | void hostap_remove_proc(local_info_t *local) | 497 | void hostap_remove_proc(local_info_t *local) |
498 | { | 498 | { |
499 | remove_proc_subtree(local->ddev->name, hostap_proc); | 499 | proc_remove(local->proc); |
500 | } | 500 | } |
501 | 501 | ||
502 | 502 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index f57608943ca6..dd55c9cf7ba8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -696,6 +696,24 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
696 | return ret; | 696 | return ret; |
697 | } | 697 | } |
698 | 698 | ||
699 | static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) | ||
700 | { | ||
701 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) | ||
702 | return false; | ||
703 | return true; | ||
704 | } | ||
705 | |||
706 | static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) | ||
707 | { | ||
708 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) | ||
709 | return false; | ||
710 | if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) | ||
711 | return true; | ||
712 | |||
713 | /* disabled by default */ | ||
714 | return false; | ||
715 | } | ||
716 | |||
699 | static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, | 717 | static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, |
700 | struct ieee80211_vif *vif, | 718 | struct ieee80211_vif *vif, |
701 | enum ieee80211_ampdu_mlme_action action, | 719 | enum ieee80211_ampdu_mlme_action action, |
@@ -717,7 +735,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, | |||
717 | 735 | ||
718 | switch (action) { | 736 | switch (action) { |
719 | case IEEE80211_AMPDU_RX_START: | 737 | case IEEE80211_AMPDU_RX_START: |
720 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) | 738 | if (!iwl_enable_rx_ampdu(priv->cfg)) |
721 | break; | 739 | break; |
722 | IWL_DEBUG_HT(priv, "start Rx\n"); | 740 | IWL_DEBUG_HT(priv, "start Rx\n"); |
723 | ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); | 741 | ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); |
@@ -729,7 +747,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, | |||
729 | case IEEE80211_AMPDU_TX_START: | 747 | case IEEE80211_AMPDU_TX_START: |
730 | if (!priv->trans->ops->txq_enable) | 748 | if (!priv->trans->ops->txq_enable) |
731 | break; | 749 | break; |
732 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) | 750 | if (!iwl_enable_tx_ampdu(priv->cfg)) |
733 | break; | 751 | break; |
734 | IWL_DEBUG_HT(priv, "start Tx\n"); | 752 | IWL_DEBUG_HT(priv, "start Tx\n"); |
735 | ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); | 753 | ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index c0d070c5df5e..9cdd91cdf661 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -590,6 +590,7 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id, | |||
590 | sizeof(priv->tid_data[sta_id][tid])); | 590 | sizeof(priv->tid_data[sta_id][tid])); |
591 | 591 | ||
592 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; | 592 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; |
593 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
593 | 594 | ||
594 | priv->num_stations--; | 595 | priv->num_stations--; |
595 | 596 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index a6839dfcb82d..398dd096674c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -1291,8 +1291,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1291 | struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data; | 1291 | struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data; |
1292 | struct iwl_ht_agg *agg; | 1292 | struct iwl_ht_agg *agg; |
1293 | struct sk_buff_head reclaimed_skbs; | 1293 | struct sk_buff_head reclaimed_skbs; |
1294 | struct ieee80211_tx_info *info; | ||
1295 | struct ieee80211_hdr *hdr; | ||
1296 | struct sk_buff *skb; | 1294 | struct sk_buff *skb; |
1297 | int sta_id; | 1295 | int sta_id; |
1298 | int tid; | 1296 | int tid; |
@@ -1379,22 +1377,28 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1379 | freed = 0; | 1377 | freed = 0; |
1380 | 1378 | ||
1381 | skb_queue_walk(&reclaimed_skbs, skb) { | 1379 | skb_queue_walk(&reclaimed_skbs, skb) { |
1382 | hdr = (struct ieee80211_hdr *)skb->data; | 1380 | struct ieee80211_hdr *hdr = (void *)skb->data; |
1381 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1383 | 1382 | ||
1384 | if (ieee80211_is_data_qos(hdr->frame_control)) | 1383 | if (ieee80211_is_data_qos(hdr->frame_control)) |
1385 | freed++; | 1384 | freed++; |
1386 | else | 1385 | else |
1387 | WARN_ON_ONCE(1); | 1386 | WARN_ON_ONCE(1); |
1388 | 1387 | ||
1389 | info = IEEE80211_SKB_CB(skb); | ||
1390 | iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]); | 1388 | iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]); |
1391 | 1389 | ||
1390 | memset(&info->status, 0, sizeof(info->status)); | ||
1391 | /* Packet was transmitted successfully, failures come as single | ||
1392 | * frames because before failing a frame the firmware transmits | ||
1393 | * it without aggregation at least once. | ||
1394 | */ | ||
1395 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
1396 | |||
1392 | if (freed == 1) { | 1397 | if (freed == 1) { |
1393 | /* this is the first skb we deliver in this batch */ | 1398 | /* this is the first skb we deliver in this batch */ |
1394 | /* put the rate scaling data there */ | 1399 | /* put the rate scaling data there */ |
1395 | info = IEEE80211_SKB_CB(skb); | 1400 | info = IEEE80211_SKB_CB(skb); |
1396 | memset(&info->status, 0, sizeof(info->status)); | 1401 | memset(&info->status, 0, sizeof(info->status)); |
1397 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
1398 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 1402 | info->flags |= IEEE80211_TX_STAT_AMPDU; |
1399 | info->status.ampdu_ack_len = ba_resp->txed_2_done; | 1403 | info->status.ampdu_ack_len = ba_resp->txed_2_done; |
1400 | info->status.ampdu_len = ba_resp->txed; | 1404 | info->status.ampdu_len = ba_resp->txed; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 847a0eded40a..0a3e841b44a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -1337,7 +1337,7 @@ module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO); | |||
1337 | MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); | 1337 | MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); |
1338 | module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); | 1338 | module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); |
1339 | MODULE_PARM_DESC(11n_disable, | 1339 | MODULE_PARM_DESC(11n_disable, |
1340 | "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); | 1340 | "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX"); |
1341 | module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, | 1341 | module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, |
1342 | int, S_IRUGO); | 1342 | int, S_IRUGO); |
1343 | MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)"); | 1343 | MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)"); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 1d100f24804c..d994317db85b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -79,9 +79,12 @@ enum iwl_power_level { | |||
79 | IWL_POWER_NUM | 79 | IWL_POWER_NUM |
80 | }; | 80 | }; |
81 | 81 | ||
82 | #define IWL_DISABLE_HT_ALL BIT(0) | 82 | enum iwl_disable_11n { |
83 | #define IWL_DISABLE_HT_TXAGG BIT(1) | 83 | IWL_DISABLE_HT_ALL = BIT(0), |
84 | #define IWL_DISABLE_HT_RXAGG BIT(2) | 84 | IWL_DISABLE_HT_TXAGG = BIT(1), |
85 | IWL_DISABLE_HT_RXAGG = BIT(2), | ||
86 | IWL_ENABLE_HT_TXAGG = BIT(3), | ||
87 | }; | ||
85 | 88 | ||
86 | /** | 89 | /** |
87 | * struct iwl_mod_params | 90 | * struct iwl_mod_params |
@@ -90,7 +93,7 @@ enum iwl_power_level { | |||
90 | * | 93 | * |
91 | * @sw_crypto: using hardware encryption, default = 0 | 94 | * @sw_crypto: using hardware encryption, default = 0 |
92 | * @disable_11n: disable 11n capabilities, default = 0, | 95 | * @disable_11n: disable 11n capabilities, default = 0, |
93 | * use IWL_DISABLE_HT_* constants | 96 | * use IWL_[DIS,EN]ABLE_HT_* constants |
94 | * @amsdu_size_8K: enable 8K amsdu size, default = 0 | 97 | * @amsdu_size_8K: enable 8K amsdu size, default = 0 |
95 | * @restart_fw: restart firmware, default = 1 | 98 | * @restart_fw: restart firmware, default = 1 |
96 | * @wd_disable: disable stuck queue check, default = 1 | 99 | * @wd_disable: disable stuck queue check, default = 1 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index d74cc43ca593..c2ab6a3318cb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -463,6 +463,24 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | |||
463 | ieee80211_free_txskb(hw, skb); | 463 | ieee80211_free_txskb(hw, skb); |
464 | } | 464 | } |
465 | 465 | ||
466 | static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) | ||
467 | { | ||
468 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) | ||
469 | return false; | ||
470 | return true; | ||
471 | } | ||
472 | |||
473 | static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) | ||
474 | { | ||
475 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) | ||
476 | return false; | ||
477 | if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) | ||
478 | return true; | ||
479 | |||
480 | /* enabled by default */ | ||
481 | return true; | ||
482 | } | ||
483 | |||
466 | static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | 484 | static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, |
467 | struct ieee80211_vif *vif, | 485 | struct ieee80211_vif *vif, |
468 | enum ieee80211_ampdu_mlme_action action, | 486 | enum ieee80211_ampdu_mlme_action action, |
@@ -482,7 +500,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | |||
482 | 500 | ||
483 | switch (action) { | 501 | switch (action) { |
484 | case IEEE80211_AMPDU_RX_START: | 502 | case IEEE80211_AMPDU_RX_START: |
485 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) { | 503 | if (!iwl_enable_rx_ampdu(mvm->cfg)) { |
486 | ret = -EINVAL; | 504 | ret = -EINVAL; |
487 | break; | 505 | break; |
488 | } | 506 | } |
@@ -492,7 +510,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | |||
492 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); | 510 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); |
493 | break; | 511 | break; |
494 | case IEEE80211_AMPDU_TX_START: | 512 | case IEEE80211_AMPDU_TX_START: |
495 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) { | 513 | if (!iwl_enable_tx_ampdu(mvm->cfg)) { |
496 | ret = -EINVAL; | 514 | ret = -EINVAL; |
497 | break; | 515 | break; |
498 | } | 516 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 5fb51099f99d..302cf779c172 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -150,7 +150,7 @@ enum iwl_power_scheme { | |||
150 | IWL_POWER_SCHEME_LP | 150 | IWL_POWER_SCHEME_LP |
151 | }; | 151 | }; |
152 | 152 | ||
153 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 | 153 | #define IWL_CONN_MAX_LISTEN_INTERVAL 10 |
154 | #define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ | 154 | #define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ |
155 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ | 155 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ |
156 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ | 156 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 6cdbf7b21714..0ba96654d2c3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -845,16 +845,12 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
845 | struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; | 845 | struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; |
846 | struct sk_buff_head reclaimed_skbs; | 846 | struct sk_buff_head reclaimed_skbs; |
847 | struct iwl_mvm_tid_data *tid_data; | 847 | struct iwl_mvm_tid_data *tid_data; |
848 | struct ieee80211_tx_info *info; | ||
849 | struct ieee80211_sta *sta; | 848 | struct ieee80211_sta *sta; |
850 | struct iwl_mvm_sta *mvmsta; | 849 | struct iwl_mvm_sta *mvmsta; |
851 | struct ieee80211_hdr *hdr; | ||
852 | struct sk_buff *skb; | 850 | struct sk_buff *skb; |
853 | int sta_id, tid, freed; | 851 | int sta_id, tid, freed; |
854 | |||
855 | /* "flow" corresponds to Tx queue */ | 852 | /* "flow" corresponds to Tx queue */ |
856 | u16 scd_flow = le16_to_cpu(ba_notif->scd_flow); | 853 | u16 scd_flow = le16_to_cpu(ba_notif->scd_flow); |
857 | |||
858 | /* "ssn" is start of block-ack Tx window, corresponds to index | 854 | /* "ssn" is start of block-ack Tx window, corresponds to index |
859 | * (in Tx queue's circular buffer) of first TFD/frame in window */ | 855 | * (in Tx queue's circular buffer) of first TFD/frame in window */ |
860 | u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn); | 856 | u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn); |
@@ -911,22 +907,26 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
911 | freed = 0; | 907 | freed = 0; |
912 | 908 | ||
913 | skb_queue_walk(&reclaimed_skbs, skb) { | 909 | skb_queue_walk(&reclaimed_skbs, skb) { |
914 | hdr = (struct ieee80211_hdr *)skb->data; | 910 | struct ieee80211_hdr *hdr = (void *)skb->data; |
911 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
915 | 912 | ||
916 | if (ieee80211_is_data_qos(hdr->frame_control)) | 913 | if (ieee80211_is_data_qos(hdr->frame_control)) |
917 | freed++; | 914 | freed++; |
918 | else | 915 | else |
919 | WARN_ON_ONCE(1); | 916 | WARN_ON_ONCE(1); |
920 | 917 | ||
921 | info = IEEE80211_SKB_CB(skb); | ||
922 | iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); | 918 | iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]); |
923 | 919 | ||
920 | memset(&info->status, 0, sizeof(info->status)); | ||
921 | /* Packet was transmitted successfully, failures come as single | ||
922 | * frames because before failing a frame the firmware transmits | ||
923 | * it without aggregation at least once. | ||
924 | */ | ||
925 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
926 | |||
924 | if (freed == 1) { | 927 | if (freed == 1) { |
925 | /* this is the first skb we deliver in this batch */ | 928 | /* this is the first skb we deliver in this batch */ |
926 | /* put the rate scaling data there */ | 929 | /* put the rate scaling data there */ |
927 | info = IEEE80211_SKB_CB(skb); | ||
928 | memset(&info->status, 0, sizeof(info->status)); | ||
929 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
930 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 930 | info->flags |= IEEE80211_TX_STAT_AMPDU; |
931 | info->status.ampdu_ack_len = ba_notif->txed_2_done; | 931 | info->status.ampdu_ack_len = ba_notif->txed_2_done; |
932 | info->status.ampdu_len = ba_notif->txed; | 932 | info->status.ampdu_len = ba_notif->txed; |
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 2d72a6b4b93e..54e344aed6e0 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c | |||
@@ -621,7 +621,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, | |||
621 | id = *pos++; | 621 | id = *pos++; |
622 | elen = *pos++; | 622 | elen = *pos++; |
623 | left -= 2; | 623 | left -= 2; |
624 | if (elen > left || elen == 0) { | 624 | if (elen > left) { |
625 | lbs_deb_scan("scan response: invalid IE fmt\n"); | 625 | lbs_deb_scan("scan response: invalid IE fmt\n"); |
626 | goto done; | 626 | goto done; |
627 | } | 627 | } |
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index d2af2127b41a..9f1683b5f28f 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c | |||
@@ -1213,6 +1213,12 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) | |||
1213 | rd_index = card->rxbd_rdptr & reg->rx_mask; | 1213 | rd_index = card->rxbd_rdptr & reg->rx_mask; |
1214 | skb_data = card->rx_buf_list[rd_index]; | 1214 | skb_data = card->rx_buf_list[rd_index]; |
1215 | 1215 | ||
1216 | /* If skb allocation was failed earlier for Rx packet, | ||
1217 | * rx_buf_list[rd_index] would have been left with a NULL. | ||
1218 | */ | ||
1219 | if (!skb_data) | ||
1220 | return -ENOMEM; | ||
1221 | |||
1216 | mwifiex_unmap_pci_memory(adapter, skb_data, PCI_DMA_FROMDEVICE); | 1222 | mwifiex_unmap_pci_memory(adapter, skb_data, PCI_DMA_FROMDEVICE); |
1217 | card->rx_buf_list[rd_index] = NULL; | 1223 | card->rx_buf_list[rd_index] = NULL; |
1218 | 1224 | ||
@@ -1525,6 +1531,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) | |||
1525 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) { | 1531 | if (adapter->ps_state == PS_STATE_SLEEP_CFM) { |
1526 | mwifiex_process_sleep_confirm_resp(adapter, skb->data, | 1532 | mwifiex_process_sleep_confirm_resp(adapter, skb->data, |
1527 | skb->len); | 1533 | skb->len); |
1534 | mwifiex_pcie_enable_host_int(adapter); | ||
1535 | if (mwifiex_write_reg(adapter, | ||
1536 | PCIE_CPU_INT_EVENT, | ||
1537 | CPU_INTR_SLEEP_CFM_DONE)) { | ||
1538 | dev_warn(adapter->dev, | ||
1539 | "Write register failed\n"); | ||
1540 | return -1; | ||
1541 | } | ||
1528 | while (reg->sleep_cookie && (count++ < 10) && | 1542 | while (reg->sleep_cookie && (count++ < 10) && |
1529 | mwifiex_pcie_ok_to_access_hw(adapter)) | 1543 | mwifiex_pcie_ok_to_access_hw(adapter)) |
1530 | usleep_range(50, 60); | 1544 | usleep_range(50, 60); |
@@ -1971,23 +1985,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) | |||
1971 | adapter->int_status |= pcie_ireg; | 1985 | adapter->int_status |= pcie_ireg; |
1972 | spin_unlock_irqrestore(&adapter->int_lock, flags); | 1986 | spin_unlock_irqrestore(&adapter->int_lock, flags); |
1973 | 1987 | ||
1974 | if (pcie_ireg & HOST_INTR_CMD_DONE) { | 1988 | if (!adapter->pps_uapsd_mode && |
1975 | if ((adapter->ps_state == PS_STATE_SLEEP_CFM) || | 1989 | adapter->ps_state == PS_STATE_SLEEP && |
1976 | (adapter->ps_state == PS_STATE_SLEEP)) { | 1990 | mwifiex_pcie_ok_to_access_hw(adapter)) { |
1977 | mwifiex_pcie_enable_host_int(adapter); | ||
1978 | if (mwifiex_write_reg(adapter, | ||
1979 | PCIE_CPU_INT_EVENT, | ||
1980 | CPU_INTR_SLEEP_CFM_DONE) | ||
1981 | ) { | ||
1982 | dev_warn(adapter->dev, | ||
1983 | "Write register failed\n"); | ||
1984 | return; | ||
1985 | |||
1986 | } | ||
1987 | } | ||
1988 | } else if (!adapter->pps_uapsd_mode && | ||
1989 | adapter->ps_state == PS_STATE_SLEEP && | ||
1990 | mwifiex_pcie_ok_to_access_hw(adapter)) { | ||
1991 | /* Potentially for PCIe we could get other | 1991 | /* Potentially for PCIe we could get other |
1992 | * interrupts like shared. Don't change power | 1992 | * interrupts like shared. Don't change power |
1993 | * state until cookie is set */ | 1993 | * state until cookie is set */ |
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 93d5d73c4800..ae30c390ebd3 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c | |||
@@ -22,8 +22,6 @@ | |||
22 | 22 | ||
23 | #define USB_VERSION "1.0" | 23 | #define USB_VERSION "1.0" |
24 | 24 | ||
25 | static const char usbdriver_name[] = "usb8xxx"; | ||
26 | |||
27 | static struct mwifiex_if_ops usb_ops; | 25 | static struct mwifiex_if_ops usb_ops; |
28 | static struct semaphore add_remove_card_sem; | 26 | static struct semaphore add_remove_card_sem; |
29 | static struct usb_card_rec *usb_card; | 27 | static struct usb_card_rec *usb_card; |
@@ -527,13 +525,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf) | |||
527 | MWIFIEX_BSS_ROLE_ANY), | 525 | MWIFIEX_BSS_ROLE_ANY), |
528 | MWIFIEX_ASYNC_CMD); | 526 | MWIFIEX_ASYNC_CMD); |
529 | 527 | ||
530 | #ifdef CONFIG_PM | ||
531 | /* Resume handler may be called due to remote wakeup, | ||
532 | * force to exit suspend anyway | ||
533 | */ | ||
534 | usb_disable_autosuspend(card->udev); | ||
535 | #endif /* CONFIG_PM */ | ||
536 | |||
537 | return 0; | 528 | return 0; |
538 | } | 529 | } |
539 | 530 | ||
@@ -567,13 +558,12 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) | |||
567 | } | 558 | } |
568 | 559 | ||
569 | static struct usb_driver mwifiex_usb_driver = { | 560 | static struct usb_driver mwifiex_usb_driver = { |
570 | .name = usbdriver_name, | 561 | .name = "mwifiex_usb", |
571 | .probe = mwifiex_usb_probe, | 562 | .probe = mwifiex_usb_probe, |
572 | .disconnect = mwifiex_usb_disconnect, | 563 | .disconnect = mwifiex_usb_disconnect, |
573 | .id_table = mwifiex_usb_table, | 564 | .id_table = mwifiex_usb_table, |
574 | .suspend = mwifiex_usb_suspend, | 565 | .suspend = mwifiex_usb_suspend, |
575 | .resume = mwifiex_usb_resume, | 566 | .resume = mwifiex_usb_resume, |
576 | .supports_autosuspend = 1, | ||
577 | }; | 567 | }; |
578 | 568 | ||
579 | static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) | 569 | static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) |
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index e0ba0115e5ae..1c5f2b66f057 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c | |||
@@ -554,7 +554,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) | |||
554 | mwifiex_wmm_delete_all_ralist(priv); | 554 | mwifiex_wmm_delete_all_ralist(priv); |
555 | memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); | 555 | memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); |
556 | 556 | ||
557 | if (priv->adapter->if_ops.clean_pcie_ring) | 557 | if (priv->adapter->if_ops.clean_pcie_ring && |
558 | !priv->adapter->surprise_removed) | ||
558 | priv->adapter->if_ops.clean_pcie_ring(priv->adapter); | 559 | priv->adapter->if_ops.clean_pcie_ring(priv->adapter); |
559 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); | 560 | spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); |
560 | 561 | ||
diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h index 56aee067f324..a6ad79f61bf9 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h | |||
@@ -15,6 +15,8 @@ | |||
15 | #ifndef RTL8187_H | 15 | #ifndef RTL8187_H |
16 | #define RTL8187_H | 16 | #define RTL8187_H |
17 | 17 | ||
18 | #include <linux/cache.h> | ||
19 | |||
18 | #include "rtl818x.h" | 20 | #include "rtl818x.h" |
19 | #include "leds.h" | 21 | #include "leds.h" |
20 | 22 | ||
@@ -139,7 +141,10 @@ struct rtl8187_priv { | |||
139 | u8 aifsn[4]; | 141 | u8 aifsn[4]; |
140 | u8 rfkill_mask; | 142 | u8 rfkill_mask; |
141 | struct { | 143 | struct { |
142 | __le64 buf; | 144 | union { |
145 | __le64 buf; | ||
146 | u8 dummy1[L1_CACHE_BYTES]; | ||
147 | } ____cacheline_aligned; | ||
143 | struct sk_buff_head queue; | 148 | struct sk_buff_head queue; |
144 | } b_tx_status; /* This queue is used by both -b and non-b devices */ | 149 | } b_tx_status; /* This queue is used by both -b and non-b devices */ |
145 | struct mutex io_mutex; | 150 | struct mutex io_mutex; |
@@ -147,7 +152,8 @@ struct rtl8187_priv { | |||
147 | u8 bits8; | 152 | u8 bits8; |
148 | __le16 bits16; | 153 | __le16 bits16; |
149 | __le32 bits32; | 154 | __le32 bits32; |
150 | } *io_dmabuf; | 155 | u8 dummy2[L1_CACHE_BYTES]; |
156 | } *io_dmabuf ____cacheline_aligned; | ||
151 | bool rfkill_off; | 157 | bool rfkill_off; |
152 | u16 seqno; | 158 | u16 seqno; |
153 | }; | 159 | }; |
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index deedae3c5449..d1c0191a195b 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c | |||
@@ -48,7 +48,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) | |||
48 | 48 | ||
49 | /*<2> Enable Adapter */ | 49 | /*<2> Enable Adapter */ |
50 | if (rtlpriv->cfg->ops->hw_init(hw)) | 50 | if (rtlpriv->cfg->ops->hw_init(hw)) |
51 | return 1; | 51 | return false; |
52 | RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); | 52 | RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); |
53 | 53 | ||
54 | /*<3> Enable Interrupt */ | 54 | /*<3> Enable Interrupt */ |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 25e178c80d70..b5b513404376 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | |||
@@ -937,14 +937,26 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) | |||
937 | bool is92c; | 937 | bool is92c; |
938 | int err; | 938 | int err; |
939 | u8 tmp_u1b; | 939 | u8 tmp_u1b; |
940 | unsigned long flags; | ||
940 | 941 | ||
941 | rtlpci->being_init_adapter = true; | 942 | rtlpci->being_init_adapter = true; |
943 | |||
944 | /* Since this function can take a very long time (up to 350 ms) | ||
945 | * and can be called with irqs disabled, reenable the irqs | ||
946 | * to let the other devices continue being serviced. | ||
947 | * | ||
948 | * It is safe doing so since our own interrupts will only be enabled | ||
949 | * in a subsequent step. | ||
950 | */ | ||
951 | local_save_flags(flags); | ||
952 | local_irq_enable(); | ||
953 | |||
942 | rtlpriv->intf_ops->disable_aspm(hw); | 954 | rtlpriv->intf_ops->disable_aspm(hw); |
943 | rtstatus = _rtl92ce_init_mac(hw); | 955 | rtstatus = _rtl92ce_init_mac(hw); |
944 | if (!rtstatus) { | 956 | if (!rtstatus) { |
945 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); | 957 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); |
946 | err = 1; | 958 | err = 1; |
947 | return err; | 959 | goto exit; |
948 | } | 960 | } |
949 | 961 | ||
950 | err = rtl92c_download_fw(hw); | 962 | err = rtl92c_download_fw(hw); |
@@ -952,7 +964,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) | |||
952 | RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, | 964 | RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, |
953 | "Failed to download FW. Init HW without FW now..\n"); | 965 | "Failed to download FW. Init HW without FW now..\n"); |
954 | err = 1; | 966 | err = 1; |
955 | return err; | 967 | goto exit; |
956 | } | 968 | } |
957 | 969 | ||
958 | rtlhal->last_hmeboxnum = 0; | 970 | rtlhal->last_hmeboxnum = 0; |
@@ -1032,6 +1044,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) | |||
1032 | RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); | 1044 | RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); |
1033 | } | 1045 | } |
1034 | rtl92c_dm_init(hw); | 1046 | rtl92c_dm_init(hw); |
1047 | exit: | ||
1048 | local_irq_restore(flags); | ||
1035 | rtlpci->being_init_adapter = false; | 1049 | rtlpci->being_init_adapter = false; |
1036 | return err; | 1050 | return err; |
1037 | } | 1051 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8603dfb52b3a..0d1a0f801b94 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1700,14 +1700,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | |||
1700 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); | 1700 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); |
1701 | void ieee80211_add_pending_skb(struct ieee80211_local *local, | 1701 | void ieee80211_add_pending_skb(struct ieee80211_local *local, |
1702 | struct sk_buff *skb); | 1702 | struct sk_buff *skb); |
1703 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 1703 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
1704 | struct sk_buff_head *skbs, | 1704 | struct sk_buff_head *skbs); |
1705 | void (*fn)(void *data), void *data); | ||
1706 | static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, | ||
1707 | struct sk_buff_head *skbs) | ||
1708 | { | ||
1709 | ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); | ||
1710 | } | ||
1711 | void ieee80211_flush_queues(struct ieee80211_local *local, | 1705 | void ieee80211_flush_queues(struct ieee80211_local *local, |
1712 | struct ieee80211_sub_if_data *sdata); | 1706 | struct ieee80211_sub_if_data *sdata); |
1713 | 1707 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 46b62bb3677c..94f0af29b742 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -222,6 +222,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
222 | switch (vht_oper->chan_width) { | 222 | switch (vht_oper->chan_width) { |
223 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | 223 | case IEEE80211_VHT_CHANWIDTH_USE_HT: |
224 | vht_chandef.width = chandef->width; | 224 | vht_chandef.width = chandef->width; |
225 | vht_chandef.center_freq1 = chandef->center_freq1; | ||
225 | break; | 226 | break; |
226 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | 227 | case IEEE80211_VHT_CHANWIDTH_80MHZ: |
227 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | 228 | vht_chandef.width = NL80211_CHAN_WIDTH_80; |
@@ -271,6 +272,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
271 | ret = 0; | 272 | ret = 0; |
272 | 273 | ||
273 | out: | 274 | out: |
275 | /* | ||
276 | * When tracking the current AP, don't do any further checks if the | ||
277 | * new chandef is identical to the one we're currently using for the | ||
278 | * connection. This keeps us from playing ping-pong with regulatory, | ||
279 | * without it the following can happen (for example): | ||
280 | * - connect to an AP with 80 MHz, world regdom allows 80 MHz | ||
281 | * - AP advertises regdom US | ||
282 | * - CRDA loads regdom US with 80 MHz prohibited (old database) | ||
283 | * - the code below detects an unsupported channel, downgrades, and | ||
284 | * we disconnect from the AP in the caller | ||
285 | * - disconnect causes CRDA to reload world regdomain and the game | ||
286 | * starts anew. | ||
287 | * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881) | ||
288 | * | ||
289 | * It seems possible that there are still scenarios with CSA or real | ||
290 | * bandwidth changes where a this could happen, but those cases are | ||
291 | * less common and wouldn't completely prevent using the AP. | ||
292 | */ | ||
293 | if (tracking && | ||
294 | cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) | ||
295 | return ret; | ||
296 | |||
274 | /* don't print the message below for VHT mismatch if VHT is disabled */ | 297 | /* don't print the message below for VHT mismatch if VHT is disabled */ |
275 | if (ret & IEEE80211_STA_DISABLE_VHT) | 298 | if (ret & IEEE80211_STA_DISABLE_VHT) |
276 | vht_chandef = *chandef; | 299 | vht_chandef = *chandef; |
@@ -3848,6 +3871,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3848 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3871 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
3849 | if (WARN_ON(!chanctx_conf)) { | 3872 | if (WARN_ON(!chanctx_conf)) { |
3850 | rcu_read_unlock(); | 3873 | rcu_read_unlock(); |
3874 | sta_info_free(local, new_sta); | ||
3851 | return -EINVAL; | 3875 | return -EINVAL; |
3852 | } | 3876 | } |
3853 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); | 3877 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 58e4b7052d17..5b617660b0ba 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1092,6 +1092,13 @@ static void sta_ps_end(struct sta_info *sta) | |||
1092 | sta->sta.addr, sta->sta.aid); | 1092 | sta->sta.addr, sta->sta.aid); |
1093 | 1093 | ||
1094 | if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 1094 | if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { |
1095 | /* | ||
1096 | * Clear the flag only if the other one is still set | ||
1097 | * so that the TX path won't start TX'ing new frames | ||
1098 | * directly ... In the case that the driver flag isn't | ||
1099 | * set ieee80211_sta_ps_deliver_wakeup() will clear it. | ||
1100 | */ | ||
1101 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1095 | ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", | 1102 | ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", |
1096 | sta->sta.addr, sta->sta.aid); | 1103 | sta->sta.addr, sta->sta.aid); |
1097 | return; | 1104 | return; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index decd30c1e290..a023b432143b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
91 | return -ENOENT; | 91 | return -ENOENT; |
92 | } | 92 | } |
93 | 93 | ||
94 | static void cleanup_single_sta(struct sta_info *sta) | 94 | static void __cleanup_single_sta(struct sta_info *sta) |
95 | { | 95 | { |
96 | int ac, i; | 96 | int ac, i; |
97 | struct tid_ampdu_tx *tid_tx; | 97 | struct tid_ampdu_tx *tid_tx; |
@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
99 | struct ieee80211_local *local = sdata->local; | 99 | struct ieee80211_local *local = sdata->local; |
100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
101 | 101 | ||
102 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | ||
103 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 104 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
104 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 105 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
105 | ps = &sdata->bss->ps; | 106 | ps = &sdata->bss->ps; |
@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
109 | return; | 110 | return; |
110 | 111 | ||
111 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 112 | clear_sta_flag(sta, WLAN_STA_PS_STA); |
113 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
112 | 114 | ||
113 | atomic_dec(&ps->num_sta_ps); | 115 | atomic_dec(&ps->num_sta_ps); |
114 | sta_info_recalc_tim(sta); | 116 | sta_info_recalc_tim(sta); |
@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
139 | ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); | 141 | ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); |
140 | kfree(tid_tx); | 142 | kfree(tid_tx); |
141 | } | 143 | } |
144 | } | ||
142 | 145 | ||
146 | static void cleanup_single_sta(struct sta_info *sta) | ||
147 | { | ||
148 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
149 | struct ieee80211_local *local = sdata->local; | ||
150 | |||
151 | __cleanup_single_sta(sta); | ||
143 | sta_info_free(local, sta); | 152 | sta_info_free(local, sta); |
144 | } | 153 | } |
145 | 154 | ||
@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
330 | rcu_read_unlock(); | 339 | rcu_read_unlock(); |
331 | 340 | ||
332 | spin_lock_init(&sta->lock); | 341 | spin_lock_init(&sta->lock); |
342 | spin_lock_init(&sta->ps_lock); | ||
333 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 343 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
334 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 344 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
335 | mutex_init(&sta->ampdu_mlme.mtx); | 345 | mutex_init(&sta->ampdu_mlme.mtx); |
@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
487 | goto out_err; | 497 | goto out_err; |
488 | } | 498 | } |
489 | 499 | ||
490 | /* notify driver */ | ||
491 | err = sta_info_insert_drv_state(local, sdata, sta); | ||
492 | if (err) | ||
493 | goto out_err; | ||
494 | |||
495 | local->num_sta++; | 500 | local->num_sta++; |
496 | local->sta_generation++; | 501 | local->sta_generation++; |
497 | smp_mb(); | 502 | smp_mb(); |
498 | 503 | ||
504 | /* simplify things and don't accept BA sessions yet */ | ||
505 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
506 | |||
499 | /* make the station visible */ | 507 | /* make the station visible */ |
500 | sta_info_hash_add(local, sta); | 508 | sta_info_hash_add(local, sta); |
501 | 509 | ||
502 | list_add_rcu(&sta->list, &local->sta_list); | 510 | list_add_rcu(&sta->list, &local->sta_list); |
503 | 511 | ||
512 | /* notify driver */ | ||
513 | err = sta_info_insert_drv_state(local, sdata, sta); | ||
514 | if (err) | ||
515 | goto out_remove; | ||
516 | |||
504 | set_sta_flag(sta, WLAN_STA_INSERTED); | 517 | set_sta_flag(sta, WLAN_STA_INSERTED); |
518 | /* accept BA sessions now */ | ||
519 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
505 | 520 | ||
506 | ieee80211_recalc_min_chandef(sdata); | 521 | ieee80211_recalc_min_chandef(sdata); |
507 | ieee80211_sta_debugfs_add(sta); | 522 | ieee80211_sta_debugfs_add(sta); |
@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
522 | mesh_accept_plinks_update(sdata); | 537 | mesh_accept_plinks_update(sdata); |
523 | 538 | ||
524 | return 0; | 539 | return 0; |
540 | out_remove: | ||
541 | sta_info_hash_del(local, sta); | ||
542 | list_del_rcu(&sta->list); | ||
543 | local->num_sta--; | ||
544 | synchronize_net(); | ||
545 | __cleanup_single_sta(sta); | ||
525 | out_err: | 546 | out_err: |
526 | mutex_unlock(&local->sta_mtx); | 547 | mutex_unlock(&local->sta_mtx); |
527 | rcu_read_lock(); | 548 | rcu_read_lock(); |
@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, | |||
1071 | } | 1092 | } |
1072 | EXPORT_SYMBOL(ieee80211_find_sta); | 1093 | EXPORT_SYMBOL(ieee80211_find_sta); |
1073 | 1094 | ||
1074 | static void clear_sta_ps_flags(void *_sta) | 1095 | /* powersave support code */ |
1096 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | ||
1075 | { | 1097 | { |
1076 | struct sta_info *sta = _sta; | ||
1077 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1098 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
1099 | struct ieee80211_local *local = sdata->local; | ||
1100 | struct sk_buff_head pending; | ||
1101 | int filtered = 0, buffered = 0, ac; | ||
1102 | unsigned long flags; | ||
1078 | struct ps_data *ps; | 1103 | struct ps_data *ps; |
1079 | 1104 | ||
1080 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 1105 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta) | |||
1085 | else | 1110 | else |
1086 | return; | 1111 | return; |
1087 | 1112 | ||
1088 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1089 | if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) | ||
1090 | atomic_dec(&ps->num_sta_ps); | ||
1091 | } | ||
1092 | |||
1093 | /* powersave support code */ | ||
1094 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | ||
1095 | { | ||
1096 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1097 | struct ieee80211_local *local = sdata->local; | ||
1098 | struct sk_buff_head pending; | ||
1099 | int filtered = 0, buffered = 0, ac; | ||
1100 | unsigned long flags; | ||
1101 | |||
1102 | clear_sta_flag(sta, WLAN_STA_SP); | 1113 | clear_sta_flag(sta, WLAN_STA_SP); |
1103 | 1114 | ||
1104 | BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); | 1115 | BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); |
@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1109 | 1120 | ||
1110 | skb_queue_head_init(&pending); | 1121 | skb_queue_head_init(&pending); |
1111 | 1122 | ||
1123 | /* sync with ieee80211_tx_h_unicast_ps_buf */ | ||
1124 | spin_lock(&sta->ps_lock); | ||
1112 | /* Send all buffered frames to the station */ | 1125 | /* Send all buffered frames to the station */ |
1113 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1126 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
1114 | int count = skb_queue_len(&pending), tmp; | 1127 | int count = skb_queue_len(&pending), tmp; |
@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1127 | buffered += tmp - count; | 1140 | buffered += tmp - count; |
1128 | } | 1141 | } |
1129 | 1142 | ||
1130 | ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); | 1143 | ieee80211_add_pending_skbs(local, &pending); |
1144 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1145 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1146 | spin_unlock(&sta->ps_lock); | ||
1147 | |||
1148 | atomic_dec(&ps->num_sta_ps); | ||
1131 | 1149 | ||
1132 | /* This station just woke up and isn't aware of our SMPS state */ | 1150 | /* This station just woke up and isn't aware of our SMPS state */ |
1133 | if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, | 1151 | if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d4d85de0d75d..4acc5fc402fa 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -268,6 +268,7 @@ struct ieee80211_tx_latency_stat { | |||
268 | * @drv_unblock_wk: used for driver PS unblocking | 268 | * @drv_unblock_wk: used for driver PS unblocking |
269 | * @listen_interval: listen interval of this station, when we're acting as AP | 269 | * @listen_interval: listen interval of this station, when we're acting as AP |
270 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly | 270 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly |
271 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking | ||
271 | * @ps_tx_buf: buffers (per AC) of frames to transmit to this station | 272 | * @ps_tx_buf: buffers (per AC) of frames to transmit to this station |
272 | * when it leaves power saving state or polls | 273 | * when it leaves power saving state or polls |
273 | * @tx_filtered: buffers (per AC) of frames we already tried to | 274 | * @tx_filtered: buffers (per AC) of frames we already tried to |
@@ -357,10 +358,8 @@ struct sta_info { | |||
357 | /* use the accessors defined below */ | 358 | /* use the accessors defined below */ |
358 | unsigned long _flags; | 359 | unsigned long _flags; |
359 | 360 | ||
360 | /* | 361 | /* STA powersave lock and frame queues */ |
361 | * STA powersave frame queues, no more than the internal | 362 | spinlock_t ps_lock; |
362 | * locking required. | ||
363 | */ | ||
364 | struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; | 363 | struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; |
365 | struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; | 364 | struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; |
366 | unsigned long driver_buffered_tids; | 365 | unsigned long driver_buffered_tids; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 722151fa5dce..cd9f80498c48 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -477,6 +477,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
477 | sta->sta.addr, sta->sta.aid, ac); | 477 | sta->sta.addr, sta->sta.aid, ac); |
478 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) | 478 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) |
479 | purge_old_ps_buffers(tx->local); | 479 | purge_old_ps_buffers(tx->local); |
480 | |||
481 | /* sync with ieee80211_sta_ps_deliver_wakeup */ | ||
482 | spin_lock(&sta->ps_lock); | ||
483 | /* | ||
484 | * STA woke up the meantime and all the frames on ps_tx_buf have | ||
485 | * been queued to pending queue. No reordering can happen, go | ||
486 | * ahead and Tx the packet. | ||
487 | */ | ||
488 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && | ||
489 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | ||
490 | spin_unlock(&sta->ps_lock); | ||
491 | return TX_CONTINUE; | ||
492 | } | ||
493 | |||
480 | if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { | 494 | if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { |
481 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); | 495 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); |
482 | ps_dbg(tx->sdata, | 496 | ps_dbg(tx->sdata, |
@@ -491,6 +505,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
491 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 505 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
492 | info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; | 506 | info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; |
493 | skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); | 507 | skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); |
508 | spin_unlock(&sta->ps_lock); | ||
494 | 509 | ||
495 | if (!timer_pending(&local->sta_cleanup)) | 510 | if (!timer_pending(&local->sta_cleanup)) |
496 | mod_timer(&local->sta_cleanup, | 511 | mod_timer(&local->sta_cleanup, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d842af5c8a95..275c94f995f7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
435 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 435 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
436 | } | 436 | } |
437 | 437 | ||
438 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 438 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
439 | struct sk_buff_head *skbs, | 439 | struct sk_buff_head *skbs) |
440 | void (*fn)(void *data), void *data) | ||
441 | { | 440 | { |
442 | struct ieee80211_hw *hw = &local->hw; | 441 | struct ieee80211_hw *hw = &local->hw; |
443 | struct sk_buff *skb; | 442 | struct sk_buff *skb; |
@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
461 | __skb_queue_tail(&local->pending[queue], skb); | 460 | __skb_queue_tail(&local->pending[queue], skb); |
462 | } | 461 | } |
463 | 462 | ||
464 | if (fn) | ||
465 | fn(data); | ||
466 | |||
467 | for (i = 0; i < hw->queues; i++) | 463 | for (i = 0; i < hw->queues; i++) |
468 | __ieee80211_wake_queue(hw, i, | 464 | __ieee80211_wake_queue(hw, i, |
469 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 465 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
@@ -1767,6 +1763,26 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1767 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1763 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
1768 | 1764 | ||
1769 | /* | 1765 | /* |
1766 | * Reconfigure sched scan if it was interrupted by FW restart or | ||
1767 | * suspend. | ||
1768 | */ | ||
1769 | mutex_lock(&local->mtx); | ||
1770 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | ||
1771 | lockdep_is_held(&local->mtx)); | ||
1772 | if (sched_scan_sdata && local->sched_scan_req) | ||
1773 | /* | ||
1774 | * Sched scan stopped, but we don't want to report it. Instead, | ||
1775 | * we're trying to reschedule. | ||
1776 | */ | ||
1777 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | ||
1778 | local->sched_scan_req)) | ||
1779 | sched_scan_stopped = true; | ||
1780 | mutex_unlock(&local->mtx); | ||
1781 | |||
1782 | if (sched_scan_stopped) | ||
1783 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
1784 | |||
1785 | /* | ||
1770 | * If this is for hw restart things are still running. | 1786 | * If this is for hw restart things are still running. |
1771 | * We may want to change that later, however. | 1787 | * We may want to change that later, however. |
1772 | */ | 1788 | */ |
@@ -1794,26 +1810,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1794 | WARN_ON(1); | 1810 | WARN_ON(1); |
1795 | #endif | 1811 | #endif |
1796 | 1812 | ||
1797 | /* | ||
1798 | * Reconfigure sched scan if it was interrupted by FW restart or | ||
1799 | * suspend. | ||
1800 | */ | ||
1801 | mutex_lock(&local->mtx); | ||
1802 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | ||
1803 | lockdep_is_held(&local->mtx)); | ||
1804 | if (sched_scan_sdata && local->sched_scan_req) | ||
1805 | /* | ||
1806 | * Sched scan stopped, but we don't want to report it. Instead, | ||
1807 | * we're trying to reschedule. | ||
1808 | */ | ||
1809 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | ||
1810 | local->sched_scan_req)) | ||
1811 | sched_scan_stopped = true; | ||
1812 | mutex_unlock(&local->mtx); | ||
1813 | |||
1814 | if (sched_scan_stopped) | ||
1815 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
1816 | |||
1817 | return 0; | 1813 | return 0; |
1818 | } | 1814 | } |
1819 | 1815 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 21211c60ca98..d51422c778de 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
154 | return IEEE80211_AC_BE; | 154 | return IEEE80211_AC_BE; |
155 | } | 155 | } |
156 | 156 | ||
157 | if (skb->protocol == sdata->control_port_protocol) { | ||
158 | skb->priority = 7; | ||
159 | return ieee80211_downgrade_queue(sdata, skb); | ||
160 | } | ||
161 | |||
157 | /* use the data classifier to determine what 802.1d tag the | 162 | /* use the data classifier to determine what 802.1d tag the |
158 | * data frame has */ | 163 | * data frame has */ |
159 | rcu_read_lock(); | 164 | rcu_read_lock(); |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 46bda010bf11..56db888b1cd5 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -301,7 +301,7 @@ static int nci_open_device(struct nci_dev *ndev) | |||
301 | rc = __nci_request(ndev, nci_reset_req, 0, | 301 | rc = __nci_request(ndev, nci_reset_req, 0, |
302 | msecs_to_jiffies(NCI_RESET_TIMEOUT)); | 302 | msecs_to_jiffies(NCI_RESET_TIMEOUT)); |
303 | 303 | ||
304 | if (ndev->ops->setup(ndev)) | 304 | if (ndev->ops->setup) |
305 | ndev->ops->setup(ndev); | 305 | ndev->ops->setup(ndev); |
306 | 306 | ||
307 | if (!rc) { | 307 | if (!rc) { |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6b6f33ad78f2..90b82e08ae69 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1798,7 +1798,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1798 | return; | 1798 | return; |
1799 | case NL80211_REGDOM_SET_BY_USER: | 1799 | case NL80211_REGDOM_SET_BY_USER: |
1800 | treatment = reg_process_hint_user(reg_request); | 1800 | treatment = reg_process_hint_user(reg_request); |
1801 | if (treatment == REG_REQ_OK || | 1801 | if (treatment == REG_REQ_IGNORE || |
1802 | treatment == REG_REQ_ALREADY_SET) | 1802 | treatment == REG_REQ_ALREADY_SET) |
1803 | return; | 1803 | return; |
1804 | queue_delayed_work(system_power_efficient_wq, | 1804 | queue_delayed_work(system_power_efficient_wq, |
@@ -2492,6 +2492,7 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd, | |||
2492 | int set_regdom(const struct ieee80211_regdomain *rd) | 2492 | int set_regdom(const struct ieee80211_regdomain *rd) |
2493 | { | 2493 | { |
2494 | struct regulatory_request *lr; | 2494 | struct regulatory_request *lr; |
2495 | bool user_reset = false; | ||
2495 | int r; | 2496 | int r; |
2496 | 2497 | ||
2497 | if (!reg_is_valid_request(rd->alpha2)) { | 2498 | if (!reg_is_valid_request(rd->alpha2)) { |
@@ -2508,6 +2509,7 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2508 | break; | 2509 | break; |
2509 | case NL80211_REGDOM_SET_BY_USER: | 2510 | case NL80211_REGDOM_SET_BY_USER: |
2510 | r = reg_set_rd_user(rd, lr); | 2511 | r = reg_set_rd_user(rd, lr); |
2512 | user_reset = true; | ||
2511 | break; | 2513 | break; |
2512 | case NL80211_REGDOM_SET_BY_DRIVER: | 2514 | case NL80211_REGDOM_SET_BY_DRIVER: |
2513 | r = reg_set_rd_driver(rd, lr); | 2515 | r = reg_set_rd_driver(rd, lr); |
@@ -2521,8 +2523,14 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2521 | } | 2523 | } |
2522 | 2524 | ||
2523 | if (r) { | 2525 | if (r) { |
2524 | if (r == -EALREADY) | 2526 | switch (r) { |
2527 | case -EALREADY: | ||
2525 | reg_set_request_processed(); | 2528 | reg_set_request_processed(); |
2529 | break; | ||
2530 | default: | ||
2531 | /* Back to world regulatory in case of errors */ | ||
2532 | restore_regulatory_settings(user_reset); | ||
2533 | } | ||
2526 | 2534 | ||
2527 | kfree(rd); | 2535 | kfree(rd); |
2528 | return r; | 2536 | return r; |