1 /*   This program is free software; you can redistribute it and/or modify
2  *   it under the terms of the GNU General Public License as published by
3  *   the Free Software Foundation; version 2 of the License
4  *
5  *   This program is distributed in the hope that it will be useful,
6  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
7  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8  *   GNU General Public License for more details.
9  *
10  *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
11  *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
12  *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
13  */
14 
15 #include "mtk_eth_soc.h"
16 #include "ethtool.h"
17 
18 struct mtk_stat {
19 	char name[ETH_GSTRING_LEN];
20 	unsigned int idx;
21 };
22 
23 #define MTK_HW_STAT(stat) { \
24 	.name = #stat, \
25 	.idx = offsetof(struct mtk_hw_stats, stat) / sizeof(u64) \
26 }
27 
28 static const struct mtk_stat mtk_ethtool_hw_stats[] = {
29 	MTK_HW_STAT(tx_bytes),
30 	MTK_HW_STAT(tx_packets),
31 	MTK_HW_STAT(tx_skip),
32 	MTK_HW_STAT(tx_collisions),
33 	MTK_HW_STAT(rx_bytes),
34 	MTK_HW_STAT(rx_packets),
35 	MTK_HW_STAT(rx_overflow),
36 	MTK_HW_STAT(rx_fcs_errors),
37 	MTK_HW_STAT(rx_short_errors),
38 	MTK_HW_STAT(rx_long_errors),
39 	MTK_HW_STAT(rx_checksum_errors),
40 	MTK_HW_STAT(rx_flow_control_packets),
41 };
42 
43 #define MTK_HW_STATS_LEN	ARRAY_SIZE(mtk_ethtool_hw_stats)
44 
mtk_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * cmd)45 static int mtk_get_link_ksettings(struct net_device *dev,
46 				  struct ethtool_link_ksettings *cmd)
47 {
48 	struct mtk_mac *mac = netdev_priv(dev);
49 	int err;
50 
51 	if (!mac->phy_dev)
52 		return -ENODEV;
53 
54 	if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
55 		err = phy_read_status(mac->phy_dev);
56 		if (err)
57 			return -ENODEV;
58 	}
59 
60 	phy_ethtool_ksettings_get(mac->phy_dev, cmd);
61 	return 0;
62 }
63 
mtk_set_link_ksettings(struct net_device * dev,const struct ethtool_link_ksettings * cmd)64 static int mtk_set_link_ksettings(struct net_device *dev,
65 				  const struct ethtool_link_ksettings *cmd)
66 {
67 	struct mtk_mac *mac = netdev_priv(dev);
68 
69 	if (!mac->phy_dev)
70 		return -ENODEV;
71 
72 	if (cmd->base.phy_address != mac->phy_dev->mdio.addr) {
73 		if (mac->hw->phy->phy_node[cmd->base.phy_address]) {
74 			mac->phy_dev = mac->hw->phy->phy[cmd->base.phy_address];
75 			mac->phy_flags = MTK_PHY_FLAG_PORT;
76 		} else if (mac->hw->mii_bus) {
77 			mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus,
78 						       cmd->base.phy_address);
79 			if (!mac->phy_dev)
80 				return -ENODEV;
81 			mac->phy_flags = MTK_PHY_FLAG_ATTACH;
82 		} else {
83 			return -ENODEV;
84 		}
85 	}
86 
87 	return phy_ethtool_ksettings_set(mac->phy_dev, cmd);
88 }
89 
mtk_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)90 static void mtk_get_drvinfo(struct net_device *dev,
91 			    struct ethtool_drvinfo *info)
92 {
93 	struct mtk_mac *mac = netdev_priv(dev);
94 	struct mtk_soc_data *soc = mac->hw->soc;
95 
96 	strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
97 	strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
98 
99 	if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE])
100 		info->n_stats = MTK_HW_STATS_LEN;
101 }
102 
mtk_get_msglevel(struct net_device * dev)103 static u32 mtk_get_msglevel(struct net_device *dev)
104 {
105 	struct mtk_mac *mac = netdev_priv(dev);
106 
107 	return mac->hw->msg_enable;
108 }
109 
mtk_set_msglevel(struct net_device * dev,u32 value)110 static void mtk_set_msglevel(struct net_device *dev, u32 value)
111 {
112 	struct mtk_mac *mac = netdev_priv(dev);
113 
114 	mac->hw->msg_enable = value;
115 }
116 
mtk_nway_reset(struct net_device * dev)117 static int mtk_nway_reset(struct net_device *dev)
118 {
119 	struct mtk_mac *mac = netdev_priv(dev);
120 
121 	if (!mac->phy_dev)
122 		return -EOPNOTSUPP;
123 
124 	return genphy_restart_aneg(mac->phy_dev);
125 }
126 
mtk_get_link(struct net_device * dev)127 static u32 mtk_get_link(struct net_device *dev)
128 {
129 	struct mtk_mac *mac = netdev_priv(dev);
130 	int err;
131 
132 	if (!mac->phy_dev)
133 		goto out_get_link;
134 
135 	if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
136 		err = genphy_update_link(mac->phy_dev);
137 		if (err)
138 			goto out_get_link;
139 	}
140 
141 	return mac->phy_dev->link;
142 
143 out_get_link:
144 	return ethtool_op_get_link(dev);
145 }
146 
mtk_set_ringparam(struct net_device * dev,struct ethtool_ringparam * ring)147 static int mtk_set_ringparam(struct net_device *dev,
148 			     struct ethtool_ringparam *ring)
149 {
150 	struct mtk_mac *mac = netdev_priv(dev);
151 
152 	if ((ring->tx_pending < 2) ||
153 	    (ring->rx_pending < 2) ||
154 	    (ring->rx_pending > mac->hw->soc->dma_ring_size) ||
155 	    (ring->tx_pending > mac->hw->soc->dma_ring_size))
156 		return -EINVAL;
157 
158 	dev->netdev_ops->ndo_stop(dev);
159 
160 	mac->hw->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
161 	mac->hw->rx_ring[0].rx_ring_size = BIT(fls(ring->rx_pending) - 1);
162 
163 	return dev->netdev_ops->ndo_open(dev);
164 }
165 
mtk_get_ringparam(struct net_device * dev,struct ethtool_ringparam * ring)166 static void mtk_get_ringparam(struct net_device *dev,
167 			      struct ethtool_ringparam *ring)
168 {
169 	struct mtk_mac *mac = netdev_priv(dev);
170 
171 	ring->rx_max_pending = mac->hw->soc->dma_ring_size;
172 	ring->tx_max_pending = mac->hw->soc->dma_ring_size;
173 	ring->rx_pending = mac->hw->rx_ring[0].rx_ring_size;
174 	ring->tx_pending = mac->hw->tx_ring.tx_ring_size;
175 }
176 
mtk_get_strings(struct net_device * dev,u32 stringset,u8 * data)177 static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
178 {
179 	int i;
180 
181 	switch (stringset) {
182 	case ETH_SS_STATS:
183 		for (i = 0; i < MTK_HW_STATS_LEN; i++) {
184 			memcpy(data, mtk_ethtool_hw_stats[i].name,
185 			       ETH_GSTRING_LEN);
186 			data += ETH_GSTRING_LEN;
187 		}
188 		break;
189 	}
190 }
191 
mtk_get_sset_count(struct net_device * dev,int sset)192 static int mtk_get_sset_count(struct net_device *dev, int sset)
193 {
194 	switch (sset) {
195 	case ETH_SS_STATS:
196 		return MTK_HW_STATS_LEN;
197 	default:
198 		return -EOPNOTSUPP;
199 	}
200 }
201 
mtk_get_ethtool_stats(struct net_device * dev,struct ethtool_stats * stats,u64 * data)202 static void mtk_get_ethtool_stats(struct net_device *dev,
203 				  struct ethtool_stats *stats, u64 *data)
204 {
205 	struct mtk_mac *mac = netdev_priv(dev);
206 	struct mtk_hw_stats *hwstats = mac->hw_stats;
207 	unsigned int start;
208 	int i;
209 
210 	if (netif_running(dev) && netif_device_present(dev)) {
211 		if (spin_trylock(&hwstats->stats_lock)) {
212 			mtk_stats_update_mac(mac);
213 			spin_unlock(&hwstats->stats_lock);
214 		}
215 	}
216 
217 	do {
218 		start = u64_stats_fetch_begin_irq(&hwstats->syncp);
219 		for (i = 0; i < MTK_HW_STATS_LEN; i++)
220 			data[i] = ((u64 *)hwstats)[mtk_ethtool_hw_stats[i].idx];
221 
222 	} while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
223 }
224 
225 static struct ethtool_ops mtk_ethtool_ops = {
226 	.get_link_ksettings     = mtk_get_link_ksettings,
227 	.set_link_ksettings     = mtk_set_link_ksettings,
228 	.get_drvinfo		= mtk_get_drvinfo,
229 	.get_msglevel		= mtk_get_msglevel,
230 	.set_msglevel		= mtk_set_msglevel,
231 	.nway_reset		= mtk_nway_reset,
232 	.get_link		= mtk_get_link,
233 	.set_ringparam		= mtk_set_ringparam,
234 	.get_ringparam		= mtk_get_ringparam,
235 };
236 
mtk_set_ethtool_ops(struct net_device * netdev)237 void mtk_set_ethtool_ops(struct net_device *netdev)
238 {
239 	struct mtk_mac *mac = netdev_priv(netdev);
240 	struct mtk_soc_data *soc = mac->hw->soc;
241 
242 	if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) {
243 		mtk_ethtool_ops.get_strings = mtk_get_strings;
244 		mtk_ethtool_ops.get_sset_count = mtk_get_sset_count;
245 		mtk_ethtool_ops.get_ethtool_stats = mtk_get_ethtool_stats;
246 	}
247 
248 	netdev->ethtool_ops = &mtk_ethtool_ops;
249 }
250