Fix for memory leak in the wireless extensions layer

2018-10-31 Thread Larry Finger

Greg,

Is the fix for a memory leak in the wext compat layer queued for stable? It is 
in kernel:HEAD as commit 848e616e66d4592fe9afc40743d3504deb7632b4 ("cfg80211: 
fix wext-compat memory leak")


I just receiv3ed a complaint about a leak for a system that is running Ubuntu's 
kernel 4.19.


Unfortunately, this commit has a "fixes" line, but not a Cc for Stable.

Larry



Re: [PATCH v2] mt76x0: run calibration after scanning

2018-10-31 Thread Felix Fietkau
On 2018-10-31 14:11, Stanislaw Gruszka wrote:
> If we are associated and scanning is performed, sw_scan_complete callback
> is done after we get back to operating channel, so we do not perform
> queue cal work. Fix this queue cal work from sw_scan_complete().
> 
> We have to restore gain in MT_BBP(AGC, 8) register after scanning, as
> it was multiple times modified by channel switch code. So queue cal work
> without  any delay and reset dev->cal.low_gain to assure calibration
> code will AGC gain value.
> 
> Note patch was not tested on mt76x2, but should work and be needed
> fix as well.
> 
> Fixes: bbd10586f0df ("mt76x0: phy: do not run calibration during channel 
> switch")
> Signed-off-by: Stanislaw Gruszka 
> ---
> v1 -> v2:
> only queue cal work with 0 delay an reset dev->cal.low_gain 
> 
>  drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 6 ++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c 
> b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
> index 9f083008dbd4..747fd2c9ec45 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
> @@ -553,6 +553,12 @@ void mt76x02_sw_scan_complete(struct ieee80211_hw *hw,
>   clear_bit(MT76_SCANNING, >mt76.state);
>   if (mt76_is_mmio(dev))
>   tasklet_enable(>pre_tbtt_tasklet);
> +
> + if (vif->bss_conf.assoc) {
> + /* Restore AGC gain and resume calibration after scanning. */
> + dev->cal.low_gain = -1;
> + ieee80211_queue_delayed_work(hw, >cal_work, 0);
> + }
I think checking vif->bss_conf.assoc here is not enough, since we might
be using multiple interfaces (e.g. AP+STA)

- Felix


Re: [PATCH v2] mt76x0: run calibration after scanning

2018-10-31 Thread Stanislaw Gruszka
On Wed, Oct 31, 2018 at 02:11:26PM +0100, Stanislaw Gruszka wrote:
> If we are associated and scanning is performed, sw_scan_complete callback
> is done after we get back to operating channel, so we do not perform
> queue cal work. Fix this queue cal work from sw_scan_complete().
> 
> We have to restore gain in MT_BBP(AGC, 8) register after scanning, as
> it was multiple times modified by channel switch code. So queue cal work
> without  any delay and reset dev->cal.low_gain to assure calibration
> code will AGC gain value.
> 
> Note patch was not tested on mt76x2, but should work and be needed
> fix as well.
> 
> Fixes: bbd10586f0df ("mt76x0: phy: do not run calibration during channel 
> switch")
> Signed-off-by: Stanislaw Gruszka 
> ---
> v1 -> v2:
> only queue cal work with 0 delay an reset dev->cal.low_gain 
> 
>  drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 6 ++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c 
> b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
> index 9f083008dbd4..747fd2c9ec45 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
> @@ -553,6 +553,12 @@ void mt76x02_sw_scan_complete(struct ieee80211_hw *hw,
>   clear_bit(MT76_SCANNING, >mt76.state);
>   if (mt76_is_mmio(dev))
>   tasklet_enable(>pre_tbtt_tasklet);
> +
> + if (vif->bss_conf.assoc) {
> + /* Restore AGC gain and resume calibration after scanning. */
> + dev->cal.low_gain = -1;
> + ieee80211_queue_delayed_work(hw, >cal_work, 0);
> + }
>  }
>  EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete);

I think this can not be sufficient fix. Something like seems
to be needed as wall to force AGC gain write to register:

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c 
b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index 1af2a1227924..fc4085ef3e16 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -833,7 +833,7 @@ mt76x0_phy_update_channel_gain(struct mt76x02_dev *dev)
low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) +
   (dev->cal.avg_rssi_all > 
mt76x02_get_low_rssi_gain_thresh(dev));
 
-   gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2);
+   gain_change = log_gain != dev->cal.low_gain;
dev->cal.low_gain = low_gain;

but I do not fully understand this xor logic, so I'm not sure.

Thanks
Stanislaw


[PATCH v2] mt76x0: run calibration after scanning

2018-10-31 Thread Stanislaw Gruszka
If we are associated and scanning is performed, sw_scan_complete callback
is done after we get back to operating channel, so we do not perform
queue cal work. Fix this queue cal work from sw_scan_complete().

We have to restore gain in MT_BBP(AGC, 8) register after scanning, as
it was multiple times modified by channel switch code. So queue cal work
without  any delay and reset dev->cal.low_gain to assure calibration
code will AGC gain value.

Note patch was not tested on mt76x2, but should work and be needed
fix as well.

Fixes: bbd10586f0df ("mt76x0: phy: do not run calibration during channel 
switch")
Signed-off-by: Stanislaw Gruszka 
---
v1 -> v2:
only queue cal work with 0 delay an reset dev->cal.low_gain 

 drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c 
b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 9f083008dbd4..747fd2c9ec45 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -553,6 +553,12 @@ void mt76x02_sw_scan_complete(struct ieee80211_hw *hw,
clear_bit(MT76_SCANNING, >mt76.state);
if (mt76_is_mmio(dev))
tasklet_enable(>pre_tbtt_tasklet);
+
+   if (vif->bss_conf.assoc) {
+   /* Restore AGC gain and resume calibration after scanning. */
+   dev->cal.low_gain = -1;
+   ieee80211_queue_delayed_work(hw, >cal_work, 0);
+   }
 }
 EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete);
 
-- 
2.7.5



[RFC v5 01/13] rtw88: main files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

main files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/mac80211.c |  480 ++
 drivers/net/wireless/realtek/rtw88/main.c | 1187 +
 drivers/net/wireless/realtek/rtw88/main.h | 1119 +++
 drivers/net/wireless/realtek/rtw88/reg.h  |  411 +
 4 files changed, 3197 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/mac80211.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/main.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/main.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/reg.h

diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c 
b/drivers/net/wireless/realtek/rtw88/mac80211.c
new file mode 100644
index 000..17b3651
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "sec.h"
+#include "tx.h"
+#include "fw.h"
+#include "mac.h"
+#include "ps.h"
+#include "reg.h"
+#include "debug.h"
+
+static void rtw_ops_tx(struct ieee80211_hw *hw,
+  struct ieee80211_tx_control *control,
+  struct sk_buff *skb)
+{
+   struct rtw_dev *rtwdev = hw->priv;
+   struct rtw_tx_pkt_info pkt_info = {0};
+
+   if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING))
+   goto out;
+
+   rtw_tx_pkt_info_update(rtwdev, _info, control, skb);
+   if (rtw_hci_tx(rtwdev, _info, skb))
+   goto out;
+
+   return;
+
+out:
+   ieee80211_free_txskb(hw, skb);
+}
+
+static int rtw_ops_start(struct ieee80211_hw *hw)
+{
+   struct rtw_dev *rtwdev = hw->priv;
+   int ret;
+
+   mutex_lock(>mutex);
+   ret = rtw_core_start(rtwdev);
+   mutex_unlock(>mutex);
+
+   return ret;
+}
+
+static void rtw_ops_stop(struct ieee80211_hw *hw)
+{
+   struct rtw_dev *rtwdev = hw->priv;
+
+   mutex_lock(>mutex);
+   rtw_core_stop(rtwdev);
+   mutex_unlock(>mutex);
+}
+
+static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
+{
+   struct rtw_dev *rtwdev = hw->priv;
+   int ret = 0;
+
+   mutex_lock(>mutex);
+
+   if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+   if (hw->conf.flags & IEEE80211_CONF_IDLE) {
+   rtw_enter_ips(rtwdev);
+   } else {
+   ret = rtw_leave_ips(rtwdev);
+   if (ret) {
+   rtw_err(rtwdev, "failed to leave idle state\n");
+   goto out;
+   }
+   }
+   }
+
+   if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
+   rtw_set_channel(rtwdev);
+
+out:
+   mutex_unlock(>mutex);
+   return ret;
+}
+
+static const struct rtw_vif_port rtw_vif_port[] = {
+   [0] = {
+   .mac_addr   = {.addr = 0x0610},
+   .bssid  = {.addr = 0x0618},
+   .net_type   = {.addr = 0x0100, .mask = 0x3},
+   .aid= {.addr = 0x06a8, .mask = 0x7ff},
+   },
+   [1] = {
+   .mac_addr   = {.addr = 0x0700},
+   .bssid  = {.addr = 0x0708},
+   .net_type   = {.addr = 0x0100, .mask = 0xc},
+   .aid= {.addr = 0x0710, .mask = 0x7ff},
+   },
+   [2] = {
+   .mac_addr   = {.addr = 0x1620},
+   .bssid  = {.addr = 0x1628},
+   .net_type   = {.addr = 0x1100, .mask = 0x3},
+   .aid= {.addr = 0x1600, .mask = 0x7ff},
+   },
+   [3] = {
+   .mac_addr   = {.addr = 0x1630},
+   .bssid  = {.addr = 0x1638},
+   .net_type   = {.addr = 0x1100, .mask = 0xc},
+   .aid= {.addr = 0x1604, .mask = 0x7ff},
+   },
+   [4] = {
+   .mac_addr   = {.addr = 0x1640},
+   .bssid  = {.addr = 0x1648},
+   .net_type   = {.addr = 0x1100, .mask = 0x30},
+   .aid= {.addr = 0x1608, .mask = 0x7ff},
+   },
+};
+
+static int rtw_ops_add_interface(struct ieee80211_hw *hw,
+struct ieee80211_vif *vif)
+{
+   struct rtw_dev *rtwdev = hw->priv;
+   struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+   enum rtw_net_type net_type;
+   u32 config = 0;
+   u8 port = 0;
+
+   vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+   rtwvif->port = port;
+   rtwvif->vif = vif;
+   rtwvif->stats.tx_unicast = 0;
+   rtwvif->stats.rx_unicast = 0;
+   rtwvif->stats.tx_cnt = 0;
+   rtwvif->stats.rx_cnt = 0;
+   rtwvif->in_lps = false;
+   rtwvif->conf = _vif_port[port];
+
+   mutex_lock(>mutex);
+
+   switch (vif->type) {
+   

[RFC v5 00/13] rtw88: mac80211 driver for Realtek 802.11ac wireless network chips

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

This is a new mac80211 driver for Realtek 802.11ac wireless network chips.
rtw88 supports 8822BE and 8822CE chips, and will be able to support
multi-vif combinations in run-time.

For now, only PCI bus is supported, but rtw88 was originally designed
to optionally support three buses includes USB & SDIO. USB & SDIO modules
will soon be supported by rtw88, with configurable core module to fit
with different bus modules in the same time.

For example, if we choose 8822BE and 8822CU, only PCI & USB modules will
be selected, built, loaded into kernel. This is one of the major
difference from rtlwifi, which can only support specific combinations.

Another difference from rtlwifi is that rtw88 is designed to support
the latest Realtek 802.11ac wireless network chips like 8822B and
8822C series. Compared to the earlier chips supported by rtlwifi like
the 802.11n 8192EE chipset or 802.11ac 8821AE/8812AE chips, newer ICs
have different MAC & PHY settings, such as new multi-port feature for the
MAC layer design and Jaguar2/Jaguar3 PHY layer IPs.

Multi-Port feature is also supported under rtw88's software architecture.
rtlwifi can only support one vif in the same time, most because of the
hardware limitations for early chips, hence the original design of it
also restricts the usage of multi-vif support, so latest chipset seems not
take advantages from its new MAC engine.

However, rtw88 can run multiple vifs concurrently by holding them on
hardware ports provided by MAC engine, hence can easily start different
roles on a single device.

Based on the reasons mentioned before, we implemented rtw88. It had many
authors, they are listed here alphabetically:

Ping-Ke Shih 
Tzu-En Huang 
Yan-Hsuan Chuang 


v5

 - make all strings terminated with a new line
 - use request_firmware_nowait to not block if the driver
   is built-in in the kernel
 - code cleanup for h2c functions
 - simplify vif and sta iterators
 - apply correct regulatory settings
 - error check for kmalloc and skb_alloc
 - use check_hw_ready to achieve hw pollings

v4

 - remove vis_list and sta_list, use mac80211 iterator
 - use kernel helpers such as bitmap, bcd2bin, lockdep
 - move debugfs into wiphy->debugfsdir
 - use spin_lock in interrupt handler
 - remove unnecessary depends on lines in Kconfig
 - make port config constant
 - avoid watchdog timer spreading
 - return -EOPNOTSUPP for PMF key error message suppression
 - do not replace regd in wiphy for now
 - use host- fix- endian transfer in linux/bitfield.h to
   replace/get bits to/from card

v3

 - missing rcu list traverse for vif_list

v2

 - rename from rtwlan to rtw88
 - remove lots of magic numbers
 - add pci null entry for auto load on boot
 - add rtwdev->mutex to protect against mac80211 callbacks
 - add rcu lock protection for vif_list and sta_list
 - refine bits & endian macros to use helper functions provided by kernel
   instead of create new ones
 - ieee80211_free_txskb for tx path dropped packets
 - not register iface_combination since now only one vif is allowed
 - some fixes suggested by Stanislaw


Yan-Hsuan Chuang (13):
  rtw88: main files
  rtw88: core files
  rtw88: hci files
  rtw88: trx files
  rtw88: mac files
  rtw88: fw and efuse files
  rtw88: phy files
  rtw88: debug files
  rtw88: chip files
  rtw88: 8822B init table
  rtw88: 8822C init table
  rtw88: Kconfig & Makefile
  rtw88: add support for Realtek 802.11ac wireless chips

 MAINTAINERS| 8 +
 drivers/net/wireless/realtek/Kconfig   | 1 +
 drivers/net/wireless/realtek/Makefile  | 1 +
 drivers/net/wireless/realtek/rtw88/Kconfig |55 +
 drivers/net/wireless/realtek/rtw88/Makefile|19 +
 drivers/net/wireless/realtek/rtw88/debug.c |   652 +
 drivers/net/wireless/realtek/rtw88/debug.h |43 +
 drivers/net/wireless/realtek/rtw88/efuse.c |   150 +
 drivers/net/wireless/realtek/rtw88/efuse.h |53 +
 drivers/net/wireless/realtek/rtw88/fw.c|   611 +
 drivers/net/wireless/realtek/rtw88/fw.h|   213 +
 drivers/net/wireless/realtek/rtw88/hci.h   |   211 +
 drivers/net/wireless/realtek/rtw88/mac.c   |  1010 +
 drivers/net/wireless/realtek/rtw88/mac.h   |35 +
 drivers/net/wireless/realtek/rtw88/mac80211.c  |   480 +
 drivers/net/wireless/realtek/rtw88/main.c  |  1187 ++
 drivers/net/wireless/realtek/rtw88/main.h  |  1119 +
 drivers/net/wireless/realtek/rtw88/pci.c   |  1208 ++
 drivers/net/wireless/realtek/rtw88/pci.h   |   229 +
 drivers/net/wireless/realtek/rtw88/phy.c   |  1670 ++
 drivers/net/wireless/realtek/rtw88/phy.h   |   125 +
 drivers/net/wireless/realtek/rtw88/ps.c|   165 +
 drivers/net/wireless/realtek/rtw88/ps.h|20 +
 drivers/net/wireless/realtek/rtw88/reg.h   |   411 +
 drivers/net/wireless/realtek/rtw88/regd.c  |   

[RFC v5 06/13] rtw88: fw and efuse files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

fw and efuse files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/efuse.c | 150 +++
 drivers/net/wireless/realtek/rtw88/efuse.h |  53 +++
 drivers/net/wireless/realtek/rtw88/fw.c| 611 +
 drivers/net/wireless/realtek/rtw88/fw.h| 213 ++
 4 files changed, 1027 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/efuse.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/efuse.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/fw.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/fw.h

diff --git a/drivers/net/wireless/realtek/rtw88/efuse.c 
b/drivers/net/wireless/realtek/rtw88/efuse.c
new file mode 100644
index 000..7c1b782
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/efuse.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "efuse.h"
+#include "reg.h"
+#include "debug.h"
+
+#define RTW_EFUSE_BANK_WIFI0x0
+
+static void switch_efuse_bank(struct rtw_dev *rtwdev)
+{
+   rtw_write32_mask(rtwdev, REG_LDO_EFUSE_CTRL, BIT_MASK_EFUSE_BANK_SEL,
+RTW_EFUSE_BANK_WIFI);
+}
+
+static int rtw_dump_logical_efuse_map(struct rtw_dev *rtwdev, u8 *phy_map,
+ u8 *log_map)
+{
+   u32 physical_size = rtwdev->efuse.physical_size;
+   u32 protect_size = rtwdev->efuse.protect_size;
+   u32 logical_size = rtwdev->efuse.logical_size;
+   u32 phy_idx, log_idx;
+   u8 hdr1, hdr2;
+   u8 blk_idx;
+   u8 valid;
+   u8 word_en;
+   int i;
+
+   phy_idx = 0;
+
+   do {
+   hdr1 = *(phy_map + phy_idx);
+   if ((hdr1 & 0x1f) == 0xf) {
+   phy_idx++;
+   hdr2 = *(phy_map + phy_idx);
+   if (hdr2 == 0xff)
+   break;
+   blk_idx = ((hdr2 & 0xf0) >> 1) | ((hdr1 >> 5) & 0x07);
+   word_en = hdr2 & 0x0f;
+   } else {
+   blk_idx = (hdr1 & 0xf0) >> 4;
+   word_en = hdr1 & 0x0f;
+   }
+
+   if (hdr1 == 0xff)
+   break;
+
+   phy_idx++;
+   for (i = 0; i < 4; i++) {
+   valid = (~(word_en >> i)) & 0x1;
+   if (valid != 0x1)
+   continue;
+   log_idx = (blk_idx << 3) + (i << 1);
+   *(log_map + log_idx) = *(phy_map + phy_idx);
+   log_idx++;
+   phy_idx++;
+   *(log_map + log_idx) = *(phy_map + phy_idx);
+   phy_idx++;
+   if (phy_idx > physical_size - protect_size ||
+   log_idx > logical_size)
+   return -EINVAL;
+   }
+   } while (1);
+
+   return 0;
+}
+
+static int rtw_dump_physical_efuse_map(struct rtw_dev *rtwdev, u8 *map)
+{
+   struct rtw_chip_info *chip = rtwdev->chip;
+   u32 size = rtwdev->efuse.physical_size;
+   u32 efuse_ctl;
+   u32 addr;
+   u32 cnt;
+
+   switch_efuse_bank(rtwdev);
+
+   /* disable 2.5V LDO */
+   chip->ops->cfg_ldo25(rtwdev, false);
+
+   efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);
+
+   for (addr = 0; addr < size; addr++) {
+   efuse_ctl &= ~(BIT_MASK_EF_DATA | BITS_EF_ADDR);
+   efuse_ctl |= (addr & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR;
+   rtw_write32(rtwdev, REG_EFUSE_CTRL, efuse_ctl & (~BIT_EF_FLAG));
+
+   cnt = 100;
+   do {
+   udelay(1);
+   efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);
+   if (--cnt == 0)
+   return -EBUSY;
+   } while (!(efuse_ctl & BIT_EF_FLAG));
+
+   *(map + addr) = (u8)(efuse_ctl & BIT_MASK_EF_DATA);
+   }
+
+   return 0;
+}
+
+int rtw_parse_efuse_map(struct rtw_dev *rtwdev)
+{
+   struct rtw_chip_info *chip = rtwdev->chip;
+   struct rtw_efuse *efuse = >efuse;
+   u32 phy_size = efuse->physical_size;
+   u32 log_size = efuse->logical_size;
+   u8 *phy_map = NULL;
+   u8 *log_map = NULL;
+   int ret = 0;
+
+   phy_map = kmalloc(phy_size, GFP_KERNEL);
+   log_map = kmalloc(log_size, GFP_KERNEL);
+   if (!phy_map || !log_map) {
+   ret = -ENOMEM;
+   goto out_free;
+   }
+
+   ret = rtw_dump_physical_efuse_map(rtwdev, phy_map);
+   if (ret) {
+   rtw_err(rtwdev, "failed to dump efuse physical map\n");
+   goto out_free;
+   }
+
+   memset(log_map, 0xff, log_size);
+   ret = rtw_dump_logical_efuse_map(rtwdev, phy_map, 

[RFC v5 09/13] rtw88: chip files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

chip files Realtek 802.11ac wireless network chips
8822B & 8822C series files

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/rtw8822b.c  | 1590 
 drivers/net/wireless/realtek/rtw88/rtw8822b.h  |  155 ++
 .../net/wireless/realtek/rtw88/rtw8822b_table.h|   18 +
 drivers/net/wireless/realtek/rtw88/rtw8822c.c  | 1169 ++
 drivers/net/wireless/realtek/rtw88/rtw8822c.h  |  171 +++
 .../net/wireless/realtek/rtw88/rtw8822c_table.h|   16 +
 6 files changed, 3119 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822b.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822b.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822b_table.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822c.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822c.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822c_table.h

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c 
b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
new file mode 100644
index 000..0339041
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
@@ -0,0 +1,1590 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "fw.h"
+#include "tx.h"
+#include "rx.h"
+#include "phy.h"
+#include "rtw8822b.h"
+#include "rtw8822b_table.h"
+#include "mac.h"
+#include "reg.h"
+#include "debug.h"
+
+static void rtw8822b_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path,
+u8 rx_path, bool is_tx2_path);
+
+static void rtw8822be_efuse_parsing(struct rtw_efuse *efuse,
+   struct rtw8822b_efuse *map)
+{
+   ether_addr_copy(efuse->addr, map->e.mac_addr);
+}
+
+static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
+{
+   struct rtw_efuse *efuse = >efuse;
+   struct rtw8822b_efuse *map;
+   int i;
+
+   map = (struct rtw8822b_efuse *)log_map;
+
+   efuse->rfe_option = map->rfe_option;
+   efuse->crystal_cap = map->xtal_k;
+   efuse->pa_type_2g = map->pa_type;
+   efuse->pa_type_5g = map->pa_type;
+   efuse->lna_type_2g = map->lna_type_2g[0];
+   efuse->lna_type_5g = map->lna_type_5g[0];
+   efuse->channel_plan = map->channel_plan;
+   efuse->country_code[0] = map->country_code[0];
+   efuse->country_code[1] = map->country_code[1];
+   efuse->bt_setting = map->rf_bt_setting;
+   efuse->regd = map->rf_board_option & 0x7;
+
+   for (i = 0; i < 4; i++)
+   efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i];
+
+   switch (rtw_hci_type(rtwdev)) {
+   case RTW_HCI_TYPE_PCIE:
+   rtw8822be_efuse_parsing(efuse, map);
+   break;
+   default:
+   /* unsupported now */
+   return -ENOTSUPP;
+   }
+
+   return 0;
+}
+
+static void rtw8822b_phy_rfe_init(struct rtw_dev *rtwdev)
+{
+   /* chip top mux */
+   rtw_write32_mask(rtwdev, 0x64, BIT(29) | BIT(28), 0x3);
+   rtw_write32_mask(rtwdev, 0x4c, BIT(26) | BIT(25), 0x0);
+   rtw_write32_mask(rtwdev, 0x40, BIT(2), 0x1);
+
+   /* from s0 or s1 */
+   rtw_write32_mask(rtwdev, 0x1990, 0x3f, 0x30);
+   rtw_write32_mask(rtwdev, 0x1990, (BIT(11) | BIT(10)), 0x3);
+
+   /* input or output */
+   rtw_write32_mask(rtwdev, 0x974, 0x3f, 0x3f);
+   rtw_write32_mask(rtwdev, 0x974, (BIT(11) | BIT(10)), 0x3);
+}
+
+static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev)
+{
+   struct rtw_hal *hal = >hal;
+   u8 crystal_cap;
+   bool is_tx2_path;
+
+   /* power on BB/RF domain */
+   rtw_write8_set(rtwdev, REG_SYS_FUNC_EN,
+  BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST);
+   rtw_write8_set(rtwdev, REG_RF_CTRL,
+  BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB);
+   rtw_write32_set(rtwdev, REG_WLRF1, BIT_WLRF1_BBRF_EN);
+
+   /* pre init before header files config */
+   rtw_write32_clr(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
+
+   rtw_phy_load_tables(rtwdev);
+
+   crystal_cap = rtwdev->efuse.crystal_cap & 0x3F;
+   rtw_write32_mask(rtwdev, 0x24, 0x7e00, crystal_cap);
+   rtw_write32_mask(rtwdev, 0x28, 0x7e, crystal_cap);
+
+   /* post init after header files config */
+   rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
+
+   is_tx2_path = false;
+   rtw8822b_config_trx_mode(rtwdev, hal->antenna_tx, hal->antenna_rx,
+is_tx2_path);
+   rtw_phy_init(rtwdev);
+
+   rtw8822b_phy_rfe_init(rtwdev);
+
+   /* wifi path controller */
+   rtw_write32_mask(rtwdev, 0x70, 0x400, 1);
+   /* BB control */
+   rtw_write32_mask(rtwdev, 0x4c, 0x0180, 0x2);
+   /* antenna mux switch */
+   rtw_write8(rtwdev, 0x974, 0xff);
+   rtw_write32_mask(rtwdev, 0x1990, 0x300, 0);
+   

[RFC v5 11/13] rtw88: 8822C init table

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

8822C init table for chip files Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 .../net/wireless/realtek/rtw88/rtw8822c_table.c| 4150 
 1 file changed, 4150 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822c_table.c

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c 
b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
new file mode 100644
index 000..e95ad82
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
@@ -0,0 +1,4150 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "phy.h"
+#include "rtw8822c_table.h"
+
+static const u32 rtw8822c_mac[] = {
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8822c_mac, rtw_phy_cfg_mac);
+
+static const u32 rtw8822c_agc[] = {
+   0x1D90, 0x31FF,
+   0x1D90, 0x300101FF,
+   0x1D90, 0x300201FF,
+   0x1D90, 0x300301FF,
+   0x1D90, 0x300401FF,
+   0x1D90, 0x300501FF,
+   0x1D90, 0x300601FE,
+   0x1D90, 0x300701FD,
+   0x1D90, 0x300801FC,
+   0x1D90, 0x300901FB,
+   0x1D90, 0x300A01FA,
+   0x1D90, 0x300B01F9,
+   0x1D90, 0x300C01F8,
+   0x1D90, 0x300D01F7,
+   0x1D90, 0x300E01F6,
+   0x1D90, 0x300F01F5,
+   0x1D90, 0x301001F4,
+   0x1D90, 0x301101F3,
+   0x1D90, 0x301201F2,
+   0x1D90, 0x301301F1,
+   0x1D90, 0x301401F0,
+   0x1D90, 0x301501EF,
+   0x1D90, 0x301601AF,
+   0x1D90, 0x301701AE,
+   0x1D90, 0x301801AD,
+   0x1D90, 0x301901AC,
+   0x1D90, 0x301A01AB,
+   0x1D90, 0x301B01AA,
+   0x1D90, 0x301C01A9,
+   0x1D90, 0x301D0188,
+   0x1D90, 0x301E0187,
+   0x1D90, 0x301F0186,
+   0x1D90, 0x30200185,
+   0x1D90, 0x30210168,
+   0x1D90, 0x30220167,
+   0x1D90, 0x30230166,
+   0x1D90, 0x30240108,
+   0x1D90, 0x30250107,
+   0x1D90, 0x30260106,
+   0x1D90, 0x30270144,
+   0x1D90, 0x30280143,
+   0x1D90, 0x30290142,
+   0x1D90, 0x302A0141,
+   0x1D90, 0x302B0140,
+   0x1D90, 0x302C00C9,
+   0x1D90, 0x302D00C8,
+   0x1D90, 0x302E00C7,
+   0x1D90, 0x302F00C6,
+   0x1D90, 0x303000C5,
+   0x1D90, 0x303100C4,
+   0x1D90, 0x303200C3,
+   0x1D90, 0x30330088,
+   0x1D90, 0x30340087,
+   0x1D90, 0x30350086,
+   0x1D90, 0x30360045,
+   0x1D90, 0x30370044,
+   0x1D90, 0x30380043,
+   0x1D90, 0x30390023,
+   0x1D90, 0x303A0022,
+   0x1D90, 0x303B0021,
+   0x1D90, 0x303C0020,
+   0x1D90, 0x303D0002,
+   0x1D90, 0x303E0001,
+   0x1D90, 0x303F,
+   0x1D90, 0x304000FF,
+   0x1D90, 0x304100FF,
+   0x1D90, 0x304200FF,
+   0x1D90, 0x304300FF,
+   0x1D90, 0x304400FF,
+   0x1D90, 0x304500FE,
+   0x1D90, 0x304600FD,
+   0x1D90, 0x304700FC,
+   0x1D90, 0x304800FB,
+   0x1D90, 0x304900FA,
+   0x1D90, 0x304A00F9,
+   0x1D90, 0x304B00F8,
+   0x1D90, 0x304C00F7,
+   0x1D90, 0x304D00F6,
+   0x1D90, 0x304E00F5,
+   0x1D90, 0x304F00F4,
+   0x1D90, 0x305000F3,
+   0x1D90, 0x305100F2,
+   0x1D90, 0x305200F1,
+   0x1D90, 0x305300F0,
+   0x1D90, 0x305400EF,
+   0x1D90, 0x305500EE,
+   0x1D90, 0x305600ED,
+   0x1D90, 0x305700EC,
+   0x1D90, 0x305800EB,
+   0x1D90, 0x305900EA,
+   0x1D90, 0x305A00E9,
+   0x1D90, 0x305B00E8,
+   0x1D90, 0x305C00E7,
+   0x1D90, 0x305D00E6,
+   0x1D90, 0x305E00E5,
+   0x1D90, 0x305F00E4,
+   0x1D90, 0x306000E3,
+   0x1D90, 0x306100C3,
+   0x1D90, 0x306200C2,
+   0x1D90, 0x306300C1,
+   0x1D90, 0x30640088,
+   0x1D90, 0x30650087,
+   0x1D90, 0x30660086,
+   0x1D90, 0x30670085,
+   0x1D90, 0x30680084,
+   0x1D90, 0x30690083,
+   0x1D90, 0x306A0082,
+   0x1D90, 0x306B0081,
+   0x1D90, 0x306C0068,
+   0x1D90, 0x306D0067,
+   0x1D90, 0x306E0066,
+   0x1D90, 0x306F0065,
+   0x1D90, 0x30700064,
+   0x1D90, 0x30710063,
+   

[RFC v5 08/13] rtw88: debug files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

debug files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/debug.c | 652 +
 drivers/net/wireless/realtek/rtw88/debug.h |  43 ++
 2 files changed, 695 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/debug.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/debug.h

diff --git a/drivers/net/wireless/realtek/rtw88/debug.c 
b/drivers/net/wireless/realtek/rtw88/debug.c
new file mode 100644
index 000..ad78e89
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include 
+#include 
+#include "main.h"
+#include "sec.h"
+#include "fw.h"
+#include "debug.h"
+
+#ifdef CONFIG_RTW88_DEBUGFS
+
+struct rtw_debugfs_priv {
+   struct rtw_dev *rtwdev;
+   int (*cb_read)(struct seq_file *m, void *v);
+   ssize_t (*cb_write)(struct file *filp, const char __user *buffer,
+   size_t count, loff_t *loff);
+   union {
+   u32 cb_data;
+   u8 *buf;
+   struct {
+   u32 page_offset;
+   u32 page_num;
+   } rsvd_page;
+   struct {
+   u8 rf_path;
+   u32 rf_addr;
+   u32 rf_mask;
+   };
+   struct {
+   u32 addr;
+   u32 len;
+   } read_reg;
+   };
+};
+
+static int rtw_debugfs_single_show(struct seq_file *m, void *v)
+{
+   struct rtw_debugfs_priv *debugfs_priv = m->private;
+
+   return debugfs_priv->cb_read(m, v);
+}
+
+static ssize_t rtw_debugfs_common_write(struct file *filp,
+   const char __user *buffer,
+   size_t count, loff_t *loff)
+{
+   struct rtw_debugfs_priv *debugfs_priv = filp->private_data;
+
+   return debugfs_priv->cb_write(filp, buffer, count, loff);
+}
+
+static ssize_t rtw_debugfs_single_write(struct file *filp,
+   const char __user *buffer,
+   size_t count, loff_t *loff)
+{
+   struct seq_file *seqpriv = (struct seq_file *)filp->private_data;
+   struct rtw_debugfs_priv *debugfs_priv = seqpriv->private;
+
+   return debugfs_priv->cb_write(filp, buffer, count, loff);
+}
+
+static int rtw_debugfs_single_open_rw(struct inode *inode, struct file *filp)
+{
+   return single_open(filp, rtw_debugfs_single_show, inode->i_private);
+}
+
+static int rtw_debugfs_close(struct inode *inode, struct file *filp)
+{
+   return 0;
+}
+
+static const struct file_operations file_ops_single_r = {
+   .owner = THIS_MODULE,
+   .open = rtw_debugfs_single_open_rw,
+   .read = seq_read,
+   .llseek = seq_lseek,
+   .release = seq_release,
+};
+
+static const struct file_operations file_ops_single_rw = {
+   .owner = THIS_MODULE,
+   .open = rtw_debugfs_single_open_rw,
+   .release = single_release,
+   .read = seq_read,
+   .llseek = seq_lseek,
+   .write = rtw_debugfs_single_write,
+};
+
+static const struct file_operations file_ops_common_write = {
+   .owner = THIS_MODULE,
+   .write = rtw_debugfs_common_write,
+   .open = simple_open,
+   .release = rtw_debugfs_close,
+};
+
+static int rtw_debugfs_get_read_reg(struct seq_file *m, void *v)
+{
+   struct rtw_debugfs_priv *debugfs_priv = m->private;
+   struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
+   u32 val, len, addr;
+
+   len = debugfs_priv->read_reg.len;
+   addr = debugfs_priv->read_reg.addr;
+   switch (len) {
+   case 1:
+   val = rtw_read8(rtwdev, addr);
+   seq_printf(m, "reg 0x%03x: 0x%02x\n", addr, val);
+   break;
+   case 2:
+   val = rtw_read16(rtwdev, addr);
+   seq_printf(m, "reg 0x%03x: 0x%04x\n", addr, val);
+   break;
+   case 4:
+   val = rtw_read32(rtwdev, addr);
+   seq_printf(m, "reg 0x%03x: 0x%08x\n", addr, val);
+   break;
+   }
+   return 0;
+}
+
+static int rtw_debugfs_get_rf_read(struct seq_file *m, void *v)
+{
+   struct rtw_debugfs_priv *debugfs_priv = m->private;
+   struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
+   u32 val, addr, mask;
+   u8 path;
+
+   path = debugfs_priv->rf_path;
+   addr = debugfs_priv->rf_addr;
+   mask = debugfs_priv->rf_mask;
+
+   val = rtw_read_rf(rtwdev, path, addr, mask);
+
+   seq_printf(m, "rf_read path:%d addr:0x%08x mask:0x%08x val=0x%08x\n",
+  path, addr, mask, val);
+
+   return 0;
+}
+
+static int rtw_debugfs_copy_from_user(char tmp[], int size,
+ const char __user *buffer, size_t count,
+   

[RFC v5 13/13] rtw88: add support for Realtek 802.11ac wireless chips

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

Signed-off-by: Yan-Hsuan Chuang 
---
 MAINTAINERS | 8 
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052a..138515b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12546,6 +12546,14 @@ T: git 
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.g
 S: Maintained
 F: drivers/net/wireless/realtek/rtlwifi/
 
+REALTEK WIRELESS DRIVER (rtw88)
+M: Yan-Hsuan Chuang 
+L: linux-wireless@vger.kernel.org
+W: http://wireless.kernel.org/
+T: git 
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
+S: Maintained
+F: drivers/net/wireless/realtek/rtw88/
+
 RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
 M: Jes Sorensen 
 L: linux-wireless@vger.kernel.org
-- 
2.7.4



[RFC v5 07/13] rtw88: phy files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

phy files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/phy.c | 1670 ++
 drivers/net/wireless/realtek/rtw88/phy.h |  125 +++
 2 files changed, 1795 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/phy.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/phy.h

diff --git a/drivers/net/wireless/realtek/rtw88/phy.c 
b/drivers/net/wireless/realtek/rtw88/phy.c
new file mode 100644
index 000..51b7fca
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -0,0 +1,1670 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include 
+
+#include "main.h"
+#include "fw.h"
+#include "phy.h"
+#include "debug.h"
+
+struct phy_cfg_pair {
+   u32 addr;
+   u32 data;
+};
+
+union phy_table_tile {
+   struct rtw_phy_cond cond;
+   struct phy_cfg_pair cfg;
+};
+
+struct phy_pg_cfg_pair {
+   u32 band;
+   u32 rf_path;
+   u32 tx_num;
+   u32 addr;
+   u32 bitmask;
+   u32 data;
+};
+
+struct txpwr_lmt_cfg_pair {
+   u8 regd;
+   u8 band;
+   u8 bw;
+   u8 rs;
+   u8 ch;
+   s8 txpwr_lmt;
+};
+
+static const u32 db_invert_table[12][8] = {
+   {10,13, 16, 20,
+25,32, 40, 50},
+   {64,80, 101,128,
+160,   201,256,318},
+   {401,   505,635,800,
+1007,  1268,   1596,   2010},
+   {316,   398,501,631,
+794,   1000,   1259,   1585},
+   {1995,  2512,   3162,   3981,
+5012,  6310,   7943,   1},
+   {12589, 15849,  19953,  25119,
+31623, 39811,  50119,  63098},
+   {79433, 10, 125893, 158489,
+199526,251189, 316228, 398107},
+   {501187,630957, 794328, 100,
+1258925,   1584893,1995262,2511886},
+   {3162278,   3981072,5011872,6309573,
+7943282,   100,12589254,   15848932},
+   {19952623,  25118864,   31622777,   39810717,
+50118723,  63095734,   79432823,   1},
+   {125892541, 158489319,  199526232,  251188643,
+316227766, 398107171,  501187234,  630957345},
+   {794328235, 10, 1258925412, 1584893192,
+1995262315,2511886432U,3162277660U,3981071706U}
+};
+
+enum rtw_phy_band_type {
+   PHY_BAND_2G = 0,
+   PHY_BAND_5G = 1,
+};
+
+void rtw_phy_init(struct rtw_dev *rtwdev)
+{
+   struct rtw_chip_info *chip = rtwdev->chip;
+   struct rtw_dm_info *dm_info = >dm_info;
+   u32 addr, mask;
+
+   dm_info->fa_history[3] = 0;
+   dm_info->fa_history[2] = 0;
+   dm_info->fa_history[1] = 0;
+   dm_info->fa_history[0] = 0;
+   dm_info->igi_bitmap = 0;
+   dm_info->igi_history[3] = 0;
+   dm_info->igi_history[2] = 0;
+   dm_info->igi_history[1] = 0;
+
+   addr = chip->dig[0].addr;
+   mask = chip->dig[0].mask;
+   dm_info->igi_history[0] = rtw_read32_mask(rtwdev, addr, mask);
+}
+
+void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi)
+{
+   struct rtw_chip_info *chip = rtwdev->chip;
+   struct rtw_hal *hal = >hal;
+   u32 addr, mask;
+   u8 path;
+
+   for (path = 0; path < hal->rf_path_num; path++) {
+   addr = chip->dig[path].addr;
+   mask = chip->dig[path].mask;
+   rtw_write32_mask(rtwdev, addr, mask, igi);
+   }
+}
+
+static void rtw_phy_stat_false_alarm(struct rtw_dev *rtwdev)
+{
+   struct rtw_chip_info *chip = rtwdev->chip;
+
+   chip->ops->false_alarm_statistics(rtwdev);
+}
+
+#define RA_FLOOR_TABLE_SIZE7
+#define RA_FLOOR_UP_GAP3
+
+static u8 rtw_phy_get_rssi_level(u8 old_level, u8 rssi)
+{
+   u8 table[RA_FLOOR_TABLE_SIZE] = {20, 34, 38, 42, 46, 50, 100};
+   u8 new_level = 0;
+   int i;
+
+   for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++)
+   if (i >= old_level)
+   table[i] += RA_FLOOR_UP_GAP;
+
+   for (i = 0; i < RA_FLOOR_TABLE_SIZE; i++) {
+   if (rssi < table[i]) {
+   new_level = i;
+   break;
+   }
+   }
+
+   return new_level;
+}
+
+struct rtw_phy_stat_iter_data {
+   struct rtw_dev *rtwdev;
+   u8 min_rssi;
+};
+
+static void rtw_phy_stat_rssi_iter(void *data, struct ieee80211_sta *sta)
+{
+   struct rtw_phy_stat_iter_data *iter_data = data;
+   struct rtw_dev 

[RFC v5 12/13] rtw88: Kconfig & Makefile

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

Kconfig & Makefile for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/Kconfig|  1 +
 drivers/net/wireless/realtek/Makefile   |  1 +
 drivers/net/wireless/realtek/rtw88/Kconfig  | 55 +
 drivers/net/wireless/realtek/rtw88/Makefile | 19 ++
 4 files changed, 76 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/Kconfig
 create mode 100644 drivers/net/wireless/realtek/rtw88/Makefile

diff --git a/drivers/net/wireless/realtek/Kconfig 
b/drivers/net/wireless/realtek/Kconfig
index 3db988e..9189fd6 100644
--- a/drivers/net/wireless/realtek/Kconfig
+++ b/drivers/net/wireless/realtek/Kconfig
@@ -14,5 +14,6 @@ if WLAN_VENDOR_REALTEK
 source "drivers/net/wireless/realtek/rtl818x/Kconfig"
 source "drivers/net/wireless/realtek/rtlwifi/Kconfig"
 source "drivers/net/wireless/realtek/rtl8xxxu/Kconfig"
+source "drivers/net/wireless/realtek/rtw88/Kconfig"
 
 endif # WLAN_VENDOR_REALTEK
diff --git a/drivers/net/wireless/realtek/Makefile 
b/drivers/net/wireless/realtek/Makefile
index 9c78deb..118af99 100644
--- a/drivers/net/wireless/realtek/Makefile
+++ b/drivers/net/wireless/realtek/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_RTL8180)   += rtl818x/
 obj-$(CONFIG_RTL8187)  += rtl818x/
 obj-$(CONFIG_RTLWIFI)  += rtlwifi/
 obj-$(CONFIG_RTL8XXXU) += rtl8xxxu/
+obj-$(CONFIG_RTW88)+= rtw88/
 
diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig 
b/drivers/net/wireless/realtek/rtw88/Kconfig
new file mode 100644
index 000..bd68c7c
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/Kconfig
@@ -0,0 +1,55 @@
+menuconfig RTW88
+   tristate "Realtek 802.11ac wireless chips support"
+   depends on MAC80211
+   default y
+   help
+ This module adds support for mac80211-based wireless drivers that
+ enables Realtek IEEE 802.11ac wireless chipsets.
+
+ If you choose to build a module, it'll be called rtw88.
+
+if RTW88
+
+config RTW88_CORE
+   tristate
+
+config RTW88_PCI
+   tristate
+
+config RTW88_8822BE
+   bool "Realtek 8822BE PCI wireless network adapter"
+   depends on PCI
+   select RTW88_CORE
+   select RTW88_PCI
+   help
+ Select this option will enable support for 8822BE chipset
+
+ 802.11ac PCIe wireless network adapter
+
+config RTW88_8822CE
+   bool "Realtek 8822CE PCI wireless network adapter"
+   depends on PCI
+   select RTW88_CORE
+   select RTW88_PCI
+   help
+ Select this option will enable support for 8822CE chipset
+
+ 802.11ac PCIe wireless network adapter
+
+config RTW88_DEBUG
+   bool "Realtek rtw88 debug support"
+   depends on RTW88_CORE
+   help
+ Enable debug support
+
+ If unsure, say Y to simplify debug problems
+
+config RTW88_DEBUGFS
+   bool "Realtek rtw88 debugfs support"
+   depends on RTW88_CORE
+   help
+ Enable debug support
+
+ If unsure, say Y to simplify debug problems
+
+endif
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile 
b/drivers/net/wireless/realtek/rtw88/Makefile
new file mode 100644
index 000..d70782a
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -0,0 +1,19 @@
+obj-$(CONFIG_RTW88_CORE)   += rtw88.o
+rtw88-y += main.o \
+  mac80211.o \
+  debug.o \
+  tx.o \
+  rx.o \
+  mac.o \
+  phy.o \
+  efuse.o \
+  fw.o \
+  ps.o \
+  sec.o \
+  regd.o
+
+rtw88-$(CONFIG_RTW88_8822BE)   += rtw8822b.o rtw8822b_table.o
+rtw88-$(CONFIG_RTW88_8822CE)   += rtw8822c.o rtw8822c_table.o
+
+obj-$(CONFIG_RTW88_PCI)+= rtwpci.o
+rtwpci-objs:= pci.o
-- 
2.7.4



[RFC v5 04/13] rtw88: trx files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

trx files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/rx.c | 151 ++
 drivers/net/wireless/realtek/rtw88/rx.h |  41 +
 drivers/net/wireless/realtek/rtw88/tx.c | 273 
 drivers/net/wireless/realtek/rtw88/tx.h |  81 ++
 4 files changed, 546 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/rx.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/rx.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/tx.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/tx.h

diff --git a/drivers/net/wireless/realtek/rtw88/rx.c 
b/drivers/net/wireless/realtek/rtw88/rx.c
new file mode 100644
index 000..276856e
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rx.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "rx.h"
+#include "ps.h"
+
+void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
+ struct sk_buff *skb)
+{
+   struct ieee80211_hdr *hdr;
+   struct rtw_vif *rtwvif;
+
+   hdr = (struct ieee80211_hdr *)skb->data;
+
+   if (!ieee80211_is_data(hdr->frame_control))
+   return;
+
+   if (!is_broadcast_ether_addr(hdr->addr1) &&
+   !is_multicast_ether_addr(hdr->addr1)) {
+   rtwdev->stats.rx_unicast += skb->len;
+   rtwdev->stats.rx_cnt++;
+   if (vif) {
+   rtwvif = (struct rtw_vif *)vif->drv_priv;
+   rtwvif->stats.rx_unicast += skb->len;
+   rtwvif->stats.rx_cnt++;
+   if (rtwvif->stats.rx_cnt > RTW_LPS_THRESHOLD)
+   rtw_leave_lps_irqsafe(rtwdev, rtwvif);
+   }
+   }
+}
+EXPORT_SYMBOL(rtw_rx_stats);
+
+struct rtw_rx_addr_match_data {
+   struct rtw_dev *rtwdev;
+   struct ieee80211_hdr *hdr;
+   struct rtw_rx_pkt_stat *pkt_stat;
+   u8 *bssid;
+};
+
+static void rtw_rx_addr_match_iter(void *data, u8 *mac,
+  struct ieee80211_vif *vif)
+{
+   struct rtw_rx_addr_match_data *iter_data = data;
+   struct ieee80211_sta *sta;
+   struct ieee80211_hdr *hdr = iter_data->hdr;
+   struct rtw_dev *rtwdev = iter_data->rtwdev;
+   struct rtw_sta_info *si;
+   struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
+   u8 *bssid = iter_data->bssid;
+
+   if (ether_addr_equal(vif->bss_conf.bssid, bssid) &&
+   (ether_addr_equal(vif->addr, hdr->addr1) ||
+ieee80211_is_beacon(hdr->frame_control)))
+   sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2,
+  vif->addr);
+   else
+   return;
+
+   if (!sta)
+   return;
+
+   si = (struct rtw_sta_info *)sta->drv_priv;
+   ewma_rssi_add(>avg_rssi, pkt_stat->rssi);
+}
+
+static void rtw_rx_addr_match(struct rtw_dev *rtwdev,
+ struct rtw_rx_pkt_stat *pkt_stat,
+ struct ieee80211_hdr *hdr)
+{
+   struct rtw_rx_addr_match_data data = {};
+
+   if (pkt_stat->crc_err || pkt_stat->icv_err || !pkt_stat->phy_status ||
+   ieee80211_is_ctl(hdr->frame_control))
+   return;
+
+   data.rtwdev = rtwdev;
+   data.hdr = hdr;
+   data.pkt_stat = pkt_stat;
+   data.bssid = get_hdr_bssid(hdr);
+
+   rtw_iterate_vifs_atomic(rtwdev, rtw_rx_addr_match_iter, );
+}
+
+void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
+  struct rtw_rx_pkt_stat *pkt_stat,
+  struct ieee80211_hdr *hdr,
+  struct ieee80211_rx_status *rx_status,
+  u8 *phy_status)
+{
+   struct ieee80211_hw *hw = rtwdev->hw;
+
+   memset(rx_status, 0, sizeof(*rx_status));
+   rx_status->freq = hw->conf.chandef.chan->center_freq;
+   rx_status->band = hw->conf.chandef.chan->band;
+   if (pkt_stat->crc_err)
+   rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+   if (pkt_stat->decrypted)
+   rx_status->flag |= RX_FLAG_DECRYPTED;
+
+   if (pkt_stat->rate >= DESC_RATEVHT1SS_MCS0)
+   rx_status->encoding = RX_ENC_VHT;
+   else if (pkt_stat->rate >= DESC_RATEMCS0)
+   rx_status->encoding = RX_ENC_HT;
+
+   if (pkt_stat->rate >= DESC_RATEVHT1SS_MCS0 &&
+   pkt_stat->rate <= DESC_RATEVHT1SS_MCS9) {
+   rx_status->nss = 1;
+   rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT1SS_MCS0;
+   } else if (pkt_stat->rate >= DESC_RATEVHT2SS_MCS0 &&
+  pkt_stat->rate <= DESC_RATEVHT2SS_MCS9) {
+   rx_status->nss = 2;
+   rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT2SS_MCS0;
+   } else if 

[RFC v5 03/13] rtw88: hci files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

hci files for Realtek 802.11ac wireless network chips

For now there is only PCI bus supported by rtwlan, in the future it
will also have USB/SDIO

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/hci.h |  211 ++
 drivers/net/wireless/realtek/rtw88/pci.c | 1208 ++
 drivers/net/wireless/realtek/rtw88/pci.h |  229 ++
 3 files changed, 1648 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/hci.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/pci.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/pci.h

diff --git a/drivers/net/wireless/realtek/rtw88/hci.h 
b/drivers/net/wireless/realtek/rtw88/hci.h
new file mode 100644
index 000..91b15ef
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/hci.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#ifndef__RTW_HCI_H__
+#define __RTW_HCI_H__
+
+/* ops for PCI, USB and SDIO */
+struct rtw_hci_ops {
+   int (*tx)(struct rtw_dev *rtwdev,
+ struct rtw_tx_pkt_info *pkt_info,
+ struct sk_buff *skb);
+   int (*setup)(struct rtw_dev *rtwdev);
+   int (*start)(struct rtw_dev *rtwdev);
+   void (*stop)(struct rtw_dev *rtwdev);
+
+   int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
+   int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
+
+   u8 (*read8)(struct rtw_dev *rtwdev, u32 addr);
+   u16 (*read16)(struct rtw_dev *rtwdev, u32 addr);
+   u32 (*read32)(struct rtw_dev *rtwdev, u32 addr);
+   void (*write8)(struct rtw_dev *rtwdev, u32 addr, u8 val);
+   void (*write16)(struct rtw_dev *rtwdev, u32 addr, u16 val);
+   void (*write32)(struct rtw_dev *rtwdev, u32 addr, u32 val);
+};
+
+static inline int rtw_hci_tx(struct rtw_dev *rtwdev,
+struct rtw_tx_pkt_info *pkt_info,
+struct sk_buff *skb)
+{
+   return rtwdev->hci.ops->tx(rtwdev, pkt_info, skb);
+}
+
+static inline int rtw_hci_setup(struct rtw_dev *rtwdev)
+{
+   return rtwdev->hci.ops->setup(rtwdev);
+}
+
+static inline int rtw_hci_start(struct rtw_dev *rtwdev)
+{
+   return rtwdev->hci.ops->start(rtwdev);
+}
+
+static inline void rtw_hci_stop(struct rtw_dev *rtwdev)
+{
+   rtwdev->hci.ops->stop(rtwdev);
+}
+
+static inline int
+rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
+{
+   return rtwdev->hci.ops->write_data_rsvd_page(rtwdev, buf, size);
+}
+
+static inline int
+rtw_hci_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
+{
+   return rtwdev->hci.ops->write_data_h2c(rtwdev, buf, size);
+}
+
+static inline u8 rtw_read8(struct rtw_dev *rtwdev, u32 addr)
+{
+   return rtwdev->hci.ops->read8(rtwdev, addr);
+}
+
+static inline u16 rtw_read16(struct rtw_dev *rtwdev, u32 addr)
+{
+   return rtwdev->hci.ops->read16(rtwdev, addr);
+}
+
+static inline u32 rtw_read32(struct rtw_dev *rtwdev, u32 addr)
+{
+   return rtwdev->hci.ops->read32(rtwdev, addr);
+}
+
+static inline void rtw_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
+{
+   rtwdev->hci.ops->write8(rtwdev, addr, val);
+}
+
+static inline void rtw_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
+{
+   rtwdev->hci.ops->write16(rtwdev, addr, val);
+}
+
+static inline void rtw_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
+{
+   rtwdev->hci.ops->write32(rtwdev, addr, val);
+}
+
+static inline void rtw_write8_set(struct rtw_dev *rtwdev, u32 addr, u8 bit)
+{
+   u8 val;
+
+   val = rtw_read8(rtwdev, addr);
+   rtw_write8(rtwdev, addr, val | bit);
+}
+
+static inline void rtw_writ16_set(struct rtw_dev *rtwdev, u32 addr, u16 bit)
+{
+   u16 val;
+
+   val = rtw_read16(rtwdev, addr);
+   rtw_write16(rtwdev, addr, val | bit);
+}
+
+static inline void rtw_write32_set(struct rtw_dev *rtwdev, u32 addr, u32 bit)
+{
+   u32 val;
+
+   val = rtw_read32(rtwdev, addr);
+   rtw_write32(rtwdev, addr, val | bit);
+}
+
+static inline void rtw_write8_clr(struct rtw_dev *rtwdev, u32 addr, u8 bit)
+{
+   u8 val;
+
+   val = rtw_read8(rtwdev, addr);
+   rtw_write8(rtwdev, addr, val & ~bit);
+}
+
+static inline void rtw_write16_clr(struct rtw_dev *rtwdev, u32 addr, u16 bit)
+{
+   u16 val;
+
+   val = rtw_read16(rtwdev, addr);
+   rtw_write16(rtwdev, addr, val & ~bit);
+}
+
+static inline void rtw_write32_clr(struct rtw_dev *rtwdev, u32 addr, u32 bit)
+{
+   u32 val;
+
+   val = rtw_read32(rtwdev, addr);
+   rtw_write32(rtwdev, addr, val & ~bit);
+}
+
+static inline u32
+rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
+   u32 addr, u32 mask)
+{
+   unsigned long flags;
+   u32 val;
+
+   spin_lock_irqsave(>rf_lock, flags);
+   val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
+   spin_unlock_irqrestore(>rf_lock, 

[RFC v5 02/13] rtw88: core files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

core files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/ps.c   | 165 +
 drivers/net/wireless/realtek/rtw88/ps.h   |  20 ++
 drivers/net/wireless/realtek/rtw88/regd.c | 391 ++
 drivers/net/wireless/realtek/rtw88/regd.h |  67 +
 drivers/net/wireless/realtek/rtw88/sec.c  | 120 +
 drivers/net/wireless/realtek/rtw88/sec.h  |  39 +++
 6 files changed, 802 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/ps.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/ps.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/regd.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/regd.h
 create mode 100644 drivers/net/wireless/realtek/rtw88/sec.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/sec.h

diff --git a/drivers/net/wireless/realtek/rtw88/ps.c 
b/drivers/net/wireless/realtek/rtw88/ps.c
new file mode 100644
index 000..db51910
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "fw.h"
+#include "ps.h"
+#include "mac.h"
+#include "debug.h"
+
+static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
+{
+   int ret;
+
+   ret = rtw_core_start(rtwdev);
+   if (ret)
+   rtw_err(rtwdev, "leave idle state failed\n");
+
+   rtw_flag_clear(rtwdev, RTW_FLAG_INACTIVE_PS);
+
+   return ret;
+}
+
+int rtw_enter_ips(struct rtw_dev *rtwdev)
+{
+   rtw_flag_set(rtwdev, RTW_FLAG_INACTIVE_PS);
+
+   rtw_core_stop(rtwdev);
+
+   return 0;
+}
+
+static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+   struct rtw_dev *rtwdev = data;
+   struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+   u32 config = ~0;
+
+   rtw_vif_port_config(rtwdev, rtwvif, config);
+}
+
+int rtw_leave_ips(struct rtw_dev *rtwdev)
+{
+   int ret;
+
+   ret = rtw_ips_pwr_up(rtwdev);
+   if (ret) {
+   rtw_err(rtwdev, "failed to leave ips state\n");
+   return ret;
+   }
+
+   rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
+
+   return 0;
+}
+
+static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
+{
+   struct rtw_lps_conf *conf = >lps_conf;
+
+   conf->state = RTW_ALL_ON;
+   conf->awake_interval = 1;
+   conf->rlbm = 0;
+   conf->smart_ps = 0;
+
+   rtw_fw_set_pwr_mode(rtwdev);
+   rtw_flag_clear(rtwdev, RTW_FLAG_LEISURE_PS);
+}
+
+static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
+{
+   struct rtw_lps_conf *conf = >lps_conf;
+
+   conf->state = RTW_RF_OFF;
+   conf->awake_interval = 1;
+   conf->rlbm = 1;
+   conf->smart_ps = 2;
+
+   rtw_fw_set_pwr_mode(rtwdev);
+   rtw_flag_set(rtwdev, RTW_FLAG_LEISURE_PS);
+}
+
+void rtw_lps_work(struct work_struct *work)
+{
+   struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
+ lps_work.work);
+   struct rtw_lps_conf *conf = >lps_conf;
+   struct rtw_vif *rtwvif = conf->rtwvif;
+
+   if (WARN_ON(!rtwvif))
+   return;
+
+   if (conf->mode == RTW_MODE_LPS)
+   rtw_enter_lps_core(rtwdev);
+   else
+   rtw_leave_lps_core(rtwdev);
+}
+
+void rtw_enter_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
+{
+   struct rtw_lps_conf *conf = >lps_conf;
+
+   if (rtwvif->in_lps)
+   return;
+
+   conf->mode = RTW_MODE_LPS;
+   conf->rtwvif = rtwvif;
+   rtwvif->in_lps = true;
+
+   ieee80211_queue_delayed_work(rtwdev->hw, >lps_work, 0);
+}
+
+void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
+{
+   struct rtw_lps_conf *conf = >lps_conf;
+
+   if (!rtwvif->in_lps)
+   return;
+
+   conf->mode = RTW_MODE_ACTIVE;
+   conf->rtwvif = rtwvif;
+   rtwvif->in_lps = false;
+
+   ieee80211_queue_delayed_work(rtwdev->hw, >lps_work, 0);
+}
+
+bool rtw_in_lps(struct rtw_dev *rtwdev)
+{
+   return rtw_flag_check(rtwdev, RTW_FLAG_LEISURE_PS);
+}
+
+void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
+{
+   struct rtw_lps_conf *conf = >lps_conf;
+
+   if (WARN_ON(!rtwvif))
+   return;
+
+   if (rtwvif->in_lps)
+   return;
+
+   conf->mode = RTW_MODE_LPS;
+   conf->rtwvif = rtwvif;
+   rtwvif->in_lps = true;
+
+   rtw_enter_lps_core(rtwdev);
+}
+
+void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
+{
+   struct rtw_lps_conf *conf = >lps_conf;
+
+   if (WARN_ON(!rtwvif))
+   return;
+
+   if (!rtwvif->in_lps)
+   return;
+
+   conf->mode = RTW_MODE_ACTIVE;
+   conf->rtwvif = rtwvif;
+   rtwvif->in_lps = false;
+

[RFC v5 05/13] rtw88: mac files

2018-10-31 Thread yhchuang
From: Yan-Hsuan Chuang 

mac files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang 
---
 drivers/net/wireless/realtek/rtw88/mac.c | 1010 ++
 drivers/net/wireless/realtek/rtw88/mac.h |   35 ++
 2 files changed, 1045 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtw88/mac.c
 create mode 100644 drivers/net/wireless/realtek/rtw88/mac.h

diff --git a/drivers/net/wireless/realtek/rtw88/mac.c 
b/drivers/net/wireless/realtek/rtw88/mac.c
new file mode 100644
index 000..126e489
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/mac.c
@@ -0,0 +1,1010 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "mac.h"
+#include "reg.h"
+#include "fw.h"
+#include "debug.h"
+
+void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw,
+u8 primary_ch_idx)
+{
+   u8 txsc40 = 0, txsc20 = 0;
+   u32 value32;
+   u8 value8;
+
+   txsc20 = primary_ch_idx;
+   if (txsc20 == 1 || txsc20 == 3)
+   txsc40 = 9;
+   else
+   txsc40 = 10;
+   rtw_write8(rtwdev, REG_DATA_SC,
+  BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40));
+
+   value32 = rtw_read32(rtwdev, REG_WMAC_TRXPTCL_CTL);
+   value32 &= ~BIT_RFMOD;
+   switch (bw) {
+   case RTW_CHANNEL_WIDTH_80:
+   value32 |= BIT_RFMOD_80M;
+   break;
+   case RTW_CHANNEL_WIDTH_40:
+   value32 |= BIT_RFMOD_40M;
+   break;
+   case RTW_CHANNEL_WIDTH_20:
+   default:
+   break;
+   }
+   rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32);
+
+   value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL);
+   value32 |= (MAC_CLK_HW_DEF_80M << BIT_SHIFT_MAC_CLK_SEL);
+   rtw_write32(rtwdev, REG_AFE_CTRL1, value32);
+
+   rtw_write8(rtwdev, REG_USTIME_TSF, MAC_CLK_SPEED);
+   rtw_write8(rtwdev, REG_USTIME_EDCA, MAC_CLK_SPEED);
+
+   value8 = rtw_read8(rtwdev, REG_CCK_CHECK);
+   value8 = value8 & ~BIT_CHECK_CCK_EN;
+   if (channel > 35)
+   value8 |= BIT_CHECK_CCK_EN;
+   rtw_write8(rtwdev, REG_CCK_CHECK, value8);
+}
+
+static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev)
+{
+   u32 value32;
+   u8 value8;
+
+   rtw_write8(rtwdev, REG_RSV_CTRL, 0);
+
+   switch (rtw_hci_type(rtwdev)) {
+   case RTW_HCI_TYPE_PCIE:
+   rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_BT_DIG_CLK_EN);
+   break;
+   case RTW_HCI_TYPE_USB:
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   /* config PIN Mux */
+   value32 = rtw_read32(rtwdev, REG_PAD_CTRL1);
+   value32 |= BIT_PAPE_WLBT_SEL | BIT_LNAON_WLBT_SEL;
+   rtw_write32(rtwdev, REG_PAD_CTRL1, value32);
+
+   value32 = rtw_read32(rtwdev, REG_LED_CFG);
+   value32 &= ~(BIT_PAPE_SEL_EN | BIT_LNAON_SEL_EN);
+   rtw_write32(rtwdev, REG_LED_CFG, value32);
+
+   value32 = rtw_read32(rtwdev, REG_GPIO_MUXCFG);
+   value32 |= BIT_WLRFE_4_5_EN;
+   rtw_write32(rtwdev, REG_GPIO_MUXCFG, value32);
+
+   /* disable BB/RF */
+   value8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
+   value8 &= ~(BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST);
+   rtw_write8(rtwdev, REG_SYS_FUNC_EN, value8);
+
+   value8 = rtw_read8(rtwdev, REG_RF_CTRL);
+   value8 &= ~(BIT_RF_SDM_RSTB | BIT_RF_RSTB | BIT_RF_EN);
+   rtw_write8(rtwdev, REG_RF_CTRL, value8);
+
+   value32 = rtw_read32(rtwdev, REG_WLRF1);
+   value32 &= ~BIT_WLRF1_BBRF_EN;
+   rtw_write32(rtwdev, REG_WLRF1, value32);
+
+   return 0;
+}
+
+static int rtw_pwr_cmd_polling(struct rtw_dev *rtwdev,
+  struct rtw_pwr_seq_cmd *cmd)
+{
+   u8 value;
+   u8 flag = 0;
+   u32 offset;
+   u32 cnt = RTW_PWR_POLLING_CNT;
+
+   if (cmd->base == RTW_PWR_ADDR_SDIO)
+   offset = cmd->offset | SDIO_LOCAL_OFFSET;
+   else
+   offset = cmd->offset;
+
+   do {
+   cnt--;
+   value = rtw_read8(rtwdev, offset);
+   value &= cmd->mask;
+   if (value == (cmd->value & cmd->mask))
+   return 0;
+   if (cnt == 0) {
+   if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE &&
+   flag == 0) {
+   value = rtw_read8(rtwdev, REG_SYS_PW_CTRL);
+   value |= BIT(3);
+   rtw_write8(rtwdev, REG_SYS_PW_CTRL, value);
+   value &= ~BIT(3);
+   rtw_write8(rtwdev, REG_SYS_PW_CTRL, value);
+   cnt = RTW_PWR_POLLING_CNT;
+   flag = 1;
+   } else {
+   return -EBUSY;
+   }
+   

Re: [PATCH] mt76x0: do not overwrite other MT_BBP(AGC, 8) fields

2018-10-31 Thread Lorenzo Bianconi
> MT_BBP(AGC, 8) register has values depend on band in
> mt76x0_bbp_switch_tab, so we should not overwrite other fields
> than MT_BBP_AGC_GAIN when setting gain.
> 
> This can fix performance issues when connecting to 2.4GHz AP.
> 
> Fixes: 4636a2544c3b ("mt76x0: phy: align channel gain logic to mt76x2 one")
> Signed-off-by: Stanislaw Gruszka 
> ---
>  drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c 
> b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
> index ba98814ae47d..88dd0aa7e877 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
> @@ -690,10 +690,8 @@ static void mt76x0_phy_temp_sensor(struct mt76x02_dev 
> *dev)
>  static void mt76x0_phy_set_gain_val(struct mt76x02_dev *dev)
>  {
>   u8 gain = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust;
> - u32 val = 0x122c << 16 | 0xf2;
>  
> - mt76_wr(dev, MT_BBP(AGC, 8),
> - val | FIELD_PREP(MT_BBP_AGC_GAIN, gain));
> + mt76_rmw_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN, gain);
>  
>   if ((dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) &&
>   !is_mt7630(dev))
> -- 
> 2.7.5
> 

Acked-by: Lorenzo Bianconi 


[PATCH 02/16] wil6210: fix reset flow for Talyn-mb

2018-10-31 Thread Maya Erez
From: Alexei Avshalom Lazar 

With current reset flow, Talyn sometimes get stuck causing PCIe
enumeration to fail. Fix this by removing some reset flow operations
that are not relevant for Talyn.
Setting bit 15 in RGF_HP_CTRL is WBE specific and is not in use for
all wil6210 devices.
For Sparrow, BIT_HPAL_PERST_FROM_PAD and BIT_CAR_PERST_RST were set
as a WA an HW issue.

Signed-off-by: Alexei Avshalom Lazar 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/main.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c 
b/drivers/net/wireless/ath/wil6210/main.c
index 398900a..c54b008 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -998,10 +998,13 @@ static int wil_target_reset(struct wil6210_priv *wil, int 
no_flash)
 
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
 
-   /* Clear MAC link up */
-   wil_s(wil, RGF_HP_CTRL, BIT(15));
-   wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
-   wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
+   if (wil->hw_version < HW_VER_TALYN) {
+   /* Clear MAC link up */
+   wil_s(wil, RGF_HP_CTRL, BIT(15));
+   wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0,
+ BIT_HPAL_PERST_FROM_PAD);
+   wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
+   }
 
wil_halt_cpu(wil);
 
-- 
1.9.1



[PATCH 15/16] wil6210: fix freeing of rx buffers in EDMA mode

2018-10-31 Thread Maya Erez
From: Ahmad Masri 

After being associated with some EDMA rx traffic, upon "down" driver
doesn't free all skbs in the rx ring.
Modify wil_move_all_rx_buff_to_free_list to loop on active list of rx
buffers, unmap the physical memory and free the skb.

Signed-off-by: Ahmad Masri 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/txrx_edma.c | 44 +---
 1 file changed, 14 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c 
b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index 686ba34..05a8348 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -234,9 +234,10 @@ static int wil_rx_refill_edma(struct wil6210_priv *wil)
struct wil_ring *ring = >ring_rx;
u32 next_head;
int rc = 0;
-   u32 swtail = *ring->edma_rx_swtail.va;
+   ring->swtail = *ring->edma_rx_swtail.va;
 
-   for (; next_head = wil_ring_next_head(ring), (next_head != swtail);
+   for (; next_head = wil_ring_next_head(ring),
+(next_head != ring->swtail);
 ring->swhead = next_head) {
rc = wil_ring_alloc_skb_edma(wil, ring, ring->swhead);
if (unlikely(rc)) {
@@ -264,43 +265,26 @@ static void wil_move_all_rx_buff_to_free_list(struct 
wil6210_priv *wil,
  struct wil_ring *ring)
 {
struct device *dev = wil_to_dev(wil);
-   u32 next_tail;
-   u32 swhead = (ring->swhead + 1) % ring->size;
+   struct list_head *active = >rx_buff_mgmt.active;
dma_addr_t pa;
-   u16 dmalen;
 
-   for (; next_tail = wil_ring_next_tail(ring), (next_tail != swhead);
-ring->swtail = next_tail) {
-   struct wil_rx_enhanced_desc dd, *d = 
-   struct wil_rx_enhanced_desc *_d =
-   (struct wil_rx_enhanced_desc *)
-   >va[ring->swtail].rx.enhanced;
-   struct sk_buff *skb;
-   u16 buff_id;
+   while (!list_empty(active)) {
+   struct wil_rx_buff *rx_buff =
+   list_first_entry(active, struct wil_rx_buff, list);
+   struct sk_buff *skb = rx_buff->skb;
 
-   *d = *_d;
-
-   /* Extract the SKB from the rx_buff management array */
-   buff_id = __le16_to_cpu(d->mac.buff_id);
-   if (buff_id >= wil->rx_buff_mgmt.size) {
-   wil_err(wil, "invalid buff_id %d\n", buff_id);
-   continue;
-   }
-   skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
-   wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
if (unlikely(!skb)) {
-   wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
+   wil_err(wil, "No Rx skb at buff_id %d\n", rx_buff->id);
} else {
-   pa = wil_rx_desc_get_addr_edma(>dma);
-   dmalen = le16_to_cpu(d->dma.length);
-   dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
-
+   rx_buff->skb = NULL;
+   memcpy(, skb->cb, sizeof(pa));
+   dma_unmap_single(dev, pa, wil->rx_buf_len,
+DMA_FROM_DEVICE);
kfree_skb(skb);
}
 
/* Move the buffer from the active to the free list */
-   list_move(>rx_buff_mgmt.buff_arr[buff_id].list,
- >rx_buff_mgmt.free);
+   list_move(_buff->list, >rx_buff_mgmt.free);
}
 }
 
-- 
1.9.1



[PATCH 05/16] wil6210: add recovery for FW error while in AP mode

2018-10-31 Thread Maya Erez
From: Dedy Lansky 

AP configuration is stored by the driver. Upon FW error, disconnect
notification is sent to user space for any associated stations. AP is
then internally restarted with the stored configuration.

Signed-off-by: Dedy Lansky 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/cfg80211.c | 102 ++--
 drivers/net/wireless/ath/wil6210/main.c |  17 -
 drivers/net/wireless/ath/wil6210/wil6210.h  |   9 +++
 3 files changed, 120 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c 
b/drivers/net/wireless/ath/wil6210/cfg80211.c
index d18e81f..e9135d6 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -51,6 +51,19 @@
CHAN60G(4, 0),
 };
 
+static void
+wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len)
+{
+   kfree(*pdst);
+   *pdst = NULL;
+   *pdst_len = 0;
+   if (src_len > 0) {
+   *pdst = kmemdup(src, src_len, GFP_KERNEL);
+   if (*pdst)
+   *pdst_len = src_len;
+   }
+}
+
 static int wil_num_supported_channels(struct wil6210_priv *wil)
 {
int num_channels = ARRAY_SIZE(wil_60ghz_channels);
@@ -1441,11 +1454,19 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
 
rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
params->key, key_usage);
-   if (!rc && !IS_ERR(cs))
+   if (!rc && !IS_ERR(cs)) {
+   /* update local storage used for AP recovery */
+   if (key_usage == WMI_KEY_USE_TX_GROUP && params->key &&
+   params->key_len <= WMI_MAX_KEY_LEN) {
+   vif->gtk_index = key_index;
+   memcpy(vif->gtk, params->key, params->key_len);
+   vif->gtk_len = params->key_len;
+   }
/* in FT set crypto will take place upon receiving
 * WMI_RING_EN_EVENTID event
 */
wil_set_crypto_rx(key_index, key_usage, cs, params);
+   }
 
return rc;
 }
@@ -1634,6 +1655,14 @@ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
u16 len = 0, proberesp_len = 0;
u8 *ies = NULL, *proberesp;
 
+   /* update local storage used for AP recovery */
+   wil_memdup_ie(>proberesp, >proberesp_len, bcon->probe_resp,
+ bcon->probe_resp_len);
+   wil_memdup_ie(>proberesp_ies, >proberesp_ies_len,
+ bcon->proberesp_ies, bcon->proberesp_ies_len);
+   wil_memdup_ie(>assocresp_ies, >assocresp_ies_len,
+ bcon->assocresp_ies, bcon->assocresp_ies_len);
+
proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
bcon->probe_resp_len,
_len);
@@ -1735,6 +1764,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
vif->channel = chan;
vif->hidden_ssid = hidden_ssid;
vif->pbss = pbss;
+   vif->bi = bi;
+   memcpy(vif->ssid, ssid, ssid_len);
+   vif->ssid_len = ssid_len;
 
netif_carrier_on(ndev);
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
@@ -1761,11 +1793,64 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
return rc;
 }
 
