[PATCH 1/2] ath10k: enable QCA6174/QCA9377 to read the chip temperature

2018-03-16 Thread ryanhsu
From: Ryan Hsu 

The firmware of QCA6174/QCA9377 already support the feature, just enable
it to be able to handle the get_temperature command and process the event.

You can read the temperature by using the hwmon interface,

cat /sys/class/ieee80211/phy*/device/hwmon/hwmon2/temp1_input

Verified with the following hardware and software combination,
QCA6174, only firmware-4.bin doesn't support this, otherwise all support.
QCA9377, all the firmwares upstreamed support this command

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 39 +--
 drivers/net/wireless/ath/ath10k/wmi-tlv.h | 11 +
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c 
b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 7616c1c..9d31b97 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -412,6 +412,19 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar,
return 0;
 }
 
+static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar,
+   struct sk_buff *skb)
+{
+   const struct wmi_tlv_pdev_temperature_event *ev;
+
+   ev = (struct wmi_tlv_pdev_temperature_event *)skb->data;
+   if (WARN_ON(skb->len < sizeof(*ev)))
+   return -EPROTO;
+
+   ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature));
+   return 0;
+}
+
 /***/
 /* TLV ops */
 /***/
@@ -552,6 +565,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct 
sk_buff *skb)
case WMI_TLV_TX_PAUSE_EVENTID:
ath10k_wmi_tlv_event_tx_pause(ar, skb);
break;
+   case WMI_TLV_PDEV_TEMPERATURE_EVENTID:
+   ath10k_wmi_tlv_event_temperature(ar, skb);
+   break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@@ -2554,6 +2570,25 @@ static void *ath10k_wmi_tlv_put_wmm(void *ptr,
 }
 
 static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_get_temperature(struct ath10k *ar)
+{
+   struct wmi_tlv_pdev_get_temp_cmd *cmd;
+   struct wmi_tlv *tlv;
+   struct sk_buff *skb;
+
+   skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+   if (!skb)
+   return ERR_PTR(-ENOMEM);
+
+   tlv = (void *)skb->data;
+   tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD);
+   tlv->len = __cpu_to_le16(sizeof(*cmd));
+   cmd = (void *)tlv->value;
+   ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature tlv\n");
+   return skb;
+}
+
+static struct sk_buff *
 ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar)
 {
struct wmi_tlv_pktlog_disable *cmd;
@@ -3334,7 +3369,7 @@ static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 
uapsd_queues, u8 sp)
.force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID,
.gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
-   .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
+   .pdev_get_temperature_cmdid = WMI_TLV_PDEV_GET_TEMPERATURE_CMDID,
.vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
.tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
.tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,
@@ -3596,7 +3631,7 @@ static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 
uapsd_queues, u8 sp)
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
/* .gen_pdev_set_quiet_mode not implemented */
-   /* .gen_pdev_get_temperature not implemented */
+   .gen_pdev_get_temperature = ath10k_wmi_tlv_op_gen_pdev_get_temperature,
/* .gen_addba_clear_resp not implemented */
/* .gen_addba_send not implemented */
/* .gen_addba_set_resp not implemented */
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h 
b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 22cf011..906e9e1 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1235,6 +1235,17 @@ struct wmi_tlv_init_cmd {
__le32 num_host_mem_chunks;
 } __packed;
 
+struct wmi_tlv_pdev_get_temp_cmd {
+   __le32 pdev_id; /* not used */
+} __packed;
+
+struct wmi_tlv_pdev_temperature_event {
+   __le32 tlv_hdr;
+   /* temperature value in Celcius degree */
+   __le32 temperature;
+   __le32 pdev_id;
+} __packed;
+
 struct wmi_tlv_pdev_set_param_cmd {
__le32 pdev_id; /* not used yet */
__le32 param_id;
-- 
1.9.1



[PATCH 2/2] ath10k: add FW API 6 firmware image for QCA9377

2018-03-16 Thread ryanhsu
From: Ryan Hsu 

Firmware WLAN.TF.2.1-00014-QCARMSWP-1 now supports reading the board ID
information and also required 9 IRAM bank, which older ath10k version
don't have the support will fail to be enabled, so in order to maintain
the backward compatibility, we need to update the FW API to 6.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index e9c3162..d2a3acd 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3496,5 +3496,6 @@ static void __exit ath10k_pci_exit(void)
 MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
 
 /* QCA9377 1.0 firmware files */
+MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API6_FILE);
 MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE);
 MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE);
-- 
1.9.1



[PATCH] ath10k: update the IRAM banks number for QCA9377

2018-02-08 Thread ryanhsu
From: Ryan Hsu 

QCA9377 firmware update the IRAM banks from 4 to 9.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 355db6a..0c1029c 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2216,7 +2216,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
}
break;
case QCA9377_1_0_DEVICE_ID:
-   return 4;
+   return 9;
}
 
ath10k_warn(ar, "unknown number of banks, assuming 1\n");
-- 
1.9.1



[PATCH] ath10k: Update the phymode along with bandwidth change request

2018-01-24 Thread ryanhsu
From: Ryan Hsu 

In the case of Station connects to AP with narrower bandwidth at beginning.
And later the AP changes the bandwidth to winder bandwidth, the AP will
beacon with wider bandwidth IE, eg VHT20->VHT40->VHT80 or VHT40->VHT80.

Since the supported BANDWIDTH will be limited by the PHYMODE, so while
Station receives the bandwidth change request, it will also need to
reconfigure the PHYMODE setting to firmware instead of just configuring
the BANDWIDTH info, otherwise it'll trigger a firmware crash with
non-support bandwidth.

The issue was observed in WLAN.RM.4.4.1-00051-QCARMSWP-1, QCA6174 with
below scenario.

--
AP xxx changed bandwidth, new config is 5200 MHz, width 2 (5190/0 MHz)
disconnect from AP xxx for new auth to yyy
RX ReassocResp from xxx (capab=0x status=0 aid=102)
associated



AP xxx changed bandwidth, new config is 5200 MHz, width 2 (5190/0 MHz)
AP xxx changed bandwidth, new config is 5200 MHz, width 3 (5210/0 MHz)



