ipq40xx: add IPQESS ethernet driver
[openwrt/staging/jow.git] / target / linux / ipq40xx / files / drivers / net / ethernet / qualcomm / ipqess / ipqess_ethtool.c
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>
4 *
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.
15 */
16
17 #include <linux/ethtool.h>
18 #include <linux/netdevice.h>
19 #include <linux/string.h>
20 #include <linux/phylink.h>
21
22 #include "ipqess.h"
23
24 struct ipqesstool_stats {
25 uint8_t string[ETH_GSTRING_LEN];
26 uint32_t offset;
27 };
28
29 #define IPQESS_STAT(m) offsetof(struct ipqesstool_statistics, m)
30 #define DRVINFO_LEN 32
31
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)},
82 };
83
84 static int ipqess_get_strset_count(struct net_device *netdev, int sset)
85 {
86 switch (sset) {
87 case ETH_SS_STATS:
88 return ARRAY_SIZE(ipqess_stats);
89 default:
90 netdev_dbg(netdev, "%s: Invalid string set", __func__);
91 return -EOPNOTSUPP;
92 }
93 }
94
95 static void ipqess_get_strings(struct net_device *netdev, uint32_t stringset,
96 uint8_t *data)
97 {
98 uint8_t *p = data;
99 uint32_t i;
100
101 switch (stringset) {
102 case ETH_SS_STATS:
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;
108 }
109 break;
110 }
111 }
112
113 static void ipqess_get_ethtool_stats(struct net_device *netdev,
114 struct ethtool_stats *stats,
115 uint64_t *data)
116 {
117 struct ipqess *ess = netdev_priv(netdev);
118 u32 *essstats = (u32 *)&ess->ipqessstats;
119 int i;
120
121 spin_lock(&ess->stats_lock);
122
123 ipqess_update_hw_stats(ess);
124
125 for (i = 0; i < ARRAY_SIZE(ipqess_stats); i++)
126 data[i] = *(u32 *)(essstats + (ipqess_stats[i].offset / sizeof(u32)));
127
128 spin_unlock(&ess->stats_lock);
129 }
130
131 static void ipqess_get_drvinfo(struct net_device *dev,
132 struct ethtool_drvinfo *info)
133 {
134 strlcpy(info->driver, "qca_ipqess", DRVINFO_LEN);
135 strlcpy(info->bus_info, "axi", ETHTOOL_BUSINFO_LEN);
136 }
137
138 static int ipqess_get_settings(struct net_device *netdev,
139 struct ethtool_link_ksettings *cmd)
140 {
141 struct ipqess *ess = netdev_priv(netdev);
142
143 return phylink_ethtool_ksettings_get(ess->phylink, cmd);
144 }
145
146 static int ipqess_set_settings(struct net_device *netdev,
147 const struct ethtool_link_ksettings *cmd)
148 {
149 struct ipqess *ess = netdev_priv(netdev);
150
151 return phylink_ethtool_ksettings_set(ess->phylink, cmd);
152 }
153
154 static void ipqess_get_ringparam(struct net_device *netdev,
155 struct ethtool_ringparam *ring)
156 {
157 ring->tx_max_pending = IPQESS_TX_RING_SIZE;
158 ring->rx_max_pending = IPQESS_RX_RING_SIZE;
159 }
160
161 static const struct ethtool_ops ipqesstool_ops = {
162 .get_drvinfo = &ipqess_get_drvinfo,
163 .get_link = &ethtool_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,
170 };
171
172 void ipqess_set_ethtool_ops(struct net_device *netdev)
173 {
174 netdev->ethtool_ops = &ipqesstool_ops;
175 }