| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 1 | /* | 
|  | 2 | * drivers/net/gianfar_sysfs.c | 
|  | 3 | * | 
|  | 4 | * Gianfar Ethernet Driver | 
|  | 5 | * This driver is designed for the non-CPM ethernet controllers | 
|  | 6 | * on the 85xx and 83xx family of integrated processors | 
|  | 7 | * Based on 8260_io/fcc_enet.c | 
|  | 8 | * | 
|  | 9 | * Author: Andy Fleming | 
| Adrian Bunk | b56d55b | 2006-01-11 02:00:10 +0100 | [diff] [blame] | 10 | * Maintainer: Kumar Gala (galak@kernel.crashing.org) | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 11 | * | 
|  | 12 | * Copyright (c) 2002-2005 Freescale Semiconductor, Inc. | 
|  | 13 | * | 
|  | 14 | * This program is free software; you can redistribute  it and/or modify it | 
|  | 15 | * under  the terms of  the GNU General  Public License as published by the | 
|  | 16 | * Free Software Foundation;  either version 2 of the  License, or (at your | 
|  | 17 | * option) any later version. | 
|  | 18 | * | 
|  | 19 | * Sysfs file creation and management | 
|  | 20 | */ | 
|  | 21 |  | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 22 | #include <linux/kernel.h> | 
|  | 23 | #include <linux/sched.h> | 
|  | 24 | #include <linux/string.h> | 
|  | 25 | #include <linux/errno.h> | 
|  | 26 | #include <linux/unistd.h> | 
|  | 27 | #include <linux/slab.h> | 
|  | 28 | #include <linux/init.h> | 
|  | 29 | #include <linux/delay.h> | 
|  | 30 | #include <linux/etherdevice.h> | 
|  | 31 | #include <linux/spinlock.h> | 
|  | 32 | #include <linux/mm.h> | 
|  | 33 | #include <linux/device.h> | 
|  | 34 |  | 
|  | 35 | #include <asm/uaccess.h> | 
|  | 36 | #include <linux/module.h> | 
|  | 37 | #include <linux/version.h> | 
|  | 38 |  | 
|  | 39 | #include "gianfar.h" | 
|  | 40 |  | 
|  | 41 | #define GFAR_ATTR(_name) \ | 
|  | 42 | static ssize_t gfar_show_##_name(struct class_device *cdev, char *buf); \ | 
|  | 43 | static ssize_t gfar_set_##_name(struct class_device *cdev, \ | 
|  | 44 | const char *buf, size_t count); \ | 
|  | 45 | static CLASS_DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name) | 
|  | 46 |  | 
|  | 47 | #define GFAR_CREATE_FILE(_dev, _name) \ | 
|  | 48 | class_device_create_file(&_dev->class_dev, &class_device_attr_##_name) | 
|  | 49 |  | 
|  | 50 | GFAR_ATTR(bd_stash); | 
|  | 51 | GFAR_ATTR(rx_stash_size); | 
|  | 52 | GFAR_ATTR(rx_stash_index); | 
|  | 53 | GFAR_ATTR(fifo_threshold); | 
|  | 54 | GFAR_ATTR(fifo_starve); | 
|  | 55 | GFAR_ATTR(fifo_starve_off); | 
|  | 56 |  | 
|  | 57 | #define to_net_dev(cd) container_of(cd, struct net_device, class_dev) | 
|  | 58 |  | 
|  | 59 | static ssize_t gfar_show_bd_stash(struct class_device *cdev, char *buf) | 
|  | 60 | { | 
|  | 61 | struct net_device *dev = to_net_dev(cdev); | 
|  | 62 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 63 |  | 
|  | 64 | return sprintf(buf, "%s\n", priv->bd_stash_en? "on" : "off"); | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | static ssize_t gfar_set_bd_stash(struct class_device *cdev, | 
|  | 68 | const char *buf, size_t count) | 
|  | 69 | { | 
|  | 70 | struct net_device *dev = to_net_dev(cdev); | 
|  | 71 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 72 | int new_setting = 0; | 
|  | 73 | u32 temp; | 
|  | 74 | unsigned long flags; | 
|  | 75 |  | 
|  | 76 | /* Find out the new setting */ | 
|  | 77 | if (!strncmp("on", buf, count-1) || !strncmp("1", buf, count-1)) | 
|  | 78 | new_setting = 1; | 
|  | 79 | else if (!strncmp("off", buf, count-1) || !strncmp("0", buf, count-1)) | 
|  | 80 | new_setting = 0; | 
|  | 81 | else | 
|  | 82 | return count; | 
|  | 83 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 84 | spin_lock_irqsave(&priv->rxlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 85 |  | 
|  | 86 | /* Set the new stashing value */ | 
|  | 87 | priv->bd_stash_en = new_setting; | 
|  | 88 |  | 
|  | 89 | temp = gfar_read(&priv->regs->attr); | 
| Jeff Garzik | 6aa20a2 | 2006-09-13 13:24:59 -0400 | [diff] [blame] | 90 |  | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 91 | if (new_setting) | 
|  | 92 | temp |= ATTR_BDSTASH; | 
|  | 93 | else | 
|  | 94 | temp &= ~(ATTR_BDSTASH); | 
|  | 95 |  | 
|  | 96 | gfar_write(&priv->regs->attr, temp); | 
|  | 97 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 98 | spin_unlock_irqrestore(&priv->rxlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 99 |  | 
|  | 100 | return count; | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | static ssize_t gfar_show_rx_stash_size(struct class_device *cdev, char *buf) | 
|  | 104 | { | 
|  | 105 | struct net_device *dev = to_net_dev(cdev); | 
|  | 106 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 107 |  | 
|  | 108 | return sprintf(buf, "%d\n", priv->rx_stash_size); | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 | static ssize_t gfar_set_rx_stash_size(struct class_device *cdev, | 
|  | 112 | const char *buf, size_t count) | 
|  | 113 | { | 
|  | 114 | struct net_device *dev = to_net_dev(cdev); | 
|  | 115 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 116 | unsigned int length = simple_strtoul(buf, NULL, 0); | 
|  | 117 | u32 temp; | 
|  | 118 | unsigned long flags; | 
|  | 119 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 120 | spin_lock_irqsave(&priv->rxlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 121 | if (length > priv->rx_buffer_size) | 
|  | 122 | return count; | 
|  | 123 |  | 
|  | 124 | if (length == priv->rx_stash_size) | 
|  | 125 | return count; | 
|  | 126 |  | 
|  | 127 | priv->rx_stash_size = length; | 
|  | 128 |  | 
|  | 129 | temp = gfar_read(&priv->regs->attreli); | 
|  | 130 | temp &= ~ATTRELI_EL_MASK; | 
|  | 131 | temp |= ATTRELI_EL(length); | 
|  | 132 | gfar_write(&priv->regs->attreli, temp); | 
|  | 133 |  | 
|  | 134 | /* Turn stashing on/off as appropriate */ | 
|  | 135 | temp = gfar_read(&priv->regs->attr); | 
|  | 136 |  | 
|  | 137 | if (length) | 
|  | 138 | temp |= ATTR_BUFSTASH; | 
|  | 139 | else | 
|  | 140 | temp &= ~(ATTR_BUFSTASH); | 
|  | 141 |  | 
|  | 142 | gfar_write(&priv->regs->attr, temp); | 
|  | 143 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 144 | spin_unlock_irqrestore(&priv->rxlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 145 |  | 
|  | 146 | return count; | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 |  | 
|  | 150 | /* Stashing will only be enabled when rx_stash_size != 0 */ | 
|  | 151 | static ssize_t gfar_show_rx_stash_index(struct class_device *cdev, char *buf) | 
|  | 152 | { | 
|  | 153 | struct net_device *dev = to_net_dev(cdev); | 
|  | 154 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 155 |  | 
|  | 156 | return sprintf(buf, "%d\n", priv->rx_stash_index); | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 | static ssize_t gfar_set_rx_stash_index(struct class_device *cdev, | 
|  | 160 | const char *buf, size_t count) | 
|  | 161 | { | 
|  | 162 | struct net_device *dev = to_net_dev(cdev); | 
|  | 163 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 164 | unsigned short index = simple_strtoul(buf, NULL, 0); | 
|  | 165 | u32 temp; | 
|  | 166 | unsigned long flags; | 
|  | 167 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 168 | spin_lock_irqsave(&priv->rxlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 169 | if (index > priv->rx_stash_size) | 
|  | 170 | return count; | 
|  | 171 |  | 
|  | 172 | if (index == priv->rx_stash_index) | 
|  | 173 | return count; | 
|  | 174 |  | 
|  | 175 | priv->rx_stash_index = index; | 
|  | 176 |  | 
|  | 177 | temp = gfar_read(&priv->regs->attreli); | 
|  | 178 | temp &= ~ATTRELI_EI_MASK; | 
|  | 179 | temp |= ATTRELI_EI(index); | 
|  | 180 | gfar_write(&priv->regs->attreli, flags); | 
|  | 181 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 182 | spin_unlock_irqrestore(&priv->rxlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 183 |  | 
|  | 184 | return count; | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | static ssize_t gfar_show_fifo_threshold(struct class_device *cdev, char *buf) | 
|  | 188 | { | 
|  | 189 | struct net_device *dev = to_net_dev(cdev); | 
|  | 190 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 191 |  | 
|  | 192 | return sprintf(buf, "%d\n", priv->fifo_threshold); | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | static ssize_t gfar_set_fifo_threshold(struct class_device *cdev, | 
|  | 196 | const char *buf, size_t count) | 
|  | 197 | { | 
|  | 198 | struct net_device *dev = to_net_dev(cdev); | 
|  | 199 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 200 | unsigned int length = simple_strtoul(buf, NULL, 0); | 
|  | 201 | u32 temp; | 
|  | 202 | unsigned long flags; | 
|  | 203 |  | 
|  | 204 | if (length > GFAR_MAX_FIFO_THRESHOLD) | 
|  | 205 | return count; | 
|  | 206 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 207 | spin_lock_irqsave(&priv->txlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 208 |  | 
|  | 209 | priv->fifo_threshold = length; | 
|  | 210 |  | 
|  | 211 | temp = gfar_read(&priv->regs->fifo_tx_thr); | 
|  | 212 | temp &= ~FIFO_TX_THR_MASK; | 
|  | 213 | temp |= length; | 
|  | 214 | gfar_write(&priv->regs->fifo_tx_thr, temp); | 
|  | 215 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 216 | spin_unlock_irqrestore(&priv->txlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 217 |  | 
|  | 218 | return count; | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 | static ssize_t gfar_show_fifo_starve(struct class_device *cdev, char *buf) | 
|  | 222 | { | 
|  | 223 | struct net_device *dev = to_net_dev(cdev); | 
|  | 224 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 225 |  | 
|  | 226 | return sprintf(buf, "%d\n", priv->fifo_starve); | 
|  | 227 | } | 
|  | 228 |  | 
|  | 229 |  | 
|  | 230 | static ssize_t gfar_set_fifo_starve(struct class_device *cdev, | 
|  | 231 | const char *buf, size_t count) | 
|  | 232 | { | 
|  | 233 | struct net_device *dev = to_net_dev(cdev); | 
|  | 234 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 235 | unsigned int num = simple_strtoul(buf, NULL, 0); | 
|  | 236 | u32 temp; | 
|  | 237 | unsigned long flags; | 
|  | 238 |  | 
|  | 239 | if (num > GFAR_MAX_FIFO_STARVE) | 
|  | 240 | return count; | 
|  | 241 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 242 | spin_lock_irqsave(&priv->txlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 243 |  | 
|  | 244 | priv->fifo_starve = num; | 
|  | 245 |  | 
|  | 246 | temp = gfar_read(&priv->regs->fifo_tx_starve); | 
|  | 247 | temp &= ~FIFO_TX_STARVE_MASK; | 
|  | 248 | temp |= num; | 
|  | 249 | gfar_write(&priv->regs->fifo_tx_starve, temp); | 
|  | 250 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 251 | spin_unlock_irqrestore(&priv->txlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 252 |  | 
|  | 253 | return count; | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | static ssize_t gfar_show_fifo_starve_off(struct class_device *cdev, char *buf) | 
|  | 257 | { | 
|  | 258 | struct net_device *dev = to_net_dev(cdev); | 
|  | 259 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 260 |  | 
|  | 261 | return sprintf(buf, "%d\n", priv->fifo_starve_off); | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 | static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev, | 
|  | 265 | const char *buf, size_t count) | 
|  | 266 | { | 
|  | 267 | struct net_device *dev = to_net_dev(cdev); | 
|  | 268 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 269 | unsigned int num = simple_strtoul(buf, NULL, 0); | 
|  | 270 | u32 temp; | 
|  | 271 | unsigned long flags; | 
|  | 272 |  | 
|  | 273 | if (num > GFAR_MAX_FIFO_STARVE_OFF) | 
|  | 274 | return count; | 
|  | 275 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 276 | spin_lock_irqsave(&priv->txlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 277 |  | 
|  | 278 | priv->fifo_starve_off = num; | 
|  | 279 |  | 
|  | 280 | temp = gfar_read(&priv->regs->fifo_tx_starve_shutoff); | 
|  | 281 | temp &= ~FIFO_TX_STARVE_OFF_MASK; | 
|  | 282 | temp |= num; | 
|  | 283 | gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp); | 
|  | 284 |  | 
| Andy Fleming | fef6108 | 2006-04-20 16:44:29 -0500 | [diff] [blame] | 285 | spin_unlock_irqrestore(&priv->txlock, flags); | 
| Andy Fleming | 7f7f531 | 2005-11-11 12:38:59 -0600 | [diff] [blame] | 286 |  | 
|  | 287 | return count; | 
|  | 288 | } | 
|  | 289 |  | 
|  | 290 | void gfar_init_sysfs(struct net_device *dev) | 
|  | 291 | { | 
|  | 292 | struct gfar_private *priv = netdev_priv(dev); | 
|  | 293 |  | 
|  | 294 | /* Initialize the default values */ | 
|  | 295 | priv->rx_stash_size = DEFAULT_STASH_LENGTH; | 
|  | 296 | priv->rx_stash_index = DEFAULT_STASH_INDEX; | 
|  | 297 | priv->fifo_threshold = DEFAULT_FIFO_TX_THR; | 
|  | 298 | priv->fifo_starve = DEFAULT_FIFO_TX_STARVE; | 
|  | 299 | priv->fifo_starve_off = DEFAULT_FIFO_TX_STARVE_OFF; | 
|  | 300 | priv->bd_stash_en = DEFAULT_BD_STASH; | 
|  | 301 |  | 
|  | 302 | /* Create our sysfs files */ | 
|  | 303 | GFAR_CREATE_FILE(dev, bd_stash); | 
|  | 304 | GFAR_CREATE_FILE(dev, rx_stash_size); | 
|  | 305 | GFAR_CREATE_FILE(dev, rx_stash_index); | 
|  | 306 | GFAR_CREATE_FILE(dev, fifo_threshold); | 
|  | 307 | GFAR_CREATE_FILE(dev, fifo_starve); | 
|  | 308 | GFAR_CREATE_FILE(dev, fifo_starve_off); | 
|  | 309 |  | 
|  | 310 | } |