Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sfc: add extra RX channel to receive MAE counter updates on ef100

Currently there is no counter-allocating machinery to connect the
resulting counter update values to; that will be added in a
subsequent patch.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Edward Cree and committed by
David S. Miller
25730d8b e5731274

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