firmware register dump:
[00]: 0x0503 0x15B3 0x00987291 0x00955B31
[04]: 0x00987291 0x00060730 0x0004 0x0001
[08]: 0x004089F0 0x00955A00 0x000A0B00 0x0040
[12]: 0x0009 0x 0x00952CD0 0x00952CE6
[16]: 0x00952CC4 0x0098E25F 0x 0x0091080D
[20]: 0x40987291 0x0040E7A8 0x 0x0041EE3C
[24]: 0x809ABF05 0x0040E808 0x 0xC0987291
[28]: 0x809A650C 0x0040E948 0x0041FE40 0x004345C4
[32]: 0x809A5C63 0x0040E988 0x0040E9AC 0x0042D1A8
[36]: 0x8091D252 0x0040E9A8 0x0002 0x0001
[40]: 0x809FDA9D 0x0040EA58 0x0043D554 0x0042D554
[44]: 0x809F8B22 0x0040EA78 0x0043D554 0x0001
[48]: 0x80911210 0x0040EAC8 0x0010 0x004041D0
[52]: 0x80911154 0x0040EB28 0x0040 0x
[56]: 0x8091122D 0x0040EB48 0x 0x00400600
--

Reported-by: Rouven Czerwinski 
Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/mac.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index ebb3f1b..68a5256 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -5996,8 +5997,18 @@ static void ath10k_sta_rc_update_wk(struct work_struct 
*wk)
   ath10k_mac_max_vht_nss(vht_mcs_mask)));
 
if (changed & IEEE80211_RC_BW_CHANGED) {
-   ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw 
%d\n",
-  sta->addr, bw);
+   mode = chan_to_phymode(&def);
+
+   ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d 
phymode %d\n",
+  sta->addr, bw, mode);
+
+   err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+   WMI_PEER_PHYMODE, mode);
+   if (err) {
+   ath10k_warn(ar, "failed to update STA %pM peer phymode 
%d: %d\n",
+   sta->addr, mode, err);
+   goto exit;
+   }
 
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_CHAN_WIDTH, bw);
@@ -6039,6 +6050,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct 
*wk)
sta->addr);
}
 
+exit:
mutex_unlock(&ar->conf_mutex);
 }
 
-- 
1.9.1



[PATCH] ath10k: add sanity check to ie_len before parsing fw/board ie

2018-01-08 Thread ryanhsu
From: Ryan Hsu 

Validate ie_len after the alignment padding before access the buffer
to avoid potential overflow.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/core.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 51444d3..64713d1 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1276,7 +1276,10 @@ static int ath10k_core_fetch_board_data_api_n(struct 
ath10k *ar,
len -= sizeof(*hdr);
data = hdr->data;
 
-   if (len < ALIGN(ie_len, 4)) {
+   /* jump over the padding */
+   ie_len = ALIGN(ie_len, 4);
+
+   if (len < ie_len) {
ath10k_err(ar, "invalid length for board ie_id %d 
ie_len %zu len %zu\n",
   ie_id, ie_len, len);
ret = -EINVAL;
@@ -1315,8 +1318,6 @@ static int ath10k_core_fetch_board_data_api_n(struct 
ath10k *ar,
goto out;
}
 
-   /* jump over the padding */
-   ie_len = ALIGN(ie_len, 4);
 
len -= ie_len;
data += ie_len;
@@ -1448,6 +1449,9 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
len -= sizeof(*hdr);
data += sizeof(*hdr);
 
+   /* jump over the padding */
+   ie_len = ALIGN(ie_len, 4);
+
if (len < ie_len) {
ath10k_err(ar, "invalid length for FW IE %d (%zu < 
%zu)\n",
   ie_id, len, ie_len);
@@ -1553,9 +1557,6 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
break;
}
 
-   /* jump over the padding */
-   ie_len = ALIGN(ie_len, 4);
-
len -= ie_len;
data += ie_len;
}
-- 
1.9.1



[PATCH] ath10k: add sanity check to ie_len before parsing fw/board ie

2017-12-27 Thread ryanhsu
From: Ryan Hsu 

Validate ie_len after the alignment padding before access the buffer
to avoid potential overflow.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/core.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 042175a..2f24c17 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1240,7 +1240,10 @@ static int ath10k_core_fetch_board_data_api_n(struct 
ath10k *ar,
len -= sizeof(*hdr);
data = hdr->data;
 
-   if (len < ALIGN(ie_len, 4)) {
+   /* jump over the padding */
+   ie_len = ALIGN(ie_len, 4);
+
+   if (len < ie_len) {
ath10k_err(ar, "invalid length for board ie_id %d 
ie_len %zu len %zu\n",
   ie_id, ie_len, len);
ret = -EINVAL;
@@ -1279,8 +1282,6 @@ static int ath10k_core_fetch_board_data_api_n(struct 
ath10k *ar,
goto out;
}
 
-   /* jump over the padding */
-   ie_len = ALIGN(ie_len, 4);
 
len -= ie_len;
data += ie_len;
@@ -1412,6 +1413,9 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
len -= sizeof(*hdr);
data += sizeof(*hdr);
 
+   /* jump over the padding */
+   ie_len = ALIGN(ie_len, 4);
+
if (len < ie_len) {
ath10k_err(ar, "invalid length for FW IE %d (%zu < 
%zu)\n",
   ie_id, len, ie_len);
@@ -1517,9 +1521,6 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
break;
}
 
-   /* jump over the padding */
-   ie_len = ALIGN(ie_len, 4);
-
len -= ie_len;
data += ie_len;
}
-- 
1.9.1



[PATCH v3 1/2] ath10k: add the PCI PM core suspend/resume ops

2017-08-22 Thread ryanhsu
From: Ryan Hsu 

The actual PCI suspend/resume in ath10k has been handled in wow.c,
but in the case of the device doesn't support remote wakeup,
the .hif_suspend() and .hif_resume() will never be handled.

  ath10k_wow_op_suspend()
  {
if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
ar->running_fw->fw_file.fw_features))) {
ret = 1;
goto exit;
}



ret = ath10k_hif_suspend(ar);
  }

So register the PCI PM core to support the suspend/resume if the device
doesn't support remote wakeup.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/pci.c | 42 +++
 1 file changed, 42 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 0457e31..4aac0de 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3358,11 +3358,53 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
 
 MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
 
