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/phylink.h>
24 struct ipqesstool_stats
{
25 uint8_t string
[ETH_GSTRING_LEN
];
29 #define IPQESS_STAT(m) offsetof(struct ipqesstool_statistics, m)
30 #define DRVINFO_LEN 32
32 static const struct ipqesstool_stats ipqess_stats
[] = {
33 {"tx_q0_pkt", IPQESS_STAT(tx_q0_pkt
)},
34 {"tx_q1_pkt", IPQESS_STAT(tx_q1_pkt
)},
35 {"tx_q2_pkt", IPQESS_STAT(tx_q2_pkt
)},
36 {"tx_q3_pkt", IPQESS_STAT(tx_q3_pkt
)},
37 {"tx_q4_pkt", IPQESS_STAT(tx_q4_pkt
)},
38 {"tx_q5_pkt", IPQESS_STAT(tx_q5_pkt
)},
39 {"tx_q6_pkt", IPQESS_STAT(tx_q6_pkt
)},
40 {"tx_q7_pkt", IPQESS_STAT(tx_q7_pkt
)},
41 {"tx_q8_pkt", IPQESS_STAT(tx_q8_pkt
)},
42 {"tx_q9_pkt", IPQESS_STAT(tx_q9_pkt
)},
43 {"tx_q10_pkt", IPQESS_STAT(tx_q10_pkt
)},
44 {"tx_q11_pkt", IPQESS_STAT(tx_q11_pkt
)},
45 {"tx_q12_pkt", IPQESS_STAT(tx_q12_pkt
)},
46 {"tx_q13_pkt", IPQESS_STAT(tx_q13_pkt
)},
47 {"tx_q14_pkt", IPQESS_STAT(tx_q14_pkt
)},
48 {"tx_q15_pkt", IPQESS_STAT(tx_q15_pkt
)},
49 {"tx_q0_byte", IPQESS_STAT(tx_q0_byte
)},
50 {"tx_q1_byte", IPQESS_STAT(tx_q1_byte
)},
51 {"tx_q2_byte", IPQESS_STAT(tx_q2_byte
)},
52 {"tx_q3_byte", IPQESS_STAT(tx_q3_byte
)},
53 {"tx_q4_byte", IPQESS_STAT(tx_q4_byte
)},
54 {"tx_q5_byte", IPQESS_STAT(tx_q5_byte
)},
55 {"tx_q6_byte", IPQESS_STAT(tx_q6_byte
)},
56 {"tx_q7_byte", IPQESS_STAT(tx_q7_byte
)},
57 {"tx_q8_byte", IPQESS_STAT(tx_q8_byte
)},
58 {"tx_q9_byte", IPQESS_STAT(tx_q9_byte
)},
59 {"tx_q10_byte", IPQESS_STAT(tx_q10_byte
)},
60 {"tx_q11_byte", IPQESS_STAT(tx_q11_byte
)},
61 {"tx_q12_byte", IPQESS_STAT(tx_q12_byte
)},
62 {"tx_q13_byte", IPQESS_STAT(tx_q13_byte
)},
63 {"tx_q14_byte", IPQESS_STAT(tx_q14_byte
)},
64 {"tx_q15_byte", IPQESS_STAT(tx_q15_byte
)},
65 {"rx_q0_pkt", IPQESS_STAT(rx_q0_pkt
)},
66 {"rx_q1_pkt", IPQESS_STAT(rx_q1_pkt
)},
67 {"rx_q2_pkt", IPQESS_STAT(rx_q2_pkt
)},
68 {"rx_q3_pkt", IPQESS_STAT(rx_q3_pkt
)},
69 {"rx_q4_pkt", IPQESS_STAT(rx_q4_pkt
)},
70 {"rx_q5_pkt", IPQESS_STAT(rx_q5_pkt
)},
71 {"rx_q6_pkt", IPQESS_STAT(rx_q6_pkt
)},
72 {"rx_q7_pkt", IPQESS_STAT(rx_q7_pkt
)},
73 {"rx_q0_byte", IPQESS_STAT(rx_q0_byte
)},
74 {"rx_q1_byte", IPQESS_STAT(rx_q1_byte
)},
75 {"rx_q2_byte", IPQESS_STAT(rx_q2_byte
)},
76 {"rx_q3_byte", IPQESS_STAT(rx_q3_byte
)},
77 {"rx_q4_byte", IPQESS_STAT(rx_q4_byte
)},
78 {"rx_q5_byte", IPQESS_STAT(rx_q5_byte
)},
79 {"rx_q6_byte", IPQESS_STAT(rx_q6_byte
)},
80 {"rx_q7_byte", IPQESS_STAT(rx_q7_byte
)},
81 {"tx_desc_error", IPQESS_STAT(tx_desc_error
)},
84 static int ipqess_get_strset_count(struct net_device
*netdev
, int sset
)
88 return ARRAY_SIZE(ipqess_stats
);
90 netdev_dbg(netdev
, "%s: Invalid string set", __func__
);
95 static void ipqess_get_strings(struct net_device
*netdev
, uint32_t stringset
,
103 for (i
= 0; i
< ARRAY_SIZE(ipqess_stats
); i
++) {
104 memcpy(p
, ipqess_stats
[i
].string
,
105 min((size_t)ETH_GSTRING_LEN
,
106 strlen(ipqess_stats
[i
].string
) + 1));
107 p
+= ETH_GSTRING_LEN
;
113 static void ipqess_get_ethtool_stats(struct net_device
*netdev
,
114 struct ethtool_stats
*stats
,
117 struct ipqess
*ess
= netdev_priv(netdev
);
118 u32
*essstats
= (u32
*)&ess
->ipqessstats
;
121 spin_lock(&ess
->stats_lock
);
123 ipqess_update_hw_stats(ess
);
125 for (i
= 0; i
< ARRAY_SIZE(ipqess_stats
); i
++)
126 data
[i
] = *(u32
*)(essstats
+ (ipqess_stats
[i
].offset
/ sizeof(u32
)));
128 spin_unlock(&ess
->stats_lock
);
131 static void ipqess_get_drvinfo(struct net_device
*dev
,
132 struct ethtool_drvinfo
*info
)
134 strlcpy(info
->driver
, "qca_ipqess", DRVINFO_LEN
);
135 strlcpy(info
->bus_info
, "axi", ETHTOOL_BUSINFO_LEN
);
138 static int ipqess_get_settings(struct net_device
*netdev
,
139 struct ethtool_link_ksettings
*cmd
)
141 struct ipqess
*ess
= netdev_priv(netdev
);
143 return phylink_ethtool_ksettings_get(ess
->phylink
, cmd
);
146 static int ipqess_set_settings(struct net_device
*netdev
,
147 const struct ethtool_link_ksettings
*cmd
)
149 struct ipqess
*ess
= netdev_priv(netdev
);
151 return phylink_ethtool_ksettings_set(ess
->phylink
, cmd
);
154 static void ipqess_get_ringparam(struct net_device
*netdev
,
155 struct ethtool_ringparam
*ring
)
157 ring
->tx_max_pending
= IPQESS_TX_RING_SIZE
;
158 ring
->rx_max_pending
= IPQESS_RX_RING_SIZE
;
161 static const struct ethtool_ops ipqesstool_ops
= {
162 .get_drvinfo
= &ipqess_get_drvinfo
,
163 .get_link
= ðtool_op_get_link
,
164 .get_link_ksettings
= &ipqess_get_settings
,
165 .set_link_ksettings
= &ipqess_set_settings
,
166 .get_strings
= &ipqess_get_strings
,
167 .get_sset_count
= &ipqess_get_strset_count
,
168 .get_ethtool_stats
= &ipqess_get_ethtool_stats
,
169 .get_ringparam
= ipqess_get_ringparam
,
172 void ipqess_set_ethtool_ops(struct net_device
*netdev
)
174 netdev
->ethtool_ops
= &ipqesstool_ops
;