+void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
+{
+   int rc, i;
+   struct wiphy *wiphy = wil_to_wiphy(wil);
+
+   for (i = 0; i < wil->max_vifs; i++) {
+   struct wil6210_vif *vif = wil->vifs[i];
+   struct net_device *ndev;
+   struct cfg80211_beacon_data bcon = {};
+   struct key_params key_params = {};
+
+   if (!vif || vif->ssid_len == 0)
+   continue;
+
+   ndev = vif_to_ndev(vif);
+   bcon.proberesp_ies = vif->proberesp_ies;
+   bcon.assocresp_ies = vif->assocresp_ies;
+   bcon.probe_resp = vif->proberesp;
+   bcon.proberesp_ies_len = vif->proberesp_ies_len;
+   bcon.assocresp_ies_len = vif->assocresp_ies_len;
+   bcon.probe_resp_len = vif->proberesp_len;
+
+   wil_info(wil,
+"AP (vif %d) recovery: privacy %d, bi %d, channel %d, 
hidden %d, pbss %d\n",
+i, vif->privacy, vif->bi, vif->channel,
+vif->hidden_ssid, vif->pbss);
+   wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
+ vif->ssid, vif->ssid_len, true);
+   rc = _wil_cfg80211_start_ap(wiphy, ndev,
+   vif->ssid, vif->ssid_len,
+   vif->privacy, vif->bi,
+   vif->channel, ,
+   vif->hidden_ssid, 

[PATCH 16/16] wil6210: fix locking in wmi_call

2018-10-31 Thread Maya Erez
From: Lior David 

Switch from spin_lock to spin_lock_irqsave, because
wmi_ev_lock is used inside interrupt handler.

Signed-off-by: Lior David 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/wmi.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/wmi.c 
b/drivers/net/wireless/ath/wil6210/wmi.c
index f46c703..345f059 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1966,16 +1966,17 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 
mid, void *buf, u16 len,
 {
int rc;
unsigned long remain;
+   ulong flags;
 
mutex_lock(>wmi_mutex);
 
-   spin_lock(>wmi_ev_lock);
+   spin_lock_irqsave(>wmi_ev_lock, flags);
wil->reply_id = reply_id;
wil->reply_mid = mid;
wil->reply_buf = reply;
wil->reply_size = reply_size;
reinit_completion(>wmi_call);
-   spin_unlock(>wmi_ev_lock);
+   spin_unlock_irqrestore(>wmi_ev_lock, flags);
 
rc = __wmi_send(wil, cmdid, mid, buf, len);
if (rc)
@@ -1995,12 +1996,12 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 
mid, void *buf, u16 len,
}
 
 out:
-   spin_lock(>wmi_ev_lock);
+   spin_lock_irqsave(>wmi_ev_lock, flags);
wil->reply_id = 0;
wil->reply_mid = U8_MAX;
wil->reply_buf = NULL;
wil->reply_size = 0;
-   spin_unlock(>wmi_ev_lock);
+   spin_unlock_irqrestore(>wmi_ev_lock, flags);
 
mutex_unlock(>wmi_mutex);
 
-- 
1.9.1



[PATCH 01/16] wil6210: remove fake support for RXHASH

2018-10-31 Thread Maya Erez
From: Hamad Kadmany 

Setting the same fake hash to all skbs prevents
distributing different flows to different CPU cores.

Signed-off-by: Hamad Kadmany 
Signed-off-by: Lior David 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/netdev.c | 3 +--
 drivers/net/wireless/ath/wil6210/txrx.c   | 8 
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/netdev.c 
b/drivers/net/wireless/ath/wil6210/netdev.c
index 7a78a06..64fa1a2 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -345,8 +345,7 @@ struct wil6210_vif *
ndev->ieee80211_ptr = wdev;
ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
NETIF_F_SG | NETIF_F_GRO |
-   NETIF_F_TSO | NETIF_F_TSO6 |
-   NETIF_F_RXHASH;
+   NETIF_F_TSO | NETIF_F_TSO6;
 
ndev->features |= ndev->hw_features;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c 
b/drivers/net/wireless/ath/wil6210/txrx.c
index cc5f263..70eceec 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -743,14 +743,6 @@ void wil_netif_rx_any(struct sk_buff *skb, struct 
net_device *ndev)
 
stats = >sta[cid].stats;
 
-   if (ndev->features & NETIF_F_RXHASH)
-   /* fake L4 to ensure it won't be re-calculated later
-* set hash to any non-zero value to activate rps
-* mechanism, core will be chosen according
-* to user-level rps configuration.
-*/
-   skb_set_hash(skb, 1, PKT_HASH_TYPE_L4);
-
skb_orphan(skb);
 
if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) {
-- 
1.9.1



[PATCH 00/16] wil6210 patches

2018-10-31 Thread Maya Erez
The following set of patches include various wil6210 fixes.

Ahmad Masri (5):
  wil6210: refactor disconnect flow
  wil6210: notify cqm packet loss on disable_ap_sme
  wil6210: fix debugfs memory access alignment
  wil6210: remove unnecessary alignment code from rx flow
  wil6210: fix freeing of rx buffers in EDMA mode

Alexei Avshalom Lazar (2):
  wil6210: fix reset flow for Talyn-mb
  wil6210: add general initialization/size checks

Dedy Lansky (2):
  wil6210: make sure Rx ring sizes are correlated
  wil6210: add recovery for FW error while in AP mode

Hamad Kadmany (1):
  wil6210: remove fake support for RXHASH

Lior David (2):
  wil6210: fix memory leak in wil_find_tx_bcast_2
  wil6210: fix locking in wmi_call

Maya Erez (4):
  wil6210: increase RX rings and RX buff array size
  wil6210: fix L2 RX status handling
  wil6210: fix RGF_CAF_ICR address for Talyn-MB
  wil6210: ignore HALP ICR if already handled

 drivers/net/wireless/ath/wil6210/cfg80211.c  | 104 +++-
 drivers/net/wireless/ath/wil6210/debugfs.c   |  17 +-
 drivers/net/wireless/ath/wil6210/interrupt.c |  10 +-
 drivers/net/wireless/ath/wil6210/main.c  | 230 ---
 drivers/net/wireless/ath/wil6210/netdev.c|   5 +-
 drivers/net/wireless/ath/wil6210/txrx.c  |  14 +-
 drivers/net/wireless/ath/wil6210/txrx_edma.c |  92 +--
 drivers/net/wireless/ath/wil6210/txrx_edma.h |   4 +-
 drivers/net/wireless/ath/wil6210/wil6210.h   |  22 ++-
 drivers/net/wireless/ath/wil6210/wmi.c   |  56 ---
 10 files changed, 386 insertions(+), 168 deletions(-)

-- 
1.9.1



[PATCH 10/16] wil6210: fix debugfs memory access alignment

2018-10-31 Thread Maya Erez
From: Ahmad Masri 

All wil6210 device memory access should be 4 bytes aligned. In io
blob wil6210 did not force alignment for read function, this caused
alignment fault on some platforms.
Fixing that by accessing all 4 lower bytes and return to host the
requested data.

Signed-off-by: Ahmad Masri 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/debugfs.c | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c 
b/drivers/net/wireless/ath/wil6210/debugfs.c
index 099a04b..20dd4d0 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -664,10 +664,10 @@ static ssize_t wil_read_file_ioblob(struct file *file, 
char __user *user_buf,
enum { max_count = 4096 };
struct wil_blob_wrapper *wil_blob = file->private_data;
struct wil6210_priv *wil = wil_blob->wil;
-   loff_t pos = *ppos;
+   loff_t aligned_pos, pos = *ppos;
size_t available = wil_blob->blob.size;
void *buf;
-   size_t ret;
+   size_t unaligned_bytes, aligned_count, ret;
int rc;
 
if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
@@ -685,7 +685,12 @@ static ssize_t wil_read_file_ioblob(struct file *file, 
char __user *user_buf,
if (count > max_count)
count = max_count;
 
-   buf = kmalloc(count, GFP_KERNEL);
+   /* set pos to 4 bytes aligned */
+   unaligned_bytes = pos % 4;
+   aligned_pos = pos - unaligned_bytes;
+   aligned_count = count + unaligned_bytes;
+
+   buf = kmalloc(aligned_count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
 
@@ -696,9 +701,9 @@ static ssize_t wil_read_file_ioblob(struct file *file, char 
__user *user_buf,
}
 
wil_memcpy_fromio_32(buf, (const void __iomem *)
-wil_blob->blob.data + pos, count);
+wil_blob->blob.data + aligned_pos, aligned_count);
 
-   ret = copy_to_user(user_buf, buf, count);
+   ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
 
wil_pm_runtime_put(wil);
 
-- 
1.9.1



[PATCH 03/16] wil6210: increase RX rings and RX buff array size

2018-10-31 Thread Maya Erez
In Talyn-MB, the 11ad throughput is higher and performance drops
may occur in the current RX configuration due to unavailability
of Rx buffers.
Increase the RX descriptor ring, RX status ring and number of RX
buffers to stabilize the performance in high throughput.

Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/main.c  | 7 ++-
 drivers/net/wireless/ath/wil6210/txrx_edma.c | 4 ++--
 drivers/net/wireless/ath/wil6210/txrx_edma.h | 4 ++--
 drivers/net/wireless/ath/wil6210/wil6210.h   | 1 +
 4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c 
b/drivers/net/wireless/ath/wil6210/main.c
index c54b008..078ad5cf 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -80,7 +80,7 @@ static int mtu_max_set(const char *val, const struct 
kernel_param *kp)
 module_param_cb(mtu_max, _max_ops, _max, 0444);
 MODULE_PARM_DESC(mtu_max, " Max MTU value.");
 
-static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
+static uint rx_ring_order;
 static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
 static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
 
@@ -1684,6 +1684,11 @@ int __wil_up(struct wil6210_priv *wil)
return rc;
 
/* Rx RING. After MAC and beacon */
+   if (rx_ring_order == 0)
+   rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ?
+   WIL_RX_RING_SIZE_ORDER_DEFAULT :
+   WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT;
+
rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order);
if (rc)
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c 
b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index 2bbae75..ce71358 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -357,8 +357,8 @@ static int wil_init_rx_sring(struct wil6210_priv *wil,
struct wil_status_ring *sring = >srings[ring_id];
int rc;
 
-   wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", sring->size,
-ring_id);
+   wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n",
+status_ring_size, ring_id);
 
memset(>rx_data, 0, sizeof(sring->rx_data));
 
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h 
b/drivers/net/wireless/ath/wil6210/txrx_edma.h
index a7fe929..343516a 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.h
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h
@@ -23,9 +23,9 @@
 #define WIL_SRING_SIZE_ORDER_MIN   (WIL_RING_SIZE_ORDER_MIN)
 #define WIL_SRING_SIZE_ORDER_MAX   (WIL_RING_SIZE_ORDER_MAX)
 /* RX sring order should be bigger than RX ring order */
-#define WIL_RX_SRING_SIZE_ORDER_DEFAULT(11)
+#define WIL_RX_SRING_SIZE_ORDER_DEFAULT(12)
 #define WIL_TX_SRING_SIZE_ORDER_DEFAULT(12)
-#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (1536)
+#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (2600)
 
 #define WIL_DEFAULT_RX_STATUS_RING_ID 0
 #define WIL_RX_DESC_RING_ID 0
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h 
b/drivers/net/wireless/ath/wil6210/wil6210.h
index abb8201..414de54 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -81,6 +81,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
 
 #define WIL_TX_Q_LEN_DEFAULT   (4000)
 #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
+#define WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT   (11)
 #define WIL_TX_RING_SIZE_ORDER_DEFAULT (12)
 #define WIL_BCAST_RING_SIZE_ORDER_DEFAULT  (7)
 #define WIL_BCAST_MCS0_LIMIT   (1024) /* limit for MCS0 frame size */
-- 
1.9.1



[PATCH 04/16] wil6210: make sure Rx ring sizes are correlated

2018-10-31 Thread Maya Erez
From: Dedy Lansky 

When enlarging rx_ring_order module param, wil6210 fails to load
because there are not enough Rx buffers.
Fix this by enlarging number of Rx buffers at startup, if needed based
on rx_ring_order.

Signed-off-by: Dedy Lansky 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/main.c  |  2 +-
 drivers/net/wireless/ath/wil6210/txrx.c  |  4 ++--
 drivers/net/wireless/ath/wil6210/txrx_edma.c | 11 ---
 drivers/net/wireless/ath/wil6210/wil6210.h   |  2 +-
 4 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c 
b/drivers/net/wireless/ath/wil6210/main.c
index 078ad5cf..55084770 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1689,7 +1689,7 @@ int __wil_up(struct wil6210_priv *wil)
WIL_RX_RING_SIZE_ORDER_DEFAULT :
WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT;
 
-   rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order);
+   rc = wil->txrx_ops.rx_init(wil, rx_ring_order);
if (rc)
return rc;
 
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c 
b/drivers/net/wireless/ath/wil6210/txrx.c
index 70eceec..c592c8e 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -872,7 +872,7 @@ static void wil_rx_buf_len_init(struct wil6210_priv *wil)
}
 }
 
