Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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