File Index
Files and directories
Sign in
FILE

am65-cpsw-ethtool.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/ti/am65-cpsw-ethtool.c C
   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/phylink.h>
  10#include <linux/platform_device.h>
  11#include <linux/pm_runtime.h>
  12
  13#include "am65-cpsw-nuss.h"
  14#include "am65-cpsw-qos.h"
  15#include "cpsw_ale.h"
  16#include "am65-cpts.h"
  17
  18#define AM65_CPSW_REGDUMP_VER 0x1
  19
  20enum {
  21	AM65_CPSW_REGDUMP_MOD_NUSS = 1,
  22	AM65_CPSW_REGDUMP_MOD_RGMII_STATUS = 2,
  23	AM65_CPSW_REGDUMP_MOD_MDIO = 3,
  24	AM65_CPSW_REGDUMP_MOD_CPSW = 4,
  25	AM65_CPSW_REGDUMP_MOD_CPSW_P0 = 5,
  26	AM65_CPSW_REGDUMP_MOD_CPSW_P1 = 6,
  27	AM65_CPSW_REGDUMP_MOD_CPSW_CPTS = 7,
  28	AM65_CPSW_REGDUMP_MOD_CPSW_ALE = 8,
  29	AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL = 9,
  30	AM65_CPSW_REGDUMP_MOD_LAST,
  31};
  32
  33/**
  34 * struct am65_cpsw_regdump_hdr - regdump record header
  35 *
  36 * @module_id: CPSW module ID
  37 * @len: CPSW module registers space length in u32
  38 */
  39
  40struct am65_cpsw_regdump_hdr {
  41	u32 module_id;
  42	u32 len;
  43};
  44
  45/**
  46 * struct am65_cpsw_regdump_item - regdump module description
  47 *
  48 * @hdr: CPSW module header
  49 * @start_ofs: CPSW module registers start addr
  50 * @end_ofs: CPSW module registers end addr
  51 *
  52 * Registers dump provided in the format:
  53 *  u32 : module ID
  54 *  u32 : dump length
  55 *  u32[..len]: registers values
  56 */
  57struct am65_cpsw_regdump_item {
  58	struct am65_cpsw_regdump_hdr hdr;
  59	u32 start_ofs;
  60	u32 end_ofs;
  61};
  62
  63#define AM65_CPSW_REGDUMP_REC(mod, start, end) { \
  64	.hdr.module_id = (mod), \
  65	.hdr.len = (end + 4 - start) * 2 + \
  66		   sizeof(struct am65_cpsw_regdump_hdr), \
  67	.start_ofs = (start), \
  68	.end_ofs = end, \
  69}
  70
  71static const struct am65_cpsw_regdump_item am65_cpsw_regdump[] = {
  72	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_NUSS, 0x0, 0x1c),
  73	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_RGMII_STATUS, 0x30, 0x4c),
  74	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_MDIO, 0xf00, 0xffc),
  75	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW, 0x20000, 0x2011c),
  76	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P0, 0x21000, 0x21320),
  77	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_P1, 0x22000, 0x223a4),
  78	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_CPTS,
  79			      0x3d000, 0x3d048),
  80	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE, 0x3e000, 0x3e13c),
  81	AM65_CPSW_REGDUMP_REC(AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL, 0, 0),
  82};
  83
  84struct am65_cpsw_stats_regs {
  85	u32	rx_good_frames;
  86	u32	rx_broadcast_frames;
  87	u32	rx_multicast_frames;
  88	u32	rx_pause_frames;		/* slave */
  89	u32	rx_crc_errors;
  90	u32	rx_align_code_errors;		/* slave */
  91	u32	rx_oversized_frames;
  92	u32	rx_jabber_frames;		/* slave */
  93	u32	rx_undersized_frames;
  94	u32	rx_fragments;			/* slave */
  95	u32	ale_drop;
  96	u32	ale_overrun_drop;
  97	u32	rx_octets;
  98	u32	tx_good_frames;
  99	u32	tx_broadcast_frames;
 100	u32	tx_multicast_frames;
 101	u32	tx_pause_frames;		/* slave */
 102	u32	tx_deferred_frames;		/* slave */
 103	u32	tx_collision_frames;		/* slave */
 104	u32	tx_single_coll_frames;		/* slave */
 105	u32	tx_mult_coll_frames;		/* slave */
 106	u32	tx_excessive_collisions;	/* slave */
 107	u32	tx_late_collisions;		/* slave */
 108	u32	rx_ipg_error;			/* slave 10G only */
 109	u32	tx_carrier_sense_errors;	/* slave */
 110	u32	tx_octets;
 111	u32	tx_64B_frames;
 112	u32	tx_65_to_127B_frames;
 113	u32	tx_128_to_255B_frames;
 114	u32	tx_256_to_511B_frames;
 115	u32	tx_512_to_1023B_frames;
 116	u32	tx_1024B_frames;
 117	u32	net_octets;
 118	u32	rx_bottom_fifo_drop;
 119	u32	rx_port_mask_drop;
 120	u32	rx_top_fifo_drop;
 121	u32	ale_rate_limit_drop;
 122	u32	ale_vid_ingress_drop;
 123	u32	ale_da_eq_sa_drop;
 124	u32	ale_block_drop;			/* K3 */
 125	u32	ale_secure_drop;		/* K3 */
 126	u32	ale_auth_drop;			/* K3 */
 127	u32	ale_unknown_ucast;
 128	u32	ale_unknown_ucast_bytes;
 129	u32	ale_unknown_mcast;
 130	u32	ale_unknown_mcast_bytes;
 131	u32	ale_unknown_bcast;
 132	u32	ale_unknown_bcast_bytes;
 133	u32	ale_pol_match;
 134	u32	ale_pol_match_red;
 135	u32	ale_pol_match_yellow;
 136	u32	ale_mcast_sa_drop;		/* K3 */
 137	u32	ale_dual_vlan_drop;		/* K3 */
 138	u32	ale_len_err_drop;		/* K3 */
 139	u32	ale_ip_next_hdr_drop;		/* K3 */
 140	u32	ale_ipv4_frag_drop;		/* K3 */
 141	u32	__rsvd_1[24];
 142	u32	iet_rx_assembly_err;		/* K3 slave */
 143	u32	iet_rx_assembly_ok;		/* K3 slave */
 144	u32	iet_rx_smd_err;			/* K3 slave */
 145	u32	iet_rx_frag;			/* K3 slave */
 146	u32	iet_tx_hold;			/* K3 slave */
 147	u32	iet_tx_frag;			/* K3 slave */
 148	u32	__rsvd_2[9];
 149	u32	tx_mem_protect_err;
 150	/* following NU only */
 151	u32	tx_pri0;
 152	u32	tx_pri1;
 153	u32	tx_pri2;
 154	u32	tx_pri3;
 155	u32	tx_pri4;
 156	u32	tx_pri5;
 157	u32	tx_pri6;
 158	u32	tx_pri7;
 159	u32	tx_pri0_bcnt;
 160	u32	tx_pri1_bcnt;
 161	u32	tx_pri2_bcnt;
 162	u32	tx_pri3_bcnt;
 163	u32	tx_pri4_bcnt;
 164	u32	tx_pri5_bcnt;
 165	u32	tx_pri6_bcnt;
 166	u32	tx_pri7_bcnt;
 167	u32	tx_pri0_drop;
 168	u32	tx_pri1_drop;
 169	u32	tx_pri2_drop;
 170	u32	tx_pri3_drop;
 171	u32	tx_pri4_drop;
 172	u32	tx_pri5_drop;
 173	u32	tx_pri6_drop;
 174	u32	tx_pri7_drop;
 175	u32	tx_pri0_drop_bcnt;
 176	u32	tx_pri1_drop_bcnt;
 177	u32	tx_pri2_drop_bcnt;
 178	u32	tx_pri3_drop_bcnt;
 179	u32	tx_pri4_drop_bcnt;
 180	u32	tx_pri5_drop_bcnt;
 181	u32	tx_pri6_drop_bcnt;
 182	u32	tx_pri7_drop_bcnt;
 183};
 184
 185struct am65_cpsw_ethtool_stat {
 186	char desc[ETH_GSTRING_LEN];
 187	int offset;
 188};
 189
 190#define AM65_CPSW_STATS(prefix, field)			\
 191{							\
 192	#prefix#field,					\
 193	offsetof(struct am65_cpsw_stats_regs, field)	\
 194}
 195
 196static const struct am65_cpsw_ethtool_stat am65_host_stats[] = {
 197	AM65_CPSW_STATS(p0_, rx_good_frames),
 198	AM65_CPSW_STATS(p0_, rx_broadcast_frames),
 199	AM65_CPSW_STATS(p0_, rx_multicast_frames),
 200	AM65_CPSW_STATS(p0_, rx_crc_errors),
 201	AM65_CPSW_STATS(p0_, rx_oversized_frames),
 202	AM65_CPSW_STATS(p0_, rx_undersized_frames),
 203	AM65_CPSW_STATS(p0_, ale_drop),
 204	AM65_CPSW_STATS(p0_, ale_overrun_drop),
 205	AM65_CPSW_STATS(p0_, rx_octets),
 206	AM65_CPSW_STATS(p0_, tx_good_frames),
 207	AM65_CPSW_STATS(p0_, tx_broadcast_frames),
 208	AM65_CPSW_STATS(p0_, tx_multicast_frames),
 209	AM65_CPSW_STATS(p0_, tx_octets),
 210	AM65_CPSW_STATS(p0_, tx_64B_frames),
 211	AM65_CPSW_STATS(p0_, tx_65_to_127B_frames),
 212	AM65_CPSW_STATS(p0_, tx_128_to_255B_frames),
 213	AM65_CPSW_STATS(p0_, tx_256_to_511B_frames),
 214	AM65_CPSW_STATS(p0_, tx_512_to_1023B_frames),
 215	AM65_CPSW_STATS(p0_, tx_1024B_frames),
 216	AM65_CPSW_STATS(p0_, net_octets),
 217	AM65_CPSW_STATS(p0_, rx_bottom_fifo_drop),
 218	AM65_CPSW_STATS(p0_, rx_port_mask_drop),
 219	AM65_CPSW_STATS(p0_, rx_top_fifo_drop),
 220	AM65_CPSW_STATS(p0_, ale_rate_limit_drop),
 221	AM65_CPSW_STATS(p0_, ale_vid_ingress_drop),
 222	AM65_CPSW_STATS(p0_, ale_da_eq_sa_drop),
 223	AM65_CPSW_STATS(p0_, ale_block_drop),
 224	AM65_CPSW_STATS(p0_, ale_secure_drop),
 225	AM65_CPSW_STATS(p0_, ale_auth_drop),
 226	AM65_CPSW_STATS(p0_, ale_unknown_ucast),
 227	AM65_CPSW_STATS(p0_, ale_unknown_ucast_bytes),
 228	AM65_CPSW_STATS(p0_, ale_unknown_mcast),
 229	AM65_CPSW_STATS(p0_, ale_unknown_mcast_bytes),
 230	AM65_CPSW_STATS(p0_, ale_unknown_bcast),
 231	AM65_CPSW_STATS(p0_, ale_unknown_bcast_bytes),
 232	AM65_CPSW_STATS(p0_, ale_pol_match),
 233	AM65_CPSW_STATS(p0_, ale_pol_match_red),
 234	AM65_CPSW_STATS(p0_, ale_pol_match_yellow),
 235	AM65_CPSW_STATS(p0_, ale_mcast_sa_drop),
 236	AM65_CPSW_STATS(p0_, ale_dual_vlan_drop),
 237	AM65_CPSW_STATS(p0_, ale_len_err_drop),
 238	AM65_CPSW_STATS(p0_, ale_ip_next_hdr_drop),
 239	AM65_CPSW_STATS(p0_, ale_ipv4_frag_drop),
 240	AM65_CPSW_STATS(p0_, tx_mem_protect_err),
 241	AM65_CPSW_STATS(p0_, tx_pri0),
 242	AM65_CPSW_STATS(p0_, tx_pri1),
 243	AM65_CPSW_STATS(p0_, tx_pri2),
 244	AM65_CPSW_STATS(p0_, tx_pri3),
 245	AM65_CPSW_STATS(p0_, tx_pri4),
 246	AM65_CPSW_STATS(p0_, tx_pri5),
 247	AM65_CPSW_STATS(p0_, tx_pri6),
 248	AM65_CPSW_STATS(p0_, tx_pri7),
 249	AM65_CPSW_STATS(p0_, tx_pri0_bcnt),
 250	AM65_CPSW_STATS(p0_, tx_pri1_bcnt),
 251	AM65_CPSW_STATS(p0_, tx_pri2_bcnt),
 252	AM65_CPSW_STATS(p0_, tx_pri3_bcnt),
 253	AM65_CPSW_STATS(p0_, tx_pri4_bcnt),
 254	AM65_CPSW_STATS(p0_, tx_pri5_bcnt),
 255	AM65_CPSW_STATS(p0_, tx_pri6_bcnt),
 256	AM65_CPSW_STATS(p0_, tx_pri7_bcnt),
 257	AM65_CPSW_STATS(p0_, tx_pri0_drop),
 258	AM65_CPSW_STATS(p0_, tx_pri1_drop),
 259	AM65_CPSW_STATS(p0_, tx_pri2_drop),
 260	AM65_CPSW_STATS(p0_, tx_pri3_drop),
 261	AM65_CPSW_STATS(p0_, tx_pri4_drop),
 262	AM65_CPSW_STATS(p0_, tx_pri5_drop),
 263	AM65_CPSW_STATS(p0_, tx_pri6_drop),
 264	AM65_CPSW_STATS(p0_, tx_pri7_drop),
 265	AM65_CPSW_STATS(p0_, tx_pri0_drop_bcnt),
 266	AM65_CPSW_STATS(p0_, tx_pri1_drop_bcnt),
 267	AM65_CPSW_STATS(p0_, tx_pri2_drop_bcnt),
 268	AM65_CPSW_STATS(p0_, tx_pri3_drop_bcnt),
 269	AM65_CPSW_STATS(p0_, tx_pri4_drop_bcnt),
 270	AM65_CPSW_STATS(p0_, tx_pri5_drop_bcnt),
 271	AM65_CPSW_STATS(p0_, tx_pri6_drop_bcnt),
 272	AM65_CPSW_STATS(p0_, tx_pri7_drop_bcnt),
 273};
 274
 275static const struct am65_cpsw_ethtool_stat am65_slave_stats[] = {
 276	AM65_CPSW_STATS(, rx_good_frames),
 277	AM65_CPSW_STATS(, rx_broadcast_frames),
 278	AM65_CPSW_STATS(, rx_multicast_frames),
 279	AM65_CPSW_STATS(, rx_pause_frames),
 280	AM65_CPSW_STATS(, rx_crc_errors),
 281	AM65_CPSW_STATS(, rx_align_code_errors),
 282	AM65_CPSW_STATS(, rx_oversized_frames),
 283	AM65_CPSW_STATS(, rx_jabber_frames),
 284	AM65_CPSW_STATS(, rx_undersized_frames),
 285	AM65_CPSW_STATS(, rx_fragments),
 286	AM65_CPSW_STATS(, ale_drop),
 287	AM65_CPSW_STATS(, ale_overrun_drop),
 288	AM65_CPSW_STATS(, rx_octets),
 289	AM65_CPSW_STATS(, tx_good_frames),
 290	AM65_CPSW_STATS(, tx_broadcast_frames),
 291	AM65_CPSW_STATS(, tx_multicast_frames),
 292	AM65_CPSW_STATS(, tx_pause_frames),
 293	AM65_CPSW_STATS(, tx_deferred_frames),
 294	AM65_CPSW_STATS(, tx_collision_frames),
 295	AM65_CPSW_STATS(, tx_single_coll_frames),
 296	AM65_CPSW_STATS(, tx_mult_coll_frames),
 297	AM65_CPSW_STATS(, tx_excessive_collisions),
 298	AM65_CPSW_STATS(, tx_late_collisions),
 299	AM65_CPSW_STATS(, rx_ipg_error),
 300	AM65_CPSW_STATS(, tx_carrier_sense_errors),
 301	AM65_CPSW_STATS(, tx_octets),
 302	AM65_CPSW_STATS(, tx_64B_frames),
 303	AM65_CPSW_STATS(, tx_65_to_127B_frames),
 304	AM65_CPSW_STATS(, tx_128_to_255B_frames),
 305	AM65_CPSW_STATS(, tx_256_to_511B_frames),
 306	AM65_CPSW_STATS(, tx_512_to_1023B_frames),
 307	AM65_CPSW_STATS(, tx_1024B_frames),
 308	AM65_CPSW_STATS(, net_octets),
 309	AM65_CPSW_STATS(, rx_bottom_fifo_drop),
 310	AM65_CPSW_STATS(, rx_port_mask_drop),
 311	AM65_CPSW_STATS(, rx_top_fifo_drop),
 312	AM65_CPSW_STATS(, ale_rate_limit_drop),
 313	AM65_CPSW_STATS(, ale_vid_ingress_drop),
 314	AM65_CPSW_STATS(, ale_da_eq_sa_drop),
 315	AM65_CPSW_STATS(, ale_block_drop),
 316	AM65_CPSW_STATS(, ale_secure_drop),
 317	AM65_CPSW_STATS(, ale_auth_drop),
 318	AM65_CPSW_STATS(, ale_unknown_ucast),
 319	AM65_CPSW_STATS(, ale_unknown_ucast_bytes),
 320	AM65_CPSW_STATS(, ale_unknown_mcast),
 321	AM65_CPSW_STATS(, ale_unknown_mcast_bytes),
 322	AM65_CPSW_STATS(, ale_unknown_bcast),
 323	AM65_CPSW_STATS(, ale_unknown_bcast_bytes),
 324	AM65_CPSW_STATS(, ale_pol_match),
 325	AM65_CPSW_STATS(, ale_pol_match_red),
 326	AM65_CPSW_STATS(, ale_pol_match_yellow),
 327	AM65_CPSW_STATS(, ale_mcast_sa_drop),
 328	AM65_CPSW_STATS(, ale_dual_vlan_drop),
 329	AM65_CPSW_STATS(, ale_len_err_drop),
 330	AM65_CPSW_STATS(, ale_ip_next_hdr_drop),
 331	AM65_CPSW_STATS(, ale_ipv4_frag_drop),
 332	AM65_CPSW_STATS(, iet_rx_assembly_err),
 333	AM65_CPSW_STATS(, iet_rx_assembly_ok),
 334	AM65_CPSW_STATS(, iet_rx_smd_err),
 335	AM65_CPSW_STATS(, iet_rx_frag),
 336	AM65_CPSW_STATS(, iet_tx_hold),
 337	AM65_CPSW_STATS(, iet_tx_frag),
 338	AM65_CPSW_STATS(, tx_mem_protect_err),
 339	AM65_CPSW_STATS(, tx_pri0),
 340	AM65_CPSW_STATS(, tx_pri1),
 341	AM65_CPSW_STATS(, tx_pri2),
 342	AM65_CPSW_STATS(, tx_pri3),
 343	AM65_CPSW_STATS(, tx_pri4),
 344	AM65_CPSW_STATS(, tx_pri5),
 345	AM65_CPSW_STATS(, tx_pri6),
 346	AM65_CPSW_STATS(, tx_pri7),
 347	AM65_CPSW_STATS(, tx_pri0_bcnt),
 348	AM65_CPSW_STATS(, tx_pri1_bcnt),
 349	AM65_CPSW_STATS(, tx_pri2_bcnt),
 350	AM65_CPSW_STATS(, tx_pri3_bcnt),
 351	AM65_CPSW_STATS(, tx_pri4_bcnt),
 352	AM65_CPSW_STATS(, tx_pri5_bcnt),
 353	AM65_CPSW_STATS(, tx_pri6_bcnt),
 354	AM65_CPSW_STATS(, tx_pri7_bcnt),
 355	AM65_CPSW_STATS(, tx_pri0_drop),
 356	AM65_CPSW_STATS(, tx_pri1_drop),
 357	AM65_CPSW_STATS(, tx_pri2_drop),
 358	AM65_CPSW_STATS(, tx_pri3_drop),
 359	AM65_CPSW_STATS(, tx_pri4_drop),
 360	AM65_CPSW_STATS(, tx_pri5_drop),
 361	AM65_CPSW_STATS(, tx_pri6_drop),
 362	AM65_CPSW_STATS(, tx_pri7_drop),
 363	AM65_CPSW_STATS(, tx_pri0_drop_bcnt),
 364	AM65_CPSW_STATS(, tx_pri1_drop_bcnt),
 365	AM65_CPSW_STATS(, tx_pri2_drop_bcnt),
 366	AM65_CPSW_STATS(, tx_pri3_drop_bcnt),
 367	AM65_CPSW_STATS(, tx_pri4_drop_bcnt),
 368	AM65_CPSW_STATS(, tx_pri5_drop_bcnt),
 369	AM65_CPSW_STATS(, tx_pri6_drop_bcnt),
 370	AM65_CPSW_STATS(, tx_pri7_drop_bcnt),
 371};
 372
 373/* Ethtool priv_flags */
 374static const char am65_cpsw_ethtool_priv_flags[][ETH_GSTRING_LEN] = {
 375#define	AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN	BIT(0)
 376	"p0-rx-ptype-rrobin",
 377};
 378
 379static int am65_cpsw_ethtool_op_begin(struct net_device *ndev)
 380{
 381	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 382	int ret;
 383
 384	ret = pm_runtime_resume_and_get(common->dev);
 385	if (ret < 0)
 386		dev_err(common->dev, "ethtool begin failed %d\n", ret);
 387
 388	return ret;
 389}
 390
 391static void am65_cpsw_ethtool_op_complete(struct net_device *ndev)
 392{
 393	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 394	int ret;
 395
 396	ret = pm_runtime_put(common->dev);
 397	if (ret < 0 && ret != -EBUSY)
 398		dev_err(common->dev, "ethtool complete failed %d\n", ret);
 399}
 400
 401static void am65_cpsw_get_drvinfo(struct net_device *ndev,
 402				  struct ethtool_drvinfo *info)
 403{
 404	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 405
 406	strscpy(info->driver, dev_driver_string(common->dev),
 407		sizeof(info->driver));
 408	strscpy(info->bus_info, dev_name(common->dev), sizeof(info->bus_info));
 409}
 410
 411static u32 am65_cpsw_get_msglevel(struct net_device *ndev)
 412{
 413	struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
 414
 415	return priv->msg_enable;
 416}
 417
 418static void am65_cpsw_set_msglevel(struct net_device *ndev, u32 value)
 419{
 420	struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
 421
 422	priv->msg_enable = value;
 423}
 424
 425static void am65_cpsw_get_channels(struct net_device *ndev,
 426				   struct ethtool_channels *ch)
 427{
 428	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 429
 430	ch->max_rx = AM65_CPSW_MAX_QUEUES;
 431	ch->max_tx = AM65_CPSW_MAX_QUEUES;
 432	ch->rx_count = common->rx_ch_num_flows;
 433	ch->tx_count = common->tx_ch_num;
 434}
 435
 436static int am65_cpsw_set_channels(struct net_device *ndev,
 437				  struct ethtool_channels *chs)
 438{
 439	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 440
 441	if (!chs->rx_count || !chs->tx_count)
 442		return -EINVAL;
 443
 444	/* Check if interface is up. Can change the num queues when
 445	 * the interface is down.
 446	 */
 447	if (common->usage_count)
 448		return -EBUSY;
 449
 450	return am65_cpsw_nuss_update_tx_rx_chns(common, chs->tx_count,
 451						chs->rx_count);
 452}
 453
 454static void
 455am65_cpsw_get_ringparam(struct net_device *ndev,
 456			struct ethtool_ringparam *ering,
 457			struct kernel_ethtool_ringparam *kernel_ering,
 458			struct netlink_ext_ack *extack)
 459{
 460	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 461
 462	/* not supported */
 463	ering->tx_pending = common->tx_chns[0].descs_num;
 464	ering->rx_pending = common->rx_chns.descs_num;
 465}
 466
 467static void am65_cpsw_get_pauseparam(struct net_device *ndev,
 468				     struct ethtool_pauseparam *pause)
 469{
 470	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 471
 472	phylink_ethtool_get_pauseparam(salve->phylink, pause);
 473}
 474
 475static int am65_cpsw_set_pauseparam(struct net_device *ndev,
 476				    struct ethtool_pauseparam *pause)
 477{
 478	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 479
 480	return phylink_ethtool_set_pauseparam(salve->phylink, pause);
 481}
 482
 483static void am65_cpsw_get_wol(struct net_device *ndev,
 484			      struct ethtool_wolinfo *wol)
 485{
 486	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 487
 488	phylink_ethtool_get_wol(salve->phylink, wol);
 489}
 490
 491static int am65_cpsw_set_wol(struct net_device *ndev,
 492			     struct ethtool_wolinfo *wol)
 493{
 494	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 495
 496	return phylink_ethtool_set_wol(salve->phylink, wol);
 497}
 498
 499static int am65_cpsw_get_link_ksettings(struct net_device *ndev,
 500					struct ethtool_link_ksettings *ecmd)
 501{
 502	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 503
 504	return phylink_ethtool_ksettings_get(salve->phylink, ecmd);
 505}
 506
 507static int
 508am65_cpsw_set_link_ksettings(struct net_device *ndev,
 509			     const struct ethtool_link_ksettings *ecmd)
 510{
 511	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 512
 513	return phylink_ethtool_ksettings_set(salve->phylink, ecmd);
 514}
 515
 516static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata)
 517{
 518	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 519
 520	return phylink_ethtool_get_eee(salve->phylink, edata);
 521}
 522
 523static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata)
 524{
 525	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 526
 527	return phylink_ethtool_set_eee(salve->phylink, edata);
 528}
 529
 530static int am65_cpsw_nway_reset(struct net_device *ndev)
 531{
 532	struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev);
 533
 534	return phylink_ethtool_nway_reset(salve->phylink);
 535}
 536
 537static int am65_cpsw_get_regs_len(struct net_device *ndev)
 538{
 539	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 540	u32 ale_entries, i, regdump_len = 0;
 541
 542	ale_entries = cpsw_ale_get_num_entries(common->ale);
 543	for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) {
 544		if (am65_cpsw_regdump[i].hdr.module_id ==
 545		    AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) {
 546			regdump_len += sizeof(struct am65_cpsw_regdump_hdr);
 547			regdump_len += ale_entries *
 548				       ALE_ENTRY_WORDS * sizeof(u32);
 549			continue;
 550		}
 551		regdump_len += am65_cpsw_regdump[i].hdr.len;
 552	}
 553
 554	return regdump_len;
 555}
 556
 557static void am65_cpsw_get_regs(struct net_device *ndev,
 558			       struct ethtool_regs *regs, void *p)
 559{
 560	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 561	u32 ale_entries, i, j, pos, *reg = p;
 562
 563	/* update CPSW IP version */
 564	regs->version = AM65_CPSW_REGDUMP_VER;
 565	ale_entries = cpsw_ale_get_num_entries(common->ale);
 566
 567	pos = 0;
 568	for (i = 0; i < ARRAY_SIZE(am65_cpsw_regdump); i++) {
 569		reg[pos++] = am65_cpsw_regdump[i].hdr.module_id;
 570
 571		if (am65_cpsw_regdump[i].hdr.module_id ==
 572		    AM65_CPSW_REGDUMP_MOD_CPSW_ALE_TBL) {
 573			u32 ale_tbl_len = ale_entries *
 574					  ALE_ENTRY_WORDS * sizeof(u32) +
 575					  sizeof(struct am65_cpsw_regdump_hdr);
 576			reg[pos++] = ale_tbl_len;
 577			cpsw_ale_dump(common->ale, &reg[pos]);
 578			pos += ale_tbl_len;
 579			continue;
 580		}
 581
 582		reg[pos++] = am65_cpsw_regdump[i].hdr.len;
 583
 584		j = am65_cpsw_regdump[i].start_ofs;
 585		do {
 586			reg[pos++] = j;
 587			reg[pos++] = readl_relaxed(common->ss_base + j);
 588			j += sizeof(u32);
 589		} while (j <= am65_cpsw_regdump[i].end_ofs);
 590	}
 591}
 592
 593static int am65_cpsw_get_sset_count(struct net_device *ndev, int sset)
 594{
 595	switch (sset) {
 596	case ETH_SS_STATS:
 597		return ARRAY_SIZE(am65_host_stats) +
 598		       ARRAY_SIZE(am65_slave_stats);
 599	case ETH_SS_PRIV_FLAGS:
 600		return ARRAY_SIZE(am65_cpsw_ethtool_priv_flags);
 601	default:
 602		return -EOPNOTSUPP;
 603	}
 604}
 605
 606static void am65_cpsw_get_strings(struct net_device *ndev,
 607				  u32 stringset, u8 *data)
 608{
 609	const struct am65_cpsw_ethtool_stat *hw_stats;
 610	u32 i, num_stats;
 611	u8 *p = data;
 612
 613	switch (stringset) {
 614	case ETH_SS_STATS:
 615		num_stats = ARRAY_SIZE(am65_host_stats);
 616		hw_stats = am65_host_stats;
 617		for (i = 0; i < num_stats; i++) {
 618			memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN);
 619			p += ETH_GSTRING_LEN;
 620		}
 621
 622		num_stats = ARRAY_SIZE(am65_slave_stats);
 623		hw_stats = am65_slave_stats;
 624		for (i = 0; i < num_stats; i++) {
 625			memcpy(p, hw_stats[i].desc, ETH_GSTRING_LEN);
 626			p += ETH_GSTRING_LEN;
 627		}
 628		break;
 629	case ETH_SS_PRIV_FLAGS:
 630		num_stats = ARRAY_SIZE(am65_cpsw_ethtool_priv_flags);
 631
 632		for (i = 0; i < num_stats; i++) {
 633			memcpy(p, am65_cpsw_ethtool_priv_flags[i],
 634			       ETH_GSTRING_LEN);
 635			p += ETH_GSTRING_LEN;
 636		}
 637		break;
 638	}
 639}
 640
 641static void am65_cpsw_get_ethtool_stats(struct net_device *ndev,
 642					struct ethtool_stats *stats, u64 *data)
 643{
 644	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 645	const struct am65_cpsw_ethtool_stat *hw_stats;
 646	struct am65_cpsw_host *host_p;
 647	struct am65_cpsw_port *port;
 648	u32 i, num_stats;
 649
 650	host_p = am65_common_get_host(common);
 651	port = am65_ndev_to_port(ndev);
 652	num_stats = ARRAY_SIZE(am65_host_stats);
 653	hw_stats = am65_host_stats;
 654	for (i = 0; i < num_stats; i++)
 655		*data++ = readl_relaxed(host_p->stat_base +
 656					hw_stats[i].offset);
 657
 658	num_stats = ARRAY_SIZE(am65_slave_stats);
 659	hw_stats = am65_slave_stats;
 660	for (i = 0; i < num_stats; i++)
 661		*data++ = readl_relaxed(port->stat_base +
 662					hw_stats[i].offset);
 663}
 664
 665static void am65_cpsw_get_eth_mac_stats(struct net_device *ndev,
 666					struct ethtool_eth_mac_stats *s)
 667{
 668	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
 669	struct am65_cpsw_stats_regs __iomem *stats;
 670
 671	stats = port->stat_base;
 672
 673	if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
 674		return;
 675
 676	s->FramesTransmittedOK = readl_relaxed(&stats->tx_good_frames);
 677	s->SingleCollisionFrames = readl_relaxed(&stats->tx_single_coll_frames);
 678	s->MultipleCollisionFrames = readl_relaxed(&stats->tx_mult_coll_frames);
 679	s->FramesReceivedOK = readl_relaxed(&stats->rx_good_frames);
 680	s->FrameCheckSequenceErrors = readl_relaxed(&stats->rx_crc_errors);
 681	s->AlignmentErrors = readl_relaxed(&stats->rx_align_code_errors);
 682	s->OctetsTransmittedOK = readl_relaxed(&stats->tx_octets);
 683	s->FramesWithDeferredXmissions = readl_relaxed(&stats->tx_deferred_frames);
 684	s->LateCollisions = readl_relaxed(&stats->tx_late_collisions);
 685	s->CarrierSenseErrors = readl_relaxed(&stats->tx_carrier_sense_errors);
 686	s->OctetsReceivedOK = readl_relaxed(&stats->rx_octets);
 687	s->MulticastFramesXmittedOK = readl_relaxed(&stats->tx_multicast_frames);
 688	s->BroadcastFramesXmittedOK = readl_relaxed(&stats->tx_broadcast_frames);
 689	s->MulticastFramesReceivedOK = readl_relaxed(&stats->rx_multicast_frames);
 690	s->BroadcastFramesReceivedOK = readl_relaxed(&stats->rx_broadcast_frames);
 691};
 692
 693static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev,
 694					 struct kernel_ethtool_ts_info *info)
 695{
 696	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 697	unsigned int ptp_filter;
 698
 699	ptp_filter = BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT)	|
 700		     BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC)	|
 701		     BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ)	|
 702		     BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT)	|
 703		     BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC)	|
 704		     BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ)	|
 705		     BIT(HWTSTAMP_FILTER_PTP_V2_EVENT)		|
 706		     BIT(HWTSTAMP_FILTER_PTP_V2_SYNC)		|
 707		     BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ)	|
 708		     BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT)	|
 709		     BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC)	|
 710		     BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ);
 711
 712	if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))
 713		return ethtool_op_get_ts_info(ndev, info);
 714
 715	info->so_timestamping =
 716		SOF_TIMESTAMPING_TX_HARDWARE |
 717		SOF_TIMESTAMPING_TX_SOFTWARE |
 718		SOF_TIMESTAMPING_RX_HARDWARE |
 719		SOF_TIMESTAMPING_RAW_HARDWARE;
 720	info->phc_index = am65_cpts_phc_index(common->cpts);
 721	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
 722	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | ptp_filter;
 723	return 0;
 724}
 725
 726static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)
 727{
 728	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 729	u32 priv_flags = 0;
 730
 731	if (common->pf_p0_rx_ptype_rrobin)
 732		priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN;
 733
 734	return priv_flags;
 735}
 736
 737static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
 738{
 739	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 740	int rrobin;
 741
 742	rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);
 743
 744	if (common->usage_count)
 745		return -EBUSY;
 746
 747	if (common->est_enabled && rrobin) {
 748		netdev_err(ndev,
 749			   "p0-rx-ptype-rrobin flag conflicts with QOS\n");
 750		return -EINVAL;
 751	}
 752
 753	common->pf_p0_rx_ptype_rrobin = rrobin;
 754
 755	return 0;
 756}
 757
 758static void am65_cpsw_port_iet_rx_enable(struct am65_cpsw_port *port, bool enable)
 759{
 760	u32 val;
 761
 762	val = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
 763	if (enable)
 764		val |= AM65_CPSW_PN_CTL_IET_PORT_EN;
 765	else
 766		val &= ~AM65_CPSW_PN_CTL_IET_PORT_EN;
 767
 768	writel(val, port->port_base + AM65_CPSW_PN_REG_CTL);
 769	am65_cpsw_iet_common_enable(port->common);
 770}
 771
 772static void am65_cpsw_port_iet_tx_enable(struct am65_cpsw_port *port, bool enable)
 773{
 774	u32 val;
 775
 776	val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
 777	if (enable)
 778		val |= AM65_CPSW_PN_IET_MAC_PENABLE;
 779	else
 780		val &= ~AM65_CPSW_PN_IET_MAC_PENABLE;
 781
 782	writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
 783}
 784
 785static int am65_cpsw_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)
 786{
 787	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
 788	struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
 789	u32 port_ctrl, iet_ctrl, iet_status;
 790	u32 add_frag_size;
 791
 792	if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
 793		return -EOPNOTSUPP;
 794
 795	mutex_lock(&priv->mm_lock);
 796
 797	iet_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
 798	port_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
 799
 800	state->tx_enabled = !!(iet_ctrl & AM65_CPSW_PN_IET_MAC_PENABLE);
 801	state->pmac_enabled = !!(port_ctrl & AM65_CPSW_PN_CTL_IET_PORT_EN);
 802
 803	iet_status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);
 804
 805	if (iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY)
 806		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
 807	else if (iet_status & AM65_CPSW_PN_MAC_VERIFIED)
 808		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
 809	else if (iet_status & AM65_CPSW_PN_MAC_VERIFY_FAIL)
 810		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
 811	else
 812		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;
 813
 814	add_frag_size = AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(iet_ctrl);
 815	state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size);
 816
 817	/* Errata i2208: RX min fragment size cannot be less than 124 */
 818	state->rx_min_frag_size = 124;
 819
 820	/* FPE active if common tx_enabled and verification success or disabled (forced) */
 821	state->tx_active = state->tx_enabled &&
 822			   (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
 823			    state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED);
 824	state->verify_enabled = !(iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY);
 825
 826	state->verify_time = port->qos.iet.verify_time_ms;
 827
 828	/* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime
 829	 * variable has a range between 1 and 128 ms inclusive. Limit to that.
 830	 */
 831	state->max_verify_time = 128;
 832
 833	mutex_unlock(&priv->mm_lock);
 834
 835	return 0;
 836}
 837
 838static int am65_cpsw_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
 839			    struct netlink_ext_ack *extack)
 840{
 841	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
 842	struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
 843	struct am65_cpsw_iet *iet = &port->qos.iet;
 844	u32 val, add_frag_size;
 845	int err;
 846
 847	if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
 848		return -EOPNOTSUPP;
 849
 850	err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size, &add_frag_size, extack);
 851	if (err)
 852		return err;
 853
 854	mutex_lock(&priv->mm_lock);
 855
 856	if (cfg->pmac_enabled) {
 857		/* change TX & RX FIFO MAX_BLKS as per TRM recommendation */
 858		if (!iet->original_max_blks)
 859			iet->original_max_blks = readl(port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
 860
 861		writel(AM65_CPSW_PN_TX_RX_MAX_BLKS_IET,
 862		       port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
 863	} else if (iet->original_max_blks) {
 864		/* restore RX & TX FIFO MAX_BLKS */
 865		writel(iet->original_max_blks,
 866		       port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
 867	}
 868
 869	am65_cpsw_port_iet_rx_enable(port, cfg->pmac_enabled);
 870	am65_cpsw_port_iet_tx_enable(port, cfg->tx_enabled);
 871
 872	val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
 873	if (cfg->verify_enabled) {
 874		val &= ~AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
 875		/* Reset Verify state machine. Verification won't start here.
 876		 * Verification will be done once link-up.
 877		 */
 878		val |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
 879	} else {
 880		val |= AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
 881		/* Clear LINKFAIL to allow verify/response packets */
 882		val &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
 883	}
 884
 885	val &= ~AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK;
 886	val |= AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(add_frag_size);
 887	writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
 888
 889	/* verify_timeout_count can only be set at valid link */
 890	port->qos.iet.verify_time_ms = cfg->verify_time;
 891
 892	/* enable/disable preemption based on link status */
 893	am65_cpsw_iet_commit_preemptible_tcs(port);
 894
 895	mutex_unlock(&priv->mm_lock);
 896
 897	return 0;
 898}
 899
 900static void am65_cpsw_get_mm_stats(struct net_device *ndev,
 901				   struct ethtool_mm_stats *s)
 902{
 903	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
 904	void __iomem *base = port->stat_base;
 905
 906	s->MACMergeFrameAssOkCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK);
 907	s->MACMergeFrameAssErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR);
 908	s->MACMergeFrameSmdErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_SMD_ERROR);
 909	/* CPSW Functional Spec states:
 910	 * "The IET stat aMACMergeFragCountRx is derived by adding the
 911	 *  Receive Assembly Error count to this value. i.e. AM65_CPSW_STATN_IET_RX_FRAG"
 912	 */
 913	s->MACMergeFragCountRx = readl(base + AM65_CPSW_STATN_IET_RX_FRAG) + s->MACMergeFrameAssErrorCount;
 914	s->MACMergeFragCountTx = readl(base + AM65_CPSW_STATN_IET_TX_FRAG);
 915	s->MACMergeHoldCount = readl(base + AM65_CPSW_STATN_IET_TX_HOLD);
 916}
 917
 918static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue,
 919					    struct ethtool_coalesce *coal)
 920{
 921	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 922	struct am65_cpsw_rx_flow *rx_flow;
 923	struct am65_cpsw_tx_chn *tx_chn;
 924
 925	if (queue >= AM65_CPSW_MAX_QUEUES)
 926		return -EINVAL;
 927
 928	tx_chn = &common->tx_chns[queue];
 929	coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
 930
 931	rx_flow = &common->rx_chns.flows[queue];
 932	coal->rx_coalesce_usecs = rx_flow->rx_pace_timeout / 1000;
 933
 934	return 0;
 935}
 936
 937static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
 938				  struct kernel_ethtool_coalesce *kernel_coal,
 939				  struct netlink_ext_ack *extack)
 940{
 941	return am65_cpsw_get_per_queue_coalesce(ndev, 0, coal);
 942}
 943
 944static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
 945					    struct ethtool_coalesce *coal)
 946{
 947	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
 948	struct am65_cpsw_rx_flow *rx_flow;
 949	struct am65_cpsw_tx_chn *tx_chn;
 950
 951	if (queue >= AM65_CPSW_MAX_QUEUES)
 952		return -EINVAL;
 953
 954	tx_chn = &common->tx_chns[queue];
 955	if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20)
 956		return -EINVAL;
 957
 958	tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
 959
 960	rx_flow = &common->rx_chns.flows[queue];
 961	if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20)
 962		return -EINVAL;
 963
 964	rx_flow->rx_pace_timeout = coal->rx_coalesce_usecs * 1000;
 965
 966	return 0;
 967}
 968
 969static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
 970				  struct kernel_ethtool_coalesce *kernel_coal,
 971				  struct netlink_ext_ack *extack)
 972{
 973	return am65_cpsw_set_per_queue_coalesce(ndev, 0, coal);
 974}
 975
 976const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
 977	.begin			= am65_cpsw_ethtool_op_begin,
 978	.complete		= am65_cpsw_ethtool_op_complete,
 979	.get_drvinfo		= am65_cpsw_get_drvinfo,
 980	.get_msglevel		= am65_cpsw_get_msglevel,
 981	.set_msglevel		= am65_cpsw_set_msglevel,
 982	.get_channels		= am65_cpsw_get_channels,
 983	.set_channels		= am65_cpsw_set_channels,
 984	.get_ringparam		= am65_cpsw_get_ringparam,
 985	.get_regs_len		= am65_cpsw_get_regs_len,
 986	.get_regs		= am65_cpsw_get_regs,
 987	.get_sset_count		= am65_cpsw_get_sset_count,
 988	.get_strings		= am65_cpsw_get_strings,
 989	.get_ethtool_stats	= am65_cpsw_get_ethtool_stats,
 990	.get_eth_mac_stats	= am65_cpsw_get_eth_mac_stats,
 991	.get_ts_info		= am65_cpsw_get_ethtool_ts_info,
 992	.get_priv_flags		= am65_cpsw_get_ethtool_priv_flags,
 993	.set_priv_flags		= am65_cpsw_set_ethtool_priv_flags,
 994	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
 995	.get_coalesce           = am65_cpsw_get_coalesce,
 996	.set_coalesce           = am65_cpsw_set_coalesce,
 997	.get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce,
 998	.set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce,
 999
1000	.get_link		= ethtool_op_get_link,
1001	.get_link_ksettings	= am65_cpsw_get_link_ksettings,
1002	.set_link_ksettings	= am65_cpsw_set_link_ksettings,
1003	.get_pauseparam		= am65_cpsw_get_pauseparam,
1004	.set_pauseparam		= am65_cpsw_set_pauseparam,
1005	.get_wol		= am65_cpsw_get_wol,
1006	.set_wol		= am65_cpsw_set_wol,
1007	.get_eee		= am65_cpsw_get_eee,
1008	.set_eee		= am65_cpsw_set_eee,
1009	.nway_reset		= am65_cpsw_nway_reset,
1010	.get_mm			= am65_cpsw_get_mm,
1011	.set_mm			= am65_cpsw_set_mm,
1012	.get_mm_stats		= am65_cpsw_get_mm_stats,
1013};
~/ Read-only file preview.