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

Commit 2c470a63 authored by Skylar Chang's avatar Skylar Chang
Browse files

msm: ipa4: add HAL support for statistics



Add support to IPA HAL for hardware statistics

Change-Id: Ibd4e1300edf4ac95f90f5ed1b4a1c69c036ac5f4
CRs-Fixed: 2069977
Acked-by: default avatarAdy Abraham <adya@qti.qualcomm.com>
Signed-off-by: default avatarSkylar Chang <chiaweic@codeaurora.org>
parent 0c37f5f6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
obj-$(CONFIG_IPA3) += ipa_hal.o

ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o
ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o ipahal_hw_stats.o
+8 −3
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
#include "ipahal_i.h"
#include "ipahal_reg_i.h"
#include "ipahal_fltrt_i.h"
#include "ipahal_hw_stats_i.h"


struct ipahal_context *ipahal_ctx;

@@ -48,9 +50,6 @@ static const char *ipahal_pkt_status_exception_to_str
	__stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT),
};

#define IPAHAL_MEM_ALLOC(__size, __is_atomic_ctx) \
		(kzalloc((__size), ((__is_atomic_ctx)?GFP_ATOMIC:GFP_KERNEL)))

static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd);


@@ -1504,6 +1503,12 @@ int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base,
		goto bail_free_ctx;
	}

	if (ipahal_hw_stats_init(ipa_hw_type)) {
		IPAHAL_ERR("failed to init ipahal hw stats\n");
		result = -EFAULT;
		goto bail_free_ctx;
	}

	ipahal_debugfs_init();

	return 0;
+557 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "ipahal_hw_stats.h"
#include "ipahal_hw_stats_i.h"
#include "ipahal_i.h"

struct ipahal_hw_stats_obj {
	struct ipahal_stats_init_pyld *(*generate_init_pyld)(void *params,
		bool is_atomic_ctx);
	int (*get_offset)(void *params, struct ipahal_stats_offset *out);
	int (*parse_stats)(void *init_params, void *raw_stats,
		void *parsed_stats);
};

static int _count_ones(u32 number)
{
	int count = 0;

	while (number) {
		count++;
		number = number & (number - 1);
	}

	return count;
}

static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_quota(
	void *params, bool is_atomic_ctx)
{
	struct ipahal_stats_init_pyld *pyld;
	struct ipahal_stats_init_quota *in =
		(struct ipahal_stats_init_quota *)params;
	int entries = _count_ones(in->enabled_bitmask);

	IPAHAL_DBG_LOW("entries = %d\n", entries);
	pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
		entries * sizeof(struct ipahal_stats_quota_hw), is_atomic_ctx);
	if (!pyld) {
		IPAHAL_ERR("no mem\n");
		return NULL;
	}

	pyld->len = entries * sizeof(struct ipahal_stats_quota_hw);
	return pyld;
}

static int ipahal_get_offset_quota(void *params,
	struct ipahal_stats_offset *out)
{
	struct ipahal_stats_get_offset_quota *in =
		(struct ipahal_stats_get_offset_quota *)params;
	int entries = _count_ones(in->init.enabled_bitmask);

	IPAHAL_DBG_LOW("\n");
	out->offset = 0;
	out->size = entries * sizeof(struct ipahal_stats_quota_hw);

	return 0;
}

static int ipahal_parse_stats_quota(void *init_params, void *raw_stats,
	void *parsed_stats)
{
	struct ipahal_stats_init_quota *init =
		(struct ipahal_stats_init_quota *)init_params;
	struct ipahal_stats_quota_hw *raw_hw =
		(struct ipahal_stats_quota_hw *)raw_stats;
	struct ipahal_stats_quota_all *out =
		(struct ipahal_stats_quota_all *)parsed_stats;
	int stat_idx = 0;
	int i;

	memset(out, 0, sizeof(*out));
	IPAHAL_DBG_LOW("\n");
	for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
		if (init->enabled_bitmask & (1 << i)) {
			IPAHAL_DBG_LOW("pipe %d stat_idx %d\n", i, stat_idx);
			out->stats[i].num_ipv4_bytes =
				raw_hw[stat_idx].num_ipv4_bytes;
			out->stats[i].num_ipv4_pkts =
				raw_hw[stat_idx].num_ipv4_pkts;
			out->stats[i].num_ipv6_pkts =
				raw_hw[stat_idx].num_ipv6_pkts;
			out->stats[i].num_ipv6_bytes =
				raw_hw[stat_idx].num_ipv6_bytes;
			stat_idx++;
		}
	}

	return 0;
}