-static int wil_rx_init(struct wil6210_priv *wil, u16 size)
+static int wil_rx_init(struct wil6210_priv *wil, uint order)
 {
struct wil_ring *vring = >ring_rx;
int rc;
@@ -886,7 +886,7 @@ static int wil_rx_init(struct wil6210_priv *wil, u16 size)
 
wil_rx_buf_len_init(wil);
 
-   vring->size = size;
+   vring->size = 1 << order;
vring->is_rx = true;
rc = wil_vring_alloc(wil, vring);
if (rc)
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c 
b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index ce71358..fe758f2 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -606,9 +606,9 @@ static void wil_rx_buf_len_init_edma(struct wil6210_priv 
*wil)
WIL_MAX_ETH_MTU : WIL_EDMA_RX_BUF_LEN_DEFAULT;
 }
 
-static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size)
+static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order)
 {
-   u16 status_ring_size;
+   u16 status_ring_size, desc_ring_size = 1 << desc_ring_order;
struct wil_ring *ring = >ring_rx;
int rc;
size_t elem_size = wil->use_compressed_rx_status ?
@@ -623,7 +623,12 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 
desc_ring_size)
"compressed RX status cannot be used with SW 
reorder\n");
return -EINVAL;
}
-
+   if (wil->rx_status_ring_order <= desc_ring_order)
+   /* make sure sring is larger than desc ring */
+   wil->rx_status_ring_order = desc_ring_order + 1;
+   if (wil->rx_buff_id_count <= desc_ring_size)
+   /* make sure we will not run out of buff_ids */
+   wil->rx_buff_id_count = desc_ring_size + 512;
if (wil->rx_status_ring_order < WIL_SRING_SIZE_ORDER_MIN ||
wil->rx_status_ring_order > WIL_SRING_SIZE_ORDER_MAX)
wil->rx_status_ring_order = WIL_RX_SRING_SIZE_ORDER_DEFAULT;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h 
b/drivers/net/wireless/ath/wil6210/wil6210.h
index 414de54..31753f94 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -614,7 +614,7 @@ struct wil_txrx_ops {
  int cid, int tid);
