1 // SPDX-License-Identifier: (GPL-2.0 OR ISC)
2 /* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2017 - 2018, John Crispin <john@phrozen.org>
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/ethtool.h>
18 #include <linux/netdevice.h>
19 #include <linux/string.h>
20 #include <linux/phy.h>
23 struct ipqesstool_stats
{
24 uint8_t string
[ETH_GSTRING_LEN
];
28 #define IPQESS_STAT(m) offsetof(struct ipqesstool_statistics, m)
29 #define DRVINFO_LEN 32
31 static const struct ipqesstool_stats ipqess_stats
[] = {
32 {"tx_q0_pkt", IPQESS_STAT(tx_q0_pkt
)},
33 {"tx_q1_pkt", IPQESS_STAT(tx_q1_pkt
)},
34 {"tx_q2_pkt", IPQESS_STAT(tx_q2_pkt
)},
35 {"tx_q3_pkt", IPQESS_STAT(tx_q3_pkt
)},
36 {"tx_q4_pkt", IPQESS_STAT(tx_q4_pkt
)},
37 {"tx_q5_pkt", IPQESS_STAT(tx_q5_pkt
)},
38 {"tx_q6_pkt", IPQESS_STAT(tx_q6_pkt
)},
39 {"tx_q7_pkt", IPQESS_STAT(tx_q7_pkt
)},
40 {"tx_q8_pkt", IPQESS_STAT(tx_q8_pkt
)},
41 {"tx_q9_pkt", IPQESS_STAT(tx_q9_pkt
)},
42 {"tx_q10_pkt", IPQESS_STAT(tx_q10_pkt
)},
43 {"tx_q11_pkt", IPQESS_STAT(tx_q11_pkt
)},
44 {"tx_q12_pkt", IPQESS_STAT(tx_q12_pkt
)},
45 {"tx_q13_pkt", IPQESS_STAT(tx_q13_pkt
)},
46 {"tx_q14_pkt", IPQESS_STAT(tx_q14_pkt
)},
47 {"tx_q15_pkt", IPQESS_STAT(tx_q15_pkt
)},
48 {"tx_q0_byte", IPQESS_STAT(tx_q0_byte
)},
49 {"tx_q1_byte", IPQESS_STAT(tx_q1_byte
)},
50 {"tx_q2_byte", IPQESS_STAT(tx_q2_byte
)},
51 {"tx_q3_byte", IPQESS_STAT(tx_q3_byte
)},
52 {"tx_q4_byte", IPQESS_STAT(tx_q4_byte
)},
53 {"tx_q5_byte", IPQESS_STAT(tx_q5_byte
)},
54 {"tx_q6_byte", IPQESS_STAT(tx_q6_byte
)},
55 {"tx_q7_byte", IPQESS_STAT(tx_q7_byte
)},
56 {"tx_q8_byte", IPQESS_STAT(tx_q8_byte
)},
57 {"tx_q9_byte", IPQESS_STAT(tx_q9_byte
)},
58 {"tx_q10_byte", IPQESS_STAT(tx_q10_byte
)},
59 {"tx_q11_byte", IPQESS_STAT(tx_q11_byte
)},
60 {"tx_q12_byte", IPQESS_STAT(tx_q12_byte
)},
61 {"tx_q13_byte", IPQESS_STAT(tx_q13_byte
)},
62 {"tx_q14_byte", IPQESS_STAT(tx_q14_byte
)},
63 {"tx_q15_byte", IPQESS_STAT(tx_q15_byte
)},
64 {"rx_q0_pkt", IPQESS_STAT(rx_q0_pkt
)},
65 {"rx_q1_pkt", IPQESS_STAT(rx_q1_pkt
)},
66 {"rx_q2_pkt", IPQESS_STAT(rx_q2_pkt
)},
67 {"rx_q3_pkt", IPQESS_STAT(rx_q3_pkt
)},
68 {"rx_q4_pkt", IPQESS_STAT(rx_q4_pkt
)},
69 {"rx_q5_pkt", IPQESS_STAT(rx_q5_pkt
)},
70 {"rx_q6_pkt", IPQESS_STAT(rx_q6_pkt
)},
71 {"rx_q7_pkt", IPQESS_STAT(rx_q7_pkt
)},
72 {"rx_q0_byte", IPQESS_STAT(rx_q0_byte
)},
73 {"rx_q1_byte", IPQESS_STAT(rx_q1_byte
)},
74 {"rx_q2_byte", IPQESS_STAT(rx_q2_byte
)},
75 {"rx_q3_byte", IPQESS_STAT(rx_q3_byte
)},
76 {"rx_q4_byte", IPQESS_STAT(rx_q4_byte
)},
77 {"rx_q5_byte", IPQESS_STAT(rx_q5_byte
)},
78 {"rx_q6_byte", IPQESS_STAT(rx_q6_byte
)},
79 {"rx_q7_byte", IPQESS_STAT(rx_q7_byte
)},
80 {"tx_desc_error", IPQESS_STAT(tx_desc_error
)},
83 static int ipqess_get_strset_count(struct net_device
*netdev
, int sset
)
87 return ARRAY_SIZE(ipqess_stats
);
89 netdev_dbg(netdev
, "%s: Invalid string set", __func__
);
94 static void ipqess_get_strings(struct net_device
*netdev
, uint32_t stringset
,
102 for (i
= 0; i
< ARRAY_SIZE(ipqess_stats
); i
++) {
103 memcpy(p
, ipqess_stats
[i
].string
,
104 min((size_t)ETH_GSTRING_LEN
,
105 strlen(ipqess_stats
[i
].string
) + 1));
106 p
+= ETH_GSTRING_LEN
;
112 static void ipqess_get_drvinfo(struct net_device
*dev
,
113 struct ethtool_drvinfo
*info
)
115 strlcpy(info
->driver
, "qca_ipqess", DRVINFO_LEN
);
116 strlcpy(info
->bus_info
, "axi", ETHTOOL_BUSINFO_LEN
);
119 static int ipqess_get_settings(struct net_device
*netdev
,
120 struct ethtool_cmd
*ecmd
)
122 struct phy_device
*phydev
= NULL
;
125 phydev
= netdev
->phydev
;
127 ecmd
->advertising
= phydev
->advertising
;
128 ecmd
->autoneg
= phydev
->autoneg
;
129 ecmd
->speed
= phydev
->speed
;
130 ecmd
->duplex
= phydev
->duplex
;
131 ecmd
->phy_address
= phydev
->mdio
.addr
;
133 phyreg
= (uint16_t)phy_read(netdev
->phydev
, MII_LPA
);
134 if (phyreg
& LPA_10HALF
)
135 ecmd
->lp_advertising
|= ADVERTISED_10baseT_Half
;
137 if (phyreg
& LPA_10FULL
)
138 ecmd
->lp_advertising
|= ADVERTISED_10baseT_Full
;
140 if (phyreg
& LPA_100HALF
)
141 ecmd
->lp_advertising
|= ADVERTISED_100baseT_Half
;
143 if (phyreg
& LPA_100FULL
)
144 ecmd
->lp_advertising
|= ADVERTISED_100baseT_Full
;
146 phyreg
= (uint16_t)phy_read(netdev
->phydev
, MII_STAT1000
);
147 if (phyreg
& LPA_1000HALF
)
148 ecmd
->lp_advertising
|= ADVERTISED_1000baseT_Half
;
150 if (phyreg
& LPA_1000FULL
)
151 ecmd
->lp_advertising
|= ADVERTISED_1000baseT_Full
;
156 static int ipqess_set_settings(struct net_device
*netdev
,
157 struct ethtool_cmd
*ecmd
)
159 struct phy_device
*phydev
= NULL
;
161 phydev
= netdev
->phydev
;
162 phydev
->advertising
= ecmd
->advertising
;
163 phydev
->autoneg
= ecmd
->autoneg
;
164 phydev
->speed
= ethtool_cmd_speed(ecmd
);
165 phydev
->duplex
= ecmd
->duplex
;
167 genphy_config_aneg(phydev
);
172 static void ipqess_get_ringparam(struct net_device
*netdev
,
173 struct ethtool_ringparam
*ring
)
175 ring
->tx_max_pending
= IPQESS_TX_RING_SIZE
;
176 ring
->rx_max_pending
= IPQESS_RX_RING_SIZE
;
179 static const struct ethtool_ops ipqesstool_ops
= {
180 .get_drvinfo
= &ipqess_get_drvinfo
,
181 .get_link
= ðtool_op_get_link
,
182 .get_settings
= &ipqess_get_settings
,
183 .set_settings
= &ipqess_set_settings
,
184 .get_strings
= &ipqess_get_strings
,
185 .get_sset_count
= &ipqess_get_strset_count
,
186 .get_ringparam
= ipqess_get_ringparam
,
189 void ipqess_set_ethtool_ops(struct net_device
*netdev
)
191 netdev
->ethtool_ops
= &ipqesstool_ops
;