static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_tethering(
	void *params, bool is_atomic_ctx)
{
	struct ipahal_stats_init_pyld *pyld;
	struct ipahal_stats_init_tethering *in =
		(struct ipahal_stats_init_tethering *)params;
	int hdr_entries = _count_ones(in->prod_bitmask);
	int entries = 0;
	int i;
	void *pyld_ptr;
	u32 incremental_offset;

	IPAHAL_DBG_LOW("prod entries = %d\n", hdr_entries);
	for (i = 0; i < sizeof(in->prod_bitmask) * 8; i++) {
		if (in->prod_bitmask & (1 << i)) {
			if (in->cons_bitmask[i] == 0) {
				IPAHAL_ERR("no cons bitmask for prod %d\n", i);
				return NULL;
			}
			entries += _count_ones(in->cons_bitmask[i]);
		}
	}
	IPAHAL_DBG_LOW("sum all entries = %d\n", entries);

	pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
		hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw) +
		entries * sizeof(struct ipahal_stats_tethering_hw),
		is_atomic_ctx);
	if (!pyld) {
		IPAHAL_ERR("no mem\n");
		return NULL;
	}

	pyld->len = hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw) +
		entries * sizeof(struct ipahal_stats_tethering_hw);

	pyld_ptr = pyld->data;
	incremental_offset =
		(hdr_entries * sizeof(struct ipahal_stats_tethering_hdr_hw))
			/ 8;
	for (i = 0; i < sizeof(in->prod_bitmask) * 8; i++) {
		if (in->prod_bitmask & (1 << i)) {
			struct ipahal_stats_tethering_hdr_hw *hdr = pyld_ptr;

			hdr->dst_mask = in->cons_bitmask[i];
			hdr->offset = incremental_offset;
			IPAHAL_DBG_LOW("hdr->dst_mask=0x%x\n", hdr->dst_mask);
			IPAHAL_DBG_LOW("hdr->offset=0x%x\n", hdr->offset);
			/* add the stats entry */
			incremental_offset += _count_ones(in->cons_bitmask[i]) *
				sizeof(struct ipahal_stats_tethering_hw) / 8;
			pyld_ptr += sizeof(*hdr);
		}
	}

	return pyld;
}

static int ipahal_get_offset_tethering(void *params,
	struct ipahal_stats_offset *out)
{
	struct ipahal_stats_get_offset_tethering *in =
		(struct ipahal_stats_get_offset_tethering *)params;
	int entries = 0;
	int i;

	for (i = 0; i < sizeof(in->init.prod_bitmask) * 8; i++) {
		if (in->init.prod_bitmask & (1 << i)) {
			if (in->init.cons_bitmask[i] == 0) {
				IPAHAL_ERR("no cons bitmask for prod %d\n", i);
				return -EPERM;
			}
			entries += _count_ones(in->init.cons_bitmask[i]);
		}
	}
	IPAHAL_DBG_LOW("sum all entries = %d\n", entries);

	/* skip the header */
	out->offset = _count_ones(in->init.prod_bitmask) *
		sizeof(struct ipahal_stats_tethering_hdr_hw);
	out->size = entries * sizeof(struct ipahal_stats_tethering_hw);

	return 0;
}

