[PATCH 00/11] SDIO support for ath10k

2017-09-30 Thread silexcommon
From: Alagu Sankar 

This patchset, generated against master-pending branch, enables a fully
functional SDIO interface driver for ath10k.  Patches have been verified on
QCA9377-3 WB396 and Silex's SX-SDCAC reference cards with Station, Access Point
and P2P modes.

The driver is verified with the firmware WLAN.TF.1.1.1-00061-QCATFSWPZ-1
with the board data from respective SDIO card vendors. Receive performance
matches the QCA reference driver when used with SDIO3.0 enabled platforms.
iperf tests indicate a downlink UDP of 275Mbit/s and TCP of 150Mbit/s

This patchset differs from the previous high latency patches, specific to SDIO.
HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET is enabled for HI_ACS. This instructs the
firmware to use HTT_T2H_MSG_TYPE_TX_COMPL_IND for outgoing packets. Without
this flag, the management frames are not sent out by the firmware. Possibility
of management frames being sent via WMI and data frames through the reduced Tx
completion needs to be probed further.

Further improvements can be done on the transmit path by implementing packet
bundle. Scatter Gather is another area of improvement for both Transmit and
Receive, but may not work on all platforms

Known issues: Surprise removal of the card, when the device is in connected
state, delays sdio function remove due to delayed WMI command failures.
Existing ath10k framework can not differentiate between a kernel module
removal and the surprise removal of teh card.

Alagu Sankar (11):
  ath10k_sdio: sdio htt data transfer fixes
  ath10k_sdio: wb396 reference card fix
  ath10k_sdio: DMA bounce buffers for read write
  ath10k_sdio: reduce transmit msdu count
  ath10k_sdio: use clean packet headers
  ath10k_sdio: high latency fixes for beacon buffer
  ath10k_sdio: fix rssi indication
  ath10k_sdio: common read write
  ath10k_sdio: virtual scatter gather for receive
  ath10k_sdio: enable firmware crash dump
  ath10k_sdio: hif start once addition

 drivers/net/wireless/ath/ath10k/core.c|  35 ++-
 drivers/net/wireless/ath/ath10k/debug.c   |   3 +
 drivers/net/wireless/ath/ath10k/htc.c |   4 +-
 drivers/net/wireless/ath/ath10k/htc.h |   1 +
 drivers/net/wireless/ath/ath10k/htt_rx.c  |  19 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c  |  24 +-
 drivers/net/wireless/ath/ath10k/hw.c  |   2 +
 drivers/net/wireless/ath/ath10k/hw.h  |   1 +
 drivers/net/wireless/ath/ath10k/mac.c |  31 ++-
 drivers/net/wireless/ath/ath10k/sdio.c| 398 ++
 drivers/net/wireless/ath/ath10k/sdio.h|  10 +-
 drivers/net/wireless/ath/ath10k/wmi-tlv.c |   2 +-
 12 files changed, 403 insertions(+), 127 deletions(-)

-- 
1.9.1



[PATCH 06/11] ath10k_sdio: high latency fixes for beacon buffer

2017-09-30 Thread silexcommon
From: Alagu Sankar 

Beacon buffer for high latency devices does not use dma. other similar
buffer allocation methods in the driver have already been modified for
high latency path. Fix the beacon buffer allocation left out in the
earlier high latency changes.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/mac.c | 31 +++
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index f374d1b..c48785b 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -944,8 +944,12 @@ static void ath10k_mac_vif_beacon_cleanup(struct 
ath10k_vif *arvif)
ath10k_mac_vif_beacon_free(arvif);
 
if (arvif->beacon_buf) {
-   dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- arvif->beacon_buf, arvif->beacon_paddr);
+   if (ar->is_high_latency)
+   kfree(arvif->beacon_buf);
+   else
+   dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf,
+ arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}
 }
