mac80211: backport some brcmfmac patches
authorRafał Miłecki <zajec5@gmail.com>
Sun, 21 Jun 2015 12:07:33 +0000 (12:07 +0000)
committerRafał Miłecki <zajec5@gmail.com>
Sun, 21 Jun 2015 12:07:33 +0000 (12:07 +0000)
There are two important patches in this patchset: updating read pointer
quicker & rework of .get_station().
There are few more upstream patches that are p2p-related and weren't
backported in this commit.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
SVN-Revision: 46084

package/kernel/mac80211/patches/385-brcmfmac-Update-msgbuf-read-pointer-quicker.patch [new file with mode: 0644]
package/kernel/mac80211/patches/386-brcmfmac-remove-chipinfo-debugfs-entry.patch [new file with mode: 0644]
package/kernel/mac80211/patches/387-brcmfmac-remove-watchdog-reset-from-brcmf_pcie_busco.patch [new file with mode: 0644]
package/kernel/mac80211/patches/388-brcmfmac-use-debugfs_create_devm_seqfile-helper-func.patch [new file with mode: 0644]
package/kernel/mac80211/patches/389-brcmfmac-Check-if-firmware-supports-p2p.patch [new file with mode: 0644]
package/kernel/mac80211/patches/390-brcmfmac-Build-wiphy-mode-and-interface-combinations.patch [new file with mode: 0644]
package/kernel/mac80211/patches/391-brcmfmac-rework-.get_station-callback.patch [new file with mode: 0644]
package/kernel/mac80211/patches/392-brcmfmac-have-sdio-return-EIO-when-device-communicat.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/385-brcmfmac-Update-msgbuf-read-pointer-quicker.patch b/package/kernel/mac80211/patches/385-brcmfmac-Update-msgbuf-read-pointer-quicker.patch
new file mode 100644 (file)
index 0000000..74df9f9
--- /dev/null
@@ -0,0 +1,109 @@
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Mon, 8 Jun 2015 14:38:32 +0200
+Subject: [PATCH] brcmfmac: Update msgbuf read pointer quicker.
+
+On device to host data using msgbuf the read pointer gets updated
+once all data is processed. Updating this pointer more frequently
+allows the firmware to add more data quicker. This will result in
+slightly higher and more stable throughput on CPU bounded host
+processors.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
+@@ -223,8 +223,6 @@ void brcmf_commonring_write_cancel(struc
+ void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
+                                   u16 *n_items)
+ {
+-      void *ret_addr;
+-
+       if (commonring->cr_update_wptr)
+               commonring->cr_update_wptr(commonring->cr_ctx);
+@@ -235,19 +233,18 @@ void *brcmf_commonring_get_read_ptr(stru
+       if (*n_items == 0)
+               return NULL;
+-      ret_addr = commonring->buf_addr +
+-                 (commonring->r_ptr * commonring->item_len);
+-
+-      commonring->r_ptr += *n_items;
+-      if (commonring->r_ptr == commonring->depth)
+-              commonring->r_ptr = 0;
+-
+-      return ret_addr;
++      return commonring->buf_addr +
++             (commonring->r_ptr * commonring->item_len);
+ }
+-int brcmf_commonring_read_complete(struct brcmf_commonring *commonring)
++int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
++                                 u16 n_items)
+ {
++      commonring->r_ptr += n_items;
++      if (commonring->r_ptr == commonring->depth)
++              commonring->r_ptr = 0;
++
+       if (commonring->cr_write_rptr)
+               return commonring->cr_write_rptr(commonring->cr_ctx);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
+@@ -62,7 +62,8 @@ void brcmf_commonring_write_cancel(struc
+                                  u16 n_items);
+ void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
+                                   u16 *n_items);
+-int brcmf_commonring_read_complete(struct brcmf_commonring *commonring);
++int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
++                                 u16 n_items);
+ #define brcmf_commonring_n_items(commonring) (commonring->depth)
+ #define brcmf_commonring_len_item(commonring) (commonring->item_len)
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -75,6 +75,8 @@
+ #define BRCMF_MSGBUF_DELAY_TXWORKER_THRS      96
+ #define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS    32
++#define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS               48
++
+ struct msgbuf_common_hdr {
+       u8                              msgtype;
+@@ -1257,19 +1259,27 @@ static void brcmf_msgbuf_process_rx(stru
+ {
+       void *buf;
+       u16 count;
++      u16 processed;
+ again:
+       buf = brcmf_commonring_get_read_ptr(commonring, &count);
+       if (buf == NULL)
+               return;
++      processed = 0;
+       while (count) {
+               brcmf_msgbuf_process_msgtype(msgbuf,
+                                            buf + msgbuf->rx_dataoffset);
+               buf += brcmf_commonring_len_item(commonring);
++              processed++;
++              if (processed == BRCMF_MSGBUF_UPDATE_RX_PTR_THRS) {
++                      brcmf_commonring_read_complete(commonring, processed);
++                      processed = 0;
++              }
+               count--;
+       }
+-      brcmf_commonring_read_complete(commonring);
++      if (processed)
++              brcmf_commonring_read_complete(commonring, processed);
+       if (commonring->r_ptr == 0)
+               goto again;
diff --git a/package/kernel/mac80211/patches/386-brcmfmac-remove-chipinfo-debugfs-entry.patch b/package/kernel/mac80211/patches/386-brcmfmac-remove-chipinfo-debugfs-entry.patch
new file mode 100644 (file)
index 0000000..9e5b486
--- /dev/null
@@ -0,0 +1,39 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Mon, 8 Jun 2015 14:38:33 +0200
+Subject: [PATCH] brcmfmac: remove chipinfo debugfs entry
+
+The information provided by chipinfo is also provided by the
+revinfo debugfs entry. Removing it from debugfs.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
+@@ -41,15 +41,6 @@ void brcmf_debugfs_exit(void)
+       root_folder = NULL;
+ }
+-static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data)
+-{
+-      struct brcmf_bus *bus = dev_get_drvdata(seq->private);
+-
+-      seq_printf(seq, "chip: %x(%u) rev %u\n",
+-                 bus->chip, bus->chip, bus->chiprev);
+-      return 0;
+-}
+-
+ int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+ {
+       struct device *dev = drvr->bus_if->dev;
+@@ -58,7 +49,6 @@ int brcmf_debugfs_attach(struct brcmf_pu
+               return -ENODEV;
+       drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
+-      brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read);
+       return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
+ }
diff --git a/package/kernel/mac80211/patches/387-brcmfmac-remove-watchdog-reset-from-brcmf_pcie_busco.patch b/package/kernel/mac80211/patches/387-brcmfmac-remove-watchdog-reset-from-brcmf_pcie_busco.patch
new file mode 100644 (file)
index 0000000..c38b2cd
--- /dev/null
@@ -0,0 +1,53 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Mon, 8 Jun 2015 14:38:34 +0200
+Subject: [PATCH] brcmfmac: remove watchdog reset from
+ brcmf_pcie_buscoreprep()
+
+The watchdog reset as done in brcmf_pcie_buscoreprep() is not
+sufficient. It needs to modify PCIe core registers as well
+which is properly done by brcmf_pcie_reset_device() after the
+chip recognition is done. So the faulty watchdog reset can be
+removed as it was causing driver reload to fail and hang the
+system requiring a power-cycle. Instead the call to to the
+brcmf_pcie_reset_device() function is done twice in the unload.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+@@ -1629,20 +1629,7 @@ static void brcmf_pcie_buscore_write32(v
+ static int brcmf_pcie_buscoreprep(void *ctx)
+ {
+-      struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx;
+-      int err;
+-
+-      err = brcmf_pcie_get_resource(devinfo);
+-      if (err == 0) {
+-              /* Set CC watchdog to reset all the cores on the chip to bring
+-               * back dongle to a sane state.
+-               */
+-              brcmf_pcie_buscore_write32(ctx, CORE_CC_REG(SI_ENUM_BASE,
+-                                                          watchdog), 4);
+-              msleep(100);
+-      }
+-
+-      return err;
++      return brcmf_pcie_get_resource(ctx);
+ }
+@@ -1824,6 +1811,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
+               brcmf_pcie_intr_disable(devinfo);
+       brcmf_detach(&pdev->dev);
++      brcmf_pcie_reset_device(devinfo);
+       kfree(bus->bus_priv.pcie);
+       kfree(bus->msgbuf->flowrings);
diff --git a/package/kernel/mac80211/patches/388-brcmfmac-use-debugfs_create_devm_seqfile-helper-func.patch b/package/kernel/mac80211/patches/388-brcmfmac-use-debugfs_create_devm_seqfile-helper-func.patch
new file mode 100644 (file)
index 0000000..756fbb2
--- /dev/null
@@ -0,0 +1,69 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Mon, 8 Jun 2015 14:38:35 +0200
+Subject: [PATCH] brcmfmac: use debugfs_create_devm_seqfile() helper
+ function
+
+Some time ago the function debugfs_create_devm_seqfile() was
+introduced in debugfs. The caller simply needs to provide a
+device pointer and read function. The function brcmf_debugfs_add_entry()
+is now simply a wrapper only doing the work for CONFIG_BRCMDBG.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
+@@ -64,44 +64,12 @@ struct dentry *brcmf_debugfs_get_devdir(
+       return drvr->dbgfs_dir;
+ }
+-struct brcmf_debugfs_entry {
+-      int (*read)(struct seq_file *seq, void *data);
+-      struct brcmf_pub *drvr;
+-};
+-
+-static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f)
+-{
+-      struct brcmf_debugfs_entry *entry = inode->i_private;
+-
+-      return single_open(f, entry->read, entry->drvr->bus_if->dev);
+-}
+-
+-static const struct file_operations brcmf_debugfs_def_ops = {
+-      .owner = THIS_MODULE,
+-      .open = brcmf_debugfs_entry_open,
+-      .release = single_release,
+-      .read = seq_read,
+-      .llseek = seq_lseek
+-};
+-
+ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
+                           int (*read_fn)(struct seq_file *seq, void *data))
+ {
+-      struct dentry *dentry =  drvr->dbgfs_dir;
+-      struct brcmf_debugfs_entry *entry;
+-
+-      if (IS_ERR_OR_NULL(dentry))
+-              return -ENOENT;
+-
+-      entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL);
+-      if (!entry)
+-              return -ENOMEM;
+-
+-      entry->read = read_fn;
+-      entry->drvr = drvr;
+-
+-      dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
+-                                   &brcmf_debugfs_def_ops);
++      struct dentry *e;
+-      return PTR_ERR_OR_ZERO(dentry);
++      e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn,
++                                      drvr->dbgfs_dir, read_fn);
++      return PTR_ERR_OR_ZERO(e);
+ }
diff --git a/package/kernel/mac80211/patches/389-brcmfmac-Check-if-firmware-supports-p2p.patch b/package/kernel/mac80211/patches/389-brcmfmac-Check-if-firmware-supports-p2p.patch
new file mode 100644 (file)
index 0000000..ff24a4a
--- /dev/null
@@ -0,0 +1,42 @@
+From: Pontus Fuchs <pontusf@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:17 +0200
+Subject: [PATCH] brcmfmac: Check if firmware supports p2p
+
+Add a feature flag to reflect the firmware's p2p capability.
+
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Signed-off-by: Pontus Fuchs <pontusf@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+@@ -129,6 +129,7 @@ void brcmf_feat_attach(struct brcmf_pub
+               brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
+       if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
+               brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
++      brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
+       /* set chip related quirks */
+       switch (drvr->bus_if->chip) {
+--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
+@@ -23,12 +23,14 @@
+  * MCHAN: multi-channel for concurrent P2P.
+  * PNO: preferred network offload.
+  * WOWL: Wake-On-WLAN.
++ * P2P: peer-to-peer
+  */
+ #define BRCMF_FEAT_LIST \
+       BRCMF_FEAT_DEF(MBSS) \
+       BRCMF_FEAT_DEF(MCHAN) \
+       BRCMF_FEAT_DEF(PNO) \
+-      BRCMF_FEAT_DEF(WOWL)
++      BRCMF_FEAT_DEF(WOWL) \
++      BRCMF_FEAT_DEF(P2P)
+ /*
+  * Quirks:
+  *
diff --git a/package/kernel/mac80211/patches/390-brcmfmac-Build-wiphy-mode-and-interface-combinations.patch b/package/kernel/mac80211/patches/390-brcmfmac-Build-wiphy-mode-and-interface-combinations.patch
new file mode 100644 (file)
index 0000000..3876ba0
--- /dev/null
@@ -0,0 +1,198 @@
+From: Pontus Fuchs <pontusf@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:18 +0200
+Subject: [PATCH] brcmfmac: Build wiphy mode and interface combinations
+ dynamically
+
+Switch from using semi hard coded interface combinations. This makes
+it easier to announce what the firmware actually supports. This fixes
+the case where brcmfmac announces p2p but the firmware doesn't
+support it.
+
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Signed-off-by: Pontus Fuchs <pontusf@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -52,8 +52,6 @@
+ #define BRCMF_PNO_SCAN_COMPLETE               1
+ #define BRCMF_PNO_SCAN_INCOMPLETE     0
+-#define BRCMF_IFACE_MAX_CNT           3
+-
+ #define WPA_OUI                               "\x00\x50\xF2"  /* WPA OUI */
+ #define WPA_OUI_TYPE                  1
+ #define RSN_OUI                               "\x00\x0F\xAC"  /* RSN OUI */
+@@ -5639,53 +5637,6 @@ static int brcmf_setup_wiphybands(struct
+       return 0;
+ }
+-static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = {
+-      {
+-              .max = 1,
+-              .types = BIT(NL80211_IFTYPE_STATION) |
+-                       BIT(NL80211_IFTYPE_ADHOC)
+-      },
+-      {
+-              .max = 4,
+-              .types = BIT(NL80211_IFTYPE_AP)
+-      },
+-      {
+-              .max = 1,
+-              .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+-                       BIT(NL80211_IFTYPE_P2P_GO)
+-      },
+-      {
+-              .max = 1,
+-              .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+-      }
+-};
+-
+-static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = {
+-      {
+-              .max = 2,
+-              .types = BIT(NL80211_IFTYPE_STATION) |
+-                       BIT(NL80211_IFTYPE_ADHOC) |
+-                       BIT(NL80211_IFTYPE_AP)
+-      },
+-      {
+-              .max = 1,
+-              .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+-                       BIT(NL80211_IFTYPE_P2P_GO)
+-      },
+-      {
+-              .max = 1,
+-              .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+-      }
+-};
+-static struct ieee80211_iface_combination brcmf_iface_combos[] = {
+-      {
+-               .max_interfaces = BRCMF_IFACE_MAX_CNT,
+-               .num_different_channels = 1,
+-               .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss),
+-               .limits = brcmf_iface_limits_sbss,
+-      }
+-};
+-
+ static const struct ieee80211_txrx_stypes
+ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+       [NL80211_IFTYPE_STATION] = {
+@@ -5715,6 +5666,67 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+       }
+ };
++static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
++{
++      struct ieee80211_iface_combination *combo = NULL;
++      struct ieee80211_iface_limit *limits = NULL;
++      int i = 0, max_iface_cnt;
++
++      combo = kzalloc(sizeof(*combo), GFP_KERNEL);
++      if (!combo)
++              goto err;
++
++      limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
++      if (!limits)
++              goto err;
++
++      wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
++                               BIT(NL80211_IFTYPE_ADHOC) |
++                               BIT(NL80211_IFTYPE_AP);
++
++      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
++              combo->num_different_channels = 2;
++      else
++              combo->num_different_channels = 1;
++
++      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
++              limits[i].max = 1;
++              limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++              limits[i].max = 4;
++              limits[i++].types = BIT(NL80211_IFTYPE_AP);
++              max_iface_cnt = 5;
++      } else {
++              limits[i].max = 2;
++              limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
++                                  BIT(NL80211_IFTYPE_AP);
++              max_iface_cnt = 2;
++      }
++
++      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
++              wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
++                                        BIT(NL80211_IFTYPE_P2P_GO) |
++                                        BIT(NL80211_IFTYPE_P2P_DEVICE);
++              limits[i].max = 1;
++              limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
++                                  BIT(NL80211_IFTYPE_P2P_GO);
++              limits[i].max = 1;
++              limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
++              max_iface_cnt += 2;
++      }
++      combo->max_interfaces = max_iface_cnt;
++      combo->limits = limits;
++      combo->n_limits = i;
++
++      wiphy->iface_combinations = combo;
++      wiphy->n_iface_combinations = 1;
++      return 0;
++
++err:
++      kfree(limits);
++      kfree(combo);
++      return -ENOMEM;
++}
++
+ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
+ {
+       /* scheduled scan settings */
+@@ -5745,7 +5757,6 @@ static void brcmf_wiphy_wowl_params(stru
+ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
+       struct ieee80211_supported_band *band;
+-      struct ieee80211_iface_combination ifc_combo;
+       __le32 bandlist[3];
+       u32 n_bands;
+       int err, i;
+@@ -5753,24 +5764,11 @@ static int brcmf_setup_wiphy(struct wiph
+       wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+       wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+       wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+-      wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+-                               BIT(NL80211_IFTYPE_ADHOC) |
+-                               BIT(NL80211_IFTYPE_AP) |
+-                               BIT(NL80211_IFTYPE_P2P_CLIENT) |
+-                               BIT(NL80211_IFTYPE_P2P_GO) |
+-                               BIT(NL80211_IFTYPE_P2P_DEVICE);
+-      /* need VSDB firmware feature for concurrent channels */
+-      ifc_combo = brcmf_iface_combos[0];
+-      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+-              ifc_combo.num_different_channels = 2;
+-      if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+-              ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss),
+-              ifc_combo.limits = brcmf_iface_limits_mbss;
+-      }
+-      wiphy->iface_combinations = kmemdup(&ifc_combo,
+-                                          sizeof(ifc_combo),
+-                                          GFP_KERNEL);
+-      wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
++
++      err = brcmf_setup_ifmodes(wiphy, ifp);
++      if (err)
++              return err;
++
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+       wiphy->cipher_suites = __wl_cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+@@ -6035,6 +6033,8 @@ static void brcmf_free_wiphy(struct wiph
+       if (!wiphy)
+               return;
++      if (wiphy->iface_combinations)
++              kfree(wiphy->iface_combinations->limits);
+       kfree(wiphy->iface_combinations);
+       if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+               kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
diff --git a/package/kernel/mac80211/patches/391-brcmfmac-rework-.get_station-callback.patch b/package/kernel/mac80211/patches/391-brcmfmac-rework-.get_station-callback.patch
new file mode 100644 (file)
index 0000000..7bd0686
--- /dev/null
@@ -0,0 +1,326 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:19 +0200
+Subject: [PATCH] brcmfmac: rework .get_station() callback
+
+The .get_station() cfg80211 callback is used in several scenarios. In
+managed mode it can obtain information about the access-point and its
+BSS parameters. In managed mode it can also obtain information about
+TDLS peers. In AP mode it can obtain information about connected
+clients.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -2395,27 +2395,80 @@ brcmf_cfg80211_reconfigure_wep(struct br
+               brcmf_err("set wsec error (%d)\n", err);
+ }
++static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
++{
++      struct nl80211_sta_flag_update *sfu;
++
++      brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
++      si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
++      sfu = &si->sta_flags;
++      sfu->mask = BIT(NL80211_STA_FLAG_WME) |
++                  BIT(NL80211_STA_FLAG_AUTHENTICATED) |
++                  BIT(NL80211_STA_FLAG_ASSOCIATED) |
++                  BIT(NL80211_STA_FLAG_AUTHORIZED);
++      if (fw_sta_flags & BRCMF_STA_WME)
++              sfu->set |= BIT(NL80211_STA_FLAG_WME);
++      if (fw_sta_flags & BRCMF_STA_AUTHE)
++              sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
++      if (fw_sta_flags & BRCMF_STA_ASSOC)
++              sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
++      if (fw_sta_flags & BRCMF_STA_AUTHO)
++              sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
++}
++
++static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
++{
++      struct {
++              __le32 len;
++              struct brcmf_bss_info_le bss_le;
++      } *buf;
++      u16 capability;
++      int err;
++
++      buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
++      if (!buf)
++              return;
++
++      buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
++      err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
++                                   WL_BSS_INFO_MAX);
++      if (err) {
++              brcmf_err("Failed to get bss info (%d)\n", err);
++              return;
++      }
++      si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
++      si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
++      si->bss_param.dtim_period = buf->bss_le.dtim_period;
++      capability = le16_to_cpu(buf->bss_le.capability);
++      if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
++              si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
++      if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
++              si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
++      if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
++              si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
++}
++
+ static s32
+ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+                          const u8 *mac, struct station_info *sinfo)
+ {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+-      struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+-      struct brcmf_scb_val_le scb_val;
+-      int rssi;
+-      s32 rate;
+       s32 err = 0;
+-      u8 *bssid = profile->bssid;
+       struct brcmf_sta_info_le sta_info_le;
+-      u32 beacon_period;
+-      u32 dtim_period;
++      u32 sta_flags;
++      u32 is_tdls_peer;
+       brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
+       if (!check_vif_up(ifp->vif))
+               return -EIO;
+-      if (brcmf_is_apmode(ifp->vif)) {
+-              memcpy(&sta_info_le, mac, ETH_ALEN);
++      memset(&sta_info_le, 0, sizeof(sta_info_le));
++      memcpy(&sta_info_le, mac, ETH_ALEN);
++      err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
++                                     &sta_info_le,
++                                     sizeof(sta_info_le));
++      is_tdls_peer = !err;
++      if (err) {
+               err = brcmf_fil_iovar_data_get(ifp, "sta_info",
+                                              &sta_info_le,
+                                              sizeof(sta_info_le));
+@@ -2423,73 +2476,48 @@ brcmf_cfg80211_get_station(struct wiphy
+                       brcmf_err("GET STA INFO failed, %d\n", err);
+                       goto done;
+               }
+-              sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
+-              sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
+-              if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
+-                      sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
+-                      sinfo->connected_time = le32_to_cpu(sta_info_le.in);
+-              }
+-              brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
+-                        sinfo->inactive_time, sinfo->connected_time);
+-      } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
+-              if (memcmp(mac, bssid, ETH_ALEN)) {
+-                      brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
+-                                mac, bssid);
+-                      err = -ENOENT;
+-                      goto done;
+-              }
+-              /* Report the current tx rate */
+-              err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
+-              if (err) {
+-                      brcmf_err("Could not get rate (%d)\n", err);
+-                      goto done;
+-              } else {
++      }
++      brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
++      sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
++      sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
++      sta_flags = le32_to_cpu(sta_info_le.flags);
++      brcmf_convert_sta_flags(sta_flags, sinfo);
++      sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
++      if (is_tdls_peer)
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
++      else
++              sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
++      if (sta_flags & BRCMF_STA_ASSOC) {
++              sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
++              sinfo->connected_time = le32_to_cpu(sta_info_le.in);
++              brcmf_fill_bss_param(ifp, sinfo);
++      }
++      if (sta_flags & BRCMF_STA_SCBSTATS) {
++              sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
++              sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
++              sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
++              sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
++              sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
++              sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
++              sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
++              sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
++              if (sinfo->tx_packets) {
+                       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
+-                      sinfo->txrate.legacy = rate * 5;
+-                      brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
++                      sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
++                      sinfo->txrate.legacy /= 100;
+               }
+-
+-              if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
+-                           &ifp->vif->sme_state)) {
+-                      memset(&scb_val, 0, sizeof(scb_val));
+-                      err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
+-                                                   &scb_val, sizeof(scb_val));
+-                      if (err) {
+-                              brcmf_err("Could not get rssi (%d)\n", err);
+-                              goto done;
+-                      } else {
+-                              rssi = le32_to_cpu(scb_val.val);
+-                              sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+-                              sinfo->signal = rssi;
+-                              brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
+-                      }
+-                      err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
+-                                                  &beacon_period);
+-                      if (err) {
+-                              brcmf_err("Could not get beacon period (%d)\n",
+-                                        err);
+-                              goto done;
+-                      } else {
+-                              sinfo->bss_param.beacon_interval =
+-                                      beacon_period;
+-                              brcmf_dbg(CONN, "Beacon peroid %d\n",
+-                                        beacon_period);
+-                      }
+-                      err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
+-                                                  &dtim_period);
+-                      if (err) {
+-                              brcmf_err("Could not get DTIM period (%d)\n",
+-                                        err);
+-                              goto done;
+-                      } else {
+-                              sinfo->bss_param.dtim_period = dtim_period;
+-                              brcmf_dbg(CONN, "DTIM peroid %d\n",
+-                                        dtim_period);
+-                      }
+-                      sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
++              if (sinfo->rx_packets) {
++                      sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
++                      sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
++                      sinfo->rxrate.legacy /= 100;
++              }
++              if (le16_to_cpu(sta_info_le.ver) >= 4) {
++                      sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
++                      sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
++                      sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
++                      sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
+               }
+-      } else
+-              err = -EPERM;
++      }
+ done:
+       brcmf_dbg(TRACE, "Exit\n");
+       return err;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+@@ -32,7 +32,11 @@
+ #define       BRCMF_BSS_INFO_VERSION  109 /* curr ver of brcmf_bss_info_le struct */
+ #define BRCMF_BSS_RSSI_ON_CHANNEL     0x0002
+-#define BRCMF_STA_ASSOC                       0x10            /* Associated */
++#define BRCMF_STA_WME              0x00000002      /* WMM association */
++#define BRCMF_STA_AUTHE            0x00000008      /* Authenticated */
++#define BRCMF_STA_ASSOC            0x00000010      /* Associated */
++#define BRCMF_STA_AUTHO            0x00000020      /* Authorized */
++#define BRCMF_STA_SCBSTATS         0x00004000      /* Per STA debug stats */
+ /* size of brcmf_scan_params not including variable length array */
+ #define BRCMF_SCAN_PARAMS_FIXED_SIZE  64
+@@ -113,6 +117,7 @@
+ #define BRCMF_WOWL_MAXPATTERNSIZE     128
+ #define BRCMF_COUNTRY_BUF_SZ          4
++#define BRCMF_ANT_MAX                 4
+ /* join preference types for join_pref iovar */
+ enum brcmf_join_pref_types {
+@@ -456,25 +461,61 @@ struct brcmf_channel_info_le {
+ };
+ struct brcmf_sta_info_le {
+-      __le16  ver;            /* version of this struct */
+-      __le16  len;            /* length in bytes of this structure */
+-      __le16  cap;            /* sta's advertised capabilities */
+-      __le32  flags;          /* flags defined below */
+-      __le32  idle;           /* time since data pkt rx'd from sta */
+-      u8      ea[ETH_ALEN];           /* Station address */
+-      __le32  count;                  /* # rates in this set */
+-      u8      rates[BRCMF_MAXRATES_IN_SET];   /* rates in 500kbps units */
++      __le16 ver;             /* version of this struct */
++      __le16 len;             /* length in bytes of this structure */
++      __le16 cap;             /* sta's advertised capabilities */
++      __le32 flags;           /* flags defined below */
++      __le32 idle;            /* time since data pkt rx'd from sta */
++      u8 ea[ETH_ALEN];                /* Station address */
++      __le32 count;                   /* # rates in this set */
++      u8 rates[BRCMF_MAXRATES_IN_SET];        /* rates in 500kbps units */
+                                               /* w/hi bit set if basic */
+-      __le32  in;             /* seconds elapsed since associated */
+-      __le32  listen_interval_inms; /* Min Listen interval in ms for STA */
+-      __le32  tx_pkts;        /* # of packets transmitted */
+-      __le32  tx_failures;    /* # of packets failed */
+-      __le32  rx_ucast_pkts;  /* # of unicast packets received */
+-      __le32  rx_mcast_pkts;  /* # of multicast packets received */
+-      __le32  tx_rate;        /* Rate of last successful tx frame */
+-      __le32  rx_rate;        /* Rate of last successful rx frame */
+-      __le32  rx_decrypt_succeeds;    /* # of packet decrypted successfully */
+-      __le32  rx_decrypt_failures;    /* # of packet decrypted failed */
++      __le32 in;              /* seconds elapsed since associated */
++      __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
++      __le32 tx_pkts; /* # of packets transmitted */
++      __le32 tx_failures;     /* # of packets failed */
++      __le32 rx_ucast_pkts;   /* # of unicast packets received */
++      __le32 rx_mcast_pkts;   /* # of multicast packets received */
++      __le32 tx_rate; /* Rate of last successful tx frame */
++      __le32 rx_rate; /* Rate of last successful rx frame */
++      __le32 rx_decrypt_succeeds;     /* # of packet decrypted successfully */
++      __le32 rx_decrypt_failures;     /* # of packet decrypted failed */
++      __le32 tx_tot_pkts;    /* # of tx pkts (ucast + mcast) */
++      __le32 rx_tot_pkts;    /* # of data packets recvd (uni + mcast) */
++      __le32 tx_mcast_pkts;  /* # of mcast pkts txed */
++      __le64 tx_tot_bytes;   /* data bytes txed (ucast + mcast) */
++      __le64 rx_tot_bytes;   /* data bytes recvd (ucast + mcast) */
++      __le64 tx_ucast_bytes; /* data bytes txed (ucast) */
++      __le64 tx_mcast_bytes; /* # data bytes txed (mcast) */
++      __le64 rx_ucast_bytes; /* data bytes recvd (ucast) */
++      __le64 rx_mcast_bytes; /* data bytes recvd (mcast) */
++      s8 rssi[BRCMF_ANT_MAX];   /* per antenna rssi */
++      s8 nf[BRCMF_ANT_MAX];     /* per antenna noise floor */
++      __le16 aid;                    /* association ID */
++      __le16 ht_capabilities;        /* advertised ht caps */
++      __le16 vht_flags;              /* converted vht flags */
++      __le32 tx_pkts_retry_cnt;      /* # of frames where a retry was
++                                       * exhausted.
++                                       */
++      __le32 tx_pkts_retry_exhausted; /* # of user frames where a retry
++                                       * was exhausted
++                                       */
++      s8 rx_lastpkt_rssi[BRCMF_ANT_MAX]; /* Per antenna RSSI of last
++                                          * received data frame.
++                                          */
++      /* TX WLAN retry/failure statistics:
++       * Separated for host requested frames and locally generated frames.
++       * Include unicast frame only where the retries/failures can be counted.
++       */
++      __le32 tx_pkts_total;          /* # user frames sent successfully */
++      __le32 tx_pkts_retries;        /* # user frames retries */
++      __le32 tx_pkts_fw_total;       /* # FW generated sent successfully */
++      __le32 tx_pkts_fw_retries;     /* # retries for FW generated frames */
++      __le32 tx_pkts_fw_retry_exhausted;     /* # FW generated where a retry
++                                              * was exhausted
++                                              */
++      __le32 rx_pkts_retried;        /* # rx with retry bit set */
++      __le32 tx_rate_fallback;       /* lowest fallback TX rate */
+ };
+ struct brcmf_chanspec_list {
diff --git a/package/kernel/mac80211/patches/392-brcmfmac-have-sdio-return-EIO-when-device-communicat.patch b/package/kernel/mac80211/patches/392-brcmfmac-have-sdio-return-EIO-when-device-communicat.patch
new file mode 100644 (file)
index 0000000..302bc3e
--- /dev/null
@@ -0,0 +1,56 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 11 Jun 2015 00:12:20 +0200
+Subject: [PATCH] brcmfmac: have sdio return -EIO when device communication
+ is not possible
+
+The bus interface functions txctl and rxctl may be used while the device
+can not be accessed, eg. upon driver .remove() callback. This patch will
+immediately return -EIO when this is the case which speeds up the module
+unload.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+@@ -988,6 +988,7 @@ static void brcmf_sdiod_freezer_detach(s
+ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
+ {
++      sdiodev->state = BRCMF_SDIOD_DOWN;
+       if (sdiodev->bus) {
+               brcmf_sdio_remove(sdiodev->bus);
+               sdiodev->bus = NULL;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -2820,6 +2820,8 @@ static int brcmf_sdio_bus_txdata(struct
+       struct brcmf_sdio *bus = sdiodev->bus;
+       brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
++      if (sdiodev->state != BRCMF_SDIOD_DATA)
++              return -EIO;
+       /* Add space for the header */
+       skb_push(pkt, bus->tx_hdrlen);
+@@ -2948,6 +2950,8 @@ brcmf_sdio_bus_txctl(struct device *dev,
+       int ret;
+       brcmf_dbg(TRACE, "Enter\n");
++      if (sdiodev->state != BRCMF_SDIOD_DATA)
++              return -EIO;
+       /* Send from dpc */
+       bus->ctrl_frame_buf = msg;
+@@ -3238,6 +3242,8 @@ brcmf_sdio_bus_rxctl(struct device *dev,
+       struct brcmf_sdio *bus = sdiodev->bus;
+       brcmf_dbg(TRACE, "Enter\n");
++      if (sdiodev->state != BRCMF_SDIOD_DATA)
++              return -EIO;
+       /* Wait until control frame is available */
+       timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);