+#ifdef CONFIG_PM
+
+static int ath10k_pci_pm_suspend(struct device *dev)
+{
+   struct ath10k *ar = dev_get_drvdata(dev);
+   int ret;
+
+   if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ar->running_fw->fw_file.fw_features))
+   return 0;
+
+   ret = ath10k_hif_suspend(ar);
+   if (ret)
+   ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
+
+   return ret;
+}
+
+static int ath10k_pci_pm_resume(struct device *dev)
+{
+   struct ath10k *ar = dev_get_drvdata(dev);
+   int ret;
+
+   if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ar->running_fw->fw_file.fw_features))
+   return 0;
+
+   ret = ath10k_hif_resume(ar);
+   if (ret)
+   ath10k_warn(ar, "failed to resume hif: %d\n", ret);
+
+   return ret;
+}
+
+SIMPLE_DEV_PM_OPS(ath10k_pci_pm_ops,
+ ath10k_pci_pm_suspend,
+ ath10k_pci_pm_resume);
+#endif
+
 static struct pci_driver ath10k_pci_driver = {
.name = "ath10k_pci",
.id_table = ath10k_pci_id_table,
.probe = ath10k_pci_probe,
.remove = ath10k_pci_remove,
+#ifdef CONFIG_PM
+   .driver.pm = &ath10k_pci_pm_ops,
+#endif
 };
 
 static int __init ath10k_pci_init(void)
-- 
1.9.1



[PATCH v3 2/2] ath10k: Configure and enable the wakeup capability

2017-08-22 Thread ryanhsu
From: Ryan Hsu 

ACPI will rely on device driver to tell it if the device could support
wakeup function when system in D3 state.

This has caused some platform can't support remote wakeup correctly,
because the ACPI wakeup GPE is not enabled, hence registers the .set_wakeup
callback to handle it if device supports wakeup.

Tested with QCA6174 hw3.0, firmware ('WLAN.RM.4.4.1-8-QCARMSWP-1')

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/mac.c |  1 +
 drivers/net/wireless/ath/ath10k/wow.c | 14 ++
 drivers/net/wireless/ath/ath10k/wow.h |  1 +
 3 files changed, 16 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 2e5d2ca..bbf7da1 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7488,6 +7488,7 @@ static const struct ieee80211_ops ath10k_ops = {
 #ifdef CONFIG_PM
.suspend= ath10k_wow_op_suspend,
.resume = ath10k_wow_op_resume,
+   .set_wakeup = ath10k_wow_op_set_wakeup,
 #endif
 #ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs= ath10k_sta_add_debugfs,
diff --git a/drivers/net/wireless/ath/ath10k/wow.c 
b/drivers/net/wireless/ath/ath10k/wow.c
index 77100d4..0d46d6d 100644
--- a/drivers/net/wireless/ath/ath10k/wow.c
+++ b/drivers/net/wireless/ath/ath10k/wow.c
@@ -277,6 +277,18 @@ exit:
return ret ? 1 : 0;
 }
 
+void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+   struct ath10k *ar = hw->priv;
+
+   mutex_lock(&ar->conf_mutex);
+   if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ar->running_fw->fw_file.fw_features)) {
+   device_set_wakeup_enable(ar->dev, enabled);
+   }
+   mutex_unlock(&ar->conf_mutex);
+}
+
 int ath10k_wow_op_resume(struct ieee80211_hw *hw)
 {
struct ath10k *ar = hw->priv;
@@ -336,5 +348,7 @@ int ath10k_wow_init(struct ath10k *ar)
ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
 
+   device_set_wakeup_capable(ar->dev, true);
+
return 0;
 }
diff --git a/drivers/net/wireless/ath/ath10k/wow.h 
b/drivers/net/wireless/ath/ath10k/wow.h
index abbb04b..9745b9d 100644
--- a/drivers/net/wireless/ath/ath10k/wow.h
+++ b/drivers/net/wireless/ath/ath10k/wow.h
@@ -28,6 +28,7 @@ int ath10k_wow_init(struct ath10k *ar);
 int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
  struct cfg80211_wowlan *wowlan);
 int ath10k_wow_op_resume(struct ieee80211_hw *hw);
+void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled);
 
 #else
 
-- 
1.9.1



[PATCH] ath10k: fix napi_poll budget overflow

2017-08-22 Thread ryanhsu
From: Ryan Hsu 

In napi_poll, the budget number is used to control the amount of packets
we should handle per poll to balance the resource in the system.

In the list of the amsdu packets reception, we check if there is budget
count left and handle the complete list of the packets, that it will have
chances the very last list will over the budget leftover.

So adding one more parameter - budget_left, this would help while
traversing the list to avoid handling more than the budget given.

Reported-by: Andrey Ryabinin 
Fix-suggested-by: Igor Mitsyanko 

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c 
b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 0b4c156..95a5a18 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1718,7 +1718,8 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct 
htt_resp *resp)
 }
 
 static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,
-  struct sk_buff_head *amsdu)
+  struct sk_buff_head *amsdu,
+  int budget_left)
 {
struct sk_buff *msdu;
struct htt_rx_desc *rxd;
@@ -1729,8 +1730,9 @@ static int ath10k_htt_rx_extract_amsdu(struct 
sk_buff_head *list,
if (WARN_ON(!skb_queue_empty(amsdu)))
return -EINVAL;
 
-   while ((msdu = __skb_dequeue(list))) {
+   while ((msdu = __skb_dequeue(list)) && budget_left) {
__skb_queue_tail(amsdu, msdu);
+   budget_left--;
 
rxd = (void *)msdu->data - sizeof(*rxd);
if (rxd->msdu_end.common.info0 &
@@ -1821,7 +1823,8 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
return num_msdu;
 }
 
-static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb,
+   int budget_left)
 {
struct ath10k_htt *htt = &ar->htt;
struct htt_resp *resp = (void *)skb->data;
@@ -1878,9 +1881,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, 
struct sk_buff *skb)
if (offload)
num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list);
 
-   while (!skb_queue_empty(&list)) {
+   while (!skb_queue_empty(&list) && budget_left) {
__skb_queue_head_init(&amsdu);
-   ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu);
+   ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu, budget_left);
switch (ret) {
case 0:
/* Note: The in-order indication may report interleaved
@@ -1890,6 +1893,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, 
struct sk_buff *skb)
 * should still give an idea about rx rate to the user.
 */
num_msdus += skb_queue_len(&amsdu);
+   budget_left -= skb_queue_len(&amsdu);
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
ath10k_htt_rx_h_filter(ar, &amsdu, status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
@@ -2400,7 +2404,8 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int 
budget)
}
 
spin_lock_bh(&htt->rx_ring.lock);
-   num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb);
+   num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb,
+   (budget - quota));
spin_unlock_bh(&htt->rx_ring.lock);
if (num_rx_msdus < 0) {
resched_napi = true;
-- 
1.9.1



[PATCH v2 1/2] ath10k: add the PCI PM core suspend/resume ops

2017-08-22 Thread ryanhsu
From: Ryan Hsu 

The actual PCI suspend/resume in ath10k has been handled in wow.c,
but in the case of the device doesn't support remote wakeup,
the .hif_suspend() and .hif_resume() will never be handled.

  ath10k_wow_op_suspend()
  {
if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
ar->running_fw->fw_file.fw_features))) {
ret = 1;
goto exit;
}