@@ -5052,10 +5056,17 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
vif->type == NL80211_IFTYPE_AP) {
-   arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
-   IEEE80211_MAX_FRAME_LEN,
-   &arvif->beacon_paddr,
-   GFP_ATOMIC);
+   if (ar->is_high_latency) {
+   arvif->beacon_buf = kmalloc(IEEE80211_MAX_FRAME_LEN,
+   GFP_KERNEL);
+   arvif->beacon_paddr = (dma_addr_t)arvif->beacon_buf;
+   } else {
+   arvif->beacon_buf =
+   dma_zalloc_coherent(ar->dev,
+   IEEE80211_MAX_FRAME_LEN,
+   &arvif->beacon_paddr,
+   GFP_ATOMIC);
+   }
if (!arvif->beacon_buf) {
ret = -ENOMEM;
ath10k_warn(ar, "failed to allocate beacon buffer: 
%d\n",
@@ -5244,8 +5255,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 
 err:
if (arvif->beacon_buf) {
-   dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- arvif->beacon_buf, arvif->beacon_paddr);
+   if (ar->is_high_latency)
+   kfree(arvif->beacon_buf);
+   else
+   dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf,
+ arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}
 
-- 
1.9.1



[PATCH 09/11] ath10k_sdio: virtual scatter gather for receive

2017-09-30 Thread silexcommon
From: Alagu Sankar 

The existing implementation of initiating multiple sdio transfers for
receive bundling is slowing down the receive speed. Combining the
transfers using a scatter gather method would be ideal. This results in
significant performance improvement.

Since the sg implementation for sdio transfers are not reliable due to
buffer start and size alignment, a virtual scatter gather implementation
is used.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/htc.h  |   1 +
 drivers/net/wireless/ath/ath10k/sdio.c | 122 -
 drivers/net/wireless/ath/ath10k/sdio.h |   5 +-
 3 files changed, 93 insertions(+), 35 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htc.h 
b/drivers/net/wireless/ath/ath10k/htc.h
index 24663b0..5d87908 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -58,6 +58,7 @@ enum ath10k_htc_tx_flags {
 };
 
 enum ath10k_htc_rx_flags {
+   ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK = 0x01,
ATH10K_HTC_FLAG_TRAILER_PRESENT = 0x02,
ATH10K_HTC_FLAG_BUNDLE_MASK = 0xF0
 };
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c 
b/drivers/net/wireless/ath/ath10k/sdio.c
index bb6fa67..45df9db 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -35,6 +35,7 @@
 #include "sdio.h"
 
 #define ATH10K_SDIO_DMA_BUF_SIZE   (32 * 1024)
+#define ATH10K_SDIO_VSG_BUF_SIZE   (32 * 1024)
 
 static int ath10k_sdio_read(struct ath10k *ar, u32 addr, void *buf,
u32 len, bool incr);
@@ -430,6 +431,7 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k 
*ar,
int ret;
 
payload_len = le16_to_cpu(htc_hdr->len);
+   skb->len = payload_len + sizeof(struct ath10k_htc_hdr);
 
if (trailer_present) {
trailer = skb->data + sizeof(*htc_hdr) +
@@ -468,12 +470,13 @@ static int ath10k_sdio_mbox_rx_process_packets(struct 
ath10k *ar,
enum ath10k_htc_ep_id id;
int ret, i, *n_lookahead_local;
u32 *lookaheads_local;
+   int lookahd_idx = 0;
 
for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
lookaheads_local = lookaheads;
n_lookahead_local = n_lookahead;
 
-   id = ((struct ath10k_htc_hdr *)&lookaheads[i])->eid;
+   id = ((struct ath10k_htc_hdr *)&lookaheads[lookahd_idx++])->eid;
 
if (id >= ATH10K_HTC_EP_COUNT) {
ath10k_warn(ar, "invalid endpoint in look-ahead: %d\n",
@@ -496,6 +499,7 @@ static int ath10k_sdio_mbox_rx_process_packets(struct 
ath10k *ar,
/* Only read lookahead's from RX trailers
 * for the last packet in a bundle.
 */
+   lookahd_idx--;
lookaheads_local = NULL;
n_lookahead_local = NULL;
}
@@ -529,11 +533,11 @@ static int ath10k_sdio_mbox_rx_process_packets(struct 
ath10k *ar,
return ret;
 }
 
-static int ath10k_sdio_mbox_alloc_pkt_bundle(struct ath10k *ar,
-struct ath10k_sdio_rx_data 
*rx_pkts,
-struct ath10k_htc_hdr *htc_hdr,
-size_t full_len, size_t act_len,
-size_t *bndl_cnt)
+static int ath10k_sdio_mbox_alloc_bundle(struct ath10k *ar,
+struct ath10k_sdio_rx_data *rx_pkts,
+struct ath10k_htc_hdr *htc_hdr,
+size_t full_len, size_t act_len,
+size_t *bndl_cnt)
 {
int ret, i;
 
@@ -574,6 +578,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
size_t full_len, act_len;
bool last_in_bundle;
int ret, i;
+   int pkt_cnt = 0;
 
if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) {
ath10k_warn(ar,
@@ -616,16 +621,22 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
 * optimally fetched as a full bundle.
 */
size_t bndl_cnt;
-
-   ret = ath10k_sdio_mbox_alloc_pkt_bundle(ar,
-   
&ar_sdio->rx_pkts[i],
-   htc_hdr,
-   full_len,
-   act_len,
-   &bndl_cnt);
-
-   n_lookaheads += bndl_cnt;
-   i += bndl_cnt;
+   struct ath10k_sdio_rx_data *rx_pkts =
+   &ar_sdio->rx_pkts[pkt_cnt];
+
+   ret = ath10k_sdi

[PATCH 08/11] ath10k_sdio: common read write

2017-09-30 Thread silexcommon
From: Alagu Sankar 

convert different read write functions in sdio hif to bring it under a
single read-write path. This helps in having a common dma bounce buffer
implementation. Also helps in address modification that is required
specific to change in certain mbox addresses of sdio_write.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/sdio.c | 131 -
 1 file changed, 64 insertions(+), 67 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c 
b/drivers/net/wireless/ath/ath10k/sdio.c
index 77d4fa4..bb6fa67 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -36,6 +36,11 @@
 
 #define ATH10K_SDIO_DMA_BUF_SIZE   (32 * 1024)
 
+static int ath10k_sdio_read(struct ath10k *ar, u32 addr, void *buf,
+   u32 len, bool incr);
+static int ath10k_sdio_write(struct ath10k *ar, u32 addr, const void *buf,
+u32 len, bool incr);
+
 /* inlined helper functions */
 
 /* Macro to check if DMA buffer is WORD-aligned and DMA-able.
@@ -152,6 +157,7 @@ static int ath10k_sdio_config(struct ath10k *ar)
struct sdio_func *func = ar_sdio->func;
unsigned char byte, asyncintdelay = 2;
int ret;
+   u32 addr;
 
ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio configuration\n");
 
@@ -180,9 +186,8 @@ static int ath10k_sdio_config(struct ath10k *ar)
 CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C |
 CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D);
 
-   ret = ath10k_sdio_func0_cmd52_wr_byte(func->card,
- 
CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR,
- byte);
+   addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR,
+   ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, addr, byte);
if (ret) {
ath10k_warn(ar, "failed to enable driver strength: %d\n", ret);
goto out;
@@ -233,13 +238,16 @@ static int ath10k_sdio_config(struct ath10k *ar)
 
 static int ath10k_sdio_write32(struct ath10k *ar, u32 addr, u32 val)
 {
-   struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
-   struct sdio_func *func = ar_sdio->func;
+   __le32 *buf;
int ret;
 
-   sdio_claim_host(func);
+   buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
 
-   sdio_writel(func, val, addr, &ret);
+   *buf = cpu_to_le32(val);
+
+   ret = ath10k_sdio_write(ar, addr, &val, sizeof(val), true);
if (ret) {
ath10k_warn(ar, "failed to write 0x%x to address 0x%x: %d\n",
val, addr, ret);
@@ -250,15 +258,13 @@ static int ath10k_sdio_write32(struct ath10k *ar, u32 
addr, u32 val)
   addr, val);
 
 out:
-   sdio_release_host(func);
+   kfree(buf);
 
return ret;
 }
 
 static int ath10k_sdio_writesb32(struct ath10k *ar, u32 addr, u32 val)
 {
-   struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
-   struct sdio_func *func = ar_sdio->func;
__le32 *buf;
int ret;
 
@@ -268,9 +274,7 @@ static int ath10k_sdio_writesb32(struct ath10k *ar, u32 
addr, u32 val)
 
*buf = cpu_to_le32(val);
 
-   sdio_claim_host(func);
-
-   ret = sdio_writesb(func, addr, buf, sizeof(*buf));
+   ret = ath10k_sdio_write(ar, addr, buf, sizeof(*buf), false);
if (ret) {
ath10k_warn(ar, "failed to write value 0x%x to fixed sb address 
0x%x: %d\n",
val, addr, ret);
@@ -281,8 +285,6 @@ static int ath10k_sdio_writesb32(struct ath10k *ar, u32 
addr, u32 val)
   addr, val);
 
 out:
-   sdio_release_host(func);
-
kfree(buf);
 
return ret;
@@ -290,28 +292,33 @@ static int ath10k_sdio_writesb32(struct ath10k *ar, u32 
addr, u32 val)
 
 static int ath10k_sdio_read32(struct ath10k *ar, u32 addr, u32 *val)
 {
-   struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
-   struct sdio_func *func = ar_sdio->func;
+   __le32 *buf;
int ret;
 
-   sdio_claim_host(func);
-   *val = sdio_readl(func, addr, &ret);
+   buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   ret = ath10k_sdio_read(ar, addr, buf, sizeof(*val), true);
if (ret) {
ath10k_warn(ar, "failed to read from address 0x%x: %d\n",
addr, ret);
goto out;
}
 
+   *val = le32_to_cpu(*buf);
+
ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio read32 addr 0x%x val 0x%x\n",
   addr, *val);
 
 out:
-   sdio_release_host(func);
+   kfree(buf);
 
return ret;
 }
 
-static int ath10k_sdio_read(struct ath10k *ar, u32 addr, void *buf, size_t len)
+static int ath10k_sdio_read(struct ath10k *ar, u32 addr, void *buf,
+   size_t len, bool incr)
 {
struct ath10k_sdio *ar_sdio = ath1

[PATCH 07/11] ath10k_sdio: fix rssi indication

2017-09-30 Thread silexcommon
From: Alagu Sankar 

Receive descriptor of sdio device does not include the rssi. notify
mac80211 accordingly. Without the fix, the rssi value indicated by
iw changes between the actual value and -95.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 13 ++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c 
b/drivers/net/wireless/ath/ath10k/htt_rx.c
index f025363..21adcad 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1646,9 +1646,16 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct 
ath10k_htt *htt,
hdr = (struct ieee80211_hdr *)skb->data;
rx_status = IEEE80211_SKB_RXCB(skb);
rx_status->chains |= BIT(0);
-   rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
-   rx->ppdu.combined_rssi;
-   rx_status->flag &= ~RX_FLAG_NO_SIGNAL_VAL;
+
+   if (ar->hif.bus == ATH10K_BUS_SDIO) {
+   /* SDIO firmware does not provide signal */
+   rx_status->signal = 0;
+   rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+   } else {
+   rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
+   rx->ppdu.combined_rssi;
+   rx_status->flag &= ~RX_FLAG_NO_SIGNAL_VAL;
+   }
 
spin_lock_bh(&ar->data_lock);
ch = ar->scan_channel;
-- 
1.9.1



[PATCH 11/11] ath10k_sdio: hif start once addition

2017-09-30 Thread silexcommon
From: Alagu Sankar 

sdio hif interface uses the start_once optimization to avoid unnecessary
firmware downloading. simulate hif_stop in sdio as core_stop does not
handle this due to start_once optimization.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/sdio.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c 
b/drivers/net/wireless/ath/ath10k/sdio.c
index 11fbf6e..c6f23a9 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -2255,6 +2255,12 @@ static void ath10k_sdio_remove(struct sdio_func *func)
cancel_work_sync(&ar_sdio->wr_async_work);
ath10k_core_unregister(ar);
ath10k_core_destroy(ar);
+
+   if (ar->is_started && ar->hw_params.start_once) {
+   ath10k_hif_stop(ar);
+   ath10k_hif_power_down(ar);
+   }
+
kfree(ar_sdio->dma_buffer);
kfree(ar_sdio->vsg_buffer);
 }
-- 
1.9.1



[PATCH 05/11] ath10k_sdio: use clean packet headers

2017-09-30 Thread silexcommon
From: Alagu Sankar 

HTC header carries junk values that may be interpreted by the firmware
differently. Enable credit update only if flow control is enabled for
the corresponding endpoint.

PLL clock setting sequence does not mask the PLL_CONTROL
register value. Side effect of not masking the values is not known as
the entire pll clock setting sequence is undocumented.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/htc.c | 4 +++-
 drivers/net/wireless/ath/ath10k/hw.c  | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/htc.c 
b/drivers/net/wireless/ath/ath10k/htc.c
index 75c2a3e..23e7216 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -84,11 +84,13 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep 
*ep,
struct ath10k_htc_hdr *hdr;
 
hdr = (struct ath10k_htc_hdr *)skb->data;
+   memset(hdr, 0, sizeof(struct ath10k_htc_hdr));
 
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
hdr->flags = 0;
-   hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
+   if (ep->tx_credit_flow_enabled)
+   hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
 
spin_lock_bh(&ep->htc->tx_lock);
hdr->seq_no = ep->seq_no++;
diff --git a/drivers/net/wireless/ath/ath10k/hw.c 
b/drivers/net/wireless/ath/ath10k/hw.c
index 07df7c6..2092392 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -812,6 +812,8 @@ static int ath10k_hw_qca6174_enable_pll_clock(struct ath10k 
*ar)
if (ret)
return -EINVAL;
 
+   reg_val &= ~(WLAN_PLL_CONTROL_REFDIV_MASK | WLAN_PLL_CONTROL_DIV_MASK |
+WLAN_PLL_CONTROL_NOPWD_MASK);
reg_val |= (SM(hw_clk->refdiv, WLAN_PLL_CONTROL_REFDIV) |
SM(hw_clk->div, WLAN_PLL_CONTROL_DIV) |
SM(1, WLAN_PLL_CONTROL_NOPWD));
-- 
1.9.1



[PATCH 10/11] ath10k_sdio: enable firmware crash dump

2017-09-30 Thread silexcommon
From: Alagu Sankar 

Handle firmware crash and gracefully restart the sdio driver on firmware
failures.  The caldata prefetch is disabled for sdio as the data read in
prefetch is resulting in errors, when enabled.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/debug.c |  3 ++
 drivers/net/wireless/ath/ath10k/sdio.c  | 86 +
 2 files changed, 89 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index eed4e9c..3a1982f 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1255,6 +1255,9 @@ static int ath10k_debug_cal_data_fetch(struct ath10k *ar)
if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN))
return -EINVAL;
 
+   if (ar->hif.bus == ATH10K_BUS_SDIO)
+   return -EINVAL;
+
hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
 
ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c 
b/drivers/net/wireless/ath/ath10k/sdio.c
index 45df9db..11fbf6e 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -28,6 +28,7 @@
 #include "core.h"
 #include "bmi.h"
 #include "debug.h"
+#include "coredump.h"
 #include "hif.h"
 #include "htc.h"
 #include "targaddrs.h"
@@ -37,6 +38,8 @@
 #define ATH10K_SDIO_DMA_BUF_SIZE   (32 * 1024)
 #define ATH10K_SDIO_VSG_BUF_SIZE   (32 * 1024)
 
+static int ath10k_sdio_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
+size_t buf_len);
 static int ath10k_sdio_read(struct ath10k *ar, u32 addr, void *buf,
u32 len, bool incr);
 static int ath10k_sdio_write(struct ath10k *ar, u32 addr, const void *buf,
@@ -810,6 +813,86 @@ static int ath10k_sdio_mbox_rxmsg_pending_handler(struct 
ath10k *ar,
return ret;
 }
 
+static int __ath10k_sdio_diag_read_hi(struct ath10k *ar, void *dest, u32 src,
+ u32 len)
+{
+   u32 host_addr, addr;
+   int ret;
+
+   host_addr = host_interest_item_address(src);
+
+   ret = ath10k_sdio_hif_diag_read(ar, host_addr, &addr, sizeof(addr));
+   if (ret != 0) {
+   ath10k_warn(ar, "failed to get firmware hi address %d: %d\n",
+   src, ret);
+   return ret;
+   }
+
+   ret = ath10k_sdio_hif_diag_read(ar, addr, dest, len);
+   if (ret != 0) {
+   ath10k_warn(ar, "failed to copy memory from %d (%d B): %d\n",
+   addr, len, ret);
+   return ret;
+   }
+
+   return 0;
+}
+
+#define ath10k_sdio_diag_read_hi(ar, dest, src, len)   \
+   __ath10k_sdio_diag_read_hi(ar, dest, HI_ITEM(src), len)
+
+static void ath10k_sdio_dump_registers(struct ath10k *ar,
+  struct ath10k_fw_crash_data *crash_data)
+{
+   __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
+   int i, ret;
+
+   ret = ath10k_sdio_diag_read_hi(ar, ®_dump_values[0],
+  hi_failure_state,
+  sizeof(reg_dump_values));
+   if (ret) {
+   ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
+   return;
+   }
+
+   BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
+
+   ath10k_err(ar, "firmware register dump:\n");
+   for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4)
+   ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
+  i,
+  __le32_to_cpu(reg_dump_values[i]),
+  __le32_to_cpu(reg_dump_values[i + 1]),
+  __le32_to_cpu(reg_dump_values[i + 2]),
+  __le32_to_cpu(reg_dump_values[i + 3]));
+
+   if (!crash_data)
+   return;
+
+   for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++)
+   crash_data->registers[i] = reg_dump_values[i];
+}
+
+static void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
+{
+   struct ath10k_fw_crash_data *crash_data;
+   char guid[UUID_STRING_LEN + 1];
+
+   ar->stats.fw_crash_counter++;
+   crash_data = ath10k_coredump_new(ar);
+
+   if (crash_data)
+   scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);
+   else
+   scnprintf(guid, sizeof(guid), "n/a");
+
+   ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);
+   ath10k_print_driver_info(ar);
+   ath10k_sdio_dump_registers(ar, crash_data);
+
+   queue_work(ar->workqueue, &ar->restart_work);
+}
+
 static int ath10k_sdio_mbox_proc_dbg_intr(struct ath10k *ar)
 {
u32 val;
@@ -933,6 +1016,9 @@ static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k 
*ar)
goto out;
}
 
