linux/drivers/net/ethernet/ti/am65-cpsw-ethtool.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver ethtool ops
   3 *
   4 * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
   5 *
   6 */
   7
   8#include <linux/net_tstamp.h>
   9#include <linux/phy.h>
  10#include <linux/platform_device.h>
  11#include <linux/pm_runtime.h>
  12
  13#include "am65-cpsw-nuss.h"
  14#include "cpsw_ale.h"
  15#include "am65-cpts.h"
  16
  17#define AM65_CPSW_REGDUMP_VER 0x1
  18
  19enum {
  20        AM65_CPSW_REGDUMP_MOD_NUSS = 1,
  21        AM65_CPSW_REGDUMP_MOD_RGMII_STATUS = 2,
  22        AM65_CPSW_REGDUMP_MOD_MDIO = 3,
  23        AM65_CPSW_REGDUMP_MOD_CPSW = 4,
  24        AM65_CPSW_REGDUMP_MOD_CPSW_P0 = 5,
  25        AM65_CPSW_REGDUMP_MOD_CPSW_P1 = 6,
  26        AM65_CPSW_REGDUMP_MOD_CPSW_CPTS = 7,
  27        AM65_CPSW_REGDUMP_MOD_CPSW_ALE = 8,
  28        AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9,
  29        AM65_CPSW_REGDUMP_MOD_LAST,
  30};
  31
  32/**
  33 * struct am65_cpsw_regdump_hdr - regdump record header
  34 *
  35 * @module_id: CPSW module ID
  36 * @len: CPSW module registers space length in u32
  37 */
  38
  39struct am65_cpsw_regdump_hdr {
  40        u32 module_id;
  41        u32 len;
  42};
  43
  44/**
  45 * struct am65_cpsw_regdump_item - regdump module description
  46 *
  47 * @hdr: CPSW module header
  48 * @start_ofs: CPSW module registers start addr
  49 * @end_ofs: CPSW module registers end addr
  50 *
  51 * Registers dump provided in the format:
  52 *  u32 : module ID
  53 *  u32 : dump length
  54 *  u32[..len]: registers values
  55 */
  56struct am65_cpsw_regdump_item {
  57        struct am65_cpsw_regdump_hdr hdr;
  58        u32 start_ofs;
  59        u32 end_ofs;
  60};
  61
  62#define AM65_CPSW_REGDUMP_REC(mod, start, end) { \
  63        .hdr.module_id = (mod), \
  64        .hdr.len = (((u32 *)(end)) - ((u32 *)(start)) + 1) * sizeof(u32) * 2 + \
  65                   sizeof(struct am65_cpsw_regdump_hdr), \
  66        .start_ofs = (start), \
  67        .end_ofs = end, \
  68}
  69
  70static const struct am65_cpsw_regdump_item am65_cpsw_regdump[] = {
  71        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_NUSS, 0x0, 0x1c),
  72        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_RGMII_STATUS, 0x30, 0x4c),
  73        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_MDIO, 0xf00, 0xffc),
  74        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW, 0x20000, 0x2011c),
  75        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P0, 0x21000, 0x21320),
  76        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P1, 0x22000, 0x223a4),
  77        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_CPTS,
  78                              0x3d000, 0x3d048),
  79        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE, 0x3e000, 0x3e13c),
  80        AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL, 0, 0),
  81};
  82
  83struct am65_cpsw_stats_regs {
  84        u32     rx_good_frames;
  85        u32     rx_broadcast_frames;
  86        u32     rx_multicast_frames;
  87        u32     rx_pause_frames;                /* slave */
  88        u32     rx_crc_errors;
  89        u32     rx_align_code_errors;           /* slave */
  90        u32     rx_oversized_frames;
  91        u32     rx_jabber_frames;               /* slave */
  92        u32     rx_undersized_frames;
  93        u32     rx_fragments;                   /* slave */
  94        u32     ale_drop;
  95        u32     ale_overrun_drop;
  96        u32     rx_octets;
  97        u32     tx_good_frames;
  98        u32     tx_broadcast_frames;
  99        u32     tx_multicast_frames;
 100        u32     tx_pause_frames;                /* slave */
 101        u32     tx_deferred_frames;             /* slave */
 102        u32     tx_collision_frames;            /* slave */
 103        u32     tx_single_coll_frames;          /* slave */
 104        u32     tx_mult_coll_frames;            /* slave */
 105        u32     tx_excessive_collisions;        /* slave */
 106        u32     tx_late_collisions;             /* slave */
 107        u32     rx_ipg_error;                   /* slave 10G only */
 108        u32     tx_carrier_sense_errors;        /* slave */
 109        u32     tx_octets;
 110        u32     tx_64B_frames;
 111        u32     tx_65_to_127B_frames;
 112        u32     tx_128_to_255B_frames;
 113        u32     tx_256_to_511B_frames;
 114        u32     tx_512_to_1023B_frames;
 115        u32     tx_1024B_frames;
 116        u32     net_octets;
 117        u32     rx_bottom_fifo_drop;
 118        u32     rx_port_mask_drop;
 119        u32     rx_top_fifo_drop;
 120        u32     ale_rate_limit_drop;
 121        u32     ale_vid_ingress_drop;
 122        u32     ale_da_eq_sa_drop;
 123        u32     ale_block_drop;                 /* K3 */
 124        u32     ale_secure_drop;                /* K3 */
 125        u32     ale_auth_drop;                  /* K3 */
 126        u32     ale_unknown_ucast;
 127        u32     ale_unknown_ucast_bytes;
 128        u32     ale_unknown_mcast;
 129        u32     ale_unknown_mcast_bytes;
 130        u32     ale_unknown_bcast;
 131        u32     ale_unknown_bcast_bytes;
 132        u32     ale_pol_match;
 133        u32     ale_pol_match_red;
 134        u32     ale_pol_match_yellow;
 135        u32     ale_mcast_sa_drop;              /* K3 */
 136        u32     ale_dual_vlan_drop;             /* K3 */
 137        u32     ale_len_err_drop;               /* K3 */
 138        u32     ale_ip_next_hdr_drop;           /* K3 */
 139        u32     ale_ipv4_frag_drop;             /* K3 */
 140        u32     __rsvd_1[24];
 141        u32     iet_rx_assembly_err;            /* K3 slave */
 142        u32     iet_rx_assembly_ok;             /* K3 slave */
 143        u32     iet_rx_smd_err;                 /* K3 slave */
 144        u32     iet_rx_frag;                    /* K3 slave */
 145        u32     iet_tx_hold;                    /* K3 slave */
 146        u32     iet_tx_frag;                    /* K3 slave */
 147        u32     __rsvd_2[9];
 148        u32     tx_mem_protect_err;
 149        /* following NU only */
 150        u32     tx_pri0;
 151        u32     tx_pri1;
 152        u32     tx_pri2;
 153        u32     tx_pri3;
 154        u32     tx_pri4;
 155        u32     tx_pri5;
 156        u32     tx_pri6;
 157        u32     tx_pri7;
 158        u32     tx_pri0_bcnt;
 159        u32     tx_pri1_bcnt;
 160        u32     tx_pri2_bcnt;
 161        u32     tx_pri3_bcnt;
 162        u32     tx_pri4_bcnt;
 163        u32     tx_pri5_bcnt;
 164        u32     tx_pri6_bcnt;
 165        u32     tx_pri7_bcnt;
 166        u32     tx_pri0_drop;
 167        u32     tx_pri1_drop;
 168        u32     tx_pri2_drop;
 169        u32     tx_pri3_drop;
 170        u32     tx_pri4_drop;
 171        u32     tx_pri5_drop;
 172        u32     tx_pri6_drop;
 173        u32     tx_pri7_drop;
 174        u32     tx_pri0_drop_bcnt;
 175        u32     tx_pri1_drop_bcnt;
 176        u32     tx_pri2_drop_bcnt;
 177        u32     tx_pri3_drop_bcnt;
 178        u32     tx_pri4_drop_bcnt;
 179        u32     tx_pri5_drop_bcnt;
 180        u32     tx_pri6_drop_bcnt;
 181        u32     tx_pri7_drop_bcnt;
 182};
 183
 184struct am65_cpsw_ethtool_stat {
 185        char desc[ETH_GSTRING_LEN];
 186        int offset;
 187};
 188
 189#define AM65_CPSW_STATS(prefix, field)                  \
 190{                                                       \
 191        #prefix#field,                                  \
 192        offsetof(struct am65_cpsw_stats_regs, field)    \
 193}
 194
 195static const struct am65_cpsw_ethtool_stat am65_host_stats[] = {
 196        AM65_CPSW_STATS(p0_, rx_good_frames),
 197        AM65_CPSW_STATS(p0_, rx_broadcast_frames),
 198        AM65_CPSW_STATS(p0_, rx_multicast_frames),
 199        AM65_CPSW_STATS(p0_, rx_crc_errors),
 200        AM65_CPSW_STATS(p0_, rx_oversized_frames),
 201        AM65_CPSW_STATS(p0_, rx_undersized_frames),
 202        AM65_CPSW_STATS(p0_, ale_drop),
 203        AM65_CPSW_STATS(p0_, ale_overrun_drop),
 204        AM65_CPSW_STATS(p0_, rx_octets),
 205        AM65_CPSW_STATS(p0_, tx_good_frames),
 206        AM65_CPSW_STATS(p0_, tx_broadcast_frames),
 207        AM65_CPSW_STATS(p0_, tx_multicast_frames),
 208        AM65_CPSW_STATS(p0_, tx_octets),
 209        AM65_CPSW_STATS(p0_, tx_64B_frames),
 210        AM65_CPSW_STATS(p0_, tx_65_to_127B_frames),
 211        AM65_CPSW_STATS(p0_, tx_128_to_255B_frames),
 212        AM65_CPSW_STATS(p0_, tx_256_to_511B_frames),
 213        AM65_CPSW_STATS(p0_, tx_512_to_1023B_frames),
 214        AM65_CPSW_STATS(p0_, tx_1024B_frames),
 215        AM65_CPSW_STATS(p0_, net_octets),
 216        AM65_CPSW_STATS(p0_, rx_bottom_fifo_drop),
 217        AM65_CPSW_STATS(p0_, rx_port_mask_drop),
 218        AM65_CPSW_STATS(p0_, rx_top_fifo_drop),
 219        AM65_CPSW_STATS(p0_, ale_rate_limit_drop),
 220        AM65_CPSW_STATS(p0_, ale_vid_ingress_drop),
 221        AM65_CPSW_STATS(p0_, ale_da_eq_sa_drop),
 222        AM65_CPSW_STATS(p0_, ale_block_drop),
 223        AM65_CPSW_STATS(p0_, ale_secure_drop),
 224        AM65_CPSW_STATS(p0_, ale_auth_drop),
 225        AM65_CPSW_STATS(p0_, ale_unknown_ucast),
 226        AM65_CPSW_STATS(p0_, ale_unknown_ucast_bytes),
 227        AM65_CPSW_STATS(p0_, ale_unknown_mcast),
 228        AM65_CPSW_STATS(p0_, ale_unknown_mcast_bytes),
 229        AM65_CPSW_STATS(p0_, ale_unknown_bcast),
 230        AM65_CPSW_STATS(p0_, ale_unknown_bcast_bytes),
 231        AM65_CPSW_STATS(p0_, ale_pol_match),
 232        AM65_CPSW_STATS(p0_, ale_pol_match_red),
 233        AM65_CPSW_STATS(p0_, ale_pol_match_yellow),
 234        AM65_CPSW_STATS(p0_, ale_mcast_sa_drop),
 235        AM65_CPSW_STATS(p0_, ale_dual_vlan_drop),
 236        AM65_CPSW_STATS(p0_, ale_len_err_drop),
 237        AM65_CPSW_STATS(p0_, ale_ip_next_hdr_drop),
 238        AM65_CPSW_STATS(p0_, ale_ipv4_frag_drop),
 239        AM65_CPSW_STATS(p0_, tx_mem_protect_err),
 240        AM65_CPSW_STATS(p0_, tx_pri0),
 241        AM65_CPSW_STATS(p0_, tx_pri1),
 242        AM65_CPSW_STATS(p0_, tx_pri2),
 243        AM65_CPSW_STATS(p0_, tx_pri3),
 244        AM65_CPSW_STATS(p0_, tx_pri4),
 245        AM65_CPSW_STATS(p0_, tx_pri5),
 246        AM65_CPSW_STATS(p0_, tx_pri6),
 247        AM65_CPSW_STATS(p0_, tx_pri7),
 248        AM65_CPSW_STATS(p0_, tx_pri0_bcnt),
 249        AM65_CPSW_STATS(p0_, tx_pri1_bcnt),
 250        AM65_CPSW_STATS(p0_, tx_pri2_bcnt),
 251        AM65_CPSW_STATS(p0_, tx_pri3_bcnt),
 252        AM65_CPSW_STATS(p0_, tx_pri4_bcnt),
 253        AM65_CPSW_STATS(p0_, tx_pri5_bcnt),
 254        AM65_CPSW_STATS(p0_, tx_pri6_bcnt),
 255        AM65_CPSW_STATS(p0_, tx_pri7_bcnt),
 256        AM65_CPSW_STATS(p0_, tx_pri0_drop),
 257        AM65_CPSW_STATS(p0_, tx_pri1_drop),
 258        AM65_CPSW_STATS(p0_, tx_pri2_drop),
 259        AM65_CPSW_STATS(p0_, tx_pri3_drop),
 260        AM65_CPSW_STATS(p0_, tx_pri4_drop),
 261        AM65_CPSW_STATS(p0_, tx_pri5_drop),
 262        AM65_CPSW_STATS(p0_, tx_pri6_drop),
 263        AM65_CPSW_STATS(p0_, tx_pri7_drop),
 264        AM65_CPSW_STATS(p0_, tx_pri0_drop_bcnt),
 265        AM65_CPSW_STATS(p0_, tx_pri1_drop_bcnt),
 266        AM65_CPSW_STATS(p0_, tx_pri2_drop_bcnt),
 267        AM65_CPSW_STATS(p0_, tx_pri3_drop_bcnt),
 268        AM65_CPSW_STATS(p0_, tx_pri4_drop_bcnt),
 269        AM65_CPSW_STATS(p0_, tx_pri5_drop_bcnt),
 270        AM65_CPSW_STATS(p0_, tx_pri6_drop_bcnt),
 271        AM65_CPSW_STATS(p0_, tx_pri7_drop_bcnt),
 272};
 273
 274static const struct am65_cpsw_ethtool_stat am65_slave_stats[] = {
 275        AM65_CPSW_STATS(, rx_good_frames),
 276        AM65_CPSW_STATS(, rx_broadcast_frames),
 277        AM65_CPSW_STATS(, rx_multicast_frames),
 278        AM65_CPSW_STATS(, rx_pause_frames),
 279        AM65_CPSW_STATS(, rx_crc_errors),
 280        AM65_CPSW_STATS(, rx_align_code_errors),
 281        AM65_CPSW_STATS(, rx_oversized_frames),
 282        AM65_CPSW_STATS(, rx_jabber_frames),
 283        AM65_CPSW_STATS(, rx_undersized_frames),
 284        AM65_CPSW_STATS(, rx_fragments),
 285        AM65_CPSW_STATS(, ale_drop),
 286        AM65_CPSW_STATS(, ale_overrun_drop),
 287        AM65_CPSW_STATS(, rx_octets),
 288        AM65_CPSW_STATS(, tx_good_frames),
 289        AM65_CPSW_STATS(, tx_broadcast_frames),
 290        AM65_CPSW_STATS(, tx_multicast_frames),
 291        AM65_CPSW_STATS(, tx_pause_frames),
 292        AM65_CPSW_STATS(, tx_deferred_frames),
 293        AM65_CPSW_STATS(, tx_collision_frames),
 294        AM65_CPSW_STATS(, tx_single_coll_frames),
 295        AM65_CPSW_STATS(, tx_mult_coll_frames),
 296        AM65_CPSW_STATS(, tx_excessive_collisions),
 297        AM65_CPSW_STATS(, tx_late_collisions),
 298        AM65_CPSW_STATS(, rx_ipg_error),
 299        AM65_CPSW_STATS(, tx_carrier_sense_errors),
 300        AM65_CPSW_STATS(, tx_octets),
 301        AM65_CPSW_STATS(, tx_64B_frames),
 302        AM65_CPSW_STATS(, tx_65_to_127B_frames),
 303        AM65_CPSW_STATS(, tx_128_to_255B_frames),
 304        AM65_CPSW_STATS(, tx_256_to_511B_frames),
 305        AM65_CPSW_STATS(, tx_512_to_1023B_frames),
 306        AM65_CPSW_STATS(, tx_1024B_frames),
 307        AM65_CPSW_STATS(, net_octets),
 308        AM65_CPSW_STATS(, rx_bottom_fifo_drop),
 309        AM65_CPSW_STATS(, rx_port_mask_drop),
 310        AM65_CPSW_STATS(, rx_top_fifo_drop),
 311        AM65_CPSW_STATS(, ale_rate_limit_drop),
 312        AM65_CPSW_STATS(, ale_vid_ingress_drop),
 313        AM65_CPSW_STATS(, ale_da_eq_sa_drop),
 314        AM65_CPSW_STATS(, ale_block_drop),
 315        AM65_CPSW_STATS(, ale_secure_drop),
 316        AM65_CPSW_STATS(, ale_auth_drop),
 317        AM65_CPSW_STATS(, ale_unknown_ucast),
 318        AM65_CPSW_STATS(, ale_unknown_ucast_bytes),
 319        AM65_CPSW_STATS(, ale_unknown_mcast),
 320        AM65_CPSW_STATS(, ale_unknown_mcast_bytes),
 321        AM65_CPSW_STATS(, ale_unknown_bcast),
 322        AM65_CPSW_STATS(, ale_unknown_bcast_bytes),
 323        AM65_CPSW_STATS(, ale_pol_match),
 324        AM65_CPSW_STATS(, ale_pol_match_red),
 325        AM65_CPSW_STATS(, ale_pol_match_yellow),
 326        AM65_CPSW_STATS(, ale_mcast_sa_drop),
 327        AM65_CPSW_STATS(, ale_dual_vlan_drop),
 328        AM65_CPSW_STATS(, ale_len_err_drop),
 329        AM65_CPSW_STATS(, ale_ip_next_hdr_drop),
 330        AM65_CPSW_STATS(, ale_ipv4_frag_drop),
 331        AM65_CPSW_STATS(, iet_rx_assembly_err),
 332        AM65_CPSW_STATS(, iet_rx_assembly_ok),
 333        AM65_CPSW_STATS(, iet_rx_smd_err),
 334        AM65_CPSW_STATS(, iet_rx_frag),
 335        AM65_CPSW_STATS(, iet_tx_hold),
 336        AM65_CPSW_STATS(, iet_tx_frag),
 337        AM65_CPSW_STATS(, tx_mem_protect_err),
 338        AM65_CPSW_STATS(, tx_pri0),
 339        AM65_CPSW_STATS(, tx_pri1),
 340        AM65_CPSW_STATS(, tx_pri2),
 341        AM65_CPSW_STATS(, tx_pri3),
 342        AM65_CPSW_STATS(, tx_pri4),
 343        AM65_CPSW_STATS(, tx_pri5),
 344        AM65_CPSW_STATS(, tx_pri6),
 345        AM65_CPSW_STATS(, tx_pri7),
 346        AM65_CPSW_STATS(, tx_pri0_bcnt),
 347        AM65_CPSW_STATS(, tx_pri1_bcnt),
 348        AM65_CPSW_STATS(, tx_pri2_bcnt),
 349        AM65_CPSW_STATS(, tx_pri3_bcnt),
 350        AM65_CPSW_STATS(, tx_pri4_bcnt),
 351        AM65_CPSW_STATS(, tx_pri5_bcnt),
 352        AM65_CPSW_STATS(, tx_pri6_bcnt),
 353        AM65_CPSW_STATS(, tx_pri7_bcnt),
 354        AM65_CPSW_STATS(, tx_pri0_drop),
 355        AM65_CPSW_STATS(, tx_pri1_drop),
 356        AM65_CPSW_STATS(, tx_pri2_drop),
 357        AM65_CPSW_STATS(, tx_pri3_drop),
 358        AM65_CPSW_STATS(, tx_pri4_drop),
 359        AM65_CPSW_STATS(, tx_pri5_drop),
 360        AM65_CPSW_STATS(, tx_pri6_drop),
 361        AM65_CPSW_STATS(, tx_pri7_drop),
 362        AM65_CPSW_STATS(, tx_pri0_drop_bcnt),
 363        AM65_CPSW_STATS(, tx_pri1_drop_bcnt),
 364        AM65_CPSW_STATS(, tx_pri2_drop_bcnt),
 365        AM65_CPSW_STATS(, tx_pri3_drop_bcnt),
 366        AM65_CPSW_STATS(, tx_pri4_drop_bcnt),
 367        AM65_CPSW_STATS(, tx_pri5_drop_bcnt),
 368        AM65_CPSW_STATS(, tx_pri6_drop_bcnt),
 369        AM65_CPSW_STATS(, tx_pri7_drop_bcnt),
 370};
 371
 372/* Ethtool priv_flags */
 373static const char am65_cpsw_ethtool_priv_flags[][ETH_GSTRING_LEN] = {
 374#define AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN       BIT(0)
 375        "p0-rx-ptype-rrobin",
 376};
 377
 378static int am65_cpsw_ethtool_op_begin(struct net_device *ndev)
 379{
 380        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 381        int ret;
 382
 383        ret = pm_runtime_get_sync(common->dev);
 384        if (ret < 0) {
 385                dev_err(common->dev, "ethtool begin failed %d\n", ret);
 386                pm_runtime_put_noidle(common->dev);
 387        }
 388
 389        return ret;
 390}
 391
 392static void am65_cpsw_ethtool_op_complete(struct net_device *ndev)
 393{
 394        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 395        int ret;
 396
 397        ret = pm_runtime_put(common->dev);
 398        if (ret < 0 && ret != -EBUSY)
 399                dev_err(common->dev, "ethtool complete failed %d\n", ret);
 400}
 401
 402static void am65_cpsw_get_drvinfo(struct net_device *ndev,
 403                                  struct ethtool_drvinfo *info)
 404{
 405        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 406
 407        strlcpy(info->driver, dev_driver_string(common->dev),
 408                sizeof(info->driver));
 409        strlcpy(info->bus_info, dev_name(common->dev), sizeof(info->bus_info));
 410}
 411
 412static u32 am65_cpsw_get_msglevel(struct net_device *ndev)
 413{
 414        struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
 415
 416        return priv->msg_enable;
 417}
 418
 419static void am65_cpsw_set_msglevel(struct net_device *ndev, u32 value)
 420{
 421        struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
 422
 423        priv->msg_enable = value;
 424}
 425
 426static void am65_cpsw_get_channels(struct net_device *ndev,
 427                                   struct ethtool_channels *ch)
 428{
 429        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 430
 431        ch->max_rx = AM65_CPSW_MAX_RX_QUEUES;
 432        ch->max_tx = AM65_CPSW_MAX_TX_QUEUES;
 433        ch->rx_count = AM65_CPSW_MAX_RX_QUEUES;
 434        ch->tx_count = common->tx_ch_num;
 435}
 436
 437static int am65_cpsw_set_channels(struct net_device *ndev,
 438                                  struct ethtool_channels *chs)
 439{
 440        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 441
 442        if (!chs->rx_count || !chs->tx_count)
 443                return -EINVAL;
 444
 445        /* Check if interface is up. Can change the num queues when
 446         * the interface is down.
 447         */
 448        if (common->usage_count)
 449                return -EBUSY;
 450
 451        am65_cpsw_nuss_remove_tx_chns(common);
 452
 453        return am65_cpsw_nuss_update_tx_chns(common, chs->tx_count);
 454}
 455
 456static void am65_cpsw_get_ringparam(struct net_device *ndev,
 457                                    struct ethtool_ringparam *ering)
 458{
 459        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 460
 461        /* not supported */
 462        ering->tx_pending = common->tx_chns[0].descs_num;
 463        ering->rx_pending = common->rx_chns.descs_num;
 464}
 465
 466static void am65_cpsw_get_pauseparam(struct net_device *ndev,
 467                                     struct ethtool_pauseparam *pause)
 468{
 469        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 470
 471        pause->autoneg = AUTONEG_DISABLE;
 472        pause->rx_pause = salve->rx_pause ? true : false;
 473        pause->tx_pause = salve->tx_pause ? true : false;
 474}
 475
 476static int am65_cpsw_set_pauseparam(struct net_device *ndev,
 477                                    struct ethtool_pauseparam *pause)
 478{
 479        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 480
 481        if (!salve->phy)
 482                return -EINVAL;
 483
 484        if (!phy_validate_pause(salve->phy, pause))
 485                return -EINVAL;
 486
 487        salve->rx_pause = pause->rx_pause ? true : false;
 488        salve->tx_pause = pause->tx_pause ? true : false;
 489
 490        phy_set_asym_pause(salve->phy, salve->rx_pause, salve->tx_pause);
 491
 492        return 0;
 493}
 494
 495static void am65_cpsw_get_wol(struct net_device *ndev,
 496                              struct ethtool_wolinfo *wol)
 497{
 498        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 499
 500        wol->supported = 0;
 501        wol->wolopts = 0;
 502
 503        if (salve->phy)
 504                phy_ethtool_get_wol(salve->phy, wol);
 505}
 506
 507static int am65_cpsw_set_wol(struct net_device *ndev,
 508                             struct ethtool_wolinfo *wol)
 509{
 510        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 511
 512        if (!salve->phy)
 513                return -EOPNOTSUPP;
 514
 515        return phy_ethtool_set_wol(salve->phy, wol);
 516}
 517
 518static int am65_cpsw_get_link_ksettings(struct net_device *ndev,
 519                                        struct ethtool_link_ksettings *ecmd)
 520{
 521        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 522
 523        if (!salve->phy)
 524                return -EOPNOTSUPP;
 525
 526        phy_ethtool_ksettings_get(salve->phy, ecmd);
 527        return 0;
 528}
 529
 530static int
 531am65_cpsw_set_link_ksettings(struct net_device *ndev,
 532                             const struct ethtool_link_ksettings *ecmd)
 533{
 534        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 535
 536        if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
 537                return -EOPNOTSUPP;
 538
 539        return phy_ethtool_ksettings_set(salve->phy, ecmd);
 540}
 541
 542static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
 543{
 544        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 545
 546        if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
 547                return -EOPNOTSUPP;
 548
 549        return phy_ethtool_get_eee(salve->phy, edata);
 550}
 551
 552static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
 553{
 554        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 555
 556        if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
 557                return -EOPNOTSUPP;
 558
 559        return phy_ethtool_set_eee(salve->phy, edata);
 560}
 561
 562static int am65_cpsw_nway_reset(struct net_device *ndev)
 563{
 564        struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 565
 566        if (!salve->phy || phy_is_pseudo_fixed_link(salve->phy))
 567                return -EOPNOTSUPP;
 568
 569        return phy_restart_aneg(salve->phy);
 570}
 571
 572static int am65_cpsw_get_regs_len(struct net_device *ndev)
 573{
 574        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 575        u32 ale_entries, i, regdump_len = 0;
 576
 577        ale_entries = cpsw_ale_get_num_entries(common->ale);
 578        for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) {
 579                if (am65_cpsw_regdump[i].hdr.module_id ==
 580                    AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) {
 581                        regdump_len += sizeof(struct am65_cpsw_regdump_hdr);
 582                        regdump_len += ale_entries *
 583                                       ALE_ENTRY_WORDS * sizeof(u32);
 584                        continue;
 585                }
 586                regdump_len += am65_cpsw_regdump[i].hdr.len;
 587        }
 588
 589        return regdump_len;
 590}
 591
 592static void am65_cpsw_get_regs(struct net_device *ndev,
 593                               struct ethtool_regs *regs, void *p)
 594{
 595        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 596        u32 ale_entries, i, j, pos, *reg = p;
 597
 598        /* update CPSW IP version */
 599        regs->version = AM65_CPSW_REGDUMP_VER;
 600        ale_entries = cpsw_ale_get_num_entries(common->ale);
 601
 602        pos = 0;
 603        for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) {
 604                reg[pos++] = am65_cpsw_regdump[i].hdr.module_id;
 605
 606                if (am65_cpsw_regdump[i].hdr.module_id ==
 607                    AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) {
 608                        u32 ale_tbl_len = ale_entries *
 609                                          ALE_ENTRY_WORDS * sizeof(u32) +
 610                                          sizeof(struct am65_cpsw_regdump_hdr);
 611                        reg[pos++] = ale_tbl_len;
 612                        cpsw_ale_dump(common->ale, &reg[pos]);
 613                        pos += ale_tbl_len;
 614                        continue;
 615                }
 616
 617                reg[pos++] = am65_cpsw_regdump[i].hdr.len;
 618
 619                j = am65_cpsw_regdump[i].start_ofs;
 620                do {
 621                        reg[pos++] = j;
 622                        reg[pos++] = readl_relaxed(common->ss_base + j);
 623                        j += sizeof(u32);
 624                } while (j <= am65_cpsw_regdump[i].end_ofs);
 625        }
 626}
 627
 628static int am65_cpsw_get_sset_count(struct net_device *ndev, int sset)
 629{
 630        switch (sset) {
 631        case ETH_SS_STATS:
 632                return ARRAY_SIZE(am65_host_stats) +
 633                       ARRAY_SIZE(am65_slave_stats);
 634        case ETH_SS_PRIV_FLAGS:
 635                return ARRAY_SIZE(am65_cpsw_ethtool_priv_flags);
 636        default:
 637                return -EOPNOTSUPP;
 638        }
 639}
 640
 641static void am65_cpsw_get_strings(struct net_device *ndev,
 642                                  u32 stringset, u8 *data)
 643{
 644        const struct am65_cpsw_ethtool_stat *hw_stats;
 645        u32 i, num_stats;
 646        u8 *p = data;
 647
 648        switch (stringset) {
 649        case ETH_SS_STATS:
 650                num_stats = ARRAY_SIZE(am65_host_stats);
 651                hw_stats = am65_host_stats;
 652                for (i = 0; i < num_stats; i++) {
 653                        memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN);
 654                        p += ETH_GSTRING_LEN;
 655                }
 656
 657                num_stats = ARRAY_SIZE(am65_slave_stats);
 658                hw_stats = am65_slave_stats;
 659                for (i = 0; i < num_stats; i++) {
 660                        memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN);
 661                        p += ETH_GSTRING_LEN;
 662                }
 663                break;
 664        case ETH_SS_PRIV_FLAGS:
 665                num_stats = ARRAY_SIZE(am65_cpsw_ethtool_priv_flags);
 666
 667                for (i = 0; i < num_stats; i++) {
 668                        memcpy(p, am65_cpsw_ethtool_priv_flags[i],
 669                               ETH_GSTRING_LEN);
 670                        p += ETH_GSTRING_LEN;
 671                }
 672                break;
 673        }
 674}
 675
 676static void am65_cpsw_get_ethtool_stats(struct net_device *ndev,
 677                                        struct ethtool_stats *stats, u64 *data)
 678{
 679        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 680        const struct am65_cpsw_ethtool_stat *hw_stats;
 681        struct am65_cpsw_host *host_p;
 682        struct am65_cpsw_port *port;
 683        u32 i, num_stats;
 684
 685        host_p = am65_common_get_host(common);
 686        port = am65_ndev_to_port(ndev);
 687        num_stats = ARRAY_SIZE(am65_host_stats);
 688        hw_stats = am65_host_stats;
 689        for (i = 0; i < num_stats; i++)
 690                *data++ = readl_relaxed(host_p->stat_base +
 691                                        hw_stats[i].offset);
 692
 693        num_stats = ARRAY_SIZE(am65_slave_stats);
 694        hw_stats = am65_slave_stats;
 695        for (i = 0; i < num_stats; i++)
 696                *data++ = readl_relaxed(port->stat_base +
 697                                        hw_stats[i].offset);
 698}
 699
 700static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev,
 701                                         struct ethtool_ts_info *info)
 702{
 703        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 704
 705        if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
 706                return ethtool_op_get_ts_info(ndev, info);
 707
 708        info->so_timestamping =
 709                SOF_TIMESTAMPING_TX_HARDWARE |
 710                SOF_TIMESTAMPING_TX_SOFTWARE |
 711                SOF_TIMESTAMPING_RX_HARDWARE |
 712                SOF_TIMESTAMPING_RX_SOFTWARE |
 713                SOF_TIMESTAMPING_SOFTWARE |
 714                SOF_TIMESTAMPING_RAW_HARDWARE;
 715        info->phc_index = am65_cpts_phc_index(common->cpts);
 716        info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
 717        info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
 718        return 0;
 719}
 720
 721static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)
 722{
 723        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 724        u32 priv_flags = 0;
 725
 726        if (common->pf_p0_rx_ptype_rrobin)
 727                priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN;
 728
 729        return priv_flags;
 730}
 731
 732static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
 733{
 734        struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 735        int rrobin;
 736
 737        rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);
 738
 739        if (common->usage_count)
 740                return -EBUSY;
 741
 742        if (common->est_enabled && rrobin) {
 743                netdev_err(ndev,
 744                           "p0-rx-ptype-rrobin flag conflicts with QOS\n");
 745                return -EINVAL;
 746        }
 747
 748        common->pf_p0_rx_ptype_rrobin = rrobin;
 749
 750        return 0;
 751}
 752
 753const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
 754        .begin                  = am65_cpsw_ethtool_op_begin,
 755        .complete               = am65_cpsw_ethtool_op_complete,
 756        .get_drvinfo            = am65_cpsw_get_drvinfo,
 757        .get_msglevel           = am65_cpsw_get_msglevel,
 758        .set_msglevel           = am65_cpsw_set_msglevel,
 759        .get_channels           = am65_cpsw_get_channels,
 760        .set_channels           = am65_cpsw_set_channels,
 761        .get_ringparam          = am65_cpsw_get_ringparam,
 762        .get_regs_len           = am65_cpsw_get_regs_len,
 763        .get_regs               = am65_cpsw_get_regs,
 764        .get_sset_count         = am65_cpsw_get_sset_count,
 765        .get_strings            = am65_cpsw_get_strings,
 766        .get_ethtool_stats      = am65_cpsw_get_ethtool_stats,
 767        .get_ts_info            = am65_cpsw_get_ethtool_ts_info,
 768        .get_priv_flags         = am65_cpsw_get_ethtool_priv_flags,
 769        .set_priv_flags         = am65_cpsw_set_ethtool_priv_flags,
 770
 771        .get_link               = ethtool_op_get_link,
 772        .get_link_ksettings     = am65_cpsw_get_link_ksettings,
 773        .set_link_ksettings     = am65_cpsw_set_link_ksettings,
 774        .get_pauseparam         = am65_cpsw_get_pauseparam,
 775        .set_pauseparam         = am65_cpsw_set_pauseparam,
 776        .get_wol                = am65_cpsw_get_wol,
 777        .set_wol                = am65_cpsw_set_wol,
 778        .get_eee                = am65_cpsw_get_eee,
 779        .set_eee                = am65_cpsw_set_eee,
 780        .nway_reset             = am65_cpsw_nway_reset,
 781};
 782