Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c041646 authored by Govind Singh's avatar Govind Singh Committed by Gerrit - the friendly Code Review server
Browse files

ath10k: Enable SRRI/DRRI support on ddr



The SRRI/DRRI can be read from DDR instead of doing an
actual hardware read. Host allocates non cached memory
on ddr and sends the physical address of this memory to
the CE hardware. The hardware updates the RRI on this
particular location. Target registers are not accessible
during CSS shutdown while target is in idle mode. Direct
access to SRRI/DRRI can lead to NOC error in target idle
state. Read SRRI/DRRI from DDR location instead of
direct target read.

Change-Id: Iae3772fb6408469c5f9db8a9210d3ab6ea35eccf
Signed-off-by: default avatarGovind Singh <govinds@codeaurora.org>
Signed-off-by: default avatarRakesh Pillai <pillair@codeaurora.org>
parent 74b6b84c
Loading
Loading
Loading
Loading
+76 −3
Original line number Original line Diff line number Diff line
@@ -96,13 +96,29 @@ static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar,
			ce_ctrl_addr + ar->hw_ce_regs->sr_wr_index_addr);
			ce_ctrl_addr + ar->hw_ce_regs->sr_wr_index_addr);
}
}


static inline u32 ath10k_ce_src_ring_read_index_get_from_ddr(
				struct ath10k *ar, u32 ce_id)
{
	struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);

	return ar_opaque->vaddr_rri_on_ddr[ce_id] & CE_DDR_RRI_MASK;
}

static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar,
static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar,
						    u32 ce_ctrl_addr)
						    u32 ce_ctrl_addr)
{
{
	struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
	struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
	u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr);
	struct ath10k_ce_pipe *ce_state = &ar_opaque->ce_states[ce_id];
	u32 index;


	return ar_opaque->bus_ops->read32(ar,
	if (ar->rri_on_ddr && (ce_state->attr_flags & CE_ATTR_DIS_INTR))
		index = ath10k_ce_src_ring_read_index_get_from_ddr(ar, ce_id);
	else
		index = ar_opaque->bus_ops->read32(ar,
			ce_ctrl_addr + ar->hw_ce_regs->current_srri_addr);
			ce_ctrl_addr + ar->hw_ce_regs->current_srri_addr);

	return index;
}
}


static inline void ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar,
static inline void ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar,
@@ -195,9 +211,19 @@ static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar,
						     u32 ce_ctrl_addr)
						     u32 ce_ctrl_addr)
{
{
	struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
	struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
	u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr);
	struct ath10k_ce_pipe *ce_state = &ar_opaque->ce_states[ce_id];
	u32 index;


	return ar_opaque->bus_ops->read32(ar,
	if (ar->rri_on_ddr && (ce_state->attr_flags & CE_ATTR_DIS_INTR))
		index = (ar_opaque->vaddr_rri_on_ddr[ce_id] >>
			  CE_DDR_RRI_SHIFT) &
			  CE_DDR_RRI_MASK;
	else
		index = ar_opaque->bus_ops->read32(ar,
			ce_ctrl_addr + ar->hw_ce_regs->current_drri_addr);
			ce_ctrl_addr + ar->hw_ce_regs->current_drri_addr);

	return index;
}
}


static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar,
static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar,
@@ -449,7 +475,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
	struct ath10k_ce_ring *src_ring = ce_state->src_ring;
	struct ath10k_ce_ring *src_ring = ce_state->src_ring;
	struct ce_desc *desc, sdesc;
	struct ce_desc *desc, sdesc;
	unsigned int nentries_mask = src_ring->nentries_mask;
	unsigned int nentries_mask = src_ring->nentries_mask;
	unsigned int sw_index = src_ring->sw_index;
	unsigned int sw_index;
	unsigned int write_index = src_ring->write_index;
	unsigned int write_index = src_ring->write_index;
	u32 ctrl_addr = ce_state->ctrl_addr;
	u32 ctrl_addr = ce_state->ctrl_addr;
	u32 desc_flags = 0;
	u32 desc_flags = 0;
@@ -462,6 +488,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
		ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
		ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
			    __func__, nbytes, ce_state->src_sz_max);
			    __func__, nbytes, ce_state->src_sz_max);


	sw_index = ath10k_ce_src_ring_read_index_get_from_ddr(ar, ce_state->id);
	if (unlikely(CE_RING_DELTA(nentries_mask,
	if (unlikely(CE_RING_DELTA(nentries_mask,
				   write_index, sw_index - 1) <= 0)) {
				   write_index, sw_index - 1) <= 0)) {
		ret = -ENOSR;
		ret = -ENOSR;
@@ -1235,6 +1262,52 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
	return dest_ring;
	return dest_ring;
}
}


void ce_config_rri_on_ddr(struct ath10k *ar)
{
	struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
	u32 hi_paddr, low_paddr;
	u32 ce_base_addr;
	u32 ctrl1_regs;
	int i;

	ar_opaque->vaddr_rri_on_ddr =
		(u32 *)dma_alloc_coherent(ar->dev,
		(CE_COUNT * sizeof(u32)),
		&ar_opaque->paddr_rri_on_ddr, GFP_KERNEL);

	if (!ar_opaque->vaddr_rri_on_ddr)
		return;

	low_paddr  = lower_32_bits(ar_opaque->paddr_rri_on_ddr);
	hi_paddr = upper_32_bits(ar_opaque->paddr_rri_on_ddr) &
					CE_DESC_FLAGS_GET_MASK;

	ar_opaque->bus_ops->write32(ar, ar->hw_ce_regs->ce_rri_low, low_paddr);
	ar_opaque->bus_ops->write32(ar, ar->hw_ce_regs->ce_rri_high, hi_paddr);

	for (i = 0; i < CE_COUNT; i++) {
		ctrl1_regs = ar->hw_ce_regs->ctrl1_regs->addr;
		ce_base_addr = ath10k_ce_base_address(ar, i);
		ar_opaque->bus_ops->write32(ar, ce_base_addr + ctrl1_regs,
		ar_opaque->bus_ops->read32(ar, ce_base_addr + ctrl1_regs) |
		ar->hw_ce_regs->upd->mask);
	}

	memset(ar_opaque->vaddr_rri_on_ddr, 0, CE_COUNT * sizeof(u32));
}

