add add new firmware support and additional fixes for wl18xx
authorImre Kaloz <kaloz@openwrt.org>
Tue, 18 Mar 2014 18:55:54 +0000 (18:55 +0000)
committerImre Kaloz <kaloz@openwrt.org>
Tue, 18 Mar 2014 18:55:54 +0000 (18:55 +0000)
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
SVN-Revision: 39947

21 files changed:
package/kernel/mac80211/Makefile
package/kernel/mac80211/patches/901-wlcore-memset-wl--rx_filter_enabled-to-zero-after-recovery.patch [new file with mode: 0644]
package/kernel/mac80211/patches/902-wlcore-cancel-Tx-watchdog-on-~-and-rearm-on-first-Tx-after.patch [new file with mode: 0644]
package/kernel/mac80211/patches/903-wlcore-block-read-writes-to-FW-during-ELP.patch [new file with mode: 0644]
package/kernel/mac80211/patches/904-wlcore-AP-don-t-start-mac80211-PS-on-non-peer-HLIDs.patch [new file with mode: 0644]
package/kernel/mac80211/patches/905-wlcore-wl12xx-wl18xx-simplify-fw_status-handling.patch [new file with mode: 0644]
package/kernel/mac80211/patches/906-wlcore-wl12xx-wl18xx-configure-num_links-per-hw.patch [new file with mode: 0644]
package/kernel/mac80211/patches/907-wlcore-wl12xx-wl18xx-configure-max_stations-per-hw.patch [new file with mode: 0644]
package/kernel/mac80211/patches/908-wlcore-wl12xx-wl18xx-configure-iface_combinations-per-hw.patch [new file with mode: 0644]
package/kernel/mac80211/patches/909-wl18xx-move-to-new-firmware-wl18xx-fw-3.bin.patch [new file with mode: 0644]
package/kernel/mac80211/patches/910-wlcore-send-EAPOL-frames-with-voice-priority.patch [new file with mode: 0644]
package/kernel/mac80211/patches/911-wlcore-don-t-stop-sched_scan-on-interface-removal.patch [new file with mode: 0644]
package/kernel/mac80211/patches/912-wlcore-wl18xx-allow-CCK-rates-for-AP-mode.patch [new file with mode: 0644]
package/kernel/mac80211/patches/913-wlcore-don-t-handle-unsetting-of-default-wep-key.patch [new file with mode: 0644]
package/kernel/mac80211/patches/914-wlcore-consider-multiple-APs-when-checking-active_link_count.patch [new file with mode: 0644]
package/kernel/mac80211/patches/915-wlcore-decrease-warning-verbosity-during-recovery.patch [new file with mode: 0644]
package/kernel/mac80211/patches/916-wlcore-increase-timeout-to-5000-msecs.patch [new file with mode: 0644]
package/kernel/mac80211/patches/917-wlcore-enable-beacon-filtering-only-after-receiving-a-beacon.patch [new file with mode: 0644]
package/kernel/mac80211/patches/918-wlcore-add-support-for-STA-CSA-with-chan-contexts.patch [new file with mode: 0644]
package/kernel/mac80211/patches/919-wl18xx-align-event-mailbox-with-current-fw.patch [new file with mode: 0644]
package/kernel/mac80211/patches/920-wlcore-don-t-switch-channels-on-disconnected-STA-vif.patch [new file with mode: 0644]

index 8b0571e3674df2a6ffcf19f25e43891af63f6584..6316825b21c7431584adcd1289678e4c1ff9e505 100644 (file)
@@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk
 PKG_NAME:=mac80211
 
 PKG_VERSION:=2014-01-23.1
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
 PKG_BACKPORT_VERSION:=
 PKG_MD5SUM:=8db16edbdaf4abc2e9c2f3b6c86736a6
@@ -1629,8 +1629,7 @@ define KernelPackage/wl18xx/install
        $(INSTALL_DIR) $(1)/lib/firmware/ti-connectivity
        $(INSTALL_DATA) \
                $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl18xx-conf.bin \
-               $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl18xx-fw.bin \
-               $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl18xx-fw-2.bin \
+               $(PKG_BUILD_DIR)/$(PKG_LINUX_FIRMWARE_SUBDIR)/ti-connectivity/wl18xx-fw-3.bin \
                $(1)/lib/firmware/ti-connectivity
 endef
 