irqreturn_t (*irq_tx)(int irq, void *cookie);
/* RX ops */
-   int (*rx_init)(struct wil6210_priv *wil, u16 ring_size);
+   int (*rx_init)(struct wil6210_priv *wil, uint ring_order);
void (*rx_fini)(struct wil6210_priv *wil);
int (*wmi_addba_rx_resp)(struct wil6210_priv *wil, u8 mid, u8 cid,
 u8 tid, u8 token, u16 status, bool amsdu,
-- 
1.9.1



[PATCH 14/16] wil6210: remove unnecessary alignment code from rx flow

2018-10-31 Thread Maya Erez
From: Ahmad Masri 

Rx buffers in EDMA mode are initialized to 4 bytes aligned size.
Remove the unnecessary alignment code applied on rx buffer size.

Signed-off-by: Ahmad Masri 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/txrx_edma.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c 
b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index c8490e7..686ba34 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -160,7 +160,7 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
   struct wil_ring *ring, u32 i)
 {
struct device *dev = wil_to_dev(wil);
-   unsigned int sz = ALIGN(wil->rx_buf_len, 4);
+   unsigned int sz = wil->rx_buf_len;
dma_addr_t pa;
u16 buff_id;
struct list_head *active = >rx_buff_mgmt.active;
@@ -602,6 +602,7 @@ static bool wil_is_rx_idle_edma(struct wil6210_priv *wil)
 
 static void wil_rx_buf_len_init_edma(struct wil6210_priv *wil)
 {
+   /* RX buffer size must be aligned to 4 bytes */
wil->rx_buf_len = rx_large_buf ?
WIL_MAX_ETH_MTU : WIL_EDMA_RX_BUF_LEN_DEFAULT;
 }
@@ -615,7 +616,6 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint 
desc_ring_order)
sizeof(struct wil_rx_status_compressed) :
sizeof(struct wil_rx_status_extended);
int i;
-   u16 max_rx_pl_per_desc;
 
