1 // SPDX-License-Identifier: GPL-2.0 2 /* Texas Instruments ICSSG Ethernet driver 3 * 4 * Copyright (C) 2018-2021 Texas Instruments Incorporated - https://www.ti.com/ 5 * 6 */ 7 8 #include "icssg_prueth.h" 9 #include "icssg_stats.h" 10 #include <linux/regmap.h> 11 12 #define ICSSG_TX_PACKET_OFFSET 0xA0 13 #define ICSSG_TX_BYTE_OFFSET 0xEC 14 15 static u32 stats_base[] = { 0x54c, /* Slice 0 stats start */ 16 0xb18, /* Slice 1 stats start */ 17 }; 18 19 void emac_update_hardware_stats(struct prueth_emac *emac) 20 { 21 struct prueth *prueth = emac->prueth; 22 int slice = prueth_emac_slice(emac); 23 u32 base = stats_base[slice]; 24 u32 tx_pkt_cnt = 0; 25 u32 val, reg; 26 int i; 27 28 spin_lock(&prueth->stats_lock); 29 30 for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) { 31 /* In MII mode TX lines are swapped inside ICSSG, so read Tx stats 32 * from slice1 for port0 and slice0 for port1 to get accurate Tx 33 * stats for a given port 34 */ 35 if (emac->phy_if == PHY_INTERFACE_MODE_MII && 36 icssg_all_miig_stats[i].offset >= ICSSG_TX_PACKET_OFFSET && 37 icssg_all_miig_stats[i].offset <= ICSSG_TX_BYTE_OFFSET) 38 base = stats_base[slice ^ 1]; 39 regmap_read(prueth->miig_rt, 40 base + icssg_all_miig_stats[i].offset, 41 &val); 42 regmap_write(prueth->miig_rt, 43 base + icssg_all_miig_stats[i].offset, 44 val); 45 46 if (icssg_all_miig_stats[i].offset == ICSSG_TX_PACKET_OFFSET) 47 tx_pkt_cnt = val; 48 49 emac->stats[i] += val; 50 if (icssg_all_miig_stats[i].offset == ICSSG_TX_BYTE_OFFSET) 51 emac->stats[i] -= tx_pkt_cnt * 8; 52 } 53 54 if (prueth->pa_stats) { 55 for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++) { 56 reg = icssg_all_pa_stats[i].offset + 57 slice * sizeof(u32); 58 regmap_read(prueth->pa_stats, reg, &val); 59 emac->pa_stats[i] += val; 60 } 61 } 62 63 spin_unlock(&prueth->stats_lock); 64 } 65 66 void icssg_stats_work_handler(struct work_struct *work) 67 { 68 struct prueth_emac *emac = container_of(work, struct prueth_emac, 69 stats_work.work); 70 emac_update_hardware_stats(emac); 71 72 queue_delayed_work(system_long_wq, &emac->stats_work, 73 msecs_to_jiffies((STATS_TIME_LIMIT_1G_MS * 1000) / emac->speed)); 74 } 75 EXPORT_SYMBOL_GPL(icssg_stats_work_handler); 76 77 int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name) 78 { 79 int i; 80 81 for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) { 82 if (!strcmp(icssg_all_miig_stats[i].name, stat_name)) 83 return emac->stats[icssg_all_miig_stats[i].offset / sizeof(u32)]; 84 } 85 86 if (emac->prueth->pa_stats) { 87 for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++) { 88 if (!strcmp(icssg_all_pa_stats[i].name, stat_name)) 89 return emac->pa_stats[i]; 90 } 91 } 92 93 netdev_err(emac->ndev, "Invalid stats %s\n", stat_name); 94 return -EINVAL; 95 } 96