void ce_remove_rri_on_ddr(struct ath10k *ar)
{
	struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);

	if (!ar_opaque->vaddr_rri_on_ddr)
		return;

	dma_free_coherent(ar->dev, (CE_COUNT * sizeof(u32)),
			  ar_opaque->vaddr_rri_on_ddr,
			  ar_opaque->paddr_rri_on_ddr);
}

/*
/*
 * Initialize a Copy Engine based on caller-supplied attributes.
 * Initialize a Copy Engine based on caller-supplied attributes.
 * This may be called once to initialize both source and destination
 * This may be called once to initialize both source and destination
+6 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,8 @@ struct ath10k_ce_pipe;


#define CE_DESC_FLAGS_GET_MASK		0x1F
#define CE_DESC_FLAGS_GET_MASK		0x1F
#define CE_DESC_37BIT_ADDR_MASK		0x1FFFFFFFFF
#define CE_DESC_37BIT_ADDR_MASK		0x1FFFFFFFFF
#define CE_DDR_RRI_MASK			0xFFFF
#define CE_DDR_RRI_SHIFT		16


/* Following desc flags are used in QCA99X0 */
/* Following desc flags are used in QCA99X0 */
#define CE_DESC_FLAGS_HOST_INT_DIS	(1 << 2)
#define CE_DESC_FLAGS_HOST_INT_DIS	(1 << 2)
@@ -211,6 +213,8 @@ struct bus_opaque {
	spinlock_t ce_lock;
	spinlock_t ce_lock;
	const struct ath10k_bus_ops *bus_ops;
	const struct ath10k_bus_ops *bus_ops;
	struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
	struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
	u32 *vaddr_rri_on_ddr;
	dma_addr_t paddr_rri_on_ddr;
};
};


/*==================Send====================*/
/*==================Send====================*/
@@ -288,6 +292,8 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
			 const struct ce_attr *attr);
			 const struct ce_attr *attr);
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
void ce_config_rri_on_ddr(struct ath10k *ar);
void ce_remove_rri_on_ddr(struct ath10k *ar);


/*==================CE Engine Shutdown=======================*/
/*==================CE Engine Shutdown=======================*/
/*
/*
+1 −0
Original line number Original line Diff line number Diff line
@@ -2374,6 +2374,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
		ar->fw_flags = &wcn3990_fw_flags;
		ar->fw_flags = &wcn3990_fw_flags;
		ar->shadow_reg_value = &wcn3990_shadow_reg_value;
		ar->shadow_reg_value = &wcn3990_shadow_reg_value;
		ar->shadow_reg_address = &wcn3990_shadow_reg_address;
		ar->shadow_reg_address = &wcn3990_shadow_reg_address;
		ar->rri_on_ddr = true;
		break;
		break;
	default:
	default:
		ath10k_err(ar, "unsupported core hardware revision %d\n",
		ath10k_err(ar, "unsupported core hardware revision %d\n",
+1 −0
Original line number Original line Diff line number Diff line
@@ -967,6 +967,7 @@ struct ath10k {
	struct completion peer_delete_done;
	struct completion peer_delete_done;
	bool is_bmi;
	bool is_bmi;
	enum ieee80211_sta_state sta_state;
	enum ieee80211_sta_state sta_state;
	bool rri_on_ddr;
	/* must be last */
	/* must be last */
	u8 drv_priv[0] __aligned(sizeof(void *));
	u8 drv_priv[0] __aligned(sizeof(void *));
};
};
+7 −0
Original line number Original line Diff line number Diff line
@@ -284,6 +284,12 @@ struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_dst_ring = {
	.wm_high	= &wcn3990_dst_wm_high,
	.wm_high	= &wcn3990_dst_wm_high,
};
};


static struct ath10k_hw_ce_ctrl1_upd wcn3990_ctrl1_upd = {
	.shift = 19,
	.mask = 0x00080000,
	.enable = 0x00000000,
};

struct ath10k_hw_ce_regs wcn3990_ce_regs = {
struct ath10k_hw_ce_regs wcn3990_ce_regs = {
	.sr_base_addr		= 0x00000000,
	.sr_base_addr		= 0x00000000,
	.sr_size_addr		= 0x00000008,
	.sr_size_addr		= 0x00000008,
@@ -305,6 +311,7 @@ struct ath10k_hw_ce_regs wcn3990_ce_regs = {
	.misc_regs		= &wcn3990_misc_reg,
	.misc_regs		= &wcn3990_misc_reg,
	.wm_srcr		= &wcn3990_wm_src_ring,
	.wm_srcr		= &wcn3990_wm_src_ring,
	.wm_dstr		= &wcn3990_wm_dst_ring,
	.wm_dstr		= &wcn3990_wm_dst_ring,
	.upd			= &wcn3990_ctrl1_upd,
};
};


struct ath10k_hw_ce_regs_addr_map qcax_src_ring = {
struct ath10k_hw_ce_regs_addr_map qcax_src_ring = {
Loading