diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2016-06-17 07:50:11 +0000 |
---|---|---|
committer | Luka Perkov <luka@openwrt.org> | 2016-06-19 19:56:13 +0200 |
commit | 0e29de61f7fa28126bba270a67fe710a6f949374 (patch) | |
tree | 13b9b00661a13e47ead8c3d001c13ecfbc74792e | |
parent | c0c62bad73d1b7b140d1b6c44ead7e600d40838a (diff) | |
download | upstream-0e29de61f7fa28126bba270a67fe710a6f949374.tar.gz upstream-0e29de61f7fa28126bba270a67fe710a6f949374.tar.bz2 upstream-0e29de61f7fa28126bba270a67fe710a6f949374.zip |
mac80211: brcmfmac: add support for get_channel
It's very useful for debugging problems with brcmfmac setting requested
channel.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Backport of r49382
git-svn-id: svn://svn.openwrt.org/openwrt/branches/chaos_calmer@49385 3c298f89-4303-0410-b956-a3cf2f4a3e73
2 files changed, 338 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch b/package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch new file mode 100644 index 0000000000..a7074a2ef6 --- /dev/null +++ b/package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch @@ -0,0 +1,244 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Fri, 20 May 2016 13:38:57 +0200 +Subject: [PATCH] brcmutil: add field storing control channel to the struct + brcmu_chan +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Our d11 code supports encoding/decoding channel info into/from chanspec +format used by firmware. Current implementation is quite misleading +because of the way "chnum" field is used. +When encoding channel info, "chnum" has to be filled by a caller with +*center* channel number. However when decoding chanspec the same field +is filled with a *control* channel number. + +1) This can be confusing. It's expected for information to be the same + after encoding and decoding. +2) It doesn't allow accessing all info when decoding. Some functions may + need to know both channel numbers, e.g. cfg80211 callback getting + current channel. +Solve this by adding a separated field for control channel. + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -2690,7 +2690,7 @@ static s32 brcmf_inform_single_bss(struc + if (!bi->ctl_ch) { + ch.chspec = le16_to_cpu(bi->chanspec); + cfg->d11inf.decchspec(&ch); +- bi->ctl_ch = ch.chnum; ++ bi->ctl_ch = ch.control_ch_num; + } + channel = bi->ctl_ch; + +@@ -2808,7 +2808,7 @@ static s32 brcmf_inform_ibss(struct brcm + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + +- freq = ieee80211_channel_to_frequency(ch.chnum, band->band); ++ freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band); + cfg->channel = freq; + notify_channel = ieee80211_get_channel(wiphy, freq); + +@@ -2818,7 +2818,7 @@ static s32 brcmf_inform_ibss(struct brcm + notify_ielen = le32_to_cpu(bi->ie_length); + notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; + +- brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq); ++ brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq); + brcmf_dbg(CONN, "capability: %X\n", notify_capability); + brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval); + brcmf_dbg(CONN, "signal: %d\n", notify_signal); +@@ -5132,7 +5132,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg8 + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + +- freq = ieee80211_channel_to_frequency(ch.chnum, band->band); ++ freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band); + notify_channel = ieee80211_get_channel(wiphy, freq); + + done: +@@ -5654,14 +5654,15 @@ static int brcmf_construct_chaninfo(stru + channel = band->channels; + index = band->n_channels; + for (j = 0; j < band->n_channels; j++) { +- if (channel[j].hw_value == ch.chnum) { ++ if (channel[j].hw_value == ch.control_ch_num) { + index = j; + break; + } + } + channel[index].center_freq = +- ieee80211_channel_to_frequency(ch.chnum, band->band); +- channel[index].hw_value = ch.chnum; ++ ieee80211_channel_to_frequency(ch.control_ch_num, ++ band->band); ++ channel[index].hw_value = ch.control_ch_num; + + /* assuming the chanspecs order is HT20, + * HT40 upper, HT40 lower, and VHT80. +@@ -5763,7 +5764,7 @@ static int brcmf_enable_bw40_2g(struct b + if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40)) + continue; + for (j = 0; j < band->n_channels; j++) { +- if (band->channels[j].hw_value == ch.chnum) ++ if (band->channels[j].hw_value == ch.control_ch_num) + break; + } + if (WARN_ON(j == band->n_channels)) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +@@ -1246,7 +1246,7 @@ bool brcmf_p2p_scan_finding_common_chann + if (!bi->ctl_ch) { + ch.chspec = le16_to_cpu(bi->chanspec); + cfg->d11inf.decchspec(&ch); +- bi->ctl_ch = ch.chnum; ++ bi->ctl_ch = ch.control_ch_num; + } + afx_hdl->peer_chan = bi->ctl_ch; + brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n", +@@ -1380,7 +1380,7 @@ int brcmf_p2p_notify_action_frame_rx(str + if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, + &p2p->status) && + (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) { +- afx_hdl->peer_chan = ch.chnum; ++ afx_hdl->peer_chan = ch.control_ch_num; + brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n", + afx_hdl->peer_chan); + complete(&afx_hdl->act_frm_scan); +@@ -1423,7 +1423,7 @@ int brcmf_p2p_notify_action_frame_rx(str + memcpy(&mgmt_frame->u, frame, mgmt_frame_len); + mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); + +- freq = ieee80211_channel_to_frequency(ch.chnum, ++ freq = ieee80211_channel_to_frequency(ch.control_ch_num, + ch.band == BRCMU_CHAN_BAND_2G ? + IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ); +@@ -1863,7 +1863,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere + + if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && + (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) { +- afx_hdl->peer_chan = ch.chnum; ++ afx_hdl->peer_chan = ch.control_ch_num; + brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n", + afx_hdl->peer_chan); + complete(&afx_hdl->act_frm_scan); +@@ -1888,7 +1888,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere + + mgmt_frame = (u8 *)(rxframe + 1); + mgmt_frame_len = e->datalen - sizeof(*rxframe); +- freq = ieee80211_channel_to_frequency(ch.chnum, ++ freq = ieee80211_channel_to_frequency(ch.control_ch_num, + ch.band == BRCMU_CHAN_BAND_2G ? + IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c +@@ -107,6 +107,7 @@ static void brcmu_d11n_decchspec(struct + u16 val; + + ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); ++ ch->control_ch_num = ch->chnum; + + switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) { + case BRCMU_CHSPEC_D11N_BW_20: +@@ -118,10 +119,10 @@ static void brcmu_d11n_decchspec(struct + val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK; + if (val == BRCMU_CHSPEC_D11N_SB_L) { + ch->sb = BRCMU_CHAN_SB_L; +- ch->chnum -= CH_10MHZ_APART; ++ ch->control_ch_num -= CH_10MHZ_APART; + } else { + ch->sb = BRCMU_CHAN_SB_U; +- ch->chnum += CH_10MHZ_APART; ++ ch->control_ch_num += CH_10MHZ_APART; + } + break; + default: +@@ -147,6 +148,7 @@ static void brcmu_d11ac_decchspec(struct + u16 val; + + ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); ++ ch->control_ch_num = ch->chnum; + + switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) { + case BRCMU_CHSPEC_D11AC_BW_20: +@@ -158,10 +160,10 @@ static void brcmu_d11ac_decchspec(struct + val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK; + if (val == BRCMU_CHSPEC_D11AC_SB_L) { + ch->sb = BRCMU_CHAN_SB_L; +- ch->chnum -= CH_10MHZ_APART; ++ ch->control_ch_num -= CH_10MHZ_APART; + } else if (val == BRCMU_CHSPEC_D11AC_SB_U) { + ch->sb = BRCMU_CHAN_SB_U; +- ch->chnum += CH_10MHZ_APART; ++ ch->control_ch_num += CH_10MHZ_APART; + } else { + WARN_ON_ONCE(1); + } +@@ -172,16 +174,16 @@ static void brcmu_d11ac_decchspec(struct + BRCMU_CHSPEC_D11AC_SB_SHIFT); + switch (ch->sb) { + case BRCMU_CHAN_SB_LL: +- ch->chnum -= CH_30MHZ_APART; ++ ch->control_ch_num -= CH_30MHZ_APART; + break; + case BRCMU_CHAN_SB_LU: +- ch->chnum -= CH_10MHZ_APART; ++ ch->control_ch_num -= CH_10MHZ_APART; + break; + case BRCMU_CHAN_SB_UL: +- ch->chnum += CH_10MHZ_APART; ++ ch->control_ch_num += CH_10MHZ_APART; + break; + case BRCMU_CHAN_SB_UU: +- ch->chnum += CH_30MHZ_APART; ++ ch->control_ch_num += CH_30MHZ_APART; + break; + default: + WARN_ON_ONCE(1); +--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h +@@ -125,14 +125,36 @@ enum brcmu_chan_sb { + BRCMU_CHAN_SB_UU = BRCMU_CHAN_SB_LUU, + }; + ++/** ++ * struct brcmu_chan - stores channel formats ++ * ++ * This structure can be used with functions translating chanspec into generic ++ * channel info and the other way. ++ * ++ * @chspec: firmware specific format ++ * @chnum: center channel number ++ * @control_ch_num: control channel number ++ * @band: frequency band ++ * @bw: channel width ++ * @sb: control sideband (location of control channel against the center one) ++ */ + struct brcmu_chan { + u16 chspec; + u8 chnum; ++ u8 control_ch_num; + u8 band; + enum brcmu_chan_bw bw; + enum brcmu_chan_sb sb; + }; + ++/** ++ * struct brcmu_d11inf - provides functions translating channel format ++ * ++ * @io_type: determines version of channel format used by firmware ++ * @encchspec: encodes channel info into a chanspec, requires center channel ++ * number, ignores control one ++ * @decchspec: decodes chanspec into generic info ++ */ + struct brcmu_d11inf { + u8 io_type; + diff --git a/package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch b/package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch new file mode 100644 index 0000000000..3344e05af8 --- /dev/null +++ b/package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch @@ -0,0 +1,94 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +Date: Fri, 20 May 2016 13:38:58 +0200 +Subject: [PATCH] brcmfmac: support get_channel cfg80211 callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is important for brcmfmac as some of released firmwares (e.g. +brcmfmac4366b-pcie.bin) may pick different channel than requested. This +has been tested with BCM4366B1 in D-Link DIR-885L. + +Signed-off-by: Rafał Miłecki <zajec5@gmail.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -4769,6 +4769,68 @@ exit: + return err; + } + ++static int brcmf_cfg80211_get_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); ++ struct net_device *ndev = wdev->netdev; ++ struct brcmf_if *ifp; ++ struct brcmu_chan ch; ++ enum nl80211_band band = 0; ++ enum nl80211_chan_width width = 0; ++ u32 chanspec; ++ int freq, err; ++ ++ if (!ndev) ++ return -ENODEV; ++ ifp = netdev_priv(ndev); ++ ++ err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec); ++ if (err) { ++ brcmf_err("chanspec failed (%d)\n", err); ++ return err; ++ } ++ ++ ch.chspec = chanspec; ++ cfg->d11inf.decchspec(&ch); ++ ++ switch (ch.band) { ++ case BRCMU_CHAN_BAND_2G: ++ band = NL80211_BAND_2GHZ; ++ break; ++ case BRCMU_CHAN_BAND_5G: ++ band = NL80211_BAND_5GHZ; ++ break; ++ } ++ ++ switch (ch.bw) { ++ case BRCMU_CHAN_BW_80: ++ width = NL80211_CHAN_WIDTH_80; ++ break; ++ case BRCMU_CHAN_BW_40: ++ width = NL80211_CHAN_WIDTH_40; ++ break; ++ case BRCMU_CHAN_BW_20: ++ width = NL80211_CHAN_WIDTH_20; ++ break; ++ case BRCMU_CHAN_BW_80P80: ++ width = NL80211_CHAN_WIDTH_80P80; ++ break; ++ case BRCMU_CHAN_BW_160: ++ width = NL80211_CHAN_WIDTH_160; ++ break; ++ } ++ ++ freq = ieee80211_channel_to_frequency(ch.control_ch_num, band); ++ chandef->chan = ieee80211_get_channel(wiphy, freq); ++ chandef->width = width; ++ chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band); ++ chandef->center_freq2 = 0; ++ ++ return 0; ++} ++ + static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_crit_proto_id proto, +@@ -4906,6 +4968,7 @@ static struct cfg80211_ops wl_cfg80211_o + .mgmt_tx = brcmf_cfg80211_mgmt_tx, + .remain_on_channel = brcmf_p2p_remain_on_channel, + .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, ++ .get_channel = brcmf_cfg80211_get_channel, + .start_p2p_device = brcmf_p2p_start_device, + .stop_p2p_device = brcmf_p2p_stop_device, + .crit_proto_start = brcmf_cfg80211_crit_proto_start, |