static int ipahal_parse_stats_tethering(void *init_params, void *raw_stats,
	void *parsed_stats)
{
	struct ipahal_stats_init_tethering *init =
		(struct ipahal_stats_init_tethering *)init_params;
	struct ipahal_stats_tethering_hw *raw_hw =
		(struct ipahal_stats_tethering_hw *)raw_stats;
	struct ipahal_stats_tethering_all *out =
		(struct ipahal_stats_tethering_all *)parsed_stats;
	int i, j;
	int stat_idx = 0;

	memset(out, 0, sizeof(*out));
	IPAHAL_DBG_LOW("\n");
	for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
		for (j = 0; j < IPAHAL_MAX_PIPES; j++) {
			if ((init->prod_bitmask & (1 << i)) &&
			    init->cons_bitmask[i] & (1 << j)) {
				IPAHAL_DBG_LOW("prod %d cons %d\n", i, j);
				IPAHAL_DBG_LOW("stat_idx %d\n", stat_idx);
				out->stats[i][j].num_ipv4_bytes =
					raw_hw[stat_idx].num_ipv4_bytes;
				IPAHAL_DBG_LOW("num_ipv4_bytes %lld\n",
					out->stats[i][j].num_ipv4_bytes);
				out->stats[i][j].num_ipv4_pkts =
					raw_hw[stat_idx].num_ipv4_pkts;
				IPAHAL_DBG_LOW("num_ipv4_pkts %lld\n",
					out->stats[i][j].num_ipv4_pkts);
				out->stats[i][j].num_ipv6_pkts =
					raw_hw[stat_idx].num_ipv6_pkts;
				IPAHAL_DBG_LOW("num_ipv6_pkts %lld\n",
					out->stats[i][j].num_ipv6_pkts);
				out->stats[i][j].num_ipv6_bytes =
					raw_hw[stat_idx].num_ipv6_bytes;
				IPAHAL_DBG_LOW("num_ipv6_bytes %lld\n",
					out->stats[i][j].num_ipv6_bytes);
				stat_idx++;
			}
		}
	}

	return 0;
}

static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_FnR(
	void *params, bool is_atomic_ctx)
{
	struct ipahal_stats_init_pyld *pyld;
	struct ipahal_stats_init_FnR *in =
		(struct ipahal_stats_init_FnR *)params;
	int hdr_entries;
	int num_rules = 0;
	int i, start_entry;
	void *pyld_ptr;
	u32 incremental_offset;

	for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++)
		num_rules += _count_ones(in->rule_id_bitmask[i]);

	if (num_rules == 0) {
		IPAHAL_ERR("no rule ids provided\n");
		return NULL;
	}
	IPAHAL_DBG_LOW("num_rules = %d\n", num_rules);

	hdr_entries = IPAHAL_MAX_RULE_ID_32;
	for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++) {
		if (in->rule_id_bitmask[i] != 0)
			break;
		hdr_entries--;
	}
	start_entry = i;

	for (i = IPAHAL_MAX_RULE_ID_32 - 1; i >= start_entry; i--) {
		if (in->rule_id_bitmask[i] != 0)
			break;
		hdr_entries--;
	}
	IPAHAL_DBG_LOW("hdr_entries = %d\n", hdr_entries);

	pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
		hdr_entries * sizeof(struct ipahal_stats_FnR_hdr_hw) +
		num_rules * sizeof(struct ipahal_stats_FnR_hw),
		is_atomic_ctx);
	if (!pyld) {
		IPAHAL_ERR("no mem\n");
		return NULL;
	}

	pyld->len = hdr_entries * sizeof(struct ipahal_stats_FnR_hdr_hw) +
		num_rules * sizeof(struct ipahal_stats_FnR_hw);

	pyld_ptr = pyld->data;
	incremental_offset =
		(hdr_entries * sizeof(struct ipahal_stats_FnR_hdr_hw))
			/ 8;
	for (i = start_entry; i < hdr_entries; i++) {
		struct ipahal_stats_FnR_hdr_hw *hdr = pyld_ptr;

		hdr->en_mask = in->rule_id_bitmask[i];
		hdr->cnt_offset = incremental_offset;
		/* add the stats entry */
		incremental_offset += _count_ones(in->rule_id_bitmask[i]) *
			sizeof(struct ipahal_stats_FnR_hw) / 8;
		pyld_ptr += sizeof(*hdr);
	}

	return pyld;
}

static int ipahal_get_offset_FnR(void *params,
	struct ipahal_stats_offset *out)
{
	struct ipahal_stats_get_offset_FnR *in =
		(struct ipahal_stats_get_offset_FnR *)params;
	int i;
	int hdr_entries;
	int skip_rules = 0;
	int start_entry;
	int rule_bit = in->rule_id % 32;
	int rule_idx = in->rule_id / 32;

	if (rule_idx >= IPAHAL_MAX_RULE_ID_32) {
		IPAHAL_ERR("invalid rule_id %d\n", in->rule_id);
		return -EPERM;
	}

	hdr_entries = IPAHAL_MAX_RULE_ID_32;
	for (i = 0; i < IPAHAL_MAX_RULE_ID_32; i++) {
		if (in->init.rule_id_bitmask[i] != 0)
			break;
		hdr_entries--;
	}

