OSDN Git Service

ath10k: Add support for shadow register for WNC3990
authorRakesh Pillai <pillair@codeaurora.org>
Fri, 3 Feb 2017 07:36:22 +0000 (13:06 +0530)
committerGerrit - the friendly Code Review server <code-review@localhost>
Fri, 17 Feb 2017 14:36:37 +0000 (06:36 -0800)
WCN3990 needs shadow register write operation support
for copy engine for regular operation in powersave mode.
Add support for copy engine shadow register write in
datapath tx for WCN3990

CRs-Fixed: 2008518
Change-Id: Ie90ff74984021fa47070e08b2fc53ad5da46cf35
Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.h
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/hw.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/snoc.c

index e5213de..7e5e25e 100644 (file)
@@ -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) +
index 1b49db1..160a13e 100644 (file)
@@ -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;
index 0803a96..052ebd7 100644 (file)
@@ -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",
index f2f0338..bb2c5fb 100644 (file)
@@ -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;
index 0cd1068..1a8f3a3 100644 (file)
@@ -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)
 {
index b59bde4..ce87f81 100644 (file)
@@ -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_ */
index be8ec97..6c8797d 100644 (file)
@@ -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;