ath10k: add support for shadow register for WNC3990

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

Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Rakesh Pillai 2018-04-17 17:36:59 +05:30 committed by Kalle Valo
parent b2e40d7ab8
commit b7ba83f7c4
2 changed files with 145 additions and 2 deletions

View File

@ -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) +

View File

@ -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
@ -113,6 +114,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];
};