	if (hdr_entries == 0) {
		IPAHAL_ERR("no rule ids provided\n");
		return -EPERM;
	}
	start_entry = i;

	for (i = IPAHAL_MAX_RULE_ID_32 - 1; i >= 0; i--) {
		if (in->init.rule_id_bitmask[i] != 0)
			break;
		hdr_entries--;
	}
	IPAHAL_DBG_LOW("hdr_entries = %d\n", hdr_entries);

	/* skip the header */
	out->offset = hdr_entries * sizeof(struct ipahal_stats_FnR_hdr_hw);

	/* skip the previous rules  */
	for (i = start_entry; i < rule_idx; i++)
		skip_rules += _count_ones(in->init.rule_id_bitmask[i]);

	for (i = 0; i < rule_bit; i++)
		if (in->init.rule_id_bitmask[rule_idx] & (1 << i))
			skip_rules++;

	out->offset += skip_rules * sizeof(struct ipahal_stats_FnR_hw);
	out->size = sizeof(struct ipahal_stats_FnR_hw);

	return 0;
}

static int ipahal_parse_stats_FnR(void *init_params, void *raw_stats,
	void *parsed_stats)
{
	struct ipahal_stats_FnR_hw *raw_hw =
		(struct ipahal_stats_FnR_hw *)raw_stats;
	struct ipahal_stats_FnR *out =
		(struct ipahal_stats_FnR *)parsed_stats;

	memset(out, 0, sizeof(*out));
	IPAHAL_DBG_LOW("\n");
	out->num_packets = raw_hw->num_packets;
	out->num_packets_hash = raw_hw->num_packets_hash;

	return 0;
}

static struct ipahal_stats_init_pyld *ipahal_generate_init_pyld_drop(
	void *params, bool is_atomic_ctx)
{
	struct ipahal_stats_init_pyld *pyld;
	struct ipahal_stats_init_drop *in =
		(struct ipahal_stats_init_drop *)params;
	int entries = _count_ones(in->enabled_bitmask);

	IPAHAL_DBG_LOW("entries = %d\n", entries);
	pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) +
		entries * sizeof(struct ipahal_stats_drop_hw), is_atomic_ctx);
	if (!pyld) {
		IPAHAL_ERR("no mem\n");
		return NULL;
	}

	pyld->len = entries * sizeof(struct ipahal_stats_drop_hw);

	return pyld;
}

static int ipahal_get_offset_drop(void *params,
	struct ipahal_stats_offset *out)
{
	struct ipahal_stats_get_offset_drop *in =
		(struct ipahal_stats_get_offset_drop *)params;
	int entries = _count_ones(in->init.enabled_bitmask);

	IPAHAL_DBG_LOW("\n");
	out->offset = 0;
	out->size = entries * sizeof(struct ipahal_stats_drop_hw);

	return 0;
}

static int ipahal_parse_stats_drop(void *init_params, void *raw_stats,
	void *parsed_stats)
{
	struct ipahal_stats_init_drop *init =
		(struct ipahal_stats_init_drop *)init_params;
	struct ipahal_stats_drop_hw *raw_hw =
		(struct ipahal_stats_drop_hw *)raw_stats;
	struct ipahal_stats_drop_all *out =
		(struct ipahal_stats_drop_all *)parsed_stats;
	int stat_idx = 0;
	int i;

	memset(out, 0, sizeof(*out));
	IPAHAL_DBG_LOW("\n");
	for (i = 0; i < IPAHAL_MAX_PIPES; i++) {
		if (init->enabled_bitmask & (1 << i)) {
			out->stats[i].drop_byte_cnt =
				raw_hw[stat_idx].drop_byte_cnt;
			out->stats[i].drop_packet_cnt =
				raw_hw[stat_idx].drop_packet_cnt;
			stat_idx++;
		}
	}

	return 0;
}

