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

Commit bd1cc6fb authored by Ravi Gummadidala's avatar Ravi Gummadidala
Browse files

msm: ipa: add support for WDI stats



This is needed to report uc collected WDI stats to AP

Change-Id: Ic4f971436067238da3f4734b7ebd583cb9cc4924
Signed-off-by: default avatarRavi Gummadidala <rgummadi@codeaurora.org>
parent e92aa60f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1445,7 +1445,7 @@ static int ipa_init_sram(void)
	IPA_SRAM_SET(IPA_v2_RAM_MODEM_HDR_OFST, IPA_CANARY_VAL);
	IPA_SRAM_SET(IPA_v2_RAM_MODEM_OFST, IPA_CANARY_VAL);
	IPA_SRAM_SET(IPA_v2_RAM_APPS_V4_FLT_OFST, IPA_CANARY_VAL);
	IPA_SRAM_SET(IPA_v2_RAM_END_OFST, IPA_CANARY_VAL);
	IPA_SRAM_SET(IPA_v2_RAM_UC_INFO_OFST, IPA_CANARY_VAL);

	iounmap(ipa_sram_mmio);

+218 −0
Original line number Diff line number Diff line
@@ -171,8 +171,11 @@ enum ipa_hw_2_cpu_responses {
enum ipa_hw_2_cpu_events {
	IPA_HW_2_CPU_EVENT_ERROR     =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 1),
	IPA_HW_2_CPU_EVENT_LOG_INFO  =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 2),
	IPA_HW_2_CPU_EVENT_WDI_ERROR =
		FEATURE_ENUM_VAL(IPA_HW_FEATURE_WDI, 0),

};

/**
@@ -439,6 +442,216 @@ union IpaHwWdiErrorEventData_t {
	u32 raw32b;
} __packed;

/**
 * union IpaHwFeatureInfoData_t - parameters for stats/config blob
 *
 * @offset : Location of a feature within the EventInfoData
 * @size : Size of the feature
 */
union IpaHwFeatureInfoData_t {
	struct IpaHwFeatureInfoParams_t {
		u32 offset:16;
		u32 size:16;
	} __packed params;
	u32 raw32b;
} __packed;

/**
 * struct IpaHwEventInfoData_t - Structure holding the parameters for
 * statistics and config info
 *
 * @baseAddrOffset : Base Address Offset of the statistics or config
 * structure from IPA_WRAPPER_BASE
 * @IpaHwFeatureInfoData_t : Location and size of each feature within
 * the statistics or config structure
 *
 * @note    Information about each feature in the featureInfo[]
 * array is populated at predefined indices per the IPA_HW_FEATURES
 * enum definition
*/
struct IpaHwEventInfoData_t {
	u32 baseAddrOffset;
	union IpaHwFeatureInfoData_t featureInfo[IPA_HW_NUM_FEATURES];
} __packed;


/**
 * struct IpaHwEventLogInfoData_t - Structure holding the parameters for
 * IPA_HW_2_CPU_EVENT_LOG_INFO Event
 *
 * @featureMask : Mask indicating the features enabled in HW.
 * Refer IPA_HW_FEATURE_MASK
 * @circBuffBaseAddrOffset : Base Address Offset of the Circular Event
 * Log Buffer structure
 * @statsInfo : Statistics related information
 * @configInfo : Configuration related information
 *
 * @note    The offset location of this structure from IPA_WRAPPER_BASE
 * will be provided as Event Params for the IPA_HW_2_CPU_EVENT_LOG_INFO
 * Event
*/
struct IpaHwEventLogInfoData_t {
	u32 featureMask;
	u32 circBuffBaseAddrOffset;
	struct IpaHwEventInfoData_t statsInfo;
	struct IpaHwEventInfoData_t configInfo;

} __packed;

/**
 * ipa_get_wdi_stats() - Query WDI statistics from uc
 * @stats:	[inout] stats blob from client populated by driver
 *
 * Returns:	0 on success, negative on failure
 *
 * @note Cannot be called from atomic context
 *
 */