ret = ath10k_hif_suspend(ar);
  }

So register the PCI PM core to support the suspend/resume if the device
doesn't support remote wakeup.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/pci.c | 42 +++
 1 file changed, 42 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 0457e31..4aac0de 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3358,11 +3358,53 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
 
 MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
 
+#ifdef CONFIG_PM
+
+static int ath10k_pci_pm_suspend(struct device *dev)
+{
+   struct ath10k *ar = dev_get_drvdata(dev);
+   int ret;
+
+   if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ar->running_fw->fw_file.fw_features))
+   return 0;
+
+   ret = ath10k_hif_suspend(ar);
+   if (ret)
+   ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
+
+   return ret;
+}
+
+static int ath10k_pci_pm_resume(struct device *dev)
+{
+   struct ath10k *ar = dev_get_drvdata(dev);
+   int ret;
+
+   if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ar->running_fw->fw_file.fw_features))
+   return 0;
+
+   ret = ath10k_hif_resume(ar);
+   if (ret)
+   ath10k_warn(ar, "failed to resume hif: %d\n", ret);
+
+   return ret;
+}
+
+SIMPLE_DEV_PM_OPS(ath10k_pci_pm_ops,
+ ath10k_pci_pm_suspend,
+ ath10k_pci_pm_resume);
+#endif
+
 static struct pci_driver ath10k_pci_driver = {
.name = "ath10k_pci",
.id_table = ath10k_pci_id_table,
.probe = ath10k_pci_probe,
.remove = ath10k_pci_remove,
+#ifdef CONFIG_PM
+   .driver.pm = &ath10k_pci_pm_ops,
+#endif
 };
 
 static int __init ath10k_pci_init(void)
-- 
1.9.1



[PATCH v2 2/2] ath10k: Configure and enable the wakeup capability

2017-08-22 Thread ryanhsu
From: Ryan Hsu 

ACPI will rely on device driver to tell it if the device could support
wakeup function when system in D3 state.

This has caused some platform can't support remote wakeup correctly,
because the ACPI wakeup GPE is not enabled, hence registers the .set_wakeup
callback to handle it if device supports wakeup.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/mac.c |  1 +
 drivers/net/wireless/ath/ath10k/wow.c | 14 ++
 drivers/net/wireless/ath/ath10k/wow.h |  1 +
 3 files changed, 16 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 2e5d2ca..bbf7da1 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7488,6 +7488,7 @@ static const struct ieee80211_ops ath10k_ops = {
 #ifdef CONFIG_PM
.suspend= ath10k_wow_op_suspend,
.resume = ath10k_wow_op_resume,
+   .set_wakeup = ath10k_wow_op_set_wakeup,
 #endif
 #ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs= ath10k_sta_add_debugfs,
diff --git a/drivers/net/wireless/ath/ath10k/wow.c 
b/drivers/net/wireless/ath/ath10k/wow.c
index 77100d4..0d46d6d 100644
--- a/drivers/net/wireless/ath/ath10k/wow.c
+++ b/drivers/net/wireless/ath/ath10k/wow.c
@@ -277,6 +277,18 @@ exit:
return ret ? 1 : 0;
 }
 
+void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+   struct ath10k *ar = hw->priv;
+
+   mutex_lock(&ar->conf_mutex);
+   if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ar->running_fw->fw_file.fw_features)) {
+   device_set_wakeup_enable(ar->dev, enabled);
+   }
+   mutex_unlock(&ar->conf_mutex);
+}
+
 int ath10k_wow_op_resume(struct ieee80211_hw *hw)
 {
struct ath10k *ar = hw->priv;
@@ -336,5 +348,7 @@ int ath10k_wow_init(struct ath10k *ar)
ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
 
+   device_set_wakeup_capable(ar->dev, true);
+
return 0;
 }
diff --git a/drivers/net/wireless/ath/ath10k/wow.h 
b/drivers/net/wireless/ath/ath10k/wow.h
index abbb04b..9745b9d 100644
--- a/drivers/net/wireless/ath/ath10k/wow.h
+++ b/drivers/net/wireless/ath/ath10k/wow.h
@@ -28,6 +28,7 @@ int ath10k_wow_init(struct ath10k *ar);
 int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
  struct cfg80211_wowlan *wowlan);
 int ath10k_wow_op_resume(struct ieee80211_hw *hw);
+void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled);
 
 #else
 
-- 
1.9.1



[PATCH] ath10k: fix the logic of limiting tdls peer counts

2017-05-30 Thread ryanhsu
From: Ryan Hsu 

The original idea is to limit the maximum TDLS peer link, but the logic
is always false, and never be able to restrict the number of TDLS peer
creation.

Fix the logic here and also move the checking earlier, so that it could
avoid to handle the failure case, e.g disable the tdls peer, delete the
peer and also vdev count cleanup.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/mac.c | 49 +++
 1 file changed, 21 insertions(+), 28 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 4674ff3..48418f9 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -6073,6 +6073,20 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
   ar->num_stations + 1, ar->max_num_stations,
   ar->num_peers + 1, ar->max_num_peers);
 
