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

Commit a9a0dbdf authored by Sean Tranchetti's avatar Sean Tranchetti
Browse files

net: qualcomm: rmnet: Add stats for QMAPv5 coalescing



Record various stats about the coalescing process so we can later
query them using ethtool.

Change-Id: I6726e277b8204b38956a332337c946d9f12abf6e
Signed-off-by: default avatarSean Tranchetti <stranche@codeaurora.org>
parent e2884cd2
Loading
Loading
Loading
Loading
+28 −1
Original line number Original line Diff line number Diff line
/* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved.
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * 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
 * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
#define _RMNET_CONFIG_H_
#define _RMNET_CONFIG_H_


#define RMNET_MAX_LOGICAL_EP 255
#define RMNET_MAX_LOGICAL_EP 255
#define RMNET_MAX_VEID 4


struct rmnet_endpoint {
struct rmnet_endpoint {
	u8 mux_id;
	u8 mux_id;
@@ -88,6 +89,31 @@ struct rmnet_pcpu_stats {
	struct u64_stats_sync syncp;
	struct u64_stats_sync syncp;
};
};


struct rmnet_coal_close_stats {
	u64 non_coal;
	u64 ip_miss;
	u64 trans_miss;
	u64 hw_nl;
	u64 hw_pkt;
	u64 hw_byte;
	u64 hw_time;
	u64 hw_evict;
	u64 coal;
};

struct rmnet_coal_stats {
	u64 coal_rx;
	u64 coal_pkts;
	u64 coal_hdr_nlo_err;
	u64 coal_hdr_pkt_err;
	u64 coal_csum_err;
	u64 coal_reconstruct;
	u64 coal_ip_invalid;
	u64 coal_trans_invalid;
	struct rmnet_coal_close_stats close;
	u64 coal_veid[RMNET_MAX_VEID];
};

struct rmnet_priv_stats {
struct rmnet_priv_stats {
	u64 csum_ok;
	u64 csum_ok;
	u64 csum_valid_unset;
	u64 csum_valid_unset;
@@ -99,6 +125,7 @@ struct rmnet_priv_stats {
	u64 csum_skipped;
	u64 csum_skipped;
	u64 csum_sw;
	u64 csum_sw;
	u64 csum_hw;
	u64 csum_hw;
	struct rmnet_coal_stats coal;
};
};


struct rmnet_priv {
struct rmnet_priv {
+83 −9
Original line number Original line Diff line number Diff line
@@ -559,16 +559,19 @@ static struct sk_buff *rmnet_map_segment_udp_skb(struct sk_buff *coal_skb,
{
{
	struct sk_buff *skbn;
	struct sk_buff *skbn;
	struct iphdr *iph = (struct iphdr *)rmnet_map_data_ptr(coal_skb);
	struct iphdr *iph = (struct iphdr *)rmnet_map_data_ptr(coal_skb);
	struct rmnet_priv *priv = netdev_priv(coal_skb->dev);
	struct udphdr *uh;
	struct udphdr *uh;
	u32 alloc_len;
	u32 alloc_len;
	u16 ip_len, udp_len = sizeof(*uh);
	u16 ip_len, udp_len = sizeof(*uh);


	if (iph->version == 4)
	if (iph->version == 4) {
		ip_len = iph->ihl * 4;
		ip_len = iph->ihl * 4;
	else if (iph->version == 6)
	} else if (iph->version == 6) {
		ip_len = sizeof(struct ipv6hdr);
		ip_len = sizeof(struct ipv6hdr);
	else
	} else {
		priv->stats.coal.coal_ip_invalid++;
		return NULL;
		return NULL;
	}


	uh = (struct udphdr *)(rmnet_map_data_ptr(coal_skb) + ip_len);
	uh = (struct udphdr *)(rmnet_map_data_ptr(coal_skb) + ip_len);


@@ -611,6 +614,7 @@ static struct sk_buff *rmnet_map_segment_udp_skb(struct sk_buff *coal_skb,


	skbn->ip_summed = CHECKSUM_UNNECESSARY;
	skbn->ip_summed = CHECKSUM_UNNECESSARY;
	skbn->dev = coal_skb->dev;
	skbn->dev = coal_skb->dev;
	priv->stats.coal.coal_reconstruct++;


	return skbn;
	return skbn;
}
}
@@ -625,16 +629,19 @@ static struct sk_buff *rmnet_map_segment_tcp_skb(struct sk_buff *coal_skb,
{
{
	struct sk_buff *skbn;
	struct sk_buff *skbn;
	struct iphdr *iph = (struct iphdr *)rmnet_map_data_ptr(coal_skb);
	struct iphdr *iph = (struct iphdr *)rmnet_map_data_ptr(coal_skb);
	struct rmnet_priv *priv = netdev_priv(coal_skb->dev);
	struct tcphdr *th;
	struct tcphdr *th;
	u32 alloc_len;
	u32 alloc_len;
	u16 ip_len, tcp_len;
	u16 ip_len, tcp_len;


	if (iph->version == 4)
	if (iph->version == 4) {
		ip_len = iph->ihl * 4;
		ip_len = iph->ihl * 4;
	else if (iph->version == 6)
	} else if (iph->version == 6) {
		ip_len = sizeof(struct ipv6hdr);
		ip_len = sizeof(struct ipv6hdr);
	else
	} else {
		priv->stats.coal.coal_ip_invalid++;
		return NULL;
		return NULL;
	}


	th = (struct tcphdr *)(rmnet_map_data_ptr(coal_skb) + ip_len);
	th = (struct tcphdr *)(rmnet_map_data_ptr(coal_skb) + ip_len);
	tcp_len = th->doff * 4;
	tcp_len = th->doff * 4;
@@ -678,6 +685,7 @@ static struct sk_buff *rmnet_map_segment_tcp_skb(struct sk_buff *coal_skb,


	skbn->ip_summed = CHECKSUM_UNNECESSARY;
	skbn->ip_summed = CHECKSUM_UNNECESSARY;
	skbn->dev = coal_skb->dev;
	skbn->dev = coal_skb->dev;
	priv->stats.coal.coal_reconstruct++;


	return skbn;
	return skbn;
}
}
@@ -697,6 +705,7 @@ static void rmnet_map_segment_coal_data(struct sk_buff *coal_skb,
				   int start_pkt_num,
				   int start_pkt_num,
				   u16 pkt_len);
				   u16 pkt_len);
	struct iphdr *iph;
	struct iphdr *iph;
	struct rmnet_priv *priv = netdev_priv(coal_skb->dev);
	struct rmnet_map_v5_coal_header *coal_hdr;
	struct rmnet_map_v5_coal_header *coal_hdr;
	u32 start = 0;
	u32 start = 0;
	u16 pkt_len, ip_len, trans_len;
	u16 pkt_len, ip_len, trans_len;
@@ -719,6 +728,7 @@ static void rmnet_map_segment_coal_data(struct sk_buff *coal_skb,
		protocol = ((struct ipv6hdr *)iph)->nexthdr;
		protocol = ((struct ipv6hdr *)iph)->nexthdr;
		ip_len = sizeof(struct ipv6hdr);
		ip_len = sizeof(struct ipv6hdr);
	} else {
	} else {
		priv->stats.coal.coal_ip_invalid++;
		return;
		return;
	}
	}


@@ -731,6 +741,7 @@ static void rmnet_map_segment_coal_data(struct sk_buff *coal_skb,
		trans_len = sizeof(struct udphdr);
		trans_len = sizeof(struct udphdr);
		segment = rmnet_map_segment_udp_skb;
		segment = rmnet_map_segment_udp_skb;
	} else {
	} else {
		priv->stats.coal.coal_trans_invalid++;
		return;
		return;
	}
	}


@@ -741,6 +752,7 @@ static void rmnet_map_segment_coal_data(struct sk_buff *coal_skb,
		     pkt++, total_pkt++) {
		     pkt++, total_pkt++) {
			nlo_err_mask <<= 1;
			nlo_err_mask <<= 1;
			if (nlo_err_mask & (1ULL << 63)) {
			if (nlo_err_mask & (1ULL << 63)) {
				priv->stats.coal.coal_csum_err++;
				/* skip over bad packet */
				/* skip over bad packet */
				start += pkt_len;
				start += pkt_len;
				start_pkt_num = total_pkt + 1;
				start_pkt_num = total_pkt + 1;
