• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Freescale Semiconductor, Inc. All rights reserved.
3  *
4  * Description: QE UCC Gigabit Ethernet Ethtool API Set
5  *
6  * Author: Li Yang <leoli@freescale.com>
7  *
8  * Limitation:
9  * Can only get/set setttings of the first queue.
10  * Need to re-open the interface manually after changing some paramters.
11  *
12  * This program is free software; you can redistribute  it and/or modify it
13  * under  the terms of  the GNU General  Public License as published by the
14  * Free Software Foundation;  either version 2 of the  License, or (at your
15  * option) any later version.
16  */
17 
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/errno.h>
21 #include <linux/slab.h>
22 #include <linux/stddef.h>
23 #include <linux/interrupt.h>
24 #include <linux/netdevice.h>
25 #include <linux/etherdevice.h>
26 #include <linux/skbuff.h>
27 #include <linux/spinlock.h>
28 #include <linux/mm.h>
29 #include <linux/delay.h>
30 #include <linux/dma-mapping.h>
31 #include <linux/fsl_devices.h>
32 #include <linux/ethtool.h>
33 #include <linux/mii.h>
34 #include <linux/phy.h>
35 
36 #include <asm/io.h>
37 #include <asm/irq.h>
38 #include <asm/uaccess.h>
39 #include <asm/types.h>
40 
41 #include "ucc_geth.h"
42 #include "ucc_geth_mii.h"
43 
44 static char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
45 	"tx-64-frames",
46 	"tx-65-127-frames",
47 	"tx-128-255-frames",
48 	"rx-64-frames",
49 	"rx-65-127-frames",
50 	"rx-128-255-frames",
51 	"tx-bytes-ok",
52 	"tx-pause-frames",
53 	"tx-multicast-frames",
54 	"tx-broadcast-frames",
55 	"rx-frames",
56 	"rx-bytes-ok",
57 	"rx-bytes-all",
58 	"rx-multicast-frames",
59 	"rx-broadcast-frames",
60 	"stats-counter-carry",
61 	"stats-counter-mask",
62 	"rx-dropped-frames",
63 };
64 
65 static char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
66 	"tx-single-collision",
67 	"tx-multiple-collision",
68 	"tx-late-collsion",
69 	"tx-aborted-frames",
70 	"tx-lost-frames",
71 	"tx-carrier-sense-errors",
72 	"tx-frames-ok",
73 	"tx-excessive-differ-frames",
74 	"tx-256-511-frames",
75 	"tx-512-1023-frames",
76 	"tx-1024-1518-frames",
77 	"tx-jumbo-frames",
78 };
79 
80 static char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
81 	"rx-crc-errors",
82 	"rx-alignment-errors",
83 	"rx-in-range-length-errors",
84 	"rx-out-of-range-length-errors",
85 	"rx-too-long-frames",
86 	"rx-runt",
87 	"rx-very-long-event",
88 	"rx-symbol-errors",
89 	"rx-busy-drop-frames",
90 	"reserved",
91 	"reserved",
92 	"rx-mismatch-drop-frames",
93 	"rx-small-than-64",
94 	"rx-256-511-frames",
95 	"rx-512-1023-frames",
96 	"rx-1024-1518-frames",
97 	"rx-jumbo-frames",
98 	"rx-mac-error-loss",
99 	"rx-pause-frames",
100 	"reserved",
101 	"rx-vlan-removed",
102 	"rx-vlan-replaced",
103 	"rx-vlan-inserted",
104 	"rx-ip-checksum-errors",
105 };
106 
107 #define UEC_HW_STATS_LEN ARRAY_SIZE(hw_stat_gstrings)
108 #define UEC_TX_FW_STATS_LEN ARRAY_SIZE(tx_fw_stat_gstrings)
109 #define UEC_RX_FW_STATS_LEN ARRAY_SIZE(rx_fw_stat_gstrings)
110 
111 static int
uec_get_settings(struct net_device * netdev,struct ethtool_cmd * ecmd)112 uec_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
113 {
114 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
115 	struct phy_device *phydev = ugeth->phydev;
116 	struct ucc_geth_info *ug_info = ugeth->ug_info;
117 
118 	if (!phydev)
119 		return -ENODEV;
120 
121 	ecmd->maxtxpkt = 1;
122 	ecmd->maxrxpkt = ug_info->interruptcoalescingmaxvalue[0];
123 
124 	return phy_ethtool_gset(phydev, ecmd);
125 }
126 
127 static int
uec_set_settings(struct net_device * netdev,struct ethtool_cmd * ecmd)128 uec_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
129 {
130 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
131 	struct phy_device *phydev = ugeth->phydev;
132 
133 	if (!phydev)
134 		return -ENODEV;
135 
136 	return phy_ethtool_sset(phydev, ecmd);
137 }
138 
139 static void
uec_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)140 uec_get_pauseparam(struct net_device *netdev,
141                      struct ethtool_pauseparam *pause)
142 {
143 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
144 
145 	pause->autoneg = ugeth->phydev->autoneg;
146 
147 	if (ugeth->ug_info->receiveFlowControl)
148 		pause->rx_pause = 1;
149 	if (ugeth->ug_info->transmitFlowControl)
150 		pause->tx_pause = 1;
151 }
152 
153 static int
uec_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)154 uec_set_pauseparam(struct net_device *netdev,
155                      struct ethtool_pauseparam *pause)
156 {
157 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
158 	int ret = 0;
159 
160 	ugeth->ug_info->receiveFlowControl = pause->rx_pause;
161 	ugeth->ug_info->transmitFlowControl = pause->tx_pause;
162 
163 	if (ugeth->phydev->autoneg) {
164 		if (netif_running(netdev)) {
165 			/* FIXME: automatically restart */
166 			printk(KERN_INFO
167 				"Please re-open the interface.\n");
168 		}
169 	} else {
170 		struct ucc_geth_info *ug_info = ugeth->ug_info;
171 
172 		ret = init_flow_control_params(ug_info->aufc,
173 					ug_info->receiveFlowControl,
174 					ug_info->transmitFlowControl,
175 					ug_info->pausePeriod,
176 					ug_info->extensionField,
177 					&ugeth->uccf->uf_regs->upsmr,
178 					&ugeth->ug_regs->uempr,
179 					&ugeth->ug_regs->maccfg1);
180 	}
181 
182 	return ret;
183 }
184 
185 static uint32_t
uec_get_msglevel(struct net_device * netdev)186 uec_get_msglevel(struct net_device *netdev)
187 {
188 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
189 	return ugeth->msg_enable;
190 }
191 
192 static void
uec_set_msglevel(struct net_device * netdev,uint32_t data)193 uec_set_msglevel(struct net_device *netdev, uint32_t data)
194 {
195 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
196 	ugeth->msg_enable = data;
197 }
198 
199 static int
uec_get_regs_len(struct net_device * netdev)200 uec_get_regs_len(struct net_device *netdev)
201 {
202 	return sizeof(struct ucc_geth);
203 }
204 
205 static void
uec_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)206 uec_get_regs(struct net_device *netdev,
207                struct ethtool_regs *regs, void *p)
208 {
209 	int i;
210 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
211 	u32 __iomem *ug_regs = (u32 __iomem *)ugeth->ug_regs;
212 	u32 *buff = p;
213 
214 	for (i = 0; i < sizeof(struct ucc_geth) / sizeof(u32); i++)
215 		buff[i] = in_be32(&ug_regs[i]);
216 }
217 
218 static void
uec_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring)219 uec_get_ringparam(struct net_device *netdev,
220                     struct ethtool_ringparam *ring)
221 {
222 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
223 	struct ucc_geth_info *ug_info = ugeth->ug_info;
224 	int queue = 0;
225 
226 	ring->rx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
227 	ring->rx_mini_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
228 	ring->rx_jumbo_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
229 	ring->tx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
230 
231 	ring->rx_pending = ug_info->bdRingLenRx[queue];
232 	ring->rx_mini_pending = ug_info->bdRingLenRx[queue];
233 	ring->rx_jumbo_pending = ug_info->bdRingLenRx[queue];
234 	ring->tx_pending = ug_info->bdRingLenTx[queue];
235 }
236 
237 static int
uec_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring)238 uec_set_ringparam(struct net_device *netdev,
239                     struct ethtool_ringparam *ring)
240 {
241 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
242 	struct ucc_geth_info *ug_info = ugeth->ug_info;
243 	int queue = 0, ret = 0;
244 
245 	if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
246 		printk("%s: RxBD ring size must be no smaller than %d.\n",
247 			       	netdev->name, UCC_GETH_RX_BD_RING_SIZE_MIN);
248 		return -EINVAL;
249 	}
250 	if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
251 		printk("%s: RxBD ring size must be multiple of %d.\n",
252 			netdev->name, UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
253 		return -EINVAL;
254 	}
255 	if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
256 		printk("%s: TxBD ring size must be no smaller than %d.\n",
257 				netdev->name, UCC_GETH_TX_BD_RING_SIZE_MIN);
258 		return -EINVAL;
259 	}
260 
261 	ug_info->bdRingLenRx[queue] = ring->rx_pending;
262 	ug_info->bdRingLenTx[queue] = ring->tx_pending;
263 
264 	if (netif_running(netdev)) {
265 		/* FIXME: restart automatically */
266 		printk(KERN_INFO
267 			"Please re-open the interface.\n");
268 	}
269 
270 	return ret;
271 }
272 
uec_get_sset_count(struct net_device * netdev,int sset)273 static int uec_get_sset_count(struct net_device *netdev, int sset)
274 {
275 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
276 	u32 stats_mode = ugeth->ug_info->statisticsMode;
277 	int len = 0;
278 
279 	switch (sset) {
280 	case ETH_SS_STATS:
281 		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
282 			len += UEC_HW_STATS_LEN;
283 		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
284 			len += UEC_TX_FW_STATS_LEN;
285 		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
286 			len += UEC_RX_FW_STATS_LEN;
287 
288 		return len;
289 
290 	default:
291 		return -EOPNOTSUPP;
292 	}
293 }
294 
uec_get_strings(struct net_device * netdev,u32 stringset,u8 * buf)295 static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
296 {
297 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
298 	u32 stats_mode = ugeth->ug_info->statisticsMode;
299 
300 	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
301 		memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
302 			       	ETH_GSTRING_LEN);
303 		buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
304 	}
305 	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
306 		memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
307 			       	ETH_GSTRING_LEN);
308 		buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
309 	}
310 	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
311 		memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
312 			       	ETH_GSTRING_LEN);
313 }
314 
uec_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,uint64_t * data)315 static void uec_get_ethtool_stats(struct net_device *netdev,
316 		struct ethtool_stats *stats, uint64_t *data)
317 {
318 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
319 	u32 stats_mode = ugeth->ug_info->statisticsMode;
320 	u32 __iomem *base;
321 	int i, j = 0;
322 
323 	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
324 		base = (u32 __iomem *)&ugeth->ug_regs->tx64;
325 		for (i = 0; i < UEC_HW_STATS_LEN; i++)
326 			data[j++] = in_be32(&base[i]);
327 	}
328 	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
329 		base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
330 		for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
331 			data[j++] = base ? in_be32(&base[i]) : 0;
332 	}
333 	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
334 		base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
335 		for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
336 			data[j++] = base ? in_be32(&base[i]) : 0;
337 	}
338 }
339 
uec_nway_reset(struct net_device * netdev)340 static int uec_nway_reset(struct net_device *netdev)
341 {
342 	struct ucc_geth_private *ugeth = netdev_priv(netdev);
343 
344 	return phy_start_aneg(ugeth->phydev);
345 }
346 
347 /* Report driver information */
348 static void
uec_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)349 uec_get_drvinfo(struct net_device *netdev,
350                        struct ethtool_drvinfo *drvinfo)
351 {
352 	strncpy(drvinfo->driver, DRV_NAME, 32);
353 	strncpy(drvinfo->version, DRV_VERSION, 32);
354 	strncpy(drvinfo->fw_version, "N/A", 32);
355 	strncpy(drvinfo->bus_info, "QUICC ENGINE", 32);
356 	drvinfo->eedump_len = 0;
357 	drvinfo->regdump_len = uec_get_regs_len(netdev);
358 }
359 
360 static const struct ethtool_ops uec_ethtool_ops = {
361 	.get_settings           = uec_get_settings,
362 	.set_settings           = uec_set_settings,
363 	.get_drvinfo            = uec_get_drvinfo,
364 	.get_regs_len           = uec_get_regs_len,
365 	.get_regs               = uec_get_regs,
366 	.get_msglevel           = uec_get_msglevel,
367 	.set_msglevel           = uec_set_msglevel,
368 	.nway_reset             = uec_nway_reset,
369 	.get_link               = ethtool_op_get_link,
370 	.get_ringparam          = uec_get_ringparam,
371 	.set_ringparam          = uec_set_ringparam,
372 	.get_pauseparam         = uec_get_pauseparam,
373 	.set_pauseparam         = uec_set_pauseparam,
374 	.set_sg                 = ethtool_op_set_sg,
375 	.get_sset_count		= uec_get_sset_count,
376 	.get_strings            = uec_get_strings,
377 	.get_ethtool_stats      = uec_get_ethtool_stats,
378 };
379 
uec_set_ethtool_ops(struct net_device * netdev)380 void uec_set_ethtool_ops(struct net_device *netdev)
381 {
382 	SET_ETHTOOL_OPS(netdev, &uec_ethtool_ops);
383 }
384