static struct ipahal_hw_stats_obj
	ipahal_hw_stats_objs[IPA_HW_MAX][IPAHAL_HW_STATS_MAX] = {
	/* IPAv4 */
	[IPA_HW_v4_0][IPAHAL_HW_STATS_QUOTA] = {
		ipahal_generate_init_pyld_quota,
		ipahal_get_offset_quota,
		ipahal_parse_stats_quota
	},
	[IPA_HW_v4_0][IPAHAL_HW_STATS_TETHERING] = {
		ipahal_generate_init_pyld_tethering,
		ipahal_get_offset_tethering,
		ipahal_parse_stats_tethering
	},
	[IPA_HW_v4_0][IPAHAL_HW_STATS_FNR] = {
		ipahal_generate_init_pyld_FnR,
		ipahal_get_offset_FnR,
		ipahal_parse_stats_FnR
	},
	[IPA_HW_v4_0][IPAHAL_HW_STATS_DROP] = {
		ipahal_generate_init_pyld_drop,
		ipahal_get_offset_drop,
		ipahal_parse_stats_drop
	},
};

int ipahal_hw_stats_init(enum ipa_hw_type ipa_hw_type)
{
	int i;
	int j;
	struct ipahal_hw_stats_obj zero_obj;

	IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type);

	if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
		IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
		return -EINVAL;
	}

	memset(&zero_obj, 0, sizeof(zero_obj));
	for (i = IPA_HW_v4_0 ; i < ipa_hw_type ; i++) {
		for (j = 0; j < IPAHAL_HW_STATS_MAX; j++) {
			if (!memcmp(&ipahal_hw_stats_objs[i + 1][j], &zero_obj,
				sizeof(struct ipahal_hw_stats_obj))) {
				memcpy(&ipahal_hw_stats_objs[i + 1][j],
					&ipahal_hw_stats_objs[i][j],
					sizeof(struct ipahal_hw_stats_obj));
			} else {
				/*
				 * explicitly overridden stat.
				 * Check validity
				 */
				if (!ipahal_hw_stats_objs[i + 1][j].
					get_offset) {
					IPAHAL_ERR(
					  "stat=%d get_offset null ver=%d\n",
					  j, i+1);
					WARN_ON(1);
				}
				if (!ipahal_hw_stats_objs[i + 1][j].
				    parse_stats) {
					IPAHAL_ERR(
					  "stat=%d parse_stats null ver=%d\n",
						j, i + 1);
					WARN_ON(1);
				}
			}
		}
	}

	return 0;
}

int ipahal_stats_get_offset(enum ipahal_hw_stats_type type, void *params,
	struct ipahal_stats_offset *out)
{
	if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
		IPAHAL_ERR("Invalid type stat=%d\n", type);
		WARN_ON(1);
		return -EFAULT;
	}

	if (!params || !out) {
		IPAHAL_ERR("Null arg\n");
		WARN_ON(1);
		return -EFAULT;
	}

	return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].get_offset(
		params, out);
}

struct ipahal_stats_init_pyld *ipahal_stats_generate_init_pyld(
	enum ipahal_hw_stats_type type, void *params, bool is_atomic_ctx)
{
	if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
		IPAHAL_ERR("Invalid type stat=%d\n", type);
		WARN_ON(1);
		return NULL;
	}

	if (!params) {
		IPAHAL_ERR("Null arg\n");
		WARN_ON(1);
		return NULL;
	}

	return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].
		generate_init_pyld(params, is_atomic_ctx);
}

int ipahal_parse_stats(enum ipahal_hw_stats_type type, void *init_params,
	void *raw_stats, void *parsed_stats)
{
	if (type < 0 || type >= IPAHAL_HW_STATS_MAX) {
		IPAHAL_ERR("Invalid type stat=%d\n", type);
		WARN_ON(1);
		return -EFAULT;
	}

	if (!raw_stats || !parsed_stats) {
		IPAHAL_ERR("Null arg\n");
		WARN_ON(1);
		return -EFAULT;
	}

	return ipahal_hw_stats_objs[ipahal_ctx->hw_type][type].parse_stats(
		init_params, raw_stats, parsed_stats);
}
+248 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef _IPAHAL_HW_STATS_H_
#define _IPAHAL_HW_STATS_H_

#include <linux/ipa.h>

#define IPAHAL_MAX_PIPES 32
#define IPAHAL_MAX_RULE_ID_32 (1024 / 32) /* 10 bits of rule id */

enum ipahal_hw_stats_type {
	IPAHAL_HW_STATS_QUOTA,
	IPAHAL_HW_STATS_TETHERING,
	IPAHAL_HW_STATS_FNR,
	IPAHAL_HW_STATS_DROP,
	IPAHAL_HW_STATS_MAX
};

