brintos

brintos / linux-shallow public Read only

0
0
Text · 30.8 KiB · 9032444 Raw
1011 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver ethtool ops3 *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 0x119 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 header35 *36 * @module_id: CPSW module ID37 * @len: CPSW module registers space length in u3238 */39 40struct am65_cpsw_regdump_hdr {41	u32 module_id;42	u32 len;43};44 45/**46 * struct am65_cpsw_regdump_item - regdump module description47 *48 * @hdr: CPSW module header49 * @start_ofs: CPSW module registers start addr50 * @end_ofs: CPSW module registers end addr51 *52 * Registers dump provided in the format:53 *  u32 : module ID54 *  u32 : dump length55 *  u32[..len]: registers values56 */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 when445	 * 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 void455am65_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 int508am65_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_v2_filter;698 699	ptp_v2_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 709	if (!IS_ENABLED(CONFIG_TI_K3_AM65_CPTS))710		return ethtool_op_get_ts_info(ndev, info);711 712	info->so_timestamping =713		SOF_TIMESTAMPING_TX_HARDWARE |714		SOF_TIMESTAMPING_TX_SOFTWARE |715		SOF_TIMESTAMPING_RX_HARDWARE |716		SOF_TIMESTAMPING_RAW_HARDWARE;717	info->phc_index = am65_cpts_phc_index(common->cpts);718	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);719	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | ptp_v2_filter;720	return 0;721}722 723static u32 am65_cpsw_get_ethtool_priv_flags(struct net_device *ndev)724{725	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);726	u32 priv_flags = 0;727 728	if (common->pf_p0_rx_ptype_rrobin)729		priv_flags |= AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN;730 731	return priv_flags;732}733 734static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)735{736	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);737	int rrobin;738 739	rrobin = !!(flags & AM65_CPSW_PRIV_P0_RX_PTYPE_RROBIN);740 741	if (common->usage_count)742		return -EBUSY;743 744	if (common->est_enabled && rrobin) {745		netdev_err(ndev,746			   "p0-rx-ptype-rrobin flag conflicts with QOS\n");747		return -EINVAL;748	}749 750	common->pf_p0_rx_ptype_rrobin = rrobin;751 752	return 0;753}754 755static void am65_cpsw_port_iet_rx_enable(struct am65_cpsw_port *port, bool enable)756{757	u32 val;758 759	val = readl(port->port_base + AM65_CPSW_PN_REG_CTL);760	if (enable)761		val |= AM65_CPSW_PN_CTL_IET_PORT_EN;762	else763		val &= ~AM65_CPSW_PN_CTL_IET_PORT_EN;764 765	writel(val, port->port_base + AM65_CPSW_PN_REG_CTL);766	am65_cpsw_iet_common_enable(port->common);767}768 769static void am65_cpsw_port_iet_tx_enable(struct am65_cpsw_port *port, bool enable)770{771	u32 val;772 773	val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);774	if (enable)775		val |= AM65_CPSW_PN_IET_MAC_PENABLE;776	else777		val &= ~AM65_CPSW_PN_IET_MAC_PENABLE;778 779	writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);780}781 782static int am65_cpsw_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)783{784	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);785	struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);786	u32 port_ctrl, iet_ctrl, iet_status;787	u32 add_frag_size;788 789	if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))790		return -EOPNOTSUPP;791 792	mutex_lock(&priv->mm_lock);793 794	iet_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);795	port_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_CTL);796 797	state->tx_enabled = !!(iet_ctrl & AM65_CPSW_PN_IET_MAC_PENABLE);798	state->pmac_enabled = !!(port_ctrl & AM65_CPSW_PN_CTL_IET_PORT_EN);799 800	iet_status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);801 802	if (iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY)803		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;804	else if (iet_status & AM65_CPSW_PN_MAC_VERIFIED)805		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;806	else if (iet_status & AM65_CPSW_PN_MAC_VERIFY_FAIL)807		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED;808	else809		state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;810 811	add_frag_size = AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(iet_ctrl);812	state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size);813 814	/* Errata i2208: RX min fragment size cannot be less than 124 */815	state->rx_min_frag_size = 124;816 817	/* FPE active if common tx_enabled and verification success or disabled (forced) */818	state->tx_active = state->tx_enabled &&819			   (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||820			    state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED);821	state->verify_enabled = !(iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY);822 823	state->verify_time = port->qos.iet.verify_time_ms;824 825	/* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime826	 * variable has a range between 1 and 128 ms inclusive. Limit to that.827	 */828	state->max_verify_time = 128;829 830	mutex_unlock(&priv->mm_lock);831 832	return 0;833}834 835static int am65_cpsw_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,836			    struct netlink_ext_ack *extack)837{838	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);839	struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);840	struct am65_cpsw_iet *iet = &port->qos.iet;841	u32 val, add_frag_size;842	int err;843 844	if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))845		return -EOPNOTSUPP;846 847	err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size, &add_frag_size, extack);848	if (err)849		return err;850 851	mutex_lock(&priv->mm_lock);852 853	if (cfg->pmac_enabled) {854		/* change TX & RX FIFO MAX_BLKS as per TRM recommendation */855		if (!iet->original_max_blks)856			iet->original_max_blks = readl(port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);857 858		writel(AM65_CPSW_PN_TX_RX_MAX_BLKS_IET,859		       port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);860	} else if (iet->original_max_blks) {861		/* restore RX & TX FIFO MAX_BLKS */862		writel(iet->original_max_blks,863		       port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);864	}865 866	am65_cpsw_port_iet_rx_enable(port, cfg->pmac_enabled);867	am65_cpsw_port_iet_tx_enable(port, cfg->tx_enabled);868 869	val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);870	if (cfg->verify_enabled) {871		val &= ~AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;872		/* Reset Verify state machine. Verification won't start here.873		 * Verification will be done once link-up.874		 */875		val |= AM65_CPSW_PN_IET_MAC_LINKFAIL;876	} else {877		val |= AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;878		/* Clear LINKFAIL to allow verify/response packets */879		val &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;880	}881 882	val &= ~AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK;883	val |= AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(add_frag_size);884	writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);885 886	/* verify_timeout_count can only be set at valid link */887	port->qos.iet.verify_time_ms = cfg->verify_time;888 889	/* enable/disable preemption based on link status */890	am65_cpsw_iet_commit_preemptible_tcs(port);891 892	mutex_unlock(&priv->mm_lock);893 894	return 0;895}896 897static void am65_cpsw_get_mm_stats(struct net_device *ndev,898				   struct ethtool_mm_stats *s)899{900	struct am65_cpsw_port *port = am65_ndev_to_port(ndev);901	void __iomem *base = port->stat_base;902 903	s->MACMergeFrameAssOkCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK);904	s->MACMergeFrameAssErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR);905	s->MACMergeFrameSmdErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_SMD_ERROR);906	/* CPSW Functional Spec states:907	 * "The IET stat aMACMergeFragCountRx is derived by adding the908	 *  Receive Assembly Error count to this value. i.e. AM65_CPSW_STATN_IET_RX_FRAG"909	 */910	s->MACMergeFragCountRx = readl(base + AM65_CPSW_STATN_IET_RX_FRAG) + s->MACMergeFrameAssErrorCount;911	s->MACMergeFragCountTx = readl(base + AM65_CPSW_STATN_IET_TX_FRAG);912	s->MACMergeHoldCount = readl(base + AM65_CPSW_STATN_IET_TX_HOLD);913}914 915static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue,916					    struct ethtool_coalesce *coal)917{918	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);919	struct am65_cpsw_rx_flow *rx_flow;920	struct am65_cpsw_tx_chn *tx_chn;921 922	if (queue >= AM65_CPSW_MAX_QUEUES)923		return -EINVAL;924 925	tx_chn = &common->tx_chns[queue];926	coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;927 928	rx_flow = &common->rx_chns.flows[queue];929	coal->rx_coalesce_usecs = rx_flow->rx_pace_timeout / 1000;930 931	return 0;932}933 934static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,935				  struct kernel_ethtool_coalesce *kernel_coal,936				  struct netlink_ext_ack *extack)937{938	return am65_cpsw_get_per_queue_coalesce(ndev, 0, coal);939}940 941static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue,942					    struct ethtool_coalesce *coal)943{944	struct am65_cpsw_common *common = am65_ndev_to_common(ndev);945	struct am65_cpsw_rx_flow *rx_flow;946	struct am65_cpsw_tx_chn *tx_chn;947 948	if (queue >= AM65_CPSW_MAX_QUEUES)949		return -EINVAL;950 951	tx_chn = &common->tx_chns[queue];952	if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20)953		return -EINVAL;954 955	tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;956 957	rx_flow = &common->rx_chns.flows[queue];958	if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20)959		return -EINVAL;960 961	rx_flow->rx_pace_timeout = coal->rx_coalesce_usecs * 1000;962 963	return 0;964}965 966static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,967				  struct kernel_ethtool_coalesce *kernel_coal,968				  struct netlink_ext_ack *extack)969{970	return am65_cpsw_set_per_queue_coalesce(ndev, 0, coal);971}972 973const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {974	.begin			= am65_cpsw_ethtool_op_begin,975	.complete		= am65_cpsw_ethtool_op_complete,976	.get_drvinfo		= am65_cpsw_get_drvinfo,977	.get_msglevel		= am65_cpsw_get_msglevel,978	.set_msglevel		= am65_cpsw_set_msglevel,979	.get_channels		= am65_cpsw_get_channels,980	.set_channels		= am65_cpsw_set_channels,981	.get_ringparam		= am65_cpsw_get_ringparam,982	.get_regs_len		= am65_cpsw_get_regs_len,983	.get_regs		= am65_cpsw_get_regs,984	.get_sset_count		= am65_cpsw_get_sset_count,985	.get_strings		= am65_cpsw_get_strings,986	.get_ethtool_stats	= am65_cpsw_get_ethtool_stats,987	.get_eth_mac_stats	= am65_cpsw_get_eth_mac_stats,988	.get_ts_info		= am65_cpsw_get_ethtool_ts_info,989	.get_priv_flags		= am65_cpsw_get_ethtool_priv_flags,990	.set_priv_flags		= am65_cpsw_set_ethtool_priv_flags,991	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,992	.get_coalesce           = am65_cpsw_get_coalesce,993	.set_coalesce           = am65_cpsw_set_coalesce,994	.get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce,995	.set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce,996 997	.get_link		= ethtool_op_get_link,998	.get_link_ksettings	= am65_cpsw_get_link_ksettings,999	.set_link_ksettings	= am65_cpsw_set_link_ksettings,1000	.get_pauseparam		= am65_cpsw_get_pauseparam,1001	.set_pauseparam		= am65_cpsw_set_pauseparam,1002	.get_wol		= am65_cpsw_get_wol,1003	.set_wol		= am65_cpsw_set_wol,1004	.get_eee		= am65_cpsw_get_eee,1005	.set_eee		= am65_cpsw_set_eee,1006	.nway_reset		= am65_cpsw_nway_reset,1007	.get_mm			= am65_cpsw_get_mm,1008	.set_mm			= am65_cpsw_set_mm,1009	.get_mm_stats		= am65_cpsw_get_mm_stats,1010};1011