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, ®[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