/*
 * struct ipahal_stats_init_pyld - Statistics initialization payload
 * @len: length of payload
 * @data: actual payload data
 */
struct ipahal_stats_init_pyld {
	u16 len;
	u16 reserved;
	u8 data[0];
};

/*
 * struct ipahal_stats_offset - Statistics offset parameters
 * @offset: offset of the statistic from beginning of stats table
 * @size: size of the statistics
 */
struct ipahal_stats_offset {
	u32 offset;
	u16 size;
};

/*
 * struct ipahal_stats_init_quota - Initializations parameters for quota
 * @enabled_bitmask: bit mask of pipes to be monitored
 */
struct ipahal_stats_init_quota {
	u32 enabled_bitmask;
};

/*
 * struct ipahal_stats_get_offset_quota - Get offset parameters for quota
 * @init: initialization parameters used in initialization of stats
 */
struct ipahal_stats_get_offset_quota {
	struct ipahal_stats_init_quota init;
};

/*
 * struct ipahal_stats_quota - Quota statistics
 * @num_ipv4_bytes: IPv4 bytes
 * @num_ipv6_bytes: IPv6 bytes
 * @num_ipv4_pkts: IPv4 packets
 * @num_ipv6_pkts: IPv6 packets
 */
struct ipahal_stats_quota {
	u64 num_ipv4_bytes;
	u64 num_ipv6_bytes;
	u64 num_ipv4_pkts;
	u64 num_ipv6_pkts;
};

/*
 * struct ipahal_stats_quota_all - Quota statistics for all pipes
 * @stats: array of statistics per pipe
 */
struct ipahal_stats_quota_all {
	struct ipahal_stats_quota stats[IPAHAL_MAX_PIPES];
};

/*
 * struct ipahal_stats_init_tethering - Initializations parameters for tethering
 * @prod_bitmask: bit mask of producer pipes to be monitored
 * @cons_bitmask: bit mask of consumer pipes to be monitored per producer
 */
struct ipahal_stats_init_tethering {
	u32 prod_bitmask;
	u32 cons_bitmask[IPAHAL_MAX_PIPES];
};

/*
 * struct ipahal_stats_get_offset_tethering - Get offset parameters for
 *	tethering
 * @init: initialization parameters used in initialization of stats
 */
struct ipahal_stats_get_offset_tethering {
	struct ipahal_stats_init_tethering init;
};

/*
 * struct ipahal_stats_tethering - Tethering statistics
 * @num_ipv4_bytes: IPv4 bytes
 * @num_ipv6_bytes: IPv6 bytes
 * @num_ipv4_pkts: IPv4 packets
 * @num_ipv6_pkts: IPv6 packets
 */
struct ipahal_stats_tethering {
	u64 num_ipv4_bytes;
	u64 num_ipv6_bytes;
	u64 num_ipv4_pkts;
	u64 num_ipv6_pkts;
};

/*
 * struct ipahal_stats_tethering_all - Tethering statistics for all pipes
 * @stats: matrix of statistics per pair of pipes
 */
struct ipahal_stats_tethering_all {
	struct ipahal_stats_tethering
		stats[IPAHAL_MAX_PIPES][IPAHAL_MAX_PIPES];
};

/*
 * struct ipahal_stats_init_FnR - Initializations parameters for FnR
 * @rule_id_bitmask: array describes which rule ids to monitor.
 *	rule_id bit is determined by:
 *		index to the array => rule_id / 32
 *		bit to enable => rule_id % 32
 */
struct ipahal_stats_init_FnR {
	u32 rule_id_bitmask[IPAHAL_MAX_RULE_ID_32];
};

/*
 * struct ipahal_stats_get_offset_FnR - Get offset parameters for FnR
 * @init: initialization parameters used in initialization of stats
 * @rule_id: rule_id to get the offset for
 */
struct ipahal_stats_get_offset_FnR {
	struct ipahal_stats_init_FnR init;
	u32 rule_id;
};

/*
 * struct ipahal_stats_FnR - FnR statistics
 * @num_packets: Total number of packets hit this rule
 * @num_packets_hash: Total number of packets hit this rule in hash table
 */
struct ipahal_stats_FnR {
	u32 num_packets;
	u32 num_packets_hash;
};