/* In SW reorder one must use extended status messages */
if (wil->use_compressed_rx_status && !wil->use_rx_hw_reordering) {
@@ -641,8 +641,6 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint 
desc_ring_order)
 
wil_rx_buf_len_init_edma(wil);
 
-   max_rx_pl_per_desc = ALIGN(wil->rx_buf_len, 4);
-
/* Use debugfs dbg_num_rx_srings if set, reserve one sring for TX */
if (wil->num_rx_status_rings > WIL6210_MAX_STATUS_RINGS - 1)
wil->num_rx_status_rings = WIL6210_MAX_STATUS_RINGS - 1;
@@ -650,7 +648,7 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint 
desc_ring_order)
wil_dbg_misc(wil, "rx_init: allocate %d status rings\n",
 wil->num_rx_status_rings);
 
-   rc = wil_wmi_cfg_def_rx_offload(wil, max_rx_pl_per_desc);
+   rc = wil_wmi_cfg_def_rx_offload(wil, wil->rx_buf_len);
if (rc)
return rc;
 
@@ -887,7 +885,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct 
wil6210_priv *wil,
struct sk_buff *skb;
dma_addr_t pa;
struct wil_ring_rx_data *rxdata = >rx_data;
-   unsigned int sz = ALIGN(wil->rx_buf_len, 4);
+   unsigned int sz = wil->rx_buf_len;
struct wil_net_stats *stats = NULL;
u16 dmalen;
int cid;
-- 
1.9.1



