summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2017-02-19 09:46:35 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-02-19 09:46:35 -0800
commit3436baed8436f303571ed5dc0027fb9b799915bd (patch)
treed95095cf58cd939f6d54c826acf0140ef2062067 /drivers
parent6f0b536eb7c5a7c7e8ae42418ec8e234a61920f1 (diff)
parentbdd8861bc054bec8512cc325becff160d326de34 (diff)
Merge "ath10k: Add support for shadow register for WNC3990"
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c111
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h61
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c54
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h57
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c24
7 files changed, 303 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index e5213de8a686..7e5e25e96762 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
- * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, 2017 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -90,6 +90,20 @@ static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar,
return ar->bus_read32(ar, ce_ctrl_addr + CURRENT_SRRI_ADDRESS);
}
+static inline void ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar,
+ u32 ce_ctrl_addr,
+ unsigned int n)
+{
+ ar->bus_write32(ar, shadow_sr_wr_ind_addr(ar, ce_ctrl_addr), n);
+}
+
+static inline void ath10k_ce_shadow_dest_ring_write_index_set(struct ath10k *ar,
+ u32 ce_ctrl_addr,
+ unsigned int n)
+{
+ ar->bus_write32(ar, shadow_dst_wr_ind_addr(ar, ce_ctrl_addr), n);
+}
+
static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar,
u32 ce_ctrl_addr,
unsigned int addr)
@@ -259,6 +273,72 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
ar->bus_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask);
}
+u32 shadow_sr_wr_ind_addr(struct ath10k *ar, u32 ctrl_addr)
+{
+ u32 addr = 0;
+ u32 ce = COPY_ENGINE_ID(ctrl_addr);
+
+ switch (ce) {
+ case 0:
+ addr = SHADOW_VALUE0;
+ break;
+ case 3:
+ addr = SHADOW_VALUE3;
+ break;
+ case 4:
+ addr = SHADOW_VALUE4;
+ break;
+ case 5:
+ addr = SHADOW_VALUE5;
+ break;
+ case 7:
+ addr = SHADOW_VALUE7;
+ break;
+ default:
+ ath10k_err(ar, "invalid CE ctrl_addr (CE=%d)", ce);
+ WARN_ON(1);
+ }
+ return addr;
+}
+
+u32 shadow_dst_wr_ind_addr(struct ath10k *ar, u32 ctrl_addr)
+{
+ u32 addr = 0;
+ u32 ce = COPY_ENGINE_ID(ctrl_addr);
+
+ switch (ce) {
+ case 1:
+ addr = SHADOW_VALUE13;
+ break;
+ case 2:
+ addr = SHADOW_VALUE14;
+ break;
+ case 5:
+ addr = SHADOW_VALUE17;
+ break;
+ case 7:
+ addr = SHADOW_VALUE19;
+ break;
+ case 8:
+ addr = SHADOW_VALUE20;
+ break;
+ case 9:
+ addr = SHADOW_VALUE21;
+ break;
+ case 10:
+ addr = SHADOW_VALUE22;
+ break;
+ case 11:
+ addr = SHADOW_VALUE23;
+ break;
+ default:
+ ath10k_err(ar, "invalid CE ctrl_addr (CE=%d)", ce);
+ WARN_ON(1);
+ }
+
+ return addr;
+}
+
/*
* Guts of ath10k_ce_send, used by both ath10k_ce_send and
* ath10k_ce_sendlist_send.
@@ -325,8 +405,14 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
/* WORKAROUND */
- if (!(flags & CE_SEND_FLAG_GATHER))
- ath10k_ce_src_ring_write_index_set(ar, ctrl_addr, write_index);
+ if (!(flags & CE_SEND_FLAG_GATHER)) {
+ if (QCA_REV_WCN3990(ar))
+ ath10k_ce_shadow_src_ring_write_index_set(ar, ctrl_addr,
+ write_index);
+ else
+ ath10k_ce_src_ring_write_index_set(ar, ctrl_addr,
+ write_index);
+ }
src_ring->write_index = write_index;
exit:
@@ -957,6 +1043,24 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
src_ring->base_addr_ce_space_unaligned,
CE_DESC_RING_ALIGN);
+ src_ring->shadow_base_unaligned = kzalloc(
+ nentries * sizeof(struct ce_desc),
+ GFP_KERNEL);
+
+ if (!src_ring->shadow_base_unaligned) {
+ dma_free_coherent(ar->dev,
+ (nentries * sizeof(struct ce_desc) +
+ CE_DESC_RING_ALIGN),
+ src_ring->base_addr_owner_space_unaligned,
+ base_addr);
+ kfree(src_ring);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ src_ring->shadow_base = (struct ce_desc *)PTR_ALIGN(
+ src_ring->shadow_base_unaligned,
+ CE_DESC_RING_ALIGN);
+
return src_ring;
}
@@ -1135,6 +1239,7 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id)
((struct ath10k_ce_pipe *)ar->ce_states + ce_id);
if (ce_state->src_ring) {
+ kfree(ce_state->src_ring->shadow_base_unaligned);
dma_free_coherent(ar->dev,
(ce_state->src_ring->nentries *
sizeof(struct ce_desc) +
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 1b49db14d387..160a13e681df 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -120,6 +120,9 @@ struct ath10k_ce_ring {
/* CE address space */
u32 base_addr_ce_space;
+ char *shadow_base_unaligned;
+ struct ce_desc *shadow_base;
+
/* keep last */
void *per_transfer_context[0];
};
@@ -143,6 +146,61 @@ struct ath10k_ce_pipe {
/* Copy Engine settable attributes */
struct ce_attr;
+#define SHADOW_VALUE0 (ar->shadow_reg_value->shadow_reg_value_0)
+#define SHADOW_VALUE1 (ar->shadow_reg_value->shadow_reg_value_1)
+#define SHADOW_VALUE2 (ar->shadow_reg_value->shadow_reg_value_2)
+#define SHADOW_VALUE3 (ar->shadow_reg_value->shadow_reg_value_3)
+#define SHADOW_VALUE4 (ar->shadow_reg_value->shadow_reg_value_4)
+#define SHADOW_VALUE5 (ar->shadow_reg_value->shadow_reg_value_5)
+#define SHADOW_VALUE6 (ar->shadow_reg_value->shadow_reg_value_6)
+#define SHADOW_VALUE7 (ar->shadow_reg_value->shadow_reg_value_7)
+#define SHADOW_VALUE8 (ar->shadow_reg_value->shadow_reg_value_8)
+#define SHADOW_VALUE9 (ar->shadow_reg_value->shadow_reg_value_9)
+#define SHADOW_VALUE10 (ar->shadow_reg_value->shadow_reg_value_10)
+#define SHADOW_VALUE11 (ar->shadow_reg_value->shadow_reg_value_11)
+#define SHADOW_VALUE12 (ar->shadow_reg_value->shadow_reg_value_12)
+#define SHADOW_VALUE13 (ar->shadow_reg_value->shadow_reg_value_13)
+#define SHADOW_VALUE14 (ar->shadow_reg_value->shadow_reg_value_14)
+#define SHADOW_VALUE15 (ar->shadow_reg_value->shadow_reg_value_15)
+#define SHADOW_VALUE16 (ar->shadow_reg_value->shadow_reg_value_16)
+#define SHADOW_VALUE17 (ar->shadow_reg_value->shadow_reg_value_17)
+#define SHADOW_VALUE18 (ar->shadow_reg_value->shadow_reg_value_18)
+#define SHADOW_VALUE19 (ar->shadow_reg_value->shadow_reg_value_19)
+#define SHADOW_VALUE20 (ar->shadow_reg_value->shadow_reg_value_20)
+#define SHADOW_VALUE21 (ar->shadow_reg_value->shadow_reg_value_21)
+#define SHADOW_VALUE22 (ar->shadow_reg_value->shadow_reg_value_22)
+#define SHADOW_VALUE23 (ar->shadow_reg_value->shadow_reg_value_23)
+#define SHADOW_ADDRESS0 (ar->shadow_reg_address->shadow_reg_address_0)
+#define SHADOW_ADDRESS1 (ar->shadow_reg_address->shadow_reg_address_1)
+#define SHADOW_ADDRESS2 (ar->shadow_reg_address->shadow_reg_address_2)
+#define SHADOW_ADDRESS3 (ar->shadow_reg_address->shadow_reg_address_3)
+#define SHADOW_ADDRESS4 (ar->shadow_reg_address->shadow_reg_address_4)
+#define SHADOW_ADDRESS5 (ar->shadow_reg_address->shadow_reg_address_5)
+#define SHADOW_ADDRESS6 (ar->shadow_reg_address->shadow_reg_address_6)
+#define SHADOW_ADDRESS7 (ar->shadow_reg_address->shadow_reg_address_7)
+#define SHADOW_ADDRESS8 (ar->shadow_reg_address->shadow_reg_address_8)
+#define SHADOW_ADDRESS9 (ar->shadow_reg_address->shadow_reg_address_9)
+#define SHADOW_ADDRESS10 (ar->shadow_reg_address->shadow_reg_address_10)
+#define SHADOW_ADDRESS11 (ar->shadow_reg_address->shadow_reg_address_11)
+#define SHADOW_ADDRESS12 (ar->shadow_reg_address->shadow_reg_address_12)
+#define SHADOW_ADDRESS13 (ar->shadow_reg_address->shadow_reg_address_13)
+#define SHADOW_ADDRESS14 (ar->shadow_reg_address->shadow_reg_address_14)
+#define SHADOW_ADDRESS15 (ar->shadow_reg_address->shadow_reg_address_15)
+#define SHADOW_ADDRESS16 (ar->shadow_reg_address->shadow_reg_address_16)
+#define SHADOW_ADDRESS17 (ar->shadow_reg_address->shadow_reg_address_17)
+#define SHADOW_ADDRESS18 (ar->shadow_reg_address->shadow_reg_address_18)
+#define SHADOW_ADDRESS19 (ar->shadow_reg_address->shadow_reg_address_19)
+#define SHADOW_ADDRESS20 (ar->shadow_reg_address->shadow_reg_address_20)
+#define SHADOW_ADDRESS21 (ar->shadow_reg_address->shadow_reg_address_21)
+#define SHADOW_ADDRESS22 (ar->shadow_reg_address->shadow_reg_address_22)
+#define SHADOW_ADDRESS23 (ar->shadow_reg_address->shadow_reg_address_23)
+
+#define SHADOW_ADDRESS(i) (SHADOW_ADDRESS0 + \
+ i * (SHADOW_ADDRESS1 - SHADOW_ADDRESS0))
+
+u32 shadow_sr_wr_ind_addr(struct ath10k *ar, u32 ctrl_addr);
+u32 shadow_dst_wr_ind_addr(struct ath10k *ar, u32 ctrl_addr);
+
/*==================Send====================*/
/* ath10k_ce_send flags */
@@ -591,6 +649,9 @@ struct ce_attr {
& (uint64_t)(0xF00000000)) >> 32))
#endif
+#define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) ((COPY_ENGINE_BASE_ADDRESS \
+ - CE0_BASE_ADDRESS) / (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS))
+
static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
{
return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id;
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 0803a963da3c..052ebd7dd26b 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2350,6 +2350,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
/* WCN3990 chip set is non bmi based */
ar->is_bmi = false;
ar->fw_flags = &wcn3990_fw_flags;
+ ar->shadow_reg_value = &wcn3990_shadow_reg_value;
+ ar->shadow_reg_address = &wcn3990_shadow_reg_address;
break;
default:
ath10k_err(ar, "unsupported core hardware revision %d\n",
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index f2f0338696e0..bb2c5fb9a125 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -741,6 +741,8 @@ struct ath10k {
const struct ath10k_hw_regs *regs;
const struct ath10k_hw_values *hw_values;
+ struct ath10k_shadow_reg_value *shadow_reg_value;
+ struct ath10k_shadow_reg_address *shadow_reg_address;
struct ath10k_bmi bmi;
struct ath10k_wmi wmi;
struct ath10k_htc htc;
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 0cd1068b0beb..1a8f3a388ce2 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -220,6 +220,60 @@ struct fw_flag wcn3990_fw_flags = {
.flags = 0x82E,
};
+struct ath10k_shadow_reg_value wcn3990_shadow_reg_value = {
+ .shadow_reg_value_0 = 0x00032000,
+ .shadow_reg_value_1 = 0x00032004,
+ .shadow_reg_value_2 = 0x00032008,
+ .shadow_reg_value_3 = 0x0003200C,
+ .shadow_reg_value_4 = 0x00032010,
+ .shadow_reg_value_5 = 0x00032014,
+ .shadow_reg_value_6 = 0x00032018,
+ .shadow_reg_value_7 = 0x0003201C,
+ .shadow_reg_value_8 = 0x00032020,
+ .shadow_reg_value_9 = 0x00032024,
+ .shadow_reg_value_10 = 0x00032028,
+ .shadow_reg_value_11 = 0x0003202C,
+ .shadow_reg_value_12 = 0x00032030,
+ .shadow_reg_value_13 = 0x00032034,
+ .shadow_reg_value_14 = 0x00032038,
+ .shadow_reg_value_15 = 0x0003203C,
+ .shadow_reg_value_16 = 0x00032040,
+ .shadow_reg_value_17 = 0x00032044,
+ .shadow_reg_value_18 = 0x00032048,
+ .shadow_reg_value_19 = 0x0003204C,
+ .shadow_reg_value_20 = 0x00032050,
+ .shadow_reg_value_21 = 0x00032054,
+ .shadow_reg_value_22 = 0x00032058,
+ .shadow_reg_value_23 = 0x0003205C
+};
+
+struct ath10k_shadow_reg_address wcn3990_shadow_reg_address = {
+ .shadow_reg_address_0 = 0x00030020,
+ .shadow_reg_address_1 = 0x00030024,
+ .shadow_reg_address_2 = 0x00030028,
+ .shadow_reg_address_3 = 0x0003002C,
+ .shadow_reg_address_4 = 0x00030030,
+ .shadow_reg_address_5 = 0x00030034,
+ .shadow_reg_address_6 = 0x00030038,
+ .shadow_reg_address_7 = 0x0003003C,
+ .shadow_reg_address_8 = 0x00030040,
+ .shadow_reg_address_9 = 0x00030044,
+ .shadow_reg_address_10 = 0x00030048,
+ .shadow_reg_address_11 = 0x0003004C,
+ .shadow_reg_address_12 = 0x00030050,
+ .shadow_reg_address_13 = 0x00030054,
+ .shadow_reg_address_14 = 0x00030058,
+ .shadow_reg_address_15 = 0x0003005C,
+ .shadow_reg_address_16 = 0x00030060,
+ .shadow_reg_address_17 = 0x00030064,
+ .shadow_reg_address_18 = 0x00030068,
+ .shadow_reg_address_19 = 0x0003006C,
+ .shadow_reg_address_20 = 0x00030070,
+ .shadow_reg_address_21 = 0x00030074,
+ .shadow_reg_address_22 = 0x00030078,
+ .shadow_reg_address_23 = 0x0003007C
+};
+
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
{
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index b59bde40714c..ce87f8112928 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -835,4 +835,61 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
#define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
+struct ath10k_shadow_reg_value {
+ u32 shadow_reg_value_0;
+ u32 shadow_reg_value_1;
+ u32 shadow_reg_value_2;
+ u32 shadow_reg_value_3;
+ u32 shadow_reg_value_4;
+ u32 shadow_reg_value_5;
+ u32 shadow_reg_value_6;
+ u32 shadow_reg_value_7;
+ u32 shadow_reg_value_8;
+ u32 shadow_reg_value_9;
+ u32 shadow_reg_value_10;
+ u32 shadow_reg_value_11;
+ u32 shadow_reg_value_12;
+ u32 shadow_reg_value_13;
+ u32 shadow_reg_value_14;
+ u32 shadow_reg_value_15;
+ u32 shadow_reg_value_16;
+ u32 shadow_reg_value_17;
+ u32 shadow_reg_value_18;
+ u32 shadow_reg_value_19;
+ u32 shadow_reg_value_20;
+ u32 shadow_reg_value_21;
+ u32 shadow_reg_value_22;
+ u32 shadow_reg_value_23;
+};
+
+struct ath10k_shadow_reg_address {
+ u32 shadow_reg_address_0;
+ u32 shadow_reg_address_1;
+ u32 shadow_reg_address_2;
+ u32 shadow_reg_address_3;
+ u32 shadow_reg_address_4;
+ u32 shadow_reg_address_5;
+ u32 shadow_reg_address_6;
+ u32 shadow_reg_address_7;
+ u32 shadow_reg_address_8;
+ u32 shadow_reg_address_9;
+ u32 shadow_reg_address_10;
+ u32 shadow_reg_address_11;
+ u32 shadow_reg_address_12;
+ u32 shadow_reg_address_13;
+ u32 shadow_reg_address_14;
+ u32 shadow_reg_address_15;
+ u32 shadow_reg_address_16;
+ u32 shadow_reg_address_17;
+ u32 shadow_reg_address_18;
+ u32 shadow_reg_address_19;
+ u32 shadow_reg_address_20;
+ u32 shadow_reg_address_21;
+ u32 shadow_reg_address_22;
+ u32 shadow_reg_address_23;
+};
+
+extern struct ath10k_shadow_reg_value wcn3990_shadow_reg_value;
+extern struct ath10k_shadow_reg_address wcn3990_shadow_reg_address;
+
#endif /* _HW_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index be8ec97574f0..6c8797d5e5fc 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -395,10 +395,23 @@ static struct service_to_pipe target_service_to_ce_map_wlan[] = {
},
};
-#define ADRASTEA_SRC_WR_INDEX_OFFSET 0x3C
-#define ADRASTEA_DST_WR_INDEX_OFFSET 0x40
-
-static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = { };
+#define WCN3990_SRC_WR_INDEX_OFFSET 0x3C
+#define WCN3990_DST_WR_INDEX_OFFSET 0x40
+
+static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {
+ { 0, WCN3990_SRC_WR_INDEX_OFFSET},
+ { 3, WCN3990_SRC_WR_INDEX_OFFSET},
+ { 4, WCN3990_SRC_WR_INDEX_OFFSET},
+ { 5, WCN3990_SRC_WR_INDEX_OFFSET},
+ { 7, WCN3990_SRC_WR_INDEX_OFFSET},
+ { 1, WCN3990_DST_WR_INDEX_OFFSET},
+ { 2, WCN3990_DST_WR_INDEX_OFFSET},
+ { 7, WCN3990_DST_WR_INDEX_OFFSET},
+ { 8, WCN3990_DST_WR_INDEX_OFFSET},
+ { 9, WCN3990_DST_WR_INDEX_OFFSET},
+ { 10, WCN3990_DST_WR_INDEX_OFFSET},
+ { 11, WCN3990_DST_WR_INDEX_OFFSET},
+};
void ath10k_snoc_write32(void *ar, u32 offset, u32 value)
{
@@ -1048,7 +1061,8 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar)
sizeof(struct ce_svc_pipe_cfg);
cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)
&target_service_to_ce_map_wlan;
- cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map);
+ cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) /
+ sizeof(struct icnss_shadow_reg_cfg);
cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *)
&target_shadow_reg_cfg_map;