630 lines
10 KiB
C
630 lines
10 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
|
||
|
*/
|
||
|
#include "sja1105.h"
|
||
|
|
||
|
enum sja1105_counter_index {
|
||
|
__SJA1105_COUNTER_UNUSED,
|
||
|
/* MAC */
|
||
|
N_RUNT,
|
||
|
N_SOFERR,
|
||
|
N_ALIGNERR,
|
||
|
N_MIIERR,
|
||
|
TYPEERR,
|
||
|
SIZEERR,
|
||
|
TCTIMEOUT,
|
||
|
PRIORERR,
|
||
|
NOMASTER,
|
||
|
MEMOV,
|
||
|
MEMERR,
|
||
|
INVTYP,
|
||
|
INTCYOV,
|
||
|
DOMERR,
|
||
|
PCFBAGDROP,
|
||
|
SPCPRIOR,
|
||
|
AGEPRIOR,
|
||
|
PORTDROP,
|
||
|
LENDROP,
|
||
|
BAGDROP,
|
||
|
POLICEERR,
|
||
|
DRPNONA664ERR,
|
||
|
SPCERR,
|
||
|
AGEDRP,
|
||
|
/* HL1 */
|
||
|
N_N664ERR,
|
||
|
N_VLANERR,
|
||
|
N_UNRELEASED,
|
||
|
N_SIZEERR,
|
||
|
N_CRCERR,
|
||
|
N_VLNOTFOUND,
|
||
|
N_CTPOLERR,
|
||
|
N_POLERR,
|
||
|
N_RXFRM,
|
||
|
N_RXBYTE,
|
||
|
N_TXFRM,
|
||
|
N_TXBYTE,
|
||
|
/* HL2 */
|
||
|
N_QFULL,
|
||
|
N_PART_DROP,
|
||
|
N_EGR_DISABLED,
|
||
|
N_NOT_REACH,
|
||
|
__MAX_SJA1105ET_PORT_COUNTER,
|
||
|
/* P/Q/R/S only */
|
||
|
/* ETHER */
|
||
|
N_DROPS_NOLEARN = __MAX_SJA1105ET_PORT_COUNTER,
|
||
|
N_DROPS_NOROUTE,
|
||
|
N_DROPS_ILL_DTAG,
|
||
|
N_DROPS_DTAG,
|
||
|
N_DROPS_SOTAG,
|
||
|
N_DROPS_SITAG,
|
||
|
N_DROPS_UTAG,
|
||
|
N_TX_BYTES_1024_2047,
|
||
|
N_TX_BYTES_512_1023,
|
||
|
N_TX_BYTES_256_511,
|
||
|
N_TX_BYTES_128_255,
|
||
|
N_TX_BYTES_65_127,
|
||
|
N_TX_BYTES_64,
|
||
|
N_TX_MCAST,
|
||
|
N_TX_BCAST,
|
||
|
N_RX_BYTES_1024_2047,
|
||
|
N_RX_BYTES_512_1023,
|
||
|
N_RX_BYTES_256_511,
|
||
|
N_RX_BYTES_128_255,
|
||
|
N_RX_BYTES_65_127,
|
||
|
N_RX_BYTES_64,
|
||
|
N_RX_MCAST,
|
||
|
N_RX_BCAST,
|
||
|
__MAX_SJA1105PQRS_PORT_COUNTER,
|
||
|
};
|
||
|
|
||
|
struct sja1105_port_counter {
|
||
|
enum sja1105_stats_area area;
|
||
|
const char name[ETH_GSTRING_LEN];
|
||
|
int offset;
|
||
|
int start;
|
||
|
int end;
|
||
|
bool is_64bit;
|
||
|
};
|
||
|
|
||
|
static const struct sja1105_port_counter sja1105_port_counters[] = {
|
||
|
/* MAC-Level Diagnostic Counters */
|
||
|
[N_RUNT] = {
|
||
|
.area = MAC,
|
||
|
.name = "n_runt",
|
||
|
.offset = 0,
|
||
|
.start = 31,
|
||
|
.end = 24,
|
||
|
},
|
||
|
[N_SOFERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "n_soferr",
|
||
|
.offset = 0x0,
|
||
|
.start = 23,
|
||
|
.end = 16,
|
||
|
},
|
||
|
[N_ALIGNERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "n_alignerr",
|
||
|
.offset = 0x0,
|
||
|
.start = 15,
|
||
|
.end = 8,
|
||
|
},
|
||
|
[N_MIIERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "n_miierr",
|
||
|
.offset = 0x0,
|
||
|
.start = 7,
|
||
|
.end = 0,
|
||
|
},
|
||
|
/* MAC-Level Diagnostic Flags */
|
||
|
[TYPEERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "typeerr",
|
||
|
.offset = 0x1,
|
||
|
.start = 27,
|
||
|
.end = 27,
|
||
|
},
|
||
|
[SIZEERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "sizeerr",
|
||
|
.offset = 0x1,
|
||
|
.start = 26,
|
||
|
.end = 26,
|
||
|
},
|
||
|
[TCTIMEOUT] = {
|
||
|
.area = MAC,
|
||
|
.name = "tctimeout",
|
||
|
.offset = 0x1,
|
||
|
.start = 25,
|
||
|
.end = 25,
|
||
|
},
|
||
|
[PRIORERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "priorerr",
|
||
|
.offset = 0x1,
|
||
|
.start = 24,
|
||
|
.end = 24,
|
||
|
},
|
||
|
[NOMASTER] = {
|
||
|
.area = MAC,
|
||
|
.name = "nomaster",
|
||
|
.offset = 0x1,
|
||
|
.start = 23,
|
||
|
.end = 23,
|
||
|
},
|
||
|
[MEMOV] = {
|
||
|
.area = MAC,
|
||
|
.name = "memov",
|
||
|
.offset = 0x1,
|
||
|
.start = 22,
|
||
|
.end = 22,
|
||
|
},
|
||
|
[MEMERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "memerr",
|
||
|
.offset = 0x1,
|
||
|
.start = 21,
|
||
|
.end = 21,
|
||
|
},
|
||
|
[INVTYP] = {
|
||
|
.area = MAC,
|
||
|
.name = "invtyp",
|
||
|
.offset = 0x1,
|
||
|
.start = 19,
|
||
|
.end = 19,
|
||
|
},
|
||
|
[INTCYOV] = {
|
||
|
.area = MAC,
|
||
|
.name = "intcyov",
|
||
|
.offset = 0x1,
|
||
|
.start = 18,
|
||
|
.end = 18,
|
||
|
},
|
||
|
[DOMERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "domerr",
|
||
|
.offset = 0x1,
|
||
|
.start = 17,
|
||
|
.end = 17,
|
||
|
},
|
||
|
[PCFBAGDROP] = {
|
||
|
.area = MAC,
|
||
|
.name = "pcfbagdrop",
|
||
|
.offset = 0x1,
|
||
|
.start = 16,
|
||
|
.end = 16,
|
||
|
},
|
||
|
[SPCPRIOR] = {
|
||
|
.area = MAC,
|
||
|
.name = "spcprior",
|
||
|
.offset = 0x1,
|
||
|
.start = 15,
|
||
|
.end = 12,
|
||
|
},
|
||
|
[AGEPRIOR] = {
|
||
|
.area = MAC,
|
||
|
.name = "ageprior",
|
||
|
.offset = 0x1,
|
||
|
.start = 11,
|
||
|
.end = 8,
|
||
|
},
|
||
|
[PORTDROP] = {
|
||
|
.area = MAC,
|
||
|
.name = "portdrop",
|
||
|
.offset = 0x1,
|
||
|
.start = 6,
|
||
|
.end = 6,
|
||
|
},
|
||
|
[LENDROP] = {
|
||
|
.area = MAC,
|
||
|
.name = "lendrop",
|
||
|
.offset = 0x1,
|
||
|
.start = 5,
|
||
|
.end = 5,
|
||
|
},
|
||
|
[BAGDROP] = {
|
||
|
.area = MAC,
|
||
|
.name = "bagdrop",
|
||
|
.offset = 0x1,
|
||
|
.start = 4,
|
||
|
.end = 4,
|
||
|
},
|
||
|
[POLICEERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "policeerr",
|
||
|
.offset = 0x1,
|
||
|
.start = 3,
|
||
|
.end = 3,
|
||
|
},
|
||
|
[DRPNONA664ERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "drpnona664err",
|
||
|
.offset = 0x1,
|
||
|
.start = 2,
|
||
|
.end = 2,
|
||
|
},
|
||
|
[SPCERR] = {
|
||
|
.area = MAC,
|
||
|
.name = "spcerr",
|
||
|
.offset = 0x1,
|
||
|
.start = 1,
|
||
|
.end = 1,
|
||
|
},
|
||
|
[AGEDRP] = {
|
||
|
.area = MAC,
|
||
|
.name = "agedrp",
|
||
|
.offset = 0x1,
|
||
|
.start = 0,
|
||
|
.end = 0,
|
||
|
},
|
||
|
/* High-Level Diagnostic Counters */
|
||
|
[N_N664ERR] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_n664err",
|
||
|
.offset = 0xF,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_VLANERR] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_vlanerr",
|
||
|
.offset = 0xE,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_UNRELEASED] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_unreleased",
|
||
|
.offset = 0xD,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_SIZEERR] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_sizeerr",
|
||
|
.offset = 0xC,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_CRCERR] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_crcerr",
|
||
|
.offset = 0xB,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_VLNOTFOUND] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_vlnotfound",
|
||
|
.offset = 0xA,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_CTPOLERR] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_ctpolerr",
|
||
|
.offset = 0x9,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_POLERR] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_polerr",
|
||
|
.offset = 0x8,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RXFRM] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_rxfrm",
|
||
|
.offset = 0x6,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
.is_64bit = true,
|
||
|
},
|
||
|
[N_RXBYTE] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_rxbyte",
|
||
|
.offset = 0x4,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
.is_64bit = true,
|
||
|
},
|
||
|
[N_TXFRM] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_txfrm",
|
||
|
.offset = 0x2,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
.is_64bit = true,
|
||
|
},
|
||
|
[N_TXBYTE] = {
|
||
|
.area = HL1,
|
||
|
.name = "n_txbyte",
|
||
|
.offset = 0x0,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
.is_64bit = true,
|
||
|
},
|
||
|
[N_QFULL] = {
|
||
|
.area = HL2,
|
||
|
.name = "n_qfull",
|
||
|
.offset = 0x3,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_PART_DROP] = {
|
||
|
.area = HL2,
|
||
|
.name = "n_part_drop",
|
||
|
.offset = 0x2,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_EGR_DISABLED] = {
|
||
|
.area = HL2,
|
||
|
.name = "n_egr_disabled",
|
||
|
.offset = 0x1,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_NOT_REACH] = {
|
||
|
.area = HL2,
|
||
|
.name = "n_not_reach",
|
||
|
.offset = 0x0,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
/* Ether Stats */
|
||
|
[N_DROPS_NOLEARN] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_drops_nolearn",
|
||
|
.offset = 0x16,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_DROPS_NOROUTE] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_drops_noroute",
|
||
|
.offset = 0x15,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_DROPS_ILL_DTAG] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_drops_ill_dtag",
|
||
|
.offset = 0x14,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_DROPS_DTAG] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_drops_dtag",
|
||
|
.offset = 0x13,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_DROPS_SOTAG] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_drops_sotag",
|
||
|
.offset = 0x12,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_DROPS_SITAG] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_drops_sitag",
|
||
|
.offset = 0x11,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_DROPS_UTAG] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_drops_utag",
|
||
|
.offset = 0x10,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_BYTES_1024_2047] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_bytes_1024_2047",
|
||
|
.offset = 0x0F,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_BYTES_512_1023] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_bytes_512_1023",
|
||
|
.offset = 0x0E,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_BYTES_256_511] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_bytes_256_511",
|
||
|
.offset = 0x0D,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_BYTES_128_255] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_bytes_128_255",
|
||
|
.offset = 0x0C,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_BYTES_65_127] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_bytes_65_127",
|
||
|
.offset = 0x0B,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_BYTES_64] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_bytes_64",
|
||
|
.offset = 0x0A,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_MCAST] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_mcast",
|
||
|
.offset = 0x09,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_TX_BCAST] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_tx_bcast",
|
||
|
.offset = 0x08,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_BYTES_1024_2047] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_bytes_1024_2047",
|
||
|
.offset = 0x07,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_BYTES_512_1023] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_bytes_512_1023",
|
||
|
.offset = 0x06,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_BYTES_256_511] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_bytes_256_511",
|
||
|
.offset = 0x05,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_BYTES_128_255] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_bytes_128_255",
|
||
|
.offset = 0x04,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_BYTES_65_127] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_bytes_65_127",
|
||
|
.offset = 0x03,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_BYTES_64] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_bytes_64",
|
||
|
.offset = 0x02,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_MCAST] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_mcast",
|
||
|
.offset = 0x01,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
[N_RX_BCAST] = {
|
||
|
.area = ETHER,
|
||
|
.name = "n_rx_bcast",
|
||
|
.offset = 0x00,
|
||
|
.start = 31,
|
||
|
.end = 0,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
static int sja1105_port_counter_read(struct sja1105_private *priv, int port,
|
||
|
enum sja1105_counter_index idx, u64 *ctr)
|
||
|
{
|
||
|
const struct sja1105_port_counter *c = &sja1105_port_counters[idx];
|
||
|
size_t size = c->is_64bit ? 8 : 4;
|
||
|
u8 buf[8] = {0};
|
||
|
u64 regs;
|
||
|
int rc;
|
||
|
|
||
|
regs = priv->info->regs->stats[c->area][port];
|
||
|
|
||
|
rc = sja1105_xfer_buf(priv, SPI_READ, regs + c->offset, buf, size);
|
||
|
if (rc)
|
||
|
return rc;
|
||
|
|
||
|
sja1105_unpack(buf, ctr, c->start, c->end, size);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
|
||
|
{
|
||
|
struct sja1105_private *priv = ds->priv;
|
||
|
enum sja1105_counter_index max_ctr, i;
|
||
|
int rc, k = 0;
|
||
|
|
||
|
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
|
||
|
priv->info->device_id == SJA1105T_DEVICE_ID)
|
||
|
max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
|
||
|
else
|
||
|
max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
|
||
|
|
||
|
for (i = 0; i < max_ctr; i++) {
|
||
|
rc = sja1105_port_counter_read(priv, port, i, &data[k++]);
|
||
|
if (rc) {
|
||
|
dev_err(ds->dev,
|
||
|
"Failed to read port %d counters: %d\n",
|
||
|
port, rc);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void sja1105_get_strings(struct dsa_switch *ds, int port,
|
||
|
u32 stringset, u8 *data)
|
||
|
{
|
||
|
struct sja1105_private *priv = ds->priv;
|
||
|
enum sja1105_counter_index max_ctr, i;
|
||
|
char *p = data;
|
||
|
|
||
|
if (stringset != ETH_SS_STATS)
|
||
|
return;
|
||
|
|
||
|
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
|
||
|
priv->info->device_id == SJA1105T_DEVICE_ID)
|
||
|
max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
|
||
|
else
|
||
|
max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
|
||
|
|
||
|
for (i = 0; i < max_ctr; i++) {
|
||
|
strscpy(p, sja1105_port_counters[i].name, ETH_GSTRING_LEN);
|
||
|
p += ETH_GSTRING_LEN;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
||
|
{
|
||
|
struct sja1105_private *priv = ds->priv;
|
||
|
enum sja1105_counter_index max_ctr, i;
|
||
|
int sset_count = 0;
|
||
|
|
||
|
if (sset != ETH_SS_STATS)
|
||
|
return -EOPNOTSUPP;
|
||
|
|
||
|
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
|
||
|
priv->info->device_id == SJA1105T_DEVICE_ID)
|
||
|
max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
|
||
|
else
|
||
|
max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
|
||
|
|
||
|
for (i = 0; i < max_ctr; i++) {
|
||
|
if (!strlen(sja1105_port_counters[i].name))
|
||
|
continue;
|
||
|
|
||
|
sset_count++;
|
||
|
}
|
||
|
|
||
|
return sset_count;
|
||
|
}
|