/*
 * struct ipahal_stats_init_drop - Initializations parameters for Drop
 * @enabled_bitmask: bit mask of pipes to be monitored
 */
struct ipahal_stats_init_drop {
	u32 enabled_bitmask;
};

/*
 * struct ipahal_stats_get_offset_drop - Get offset parameters for Drop
 * @init: initialization parameters used in initialization of stats
 */
struct ipahal_stats_get_offset_drop {
	struct ipahal_stats_init_drop init;
};

/*
 * struct ipahal_stats_drop - Packet Drop statistics
 * @drop_packet_cnt: number of packets dropped
 * @drop_byte_cnt: number of bytes dropped
 */
struct ipahal_stats_drop {
	u32 drop_packet_cnt;
	u32 drop_byte_cnt;
};

/*
 * struct ipahal_stats_drop_all - Drop statistics for all pipes
 * @stats: array of statistics per pipes
 */
struct ipahal_stats_drop_all {
	struct ipahal_stats_drop stats[IPAHAL_MAX_PIPES];
};

/*
 * ipahal_stats_generate_init_pyld - Generate the init payload for stats
 * @type: type of stats
 * @params: init_pyld parameters based of stats type
 * @is_atomic_ctx: is calling context atomic ?
 *
 * This function will generate the initialization payload for a particular
 * statistic in hardware. IPA driver is expected to use this payload to
 * initialize the SRAM.
 *
 * Return: pointer to ipahal_stats_init_pyld on success or NULL on failure.
 */
struct ipahal_stats_init_pyld *ipahal_stats_generate_init_pyld(
	enum ipahal_hw_stats_type type, void *params, bool is_atomic_ctx);

/*
 * ipahal_destroy_stats_init_pyld() - Destroy/Release bulk that was built
 *  by the ipahal_stats_generate_init_pyld function.
 */
static inline void ipahal_destroy_stats_init_pyld(
	struct ipahal_stats_init_pyld *pyld)
{
	kfree(pyld);
}

/*
 * ipahal_stats_get_offset - Get the offset / size of payload for stats
 * @type: type of stats
 * @params: get_offset parameters based of stats type
 * @out: out parameter for the offset and size.
 *
 * This function will return the offset of the counter from beginning of
 * the table.IPA driver is expected to read this portion in SRAM and pass
 * it to ipahal_parse_stats() to interprete the stats.
 *
 * Return: 0 on success and negative on failure
 */
int ipahal_stats_get_offset(enum ipahal_hw_stats_type type, void *params,
	struct ipahal_stats_offset *out);

/*
 * ipahal_parse_stats - parse statistics
 * @type: type of stats
 * @init_params: init_pyld parameters used on init
 * @raw_stats: stats read from IPA SRAM
 * @parsed_stats: pointer to parsed stats based on type
 *
 * Return: 0 on success and negative on failure
 */
int ipahal_parse_stats(enum ipahal_hw_stats_type type, void *init_params,
	void *raw_stats, void *parsed_stats);


#endif /* _IPAHAL_HW_STATS_H_ */
+55 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef _IPAHAL_HW_STATS_I_H_
#define _IPAHAL_HW_STATS_I_H_

#include "ipahal_hw_stats.h"

int ipahal_hw_stats_init(enum ipa_hw_type ipa_hw_type);

struct ipahal_stats_quota_hw {
	u64 num_ipv4_bytes;
	u64 num_ipv4_pkts:32;
	u64 num_ipv6_pkts:32;
	u64 num_ipv6_bytes;
};

struct ipahal_stats_tethering_hdr_hw {
	u64 dst_mask:32;
	u64 offset:32;
};

struct ipahal_stats_tethering_hw {
	u64 num_ipv4_bytes;
	u64 num_ipv4_pkts:32;
	u64 num_ipv6_pkts:32;
	u64 num_ipv6_bytes;
};

struct ipahal_stats_FnR_hdr_hw {
	u64 en_mask:32;
	u64 reserved:16;
	u64 cnt_offset:16;
};

struct ipahal_stats_FnR_hw {
	u64 num_packets_hash:32;
	u64 num_packets:32;
};

struct ipahal_stats_drop_hw {
	u64 drop_byte_cnt:40;
	u64 drop_packet_cnt:24;
};

#endif /* _IPAHAL_HW_STATS_I_H_ */
Loading