int ipa_get_wdi_stats(struct IpaHwStatsWDIInfoData_t *stats)
{
#define TX_STATS(y) stats->tx_ch_stats.y = \
	ipa_ctx->wdi.uc_wdi_stats_mmio->tx_ch_stats.y
#define RX_STATS(y) stats->rx_ch_stats.y = \
	ipa_ctx->wdi.uc_wdi_stats_mmio->rx_ch_stats.y

	if (!stats || !ipa_ctx->wdi.uc_top_mmio ||
		!ipa_ctx->wdi.uc_wdi_stats_mmio) {
		IPAERR("bad parms stats=%p uc_top=%p wdi_stats=%p\n",
			stats,
			ipa_ctx->wdi.uc_top_mmio,
			ipa_ctx->wdi.uc_wdi_stats_mmio);
		return -EINVAL;
	}

	ipa_inc_client_enable_clks();

	TX_STATS(num_pkts_processed);
	TX_STATS(copy_engine_doorbell_value);
	TX_STATS(num_db_fired);
	TX_STATS(tx_comp_ring_stats.ringFull);
	TX_STATS(tx_comp_ring_stats.ringEmpty);
	TX_STATS(tx_comp_ring_stats.ringUsageHigh);
	TX_STATS(tx_comp_ring_stats.ringUsageLow);
	TX_STATS(bam_stats.bamFifoFull);
	TX_STATS(bam_stats.bamFifoEmpty);
	TX_STATS(bam_stats.bamFifoUsageHigh);
	TX_STATS(bam_stats.bamFifoUsageLow);
	TX_STATS(num_db);
	TX_STATS(num_unexpected_db);
	TX_STATS(num_bam_int_handled);
	TX_STATS(num_bam_int_in_non_runnning_state);
	TX_STATS(num_qmb_int_handled);

	RX_STATS(max_outstanding_pkts);
	RX_STATS(num_pkts_processed);
	RX_STATS(rx_ring_rp_value);
	RX_STATS(rx_ind_ring_stats.ringFull);
	RX_STATS(rx_ind_ring_stats.ringEmpty);
	RX_STATS(rx_ind_ring_stats.ringUsageHigh);
	RX_STATS(rx_ind_ring_stats.ringUsageLow);
	RX_STATS(bam_stats.bamFifoFull);
	RX_STATS(bam_stats.bamFifoEmpty);
	RX_STATS(bam_stats.bamFifoUsageHigh);
	RX_STATS(bam_stats.bamFifoUsageLow);
	RX_STATS(num_bam_int_handled);
	RX_STATS(num_db);
	RX_STATS(num_unexpected_db);
	RX_STATS(reserved1);
	RX_STATS(reserved2);

	ipa_dec_client_disable_clks();

	return 0;
}
EXPORT_SYMBOL(ipa_get_wdi_stats);

