|
@@ -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
|
|
@@ -58,6 +59,74 @@
|
|
|
* the buffer is sent/received.
|
|
|
*/
|
|
|
|
|
|
+static inline u32 shadow_sr_wr_ind_addr(struct ath10k *ar,
|
|
|
+ struct ath10k_ce_pipe *ce_state)
|
|
|
+{
|
|
|
+ u32 ce_id = ce_state->id;
|
|
|
+ u32 addr = 0;
|
|
|
+
|
|
|
+ switch (ce_id) {
|
|
|
+ case 0:
|
|
|
+ addr = 0x00032000;
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ addr = 0x0003200C;
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ addr = 0x00032010;
|
|
|
+ break;
|
|
|
+ case 5:
|
|
|
+ addr = 0x00032014;
|
|
|
+ break;
|
|
|
+ case 7:
|
|
|
+ addr = 0x0003201C;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ath10k_warn(ar, "invalid CE id: %d", ce_id);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return addr;
|
|
|
+}
|
|
|
+
|
|
|
+static inline u32 shadow_dst_wr_ind_addr(struct ath10k *ar,
|
|
|
+ struct ath10k_ce_pipe *ce_state)
|
|
|
+{
|
|
|
+ u32 ce_id = ce_state->id;
|
|
|
+ u32 addr = 0;
|
|
|
+
|
|
|
+ switch (ce_id) {
|
|
|
+ case 1:
|
|
|
+ addr = 0x00032034;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ addr = 0x00032038;
|
|
|
+ break;
|
|
|
+ case 5:
|
|
|
+ addr = 0x00032044;
|
|
|
+ break;
|
|
|
+ case 7:
|
|
|
+ addr = 0x0003204C;
|
|
|
+ break;
|
|
|
+ case 8:
|
|
|
+ addr = 0x00032050;
|
|
|
+ break;
|
|
|
+ case 9:
|
|
|
+ addr = 0x00032054;
|
|
|
+ break;
|
|
|
+ case 10:
|
|
|
+ addr = 0x00032058;
|
|
|
+ break;
|
|
|
+ case 11:
|
|
|
+ addr = 0x0003205C;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ath10k_warn(ar, "invalid CE id: %d", ce_id);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return addr;
|
|
|
+}
|
|
|
+
|
|
|
static inline unsigned int
|
|
|
ath10k_set_ring_byte(unsigned int offset,
|
|
|
struct ath10k_hw_ce_regs_addr_map *addr_map)
|
|
@@ -123,6 +192,22 @@ static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar,
|
|
|
ar->hw_ce_regs->current_srri_addr);
|
|
|
}
|
|
|
|
|
|
+static inline void
|
|
|
+ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar,
|
|
|
+ struct ath10k_ce_pipe *ce_state,
|
|
|
+ unsigned int value)
|
|
|
+{
|
|
|
+ ath10k_ce_write32(ar, shadow_sr_wr_ind_addr(ar, ce_state), value);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void
|
|
|
+ath10k_ce_shadow_dest_ring_write_index_set(struct ath10k *ar,
|
|
|
+ struct ath10k_ce_pipe *ce_state,
|
|
|
+ unsigned int value)
|
|
|
+{
|
|
|
+ ath10k_ce_write32(ar, shadow_dst_wr_ind_addr(ar, ce_state), value);
|
|
|
+}
|
|
|
+
|
|
|
static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar,
|
|
|
u32 ce_ctrl_addr,
|
|
|
unsigned int addr)
|
|
@@ -376,8 +461,14 @@ static 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 (ar->hw_params.shadow_reg_support)
|
|
|
+ ath10k_ce_shadow_src_ring_write_index_set(ar, ce_state,
|
|
|
+ write_index);
|
|
|
+ else
|
|
|
+ ath10k_ce_src_ring_write_index_set(ar, ctrl_addr,
|
|
|
+ write_index);
|
|
|
+ }
|
|
|
|
|
|
src_ring->write_index = write_index;
|
|
|
exit:
|
|
@@ -1251,6 +1342,22 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int ath10k_ce_alloc_shadow_base(struct ath10k *ar,
|
|
|
+ struct ath10k_ce_ring *src_ring,
|
|
|
+ u32 nentries)
|
|
|
+{
|
|
|
+ src_ring->shadow_base_unaligned = kcalloc(nentries,
|
|
|
+ sizeof(struct ce_desc),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!src_ring->shadow_base_unaligned)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ src_ring->shadow_base = (struct ce_desc *)
|
|
|
+ PTR_ALIGN(src_ring->shadow_base_unaligned,
|
|
|
+ CE_DESC_RING_ALIGN);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct ath10k_ce_ring *
|
|
|
ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
|
|
|
const struct ce_attr *attr)
|
|
@@ -1258,6 +1365,7 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
|
|
|
struct ath10k_ce_ring *src_ring;
|
|
|
u32 nentries = attr->src_nentries;
|
|
|
dma_addr_t base_addr;
|
|
|
+ int ret;
|
|
|
|
|
|
nentries = roundup_pow_of_two(nentries);
|
|
|
|
|
@@ -1294,6 +1402,19 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
|
|
|
ALIGN(src_ring->base_addr_ce_space_unaligned,
|
|
|
CE_DESC_RING_ALIGN);
|
|
|
|
|
|
+ if (ar->hw_params.shadow_reg_support) {
|
|
|
+ ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries);
|
|
|
+ if (ret) {
|
|
|
+ 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(ret);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return src_ring;
|
|
|
}
|
|
|
|
|
@@ -1304,6 +1425,7 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id,
|
|
|
struct ath10k_ce_ring *src_ring;
|
|
|
u32 nentries = attr->src_nentries;
|
|
|
dma_addr_t base_addr;
|
|
|
+ int ret;
|
|
|
|
|
|
nentries = roundup_pow_of_two(nentries);
|
|
|
|
|
@@ -1339,6 +1461,19 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id,
|
|
|
ALIGN(src_ring->base_addr_ce_space_unaligned,
|
|
|
CE_DESC_RING_ALIGN);
|
|
|
|
|
|
+ if (ar->hw_params.shadow_reg_support) {
|
|
|
+ ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries);
|
|
|
+ if (ret) {
|
|
|
+ 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(ret);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return src_ring;
|
|
|
}
|
|
|
|
|
@@ -1505,6 +1640,8 @@ static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id)
|
|
|
struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id];
|
|
|
|
|
|
if (ce_state->src_ring) {
|
|
|
+ if (ar->hw_params.shadow_reg_support)
|
|
|
+ kfree(ce_state->src_ring->shadow_base_unaligned);
|
|
|
dma_free_coherent(ar->dev,
|
|
|
(ce_state->src_ring->nentries *
|
|
|
sizeof(struct ce_desc) +
|
|
@@ -1534,6 +1671,8 @@ static void _ath10k_ce_free_pipe_64(struct ath10k *ar, int ce_id)
|
|
|
struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id];
|
|
|
|
|
|
if (ce_state->src_ring) {
|
|
|
+ if (ar->hw_params.shadow_reg_support)
|
|
|
+ kfree(ce_state->src_ring->shadow_base_unaligned);
|
|
|
dma_free_coherent(ar->dev,
|
|
|
(ce_state->src_ring->nentries *
|
|
|
sizeof(struct ce_desc_64) +
|