xref: /linux/drivers/net/ethernet/sfc/tc_counters.c (revision 25730d8be5d8bc691ed89dca065f2b229b244ae0)
1*25730d8bSEdward Cree // SPDX-License-Identifier: GPL-2.0-only
2*25730d8bSEdward Cree /****************************************************************************
3*25730d8bSEdward Cree  * Driver for Solarflare network controllers and boards
4*25730d8bSEdward Cree  * Copyright 2022 Advanced Micro Devices, Inc.
5*25730d8bSEdward Cree  *
6*25730d8bSEdward Cree  * This program is free software; you can redistribute it and/or modify it
7*25730d8bSEdward Cree  * under the terms of the GNU General Public License version 2 as published
8*25730d8bSEdward Cree  * by the Free Software Foundation, incorporated herein by reference.
9*25730d8bSEdward Cree  */
10*25730d8bSEdward Cree 
11*25730d8bSEdward Cree #include "tc_counters.h"
12*25730d8bSEdward Cree #include "mae_counter_format.h"
13*25730d8bSEdward Cree #include "mae.h"
14*25730d8bSEdward Cree #include "rx_common.h"
15*25730d8bSEdward Cree 
16*25730d8bSEdward Cree /* TC Channel.  Counter updates are delivered on this channel's RXQ. */
17*25730d8bSEdward Cree 
18*25730d8bSEdward Cree static void efx_tc_handle_no_channel(struct efx_nic *efx)
19*25730d8bSEdward Cree {
20*25730d8bSEdward Cree 	netif_warn(efx, drv, efx->net_dev,
21*25730d8bSEdward Cree 		   "MAE counters require MSI-X and 1 additional interrupt vector.\n");
22*25730d8bSEdward Cree }
23*25730d8bSEdward Cree 
24*25730d8bSEdward Cree static int efx_tc_probe_channel(struct efx_channel *channel)
25*25730d8bSEdward Cree {
26*25730d8bSEdward Cree 	struct efx_rx_queue *rx_queue = &channel->rx_queue;
27*25730d8bSEdward Cree 
28*25730d8bSEdward Cree 	channel->irq_moderation_us = 0;
29*25730d8bSEdward Cree 	rx_queue->core_index = 0;
30*25730d8bSEdward Cree 
31*25730d8bSEdward Cree 	INIT_WORK(&rx_queue->grant_work, efx_mae_counters_grant_credits);
32*25730d8bSEdward Cree 
33*25730d8bSEdward Cree 	return 0;
34*25730d8bSEdward Cree }
35*25730d8bSEdward Cree 
36*25730d8bSEdward Cree static int efx_tc_start_channel(struct efx_channel *channel)
37*25730d8bSEdward Cree {
38*25730d8bSEdward Cree 	struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
39*25730d8bSEdward Cree 	struct efx_nic *efx = channel->efx;
40*25730d8bSEdward Cree 
41*25730d8bSEdward Cree 	return efx_mae_start_counters(efx, rx_queue);
42*25730d8bSEdward Cree }
43*25730d8bSEdward Cree 
44*25730d8bSEdward Cree static void efx_tc_stop_channel(struct efx_channel *channel)
45*25730d8bSEdward Cree {
46*25730d8bSEdward Cree 	struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
47*25730d8bSEdward Cree 	struct efx_nic *efx = channel->efx;
48*25730d8bSEdward Cree 	int rc;
49*25730d8bSEdward Cree 
50*25730d8bSEdward Cree 	rc = efx_mae_stop_counters(efx, rx_queue);
51*25730d8bSEdward Cree 	if (rc)
52*25730d8bSEdward Cree 		netif_warn(efx, drv, efx->net_dev,
53*25730d8bSEdward Cree 			   "Failed to stop MAE counters streaming, rc=%d.\n",
54*25730d8bSEdward Cree 			   rc);
55*25730d8bSEdward Cree 	rx_queue->grant_credits = false;
56*25730d8bSEdward Cree 	flush_work(&rx_queue->grant_work);
57*25730d8bSEdward Cree }
58*25730d8bSEdward Cree 
59*25730d8bSEdward Cree static void efx_tc_remove_channel(struct efx_channel *channel)
60*25730d8bSEdward Cree {
61*25730d8bSEdward Cree }
62*25730d8bSEdward Cree 
63*25730d8bSEdward Cree static void efx_tc_get_channel_name(struct efx_channel *channel,
64*25730d8bSEdward Cree 				    char *buf, size_t len)
65*25730d8bSEdward Cree {
66*25730d8bSEdward Cree 	snprintf(buf, len, "%s-mae", channel->efx->name);
67*25730d8bSEdward Cree }
68*25730d8bSEdward Cree 
69*25730d8bSEdward Cree static void efx_tc_counter_update(struct efx_nic *efx,
70*25730d8bSEdward Cree 				  enum efx_tc_counter_type counter_type,
71*25730d8bSEdward Cree 				  u32 counter_idx, u64 packets, u64 bytes,
72*25730d8bSEdward Cree 				  u32 mark)
73*25730d8bSEdward Cree {
74*25730d8bSEdward Cree 	/* Software counter objects do not exist yet, for now we ignore this */
75*25730d8bSEdward Cree }
76*25730d8bSEdward Cree 
77*25730d8bSEdward Cree static void efx_tc_rx_version_1(struct efx_nic *efx, const u8 *data, u32 mark)
78*25730d8bSEdward Cree {
79*25730d8bSEdward Cree 	u16 n_counters, i;
80*25730d8bSEdward Cree 
81*25730d8bSEdward Cree 	/* Header format:
82*25730d8bSEdward Cree 	 * + |   0    |   1    |   2    |   3    |
83*25730d8bSEdward Cree 	 * 0 |version |         reserved         |
84*25730d8bSEdward Cree 	 * 4 |    seq_index    |   n_counters    |
85*25730d8bSEdward Cree 	 */
86*25730d8bSEdward Cree 
87*25730d8bSEdward Cree 	n_counters = le16_to_cpu(*(const __le16 *)(data + 6));
88*25730d8bSEdward Cree 
89*25730d8bSEdward Cree 	/* Counter update entry format:
90*25730d8bSEdward Cree 	 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f |
91*25730d8bSEdward Cree 	 * |  counter_idx  |     packet_count      |      byte_count       |
92*25730d8bSEdward Cree 	 */
93*25730d8bSEdward Cree 	for (i = 0; i < n_counters; i++) {
94*25730d8bSEdward Cree 		const void *entry = data + 8 + 16 * i;
95*25730d8bSEdward Cree 		u64 packet_count, byte_count;
96*25730d8bSEdward Cree 		u32 counter_idx;
97*25730d8bSEdward Cree 
98*25730d8bSEdward Cree 		counter_idx = le32_to_cpu(*(const __le32 *)entry);
99*25730d8bSEdward Cree 		packet_count = le32_to_cpu(*(const __le32 *)(entry + 4)) |
100*25730d8bSEdward Cree 			       ((u64)le16_to_cpu(*(const __le16 *)(entry + 8)) << 32);
101*25730d8bSEdward Cree 		byte_count = le16_to_cpu(*(const __le16 *)(entry + 10)) |
102*25730d8bSEdward Cree 			     ((u64)le32_to_cpu(*(const __le32 *)(entry + 12)) << 16);
103*25730d8bSEdward Cree 		efx_tc_counter_update(efx, EFX_TC_COUNTER_TYPE_AR, counter_idx,
104*25730d8bSEdward Cree 				      packet_count, byte_count, mark);
105*25730d8bSEdward Cree 	}
106*25730d8bSEdward Cree }
107*25730d8bSEdward Cree 
108*25730d8bSEdward Cree #define TCV2_HDR_PTR(pkt, field)						\
109*25730d8bSEdward Cree 	((void)BUILD_BUG_ON_ZERO(ERF_SC_PACKETISER_HEADER_##field##_LBN & 7),	\
110*25730d8bSEdward Cree 	 (pkt) + ERF_SC_PACKETISER_HEADER_##field##_LBN / 8)
111*25730d8bSEdward Cree #define TCV2_HDR_BYTE(pkt, field)						\
112*25730d8bSEdward Cree 	((void)BUILD_BUG_ON_ZERO(ERF_SC_PACKETISER_HEADER_##field##_WIDTH != 8),\
113*25730d8bSEdward Cree 	 *TCV2_HDR_PTR(pkt, field))
114*25730d8bSEdward Cree #define TCV2_HDR_WORD(pkt, field)						\
115*25730d8bSEdward Cree 	((void)BUILD_BUG_ON_ZERO(ERF_SC_PACKETISER_HEADER_##field##_WIDTH != 16),\
116*25730d8bSEdward Cree 	 (void)BUILD_BUG_ON_ZERO(ERF_SC_PACKETISER_HEADER_##field##_LBN & 15),	\
117*25730d8bSEdward Cree 	 *(__force const __le16 *)TCV2_HDR_PTR(pkt, field))
118*25730d8bSEdward Cree #define TCV2_PKT_PTR(pkt, poff, i, field)					\
119*25730d8bSEdward Cree 	((void)BUILD_BUG_ON_ZERO(ERF_SC_PACKETISER_PAYLOAD_##field##_LBN & 7),	\
120*25730d8bSEdward Cree 	 (pkt) + ERF_SC_PACKETISER_PAYLOAD_##field##_LBN/8 + poff +		\
121*25730d8bSEdward Cree 	 i * ER_RX_SL_PACKETISER_PAYLOAD_WORD_SIZE)
122*25730d8bSEdward Cree 
123*25730d8bSEdward Cree /* Read a little-endian 48-bit field with 16-bit alignment */
124*25730d8bSEdward Cree static u64 efx_tc_read48(const __le16 *field)
125*25730d8bSEdward Cree {
126*25730d8bSEdward Cree 	u64 out = 0;
127*25730d8bSEdward Cree 	int i;
128*25730d8bSEdward Cree 
129*25730d8bSEdward Cree 	for (i = 0; i < 3; i++)
130*25730d8bSEdward Cree 		out |= (u64)le16_to_cpu(field[i]) << (i * 16);
131*25730d8bSEdward Cree 	return out;
132*25730d8bSEdward Cree }
133*25730d8bSEdward Cree 
134*25730d8bSEdward Cree static enum efx_tc_counter_type efx_tc_rx_version_2(struct efx_nic *efx,
135*25730d8bSEdward Cree 						    const u8 *data, u32 mark)
136*25730d8bSEdward Cree {
137*25730d8bSEdward Cree 	u8 payload_offset, header_offset, ident;
138*25730d8bSEdward Cree 	enum efx_tc_counter_type type;
139*25730d8bSEdward Cree 	u16 n_counters, i;
140*25730d8bSEdward Cree 
141*25730d8bSEdward Cree 	ident = TCV2_HDR_BYTE(data, IDENTIFIER);
142*25730d8bSEdward Cree 	switch (ident) {
143*25730d8bSEdward Cree 	case ERF_SC_PACKETISER_HEADER_IDENTIFIER_AR:
144*25730d8bSEdward Cree 		type = EFX_TC_COUNTER_TYPE_AR;
145*25730d8bSEdward Cree 		break;
146*25730d8bSEdward Cree 	case ERF_SC_PACKETISER_HEADER_IDENTIFIER_CT:
147*25730d8bSEdward Cree 		type = EFX_TC_COUNTER_TYPE_CT;
148*25730d8bSEdward Cree 		break;
149*25730d8bSEdward Cree 	case ERF_SC_PACKETISER_HEADER_IDENTIFIER_OR:
150*25730d8bSEdward Cree 		type = EFX_TC_COUNTER_TYPE_OR;
151*25730d8bSEdward Cree 		break;
152*25730d8bSEdward Cree 	default:
153*25730d8bSEdward Cree 		if (net_ratelimit())
154*25730d8bSEdward Cree 			netif_err(efx, drv, efx->net_dev,
155*25730d8bSEdward Cree 				  "ignored v2 MAE counter packet (bad identifier %u"
156*25730d8bSEdward Cree 				  "), counters may be inaccurate\n", ident);
157*25730d8bSEdward Cree 		return EFX_TC_COUNTER_TYPE_MAX;
158*25730d8bSEdward Cree 	}
159*25730d8bSEdward Cree 	header_offset = TCV2_HDR_BYTE(data, HEADER_OFFSET);
160*25730d8bSEdward Cree 	/* mae_counter_format.h implies that this offset is fixed, since it
161*25730d8bSEdward Cree 	 * carries on with SOP-based LBNs for the fields in this header
162*25730d8bSEdward Cree 	 */
163*25730d8bSEdward Cree 	if (header_offset != ERF_SC_PACKETISER_HEADER_HEADER_OFFSET_DEFAULT) {
164*25730d8bSEdward Cree 		if (net_ratelimit())
165*25730d8bSEdward Cree 			netif_err(efx, drv, efx->net_dev,
166*25730d8bSEdward Cree 				  "choked on v2 MAE counter packet (bad header_offset %u"
167*25730d8bSEdward Cree 				  "), counters may be inaccurate\n", header_offset);
168*25730d8bSEdward Cree 		return EFX_TC_COUNTER_TYPE_MAX;
169*25730d8bSEdward Cree 	}
170*25730d8bSEdward Cree 	payload_offset = TCV2_HDR_BYTE(data, PAYLOAD_OFFSET);
171*25730d8bSEdward Cree 	n_counters = le16_to_cpu(TCV2_HDR_WORD(data, COUNT));
172*25730d8bSEdward Cree 
173*25730d8bSEdward Cree 	for (i = 0; i < n_counters; i++) {
174*25730d8bSEdward Cree 		const void *counter_idx_p, *packet_count_p, *byte_count_p;
175*25730d8bSEdward Cree 		u64 packet_count, byte_count;
176*25730d8bSEdward Cree 		u32 counter_idx;
177*25730d8bSEdward Cree 
178*25730d8bSEdward Cree 		/* 24-bit field with 32-bit alignment */
179*25730d8bSEdward Cree 		counter_idx_p = TCV2_PKT_PTR(data, payload_offset, i, COUNTER_INDEX);
180*25730d8bSEdward Cree 		BUILD_BUG_ON(ERF_SC_PACKETISER_PAYLOAD_COUNTER_INDEX_WIDTH != 24);
181*25730d8bSEdward Cree 		BUILD_BUG_ON(ERF_SC_PACKETISER_PAYLOAD_COUNTER_INDEX_LBN & 31);
182*25730d8bSEdward Cree 		counter_idx = le32_to_cpu(*(const __le32 *)counter_idx_p) & 0xffffff;
183*25730d8bSEdward Cree 		/* 48-bit field with 16-bit alignment */
184*25730d8bSEdward Cree 		packet_count_p = TCV2_PKT_PTR(data, payload_offset, i, PACKET_COUNT);
185*25730d8bSEdward Cree 		BUILD_BUG_ON(ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_WIDTH != 48);
186*25730d8bSEdward Cree 		BUILD_BUG_ON(ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_LBN & 15);
187*25730d8bSEdward Cree 		packet_count = efx_tc_read48((const __le16 *)packet_count_p);
188*25730d8bSEdward Cree 		/* 48-bit field with 16-bit alignment */
189*25730d8bSEdward Cree 		byte_count_p = TCV2_PKT_PTR(data, payload_offset, i, BYTE_COUNT);
190*25730d8bSEdward Cree 		BUILD_BUG_ON(ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_WIDTH != 48);
191*25730d8bSEdward Cree 		BUILD_BUG_ON(ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_LBN & 15);
192*25730d8bSEdward Cree 		byte_count = efx_tc_read48((const __le16 *)byte_count_p);
193*25730d8bSEdward Cree 
194*25730d8bSEdward Cree 		if (type == EFX_TC_COUNTER_TYPE_CT) {
195*25730d8bSEdward Cree 			/* CT counters are 1-bit saturating counters to update
196*25730d8bSEdward Cree 			 * the lastuse time in CT stats. A received CT counter
197*25730d8bSEdward Cree 			 * should have packet counter to 0 and only LSB bit on
198*25730d8bSEdward Cree 			 * in byte counter.
199*25730d8bSEdward Cree 			 */
200*25730d8bSEdward Cree 			if (packet_count || byte_count != 1)
201*25730d8bSEdward Cree 				netdev_warn_once(efx->net_dev,
202*25730d8bSEdward Cree 						 "CT counter with inconsistent state (%llu, %llu)\n",
203*25730d8bSEdward Cree 						 packet_count, byte_count);
204*25730d8bSEdward Cree 			/* Do not increment the driver's byte counter */
205*25730d8bSEdward Cree 			byte_count = 0;
206*25730d8bSEdward Cree 		}
207*25730d8bSEdward Cree 
208*25730d8bSEdward Cree 		efx_tc_counter_update(efx, type, counter_idx, packet_count,
209*25730d8bSEdward Cree 				      byte_count, mark);
210*25730d8bSEdward Cree 	}
211*25730d8bSEdward Cree 	return type;
212*25730d8bSEdward Cree }
213*25730d8bSEdward Cree 
214*25730d8bSEdward Cree /* We always swallow the packet, whether successful or not, since it's not
215*25730d8bSEdward Cree  * a network packet and shouldn't ever be forwarded to the stack.
216*25730d8bSEdward Cree  * @mark is the generation count for counter allocations.
217*25730d8bSEdward Cree  */
218*25730d8bSEdward Cree static bool efx_tc_rx(struct efx_rx_queue *rx_queue, u32 mark)
219*25730d8bSEdward Cree {
220*25730d8bSEdward Cree 	struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
221*25730d8bSEdward Cree 	struct efx_rx_buffer *rx_buf = efx_rx_buffer(rx_queue,
222*25730d8bSEdward Cree 						     channel->rx_pkt_index);
223*25730d8bSEdward Cree 	const u8 *data = efx_rx_buf_va(rx_buf);
224*25730d8bSEdward Cree 	struct efx_nic *efx = rx_queue->efx;
225*25730d8bSEdward Cree 	enum efx_tc_counter_type type;
226*25730d8bSEdward Cree 	u8 version;
227*25730d8bSEdward Cree 
228*25730d8bSEdward Cree 	/* version is always first byte of packet */
229*25730d8bSEdward Cree 	version = *data;
230*25730d8bSEdward Cree 	switch (version) {
231*25730d8bSEdward Cree 	case 1:
232*25730d8bSEdward Cree 		type = EFX_TC_COUNTER_TYPE_AR;
233*25730d8bSEdward Cree 		efx_tc_rx_version_1(efx, data, mark);
234*25730d8bSEdward Cree 		break;
235*25730d8bSEdward Cree 	case ERF_SC_PACKETISER_HEADER_VERSION_VALUE: // 2
236*25730d8bSEdward Cree 		type = efx_tc_rx_version_2(efx, data, mark);
237*25730d8bSEdward Cree 		break;
238*25730d8bSEdward Cree 	default:
239*25730d8bSEdward Cree 		if (net_ratelimit())
240*25730d8bSEdward Cree 			netif_err(efx, drv, efx->net_dev,
241*25730d8bSEdward Cree 				  "choked on MAE counter packet (bad version %u"
242*25730d8bSEdward Cree 				  "); counters may be inaccurate\n",
243*25730d8bSEdward Cree 				  version);
244*25730d8bSEdward Cree 		goto out;
245*25730d8bSEdward Cree 	}
246*25730d8bSEdward Cree 
247*25730d8bSEdward Cree 	/* Update seen_gen unconditionally, to avoid a missed wakeup if
248*25730d8bSEdward Cree 	 * we race with efx_mae_stop_counters().
249*25730d8bSEdward Cree 	 */
250*25730d8bSEdward Cree 	efx->tc->seen_gen[type] = mark;
251*25730d8bSEdward Cree 	if (efx->tc->flush_counters &&
252*25730d8bSEdward Cree 	    (s32)(efx->tc->flush_gen[type] - mark) <= 0)
253*25730d8bSEdward Cree 		wake_up(&efx->tc->flush_wq);
254*25730d8bSEdward Cree out:
255*25730d8bSEdward Cree 	efx_free_rx_buffers(rx_queue, rx_buf, 1);
256*25730d8bSEdward Cree 	channel->rx_pkt_n_frags = 0;
257*25730d8bSEdward Cree 	return true;
258*25730d8bSEdward Cree }
259*25730d8bSEdward Cree 
260*25730d8bSEdward Cree const struct efx_channel_type efx_tc_channel_type = {
261*25730d8bSEdward Cree 	.handle_no_channel	= efx_tc_handle_no_channel,
262*25730d8bSEdward Cree 	.pre_probe		= efx_tc_probe_channel,
263*25730d8bSEdward Cree 	.start			= efx_tc_start_channel,
264*25730d8bSEdward Cree 	.stop			= efx_tc_stop_channel,
265*25730d8bSEdward Cree 	.post_remove		= efx_tc_remove_channel,
266*25730d8bSEdward Cree 	.get_name		= efx_tc_get_channel_name,
267*25730d8bSEdward Cree 	.receive_raw		= efx_tc_rx,
268*25730d8bSEdward Cree 	.keep_eventq		= true,
269*25730d8bSEdward Cree };
270