+   num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif);
+   num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw);
+
+   if (sta->tdls) {
+   if (num_tdls_stations >= ar->max_num_tdls_vdevs) {
+   ath10k_warn(ar, "vdev %i exceeded maximum 
number of tdls vdevs %i\n",
+   arvif->vdev_id,
+   ar->max_num_tdls_vdevs);
+   ret = -ELNRNG;
+   goto exit;
+   }
+   peer_type = WMI_PEER_TYPE_TDLS;
+   }
+
ret = ath10k_mac_inc_num_stations(arvif, sta);
if (ret) {
ath10k_warn(ar, "refusing to associate station: too 
many connected already (%d)\n",
@@ -6080,9 +6094,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
goto exit;
}
 
-   if (sta->tdls)
-   peer_type = WMI_PEER_TYPE_TDLS;
-
ret = ath10k_peer_create(ar, vif, sta, arvif->vdev_id,
 sta->addr, peer_type);
if (ret) {
@@ -6113,35 +6124,17 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
if (!sta->tdls)
goto exit;
 
-   num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif);
-   num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw);
-
-   if (num_tdls_vifs >= ar->max_num_tdls_vdevs &&
-   num_tdls_stations == 0) {
-   ath10k_warn(ar, "vdev %i exceeded maximum number of 
tdls vdevs %i\n",
-   arvif->vdev_id, ar->max_num_tdls_vdevs);
-   ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
+   ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id,
+ WMI_TDLS_ENABLE_ACTIVE);
+   if (ret) {
+   ath10k_warn(ar, "failed to update fw tdls state on vdev 
%i: %i\n",
+   arvif->vdev_id, ret);
+   ath10k_peer_delete(ar, arvif->vdev_id,
+  sta->addr);
ath10k_mac_dec_num_stations(arvif, sta);
-   ret = -ENOBUFS;
goto exit;
}
 
-   if (num_tdls_stations == 0) {
-   /* This is the first tdls peer in current vif */
-   enum wmi_tdls_state state = WMI_TDLS_ENABLE_ACTIVE;
-
-   ret = ath10k_wmi_update_fw_tdls_state(ar, 
arvif->vdev_id,
- state);
-   if (ret) {
-   ath10k_warn(ar, "failed to update fw tdls state 
on vdev %i: %i\n",
-   arvif->vdev_id, ret);
-   ath10k_peer_delete(ar, arvif->vdev_id,
-  sta->addr);
-   ath10k_mac_dec_num_stations(arvif, sta);
-   goto exit;
-   }
-   }
-
ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
  WMI_TDLS_PEER_STATE_PEERING);
if (ret) {
-- 
1.9.1



[PATCH] ath10k: append the wmi_op_version to testmode get_version cmd

2017-04-25 Thread ryanhsu
From: Ryan Hsu 

QCA9xxx and QCA61x4/QCA93xx are using different wmi operation, in order
for userspace to differentiate it, appends the wmi_op_version information
alone with the get_version command.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/testmode.c   | 7 +++
 drivers/net/wireless/ath/ath10k/testmode_i.h | 1 +
 2 files changed, 8 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/testmode.c 
b/drivers/net/wireless/ath/ath10k/testmode.c
index ed85f93..eaf4a4b 100644
--- a/drivers/net/wireless/ath/ath10k/testmode.c
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -137,6 +137,13 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, 
struct nlattr *tb[])
return ret;
}
 