diff --git a/package/kernel/mac80211/patches/901-wlcore-memset-wl--rx_filter_enabled-to-zero-after-recovery.patch b/package/kernel/mac80211/patches/901-wlcore-memset-wl--rx_filter_enabled-to-zero-after-recovery.patch
new file mode 100644 (file)
index 0000000..df2a6e9
--- /dev/null
@@ -0,0 +1,73 @@
+zero rx_filter_enabled array after recovery to avoid
+cases were the driver will keep trying to clear a
+filter which is not configured in FW.
+
+Such case will cause consecutive recoveries due to
+command execution failures.
+
+While on it, convert rx_filter_enabled to bitmap,
+to save some memory and make sparse happy (it
+doesn't like sizeof(bool array)).
+
+Signed-off-by: Nadim Zubidat <nadimz@ti.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/main.c   | 1 +
+ drivers/net/wireless/ti/wlcore/rx.c     | 9 ++++++---
+ drivers/net/wireless/ti/wlcore/wlcore.h | 2 +-
+ 3 files changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -1914,6 +1914,7 @@ static void wlcore_op_stop_locked(struct
+       memset(wl->links_map, 0, sizeof(wl->links_map));
+       memset(wl->roc_map, 0, sizeof(wl->roc_map));
+       memset(wl->session_ids, 0, sizeof(wl->session_ids));
++      memset(wl->rx_filter_enabled, 0, sizeof(wl->rx_filter_enabled));
+       wl->active_sta_count = 0;
+       wl->active_link_count = 0;
+--- a/drivers/net/wireless/ti/wlcore/rx.c
++++ b/drivers/net/wireless/ti/wlcore/rx.c
+@@ -302,7 +302,7 @@ int wl1271_rx_filter_enable(struct wl127
+ {
+       int ret;
+-      if (wl->rx_filter_enabled[index] == enable) {
++      if (!!test_bit(index, wl->rx_filter_enabled) == enable) {
+               wl1271_warning("Request to enable an already "
+                            "enabled rx filter %d", index);
+               return 0;
+@@ -316,7 +316,10 @@ int wl1271_rx_filter_enable(struct wl127
+               return ret;
+       }
+-      wl->rx_filter_enabled[index] = enable;
++      if (enable)
++              __set_bit(index, wl->rx_filter_enabled);
++      else
++              __clear_bit(index, wl->rx_filter_enabled);
+       return 0;
+ }
+@@ -326,7 +329,7 @@ int wl1271_rx_filter_clear_all(struct wl
+       int i, ret = 0;
+       for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
+-              if (!wl->rx_filter_enabled[i])
++              if (!test_bit(i, wl->rx_filter_enabled))
+                       continue;
+               ret = wl1271_rx_filter_enable(wl, i, 0, NULL);
+               if (ret)
+--- a/drivers/net/wireless/ti/wlcore/wlcore.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore.h
+@@ -453,7 +453,7 @@ struct wl1271 {
+       size_t fw_status_priv_len;
+       /* RX Data filter rule state - enabled/disabled */
+-      bool rx_filter_enabled[WL1271_MAX_RX_FILTERS];
++      unsigned long rx_filter_enabled[BITS_TO_LONGS(WL1271_MAX_RX_FILTERS)];
+       /* size of the private static data */
+       size_t static_data_priv_len;
diff --git a/package/kernel/mac80211/patches/902-wlcore-cancel-Tx-watchdog-on-~-and-rearm-on-first-Tx-after.patch b/package/kernel/mac80211/patches/902-wlcore-cancel-Tx-watchdog-on-~-and-rearm-on-first-Tx-after.patch
new file mode 100644 (file)
index 0000000..497227d
--- /dev/null
@@ -0,0 +1,73 @@
+Sometimes a tx_flush during suspend fails, but the FW manages to flush
+out the packets during the time when the host is supsended. Cancel
+the Tx-watchdog on suspend to not cause a spurious recovery on resume
+for that case. Set a flag to reinit the watchdog on the first Tx after
+resume, so we'll still recover if the FW is not empty and there's
+indeed a problem.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/main.c     | 13 +++++++++++++
+ drivers/net/wireless/ti/wlcore/tx.c       |  9 +++++++--
+ drivers/net/wireless/ti/wlcore/wlcore_i.h |  1 +
+ 3 files changed, 21 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -1767,6 +1767,12 @@ static int wl1271_op_suspend(struct ieee
+       flush_work(&wl->tx_work);
+       flush_delayed_work(&wl->elp_work);
++      /*
++       * Cancel the watchdog even if above tx_flush failed. We will detect
++       * it on resume anyway.
++       */
++      cancel_delayed_work(&wl->tx_watchdog_work);
++
+       return 0;
+ }
+@@ -1824,6 +1830,13 @@ static int wl1271_op_resume(struct ieee8
+ out:
+       wl->wow_enabled = false;
++
++      /*
++       * Set a flag to re-init the watchdog on the first Tx after resume.
++       * That way we avoid possible conditions where Tx-complete interrupts
++       * fail to arrive and we perform a spurious recovery.
++       */
++      set_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags);
+       mutex_unlock(&wl->mutex);
+       return 0;
+--- a/drivers/net/wireless/ti/wlcore/tx.c
++++ b/drivers/net/wireless/ti/wlcore/tx.c
+@@ -234,8 +234,13 @@ static int wl1271_tx_allocate(struct wl1
+               wl->tx_blocks_available -= total_blocks;
+               wl->tx_allocated_blocks += total_blocks;
+-              /* If the FW was empty before, arm the Tx watchdog */
+-              if (wl->tx_allocated_blocks == total_blocks)
++              /*
++               * If the FW was empty before, arm the Tx watchdog. Also do
++               * this on the first Tx after resume, as we always cancel the
++               * watchdog on suspend.
++               */
++              if (wl->tx_allocated_blocks == total_blocks ||
++                  test_and_clear_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags))
+                       wl12xx_rearm_tx_watchdog_locked(wl);
+               ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
+@@ -240,6 +240,7 @@ enum wl12xx_flags {
+       WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
+       WL1271_FLAG_INTENDED_FW_RECOVERY,
+       WL1271_FLAG_IO_FAILED,
++      WL1271_FLAG_REINIT_TX_WDOG,
+ };
+ enum wl12xx_vif_flags {
diff --git a/package/kernel/mac80211/patches/903-wlcore-block-read-writes-to-FW-during-ELP.patch b/package/kernel/mac80211/patches/903-wlcore-block-read-writes-to-FW-during-ELP.patch
new file mode 100644 (file)
index 0000000..1aafb32
--- /dev/null
@@ -0,0 +1,36 @@
+When the chip is in ELP mode read/write to FW is invalid and may cause
+the lower layers to get stuck. The reads/writes concerning ELP wakeup
+are the exception here and are checked for. In addition to blocking the
+IO, produce a warning.
+
+Signed-off-by: Barak Bercovitz <barak@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/io.h | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/io.h
++++ b/drivers/net/wireless/ti/wlcore/io.h
+@@ -60,7 +60,9 @@ static inline int __must_check wlcore_ra
+ {
+       int ret;
+-      if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags))
++      if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags) ||
++          WARN_ON((test_bit(WL1271_FLAG_IN_ELP, &wl->flags) &&
++                   addr != HW_ACCESS_ELP_CTRL_REG)))
+               return -EIO;
+       ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed);
+@@ -76,7 +78,9 @@ static inline int __must_check wlcore_ra
+ {
+       int ret;
+-      if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags))
++      if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags) ||
++          WARN_ON((test_bit(WL1271_FLAG_IN_ELP, &wl->flags) &&
++                   addr != HW_ACCESS_ELP_CTRL_REG)))
+               return -EIO;
+       ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed);
diff --git a/package/kernel/mac80211/patches/904-wlcore-AP-don-t-start-mac80211-PS-on-non-peer-HLIDs.patch b/package/kernel/mac80211/patches/904-wlcore-AP-don-t-start-mac80211-PS-on-non-peer-HLIDs.patch
new file mode 100644 (file)
index 0000000..3942f1e
--- /dev/null
@@ -0,0 +1,28 @@
+It seems the wl18xx FW sometimes sends spurious changes on the PSM state
+of the broadcast HLID. This causes us to search for a station on a
+non-peer link and fail, causing warnings in our log.
+
+Prevent the driver from considering PSM changes for any non-peer HLIDs.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/ps.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ti/wlcore/ps.c
++++ b/drivers/net/wireless/ti/wlcore/ps.c
+@@ -280,7 +280,11 @@ void wl12xx_ps_link_start(struct wl1271
+       struct ieee80211_sta *sta;
+       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+-      if (test_bit(hlid, &wl->ap_ps_map))
++      if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS))
++              return;
++
++      if (!test_bit(hlid, wlvif->ap.sta_hlid_map) ||
++          test_bit(hlid, &wl->ap_ps_map))
+               return;
+       wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d "
diff --git a/package/kernel/mac80211/patches/905-wlcore-wl12xx-wl18xx-simplify-fw_status-handling.patch b/package/kernel/mac80211/patches/905-wlcore-wl12xx-wl18xx-simplify-fw_status-handling.patch
new file mode 100644 (file)
index 0000000..c669797
--- /dev/null
@@ -0,0 +1,731 @@
+Instead of splitting the fw_status into 2 and using some
+complex calculations, read the fw status and let each low-level
+driver (wl12xx/wl18xx) convert it into a common struct.
+
+This is required for the upcoming fw api changes, which
+break the current logic anyway.
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wl12xx/main.c     | 35 ++++++++++-
+ drivers/net/wireless/ti/wl12xx/wl12xx.h   | 50 ++++++++++++++++
+ drivers/net/wireless/ti/wl18xx/main.c     | 39 ++++++++++++-
+ drivers/net/wireless/ti/wl18xx/tx.c       |  4 +-
+ drivers/net/wireless/ti/wl18xx/wl18xx.h   | 53 +++++++++++++++++
+ drivers/net/wireless/ti/wlcore/cmd.c      | 11 +++-
+ drivers/net/wireless/ti/wlcore/hw_ops.h   |  9 +++
+ drivers/net/wireless/ti/wlcore/main.c     | 96 +++++++++++++++----------------
+ drivers/net/wireless/ti/wlcore/rx.c       |  2 +-
+ drivers/net/wireless/ti/wlcore/rx.h       |  2 +-
+ drivers/net/wireless/ti/wlcore/wlcore.h   |  7 ++-
+ drivers/net/wireless/ti/wlcore/wlcore_i.h | 72 ++++++++++-------------
+ 12 files changed, 277 insertions(+), 103 deletions(-)
+
+--- a/drivers/net/wireless/ti/wl12xx/main.c
++++ b/drivers/net/wireless/ti/wl12xx/main.c
+@@ -1378,7 +1378,7 @@ static u32 wl12xx_get_rx_packet_len(stru
+ static int wl12xx_tx_delayed_compl(struct wl1271 *wl)
+ {
+-      if (wl->fw_status_1->tx_results_counter ==
++      if (wl->fw_status->tx_results_counter ==
+           (wl->tx_results_count & 0xff))
+               return 0;
+@@ -1438,6 +1438,37 @@ out:
+       return ret;
+ }
++static void wl12xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
++                                   struct wl_fw_status *fw_status)
++{
++      struct wl12xx_fw_status *int_fw_status = raw_fw_status;
++
++      fw_status->intr = le32_to_cpu(int_fw_status->intr);
++      fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
++      fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
++      fw_status->tx_results_counter = int_fw_status->tx_results_counter;
++      fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
++
++      fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
++      fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
++      fw_status->link_fast_bitmap =
++                      le32_to_cpu(int_fw_status->link_fast_bitmap);
++      fw_status->total_released_blks =
++                      le32_to_cpu(int_fw_status->total_released_blks);
++      fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
++
++      fw_status->counters.tx_released_pkts =
++                      int_fw_status->counters.tx_released_pkts;
++      fw_status->counters.tx_lnk_free_pkts =
++                      int_fw_status->counters.tx_lnk_free_pkts;
++      fw_status->counters.tx_voice_released_blks =
++                      int_fw_status->counters.tx_voice_released_blks;
++      fw_status->counters.tx_last_rate =
++                      int_fw_status->counters.tx_last_rate;
++
++      fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
++}
++
+ static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl,
+                                      struct wl12xx_vif *wlvif)
+ {
+@@ -1677,6 +1708,7 @@ static struct wlcore_ops wl12xx_ops = {
+       .tx_delayed_compl       = wl12xx_tx_delayed_compl,
+       .hw_init                = wl12xx_hw_init,
+       .init_vif               = NULL,
++      .convert_fw_status      = wl12xx_convert_fw_status,
+       .sta_get_ap_rate_mask   = wl12xx_sta_get_ap_rate_mask,
+       .get_pg_ver             = wl12xx_get_pg_ver,
+       .get_mac                = wl12xx_get_mac,
+@@ -1725,6 +1757,7 @@ static int wl12xx_setup(struct wl1271 *w
+       wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
+       wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
+       wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
++      wl->fw_status_len = sizeof(struct wl12xx_fw_status);
+       wl->fw_status_priv_len = 0;
+       wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
+       wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap);
+--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
++++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
+@@ -79,4 +79,54 @@ struct wl12xx_priv {
+       struct wl127x_rx_mem_pool_addr *rx_mem_addr;
+ };
++struct wl12xx_fw_packet_counters {
++      /* Cumulative counter of released packets per AC */
++      u8 tx_released_pkts[NUM_TX_QUEUES];
++
++      /* Cumulative counter of freed packets per HLID */
++      u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
++
++      /* Cumulative counter of released Voice memory blocks */
++      u8 tx_voice_released_blks;
++
++      /* Tx rate of the last transmitted packet */
++      u8 tx_last_rate;
++
++      u8 padding[2];
++} __packed;
++
++/* FW status registers */
++struct wl12xx_fw_status {
++      __le32 intr;
++      u8  fw_rx_counter;
++      u8  drv_rx_counter;
++      u8  reserved;
++      u8  tx_results_counter;
++      __le32 rx_pkt_descs[WL12XX_NUM_RX_DESCRIPTORS];
++
++      __le32 fw_localtime;
++
++      /*
++       * A bitmap (where each bit represents a single HLID)
++       * to indicate if the station is in PS mode.
++       */
++      __le32 link_ps_bitmap;
++
++      /*
++       * A bitmap (where each bit represents a single HLID) to indicate
++       * if the station is in Fast mode
++       */
++      __le32 link_fast_bitmap;
++
++      /* Cumulative counter of total released mem blocks since FW-reset */
++      __le32 total_released_blks;
++
++      /* Size (in Memory Blocks) of TX pool */
++      __le32 tx_total;
++
++      struct wl12xx_fw_packet_counters counters;
++
++      __le32 log_start_addr;
++} __packed;
++
+ #endif /* __WL12XX_PRIV_H__ */
+--- a/drivers/net/wireless/ti/wl18xx/main.c
++++ b/drivers/net/wireless/ti/wl18xx/main.c
+@@ -1133,6 +1133,39 @@ static int wl18xx_hw_init(struct wl1271
+       return ret;
+ }
++static void wl18xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
++                                   struct wl_fw_status *fw_status)
++{
++      struct wl18xx_fw_status *int_fw_status = raw_fw_status;
++
++      fw_status->intr = le32_to_cpu(int_fw_status->intr);
++      fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
++      fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
++      fw_status->tx_results_counter = int_fw_status->tx_results_counter;
++      fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
++
++      fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
++      fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
++      fw_status->link_fast_bitmap =
++                      le32_to_cpu(int_fw_status->link_fast_bitmap);
++      fw_status->total_released_blks =
++                      le32_to_cpu(int_fw_status->total_released_blks);
++      fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
++
++      fw_status->counters.tx_released_pkts =
++                      int_fw_status->counters.tx_released_pkts;
++      fw_status->counters.tx_lnk_free_pkts =
++                      int_fw_status->counters.tx_lnk_free_pkts;
++      fw_status->counters.tx_voice_released_blks =
++                      int_fw_status->counters.tx_voice_released_blks;
++      fw_status->counters.tx_last_rate =
++                      int_fw_status->counters.tx_last_rate;
++
++      fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
++
++      fw_status->priv = &int_fw_status->priv;
++}
++
+ static void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
+                                   struct wl1271_tx_hw_descr *desc,
+                                   struct sk_buff *skb)
+@@ -1572,7 +1605,7 @@ static bool wl18xx_lnk_high_prio(struct
+ {
+       u8 thold;
+       struct wl18xx_fw_status_priv *status_priv =
+-              (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
++              (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
+       u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+       /* suspended links are never high priority */
+@@ -1594,7 +1627,7 @@ static bool wl18xx_lnk_low_prio(struct w
+ {
+       u8 thold;
+       struct wl18xx_fw_status_priv *status_priv =
+-              (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
++              (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
+       u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+       if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+@@ -1632,6 +1665,7 @@ static struct wlcore_ops wl18xx_ops = {
+       .tx_immediate_compl = wl18xx_tx_immediate_completion,
+       .tx_delayed_compl = NULL,
+       .hw_init        = wl18xx_hw_init,
++      .convert_fw_status = wl18xx_convert_fw_status,
+       .set_tx_desc_csum = wl18xx_set_tx_desc_csum,
+       .get_pg_ver     = wl18xx_get_pg_ver,
+       .set_rx_csum = wl18xx_set_rx_csum,
+@@ -1726,6 +1760,7 @@ static int wl18xx_setup(struct wl1271 *w
+       wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
+       wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
+       wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
++      wl->fw_status_len = sizeof(struct wl18xx_fw_status);
+       wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv);
+       wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
+       wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
+--- a/drivers/net/wireless/ti/wl18xx/tx.c
++++ b/drivers/net/wireless/ti/wl18xx/tx.c
+@@ -32,7 +32,7 @@ static
+ void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
+                            struct ieee80211_tx_rate *rate)
+ {
+-      u8 fw_rate = wl->fw_status_2->counters.tx_last_rate;
++      u8 fw_rate = wl->fw_status->counters.tx_last_rate;
+       if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
+               wl1271_error("last Tx rate invalid: %d", fw_rate);
+@@ -139,7 +139,7 @@ static void wl18xx_tx_complete_packet(st
+ void wl18xx_tx_immediate_complete(struct wl1271 *wl)
+ {
+       struct wl18xx_fw_status_priv *status_priv =
+-              (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
++              (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
+       struct wl18xx_priv *priv = wl->priv;
+       u8 i;
+--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
++++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
+@@ -109,6 +109,59 @@ struct wl18xx_fw_status_priv {
+       u8 padding[3];
+ };
++struct wl18xx_fw_packet_counters {
++      /* Cumulative counter of released packets per AC */
++      u8 tx_released_pkts[NUM_TX_QUEUES];
++
++      /* Cumulative counter of freed packets per HLID */
++      u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
++
++      /* Cumulative counter of released Voice memory blocks */
++      u8 tx_voice_released_blks;
++
++      /* Tx rate of the last transmitted packet */
++      u8 tx_last_rate;
++
++      u8 padding[2];
++} __packed;
++
++/* FW status registers */
++struct wl18xx_fw_status {
++      __le32 intr;
++      u8  fw_rx_counter;
++      u8  drv_rx_counter;
++      u8  reserved;
++      u8  tx_results_counter;
++      __le32 rx_pkt_descs[WL18XX_NUM_RX_DESCRIPTORS];
++
++      __le32 fw_localtime;
++
++      /*
++       * A bitmap (where each bit represents a single HLID)
++       * to indicate if the station is in PS mode.
++       */
++      __le32 link_ps_bitmap;
++
++      /*
++       * A bitmap (where each bit represents a single HLID) to indicate
++       * if the station is in Fast mode
++       */
++      __le32 link_fast_bitmap;
++
++      /* Cumulative counter of total released mem blocks since FW-reset */
++      __le32 total_released_blks;
++
++      /* Size (in Memory Blocks) of TX pool */
++      __le32 tx_total;
++
++      struct wl18xx_fw_packet_counters counters;
++
++      __le32 log_start_addr;
++
++      /* Private status to be used by the lower drivers */
++      struct wl18xx_fw_status_priv priv;
++} __packed;
++
+ #define WL18XX_PHY_VERSION_MAX_LEN 20
+ struct wl18xx_static_data_priv {
+--- a/drivers/net/wireless/ti/wlcore/cmd.c
++++ b/drivers/net/wireless/ti/wlcore/cmd.c
+@@ -324,9 +324,14 @@ int wl12xx_allocate_link(struct wl1271 *
+       __set_bit(link, wlvif->links_map);
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+-      /* take the last "freed packets" value from the current FW status */
+-      wl->links[link].prev_freed_pkts =
+-                      wl->fw_status_2->counters.tx_lnk_free_pkts[link];
++      /*
++       * take the last "freed packets" value from the current FW status.
++       * on recovery, we might not have fw_status yet, and
++       * tx_lnk_free_pkts will be NULL. check for it.
++       */
++      if (wl->fw_status->counters.tx_lnk_free_pkts)
++              wl->links[link].prev_freed_pkts =
++                      wl->fw_status->counters.tx_lnk_free_pkts[link];
+       wl->links[link].wlvif = wlvif;
+       /*
+--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
++++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
+@@ -106,6 +106,15 @@ wlcore_hw_init_vif(struct wl1271 *wl, st
+       return 0;
+ }
++static inline void
++wlcore_hw_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
++                          struct wl_fw_status *fw_status)
++{
++      BUG_ON(!wl->ops->convert_fw_status);
++
++      wl->ops->convert_fw_status(wl, raw_fw_status, fw_status);
++}
++
+ static inline u32
+ wlcore_hw_sta_get_ap_rate_mask(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+ {
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -357,12 +357,12 @@ static void wl12xx_irq_ps_regulate_link(
+ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
+                                          struct wl12xx_vif *wlvif,
+-                                         struct wl_fw_status_2 *status)
++                                         struct wl_fw_status *status)
+ {
+       u32 cur_fw_ps_map;
+       u8 hlid;
+-      cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
++      cur_fw_ps_map = status->link_ps_bitmap;
+       if (wl->ap_fw_ps_map != cur_fw_ps_map) {
+               wl1271_debug(DEBUG_PSM,
+                            "link ps prev 0x%x cur 0x%x changed 0x%x",
+@@ -377,41 +377,38 @@ static void wl12xx_irq_update_links_stat
+                                           wl->links[hlid].allocated_pkts);
+ }
+-static int wlcore_fw_status(struct wl1271 *wl,
+-                          struct wl_fw_status_1 *status_1,
+-                          struct wl_fw_status_2 *status_2)
++static int wlcore_fw_status(struct wl1271 *wl, struct wl_fw_status *status)
+ {
+       struct wl12xx_vif *wlvif;
+       struct timespec ts;
+       u32 old_tx_blk_count = wl->tx_blocks_available;
+       int avail, freed_blocks;
+       int i;
+-      size_t status_len;
+       int ret;
+       struct wl1271_link *lnk;
+-      status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
+-              sizeof(*status_2) + wl->fw_status_priv_len;
+-
+-      ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
+-                                 status_len, false);
++      ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR,
++                                 wl->raw_fw_status,
++                                 wl->fw_status_len, false);
+       if (ret < 0)
+               return ret;
++      wlcore_hw_convert_fw_status(wl, wl->raw_fw_status, wl->fw_status);
++
+       wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
+                    "drv_rx_counter = %d, tx_results_counter = %d)",
+-                   status_1->intr,
+-                   status_1->fw_rx_counter,
+-                   status_1->drv_rx_counter,
+-                   status_1->tx_results_counter);
++                   status->intr,
++                   status->fw_rx_counter,
++                   status->drv_rx_counter,
++                   status->tx_results_counter);
+       for (i = 0; i < NUM_TX_QUEUES; i++) {
+               /* prevent wrap-around in freed-packets counter */
+               wl->tx_allocated_pkts[i] -=
+-                              (status_2->counters.tx_released_pkts[i] -
++                              (status->counters.tx_released_pkts[i] -
+                               wl->tx_pkts_freed[i]) & 0xff;
+-              wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
++              wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
+       }
+@@ -420,29 +417,28 @@ static int wlcore_fw_status(struct wl127
+               lnk = &wl->links[i];
+               /* prevent wrap-around in freed-packets counter */
+-              diff = (status_2->counters.tx_lnk_free_pkts[i] -
++              diff = (status->counters.tx_lnk_free_pkts[i] -
+                      lnk->prev_freed_pkts) & 0xff;
+               if (diff == 0)
+                       continue;
+               lnk->allocated_pkts -= diff;
+-              lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
++              lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[i];
+               /* accumulate the prev_freed_pkts counter */
+               lnk->total_freed_pkts += diff;
+       }
+       /* prevent wrap-around in total blocks counter */
+-      if (likely(wl->tx_blocks_freed <=
+-                 le32_to_cpu(status_2->total_released_blks)))
+-              freed_blocks = le32_to_cpu(status_2->total_released_blks) -
++      if (likely(wl->tx_blocks_freed <= status->total_released_blks))
++              freed_blocks = status->total_released_blks -
+                              wl->tx_blocks_freed;
+       else
+               freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
+-                             le32_to_cpu(status_2->total_released_blks);
++                             status->total_released_blks;
+-      wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
++      wl->tx_blocks_freed = status->total_released_blks;
+       wl->tx_allocated_blocks -= freed_blocks;
+@@ -458,7 +454,7 @@ static int wlcore_fw_status(struct wl127
+                       cancel_delayed_work(&wl->tx_watchdog_work);
+       }
+-      avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
++      avail = status->tx_total - wl->tx_allocated_blocks;
+       /*
+        * The FW might change the total number of TX memblocks before
+@@ -477,15 +473,15 @@ static int wlcore_fw_status(struct wl127
+       /* for AP update num of allocated TX blocks per link and ps status */
+       wl12xx_for_each_wlvif_ap(wl, wlvif) {
+-              wl12xx_irq_update_links_status(wl, wlvif, status_2);
++              wl12xx_irq_update_links_status(wl, wlvif, status);
+       }
+       /* update the host-chipset time offset */
+       getnstimeofday(&ts);
+       wl->time_offset = (timespec_to_ns(&ts) >> 10) -
+-              (s64)le32_to_cpu(status_2->fw_localtime);
++              (s64)(status->fw_localtime);
+-      wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap);
++      wl->fw_fast_lnk_map = status->link_fast_bitmap;
+       return 0;
+ }
+@@ -549,13 +545,13 @@ static int wlcore_irq_locked(struct wl12
+               clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
+               smp_mb__after_clear_bit();
+-              ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
++              ret = wlcore_fw_status(wl, wl->fw_status);
+               if (ret < 0)
+                       goto out;
+               wlcore_hw_tx_immediate_compl(wl);
+-              intr = le32_to_cpu(wl->fw_status_1->intr);
++              intr = wl->fw_status->intr;
+               intr &= WLCORE_ALL_INTR_MASK;
+               if (!intr) {
+                       done = true;
+@@ -584,7 +580,7 @@ static int wlcore_irq_locked(struct wl12
+               if (likely(intr & WL1271_ACX_INTR_DATA)) {
+                       wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
+-                      ret = wlcore_rx(wl, wl->fw_status_1);
++                      ret = wlcore_rx(wl, wl->fw_status);
+                       if (ret < 0)
+                               goto out;
+@@ -843,11 +839,11 @@ static void wl12xx_read_fwlog_panic(stru
+               wl12xx_cmd_stop_fwlog(wl);
+       /* Read the first memory block address */
+-      ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
++      ret = wlcore_fw_status(wl, wl->fw_status);
+       if (ret < 0)
+               goto out;
+-      addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
++      addr = wl->fw_status->log_start_addr;
+       if (!addr)
+               goto out;
+@@ -990,23 +986,23 @@ static int wlcore_fw_wakeup(struct wl127
+ static int wl1271_setup(struct wl1271 *wl)
+ {
+-      wl->fw_status_1 = kzalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
+-                                sizeof(*wl->fw_status_2) +
+-                                wl->fw_status_priv_len, GFP_KERNEL);
+-      if (!wl->fw_status_1)
+-              return -ENOMEM;
++      wl->raw_fw_status = kzalloc(wl->fw_status_len, GFP_KERNEL);
++      if (!wl->raw_fw_status)
++              goto err;
+-      wl->fw_status_2 = (struct wl_fw_status_2 *)
+-                              (((u8 *) wl->fw_status_1) +
+-                              WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
++      wl->fw_status = kzalloc(sizeof(*wl->fw_status), GFP_KERNEL);
++      if (!wl->fw_status)
++              goto err;
+       wl->tx_res_if = kzalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
+-      if (!wl->tx_res_if) {
+-              kfree(wl->fw_status_1);
+-              return -ENOMEM;
+-      }
++      if (!wl->tx_res_if)
++              goto err;
+       return 0;
++err:
++      kfree(wl->fw_status);
++      kfree(wl->raw_fw_status);
++      return -ENOMEM;
+ }
+ static int wl12xx_set_power_on(struct wl1271 *wl)
+@@ -1952,9 +1948,10 @@ static void wlcore_op_stop_locked(struct
+       wl1271_debugfs_reset(wl);
+-      kfree(wl->fw_status_1);
+-      wl->fw_status_1 = NULL;
+-      wl->fw_status_2 = NULL;
++      kfree(wl->raw_fw_status);
++      wl->raw_fw_status = NULL;
++      kfree(wl->fw_status);
++      wl->fw_status = NULL;
+       kfree(wl->tx_res_if);
+       wl->tx_res_if = NULL;
+       kfree(wl->target_mem_map);
+@@ -6058,7 +6055,8 @@ int wlcore_free_hw(struct wl1271 *wl)
+       kfree(wl->nvs);
+       wl->nvs = NULL;
+-      kfree(wl->fw_status_1);
++      kfree(wl->raw_fw_status);
++      kfree(wl->fw_status);
+       kfree(wl->tx_res_if);
+       destroy_workqueue(wl->freezable_wq);
+--- a/drivers/net/wireless/ti/wlcore/rx.c
++++ b/drivers/net/wireless/ti/wlcore/rx.c
+@@ -203,7 +203,7 @@ static int wl1271_rx_handle_data(struct
+       return is_data;
+ }
+-int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
++int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status)
+ {
+       unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
+       u32 buf_size;
+--- a/drivers/net/wireless/ti/wlcore/rx.h
++++ b/drivers/net/wireless/ti/wlcore/rx.h
+@@ -142,7 +142,7 @@ struct wl1271_rx_descriptor {
+       u8  reserved;
+ } __packed;
+-int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status);
++int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status);
+ u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
+ int wl1271_rx_filter_enable(struct wl1271 *wl,
+                           int index, bool enable,
+--- a/drivers/net/wireless/ti/wlcore/wlcore.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore.h
+@@ -73,6 +73,8 @@ struct wlcore_ops {
+       void (*tx_immediate_compl)(struct wl1271 *wl);
+       int (*hw_init)(struct wl1271 *wl);
+       int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
++      void (*convert_fw_status)(struct wl1271 *wl, void *raw_fw_status,
++                                struct wl_fw_status *fw_status);
+       u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,
+                                   struct wl12xx_vif *wlvif);
+       int (*get_pg_ver)(struct wl1271 *wl, s8 *ver);
+@@ -348,8 +350,8 @@ struct wl1271 {
+       u32 buffer_cmd;
+       u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
+-      struct wl_fw_status_1 *fw_status_1;
+-      struct wl_fw_status_2 *fw_status_2;
++      void *raw_fw_status;
++      struct wl_fw_status *fw_status;
+       struct wl1271_tx_hw_res_if *tx_res_if;
+       /* Current chipset configuration */
+@@ -450,6 +452,7 @@ struct wl1271 {
+       struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS];
+       /* size of the private FW status data */
++      size_t fw_status_len;
+       size_t fw_status_priv_len;
+       /* RX Data filter rule state - enabled/disabled */
+--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
+@@ -120,70 +120,58 @@ struct wl1271_chip {
+ #define AP_MAX_STATIONS            8
+-struct wl_fw_packet_counters {
+-      /* Cumulative counter of released packets per AC */
+-      u8 tx_released_pkts[NUM_TX_QUEUES];
+-
+-      /* Cumulative counter of freed packets per HLID */
+-      u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
+-
+-      /* Cumulative counter of released Voice memory blocks */
+-      u8 tx_voice_released_blks;
+-
+-      /* Tx rate of the last transmitted packet */
+-      u8 tx_last_rate;
+-
+-      u8 padding[2];
+-} __packed;
+-
+-/* FW status registers */
+-struct wl_fw_status_1 {
+-      __le32 intr;
++struct wl_fw_status {
++      u32 intr;
+       u8  fw_rx_counter;
+       u8  drv_rx_counter;
+-      u8  reserved;
+       u8  tx_results_counter;
+-      __le32 rx_pkt_descs[0];
+-} __packed;
+-
+-/*
+- * Each HW arch has a different number of Rx descriptors.
+- * The length of the status depends on it, since it holds an array
+- * of descriptors.
+- */
+-#define WLCORE_FW_STATUS_1_LEN(num_rx_desc) \
+-              (sizeof(struct wl_fw_status_1) + \
+-              (sizeof(((struct wl_fw_status_1 *)0)->rx_pkt_descs[0])) * \
+-              num_rx_desc)
++      __le32 *rx_pkt_descs;
+-struct wl_fw_status_2 {
+-      __le32 fw_localtime;
++      u32 fw_localtime;
+       /*
+        * A bitmap (where each bit represents a single HLID)
+        * to indicate if the station is in PS mode.
+        */
+-      __le32 link_ps_bitmap;
++      u32 link_ps_bitmap;
+       /*
+        * A bitmap (where each bit represents a single HLID) to indicate
+        * if the station is in Fast mode
+        */
+-      __le32 link_fast_bitmap;
++      u32 link_fast_bitmap;
+       /* Cumulative counter of total released mem blocks since FW-reset */
+-      __le32 total_released_blks;
++      u32 total_released_blks;
+       /* Size (in Memory Blocks) of TX pool */
+-      __le32 tx_total;
++      u32 tx_total;
+-      struct wl_fw_packet_counters counters;
++      struct {
++              /*
++               * Cumulative counter of released packets per AC
++               * (length of the array is NUM_TX_QUEUES)
++               */
++              u8 *tx_released_pkts;
++
++              /*
++               * Cumulative counter of freed packets per HLID
++               * (length of the array is WL12XX_MAX_LINKS)
++               */
++              u8 *tx_lnk_free_pkts;
++
++              /* Cumulative counter of released Voice memory blocks */
++              u8 tx_voice_released_blks;
++
++              /* Tx rate of the last transmitted packet */
++              u8 tx_last_rate;
++      } counters;
+-      __le32 log_start_addr;
++      u32 log_start_addr;
+       /* Private status to be used by the lower drivers */
+-      u8 priv[0];
+-} __packed;
++      void *priv;
++};
+ #define WL1271_MAX_CHANNELS 64
+ struct wl1271_scan {
diff --git a/package/kernel/mac80211/patches/906-wlcore-wl12xx-wl18xx-configure-num_links-per-hw.patch b/package/kernel/mac80211/patches/906-wlcore-wl12xx-wl18xx-configure-num_links-per-hw.patch
new file mode 100644 (file)
index 0000000..5c342f5
--- /dev/null
@@ -0,0 +1,345 @@
+Upcoming fw versions will have different max links support
+(according to the hw). Get ready for it by configuring
+wl->num_links per-hw, instead of using the const WL12XX_MAX_LINKS.
+
+However, continue using WLCORE_MAX_LINKS in order to simplify
+structs declarations (we use it in multiple bitmaps, and converting
+them to dynamic arrays is just cumbersome).
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wl12xx/main.c     |  3 +++
+ drivers/net/wireless/ti/wl12xx/wl12xx.h   |  2 ++
+ drivers/net/wireless/ti/wl18xx/main.c     |  3 +++
+ drivers/net/wireless/ti/wl18xx/wl18xx.h   |  4 +++-
+ drivers/net/wireless/ti/wlcore/cmd.c      |  4 ++--
+ drivers/net/wireless/ti/wlcore/event.c    |  4 ++--
+ drivers/net/wireless/ti/wlcore/main.c     | 12 ++++++++----
+ drivers/net/wireless/ti/wlcore/rx.c       |  8 ++++----
+ drivers/net/wireless/ti/wlcore/tx.c       | 20 ++++++++++----------
+ drivers/net/wireless/ti/wlcore/wlcore.h   |  8 +++++---
+ drivers/net/wireless/ti/wlcore/wlcore_i.h | 13 +++++++++----
+ 11 files changed, 51 insertions(+), 30 deletions(-)
+
+--- a/drivers/net/wireless/ti/wl12xx/main.c
++++ b/drivers/net/wireless/ti/wl12xx/main.c
+@@ -1749,9 +1749,12 @@ static int wl12xx_setup(struct wl1271 *w
+       struct wlcore_platdev_data *pdev_data = dev_get_platdata(&wl->pdev->dev);
+       struct wl12xx_platform_data *pdata = pdev_data->pdata;
++      BUILD_BUG_ON(WL12XX_MAX_LINKS > WLCORE_MAX_LINKS);
++
+       wl->rtable = wl12xx_rtable;
+       wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
+       wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
++      wl->num_links = WL12XX_MAX_LINKS;
+       wl->num_channels = 1;
+       wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
+       wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
+--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
++++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
+@@ -65,6 +65,8 @@
+ #define WL12XX_RX_BA_MAX_SESSIONS 3
++#define WL12XX_MAX_LINKS 12
++
+ struct wl127x_rx_mem_pool_addr {
+       u32 addr;
+       u32 addr_extra;
+--- a/drivers/net/wireless/ti/wl18xx/main.c
++++ b/drivers/net/wireless/ti/wl18xx/main.c
+@@ -1752,9 +1752,12 @@ static int wl18xx_setup(struct wl1271 *w
+       struct wl18xx_priv *priv = wl->priv;
+       int ret;
++      BUILD_BUG_ON(WL18XX_MAX_LINKS > WLCORE_MAX_LINKS);
++
+       wl->rtable = wl18xx_rtable;
+       wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
+       wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
++      wl->num_links = WL18XX_MAX_LINKS;
+       wl->num_channels = 2;
+       wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
+       wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
+--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
++++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
+@@ -42,6 +42,8 @@
+ #define WL18XX_RX_BA_MAX_SESSIONS 5
++#define WL18XX_MAX_LINKS 12
++
+ struct wl18xx_priv {
+       /* buffer for sending commands to FW */
+       u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
+@@ -114,7 +116,7 @@ struct wl18xx_fw_packet_counters {
+       u8 tx_released_pkts[NUM_TX_QUEUES];
+       /* Cumulative counter of freed packets per HLID */
+-      u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
++      u8 tx_lnk_free_pkts[WL18XX_MAX_LINKS];
+       /* Cumulative counter of released Voice memory blocks */
+       u8 tx_voice_released_blks;
+--- a/drivers/net/wireless/ti/wlcore/cmd.c
++++ b/drivers/net/wireless/ti/wlcore/cmd.c
+@@ -312,8 +312,8 @@ static int wlcore_get_new_session_id(str
+ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
+ {
+       unsigned long flags;
+-      u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
+-      if (link >= WL12XX_MAX_LINKS)
++      u8 link = find_first_zero_bit(wl->links_map, wl->num_links);
++      if (link >= wl->num_links)
+               return -EBUSY;
+       wl->session_ids[link] = wlcore_get_new_session_id(wl, link);
+--- a/drivers/net/wireless/ti/wlcore/event.c
++++ b/drivers/net/wireless/ti/wlcore/event.c
+@@ -68,7 +68,7 @@ static void wl1271_stop_ba_event(struct
+               u8 hlid;
+               struct wl1271_link *lnk;
+               for_each_set_bit(hlid, wlvif->ap.sta_hlid_map,
+-                               WL12XX_MAX_LINKS) {
++                               wl->num_links) {
+                       lnk = &wl->links[hlid];
+                       if (!lnk->ba_bitmap)
+                               continue;
+@@ -173,7 +173,7 @@ static void wlcore_disconnect_sta(struct
+       const u8 *addr;
+       int h;
+-      for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
++      for_each_set_bit(h, &sta_bitmap, wl->num_links) {
+               bool found = false;
+               /* find the ap vif connected to this sta */
+               wl12xx_for_each_wlvif_ap(wl, wlvif) {
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -372,7 +372,7 @@ static void wl12xx_irq_update_links_stat
+               wl->ap_fw_ps_map = cur_fw_ps_map;
+       }
+-      for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS)
++      for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, wl->num_links)
+               wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
+                                           wl->links[hlid].allocated_pkts);
+ }
+@@ -412,7 +412,7 @@ static int wlcore_fw_status(struct wl127
+       }
+-      for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
++      for_each_set_bit(i, wl->links_map, wl->num_links) {
+               u8 diff;
+               lnk = &wl->links[i];
+@@ -5888,7 +5888,7 @@ struct ieee80211_hw *wlcore_alloc_hw(siz
+       int i, j, ret;
+       unsigned int order;
+-      BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
++      BUILD_BUG_ON(AP_MAX_STATIONS > WLCORE_MAX_LINKS);
+       hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
+       if (!hw) {
+@@ -5911,8 +5911,12 @@ struct ieee80211_hw *wlcore_alloc_hw(siz
+       wl->hw = hw;
++      /*
++       * wl->num_links is not configured yet, so just use WLCORE_MAX_LINKS.
++       * we don't allocate any additional resource here, so that's fine.
++       */
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+-              for (j = 0; j < WL12XX_MAX_LINKS; j++)
++              for (j = 0; j < WLCORE_MAX_LINKS; j++)
+                       skb_queue_head_init(&wl->links[j].tx_queue[i]);
+       skb_queue_head_init(&wl->deferred_rx_queue);
+--- a/drivers/net/wireless/ti/wlcore/rx.c
++++ b/drivers/net/wireless/ti/wlcore/rx.c
+@@ -205,7 +205,7 @@ static int wl1271_rx_handle_data(struct
+ int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status)
+ {
+-      unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
++      unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0};
+       u32 buf_size;
+       u32 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc;
+       u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc;
+@@ -263,12 +263,12 @@ int wlcore_rx(struct wl1271 *wl, struct
+                                                 wl->aggr_buf + pkt_offset,
+                                                 pkt_len, rx_align,
+                                                 &hlid) == 1) {
+-                              if (hlid < WL12XX_MAX_LINKS)
++                              if (hlid < wl->num_links)
+                                       __set_bit(hlid, active_hlids);
+                               else
+                                       WARN(1,
+-                                           "hlid exceeded WL12XX_MAX_LINKS "
+-                                           "(%d)\n", hlid);
++                                           "hlid (%d) exceeded MAX_LINKS\n",
++                                           hlid);
+                       }
+                       wl->rx_counter++;
+--- a/drivers/net/wireless/ti/wlcore/tx.c
++++ b/drivers/net/wireless/ti/wlcore/tx.c
+@@ -565,11 +565,11 @@ static struct sk_buff *wlcore_vif_dequeu
+       int i, h, start_hlid;
+       /* start from the link after the last one */
+-      start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS;
++      start_hlid = (wlvif->last_tx_hlid + 1) % wl->num_links;
+       /* dequeue according to AC, round robin on each link */
+-      for (i = 0; i < WL12XX_MAX_LINKS; i++) {
+-              h = (start_hlid + i) % WL12XX_MAX_LINKS;
++      for (i = 0; i < wl->num_links; i++) {
++              h = (start_hlid + i) % wl->num_links;
+               /* only consider connected stations */
+               if (!test_bit(h, wlvif->links_map))
+@@ -693,8 +693,8 @@ static void wl1271_skb_queue_head(struct
+               skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
+               /* make sure we dequeue the same packet next time */
+-              wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) %
+-                                    WL12XX_MAX_LINKS;
++              wlvif->last_tx_hlid = (hlid + wl->num_links - 1) %
++                                    wl->num_links;
+       }
+       spin_lock_irqsave(&wl->wl_lock, flags);
+@@ -727,7 +727,7 @@ void wl12xx_rearm_rx_streaming(struct wl
+       timeout = wl->conf.rx_streaming.duration;
+       wl12xx_for_each_wlvif_sta(wl, wlvif) {
+               bool found = false;
+-              for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) {
++              for_each_set_bit(hlid, active_hlids, wl->num_links) {
+                       if (test_bit(hlid, wlvif->links_map)) {
+                               found  = true;
+                               break;
+@@ -764,7 +764,7 @@ int wlcore_tx_work_locked(struct wl1271
+       struct wl1271_tx_hw_descr *desc;
+       u32 buf_offset = 0, last_len = 0;
+       bool sent_packets = false;
+-      unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
++      unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0};
+       int ret = 0;
+       int bus_ret = 0;
+       u8 hlid;
+@@ -1066,7 +1066,7 @@ void wl12xx_tx_reset_wlvif(struct wl1271
+       int i;
+       /* TX failure */
+-      for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
++      for_each_set_bit(i, wlvif->links_map, wl->num_links) {
+               if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
+                   i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {
+                       /* this calls wl12xx_free_link */
+@@ -1090,7 +1090,7 @@ void wl12xx_tx_reset(struct wl1271 *wl)
+       /* only reset the queues if something bad happened */
+       if (wl1271_tx_total_queue_count(wl) != 0) {
+-              for (i = 0; i < WL12XX_MAX_LINKS; i++)
++              for (i = 0; i < wl->num_links; i++)
+                       wl1271_tx_reset_link_queues(wl, i);
+               for (i = 0; i < NUM_TX_QUEUES; i++)
+@@ -1183,7 +1183,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
+                      WL1271_TX_FLUSH_TIMEOUT / 1000);
+       /* forcibly flush all Tx buffers on our queues */
+-      for (i = 0; i < WL12XX_MAX_LINKS; i++)
++      for (i = 0; i < wl->num_links; i++)
+               wl1271_tx_reset_link_queues(wl, i);
+ out_wake:
+--- a/drivers/net/wireless/ti/wlcore/wlcore.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore.h
+@@ -224,7 +224,7 @@ struct wl1271 {
+       int channel;
+       u8 system_hlid;
+-      unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
++      unsigned long links_map[BITS_TO_LONGS(WLCORE_MAX_LINKS)];
+       unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
+       unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
+       unsigned long rate_policies_map[
+@@ -232,7 +232,7 @@ struct wl1271 {
+       unsigned long klv_templates_map[
+                       BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)];
+-      u8 session_ids[WL12XX_MAX_LINKS];
++      u8 session_ids[WLCORE_MAX_LINKS];
+       struct list_head wlvif_list;
+@@ -380,7 +380,7 @@ struct wl1271 {
+        * AP-mode - links indexed by HLID. The global and broadcast links
+        * are always active.
+        */
+-      struct wl1271_link links[WL12XX_MAX_LINKS];
++      struct wl1271_link links[WLCORE_MAX_LINKS];
+       /* number of currently active links */
+       int active_link_count;
+@@ -438,6 +438,8 @@ struct wl1271 {
+       u32 num_tx_desc;
+       /* number of RX descriptors the HW supports. */
+       u32 num_rx_desc;
++      /* number of links the HW supports */
++      u8 num_links;
+       /* translate HW Tx rates to standard rate-indices */
+       const u8 **band_rate_to_idx;
+--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
+@@ -58,10 +58,15 @@
+ #define WL1271_DEFAULT_DTIM_PERIOD 1
+ #define WL12XX_MAX_ROLES           4
+-#define WL12XX_MAX_LINKS           12
+ #define WL12XX_INVALID_ROLE_ID     0xff
+ #define WL12XX_INVALID_LINK_ID     0xff
++/*
++ * max number of links allowed by all HWs.
++ * this is NOT the actual max links supported by the current hw.
++ */
++#define WLCORE_MAX_LINKS 12
++
+ /* the driver supports the 2.4Ghz and 5Ghz bands */
+ #define WLCORE_NUM_BANDS           2
+@@ -156,7 +161,7 @@ struct wl_fw_status {
+               /*
+                * Cumulative counter of freed packets per HLID
+-               * (length of the array is WL12XX_MAX_LINKS)
++               * (length of the array is wl->num_links)
+                */
+               u8 *tx_lnk_free_pkts;
+@@ -357,7 +362,7 @@ struct wl12xx_vif {
+                       /* HLIDs bitmap of associated stations */
+                       unsigned long sta_hlid_map[BITS_TO_LONGS(
+-                                                      WL12XX_MAX_LINKS)];
++                                                      WLCORE_MAX_LINKS)];
+                       /* recoreded keys - set here before AP startup */
+                       struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
+@@ -374,7 +379,7 @@ struct wl12xx_vif {
+       /* counters of packets per AC, across all links in the vif */
+       int tx_queue_count[NUM_TX_QUEUES];
+-      unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
++      unsigned long links_map[BITS_TO_LONGS(WLCORE_MAX_LINKS)];
+       u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+       u8 ssid_len;
diff --git a/package/kernel/mac80211/patches/907-wlcore-wl12xx-wl18xx-configure-max_stations-per-hw.patch b/package/kernel/mac80211/patches/907-wlcore-wl12xx-wl18xx-configure-max_stations-per-hw.patch
new file mode 100644 (file)
index 0000000..66fd7dd
--- /dev/null
@@ -0,0 +1,110 @@
+Each hw supports a different max stations (connected to the
+same ap). add a new wl->max_ap_stations and use it instead
+of the current common AP_MAX_STATIONS.
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wl12xx/main.c     | 2 ++
+ drivers/net/wireless/ti/wl12xx/wl12xx.h   | 1 +
+ drivers/net/wireless/ti/wl18xx/main.c     | 2 ++
+ drivers/net/wireless/ti/wl18xx/wl18xx.h   | 1 +
+ drivers/net/wireless/ti/wlcore/main.c     | 4 +---
+ drivers/net/wireless/ti/wlcore/wlcore.h   | 2 ++
+ drivers/net/wireless/ti/wlcore/wlcore_i.h | 2 --
+ 7 files changed, 9 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/wireless/ti/wl12xx/main.c
++++ b/drivers/net/wireless/ti/wl12xx/main.c
+@@ -1750,11 +1750,13 @@ static int wl12xx_setup(struct wl1271 *w
+       struct wl12xx_platform_data *pdata = pdev_data->pdata;
+       BUILD_BUG_ON(WL12XX_MAX_LINKS > WLCORE_MAX_LINKS);
++      BUILD_BUG_ON(WL12XX_MAX_AP_STATIONS > WL12XX_MAX_LINKS);
+       wl->rtable = wl12xx_rtable;
+       wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
+       wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
+       wl->num_links = WL12XX_MAX_LINKS;
++      wl->max_ap_stations = WL12XX_MAX_AP_STATIONS;
+       wl->num_channels = 1;
+       wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
+       wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
+--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
++++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
+@@ -65,6 +65,7 @@
+ #define WL12XX_RX_BA_MAX_SESSIONS 3
++#define WL12XX_MAX_AP_STATIONS 8
+ #define WL12XX_MAX_LINKS 12
+ struct wl127x_rx_mem_pool_addr {
+--- a/drivers/net/wireless/ti/wl18xx/main.c
++++ b/drivers/net/wireless/ti/wl18xx/main.c
+@@ -1753,11 +1753,13 @@ static int wl18xx_setup(struct wl1271 *w
+       int ret;
+       BUILD_BUG_ON(WL18XX_MAX_LINKS > WLCORE_MAX_LINKS);
++      BUILD_BUG_ON(WL18XX_MAX_AP_STATIONS > WL18XX_MAX_LINKS);
+       wl->rtable = wl18xx_rtable;
+       wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
+       wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
+       wl->num_links = WL18XX_MAX_LINKS;
++      wl->max_ap_stations = WL18XX_MAX_AP_STATIONS;
+       wl->num_channels = 2;
+       wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
+       wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
+--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
++++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
+@@ -42,6 +42,7 @@
+ #define WL18XX_RX_BA_MAX_SESSIONS 5
++#define WL18XX_MAX_AP_STATIONS 8
+ #define WL18XX_MAX_LINKS 12
+ struct wl18xx_priv {
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -4695,7 +4695,7 @@ static int wl1271_allocate_sta(struct wl
+       int ret;
+-      if (wl->active_sta_count >= AP_MAX_STATIONS) {
++      if (wl->active_sta_count >= wl->max_ap_stations) {
+               wl1271_warning("could not allocate HLID - too much stations");
+               return -EBUSY;
+       }
+@@ -5888,8 +5888,6 @@ struct ieee80211_hw *wlcore_alloc_hw(siz
+       int i, j, ret;
+       unsigned int order;
+-      BUILD_BUG_ON(AP_MAX_STATIONS > WLCORE_MAX_LINKS);
+-
+       hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
+       if (!hw) {
+               wl1271_error("could not alloc ieee80211_hw");
+--- a/drivers/net/wireless/ti/wlcore/wlcore.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore.h
+@@ -440,6 +440,8 @@ struct wl1271 {
+       u32 num_rx_desc;
+       /* number of links the HW supports */
+       u8 num_links;
++      /* max stations a single AP can support */
++      u8 max_ap_stations;
+       /* translate HW Tx rates to standard rate-indices */
+       const u8 **band_rate_to_idx;
+--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
+@@ -123,8 +123,6 @@ struct wl1271_chip {
+ #define NUM_TX_QUEUES              4
+-#define AP_MAX_STATIONS            8
+-
+ struct wl_fw_status {
+       u32 intr;
+       u8  fw_rx_counter;
diff --git a/package/kernel/mac80211/patches/908-wlcore-wl12xx-wl18xx-configure-iface_combinations-per-hw.patch b/package/kernel/mac80211/patches/908-wlcore-wl12xx-wl18xx-configure-iface_combinations-per-hw.patch
new file mode 100644 (file)
index 0000000..eb00a50
--- /dev/null
@@ -0,0 +1,176 @@
+Each hw supports a different iface combinations.
+Define the supported combinations in each driver,
+and save it in wl->iface_combinations.
+
+Since each driver defines its own combinations now,
+it can also define its max supported channels, so
+we no longer need to save and set it explicitly
+in wlcore.
+
+Update wl18xx interface combinations to allow
+multiple APs.
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wl12xx/main.c   | 26 +++++++++++++++++++++-
+ drivers/net/wireless/ti/wl18xx/main.c   | 39 ++++++++++++++++++++++++++++++++-
+ drivers/net/wireless/ti/wlcore/main.c   | 28 ++---------------------
+ drivers/net/wireless/ti/wlcore/wlcore.h |  5 +++--
+ 4 files changed, 68 insertions(+), 30 deletions(-)
+
+--- a/drivers/net/wireless/ti/wl12xx/main.c
++++ b/drivers/net/wireless/ti/wl12xx/main.c
+@@ -1743,6 +1743,29 @@ static struct ieee80211_sta_ht_cap wl12x
+               },
+ };
++static const struct ieee80211_iface_limit wl12xx_iface_limits[] = {
++      {
++              .max = 3,
++              .types = BIT(NL80211_IFTYPE_STATION),
++      },
++      {
++              .max = 1,
++              .types = BIT(NL80211_IFTYPE_AP) |
++                       BIT(NL80211_IFTYPE_P2P_GO) |
++                       BIT(NL80211_IFTYPE_P2P_CLIENT),
++      },
++};
++
++static const struct ieee80211_iface_combination
++wl12xx_iface_combinations[] = {
++      {
++              .max_interfaces = 3,
++              .limits = wl12xx_iface_limits,
++              .n_limits = ARRAY_SIZE(wl12xx_iface_limits),
++              .num_different_channels = 1,
++      },
++};
++
+ static int wl12xx_setup(struct wl1271 *wl)
+ {
+       struct wl12xx_priv *priv = wl->priv;
+@@ -1757,7 +1780,8 @@ static int wl12xx_setup(struct wl1271 *w
+       wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
+       wl->num_links = WL12XX_MAX_LINKS;
+       wl->max_ap_stations = WL12XX_MAX_AP_STATIONS;
+-      wl->num_channels = 1;
++      wl->iface_combinations = wl12xx_iface_combinations;
++      wl->n_iface_combinations = ARRAY_SIZE(wl12xx_iface_combinations);
+       wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
+       wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
+       wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
+--- a/drivers/net/wireless/ti/wl18xx/main.c
++++ b/drivers/net/wireless/ti/wl18xx/main.c
+@@ -1747,6 +1747,42 @@ static struct ieee80211_sta_ht_cap wl18x
+               },
+ };
++static const struct ieee80211_iface_limit wl18xx_iface_limits[] = {
++      {
++              .max = 3,
++              .types = BIT(NL80211_IFTYPE_STATION),
++      },
++      {
++              .max = 1,
++              .types = BIT(NL80211_IFTYPE_AP) |
++                       BIT(NL80211_IFTYPE_P2P_GO) |
++                       BIT(NL80211_IFTYPE_P2P_CLIENT),
++      },
++};
++
++static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
++      {
++              .max = 2,
++              .types = BIT(NL80211_IFTYPE_AP),
++      },
++};
++
++static const struct ieee80211_iface_combination
++wl18xx_iface_combinations[] = {
++      {
++              .max_interfaces = 3,
++              .limits = wl18xx_iface_limits,
++              .n_limits = ARRAY_SIZE(wl18xx_iface_limits),
++              .num_different_channels = 2,
++      },
++      {
++              .max_interfaces = 2,
++              .limits = wl18xx_iface_ap_limits,
++              .n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits),
++              .num_different_channels = 1,
++      }
++};
++
+ static int wl18xx_setup(struct wl1271 *wl)
+ {
+       struct wl18xx_priv *priv = wl->priv;
+@@ -1760,7 +1796,8 @@ static int wl18xx_setup(struct wl1271 *w
+       wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
+       wl->num_links = WL18XX_MAX_LINKS;
+       wl->max_ap_stations = WL18XX_MAX_AP_STATIONS;
+-      wl->num_channels = 2;
++      wl->iface_combinations = wl18xx_iface_combinations;
++      wl->n_iface_combinations = ARRAY_SIZE(wl18xx_iface_combinations);
+       wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
+       wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
+       wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -5723,28 +5723,6 @@ static void wl1271_unregister_hw(struct
+ }
+-static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
+-      {
+-              .max = 3,
+-              .types = BIT(NL80211_IFTYPE_STATION),
+-      },
+-      {
+-              .max = 1,
+-              .types = BIT(NL80211_IFTYPE_AP) |
+-                       BIT(NL80211_IFTYPE_P2P_GO) |
+-                       BIT(NL80211_IFTYPE_P2P_CLIENT),
+-      },
+-};
+-
+-static struct ieee80211_iface_combination
+-wlcore_iface_combinations[] = {
+-      {
+-        .max_interfaces = 3,
+-        .limits = wlcore_iface_limits,
+-        .n_limits = ARRAY_SIZE(wlcore_iface_limits),
+-      },
+-};
+-
+ static int wl1271_init_ieee80211(struct wl1271 *wl)
+ {
+       int i;
+@@ -5865,10 +5843,8 @@ static int wl1271_init_ieee80211(struct
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
+       /* allowed interface combinations */
+-      wlcore_iface_combinations[0].num_different_channels = wl->num_channels;
+-      wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
+-      wl->hw->wiphy->n_iface_combinations =
+-              ARRAY_SIZE(wlcore_iface_combinations);
++      wl->hw->wiphy->iface_combinations = wl->iface_combinations;
++      wl->hw->wiphy->n_iface_combinations = wl->n_iface_combinations;
+       SET_IEEE80211_DEV(wl->hw, wl->dev);
+--- a/drivers/net/wireless/ti/wlcore/wlcore.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore.h
+@@ -485,8 +485,9 @@ struct wl1271 {
+       struct completion nvs_loading_complete;
+-      /* number of concurrent channels the HW supports */
+-      u32 num_channels;
++      /* interface combinations supported by the hw */
++      const struct ieee80211_iface_combination *iface_combinations;
++      u8 n_iface_combinations;
+ };
+ int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
diff --git a/package/kernel/mac80211/patches/909-wl18xx-move-to-new-firmware-wl18xx-fw-3.bin.patch b/package/kernel/mac80211/patches/909-wl18xx-move-to-new-firmware-wl18xx-fw-3.bin.patch
new file mode 100644 (file)
index 0000000..85214c1
--- /dev/null
@@ -0,0 +1,200 @@
+Bump the min wl18xx fw version to 8.8.0.0.13
+
+This fw is not backward compatible with older
+firmware (due to api changes), so use bump
+the firmware name as well.
+
+Some modifications were done to the driver-fw api
+in order to support multiple APs.
+
+Additionally, some of the consts (such as max stations,
+max links and max RX BA sessions) were changed.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wl18xx/main.c     |  2 +-
+ drivers/net/wireless/ti/wl18xx/wl18xx.h   | 10 +++++-----
+ drivers/net/wireless/ti/wlcore/acx.c      |  4 +++-
+ drivers/net/wireless/ti/wlcore/acx.h      |  6 ++++--
+ drivers/net/wireless/ti/wlcore/cmd.c      |  5 ++++-
+ drivers/net/wireless/ti/wlcore/cmd.h      |  7 +++++--
+ drivers/net/wireless/ti/wlcore/main.c     |  2 +-
+ drivers/net/wireless/ti/wlcore/tx.c       |  2 +-
+ drivers/net/wireless/ti/wlcore/wlcore_i.h |  2 +-
+ 9 files changed, 25 insertions(+), 15 deletions(-)
+
+--- a/drivers/net/wireless/ti/wl18xx/main.c
++++ b/drivers/net/wireless/ti/wl18xx/main.c
+@@ -648,7 +648,7 @@ static const struct wl18xx_clk_cfg wl18x
+ };
+ /* TODO: maybe move to a new header file? */
+-#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-2.bin"
++#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-3.bin"
+ static int wl18xx_identify_chip(struct wl1271 *wl)
+ {
+--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
++++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
+@@ -26,10 +26,10 @@
+ /* minimum FW required for driver */
+ #define WL18XX_CHIP_VER               8
+-#define WL18XX_IFTYPE_VER     5
++#define WL18XX_IFTYPE_VER     8
+ #define WL18XX_MAJOR_VER      WLCORE_FW_VER_IGNORE
+ #define WL18XX_SUBTYPE_VER    WLCORE_FW_VER_IGNORE
+-#define WL18XX_MINOR_VER      39
++#define WL18XX_MINOR_VER      13
+ #define WL18XX_CMD_MAX_SIZE          740
+@@ -40,10 +40,10 @@
+ #define WL18XX_NUM_MAC_ADDRESSES 3
+-#define WL18XX_RX_BA_MAX_SESSIONS 5
++#define WL18XX_RX_BA_MAX_SESSIONS 13
+-#define WL18XX_MAX_AP_STATIONS 8
+-#define WL18XX_MAX_LINKS 12
++#define WL18XX_MAX_AP_STATIONS 10
++#define WL18XX_MAX_LINKS 16
+ struct wl18xx_priv {
+       /* buffer for sending commands to FW */
+--- a/drivers/net/wireless/ti/wlcore/acx.c
++++ b/drivers/net/wireless/ti/wlcore/acx.c
+@@ -1591,7 +1591,8 @@ out:
+       return ret;
+ }
+-int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)
++int wl1271_acx_set_inconnection_sta(struct wl1271 *wl,
++                                  struct wl12xx_vif *wlvif, u8 *addr)
+ {
+       struct wl1271_acx_inconnection_sta *acx = NULL;
+       int ret;
+@@ -1603,6 +1604,7 @@ int wl1271_acx_set_inconnection_sta(stru
+               return -ENOMEM;
+       memcpy(acx->addr, addr, ETH_ALEN);
++      acx->role_id = wlvif->role_id;
+       ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST,
+                                  acx, sizeof(*acx));
+--- a/drivers/net/wireless/ti/wlcore/acx.h
++++ b/drivers/net/wireless/ti/wlcore/acx.h
+@@ -824,7 +824,8 @@ struct wl1271_acx_inconnection_sta {
+       struct acx_header header;
+       u8 addr[ETH_ALEN];
+-      u8 padding1[2];
++      u8 role_id;
++      u8 padding;
+ } __packed;
+ /*
+@@ -1118,7 +1119,8 @@ int wl1271_acx_ps_rx_streaming(struct wl
+                              bool enable);
+ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+ int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+-int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
++int wl1271_acx_set_inconnection_sta(struct wl1271 *wl,
++                                  struct wl12xx_vif *wlvif, u8 *addr);
+ int wl1271_acx_fm_coex(struct wl1271 *wl);
+ int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
+ int wl12xx_acx_config_hangover(struct wl1271 *wl);
+--- a/drivers/net/wireless/ti/wlcore/cmd.c
++++ b/drivers/net/wireless/ti/wlcore/cmd.c
+@@ -1532,6 +1532,7 @@ int wl12xx_cmd_add_peer(struct wl1271 *w
+       cmd->sp_len = sta->max_sp;
+       cmd->wmm = sta->wme ? 1 : 0;
+       cmd->session_id = wl->session_ids[hlid];
++      cmd->role_id = wlvif->role_id;
+       for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
+               if (sta->wme && (sta->uapsd_queues & BIT(i)))
+@@ -1568,7 +1569,8 @@ out:
+       return ret;
+ }
+-int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
++int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
++                         u8 hlid)
+ {
+       struct wl12xx_cmd_remove_peer *cmd;
+       int ret;
+@@ -1586,6 +1588,7 @@ int wl12xx_cmd_remove_peer(struct wl1271
+       /* We never send a deauth, mac80211 is in charge of this */
+       cmd->reason_opcode = 0;
+       cmd->send_deauth_flag = 0;
++      cmd->role_id = wlvif->role_id;
+       ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);
+       if (ret < 0) {
+--- a/drivers/net/wireless/ti/wlcore/cmd.h
++++ b/drivers/net/wireless/ti/wlcore/cmd.h
+@@ -88,7 +88,8 @@ int wl12xx_roc(struct wl1271 *wl, struct
+ int wl12xx_croc(struct wl1271 *wl, u8 role_id);
+ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                       struct ieee80211_sta *sta, u8 hlid);
+-int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
++int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
++                         u8 hlid);
+ void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
+                                    enum ieee80211_band band);
+ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl);
+@@ -594,6 +595,8 @@ struct wl12xx_cmd_add_peer {
+       u8 sp_len;
+       u8 wmm;
+       u8 session_id;
++      u8 role_id;
++      u8 padding[3];
+ } __packed;
+ struct wl12xx_cmd_remove_peer {
+@@ -602,7 +605,7 @@ struct wl12xx_cmd_remove_peer {
+       u8 hlid;
+       u8 reason_opcode;
+       u8 send_deauth_flag;
+-      u8 padding1;
++      u8 role_id;
+ } __packed;
+ /*
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -4798,7 +4798,7 @@ static int wl12xx_sta_remove(struct wl12
+       if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
+               return -EINVAL;
+-      ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
++      ret = wl12xx_cmd_remove_peer(wl, wlvif, wl_sta->hlid);
+       if (ret < 0)
+               return ret;
+--- a/drivers/net/wireless/ti/wlcore/tx.c
++++ b/drivers/net/wireless/ti/wlcore/tx.c
+@@ -101,7 +101,7 @@ static void wl1271_tx_ap_update_inconnec
+        * authentication response. this way it won't get de-authed by FW
+        * when transmitting too soon.
+        */
+-      wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
++      wl1271_acx_set_inconnection_sta(wl, wlvif, hdr->addr1);
+       /*
+        * ROC for 1 second on the AP channel for completing the connection.
+--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
+@@ -65,7 +65,7 @@
+  * max number of links allowed by all HWs.
+  * this is NOT the actual max links supported by the current hw.
+  */
+-#define WLCORE_MAX_LINKS 12
++#define WLCORE_MAX_LINKS 16
+ /* the driver supports the 2.4Ghz and 5Ghz bands */
+ #define WLCORE_NUM_BANDS           2
diff --git a/package/kernel/mac80211/patches/910-wlcore-send-EAPOL-frames-with-voice-priority.patch b/package/kernel/mac80211/patches/910-wlcore-send-EAPOL-frames-with-voice-priority.patch
new file mode 100644 (file)
index 0000000..6f6b22a
--- /dev/null
@@ -0,0 +1,37 @@
+Send EAPOL frames with voice priority by setting (the new)
+TX_HW_ATTR_EAPOL_FRAME bit in tx attribute.
+
+Sending EAPOL with voice priority fixes re-key
+timeout issues during heavy traffic.
+
+Signed-off-by: Igal Chernobelsky <igalc@ti.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/tx.c | 4 ++++
+ drivers/net/wireless/ti/wlcore/tx.h | 1 +
+ 2 files changed, 5 insertions(+)
+
+--- a/drivers/net/wireless/ti/wlcore/tx.c
++++ b/drivers/net/wireless/ti/wlcore/tx.c
+@@ -362,6 +362,10 @@ static void wl1271_tx_fill_hdr(struct wl
+           ieee80211_has_protected(frame_control))
+               tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
++      /* send EAPOL frames as voice */
++      if (control->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)
++              tx_attr |= TX_HW_ATTR_EAPOL_FRAME;
++
+       desc->tx_attr = cpu_to_le16(tx_attr);
+       wlcore_hw_set_tx_desc_csum(wl, desc, skb);
+--- a/drivers/net/wireless/ti/wlcore/tx.h
++++ b/drivers/net/wireless/ti/wlcore/tx.h
+@@ -37,6 +37,7 @@
+ #define TX_HW_ATTR_TX_CMPLT_REQ          BIT(12)
+ #define TX_HW_ATTR_TX_DUMMY_REQ          BIT(13)
+ #define TX_HW_ATTR_HOST_ENCRYPT          BIT(14)
++#define TX_HW_ATTR_EAPOL_FRAME           BIT(15)
+ #define TX_HW_ATTR_OFST_SAVE_RETRIES     0
+ #define TX_HW_ATTR_OFST_HEADER_PAD       1
diff --git a/package/kernel/mac80211/patches/911-wlcore-don-t-stop-sched_scan-on-interface-removal.patch b/package/kernel/mac80211/patches/911-wlcore-don-t-stop-sched_scan-on-interface-removal.patch
new file mode 100644 (file)
index 0000000..91269d2
--- /dev/null
@@ -0,0 +1,25 @@
+Stopping sched scan on interface removal (during recovery)
+is no longer needed, as sched scanning is automatically
+restarted by mac80211.
+
+Signed-off-by: Barak Bercovitz <barak@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/main.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -2582,10 +2582,8 @@ static void __wl1271_op_remove_interface
+               ieee80211_scan_completed(wl->hw, true);
+       }
+-      if (wl->sched_vif == wlvif) {
+-              ieee80211_sched_scan_stopped(wl->hw);
++      if (wl->sched_vif == wlvif)
+               wl->sched_vif = NULL;
+-      }
+       if (wl->roc_vif == vif) {
+               wl->roc_vif = NULL;
diff --git a/package/kernel/mac80211/patches/912-wlcore-wl18xx-allow-CCK-rates-for-AP-mode.patch b/package/kernel/mac80211/patches/912-wlcore-wl18xx-allow-CCK-rates-for-AP-mode.patch
new file mode 100644 (file)
index 0000000..c957b9c
--- /dev/null
@@ -0,0 +1,47 @@
+12xx chips allow only OFDM rates in AP mode for BT-Coex purposes. This
+is no longer required in 18xx chips, starting with FW 8.6.0.0.8.
+
+Update the min allowed FW version in 18xx to support this functionality.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wl12xx/main.c   | 1 +
+ drivers/net/wireless/ti/wlcore/init.c   | 2 +-
+ drivers/net/wireless/ti/wlcore/wlcore.h | 3 +++
+ 3 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ti/wl12xx/main.c
++++ b/drivers/net/wireless/ti/wl12xx/main.c
+@@ -1789,6 +1789,7 @@ static int wl12xx_setup(struct wl1271 *w
+       wl->fw_status_len = sizeof(struct wl12xx_fw_status);
+       wl->fw_status_priv_len = 0;
+       wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
++      wl->ofdm_only_ap = true;
+       wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap);
+       wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap);
+       wl12xx_conf_init(wl);
+--- a/drivers/net/wireless/ti/wlcore/init.c
++++ b/drivers/net/wireless/ti/wlcore/init.c
+@@ -462,7 +462,7 @@ int wl1271_init_ap_rates(struct wl1271 *
+        * If the basic rates contain OFDM rates, use OFDM only
+        * rates for unicast TX as well. Else use all supported rates.
+        */
+-      if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
++      if (wl->ofdm_only_ap && (wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
+               supported_rates = CONF_TX_OFDM_RATES;
+       else
+               supported_rates = CONF_TX_ENABLED_RATES;
+--- a/drivers/net/wireless/ti/wlcore/wlcore.h
++++ b/drivers/net/wireless/ti/wlcore/wlcore.h
+@@ -409,6 +409,9 @@ struct wl1271 {
+       /* AP-mode - number of currently connected stations */
+       int active_sta_count;
++      /* Flag determining whether AP should broadcast OFDM-only rates */
++      bool ofdm_only_ap;
++
+       /* last wlvif we transmitted from */
+       struct wl12xx_vif *last_wlvif;
diff --git a/package/kernel/mac80211/patches/913-wlcore-don-t-handle-unsetting-of-default-wep-key.patch b/package/kernel/mac80211/patches/913-wlcore-don-t-handle-unsetting-of-default-wep-key.patch
new file mode 100644 (file)
index 0000000..69621c5
--- /dev/null
@@ -0,0 +1,28 @@
+mac80211 unsets the default wep key on disassoc.
+The fw doesn't support this notification, so simply
+ignore it.
+
+The actual flow actually triggers fw recovery in some
+cases, as mac80211 unsets the default key only after
+disassoc, when wlvif->sta.hlid, resulting in invalid
+hlid being passed to the fw.
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/main.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -3505,6 +3505,10 @@ static void wl1271_op_set_default_key_id
+       wl1271_debug(DEBUG_MAC80211, "mac80211 set default key idx %d",
+                    key_idx);
++      /* we don't handle unsetting of default key */
++      if (key_idx == -1)
++              return;
++
+       mutex_lock(&wl->mutex);
+       if (unlikely(wl->state != WLCORE_STATE_ON)) {
diff --git a/package/kernel/mac80211/patches/914-wlcore-consider-multiple-APs-when-checking-active_link_count.patch b/package/kernel/mac80211/patches/914-wlcore-consider-multiple-APs-when-checking-active_link_count.patch
new file mode 100644 (file)
index 0000000..9e9eba7
--- /dev/null
@@ -0,0 +1,51 @@
+Each AP has its own global and broadcast links, so when
+checking for active sta count (according to the active_link_count)
+we must take them all into account.
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/main.c | 10 +++++-----
+ drivers/net/wireless/ti/wlcore/tx.c   | 10 +++++-----
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -345,12 +345,12 @@ static void wl12xx_irq_ps_regulate_link(
+        * Start high-level PS if the STA is asleep with enough blocks in FW.
+        * Make an exception if this is the only connected link. In this
+        * case FW-memory congestion is less of a problem.
+-       * Note that a single connected STA means 3 active links, since we must
+-       * account for the global and broadcast AP links. The "fw_ps" check
+-       * assures us the third link is a STA connected to the AP. Otherwise
+-       * the FW would not set the PSM bit.
++       * Note that a single connected STA means 2*ap_count + 1 active links,
++       * since we must account for the global and broadcast AP links
++       * for each AP. The "fw_ps" check assures us the other link is a STA
++       * connected to the AP. Otherwise the FW would not set the PSM bit.
+        */
+-      else if (wl->active_link_count > 3 && fw_ps &&
++      else if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&
+                tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+               wl12xx_ps_link_start(wl, wlvif, hlid, true);
+ }
+--- a/drivers/net/wireless/ti/wlcore/tx.c
++++ b/drivers/net/wireless/ti/wlcore/tx.c
+@@ -134,12 +134,12 @@ static void wl1271_tx_regulate_link(stru
+        * into high-level PS and clean out its TX queues.
+        * Make an exception if this is the only connected link. In this
+        * case FW-memory congestion is less of a problem.
+-       * Note that a single connected STA means 3 active links, since we must
+-       * account for the global and broadcast AP links. The "fw_ps" check
+-       * assures us the third link is a STA connected to the AP. Otherwise
+-       * the FW would not set the PSM bit.
++       * Note that a single connected STA means 2*ap_count + 1 active links,
++       * since we must account for the global and broadcast AP links
++       * for each AP. The "fw_ps" check assures us the other link is a STA
++       * connected to the AP. Otherwise the FW would not set the PSM bit.
+        */
+-      if (wl->active_link_count > 3 && fw_ps &&
++      if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&
+           tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+               wl12xx_ps_link_start(wl, wlvif, hlid, true);
+ }
diff --git a/package/kernel/mac80211/patches/915-wlcore-decrease-warning-verbosity-during-recovery.patch b/package/kernel/mac80211/patches/915-wlcore-decrease-warning-verbosity-during-recovery.patch
new file mode 100644 (file)
index 0000000..be2de10
--- /dev/null
@@ -0,0 +1,42 @@
+Silently ignore repetitive scheduling of recovery work and commands
+being passed to the bus when the HW is not available. This can happen
+many times during recovery and slow it down. It also spams the kernel
+logs.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/cmd.c  | 4 ++--
+ drivers/net/wireless/ti/wlcore/main.c | 5 +++--
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/cmd.c
++++ b/drivers/net/wireless/ti/wlcore/cmd.c
+@@ -60,8 +60,8 @@ static int __wlcore_cmd_send(struct wl12
+       u16 status;
+       u16 poll_count = 0;
+-      if (WARN_ON(wl->state == WLCORE_STATE_RESTARTING &&
+-                  id != CMD_STOP_FWLOGGER))
++      if (unlikely(wl->state == WLCORE_STATE_RESTARTING &&
++                   id != CMD_STOP_FWLOGGER))
+               return -EIO;
+       cmd = buf;
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -782,10 +782,11 @@ out:
+ void wl12xx_queue_recovery_work(struct wl1271 *wl)
+ {
+-      WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
+-
+       /* Avoid a recursive recovery */
+       if (wl->state == WLCORE_STATE_ON) {
++              WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY,
++                                &wl->flags));
++
+               wl->state = WLCORE_STATE_RESTARTING;
+               set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
+               wl1271_ps_elp_wakeup(wl);
diff --git a/package/kernel/mac80211/patches/916-wlcore-increase-timeout-to-5000-msecs.patch b/package/kernel/mac80211/patches/916-wlcore-increase-timeout-to-5000-msecs.patch
new file mode 100644 (file)
index 0000000..eb490e4
--- /dev/null
@@ -0,0 +1,21 @@
+dfs configuration command might take longer than
+the current timeout. increase it to 5 seconds.
+
+Signed-off-by: Yaniv Machani <yanivma@ti.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/cmd.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ti/wlcore/cmd.h
++++ b/drivers/net/wireless/ti/wlcore/cmd.h
+@@ -207,7 +207,7 @@ enum cmd_templ {
+ #define WL1271_COMMAND_TIMEOUT     2000
+ #define WL1271_CMD_TEMPL_DFLT_SIZE 252
+ #define WL1271_CMD_TEMPL_MAX_SIZE  512
+-#define WL1271_EVENT_TIMEOUT       1500
++#define WL1271_EVENT_TIMEOUT       5000
+ struct wl1271_cmd_header {
+       __le16 id;
diff --git a/package/kernel/mac80211/patches/917-wlcore-enable-beacon-filtering-only-after-receiving-a-beacon.patch b/package/kernel/mac80211/patches/917-wlcore-enable-beacon-filtering-only-after-receiving-a-beacon.patch
new file mode 100644 (file)
index 0000000..5dbad94
--- /dev/null
@@ -0,0 +1,71 @@
+Enabling beacon filtering before receving a beacon
+might result in not having a beacon at all for the
+current connected AP, which prevents the station
+from entering power-save.
+
+Replace the current approach (of starting beacon
+filtering on init) and configure beacon filering
+only after bss_conf->dtimper is set (which means
+mac80211 already parsed a beacon).
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/acx.c  |  3 ++-
+ drivers/net/wireless/ti/wlcore/init.c |  4 ++--
+ drivers/net/wireless/ti/wlcore/main.c | 12 ++++++++++++
+ 3 files changed, 16 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/acx.c
++++ b/drivers/net/wireless/ti/wlcore/acx.c
+@@ -358,7 +358,8 @@ int wl1271_acx_beacon_filter_opt(struct
+       struct acx_beacon_filter_option *beacon_filter = NULL;
+       int ret = 0;
+-      wl1271_debug(DEBUG_ACX, "acx beacon filter opt");
++      wl1271_debug(DEBUG_ACX, "acx beacon filter opt enable=%d",
++                   enable_filter);
+       if (enable_filter &&
+           wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED)
+--- a/drivers/net/wireless/ti/wlcore/init.c
++++ b/drivers/net/wireless/ti/wlcore/init.c
+@@ -287,8 +287,8 @@ static int wl1271_init_sta_beacon_filter
+       if (ret < 0)
+               return ret;
+-      /* enable beacon filtering */
+-      ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
++      /* disable beacon filtering until we get the first beacon */
++      ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
+       if (ret < 0)
+               return ret;
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -2941,6 +2941,11 @@ static int wlcore_unset_assoc(struct wl1
+               ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
+               if (ret < 0)
+                       return ret;
++
++              /* disable beacon filtering */
++              ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
++              if (ret < 0)
++                      return ret;
+       }
+       if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
+@@ -4345,6 +4350,13 @@ static void wl1271_bss_info_changed_sta(
+               }
+       }
++      if ((changed & BSS_CHANGED_BEACON_INFO) && bss_conf->dtim_period) {
++              /* enable beacon filtering */
++              ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
++              if (ret < 0)
++                      goto out;
++      }
++
+       ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
+       if (ret < 0)
+               goto out;
diff --git a/package/kernel/mac80211/patches/918-wlcore-add-support-for-STA-CSA-with-chan-contexts.patch b/package/kernel/mac80211/patches/918-wlcore-add-support-for-STA-CSA-with-chan-contexts.patch
new file mode 100644 (file)
index 0000000..c33535d
--- /dev/null
@@ -0,0 +1,22 @@
+TI wl12xx/wl18xx cards support channel switch via a driver specific
+switch_channel op while operating with channel contexts.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+
+---
+drivers/net/wireless/ti/wlcore/main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -5770,7 +5770,8 @@ static int wl1271_init_ieee80211(struct
+               IEEE80211_HW_AP_LINK_PS |
+               IEEE80211_HW_AMPDU_AGGREGATION |
+               IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
+-              IEEE80211_HW_QUEUE_CONTROL;
++              IEEE80211_HW_QUEUE_CONTROL |
++              IEEE80211_HW_CHANCTX_STA_CSA;
+       wl->hw->wiphy->cipher_suites = cipher_suites;
+       wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
diff --git a/package/kernel/mac80211/patches/919-wl18xx-align-event-mailbox-with-current-fw.patch b/package/kernel/mac80211/patches/919-wl18xx-align-event-mailbox-with-current-fw.patch
new file mode 100644 (file)
index 0000000..95db58f
--- /dev/null
@@ -0,0 +1,52 @@
+From fde3f0a7f3112527a18e06e32efdd9a354c91b02 Mon Sep 17 00:00:00 2001
+From: Eliad Peller <eliad@wizery.com>
+Date: Tue, 18 Mar 2014 13:19:48 +0200
+Subject: [PATCH] wl18xx: align event mailbox with current fw
+
+Some fields are missing from the event mailbox
+struct definitions, which cause issues when
+trying to handle some events.
+
+Add the missing fields in order to align the
+struct size (without adding actual support
+for the new fields).
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+---
+ drivers/net/wireless/ti/wl18xx/event.h | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
+index 398f3d2..a76e98e 100644
+--- a/drivers/net/wireless/ti/wl18xx/event.h
++++ b/drivers/net/wireless/ti/wl18xx/event.h
+@@ -68,6 +68,26 @@ struct wl18xx_event_mailbox {
+       /* bitmap of inactive stations (by HLID) */
+       __le32 inactive_sta_bitmap;
++
++      /* rx BA win size indicated by RX_BA_WIN_SIZE_CHANGE_EVENT_ID */
++      u8 rx_ba_role_id;
++      u8 rx_ba_link_id;
++      u8 rx_ba_win_size;
++      u8 padding;
++
++      /* smart config */
++      u8 sc_ssid_len;
++      u8 sc_pwd_len;
++      u8 sc_token_len;
++      u8 padding1;
++      u8 sc_ssid[32];
++      u8 sc_pwd[32];
++      u8 sc_token[32];
++
++      /* smart config sync channel */
++      u8 sc_sync_channel;
++      u8 sc_sync_band;
++      u8 padding2[2];
+ } __packed;
+ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+-- 
+1.8.5.2.229.g4448466.dirty
+
diff --git a/package/kernel/mac80211/patches/920-wlcore-don-t-switch-channels-on-disconnected-STA-vif.patch b/package/kernel/mac80211/patches/920-wlcore-don-t-switch-channels-on-disconnected-STA-vif.patch
new file mode 100644 (file)
index 0000000..3c2c14a
--- /dev/null
@@ -0,0 +1,41 @@
+From 4101e8dc540d19f1f6c24930629149191786e4cd Mon Sep 17 00:00:00 2001
+From: Arik Nemtsov <arik@wizery.com>
+Date: Mon, 9 Sep 2013 16:48:59 +0300
+Subject: [PATCH 27/75] wlcore: don't switch channels on disconnected STA vifs
+
+Sending the FW a channel switch command on a disconnected vif may result
+in a beacon loss event. Avoid this edge case.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+---
+ drivers/net/wireless/ti/wlcore/main.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
+index 117e01e..a0c5a1e 100644
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -5224,6 +5224,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+       if (unlikely(wl->state == WLCORE_STATE_OFF)) {
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
++
++                      if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
++                              continue;
++
+                       ieee80211_chswitch_done(vif, false);
+               }
+               goto out;
+@@ -5239,6 +5243,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+       wl12xx_for_each_wlvif_sta(wl, wlvif) {
+               unsigned long delay_usec;
++              if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
++                      continue;
++
+               ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
+               if (ret)
+                       goto out_sleep;
+-- 
+1.8.3.2
+