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

Commit 7a9a2659 authored by Jinesh K. Jayakumar's avatar Jinesh K. Jayakumar
Browse files

msm: ipa: eth: Enable IPA uC based GSI channel monitor



Enable support in IPA offload sub-system to request IPA uC to perform GSI
channel monitoring for collecting channel usage statistics.

Change-Id: I98f26f4daccad34d2e54885952559388b074d416
Signed-off-by: default avatarJinesh K. Jayakumar <jineshk@codeaurora.org>
parent 12852aea
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -103,6 +103,11 @@ static int ipa_eth_init_device(struct ipa_eth_device *eth_dev)
		return rc;
	}

	rc = ipa_eth_uc_stats_init(eth_dev);
	if (rc)
		ipa_eth_dev_err(eth_dev,
			"Failed to init uC stats monitor, continuing.");

	ipa_eth_dev_log(eth_dev, "Initialized device");

	eth_dev->of_state = IPA_ETH_OF_ST_INITED;
@@ -120,6 +125,11 @@ static int ipa_eth_deinit_device(struct ipa_eth_device *eth_dev)
	if (eth_dev->of_state != IPA_ETH_OF_ST_INITED)
		return -EFAULT;

	rc = ipa_eth_uc_stats_deinit(eth_dev);
	if (rc)
		ipa_eth_dev_err(eth_dev,
			"Failed to deinit uC stats monitor, continuing.");

	rc = ipa_eth_offload_deinit(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to deinit offload");
@@ -187,6 +197,11 @@ static int ipa_eth_start_device(struct ipa_eth_device *eth_dev)
		return rc;
	}

	rc = ipa_eth_uc_stats_start(eth_dev);
	if (rc)
		ipa_eth_dev_err(eth_dev,
			"Failed to start uC stats monitor, continuing.");

	ipa_eth_dev_log(eth_dev, "Started device");

	eth_dev->of_state = IPA_ETH_OF_ST_STARTED;
@@ -204,6 +219,11 @@ static int ipa_eth_stop_device(struct ipa_eth_device *eth_dev)
	if (eth_dev->of_state != IPA_ETH_OF_ST_STARTED)
		return -EFAULT;

	rc = ipa_eth_uc_stats_stop(eth_dev);
	if (rc)
		ipa_eth_dev_err(eth_dev,
			"Failed to stop uC stats monitor, continuing.");

	rc = ipa_eth_ep_unregister_interface(eth_dev);
	if (rc) {
		ipa_eth_dev_err(eth_dev, "Failed to unregister IPA interface");
+5 −0
Original line number Diff line number Diff line
@@ -194,6 +194,11 @@ int ipa_eth_pm_deactivate(struct ipa_eth_device *eth_dev);

int ipa_eth_pm_vote_bw(struct ipa_eth_device *eth_dev);

int ipa_eth_uc_stats_init(struct ipa_eth_device *eth_dev);
int ipa_eth_uc_stats_deinit(struct ipa_eth_device *eth_dev);
int ipa_eth_uc_stats_start(struct ipa_eth_device *eth_dev);
int ipa_eth_uc_stats_stop(struct ipa_eth_device *eth_dev);

/* ipa_eth_utils.c APIs */

const char *ipa_eth_device_event_name(enum ipa_eth_device_event event);
+123 −0
Original line number Diff line number Diff line
@@ -109,3 +109,126 @@ int ipa_eth_uc_send_cmd(enum ipa_eth_uc_op op, u32 protocol,
	return rc;
}
EXPORT_SYMBOL(ipa_eth_uc_send_cmd);

/* Define IPA hardware constants not available from IPA header files */

#define IPA_HW_DIR_PRODUCER 0
#define IPA_HW_DIR_CONSUMER 1

#define IPA_HW_CH_ID_INVALID 0xFF
#define IPA_HW_PROTOCOL_INVALID 0xFFFFFFFF

static u32 find_uc_protocol(struct ipa_eth_device *eth_dev)
{
	int protocol;
	struct ipa_eth_channel *ch;

	list_for_each_entry(ch, &eth_dev->rx_channels, channel_list) {
		protocol = ipa_get_prot_id(ch->ipa_client);
		if (protocol >= 0)
			return lower_32_bits(protocol);
	}

	list_for_each_entry(ch, &eth_dev->tx_channels, channel_list) {
		protocol = ipa_get_prot_id(ch->ipa_client);
		if (protocol >= 0)
			return lower_32_bits(protocol);
	}

	return IPA_HW_PROTOCOL_INVALID;
}

static int find_client_channel(enum ipa_client_type client)
{
	const struct ipa_gsi_ep_config *gsi_ep_cfg;

	gsi_ep_cfg = ipa3_get_gsi_ep_info(client);
	if (!gsi_ep_cfg)
		return -EFAULT;

	return gsi_ep_cfg->ipa_gsi_chan_num;
}

int ipa_eth_uc_stats_init(struct ipa_eth_device *eth_dev)
{
	return 0;
}

int ipa_eth_uc_stats_deinit(struct ipa_eth_device *eth_dev)
{
	u32 protocol = find_uc_protocol(eth_dev);

	if (protocol == IPA_HW_PROTOCOL_INVALID)
		return -EFAULT;

	return ipa_uc_debug_stats_dealloc(protocol);
}

static void __fill_stats_info(
	struct ipa_eth_channel *ch,
	struct IpaOffloadStatschannel_info *ch_info,
	bool start)
{
	ch_info->dir = IPA_ETH_CH_IS_RX(ch) ?
			IPA_HW_DIR_CONSUMER : IPA_HW_DIR_PRODUCER;

	if (start) {
		int gsi_ch = find_client_channel(ch->ipa_client);

		if (gsi_ch < 0) {
			ipa_eth_dev_err(ch->eth_dev,
				"Failed to determine GSI channel for client %d",
				ch->ipa_client);
			gsi_ch = IPA_HW_CH_ID_INVALID;
		}

		ch_info->ch_id = (u8) gsi_ch;
	} else {
		ch_info->ch_id = IPA_HW_CH_ID_INVALID;
	}
}

static int ipa_eth_uc_stats_control(struct ipa_eth_device *eth_dev, bool start)
{
	int stats_idx = 0;
	struct ipa_eth_channel *ch;
	u32 protocol = find_uc_protocol(eth_dev);
	struct IpaHwOffloadStatsAllocCmdData_t stats_info;

	if (protocol == IPA_HW_PROTOCOL_INVALID) {
		ipa_eth_dev_err(eth_dev, "Failed find to uC protocol");
		return -EFAULT;
	}

	memset(&stats_info, 0, sizeof(stats_info));

	stats_info.protocol = protocol;

	list_for_each_entry(ch, &eth_dev->rx_channels, channel_list) {
		if (stats_idx == IPA_MAX_CH_STATS_SUPPORTED)
			break;

		__fill_stats_info(ch,
			&stats_info.ch_id_info[stats_idx++], start);
	}

	list_for_each_entry(ch, &eth_dev->tx_channels, channel_list) {
		if (stats_idx == IPA_MAX_CH_STATS_SUPPORTED)
			break;

		__fill_stats_info(ch,
			&stats_info.ch_id_info[stats_idx++], start);
	}

	return ipa_uc_debug_stats_alloc(stats_info);
}

int ipa_eth_uc_stats_start(struct ipa_eth_device *eth_dev)
{
	return ipa_eth_uc_stats_control(eth_dev, true);
}

int ipa_eth_uc_stats_stop(struct ipa_eth_device *eth_dev)
{
	return ipa_eth_uc_stats_control(eth_dev, false);
}