+   if (cpu_int_status & 0x1)
+   ath10k_

[PATCH 01/11] ath10k_sdio: sdio htt data transfer fixes

2017-09-30 Thread silexcommon
From: Alagu Sankar 

The ath10k sdio firmware does not allow transmitting packets with the
reduced tx completion HI_ACS option. sdio firmware uses 1544 as
alternate credit size, which is not big enough for the maximum sized
mac80211 frames. Disable both these HI_ACS flags for SDIO.

Transmit completion for SDIO is similar to PCIe, via the T2H message
HTT_T2H_MSG_TYPE_TX_COMPL_IND.  Modify the high latency path to allow
SDIO modules to use the htt transmit completion path. This differs from
the high latency path taken by the USB devices.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/core.c   | 20 +---
 drivers/net/wireless/ath/ath10k/htt_rx.c |  6 --
 drivers/net/wireless/ath/ath10k/htt_tx.c | 24 +++-
 3 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 4351341..b4f66cd 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -494,11 +494,25 @@ static void ath10k_init_sdio(struct ath10k *ar)
ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99);
ath10k_bmi_read32(ar, hi_acs_flags, ¶m);
 
-   param |= (HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET |
- HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET |
- HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE);
+   /* Data transfer is not initiated, when reduced Tx completion
+* is used for SDIO. disable it until fixed
+*/
+   param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;
+
+   /* Alternate credit size of 1544 as used by SDIO firmware is
+* not big enough for mac80211 / native wifi frames. disable it
+*/
+   param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;
 