@@ -759,6 +771,51 @@ static void rmnet_map_segment_coal_data(struct sk_buff *coal_skb,
	}
	}
}
}


/* Record reason for coalescing pipe closure */
static void rmnet_map_data_log_close_stats(struct rmnet_priv *priv, u8 type,
					   u8 code)
{
	struct rmnet_coal_close_stats *stats = &priv->stats.coal.close;

	switch (type) {
	case RMNET_MAP_COAL_CLOSE_NON_COAL:
		stats->non_coal++;
		break;
	case RMNET_MAP_COAL_CLOSE_IP_MISS:
		stats->ip_miss++;
		break;
	case RMNET_MAP_COAL_CLOSE_TRANS_MISS:
		stats->trans_miss++;
		break;
	case RMNET_MAP_COAL_CLOSE_HW:
		switch (code) {
		case RMNET_MAP_COAL_CLOSE_HW_NL:
			stats->hw_nl++;
			break;
		case RMNET_MAP_COAL_CLOSE_HW_PKT:
			stats->hw_pkt++;
			break;
		case RMNET_MAP_COAL_CLOSE_HW_BYTE:
			stats->hw_byte++;
			break;
		case RMNET_MAP_COAL_CLOSE_HW_TIME:
			stats->hw_time++;
			break;
		case RMNET_MAP_COAL_CLOSE_HW_EVICT:
			stats->hw_evict++;
			break;
		default:
			break;
		}
		break;
	case RMNET_MAP_COAL_CLOSE_COAL:
		stats->coal++;
		break;
	default:
		break;
	}
}