[PATCH 12/16] wil6210: fix RGF_CAF_ICR address for Talyn-MB

2018-10-31 Thread Maya Erez
RGF_CAF_ICR register location has changed in Talyn-MB.
Add RGF_CAF_ICR_TALYN_MB to support the new address.

Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/main.c| 11 +--
 drivers/net/wireless/ath/wil6210/wil6210.h |  1 +
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/main.c 
b/drivers/net/wireless/ath/wil6210/main.c
index 9dd068d..5303867 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1500,8 +1500,15 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
wil6210_clear_irq(wil);
/* CAF_ICR - clear and mask */
/* it is W1C, clear by writing back same value */
-   wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
-   wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
+   if (wil->hw_version < HW_VER_TALYN_MB) {
+   wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
+   wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
+   } else {
+   wil_s(wil,
+ RGF_CAF_ICR_TALYN_MB + offsetof(struct RGF_ICR, ICR), 0);
+   wil_w(wil, RGF_CAF_ICR_TALYN_MB +
+ offsetof(struct RGF_ICR, IMV), ~0);
+   }
/* clear PAL_UNIT_ICR (potential D0->D3 leftover)
 * In Talyn-MB host cannot access this register due to
 * access control, hence PAL_UNIT_ICR is cleared by the FW
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h 
b/drivers/net/wireless/ath/wil6210/wil6210.h
index ad7003f..0f3be3ff 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -320,6 +320,7 @@ struct RGF_ICR {
 /* MAC timer, usec, for packet lifetime */
 #define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
 