+   param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;
ath10k_bmi_write32(ar, hi_acs_flags, param);
+
+   /* Explicitly set fwlog prints to zero as target may turn it on
+* based on scratch registers.
+*/
+   ath10k_bmi_read32(ar, hi_option_flag, ¶m);
+   param |= HI_OPTION_DISABLE_DBGLOG;
+   ath10k_bmi_write32(ar, hi_option_flag, param);
 }
 
 static int ath10k_init_configure_target(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c 
b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 569edd0..f025363 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1764,7 +1764,9 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
 *  Note that with only one concurrent reader and one concurrent
 *  writer, you don't need extra locking to use these macro.
 */
-   if (!kfifo_put(&htt->txdone_fifo, tx_done)) {
+   if (ar->hif.bus == ATH10K_BUS_SDIO) {
+   ath10k_txrx_tx_unref(htt, &tx_done);
+   } else if (!kfifo_put(&htt->txdone_fifo, tx_done)) {
ath10k_warn(ar, "txdone fifo overrun, msdu_id %d status 
%d\n",
tx_done.msdu_id, tx_done.status);
ath10k_txrx_tx_unref(htt, &tx_done);
@@ -2541,7 +2543,7 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct 
sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
-   if (!ar->is_high_latency)
+   if (!(ar->hif.bus == ATH10K_BUS_USB))
ath10k_htt_rx_tx_compl_ind(htt->ar, skb);
break;
case HTT_T2H_MSG_TYPE_SEC_IND: {
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c 
b/drivers/net/wireless/ath/ath10k/htt_tx.c
index c74fc13..d7f59a2 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -153,7 +153,7 @@ void ath10k_htt_tx_txq_update(struct ieee80211_hw *hw,
 
 void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
 {
-   if (htt->ar->is_high_latency)
+   if (htt->ar->hif.bus == ATH10K_BUS_USB)
return;
 
lockdep_assert_held(&htt->tx_lock);
@@ -165,7 +165,7 @@ void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
 
 int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
 {
-   if (htt->ar->is_high_latency)
+   if (htt->ar->hif.bus == ATH10K_BUS_USB)
return 0;
 
lockdep_assert_held(&htt->tx_lock);
@@ -454,7 +454,7 @@ void ath10k_htt_tx_destroy(struct ath10k_htt *htt)
return;
 
ath10k_htt_tx_free_cont_txbuf(htt);
-   if (!htt->ar->is_high_latency)
+   if (!(htt->ar->hif.bus == ATH10K_BUS_USB))
ath10k_htt_tx_free_txq(htt);
ath10k_htt_tx_free_cont_frag_desc(htt);
ath10k_htt_tx_free_txdone_fifo(htt);
@@ -475,7 +475,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
 
 void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
 {
-   dev_kfree_skb_any(skb);
+   if (!(ar->hif.bus == ATH10K_BUS_SDIO))
+   dev_kf

[PATCH 02/11] ath10k_sdio: wb396 reference card fix

2017-09-30 Thread silexcommon
From: Alagu Sankar 

The QCA9377-3 WB396 sdio reference card does not get initialized
due to the conflict in uart gpio pins. This fix is not required
for other QCA9377 sdio cards.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/core.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index b4f66cd..86247c8 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1708,8 +1708,15 @@ static int ath10k_init_uart(struct ath10k *ar)
return ret;
}
 
-   if (!uart_print)
+   if (!uart_print) {
+   /* Hack: override dbg TX pin to avoid side effects of default
+* GPIO_6 in QCA9377 WB396 reference card
+*/
+   if (ar->hif.bus == ATH10K_BUS_SDIO)
+   ath10k_bmi_write32(ar, hi_dbg_uart_txpin,
+  ar->hw_params.uart_pin);
return 0;
+   }
 
ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);
if (ret) {
-- 
1.9.1



[PATCH 04/11] ath10k_sdio: reduce transmit msdu count

2017-09-30 Thread silexcommon
From: Alagu Sankar 

Reduce the transmit MSDU count for SDIO, to match with the descriptors
as used by the firmware. This also acts as a high watermark level for
transmit. Too many packets to the firmware results in transmit overflow
interrupt.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/core.c| 6 +-
 drivers/net/wireless/ath/ath10k/hw.h  | 1 +
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +-
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 86247c8..9de49f5 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1968,7 +1968,11 @@ static int ath10k_core_init_firmware_features(struct 
ath10k *ar)
ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;
-   ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;
+   if (ar->hif.bus == ATH10K_BUS_SDIO)
+   ar->htt.max_num_pending_tx =
+   TARGET_TLV_NUM_MSDU_DESC_HL;
+   else
+   ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;
ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS;
ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
WMI_STAT_PEER;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index 7c9f6f9..b870a92 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -688,6 +688,7 @@ struct ath10k_hw_ops {
 #define TARGET_TLV_NUM_TDLS_VDEVS  1
 #define TARGET_TLV_NUM_TIDS((TARGET_TLV_NUM_PEERS) * 2)
 #define TARGET_TLV_NUM_MSDU_DESC   (1024 + 32)
+#define TARGET_TLV_NUM_MSDU_DESC_HL64
 #define TARGET_TLV_NUM_WOW_PATTERNS22
 
 /* Target specific defines for QCA9377 high latency firmware */
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c 
b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 34e9770..3842caa 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1440,7 +1440,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct 
ath10k *ar)
cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0);
cfg->vow_config = __cpu_to_le32(0);
cfg->gtk_offload_max_vdev = __cpu_to_le32(2);
-   cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC);
+   cfg->num_msdu_desc = __cpu_to_le32(ar->htt.max_num_pending_tx);
cfg->max_frag_entries = __cpu_to_le32(2);
cfg->num_tdls_vdevs = __cpu_to_le32(TARGET_TLV_NUM_TDLS_VDEVS);
cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20);
-- 
1.9.1



[PATCH 03/11] ath10k_sdio: DMA bounce buffers for read write

2017-09-30 Thread silexcommon
From: Alagu Sankar 

Some SD host controllers still need bounce buffers for SDIO data
transfers. While the transfers worked fine on x86 platforms,
this is found to be required for i.MX6 based systems.

Changes are similar to and derived from the ath6kl sdio driver.

Signed-off-by: Alagu Sankar 
---
 drivers/net/wireless/ath/ath10k/sdio.c | 59 --
 drivers/net/wireless/ath/ath10k/sdio.h |  5 +++
 2 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c 
b/drivers/net/wireless/ath/ath10k/sdio.c
index 03a69e5..77d4fa4 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -34,8 +34,20 @@
 #include "trace.h"
 #include "sdio.h"
 
+#define ATH10K_SDIO_DMA_BUF_SIZE   (32 * 1024)
+
 /* inlined helper functions */
 
+/* Macro to check if DMA buffer is WORD-aligned and DMA-able.
+ * Most host controllers assume the buffer is DMA'able and will
+ * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid
+ * check fails on stack memory.
+ */
+static inline bool buf_needs_bounce(const u8 *buf)
+{
+   return ((unsigned long)buf & 0x3) || !virt_addr_valid(buf);
+}
+
 static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
   size_t len)
 {
@@ -303,15 +315,29 @@ static int ath10k_sdio_read(struct ath10k *ar, u32 addr, 
void *buf, size_t len)
 {
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
struct sdio_func *func = ar_sdio->func;
+   bool bounced = false;
+   u8 *tbuf = NULL;
int ret;
 
+   if (buf_needs_bounce(buf)) {
+   if (!ar_sdio->dma_buffer)
+   return -ENOMEM;
+   mutex_lock(&ar_sdio->dma_buffer_mutex);
+   tbuf = ar_sdio->dma_buffer;
+   bounced = true;
+   } else {
+   tbuf = buf;
+   }
+
sdio_claim_host(func);
 
-   ret = sdio_memcpy_fromio(func, buf, addr, len);
+   ret = sdio_memcpy_fromio(func, tbuf, addr, len);
if (ret) {
ath10k_warn(ar, "failed to read from address 0x%x: %d\n",
addr, ret);
goto out;
+   } else if (bounced) {
+   memcpy(buf, tbuf, len);
}
 
ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio read addr 0x%x buf 0x%p len 
%zu\n",
@@ -320,6 +346,8 @@ static int ath10k_sdio_read(struct ath10k *ar, u32 addr, 
void *buf, size_t len)
 
 out:
sdio_release_host(func);
+   if (bounced)
+   mutex_unlock(&ar_sdio->dma_buffer_mutex);
 
return ret;
 }
@@ -328,14 +356,27 @@ static int ath10k_sdio_write(struct ath10k *ar, u32 addr, 
const void *buf, size_
 {
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
struct sdio_func *func = ar_sdio->func;
+   bool bounced = false;
+   u8 *tbuf = NULL;
int ret;
 
+   if (buf_needs_bounce(buf)) {
+   if (!ar_sdio->dma_buffer)
+   return -ENOMEM;
+   mutex_lock(&ar_sdio->dma_buffer_mutex);
+   tbuf = ar_sdio->dma_buffer;
+   memcpy(tbuf, buf, len);
+   bounced = true;
+   } else {
+   tbuf = (u8 *)buf;
+   }
+
sdio_claim_host(func);
 
/* For some reason toio() doesn't have const for the buffer, need
 * an ugly hack to workaround that.
 */
-   ret = sdio_memcpy_toio(func, addr, (void *)buf, len);
+   ret = sdio_memcpy_toio(func, addr, (void *)tbuf, len);
if (ret) {
ath10k_warn(ar, "failed to write to address 0x%x: %d\n",
addr, ret);
@@ -348,6 +389,8 @@ static int ath10k_sdio_write(struct ath10k *ar, u32 addr, 
const void *buf, size_
 
 out:
sdio_release_host(func);
+   if (bounced)
+   mutex_unlock(&ar_sdio->dma_buffer_mutex);
 
return ret;
 }
@@ -1978,6 +2021,12 @@ static int ath10k_sdio_probe(struct sdio_func *func,
goto err_free_en_reg;
}
 
+   ar_sdio->dma_buffer = kzalloc(ATH10K_SDIO_DMA_BUF_SIZE, GFP_KERNEL);
+   if (!ar_sdio->dma_buffer) {
+   ret = -ENOMEM;
+   goto err_free_bmi_buf;
+   }
+
ar_sdio->func = func;
sdio_set_drvdata(func, ar_sdio);
 
@@ -1987,6 +2036,7 @@ static int ath10k_sdio_probe(struct sdio_func *func,
spin_lock_init(&ar_sdio->lock);
spin_lock_init(&ar_sdio->wr_async_lock);
mutex_init(&ar_sdio->irq_data.mtx);
+   mutex_init(&ar_sdio->dma_buffer_mutex);
 
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
INIT_LIST_HEAD(&ar_sdio->wr_asyncq);
@@ -1995,7 +2045,7 @@ static int ath10k_sdio_probe(struct sdio_func *func,
ar_sdio->workqueue = create_singlethread_workqueue("ath10k_sdio_wq");
if (!ar_sdio->workqueue) {
ret = -ENOMEM;
-   goto err_free_bmi_buf;
+   goto