/* TODO: add support for IPA_HW_v2_5 */
static void ipa_log_evt_hdlr(void)
{
	if (!ipa_ctx->wdi.uc_top_ofst) {
		ipa_ctx->wdi.uc_top_ofst =
			ipa_ctx->wdi.ipa_sram_mmio->common.eventParams;
		if (ipa_ctx->wdi.uc_top_ofst +
				sizeof(struct IpaHwEventLogInfoData_t) >=
				ipa_ctx->ctrl->ipa_reg_base_ofst +
				IPA_SRAM_DIRECT_ACCESS_N_OFST_v2_0(0) +
				ipa_ctx->smem_sz) {
			IPAERR("uc_top 0x%x outside SRAM\n",
					ipa_ctx->wdi.uc_top_ofst);
			goto bad_uc_top_ofst;
		}

		ipa_ctx->wdi.uc_top_mmio = ioremap(ipa_ctx->ipa_wrapper_base +
				ipa_ctx->wdi.uc_top_ofst,
				sizeof(struct IpaHwEventLogInfoData_t));
		if (!ipa_ctx->wdi.uc_top_mmio) {
			IPAERR("fail to ioremap uc top\n");
			goto bad_uc_top_ofst;
		}

		if ((ipa_ctx->wdi.uc_top_mmio->featureMask &
					(1 << IPA_HW_FEATURE_WDI)) == 0) {
			IPAERR("WDI feature missing 0x%x\n",
					ipa_ctx->wdi.uc_top_mmio->featureMask);
			goto feat_miss;
		}

		if (ipa_ctx->wdi.uc_top_mmio->statsInfo.
			featureInfo[IPA_HW_FEATURE_WDI].params.size !=
			sizeof(struct IpaHwStatsWDIInfoData_t)) {
			IPAERR("wdi stats size invalid exp=%zu is=%u\n",
				sizeof(struct IpaHwStatsWDIInfoData_t),
				ipa_ctx->wdi.uc_top_mmio->statsInfo.
				featureInfo[IPA_HW_FEATURE_WDI].
				params.size);
			goto feat_miss;
		}

		ipa_ctx->wdi.uc_wdi_stats_ofst = ipa_ctx->wdi.
			uc_top_mmio->statsInfo.baseAddrOffset +
			ipa_ctx->wdi.uc_top_mmio->statsInfo.
			featureInfo[IPA_HW_FEATURE_WDI].params.offset;
		IPAERR("WDI stats ofst=0x%x\n",
				ipa_ctx->wdi.uc_wdi_stats_ofst);
		if (ipa_ctx->wdi.uc_wdi_stats_ofst +
				sizeof(struct IpaHwStatsWDIInfoData_t) >=
				ipa_ctx->ctrl->ipa_reg_base_ofst +
				IPA_SRAM_DIRECT_ACCESS_N_OFST_v2_0(0) +
				ipa_ctx->smem_sz) {
			IPAERR("uc_wdi_stats 0x%x outside SRAM\n",
					ipa_ctx->wdi.uc_wdi_stats_ofst);
			goto bad_stats_ofst;
		}

		ipa_ctx->wdi.uc_wdi_stats_mmio =
			ioremap(ipa_ctx->ipa_wrapper_base +
				ipa_ctx->wdi.uc_wdi_stats_ofst,
				sizeof(struct IpaHwStatsWDIInfoData_t));
		if (!ipa_ctx->wdi.uc_wdi_stats_mmio) {
			IPAERR("fail to ioremap uc wdi stats\n");
			goto bad_stats_ofst;
		}
	} else {
		if (ipa_ctx->wdi.ipa_sram_mmio->common.eventParams !=
				ipa_ctx->wdi.uc_top_ofst) {
			IPAERR("uc top ofst changed new=%u cur=%u\n",
				ipa_ctx->wdi.uc_top_mmio->statsInfo.
				featureInfo[IPA_HW_FEATURE_WDI].params.size,
				ipa_ctx->wdi.uc_top_ofst);
		}
	}

	return;

bad_stats_ofst:
	ipa_ctx->wdi.uc_wdi_stats_ofst = 0;
feat_miss:
	iounmap(ipa_ctx->wdi.uc_top_mmio);
bad_uc_top_ofst:
	ipa_ctx->wdi.uc_top_ofst = 0;
	return;
}

static void ipa_wdi_evt_handler(enum ipa_irq_type interrupt,
				void *private_data,
				void *interrupt_data)