+   ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION,
+ ar->normal_mode_fw.fw_file.wmi_op_version);
+   if (ret) {
+   kfree_skb(skb);
+   return ret;
+   }
+
return cfg80211_testmode_reply(skb);
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/testmode_i.h 
b/drivers/net/wireless/ath/ath10k/testmode_i.h
index ba81bf6..191a8f3 100644
--- a/drivers/net/wireless/ath/ath10k/testmode_i.h
+++ b/drivers/net/wireless/ath/ath10k/testmode_i.h
@@ -33,6 +33,7 @@ enum ath10k_tm_attr {
ATH10K_TM_ATTR_WMI_CMDID= 3,
ATH10K_TM_ATTR_VERSION_MAJOR= 4,
ATH10K_TM_ATTR_VERSION_MINOR= 5,
+   ATH10K_TM_ATTR_WMI_OP_VERSION   = 6,
 
/* keep last */
__ATH10K_TM_ATTR_AFTER_LAST,
-- 
1.9.1



[PATCH] ath10k: ath10k: bump up FW API to 6

2017-04-11 Thread ryanhsu
From: Ryan Hsu 

For QCA6174 hw3.0, since WLAN.RM.4.4-00022-QCARMSWPZ-2, it starts to
support the board ID information from otp, with some devices released on
the market that didn't calibrated with OTP, will have 0 for board ID
information, which cause the backward compatibility issue and was fixed
in commit 'd2e202c06ca4 ("ath10k: ignore configuring the incorrect board_id")'

So bump the fw api version to differentiate the latest firmware support.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/hw.h  | 5 -
 drivers/net/wireless/ath/ath10k/pci.c | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index f7c5c13..cd3dd11 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -129,7 +129,7 @@ enum qca9377_chip_id_rev {
 #define QCA4019_HW_1_0_PATCH_LOAD_ADDR  0x1234
 
 #define ATH10K_FW_FILE_BASE"firmware"
-#define ATH10K_FW_API_MAX  5
+#define ATH10K_FW_API_MAX  6
 #define ATH10K_FW_API_MIN  2
 
 #define ATH10K_FW_API2_FILE"firmware-2.bin"
@@ -141,6 +141,9 @@ enum qca9377_chip_id_rev {
 /* HTT id conflict fix for management frames over HTT */
 #define ATH10K_FW_API5_FILE"firmware-5.bin"
 
+/* the firmware-6.bin blob */
+#define ATH10K_FW_API6_FILE"firmware-6.bin"
+
 #define ATH10K_FW_UTF_FILE "utf.bin"
 #define ATH10K_FW_UTF_API2_FILE"utf-2.bin"
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 5d2f9b9..66e27a3 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3429,6 +3429,7 @@ static void __exit ath10k_pci_exit(void)
 /* QCA6174 3.1 firmware files */
 MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
 MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API6_FILE);
 MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
 MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
 
-- 
1.9.1



[PATCH 4.11] ath10k: fix incorrect wlan_mac_base in qca6174_regs

2017-03-13 Thread ryanhsu
From: Ryan Hsu 

In the 'commit ebee76f7fa46 ("ath10k: allow setting coverage class")',
it inherits the design and the address offset from ath9k, but the address
is not applicable to QCA6174, which leads to a random crash while doing the
resume() operation, since the set_coverage_class.ops will be called from
ieee80211_reconfig() when resume() (if the wow is not configured).

Fix the incorrect address offset here to avoid the random crash.

Verified on QCA6174/hw3.0 with firmware WLAN.RM.4.4-00022-QCARMSWPZ-2.

Fixes: ebee76f7fa46 ("ath10k: allow setting coverage class")
Cc: sta...@vger.kernel.org
Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/hw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/hw.c 
b/drivers/net/wireless/ath/ath10k/hw.c
index 33fb268..d9f37ee 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -51,7 +51,7 @@
.rtc_soc_base_address   = 0x0800,
.rtc_wmac_base_address  = 0x1000,
.soc_core_base_address  = 0x0003a000,
-   .wlan_mac_base_address  = 0x0002,
+   .wlan_mac_base_address  = 0x0001,
.ce_wrapper_base_address= 0x00034000,
.ce0_base_address   = 0x00034400,
.ce1_base_address   = 0x00034800,
-- 
1.9.1



[PATCH v2 1/2] ath10k: improve the firmware download time for QCA6174

2017-02-15 Thread ryanhsu
From: Ryan Hsu 

Len Brown reported the system resume time is taking more than 2 seconds in
bug - https://bugzilla.kernel.org/show_bug.cgi?id=185621.

The reason of the 2 seconds is due to the firmware download time.

The chip is booted up in the default reference clock speed to handle the
firmware download to chip memory and advanced to the support higher speed
clock to run the firmware after all. The default reference clock in the
hardware is slow so that the firmware download time is taking up to 2
seconds for a 600KB firmware file.

[76796.349701] ath10k_pci : boot uploading firmware image len 688691
[76798.334612] ath10k_pci : htt tx max num pending tx 1056

The resolution here is to enable the higher speed clock if the hardware
supported before the firmware download at BMI stage, so that the hardware
can handle the firmare download in a more efficient way. This can help to
improve the firmware download time from 2 seconds to around 500ms for the
same 600KB firmware file.

[322858.577919] ath10k_pci boot uploading firmware image len 688691
[322859.093094] ath10k_pci htt tx max num pending tx 1056

The steps to advance to the higher speed clock is very hardware specific,
so adding the hardware ops for the hardware that can support this.

Reported-by: Len Brown 
Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/bmi.c  |  72 +
 drivers/net/wireless/ath/ath10k/bmi.h  |   2 +
 drivers/net/wireless/ath/ath10k/core.c |   4 +-
 drivers/net/wireless/ath/ath10k/hw.c   | 265 +
 drivers/net/wireless/ath/ath10k/hw.h   |  69 +
 5 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/bmi.c 
b/drivers/net/wireless/ath/ath10k/bmi.c
index 2872d34..abeee20 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -19,12 +19,21 @@
 #include "hif.h"
 #include "debug.h"
 #include "htc.h"
+#include "hw.h"
 
 void ath10k_bmi_start(struct ath10k *ar)
 {
+   int ret;
+
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
 
ar->bmi.done_sent = false;
+
+   /* Enable hardware clock to speed up firmware download */
+   if (ar->hw_params.hw_ops->enable_pll_clk) {
+   ret = ar->hw_params.hw_ops->enable_pll_clk(ar);
+   ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi enable pll ret %d\n", ret);
+   }
 }
 
 int ath10k_bmi_done(struct ath10k *ar)
@@ -129,6 +138,69 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
return 0;
 }
 
+int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
+{
+   struct bmi_cmd cmd;
+   u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
+   int ret;
+
+   ath10k_dbg(ar, ATH10K_DBG_BMI,
+  "bmi write soc register 0x%08x val 0x%08x\n",
+  address, reg_val);
+
+   if (ar->bmi.done_sent) {
+   ath10k_warn(ar, "bmi write soc register command in progress\n");
+   return -EBUSY;
+   }
+
+   cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
+   cmd.write_soc_reg.addr = __cpu_to_le32(address);
+   cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
+
+   ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
+   if (ret) {
+   ath10k_warn(ar, "Unable to write soc register to device: %d\n",
+   ret);
+   return ret;
+   }
+
+   return 0;
+}
+
+int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
+{
+   struct bmi_cmd cmd;
+   union bmi_resp resp;
+   u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
+   u32 resplen = sizeof(resp.read_soc_reg);
+   int ret;
+
+   ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
+  address);
+
+   if (ar->bmi.done_sent) {
+   ath10k_warn(ar, "bmi read soc register command in progress\n");
+   return -EBUSY;
+   }
+
+   cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
+   cmd.read_soc_reg.addr = __cpu_to_le32(address);
+
+   ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
+   if (ret) {
+   ath10k_warn(ar, "Unable to read soc register from device: %d\n",
+   ret);
+   return ret;
+   }
+
+   *reg_val = __le32_to_cpu(resp.read_soc_reg.value);
+
+   ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
+  *reg_val);
+
+   return 0;
+}
+
 int ath10k_bmi_write_memory(struct ath10k *ar,
u32 address, const void *buffer, u32 length)
 {
diff --git a/drivers/net/wireless/ath/ath10k/bmi.h 
b/drivers/net/wireless/ath/ath10k/bmi.h
index 7d3231a..a65f262 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.h
+++ b/drivers/net/wireless/ath/ath10k/bmi.h
@@ -232,4 +232,6 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
 int at

[PATCH v2 2/2] ath10k: improve the firmware download time for QCA9377

2017-02-15 Thread ryanhsu
From: Ryan Hsu 

QCA9377 is the family of QCA61x4 which shared the same procedure
to enable the hardware clock that could improve the firmware download time.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/core.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index c6de267..91e2731 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -282,7 +282,9 @@
.board_size = QCA9377_BOARD_DATA_SZ,
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
},
-   .hw_ops = &qca988x_ops,
+   .hw_ops = &qca6174_ops,
+   .hw_clk = qca6174_clk,
+   .target_cpu_freq = 17600,
.decap_align_bytes = 4,
},
{
-- 
1.9.1



[PATCH 1/2] ath10k: improve the firmware download time for QCA6174

2017-02-15 Thread ryanhsu
From: Ryan Hsu 

Len Brown reported the system resume time is taking more than 2 seconds in
bug - https://bugzilla.kernel.org/show_bug.cgi?id=185621.

The reason of the 2 seconds is due to the firmware download time.

The chip is booted up in the default reference clock speed to handle the
firmware download to chip memory and advanced to the support higher speed
clock to run the firmware after all. The default reference clock in the
hardware is slow so that the firmware download time is taking up to 2
seconds for a 600KB firmware file.

[76796.349701] ath10k_pci : boot uploading firmware image len 688691
[76798.334612] ath10k_pci : htt tx max num pending tx 1056

The resolution here is to enable the higher speed clock if the hardware
supported before the firmware download at BMI stage, so that the hardware
can handle the firmare download in a more efficient way. This can help to
improve the firmware download time from 2 seconds to around 500ms for the
same 600KB firmware file.

[322858.577919] ath10k_pci boot uploading firmware image len 688691
[322859.093094] ath10k_pci htt tx max num pending tx 1056

The steps to advance to the higher speed clock is very hardware specific,
so adding the hardware ops for the hardware that can support this.

Reported-by: Len Brown 
Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/bmi.c  |  72 +
 drivers/net/wireless/ath/ath10k/bmi.h  |   2 +
 drivers/net/wireless/ath/ath10k/core.c |   4 +-
 drivers/net/wireless/ath/ath10k/hw.c   | 265 +
 drivers/net/wireless/ath/ath10k/hw.h   |  69 +
 5 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/bmi.c 
b/drivers/net/wireless/ath/ath10k/bmi.c
index 2872d34..073a6f3 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -19,12 +19,21 @@
 #include "hif.h"
 #include "debug.h"
 #include "htc.h"
+#include "hw.h"
 
 void ath10k_bmi_start(struct ath10k *ar)
 {
+   int ret;
+
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
 
ar->bmi.done_sent = false;
+
+   /* Enable hardware clock to speed up firmware download */
+   if (ar->hw_params.hw_ops->enable_pll_clk) {
+   ret = ar->hw_params.hw_ops->enable_pll_clk(ar)
+   ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi enable pll ret %d\n", ret);
+   }
 }
 
 int ath10k_bmi_done(struct ath10k *ar)
@@ -129,6 +138,69 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
return 0;
 }
 