/* Check if the coalesced header has any incorrect values, in which case, the
/* Check if the coalesced header has any incorrect values, in which case, the
 * entire coalesced skb must be dropped. Then check if there are any
 * entire coalesced skb must be dropped. Then check if there are any
 * checksum issues
 * checksum issues
@@ -768,16 +825,20 @@ static int rmnet_map_data_check_coal_header(struct sk_buff *skb,
{
{
	struct rmnet_map_v5_coal_header *coal_hdr;
	struct rmnet_map_v5_coal_header *coal_hdr;
	unsigned char *data = rmnet_map_data_ptr(skb);
	unsigned char *data = rmnet_map_data_ptr(skb);
	struct rmnet_priv *priv = netdev_priv(skb->dev);
	u64 mask = 0;
	u64 mask = 0;
	int i;
	int i;
	u8 pkts = 0;
	u8 veid, pkts = 0;


	coal_hdr = ((struct rmnet_map_v5_coal_header *)
	coal_hdr = ((struct rmnet_map_v5_coal_header *)
		    (data + sizeof(struct rmnet_map_header)));
		    (data + sizeof(struct rmnet_map_header)));
	veid = coal_hdr->virtual_channel_id;


	if (coal_hdr->num_nlos == 0 ||
	if (coal_hdr->num_nlos == 0 ||
	    coal_hdr->num_nlos > RMNET_MAP_V5_MAX_NLOS)
	    coal_hdr->num_nlos > RMNET_MAP_V5_MAX_NLOS) {
		priv->stats.coal.coal_hdr_nlo_err++;
		return -EINVAL;
		return -EINVAL;
	}


	for (i = 0; i < RMNET_MAP_V5_MAX_NLOS; i++) {
	for (i = 0; i < RMNET_MAP_V5_MAX_NLOS; i++) {
		/* If there is a checksum issue, we need to split
		/* If there is a checksum issue, we need to split
@@ -790,9 +851,21 @@ static int rmnet_map_data_check_coal_header(struct sk_buff *skb,


		/* Track total packets in frame */
		/* Track total packets in frame */
		pkts += pkt;
		pkts += pkt;
		if (pkts > RMNET_MAP_V5_MAX_PACKETS)
		if (pkts > RMNET_MAP_V5_MAX_PACKETS) {
			priv->stats.coal.coal_hdr_pkt_err++;
			return -EINVAL;
			return -EINVAL;
		}
		}
	}

	/* Track number of packets we get inside of coalesced frames */
	priv->stats.coal.coal_pkts += pkts;

	/* Update ethtool stats */
	rmnet_map_data_log_close_stats(priv,
				       coal_hdr->close_type,
				       coal_hdr->close_value);
	if (veid < RMNET_MAX_VEID)
		priv->stats.coal.coal_veid[veid]++;


	*nlo_err_mask = mask;
	*nlo_err_mask = mask;


@@ -809,6 +882,7 @@ int rmnet_map_process_next_hdr_packet(struct sk_buff *skb,


	switch (rmnet_map_get_next_hdr_type(skb)) {
	switch (rmnet_map_get_next_hdr_type(skb)) {
	case RMNET_MAP_HEADER_TYPE_COALESCING:
	case RMNET_MAP_HEADER_TYPE_COALESCING:
		priv->stats.coal.coal_rx++;
		rc = rmnet_map_data_check_coal_header(skb, &nlo_err_mask);
		rc = rmnet_map_data_check_coal_header(skb, &nlo_err_mask);
		if (rc)
		if (rc)
			return rc;
			return rc;
+21 −0
Original line number Original line Diff line number Diff line
@@ -198,6 +198,27 @@ static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = {
	"Checksum skipped",
	"Checksum skipped",
	"Checksum computed in software",
	"Checksum computed in software",
	"Checksum computed in hardware",
	"Checksum computed in hardware",
	"Coalescing packets received",
	"Coalesced packets",
	"Coalescing header NLO errors",
	"Coalescing header pcount errors",
	"Coalescing checksum errors",
	"Coalescing packet reconstructs",
	"Coalescing IP version invalid",
	"Coalescing L4 header invalid",
	"Coalescing close Non-coalescable",
	"Coalescing close L3 mismatch",
	"Coalescing close L4 mismatch",
	"Coalescing close HW NLO limit",
	"Coalescing close HW packet limit",
	"Coalescing close HW byte limit",
	"Coalescing close HW time limit",
	"Coalescing close HW eviction",
	"Coalescing close Coalescable",
	"Coalescing packets over VEID0",
	"Coalescing packets over VEID1",
	"Coalescing packets over VEID2",
	"Coalescing packets over VEID3",
};
};


static const char rmnet_port_gstrings_stats[][ETH_GSTRING_LEN] = {
static const char rmnet_port_gstrings_stats[][ETH_GSTRING_LEN] = {