@@ -467,6 +680,11 @@ static void ipa_wdi_evt_handler(enum ipa_irq_type interrupt,
				ipa_ctx->wdi.ipa_sram_mmio->wdi_tx_ch_0_state,
				ipa_ctx->wdi.ipa_sram_mmio->wdi_rx_ch_0_state);

	} else if (ipa_ctx->wdi.ipa_sram_mmio->common.eventOp ==
			IPA_HW_2_CPU_EVENT_LOG_INFO) {
		IPAERR("WDI evt log info ofst=0x%x\n",
				ipa_ctx->wdi.ipa_sram_mmio->common.eventParams);
		ipa_log_evt_hdlr();
	} else {
		IPAERR("unsupported WDI evt opcode=%u\n",
				ipa_ctx->wdi.ipa_sram_mmio->common.eventOp);
+97 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ static struct dentry *dfile_ip4_flt;
static struct dentry *dfile_ip6_flt;
static struct dentry *dfile_stats;
static struct dentry *dfile_wstats;
static struct dentry *dfile_wdi_stats;
static struct dentry *dfile_dbg_cnt;
static struct dentry *dfile_msg;
static struct dentry *dfile_ip4_nat;
@@ -933,6 +934,91 @@ nxt_clnt_cons:
	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}

static ssize_t ipa_read_wdi(struct file *file, char __user *ubuf,
		size_t count, loff_t *ppos)
{
	struct IpaHwStatsWDIInfoData_t stats;
	int nbytes;
	int cnt = 0;

	if (!ipa_get_wdi_stats(&stats)) {
		nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
			"TX num_pkts_processed=%u\n"
			"TX copy_engine_doorbell_value=%u\n"
			"TX num_db_fired=%u\n"
			"TX ringFull=%u\n"
			"TX ringEmpty=%u\n"
			"TX ringUsageHigh=%u\n"
			"TX ringUsageLow=%u\n"
			"TX bamFifoFull=%u\n"
			"TX bamFifoEmpty=%u\n"
			"TX bamFifoUsageHigh=%u\n"
			"TX bamFifoUsageLow=%u\n"
			"TX num_db=%u\n"
			"TX num_unexpected_db=%u\n"
			"TX num_bam_int_handled=%u\n"
			"TX num_bam_int_in_non_runnning_state=%u\n"
			"TX num_qmb_int_handled=%u\n",
			stats.tx_ch_stats.num_pkts_processed,
			stats.tx_ch_stats.copy_engine_doorbell_value,
			stats.tx_ch_stats.num_db_fired,
			stats.tx_ch_stats.tx_comp_ring_stats.ringFull,
			stats.tx_ch_stats.tx_comp_ring_stats.ringEmpty,
			stats.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh,
			stats.tx_ch_stats.tx_comp_ring_stats.ringUsageLow,
			stats.tx_ch_stats.bam_stats.bamFifoFull,
			stats.tx_ch_stats.bam_stats.bamFifoEmpty,
			stats.tx_ch_stats.bam_stats.bamFifoUsageHigh,
			stats.tx_ch_stats.bam_stats.bamFifoUsageLow,
			stats.tx_ch_stats.num_db,
			stats.tx_ch_stats.num_unexpected_db,
			stats.tx_ch_stats.num_bam_int_handled,
			stats.tx_ch_stats.num_bam_int_in_non_runnning_state,
			stats.tx_ch_stats.num_qmb_int_handled);
		cnt += nbytes;
		nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
			"RX max_outstanding_pkts=%u\n"
			"RX num_pkts_processed=%u\n"
			"RX rx_ring_rp_value=%u\n"
			"RX ringFull=%u\n"
			"RX ringEmpty=%u\n"
			"RX ringUsageHigh=%u\n"
			"RX ringUsageLow=%u\n"
			"RX bamFifoFull=%u\n"
			"RX bamFifoEmpty=%u\n"
			"RX bamFifoUsageHigh=%u\n"
			"RX bamFifoUsageLow=%u\n"
			"RX num_bam_int_handled=%u\n"
			"RX num_db=%u\n"
			"RX num_unexpected_db=%u\n"
			"RX reserved1=%u\n"
			"RX reserved2=%u\n",
			stats.rx_ch_stats.max_outstanding_pkts,
			stats.rx_ch_stats.num_pkts_processed,
			stats.rx_ch_stats.rx_ring_rp_value,
			stats.rx_ch_stats.rx_ind_ring_stats.ringFull,
			stats.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
			stats.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
			stats.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
			stats.rx_ch_stats.bam_stats.bamFifoFull,
			stats.rx_ch_stats.bam_stats.bamFifoEmpty,
			stats.rx_ch_stats.bam_stats.bamFifoUsageHigh,
			stats.rx_ch_stats.bam_stats.bamFifoUsageLow,
			stats.rx_ch_stats.num_bam_int_handled,
			stats.rx_ch_stats.num_db,
			stats.rx_ch_stats.num_unexpected_db,
			stats.rx_ch_stats.reserved1,
			stats.rx_ch_stats.reserved2);
		cnt += nbytes;
	} else {
		nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
				"Fail to read WDI stats\n");
		cnt += nbytes;
	}

	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}