+int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
+{
+   struct bmi_cmd cmd;
+   u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
+   int ret;
+
+   ath10k_dbg(ar, ATH10K_DBG_BMI,
+  "bmi write soc register 0x%08x val 0x%08x\n",
+  address, reg_val);
+
+   if (ar->bmi.done_sent) {
+   ath10k_warn(ar, "bmi write soc register command in progress\n");
+   return -EBUSY;
+   }
+
+   cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
+   cmd.write_soc_reg.addr = __cpu_to_le32(address);
+   cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
+
+   ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
+   if (ret) {
+   ath10k_warn(ar, "Unable to write soc register to device: %d\n",
+   ret);
+   return ret;
+   }
+
+   return 0;
+}
+
+int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
+{
+   struct bmi_cmd cmd;
+   union bmi_resp resp;
+   u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
+   u32 resplen = sizeof(resp.read_soc_reg);
+   int ret;
+
+   ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
+  address);
+
+   if (ar->bmi.done_sent) {
+   ath10k_warn(ar, "bmi read soc register command in progress\n");
+   return -EBUSY;
+   }
+
+   cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
+   cmd.read_soc_reg.addr = __cpu_to_le32(address);
+
+   ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
+   if (ret) {
+   ath10k_warn(ar, "Unable to read soc register from device: %d\n",
+   ret);
+   return ret;
+   }
+
+   *reg_val = __le32_to_cpu(resp.read_soc_reg.value);
+
+   ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
+  *reg_val);
+
+   return 0;
+}
+
 int ath10k_bmi_write_memory(struct ath10k *ar,
u32 address, const void *buffer, u32 length)
 {
diff --git a/drivers/net/wireless/ath/ath10k/bmi.h 
b/drivers/net/wireless/ath/ath10k/bmi.h
index 7d3231a..a65f262 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.h
+++ b/drivers/net/wireless/ath/ath10k/bmi.h
@@ -232,4 +232,6 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
 int ath

[PATCH 2/2] ath10k: improve the firmware download time for QCA9377

2017-02-15 Thread ryanhsu
From: Ryan Hsu 

QCA9377 is the family of QCA61x4 which shared the same procedure
to enable the hardware clock that could improve the firmware download time.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/core.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index c6de267..91e2731 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -282,7 +282,9 @@
.board_size = QCA9377_BOARD_DATA_SZ,
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
},
-   .hw_ops = &qca988x_ops,
+   .hw_ops = &qca6174_ops,
+   .hw_clk = qca6174_clk,
+   .target_cpu_freq = 17600,
.decap_align_bytes = 4,
},
{
-- 
1.9.1



[PATCH] ath10k: fix the garage chars in board file name creation

2017-02-10 Thread ryanhsu
From: Ryan Hsu 

The variant[] string will be valid only if the bdf_ext is set.

The string memory needs to be null-terminated to avoid the undefined garbage
appended by the subsequent board file name creation.

ath10k_pci :04:00.0: failed to fetch board data for
"bus=pci,vendor=168c,device=003e,subsystem-vendor=168c,subsystem-device=3363��P�"
from ath10k/QCA6174/hw3.0/board-2.bin

Fixes: f2593cb1b291 ("ath10k: Search SMBIOS for OEM board file extension")
Reported-by: Kalle Valo 
Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index c27e7ea..014a87e 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1122,7 +1122,7 @@ static int ath10k_core_create_board_name(struct ath10k 
*ar, char *name,
 size_t name_len)
 {
/* strlen(',variant=') + strlen(ar->id.bdf_ext) */
-   char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH];
+   char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };
 
if (ar->id.bmi_ids_valid) {
scnprintf(name, name_len,
-- 
1.9.1



[PATCH] ath10k: ignore configuring the incorrect board_id

2016-12-22 Thread ryanhsu
From: Ryan Hsu 

With command to get board_id from otp, in the case of following

  boot get otp board id result 0x board_id 0 chip_id 0
  boot using board name 'bus=pci,bmi-chip-id=0,bmi-board-id=0"
  ...
  failed to fetch board data for bus=pci,bmi-chip-id=0,bmi-board-id=0 from
  ath10k/QCA6174/hw3.0/board-2.bin

The invalid board_id=0 will be used as index to search in the board-2.bin.

Ignore the case with board_id=0, as it means the otp is not carrying
the board id information.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/core.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 749e381..1bf67ad 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -694,8 +694,11 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k 
*ar)
   "boot get otp board id result 0x%08x board_id %d chip_id 
%d\n",
   result, board_id, chip_id);
 
-   if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0)
+   if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 ||
+   (board_id == 0)) {
+   ath10k_warn(ar, "board id is not exist in otp, ignore it\n");
return -EOPNOTSUPP;
+   }
 
ar->id.bmi_ids_valid = true;
ar->id.bmi_board_id = board_id;
-- 
1.9.1



[PATCH] ath10k: recal the txpower when removing interface

