linux/drivers/net/dsa/sja1105/sja1105_ethtool.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
   3 */
   4#include "sja1105.h"
   5
   6#define SJA1105_SIZE_MAC_AREA           (0x02 * 4)
   7#define SJA1105_SIZE_HL1_AREA           (0x10 * 4)
   8#define SJA1105_SIZE_HL2_AREA           (0x4 * 4)
   9#define SJA1105_SIZE_QLEVEL_AREA        (0x8 * 4) /* 0x4 to 0xB */
  10
  11struct sja1105_port_status_mac {
  12        u64 n_runt;
  13        u64 n_soferr;
  14        u64 n_alignerr;
  15        u64 n_miierr;
  16        u64 typeerr;
  17        u64 sizeerr;
  18        u64 tctimeout;
  19        u64 priorerr;
  20        u64 nomaster;
  21        u64 memov;
  22        u64 memerr;
  23        u64 invtyp;
  24        u64 intcyov;
  25        u64 domerr;
  26        u64 pcfbagdrop;
  27        u64 spcprior;
  28        u64 ageprior;
  29        u64 portdrop;
  30        u64 lendrop;
  31        u64 bagdrop;
  32        u64 policeerr;
  33        u64 drpnona664err;
  34        u64 spcerr;
  35        u64 agedrp;
  36};
  37
  38struct sja1105_port_status_hl1 {
  39        u64 n_n664err;
  40        u64 n_vlanerr;
  41        u64 n_unreleased;
  42        u64 n_sizeerr;
  43        u64 n_crcerr;
  44        u64 n_vlnotfound;
  45        u64 n_ctpolerr;
  46        u64 n_polerr;
  47        u64 n_rxfrmsh;
  48        u64 n_rxfrm;
  49        u64 n_rxbytesh;
  50        u64 n_rxbyte;
  51        u64 n_txfrmsh;
  52        u64 n_txfrm;
  53        u64 n_txbytesh;
  54        u64 n_txbyte;
  55};
  56
  57struct sja1105_port_status_hl2 {
  58        u64 n_qfull;
  59        u64 n_part_drop;
  60        u64 n_egr_disabled;
  61        u64 n_not_reach;
  62        u64 qlevel_hwm[8]; /* Only for P/Q/R/S */
  63        u64 qlevel[8];     /* Only for P/Q/R/S */
  64};
  65
  66struct sja1105_port_status {
  67        struct sja1105_port_status_mac mac;
  68        struct sja1105_port_status_hl1 hl1;
  69        struct sja1105_port_status_hl2 hl2;
  70};
  71
  72static void
  73sja1105_port_status_mac_unpack(void *buf,
  74                               struct sja1105_port_status_mac *status)
  75{
  76        /* Make pointer arithmetic work on 4 bytes */
  77        u32 *p = buf;
  78
  79        sja1105_unpack(p + 0x0, &status->n_runt,       31, 24, 4);
  80        sja1105_unpack(p + 0x0, &status->n_soferr,     23, 16, 4);
  81        sja1105_unpack(p + 0x0, &status->n_alignerr,   15,  8, 4);
  82        sja1105_unpack(p + 0x0, &status->n_miierr,      7,  0, 4);
  83        sja1105_unpack(p + 0x1, &status->typeerr,      27, 27, 4);
  84        sja1105_unpack(p + 0x1, &status->sizeerr,      26, 26, 4);
  85        sja1105_unpack(p + 0x1, &status->tctimeout,    25, 25, 4);
  86        sja1105_unpack(p + 0x1, &status->priorerr,     24, 24, 4);
  87        sja1105_unpack(p + 0x1, &status->nomaster,     23, 23, 4);
  88        sja1105_unpack(p + 0x1, &status->memov,        22, 22, 4);
  89        sja1105_unpack(p + 0x1, &status->memerr,       21, 21, 4);
  90        sja1105_unpack(p + 0x1, &status->invtyp,       19, 19, 4);
  91        sja1105_unpack(p + 0x1, &status->intcyov,      18, 18, 4);
  92        sja1105_unpack(p + 0x1, &status->domerr,       17, 17, 4);
  93        sja1105_unpack(p + 0x1, &status->pcfbagdrop,   16, 16, 4);
  94        sja1105_unpack(p + 0x1, &status->spcprior,     15, 12, 4);
  95        sja1105_unpack(p + 0x1, &status->ageprior,     11,  8, 4);
  96        sja1105_unpack(p + 0x1, &status->portdrop,      6,  6, 4);
  97        sja1105_unpack(p + 0x1, &status->lendrop,       5,  5, 4);
  98        sja1105_unpack(p + 0x1, &status->bagdrop,       4,  4, 4);
  99        sja1105_unpack(p + 0x1, &status->policeerr,     3,  3, 4);
 100        sja1105_unpack(p + 0x1, &status->drpnona664err, 2,  2, 4);
 101        sja1105_unpack(p + 0x1, &status->spcerr,        1,  1, 4);
 102        sja1105_unpack(p + 0x1, &status->agedrp,        0,  0, 4);
 103}
 104
 105static void
 106sja1105_port_status_hl1_unpack(void *buf,
 107                               struct sja1105_port_status_hl1 *status)
 108{
 109        /* Make pointer arithmetic work on 4 bytes */
 110        u32 *p = buf;
 111
 112        sja1105_unpack(p + 0xF, &status->n_n664err,    31,  0, 4);
 113        sja1105_unpack(p + 0xE, &status->n_vlanerr,    31,  0, 4);
 114        sja1105_unpack(p + 0xD, &status->n_unreleased, 31,  0, 4);
 115        sja1105_unpack(p + 0xC, &status->n_sizeerr,    31,  0, 4);
 116        sja1105_unpack(p + 0xB, &status->n_crcerr,     31,  0, 4);
 117        sja1105_unpack(p + 0xA, &status->n_vlnotfound, 31,  0, 4);
 118        sja1105_unpack(p + 0x9, &status->n_ctpolerr,   31,  0, 4);
 119        sja1105_unpack(p + 0x8, &status->n_polerr,     31,  0, 4);
 120        sja1105_unpack(p + 0x7, &status->n_rxfrmsh,    31,  0, 4);
 121        sja1105_unpack(p + 0x6, &status->n_rxfrm,      31,  0, 4);
 122        sja1105_unpack(p + 0x5, &status->n_rxbytesh,   31,  0, 4);
 123        sja1105_unpack(p + 0x4, &status->n_rxbyte,     31,  0, 4);
 124        sja1105_unpack(p + 0x3, &status->n_txfrmsh,    31,  0, 4);
 125        sja1105_unpack(p + 0x2, &status->n_txfrm,      31,  0, 4);
 126        sja1105_unpack(p + 0x1, &status->n_txbytesh,   31,  0, 4);
 127        sja1105_unpack(p + 0x0, &status->n_txbyte,     31,  0, 4);
 128        status->n_rxfrm  += status->n_rxfrmsh  << 32;
 129        status->n_rxbyte += status->n_rxbytesh << 32;
 130        status->n_txfrm  += status->n_txfrmsh  << 32;
 131        status->n_txbyte += status->n_txbytesh << 32;
 132}
 133
 134static void
 135sja1105_port_status_hl2_unpack(void *buf,
 136                               struct sja1105_port_status_hl2 *status)
 137{
 138        /* Make pointer arithmetic work on 4 bytes */
 139        u32 *p = buf;
 140
 141        sja1105_unpack(p + 0x3, &status->n_qfull,        31,  0, 4);
 142        sja1105_unpack(p + 0x2, &status->n_part_drop,    31,  0, 4);
 143        sja1105_unpack(p + 0x1, &status->n_egr_disabled, 31,  0, 4);
 144        sja1105_unpack(p + 0x0, &status->n_not_reach,    31,  0, 4);
 145}
 146
 147static void
 148sja1105pqrs_port_status_qlevel_unpack(void *buf,
 149                                      struct sja1105_port_status_hl2 *status)
 150{
 151        /* Make pointer arithmetic work on 4 bytes */
 152        u32 *p = buf;
 153        int i;
 154
 155        for (i = 0; i < 8; i++) {
 156                sja1105_unpack(p + i, &status->qlevel_hwm[i], 24, 16, 4);
 157                sja1105_unpack(p + i, &status->qlevel[i],      8,  0, 4);
 158        }
 159}
 160
 161static int sja1105_port_status_get_mac(struct sja1105_private *priv,
 162                                       struct sja1105_port_status_mac *status,
 163                                       int port)
 164{
 165        const struct sja1105_regs *regs = priv->info->regs;
 166        u8 packed_buf[SJA1105_SIZE_MAC_AREA] = {0};
 167        int rc;
 168
 169        /* MAC area */
 170        rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac[port],
 171                                         packed_buf, SJA1105_SIZE_MAC_AREA);
 172        if (rc < 0)
 173                return rc;
 174
 175        sja1105_port_status_mac_unpack(packed_buf, status);
 176
 177        return 0;
 178}
 179
 180static int sja1105_port_status_get_hl1(struct sja1105_private *priv,
 181                                       struct sja1105_port_status_hl1 *status,
 182                                       int port)
 183{
 184        const struct sja1105_regs *regs = priv->info->regs;
 185        u8 packed_buf[SJA1105_SIZE_HL1_AREA] = {0};
 186        int rc;
 187
 188        rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl1[port],
 189                                         packed_buf, SJA1105_SIZE_HL1_AREA);
 190        if (rc < 0)
 191                return rc;
 192
 193        sja1105_port_status_hl1_unpack(packed_buf, status);
 194
 195        return 0;
 196}
 197
 198static int sja1105_port_status_get_hl2(struct sja1105_private *priv,
 199                                       struct sja1105_port_status_hl2 *status,
 200                                       int port)
 201{
 202        const struct sja1105_regs *regs = priv->info->regs;
 203        u8 packed_buf[SJA1105_SIZE_QLEVEL_AREA] = {0};
 204        int rc;
 205
 206        rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl2[port],
 207                                         packed_buf, SJA1105_SIZE_HL2_AREA);
 208        if (rc < 0)
 209                return rc;
 210
 211        sja1105_port_status_hl2_unpack(packed_buf, status);
 212
 213        /* Code below is strictly P/Q/R/S specific. */
 214        if (priv->info->device_id == SJA1105E_DEVICE_ID ||
 215            priv->info->device_id == SJA1105T_DEVICE_ID)
 216                return 0;
 217
 218        rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->qlevel[port],
 219                                         packed_buf, SJA1105_SIZE_QLEVEL_AREA);
 220        if (rc < 0)
 221                return rc;
 222
 223        sja1105pqrs_port_status_qlevel_unpack(packed_buf, status);
 224
 225        return 0;
 226}
 227
 228static int sja1105_port_status_get(struct sja1105_private *priv,
 229                                   struct sja1105_port_status *status,
 230                                   int port)
 231{
 232        int rc;
 233
 234        rc = sja1105_port_status_get_mac(priv, &status->mac, port);
 235        if (rc < 0)
 236                return rc;
 237        rc = sja1105_port_status_get_hl1(priv, &status->hl1, port);
 238        if (rc < 0)
 239                return rc;
 240        rc = sja1105_port_status_get_hl2(priv, &status->hl2, port);
 241        if (rc < 0)
 242                return rc;
 243
 244        return 0;
 245}
 246
 247static char sja1105_port_stats[][ETH_GSTRING_LEN] = {
 248        /* MAC-Level Diagnostic Counters */
 249        "n_runt",
 250        "n_soferr",
 251        "n_alignerr",
 252        "n_miierr",
 253        /* MAC-Level Diagnostic Flags */
 254        "typeerr",
 255        "sizeerr",
 256        "tctimeout",
 257        "priorerr",
 258        "nomaster",
 259        "memov",
 260        "memerr",
 261        "invtyp",
 262        "intcyov",
 263        "domerr",
 264        "pcfbagdrop",
 265        "spcprior",
 266        "ageprior",
 267        "portdrop",
 268        "lendrop",
 269        "bagdrop",
 270        "policeerr",
 271        "drpnona664err",
 272        "spcerr",
 273        "agedrp",
 274        /* High-Level Diagnostic Counters */
 275        "n_n664err",
 276        "n_vlanerr",
 277        "n_unreleased",
 278        "n_sizeerr",
 279        "n_crcerr",
 280        "n_vlnotfound",
 281        "n_ctpolerr",
 282        "n_polerr",
 283        "n_rxfrm",
 284        "n_rxbyte",
 285        "n_txfrm",
 286        "n_txbyte",
 287        "n_qfull",
 288        "n_part_drop",
 289        "n_egr_disabled",
 290        "n_not_reach",
 291};
 292
 293static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = {
 294        /* Queue Levels */
 295        "qlevel_hwm_0",
 296        "qlevel_hwm_1",
 297        "qlevel_hwm_2",
 298        "qlevel_hwm_3",
 299        "qlevel_hwm_4",
 300        "qlevel_hwm_5",
 301        "qlevel_hwm_6",
 302        "qlevel_hwm_7",
 303        "qlevel_0",
 304        "qlevel_1",
 305        "qlevel_2",
 306        "qlevel_3",
 307        "qlevel_4",
 308        "qlevel_5",
 309        "qlevel_6",
 310        "qlevel_7",
 311};
 312
 313void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
 314{
 315        struct sja1105_private *priv = ds->priv;
 316        struct sja1105_port_status status;
 317        int rc, i, k = 0;
 318
 319        memset(&status, 0, sizeof(status));
 320
 321        rc = sja1105_port_status_get(priv, &status, port);
 322        if (rc < 0) {
 323                dev_err(ds->dev, "Failed to read port %d counters: %d\n",
 324                        port, rc);
 325                return;
 326        }
 327        memset(data, 0, ARRAY_SIZE(sja1105_port_stats) * sizeof(u64));
 328        data[k++] = status.mac.n_runt;
 329        data[k++] = status.mac.n_soferr;
 330        data[k++] = status.mac.n_alignerr;
 331        data[k++] = status.mac.n_miierr;
 332        data[k++] = status.mac.typeerr;
 333        data[k++] = status.mac.sizeerr;
 334        data[k++] = status.mac.tctimeout;
 335        data[k++] = status.mac.priorerr;
 336        data[k++] = status.mac.nomaster;
 337        data[k++] = status.mac.memov;
 338        data[k++] = status.mac.memerr;
 339        data[k++] = status.mac.invtyp;
 340        data[k++] = status.mac.intcyov;
 341        data[k++] = status.mac.domerr;
 342        data[k++] = status.mac.pcfbagdrop;
 343        data[k++] = status.mac.spcprior;
 344        data[k++] = status.mac.ageprior;
 345        data[k++] = status.mac.portdrop;
 346        data[k++] = status.mac.lendrop;
 347        data[k++] = status.mac.bagdrop;
 348        data[k++] = status.mac.policeerr;
 349        data[k++] = status.mac.drpnona664err;
 350        data[k++] = status.mac.spcerr;
 351        data[k++] = status.mac.agedrp;
 352        data[k++] = status.hl1.n_n664err;
 353        data[k++] = status.hl1.n_vlanerr;
 354        data[k++] = status.hl1.n_unreleased;
 355        data[k++] = status.hl1.n_sizeerr;
 356        data[k++] = status.hl1.n_crcerr;
 357        data[k++] = status.hl1.n_vlnotfound;
 358        data[k++] = status.hl1.n_ctpolerr;
 359        data[k++] = status.hl1.n_polerr;
 360        data[k++] = status.hl1.n_rxfrm;
 361        data[k++] = status.hl1.n_rxbyte;
 362        data[k++] = status.hl1.n_txfrm;
 363        data[k++] = status.hl1.n_txbyte;
 364        data[k++] = status.hl2.n_qfull;
 365        data[k++] = status.hl2.n_part_drop;
 366        data[k++] = status.hl2.n_egr_disabled;
 367        data[k++] = status.hl2.n_not_reach;
 368
 369        if (priv->info->device_id == SJA1105E_DEVICE_ID ||
 370            priv->info->device_id == SJA1105T_DEVICE_ID)
 371                return;
 372
 373        memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) *
 374                        sizeof(u64));
 375        for (i = 0; i < 8; i++) {
 376                data[k++] = status.hl2.qlevel_hwm[i];
 377                data[k++] = status.hl2.qlevel[i];
 378        }
 379}
 380
 381void sja1105_get_strings(struct dsa_switch *ds, int port,
 382                         u32 stringset, u8 *data)
 383{
 384        struct sja1105_private *priv = ds->priv;
 385        u8 *p = data;
 386        int i;
 387
 388        switch (stringset) {
 389        case ETH_SS_STATS:
 390                for (i = 0; i < ARRAY_SIZE(sja1105_port_stats); i++) {
 391                        strlcpy(p, sja1105_port_stats[i], ETH_GSTRING_LEN);
 392                        p += ETH_GSTRING_LEN;
 393                }
 394                if (priv->info->device_id == SJA1105E_DEVICE_ID ||
 395                    priv->info->device_id == SJA1105T_DEVICE_ID)
 396                        return;
 397                for (i = 0; i < ARRAY_SIZE(sja1105pqrs_extra_port_stats); i++) {
 398                        strlcpy(p, sja1105pqrs_extra_port_stats[i],
 399                                ETH_GSTRING_LEN);
 400                        p += ETH_GSTRING_LEN;
 401                }
 402                break;
 403        }
 404}
 405
 406int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset)
 407{
 408        int count = ARRAY_SIZE(sja1105_port_stats);
 409        struct sja1105_private *priv = ds->priv;
 410
 411        if (sset != ETH_SS_STATS)
 412                return -EOPNOTSUPP;
 413
 414        if (priv->info->device_id == SJA1105PR_DEVICE_ID ||
 415            priv->info->device_id == SJA1105QS_DEVICE_ID)
 416                count += ARRAY_SIZE(sja1105pqrs_extra_port_stats);
 417
 418        return count;
 419}
 420