+#define RGF_CAF_ICR_TALYN_MB   (0x8893d4) /* struct RGF_ICR */
 #define RGF_CAF_ICR(0x88946c) /* struct RGF_ICR */
 #define RGF_CAF_OSC_CONTROL(0x88afa4)
#define BIT_CAF_OSC_XTAL_EN BIT(0)
-- 
1.9.1



[PATCH 08/16] wil6210: notify cqm packet loss on disable_ap_sme

2018-10-31 Thread Maya Erez
From: Ahmad Masri 

wil6210 used to notify cfg80211_del_sta on every fw disconnect event.
In disable_ap_sme mode the userspace manages the protocol SME and
FW sends disconnect event only due to link loss.

In disable_ap_sme mode, indicate CQM packet loss to let the host
control the connection and disconnect the link if needed.

Signed-off-by: Ahmad Masri 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/wmi.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/net/wireless/ath/wil6210/wmi.c 
b/drivers/net/wireless/ath/wil6210/wmi.c
index 5ff1862..fa08a96 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1113,6 +1113,23 @@ static void wmi_evt_disconnect(struct wil6210_vif *vif, 
int id,
 
mutex_lock(>mutex);
wil6210_disconnect_complete(vif, evt->bssid, reason_code);
+   if (disable_ap_sme) {
+   struct wireless_dev *wdev = vif_to_wdev(vif);
+   struct net_device *ndev = vif_to_ndev(vif);
+
+   /* disconnect event in disable_ap_sme mode means link loss */
+   switch (wdev->iftype) {
+   /* AP-like interface */
+   case NL80211_IFTYPE_AP:
+   case NL80211_IFTYPE_P2P_GO:
+   /* notify hostapd about link loss */
+   cfg80211_cqm_pktloss_notify(ndev, evt->bssid, 0,
+   GFP_KERNEL);
+   break;
+   default:
+   break;
+   }
+   }
mutex_unlock(>mutex);
 }
 