void _ipa_write_dbg_cnt_v1(int option)
{
	if (option == 1)
@@ -1249,6 +1335,10 @@ const struct file_operations ipa_wstats_ops = {
	.read = ipa_read_wstats,
};

const struct file_operations ipa_wdi_ops = {
	.read = ipa_read_wdi,
};

const struct file_operations ipa_msg_ops = {
	.read = ipa_read_msg,
};
@@ -1358,6 +1448,13 @@ void ipa_debugfs_init(void)
		goto fail;
	}

	dfile_wdi_stats = debugfs_create_file("wdi", read_only_mode, dent, 0,
			&ipa_wdi_ops);
	if (!dfile_wdi_stats || IS_ERR(dfile_wdi_stats)) {
		IPAERR("fail to create file for debug_fs wdi stats\n");
		goto fail;
	}

	dfile_dbg_cnt = debugfs_create_file("dbg_cnt", read_write_mode, dent, 0,
			&ipa_dbg_cnt_ops);
	if (!dfile_dbg_cnt || IS_ERR(dfile_dbg_cnt)) {
+4 −0
Original line number Diff line number Diff line
@@ -662,6 +662,10 @@ struct ipa_wdi_ctx {
	u32 pending_cmd;
	u32 last_resp;
	struct dma_pool *dma_pool;
	u32 uc_top_ofst;
	struct IpaHwEventLogInfoData_t *uc_top_mmio;
	u32 uc_wdi_stats_ofst;
	struct IpaHwStatsWDIInfoData_t *uc_wdi_stats_mmio;
};

/**
+5 −2
Original line number Diff line number Diff line
@@ -80,9 +80,12 @@
#define IPA_v2_RAM_APPS_V4_FLT_SIZE 2176
#define IPA_v2_RAM_APPS_V6_FLT_OFST (IPA_v2_RAM_APPS_V4_FLT_OFST + \
		IPA_v2_RAM_APPS_V4_FLT_SIZE)
#define IPA_v2_RAM_APPS_V6_FLT_SIZE 1664
#define IPA_v2_RAM_END_OFST (IPA_v2_RAM_APPS_V6_FLT_OFST + \
#define IPA_v2_RAM_APPS_V6_FLT_SIZE 1372
#define IPA_v2_RAM_UC_INFO_OFST (IPA_v2_RAM_APPS_V6_FLT_OFST + \
		IPA_v2_RAM_APPS_V6_FLT_SIZE + IPA_CANARY_SIZE)
#define IPA_v2_RAM_UC_INFO_SIZE 292
#define IPA_v2_RAM_END_OFST (IPA_v2_RAM_UC_INFO_OFST + \
		IPA_v2_RAM_UC_INFO_SIZE)
#define IPA_v2_RAM_APPS_V4_RT_OFST IPA_v2_RAM_END_OFST
#define IPA_v2_RAM_APPS_V4_RT_SIZE 0
#define IPA_v2_RAM_APPS_V6_RT_OFST IPA_v2_RAM_END_OFST
Loading