Commit 7f7f5316 authored by Andy Fleming's avatar Andy Fleming Committed by Jeff Garzik

[PATCH] Gianfar update and sysfs support

This seems to have gotten lost, so I'll resend.
Signed-off-by: default avatarAndy Fleming <afleming@freescale.com>

* Added sysfs support to gianfar for modifying FIFO and stashing parameters
* Updated driver to support 10 Mbit, full duplex operation
* Improved comments throughout
* Cleaned up and optimized offloading code
* Fixed a bug where rx buffers were being improperly mapped and unmapped
* (only manifested if cache-coherency was off)
* Added support for using the eTSEC exact-match MAC registers
* Bumped the version to 1.3
* Added support for distinguishing between reduced 100 and 10 Mbit modes
* Modified default coalescing values to lower latency
* Added documentation
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent fed5eccd
The Gianfar Ethernet Driver
Sysfs File description
Author: Andy Fleming <afleming@freescale.com>
Updated: 2005-07-28
SYSFS
Several of the features of the gianfar driver are controlled
through sysfs files. These are:
bd_stash:
To stash RX Buffer Descriptors in the L2, echo 'on' or '1' to
bd_stash, echo 'off' or '0' to disable
rx_stash_len:
To stash the first n bytes of the packet in L2, echo the number
of bytes to buf_stash_len. echo 0 to disable.
WARNING: You could really screw these up if you set them too low or high!
fifo_threshold:
To change the number of bytes the controller needs in the
fifo before it starts transmission, echo the number of bytes to
fifo_thresh. Range should be 0-511.
fifo_starve:
When the FIFO has less than this many bytes during a transmit, it
enters starve mode, and increases the priority of TX memory
transactions. To change, echo the number of bytes to
fifo_starve. Range should be 0-511.
fifo_starve_off:
Once in starve mode, the FIFO remains there until it has this
many bytes. To change, echo the number of bytes to
fifo_starve_off. Range should be 0-511.
CHECKSUM OFFLOADING
The eTSEC controller (first included in parts from late 2005 like
the 8548) has the ability to perform TCP, UDP, and IP checksums
in hardware. The Linux kernel only offloads the TCP and UDP
checksums (and always performs the pseudo header checksums), so
the driver only supports checksumming for TCP/IP and UDP/IP
packets. Use ethtool to enable or disable this feature for RX
and TX.
VLAN
In order to use VLAN, please consult Linux documentation on
configuring VLANs. The gianfar driver supports hardware insertion and
extraction of VLAN headers, but not filtering. Filtering will be
done by the kernel.
MULTICASTING
The gianfar driver supports using the group hash table on the
TSEC (and the extended hash table on the eTSEC) for multicast
filtering. On the eTSEC, the exact-match MAC registers are used
before the hash tables. See Linux documentation on how to join
multicast groups.
PADDING
The gianfar driver supports padding received frames with 2 bytes
to align the IP header to a 16-byte boundary, when supported by
hardware.
ETHTOOL
The gianfar driver supports the use of ethtool for many
configuration options. You must run ethtool only on currently
open interfaces. See ethtool documentation for details.
...@@ -13,7 +13,10 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ ...@@ -13,7 +13,10 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o obj-$(CONFIG_GIANFAR) += gianfar_driver.o
gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o gianfar_driver-objs := gianfar.o \
gianfar_ethtool.o \
gianfar_mii.o \
gianfar_sysfs.o
# #
# link order important here # link order important here
......
This diff is collapsed.
...@@ -90,12 +90,26 @@ extern const char gfar_driver_version[]; ...@@ -90,12 +90,26 @@ extern const char gfar_driver_version[];
#define GFAR_RX_MAX_RING_SIZE 256 #define GFAR_RX_MAX_RING_SIZE 256
#define GFAR_TX_MAX_RING_SIZE 256 #define GFAR_TX_MAX_RING_SIZE 256
#define GFAR_MAX_FIFO_THRESHOLD 511
#define GFAR_MAX_FIFO_STARVE 511
#define GFAR_MAX_FIFO_STARVE_OFF 511
#define DEFAULT_RX_BUFFER_SIZE 1536 #define DEFAULT_RX_BUFFER_SIZE 1536
#define TX_RING_MOD_MASK(size) (size-1) #define TX_RING_MOD_MASK(size) (size-1)
#define RX_RING_MOD_MASK(size) (size-1) #define RX_RING_MOD_MASK(size) (size-1)
#define JUMBO_BUFFER_SIZE 9728 #define JUMBO_BUFFER_SIZE 9728
#define JUMBO_FRAME_SIZE 9600 #define JUMBO_FRAME_SIZE 9600
#define DEFAULT_FIFO_TX_THR 0x100
#define DEFAULT_FIFO_TX_STARVE 0x40
#define DEFAULT_FIFO_TX_STARVE_OFF 0x80
#define DEFAULT_BD_STASH 1
#define DEFAULT_STASH_LENGTH 64
#define DEFAULT_STASH_INDEX 0
/* The number of Exact Match registers */
#define GFAR_EM_NUM 15
/* Latency of interface clock in nanoseconds */ /* Latency of interface clock in nanoseconds */
/* Interface clock latency , in this case, means the /* Interface clock latency , in this case, means the
* time described by a value of 1 in the interrupt * time described by a value of 1 in the interrupt
...@@ -112,11 +126,11 @@ extern const char gfar_driver_version[]; ...@@ -112,11 +126,11 @@ extern const char gfar_driver_version[];
#define DEFAULT_TX_COALESCE 1 #define DEFAULT_TX_COALESCE 1
#define DEFAULT_TXCOUNT 16 #define DEFAULT_TXCOUNT 16
#define DEFAULT_TXTIME 400 #define DEFAULT_TXTIME 4
#define DEFAULT_RX_COALESCE 1 #define DEFAULT_RX_COALESCE 1
#define DEFAULT_RXCOUNT 16 #define DEFAULT_RXCOUNT 16
#define DEFAULT_RXTIME 400 #define DEFAULT_RXTIME 4
#define TBIPA_VALUE 0x1f #define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007 #define MIIMCFG_INIT_VALUE 0x00000007
...@@ -147,6 +161,7 @@ extern const char gfar_driver_version[]; ...@@ -147,6 +161,7 @@ extern const char gfar_driver_version[];
#define ECNTRL_INIT_SETTINGS 0x00001000 #define ECNTRL_INIT_SETTINGS 0x00001000
#define ECNTRL_TBI_MODE 0x00000020 #define ECNTRL_TBI_MODE 0x00000020
#define ECNTRL_R100 0x00000008
#define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE #define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE
...@@ -181,10 +196,12 @@ extern const char gfar_driver_version[]; ...@@ -181,10 +196,12 @@ extern const char gfar_driver_version[];
#define RCTRL_PRSDEP_MASK 0x000000c0 #define RCTRL_PRSDEP_MASK 0x000000c0
#define RCTRL_PRSDEP_INIT 0x000000c0 #define RCTRL_PRSDEP_INIT 0x000000c0
#define RCTRL_PROM 0x00000008 #define RCTRL_PROM 0x00000008
#define RCTRL_EMEN 0x00000002
#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \ #define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \
| RCTRL_TUCSEN | RCTRL_PRSDEP_INIT) | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
#define RCTRL_EXTHASH (RCTRL_GHTX) #define RCTRL_EXTHASH (RCTRL_GHTX)
#define RCTRL_VLAN (RCTRL_PRSDEP_INIT) #define RCTRL_VLAN (RCTRL_PRSDEP_INIT)
#define RCTRL_PADDING(x) ((x << 16) & RCTRL_PAL_MASK)
#define RSTAT_CLEAR_RHALT 0x00800000 #define RSTAT_CLEAR_RHALT 0x00800000
...@@ -251,28 +268,26 @@ extern const char gfar_driver_version[]; ...@@ -251,28 +268,26 @@ extern const char gfar_driver_version[];
IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
| IMASK_PERR) | IMASK_PERR)
/* Fifo management */
#define FIFO_TX_THR_MASK 0x01ff
#define FIFO_TX_STARVE_MASK 0x01ff
#define FIFO_TX_STARVE_OFF_MASK 0x01ff
/* Attribute fields */ /* Attribute fields */
/* This enables rx snooping for buffers and descriptors */ /* This enables rx snooping for buffers and descriptors */
#ifdef CONFIG_GFAR_BDSTASH
#define ATTR_BDSTASH 0x00000800 #define ATTR_BDSTASH 0x00000800
#else
#define ATTR_BDSTASH 0x00000000
#endif
#ifdef CONFIG_GFAR_BUFSTASH
#define ATTR_BUFSTASH 0x00004000 #define ATTR_BUFSTASH 0x00004000
#define STASH_LENGTH 64
#else
#define ATTR_BUFSTASH 0x00000000
#endif
#define ATTR_SNOOPING 0x000000c0 #define ATTR_SNOOPING 0x000000c0
#define ATTR_INIT_SETTINGS (ATTR_SNOOPING \ #define ATTR_INIT_SETTINGS ATTR_SNOOPING
| ATTR_BDSTASH | ATTR_BUFSTASH)
#define ATTRELI_INIT_SETTINGS 0x0 #define ATTRELI_INIT_SETTINGS 0x0
#define ATTRELI_EL_MASK 0x3fff0000
#define ATTRELI_EL(x) (x << 16)
#define ATTRELI_EI_MASK 0x00003fff
#define ATTRELI_EI(x) (x)
/* TxBD status field bits */ /* TxBD status field bits */
...@@ -328,6 +343,7 @@ extern const char gfar_driver_version[]; ...@@ -328,6 +343,7 @@ extern const char gfar_driver_version[];
#define RXFCB_CTU 0x0400 #define RXFCB_CTU 0x0400
#define RXFCB_EIP 0x0200 #define RXFCB_EIP 0x0200
#define RXFCB_ETU 0x0100 #define RXFCB_ETU 0x0100
#define RXFCB_CSUM_MASK 0x0f00
#define RXFCB_PERR_MASK 0x000c #define RXFCB_PERR_MASK 0x000c
#define RXFCB_PERR_BADL3 0x0008 #define RXFCB_PERR_BADL3 0x0008
...@@ -339,14 +355,7 @@ struct txbd8 ...@@ -339,14 +355,7 @@ struct txbd8
}; };
struct txfcb { struct txfcb {
u8 vln:1, u8 flags;
ip:1,
ip6:1,
tup:1,
udp:1,
cip:1,
ctu:1,
nph:1;
u8 reserved; u8 reserved;
u8 l4os; /* Level 4 Header Offset */ u8 l4os; /* Level 4 Header Offset */
u8 l3os; /* Level 3 Header Offset */ u8 l3os; /* Level 3 Header Offset */
...@@ -362,14 +371,7 @@ struct rxbd8 ...@@ -362,14 +371,7 @@ struct rxbd8
}; };
struct rxfcb { struct rxfcb {
u16 vln:1, u16 flags;
ip:1,
ip6:1,
tup:1,
cip:1,
ctu:1,
eip:1,
etu:1;
u8 rq; /* Receive Queue index */ u8 rq; /* Receive Queue index */
u8 pro; /* Layer 4 Protocol */ u8 pro; /* Layer 4 Protocol */
u16 reserved; u16 reserved;
...@@ -688,12 +690,17 @@ struct gfar_private { ...@@ -688,12 +690,17 @@ struct gfar_private {
spinlock_t lock; spinlock_t lock;
unsigned int rx_buffer_size; unsigned int rx_buffer_size;
unsigned int rx_stash_size; unsigned int rx_stash_size;
unsigned int rx_stash_index;
unsigned int tx_ring_size; unsigned int tx_ring_size;
unsigned int rx_ring_size; unsigned int rx_ring_size;
unsigned int fifo_threshold;
unsigned int fifo_starve;
unsigned int fifo_starve_off;
unsigned char vlan_enable:1, unsigned char vlan_enable:1,
rx_csum_enable:1, rx_csum_enable:1,
extended_hash:1; extended_hash:1,
bd_stash_en:1;
unsigned short padding; unsigned short padding;
struct vlan_group *vlgrp; struct vlan_group *vlgrp;
/* Info structure initialized by board setup code */ /* Info structure initialized by board setup code */
...@@ -731,6 +738,6 @@ extern void stop_gfar(struct net_device *dev); ...@@ -731,6 +738,6 @@ extern void stop_gfar(struct net_device *dev);
extern void gfar_halt(struct net_device *dev); extern void gfar_halt(struct net_device *dev);
extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
int enable, u32 regnum, u32 read); int enable, u32 regnum, u32 read);
void gfar_setup_stashing(struct net_device *dev); void gfar_init_sysfs(struct net_device *dev);
#endif /* __GIANFAR_H */ #endif /* __GIANFAR_H */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define MII_READ_COMMAND 0x00000001 #define MII_READ_COMMAND 0x00000001
#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \ #define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \
| SUPPORTED_10baseT_Full \
| SUPPORTED_100baseT_Half \ | SUPPORTED_100baseT_Half \
| SUPPORTED_100baseT_Full \ | SUPPORTED_100baseT_Full \
| SUPPORTED_Autoneg \ | SUPPORTED_Autoneg \
......
/*
* drivers/net/gianfar_sysfs.c
*
* Gianfar Ethernet Driver
* This driver is designed for the non-CPM ethernet controllers
* on the 85xx and 83xx family of integrated processors
* Based on 8260_io/fcc_enet.c
*
* Author: Andy Fleming
* Maintainer: Kumar Gala (kumar.gala@freescale.com)
*
* Copyright (c) 2002-2005 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* Sysfs file creation and management
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/version.h>
#include "gianfar.h"
#define GFAR_ATTR(_name) \
static ssize_t gfar_show_##_name(struct class_device *cdev, char *buf); \
static ssize_t gfar_set_##_name(struct class_device *cdev, \
const char *buf, size_t count); \
static CLASS_DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name)
#define GFAR_CREATE_FILE(_dev, _name) \
class_device_create_file(&_dev->class_dev, &class_device_attr_##_name)
GFAR_ATTR(bd_stash);
GFAR_ATTR(rx_stash_size);
GFAR_ATTR(rx_stash_index);
GFAR_ATTR(fifo_threshold);
GFAR_ATTR(fifo_starve);
GFAR_ATTR(fifo_starve_off);
#define to_net_dev(cd) container_of(cd, struct net_device, class_dev)
static ssize_t gfar_show_bd_stash(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%s\n", priv->bd_stash_en? "on" : "off");
}
static ssize_t gfar_set_bd_stash(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
int new_setting = 0;
u32 temp;
unsigned long flags;
/* Find out the new setting */
if (!strncmp("on", buf, count-1) || !strncmp("1", buf, count-1))
new_setting = 1;
else if (!strncmp("off", buf, count-1) || !strncmp("0", buf, count-1))
new_setting = 0;
else
return count;
spin_lock_irqsave(&priv->lock, flags);
/* Set the new stashing value */
priv->bd_stash_en = new_setting;
temp = gfar_read(&priv->regs->attr);
if (new_setting)
temp |= ATTR_BDSTASH;
else
temp &= ~(ATTR_BDSTASH);
gfar_write(&priv->regs->attr, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_rx_stash_size(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->rx_stash_size);
}
static ssize_t gfar_set_rx_stash_size(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
if (length > priv->rx_buffer_size)
return count;
if (length == priv->rx_stash_size)
return count;
priv->rx_stash_size = length;
temp = gfar_read(&priv->regs->attreli);
temp &= ~ATTRELI_EL_MASK;
temp |= ATTRELI_EL(length);
gfar_write(&priv->regs->attreli, temp);
/* Turn stashing on/off as appropriate */
temp = gfar_read(&priv->regs->attr);
if (length)
temp |= ATTR_BUFSTASH;
else
temp &= ~(ATTR_BUFSTASH);
gfar_write(&priv->regs->attr, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
/* Stashing will only be enabled when rx_stash_size != 0 */
static ssize_t gfar_show_rx_stash_index(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->rx_stash_index);
}
static ssize_t gfar_set_rx_stash_index(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned short index = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
if (index > priv->rx_stash_size)
return count;
if (index == priv->rx_stash_index)
return count;
priv->rx_stash_index = index;
temp = gfar_read(&priv->regs->attreli);
temp &= ~ATTRELI_EI_MASK;
temp |= ATTRELI_EI(index);
gfar_write(&priv->regs->attreli, flags);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_fifo_threshold(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->fifo_threshold);
}
static ssize_t gfar_set_fifo_threshold(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
if (length > GFAR_MAX_FIFO_THRESHOLD)
return count;
spin_lock_irqsave(&priv->lock, flags);
priv->fifo_threshold = length;
temp = gfar_read(&priv->regs->fifo_tx_thr);
temp &= ~FIFO_TX_THR_MASK;
temp |= length;
gfar_write(&priv->regs->fifo_tx_thr, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_fifo_starve(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->fifo_starve);
}
static ssize_t gfar_set_fifo_starve(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
if (num > GFAR_MAX_FIFO_STARVE)
return count;
spin_lock_irqsave(&priv->lock, flags);
priv->fifo_starve = num;
temp = gfar_read(&priv->regs->fifo_tx_starve);
temp &= ~FIFO_TX_STARVE_MASK;
temp |= num;
gfar_write(&priv->regs->fifo_tx_starve, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_fifo_starve_off(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->fifo_starve_off);
}
static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
if (num > GFAR_MAX_FIFO_STARVE_OFF)
return count;
spin_lock_irqsave(&priv->lock, flags);
priv->fifo_starve_off = num;
temp = gfar_read(&priv->regs->fifo_tx_starve_shutoff);
temp &= ~FIFO_TX_STARVE_OFF_MASK;
temp |= num;
gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
void gfar_init_sysfs(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
/* Initialize the default values */
priv->rx_stash_size = DEFAULT_STASH_LENGTH;
priv->rx_stash_index = DEFAULT_STASH_INDEX;
priv->fifo_threshold = DEFAULT_FIFO_TX_THR;
priv->fifo_starve = DEFAULT_FIFO_TX_STARVE;
priv->fifo_starve_off = DEFAULT_FIFO_TX_STARVE_OFF;
priv->bd_stash_en = DEFAULT_BD_STASH;
/* Create our sysfs files */
GFAR_CREATE_FILE(dev, bd_stash);
GFAR_CREATE_FILE(dev, rx_stash_size);
GFAR_CREATE_FILE(dev, rx_stash_index);
GFAR_CREATE_FILE(dev, fifo_threshold);
GFAR_CREATE_FILE(dev, fifo_starve);
GFAR_CREATE_FILE(dev, fifo_starve_off);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment