From: rmilecki Date: Fri, 17 Jun 2016 06:23:19 +0000 (+0000) Subject: mac80211: brcmfmac: add support for get_channel X-Git-Url: https://git.archive.openwrt.org/?p=openwrt.git;a=commitdiff_plain;h=8c7cbcc1afb8f8365c2e39643e69725e5c0c2d99 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 git-svn-id: svn://svn.openwrt.org/openwrt/trunk@49382 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- diff --git a/package/kernel/mac80211/patches/351-0006-brcmfmac-use-kmemdup.patch b/package/kernel/mac80211/patches/351-0006-brcmfmac-use-kmemdup.patch new file mode 100644 index 0000000000..913752c19d --- /dev/null +++ b/package/kernel/mac80211/patches/351-0006-brcmfmac-use-kmemdup.patch @@ -0,0 +1,28 @@ +From: Muhammad Falak R Wani +Date: Thu, 19 May 2016 19:29:03 +0530 +Subject: [PATCH] brcmfmac: use kmemdup + +Use kmemdup when some other buffer is immediately copied into allocated +region. It replaces call to allocation followed by memcpy, by a single +call to kmemdup. + +Signed-off-by: Muhammad Falak R Wani +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -6666,11 +6666,10 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + return NULL; + } + +- ops = kzalloc(sizeof(*ops), GFP_KERNEL); ++ ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL); + if (!ops) + return NULL; + +- memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops)); + ifp = netdev_priv(ndev); + #ifdef CONFIG_PM + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) 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..8b284f0b2f --- /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?= +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 +Reviewed-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -2705,7 +2705,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; + +@@ -2823,7 +2823,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); + +@@ -2833,7 +2833,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); +@@ -5251,7 +5251,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: +@@ -5773,14 +5773,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. +@@ -5882,7 +5883,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", +@@ -1385,7 +1385,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); +@@ -1428,7 +1428,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); +@@ -1873,7 +1873,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); +@@ -1898,7 +1898,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..cea4975735 --- /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?= +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 +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -4863,6 +4863,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, +@@ -5025,6 +5087,7 @@ static struct cfg80211_ops brcmf_cfg8021 + .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,