Commit e838c14a authored by Carl Huang's avatar Carl Huang Committed by Kalle Valo
Browse files

ath11k: enable shadow register configuration and access



To enable shadow register access, host needs to pass shadow
register configuration to firmware via qmi message. Host also
needs to update ring's HP or TP address to shadow register
address. The write operation to shadow register will be
forwarded to target register by hardware automatically, and
the write operation to shadow register is permitted even
when the target is in power save or sleep mode.

Update the shadow config whenever power up happens.

This feature is controlled by hw parameter supports_shadow_regs which is only
enabled for QCA6390.

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

Signed-off-by: default avatarCarl Huang <cjhuang@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1601544890-13450-3-git-send-email-kvalo@codeaurora.org
parent a05bd851
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -713,6 +713,49 @@ static void ath11k_ce_rx_pipe_cleanup(struct ath11k_ce_pipe *pipe)
	}
}

static void ath11k_ce_shadow_config(struct ath11k_base *ab)
{
	int i;

	for (i = 0; i < ab->hw_params.ce_count; i++) {
		if (ab->hw_params.host_ce_config[i].src_nentries)
			ath11k_hal_srng_update_shadow_config(ab,
							     HAL_CE_SRC, i);

		if (ab->hw_params.host_ce_config[i].dest_nentries) {
			ath11k_hal_srng_update_shadow_config(ab,
							     HAL_CE_DST, i);

			ath11k_hal_srng_update_shadow_config(ab,
							     HAL_CE_DST_STATUS, i);
		}
	}
}

void ath11k_ce_get_shadow_config(struct ath11k_base *ab,
				 u32 **shadow_cfg, u32 *shadow_cfg_len)
{
	if (!ab->hw_params.supports_shadow_regs)
		return;

	ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len);

	/* shadow is already configured */
	if (*shadow_cfg_len)
		return;

	/* shadow isn't configured yet, configure now.
	 * non-CE srngs are configured firstly, then
	 * all CE srngs.
	 */
	ath11k_hal_srng_shadow_config(ab);
	ath11k_ce_shadow_config(ab);

	/* get the shadow configuration */
	ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len);
}
EXPORT_SYMBOL(ath11k_ce_get_shadow_config);

void ath11k_ce_cleanup_pipes(struct ath11k_base *ab)
{
	struct ath11k_ce_pipe *pipe;
@@ -767,6 +810,9 @@ int ath11k_ce_init_pipes(struct ath11k_base *ab)
	int i;
	int ret;

	ath11k_ce_get_shadow_config(ab, &ab->qmi.ce_cfg.shadow_reg_v2,
				    &ab->qmi.ce_cfg.shadow_reg_v2_len);

	for (i = 0; i < ab->hw_params.ce_count; i++) {
		pipe = &ab->ce.ce_pipe[i];

+2 −0
Original line number Diff line number Diff line
@@ -187,4 +187,6 @@ void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id);
int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
				  u8 *ul_pipe, u8 *dl_pipe);
int ath11k_ce_attr_attach(struct ath11k_base *ab);
void ath11k_ce_get_shadow_config(struct ath11k_base *ab,
				 u32 **shadow_cfg, u32 *shadow_cfg_len);
#endif
+4 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
					BIT(NL80211_IFTYPE_AP) |
					BIT(NL80211_IFTYPE_MESH_POINT),
		.supports_monitor = true,
		.supports_shadow_regs = false,
	},
	{
		.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -98,6 +99,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
					BIT(NL80211_IFTYPE_AP) |
					BIT(NL80211_IFTYPE_MESH_POINT),
		.supports_monitor = true,
		.supports_shadow_regs = false,
	},
	{
		.name = "qca6390 hw2.0",
@@ -132,6 +134,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.interface_modes = BIT(NL80211_IFTYPE_STATION) |
					BIT(NL80211_IFTYPE_AP),
		.supports_monitor = false,
		.supports_shadow_regs = true,
	},
};

