mac80211: brcmfmac: add support for get_channel
authorRafał Miłecki <zajec5@gmail.com>
Fri, 17 Jun 2016 07:50:11 +0000 (07:50 +0000)
committerRafał Miłecki <zajec5@gmail.com>
Fri, 17 Jun 2016 07:50:11 +0000 (07:50 +0000)
It's very useful for debugging problems with brcmfmac setting requested
channel.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Backport of r49382

SVN-Revision: 49385

package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch [new file with mode: 0644]
package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch [new file with mode: 0644]

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 (file)
index 0000000..a7074a2
--- /dev/null
@@ -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 (file)
index 0000000..3344e05
--- /dev/null
@@ -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,