2016-12-22 Thread ryanhsu
From: Ryan Hsu 

The txpower is being recalculated when adding interface to make sure
txpower won't overshoot the spec, and when removing the interface,
the txpower should again to be recalculated to restore the correct value
from the active interface list.

Following is one of the scenario
vdev0 is created as STA and connected: txpower:23
vdev1 is created as P2P_DEVICE for control interface: txpower:0
vdev2 is created as p2p go/gc interface: txpower is 21

So the vdev2@txpower:21 will be set to firmware when vdev2 is created.
When we tear down the vdev2, the txpower needs to be recalculated to
re-set it to vdev0@txpower:23 as vdev0/vdev1 are the active interface.

ath10k_pci mac vdev 0 peer create 8c:fd:f0:01:62:98
ath10k_pci mac vdev_id 0 txpower 23
... (adding interface)
ath10k_pci mac vdev create 2 (add interface) type 1 subtype 3
ath10k_pci mac vdev_id 2 txpower 21
ath10k_pci mac txpower 21
... (removing interface)
ath10k_pci mac vdev 2 delete (remove interface)
ath10k_pci vdev 1 txpower 0
ath10k_pci vdev 0 txpower 23
ath10k_pci mac txpower 23

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index aa545a1..6475dc8 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5194,6 +5194,10 @@ static void ath10k_remove_interface(struct ieee80211_hw 
*hw,
ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
}
 
+   ret = ath10k_mac_txpower_recalc(ar);
+   if (ret)
+   ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+
spin_lock_bh(&ar->htt.tx_lock);
ath10k_mac_vif_tx_unlock_all(arvif);
spin_unlock_bh(&ar->htt.tx_lock);
-- 
1.9.1



[PATCH V2] ath10k: fix incorrect txpower set by P2P_DEVICE interface

2016-12-13 Thread ryanhsu
From: Ryan Hsu 

Ath10k reports the phy capability that supports P2P_DEVICE interface.

When we use the P2P supported wpa_supplicant to start connection, it'll
create two interfaces, one is wlan0 (vdev_id=0) and one is P2P_DEVICE
p2p-dev-wlan0 which is for p2p control channel (vdev_id=1).

ath10k_pci mac vdev create 0 (add interface) type 2 subtype 0
ath10k_add_interface: vdev_id: 0, txpower: 0, bss_power: 0
...
ath10k_pci mac vdev create 1 (add interface) type 2 subtype 1
ath10k_add_interface: vdev_id: 1, txpower: 0, bss_power: 0

And the txpower in per vif bss_conf will only be set to valid tx power when
the interface is assigned with channel_ctx.

But this P2P_DEVICE interface will never be used for any connection, so
that the uninitialized bss_conf.txpower=0 is assinged to the
arvif->txpower when interface created.

Since the txpower configuration is firmware per physical interface.
So the smallest txpower of all vifs will be the one limit the tx power
of the physical device, that causing the low txpower issue on other
active interfaces.

wlan0: Limiting TX power to 21 (24 - 3) dBm
ath10k_pci mac vdev_id 0 txpower 21
ath10k_mac_txpower_recalc: vdev_id: 1, txpower: 0
ath10k_mac_txpower_recalc: vdev_id: 0, txpower: 21
ath10k_pci mac txpower 0

This issue only happens when we use the wpa_supplicant that supports
P2P or if we use the iw tool to create the control P2P_DEVICE interface.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/mac.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index fe42bf5..6e1550b 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4671,7 +4671,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
 
list_for_each_entry(arvif, &ar->arvifs, list) {
-   WARN_ON(arvif->txpower < 0);
+   if (arvif->txpower <= 0)
+   continue;
 
if (txpower == -1)
txpower = arvif->txpower;
@@ -4679,8 +4680,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
txpower = min(txpower, arvif->txpower);
}
 
-   if (WARN_ON(txpower == -1))
-   return -EINVAL;
+   if (txpower == -1)
+   return 0;
 
ret = ath10k_mac_txpower_setup(ar, txpower);
if (ret) {
-- 
1.9.1



[PATCH] ath10k: fix incorrect txpower set by P2P_DEVICE interface

2016-12-07 Thread ryanhsu
From: Ryan Hsu 

Ath10k reports the phy capability that upports P2P_DEVICE interface.

When we use the P2P supported wpa_supplicant to start connection, it'll
create the two interfaces, one is wlan0 (vdev_id=0) and one is P2P_DEVICE
p2p-dev-wlan0 which is for p2p control channel (vdev_id=1).

ath10k_pci mac vdev create 0 (add interface) type 2 subtype 0
ath10k_add_interface: vdev_id: 0, txpower: 0, bss_power: 0
...
ath10k_pci mac vdev create 1 (add interface) type 2 subtype 1
ath10k_add_interface: vdev_id: 1, txpower: 0, bss_power: 0

And the txpower in per vif bss_conf will only be set to valid tx power when
the interface is assigned with channel_ctx.

But this P2P_DEVICE interface will never be used for any connection, so
that the uninitialized bss_conf.txpower=0 is assinged to the
arvif->txpower when interface created.

Since the txpower configuration is per phy interface.
So the smallest txpower of all vifs will be the one limit the tx power
of the phyical device, that causing the low txpower issue on other
active interfaces.

wlan0: Limiting TX power to 21 (24 - 3) dBm
ath10k_pci mac vdev_id 0 txpower 21
ath10k_mac_txpower_recalc: vdev_id: 1, txpower: 0
ath10k_mac_txpower_recalc: vdev_id: 0, txpower: 21
ath10k_pci mac txpower 0

This issue only happens when we use the wpa_supplicant that supports
P2P or if we use the iw tool to create the control P2P_DEVICE interface.

Signed-off-by: Ryan Hsu 
---
 drivers/net/wireless/ath/ath10k/mac.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index fe42bf5..6e1550b 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4671,7 +4671,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
 
list_for_each_entry(arvif, &ar->arvifs, list) {
-   WARN_ON(arvif->txpower < 0);
+   if (arvif->txpower <= 0)
+   continue;
 
if (txpower == -1)
txpower = arvif->txpower;
@@ -4679,8 +4680,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
txpower = min(txpower, arvif->txpower);
}
 
-   if (WARN_ON(txpower == -1))
-   return -EINVAL;
+   if (txpower == -1)
+   return 0;
 
ret = ath10k_mac_txpower_setup(ar, txpower);
if (ret) {
-- 
1.9.1