-- 
1.9.1



[PATCH 13/16] wil6210: ignore HALP ICR if already handled

2018-10-31 Thread Maya Erez
HALP ICR is set as long as the FW should stay awake.
To prevent its multiple handling the driver masks this IRQ bit.
However, if there is a different MISC ICR before the driver clears
this bit, there is a risk of race condition between HALP mask and
unmask. This race leads to HALP timeout, in case it is mistakenly
masked.
Add an atomic flag to indicate if HALP ICR should be handled.

Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/interrupt.c | 10 +++---
 drivers/net/wireless/ath/wil6210/main.c  |  2 ++
 drivers/net/wireless/ath/wil6210/wil6210.h   |  1 +
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c 
b/drivers/net/wireless/ath/wil6210/interrupt.c
index 5d287a8..a58fccb 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -575,10 +575,14 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
}
 
if (isr & BIT_DMA_EP_MISC_ICR_HALP) {
-   wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
-   wil6210_mask_halp(wil);
isr &= ~BIT_DMA_EP_MISC_ICR_HALP;
-   complete(>halp.comp);
+   if (atomic_read(>halp.handle_icr)) {
+   /* no need to handle HALP ICRs until next vote */
+   atomic_set(>halp.handle_icr, 0);
+   wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
+   wil6210_mask_halp(wil);
+   complete(>halp.comp);
+   }
}
 
wil->isr_misc = isr;
diff --git a/drivers/net/wireless/ath/wil6210/main.c 
b/drivers/net/wireless/ath/wil6210/main.c
index 5303867..5c89c01 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1922,6 +1922,8 @@ void wil_halp_vote(struct wil6210_priv *wil)
 
if (++wil->halp.ref_cnt == 1) {
reinit_completion(>halp.comp);
+   /* mark to IRQ context to handle HALP ICR */
+   atomic_set(>halp.handle_icr, 1);
wil6210_set_halp(wil);
rc = wait_for_completion_timeout(>halp.comp, to_jiffies);
if (!rc) {
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h 
b/drivers/net/wireless/ath/wil6210/wil6210.h
index 0f3be3ff..1897d8c 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -791,6 +791,7 @@ struct wil_halp {
struct mutexlock; /* protect halp ref_cnt */
unsigned intref_cnt;
struct completion   comp;
+   atomic_thandle_icr;
 };
 
 struct wil_blob_wrapper {
-- 
1.9.1



[PATCH 11/16] wil6210: fix L2 RX status handling

2018-10-31 Thread Maya Erez
L2 RX status errors should not be treated as a bitmap and the actual
error values should be checked.
Print L2 errors as wil_err_ratelimited for easier debugging
when such errors occurs.

Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/txrx_edma.c | 23 ---
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c 
b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index fe758f2..c8490e7 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -839,23 +839,24 @@ static int wil_rx_error_check_edma(struct wil6210_priv 
*wil,
wil_dbg_txrx(wil, "L2 RX error, l2_rx_status=0x%x\n",
 l2_rx_status);
/* Due to HW issue, KEY error will trigger a MIC error */
-   if (l2_rx_status & WIL_RX_EDMA_ERROR_MIC) {
-   wil_dbg_txrx(wil,
-"L2 MIC/KEY error, dropping packet\n");
+   if (l2_rx_status == WIL_RX_EDMA_ERROR_MIC) {
+   wil_err_ratelimited(wil,
+   "L2 MIC/KEY error, dropping 
packet\n");
stats->rx_mic_error++;
}
-   if (l2_rx_status & WIL_RX_EDMA_ERROR_KEY) {
-   wil_dbg_txrx(wil, "L2 KEY error, dropping packet\n");
+   if (l2_rx_status == WIL_RX_EDMA_ERROR_KEY) {
+   wil_err_ratelimited(wil,
+   "L2 KEY error, dropping packet\n");
stats->rx_key_error++;
}
-   if (l2_rx_status & WIL_RX_EDMA_ERROR_REPLAY) {
-   wil_dbg_txrx(wil,
-"L2 REPLAY error, dropping packet\n");
+   if (l2_rx_status == WIL_RX_EDMA_ERROR_REPLAY) {
+   wil_err_ratelimited(wil,
+   "L2 REPLAY error, dropping 
packet\n");
stats->rx_replay++;
}
-   if (l2_rx_status & WIL_RX_EDMA_ERROR_AMSDU) {
-   wil_dbg_txrx(wil,
-"L2 AMSDU error, dropping packet\n");
+   if (l2_rx_status == WIL_RX_EDMA_ERROR_AMSDU) {
+   wil_err_ratelimited(wil,
+   "L2 AMSDU error, dropping 
packet\n");
stats->rx_amsdu_error++;
}
return -EFAULT;
-- 
1.9.1



[PATCH 07/16] wil6210: refactor disconnect flow

2018-10-31 Thread Maya Erez
From: Ahmad Masri 

Separate sending command to the fw from the event handling function to
simplify the disconnect flow and track the from_event flag correctly.

Signed-off-by: Ahmad Masri 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/cfg80211.c |   2 +-
 drivers/net/wireless/ath/wil6210/main.c | 180 +---
 drivers/net/wireless/ath/wil6210/netdev.c   |   2 +-
 drivers/net/wireless/ath/wil6210/wil6210.h  |   8 +-
 drivers/net/wireless/ath/wil6210/wmi.c  |  28 ++---
 5 files changed, 148 insertions(+), 72 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c 
b/drivers/net/wireless/ath/wil6210/cfg80211.c
index e9135d6..9b2f9f5 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -2015,7 +2015,7 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
 params->mac, params->reason_code, vif->mid);
 
mutex_lock(>mutex);
-   wil6210_disconnect(vif, params->mac, params->reason_code, false);
+   wil6210_disconnect(vif, params->mac, params->reason_code);
mutex_unlock(>mutex);
 
return 0;
diff --git a/drivers/net/wireless/ath/wil6210/main.c 
b/drivers/net/wireless/ath/wil6210/main.c
index 2b328c1..9dd068d 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -215,8 +215,21 @@ static void wil_ring_fini_tx(struct wil6210_priv *wil, int 
id)
wil->txrx_ops.ring_fini_tx(wil, ring);
 }
 
-static void wil_disconnect_cid(struct wil6210_vif *vif, int cid,
-  u16 reason_code, bool from_event)
+static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
+{
+   int i;
+
+   for (i = 0; i < WIL6210_MAX_CID; i++) {
+   if (wil->sta[i].mid == mid &&
+   wil->sta[i].status == wil_sta_connected)
+   return true;
+   }
+
+   return false;
+}
+
+static void wil_disconnect_cid_complete(struct wil6210_vif *vif, int cid,
+   u16 reason_code)
 __acquires(>tid_rx_lock) __releases(>tid_rx_lock)
 {
uint i;
@@ -227,24 +240,14 @@ static void wil_disconnect_cid(struct wil6210_vif *vif, 
int cid,
int min_ring_id = wil_get_min_tx_ring_id(wil);
 
might_sleep();
-   wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
+   wil_dbg_misc(wil,
+"disconnect_cid_complete: CID %d, MID %d, status %d\n",
 cid, sta->mid, sta->status);
-   /* inform upper/lower layers */
+   /* inform upper layers */
if (sta->status != wil_sta_unused) {
if (vif->mid != sta->mid) {
wil_err(wil, "STA MID mismatch with VIF MID(%d)\n",
vif->mid);
-   /* let FW override sta->mid but be more strict with
-* user space requests
-*/
-   if (!from_event)
-   return;
-   }
-   if (!from_event) {
-   bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
-   disable_ap_sme : false;
-   wmi_disconnect_sta(vif, sta->addr, reason_code,
-  true, del_sta);
}
 
switch (wdev->iftype) {
@@ -284,36 +287,20 @@ static void wil_disconnect_cid(struct wil6210_vif *vif, 
int cid,
sta->stats.tx_latency_min_us = U32_MAX;
 }
 
-static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
-{
-   int i;
-
-   for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
-   if (wil->sta[i].mid == mid &&
-   wil->sta[i].status == wil_sta_connected)
-   return true;
-   }
-
-   return false;
-}
-
-static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
-   u16 reason_code, bool from_event)
+static void _wil6210_disconnect_complete(struct wil6210_vif *vif,
+const u8 *bssid, u16 reason_code)
 {
struct wil6210_priv *wil = vif_to_wil(vif);
int cid = -ENOENT;
struct net_device *ndev;
struct wireless_dev *wdev;
 
-   if (unlikely(!vif))
-   return;
-
ndev = vif_to_ndev(vif);
wdev = vif_to_wdev(vif);
 
might_sleep();
-   wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid,
-reason_code, from_event ? "+" : "-");
+   wil_info(wil, "disconnect_complete: bssid=%pM, reason=%d\n",
+bssid, reason_code);
 
/* Cases are:
 * - disconnect single STA, still connected
@@ -328,14 +315,15 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, 
const u8 *bssid,
if (bssid && !is_broadcast_ether_addr(bssid) &&

[PATCH 06/16] wil6210: fix memory leak in wil_find_tx_bcast_2

2018-10-31 Thread Maya Erez
From: Lior David 

A successful call to wil_tx_ring takes skb reference so
it will only be freed in wil_tx_complete. Consume the skb
in wil_find_tx_bcast_2 to prevent memory leak.

Signed-off-by: Lior David 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/txrx.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/wil6210/txrx.c 
b/drivers/net/wireless/ath/wil6210/txrx.c
index c592c8e..3e1c831 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1395,6 +1395,8 @@ static struct wil_ring *wil_find_tx_bcast_2(struct 
wil6210_priv *wil,
wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
wil_set_da_for_vring(wil, skb2, i);
wil_tx_ring(wil, vif, v2, skb2);
+   /* successful call to wil_tx_ring takes skb2 ref */
+   dev_kfree_skb_any(skb2);
} else {
wil_err(wil, "skb_copy failed\n");
}
-- 
1.9.1



[PATCH 09/16] wil6210: add general initialization/size checks

2018-10-31 Thread Maya Erez
From: Alexei Avshalom Lazar 

Initialize unset variable, and verify that mid is valid.

Signed-off-by: Alexei Avshalom Lazar 
Signed-off-by: Maya Erez 
---
 drivers/net/wireless/ath/wil6210/debugfs.c | 2 ++
 drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c 
b/drivers/net/wireless/ath/wil6210/debugfs.c
index aa50813..099a04b 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -962,6 +962,8 @@ static ssize_t wil_write_file_txmgmt(struct file *file, 
const char __user *buf,
int rc;
void *frame;
 
+   memset(, 0, sizeof(params));
+
if (!len)
return -EINVAL;
 
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c 
b/drivers/net/wireless/ath/wil6210/wmi.c
index fa08a96..f46c703 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -3148,7 +3148,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
 
if (mid == MID_BROADCAST)
mid = 0;
-   if (mid >= wil->max_vifs) {
+   if (mid >= ARRAY_SIZE(wil->vifs) || mid >= wil->max_vifs) {
wil_dbg_wmi(wil, "invalid mid %d, event skipped\n",
mid);
return;
-- 
1.9.1



[PATCH] mt76x0: do not overwrite other MT_BBP(AGC, 8) fields

2018-10-31 Thread Stanislaw Gruszka
MT_BBP(AGC, 8) register has values depend on band in
mt76x0_bbp_switch_tab, so we should not overwrite other fields
than MT_BBP_AGC_GAIN when setting gain.

This can fix performance issues when connecting to 2.4GHz AP.

Fixes: 4636a2544c3b ("mt76x0: phy: align channel gain logic to mt76x2 one")
Signed-off-by: Stanislaw Gruszka 
---
 drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c 
b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index ba98814ae47d..88dd0aa7e877 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -690,10 +690,8 @@ static void mt76x0_phy_temp_sensor(struct mt76x02_dev *dev)
 static void mt76x0_phy_set_gain_val(struct mt76x02_dev *dev)
 {
u8 gain = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust;
-   u32 val = 0x122c << 16 | 0xf2;
 
-   mt76_wr(dev, MT_BBP(AGC, 8),
-   val | FIELD_PREP(MT_BBP_AGC_GAIN, gain));
+   mt76_rmw_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN, gain);
 
if ((dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR) &&
!is_mt7630(dev))
-- 
2.7.5