@@ -412,6 +415,7 @@ static void ath11k_core_stop(struct ath11k_base *ab)
{
	if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
		ath11k_qmi_firmware_stop(ab);

	ath11k_hif_stop(ab);
	ath11k_wmi_detach(ab);
	ath11k_dp_pdev_reo_cleanup(ab);
+112 −2
Original line number Diff line number Diff line
@@ -1020,8 +1020,16 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
						   lmac_idx);
			srng->flags |= HAL_SRNG_FLAGS_LMAC_RING;
		} else {
			if (!ab->hw_params.supports_shadow_regs)
				srng->u.src_ring.hp_addr =
				(u32 *)((unsigned long)ab->mem + reg_base);
			else
				ath11k_dbg(ab, ATH11k_DBG_HAL,
					   "hal type %d ring_num %d reg_base 0x%x shadow 0x%lx\n",
					   type, ring_num,
					   reg_base,
					   (unsigned long)srng->u.src_ring.hp_addr -
					   (unsigned long)ab->mem);
		}
	} else {
		/* During initialization loop count in all the descriptors
@@ -1045,9 +1053,18 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
						   lmac_idx);
			srng->flags |= HAL_SRNG_FLAGS_LMAC_RING;
		} else {
			if (!ab->hw_params.supports_shadow_regs)
				srng->u.dst_ring.tp_addr =
				(u32 *)((unsigned long)ab->mem + reg_base +
					(HAL_REO1_RING_TP(ab) - HAL_REO1_RING_HP(ab)));
			else
				ath11k_dbg(ab, ATH11k_DBG_HAL,
					   "type %d ring_num %d target_reg 0x%x shadow 0x%lx\n",
					   type, ring_num,
					   reg_base + (HAL_REO1_RING_TP(ab) -
						       HAL_REO1_RING_HP(ab)),
					   (unsigned long)srng->u.dst_ring.tp_addr -
					   (unsigned long)ab->mem);
		}
	}

@@ -1064,6 +1081,99 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
	return ring_id;
}

static void ath11k_hal_srng_update_hp_tp_addr(struct ath11k_base *ab,
					      int shadow_cfg_idx,
					  enum hal_ring_type ring_type,
					  int ring_num)
{
	struct hal_srng *srng;
	struct ath11k_hal *hal = &ab->hal;
	int ring_id;
	struct hal_srng_config *srng_config = &hal->srng_config[ring_type];

	ring_id = ath11k_hal_srng_get_ring_id(ab, ring_type, ring_num, 0);
	if (ring_id < 0)
		return;

	srng = &hal->srng_list[ring_id];

	if (srng_config->ring_dir == HAL_SRNG_DIR_DST)
		srng->u.dst_ring.tp_addr = (u32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
						   (unsigned long)ab->mem);
	else
		srng->u.src_ring.hp_addr = (u32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
						   (unsigned long)ab->mem);
}

int ath11k_hal_srng_update_shadow_config(struct ath11k_base *ab,
					 enum hal_ring_type ring_type,
					 int ring_num)
{
	struct ath11k_hal *hal = &ab->hal;
	struct hal_srng_config *srng_config = &hal->srng_config[ring_type];
	int shadow_cfg_idx = hal->num_shadow_reg_configured;
	u32 target_reg;

	if (shadow_cfg_idx >= HAL_SHADOW_NUM_REGS)
		return -EINVAL;

	hal->num_shadow_reg_configured++;

	target_reg = srng_config->reg_start[HAL_HP_OFFSET_IN_REG_START];
	target_reg += srng_config->reg_size[HAL_HP_OFFSET_IN_REG_START] *
		ring_num;

	/* For destination ring, shadow the TP */
	if (srng_config->ring_dir == HAL_SRNG_DIR_DST)
		target_reg += HAL_OFFSET_FROM_HP_TO_TP;

	hal->shadow_reg_addr[shadow_cfg_idx] = target_reg;

	/* update hp/tp addr to hal structure*/
	ath11k_hal_srng_update_hp_tp_addr(ab, shadow_cfg_idx, ring_type,
					  ring_num);

	ath11k_dbg(ab, ATH11k_DBG_HAL,
		   "target_reg %x, shadow reg 0x%x shadow_idx 0x%x, ring_type %d, ring num %d",
		  target_reg,
		  HAL_SHADOW_REG(shadow_cfg_idx),
		  shadow_cfg_idx,
		  ring_type, ring_num);

	return 0;
}

void ath11k_hal_srng_shadow_config(struct ath11k_base *ab)
{
	struct ath11k_hal *hal = &ab->hal;
	int ring_type, ring_num;

	/* update all the non-CE srngs. */
	for (ring_type = 0; ring_type < HAL_MAX_RING_TYPES; ring_type++) {
		struct hal_srng_config *srng_config = &hal->srng_config[ring_type];

		if (ring_type == HAL_CE_SRC ||
		    ring_type == HAL_CE_DST ||
			ring_type == HAL_CE_DST_STATUS)
			continue;

		if (srng_config->lmac_ring)
			continue;

		for (ring_num = 0; ring_num < srng_config->max_rings; ring_num++)
			ath11k_hal_srng_update_shadow_config(ab, ring_type, ring_num);
	}
}

void ath11k_hal_srng_get_shadow_config(struct ath11k_base *ab,
				       u32 **cfg, u32 *len)
{
	struct ath11k_hal *hal = &ab->hal;

	*len = hal->num_shadow_reg_configured;
	*cfg = hal->shadow_reg_addr;
}

static int ath11k_hal_srng_create_config(struct ath11k_base *ab)
{
	struct ath11k_hal *hal = &ab->hal;
+13 −4
Original line number Diff line number Diff line
@@ -31,8 +31,12 @@ struct ath11k_base;
#define HAL_DSCP_TID_TBL_SIZE			24

/* calculate the register address from bar0 of shadow register x */
#define SHADOW_BASE_ADDRESS			0x00003024
#define SHADOW_NUM_REGISTERS				36
#define HAL_SHADOW_BASE_ADDR			0x000008fc
#define HAL_SHADOW_NUM_REGS			36
#define HAL_HP_OFFSET_IN_REG_START		1
#define HAL_OFFSET_FROM_HP_TO_TP		4

#define HAL_SHADOW_REG(x) (HAL_SHADOW_BASE_ADDR + (4 * (x)))

/* WCSS Relative address */
#define HAL_SEQ_WCSS_UMAC_REO_REG		0x00a38000
@@ -882,7 +886,7 @@ struct ath11k_hal {
	u8 current_blk_index;

	/* shadow register configuration */
	u32 shadow_reg_addr[SHADOW_NUM_REGISTERS];
	u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS];
	int num_shadow_reg_configured;
};

@@ -935,5 +939,10 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
int ath11k_hal_srng_init(struct ath11k_base *ath11k);
void ath11k_hal_srng_deinit(struct ath11k_base *ath11k);
void ath11k_hal_dump_srng_stats(struct ath11k_base *ab);

void ath11k_hal_srng_get_shadow_config(struct ath11k_base *ab,
				       u32 **cfg, u32 *len);
int ath11k_hal_srng_update_shadow_config(struct ath11k_base *ab,
					 enum hal_ring_type ring_type,
					int ring_num);
void ath11k_hal_srng_shadow_config(struct ath11k_base *ab);
#endif
Loading