mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
[PATCH] Gianfar update and sysfs support
This seems to have gotten lost, so I'll resend. Signed-off-by: Andy 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: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
fed5eccdcf
commit
7f7f53168d
7 changed files with 579 additions and 112 deletions
72
Documentation/networking/gianfar.txt
Normal file
72
Documentation/networking/gianfar.txt
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
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/
|
||||||
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
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
* drivers/net/gianfar.c
|
* drivers/net/gianfar.c
|
||||||
*
|
*
|
||||||
* Gianfar Ethernet Driver
|
* Gianfar Ethernet Driver
|
||||||
* Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560
|
* 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
|
* Based on 8260_io/fcc_enet.c
|
||||||
*
|
*
|
||||||
* Author: Andy Fleming
|
* Author: Andy Fleming
|
||||||
|
@ -22,8 +23,6 @@
|
||||||
* B-V +1.62
|
* B-V +1.62
|
||||||
*
|
*
|
||||||
* Theory of operation
|
* Theory of operation
|
||||||
* This driver is designed for the non-CPM ethernet controllers
|
|
||||||
* on the 85xx and 83xx family of integrated processors
|
|
||||||
*
|
*
|
||||||
* The driver is initialized through platform_device. Structures which
|
* The driver is initialized through platform_device. Structures which
|
||||||
* define the configuration needed by the board are defined in a
|
* define the configuration needed by the board are defined in a
|
||||||
|
@ -110,7 +109,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char gfar_driver_name[] = "Gianfar Ethernet";
|
const char gfar_driver_name[] = "Gianfar Ethernet";
|
||||||
const char gfar_driver_version[] = "1.2";
|
const char gfar_driver_version[] = "1.3";
|
||||||
|
|
||||||
static int gfar_enet_open(struct net_device *dev);
|
static int gfar_enet_open(struct net_device *dev);
|
||||||
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||||
|
@ -139,6 +138,10 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int l
|
||||||
static void gfar_vlan_rx_register(struct net_device *netdev,
|
static void gfar_vlan_rx_register(struct net_device *netdev,
|
||||||
struct vlan_group *grp);
|
struct vlan_group *grp);
|
||||||
static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
|
static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
|
||||||
|
void gfar_halt(struct net_device *dev);
|
||||||
|
void gfar_start(struct net_device *dev);
|
||||||
|
static void gfar_clear_exact_match(struct net_device *dev);
|
||||||
|
static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
|
||||||
|
|
||||||
extern struct ethtool_ops gfar_ethtool_ops;
|
extern struct ethtool_ops gfar_ethtool_ops;
|
||||||
|
|
||||||
|
@ -146,12 +149,10 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
|
||||||
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
|
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
int gfar_uses_fcb(struct gfar_private *priv)
|
/* Returns 1 if incoming frames use an FCB */
|
||||||
|
static inline int gfar_uses_fcb(struct gfar_private *priv)
|
||||||
{
|
{
|
||||||
if (priv->vlan_enable || priv->rx_csum_enable)
|
return (priv->vlan_enable || priv->rx_csum_enable);
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up the ethernet device structure, private data,
|
/* Set up the ethernet device structure, private data,
|
||||||
|
@ -320,15 +321,10 @@ static int gfar_probe(struct platform_device *pdev)
|
||||||
else
|
else
|
||||||
priv->padding = 0;
|
priv->padding = 0;
|
||||||
|
|
||||||
dev->hard_header_len += priv->padding;
|
|
||||||
|
|
||||||
if (dev->features & NETIF_F_IP_CSUM)
|
if (dev->features & NETIF_F_IP_CSUM)
|
||||||
dev->hard_header_len += GMAC_FCB_LEN;
|
dev->hard_header_len += GMAC_FCB_LEN;
|
||||||
|
|
||||||
priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
|
priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
|
||||||
#ifdef CONFIG_GFAR_BUFSTASH
|
|
||||||
priv->rx_stash_size = STASH_LENGTH;
|
|
||||||
#endif
|
|
||||||
priv->tx_ring_size = DEFAULT_TX_RING_SIZE;
|
priv->tx_ring_size = DEFAULT_TX_RING_SIZE;
|
||||||
priv->rx_ring_size = DEFAULT_RX_RING_SIZE;
|
priv->rx_ring_size = DEFAULT_RX_RING_SIZE;
|
||||||
|
|
||||||
|
@ -350,6 +346,9 @@ static int gfar_probe(struct platform_device *pdev)
|
||||||
goto register_fail;
|
goto register_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create all the sysfs files */
|
||||||
|
gfar_init_sysfs(dev);
|
||||||
|
|
||||||
/* Print out the device info */
|
/* Print out the device info */
|
||||||
printk(KERN_INFO DEVICE_NAME, dev->name);
|
printk(KERN_INFO DEVICE_NAME, dev->name);
|
||||||
for (idx = 0; idx < 6; idx++)
|
for (idx = 0; idx < 6; idx++)
|
||||||
|
@ -357,8 +356,7 @@ static int gfar_probe(struct platform_device *pdev)
|
||||||
printk("\n");
|
printk("\n");
|
||||||
|
|
||||||
/* Even more device info helps when determining which kernel */
|
/* Even more device info helps when determining which kernel */
|
||||||
/* provided which set of benchmarks. Since this is global for all */
|
/* provided which set of benchmarks. */
|
||||||
/* devices, we only print it once */
|
|
||||||
#ifdef CONFIG_GFAR_NAPI
|
#ifdef CONFIG_GFAR_NAPI
|
||||||
printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name);
|
printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name);
|
||||||
#else
|
#else
|
||||||
|
@ -463,19 +461,9 @@ static void init_registers(struct net_device *dev)
|
||||||
/* Initialize the max receive buffer length */
|
/* Initialize the max receive buffer length */
|
||||||
gfar_write(&priv->regs->mrblr, priv->rx_buffer_size);
|
gfar_write(&priv->regs->mrblr, priv->rx_buffer_size);
|
||||||
|
|
||||||
#ifdef CONFIG_GFAR_BUFSTASH
|
|
||||||
/* If we are stashing buffers, we need to set the
|
|
||||||
* extraction length to the size of the buffer */
|
|
||||||
gfar_write(&priv->regs->attreli, priv->rx_stash_size << 16);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Initialize the Minimum Frame Length Register */
|
/* Initialize the Minimum Frame Length Register */
|
||||||
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
|
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
|
||||||
|
|
||||||
/* Setup Attributes so that snooping is on for rx */
|
|
||||||
gfar_write(&priv->regs->attr, ATTR_INIT_SETTINGS);
|
|
||||||
gfar_write(&priv->regs->attreli, ATTRELI_INIT_SETTINGS);
|
|
||||||
|
|
||||||
/* Assign the TBI an address which won't conflict with the PHYs */
|
/* Assign the TBI an address which won't conflict with the PHYs */
|
||||||
gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
|
gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
|
||||||
}
|
}
|
||||||
|
@ -577,8 +565,7 @@ static void free_skb_resources(struct gfar_private *priv)
|
||||||
for (i = 0; i < priv->rx_ring_size; i++) {
|
for (i = 0; i < priv->rx_ring_size; i++) {
|
||||||
if (priv->rx_skbuff[i]) {
|
if (priv->rx_skbuff[i]) {
|
||||||
dma_unmap_single(NULL, rxbdp->bufPtr,
|
dma_unmap_single(NULL, rxbdp->bufPtr,
|
||||||
priv->rx_buffer_size
|
priv->rx_buffer_size,
|
||||||
+ RXBUF_ALIGNMENT,
|
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
|
|
||||||
dev_kfree_skb_any(priv->rx_skbuff[i]);
|
dev_kfree_skb_any(priv->rx_skbuff[i]);
|
||||||
|
@ -636,6 +623,7 @@ int startup_gfar(struct net_device *dev)
|
||||||
struct gfar *regs = priv->regs;
|
struct gfar *regs = priv->regs;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u32 rctrl = 0;
|
u32 rctrl = 0;
|
||||||
|
u32 attrs = 0;
|
||||||
|
|
||||||
gfar_write(®s->imask, IMASK_INIT_CLEAR);
|
gfar_write(®s->imask, IMASK_INIT_CLEAR);
|
||||||
|
|
||||||
|
@ -795,18 +783,50 @@ int startup_gfar(struct net_device *dev)
|
||||||
if (priv->rx_csum_enable)
|
if (priv->rx_csum_enable)
|
||||||
rctrl |= RCTRL_CHECKSUMMING;
|
rctrl |= RCTRL_CHECKSUMMING;
|
||||||
|
|
||||||
if (priv->extended_hash)
|
if (priv->extended_hash) {
|
||||||
rctrl |= RCTRL_EXTHASH;
|
rctrl |= RCTRL_EXTHASH;
|
||||||
|
|
||||||
|
gfar_clear_exact_match(dev);
|
||||||
|
rctrl |= RCTRL_EMEN;
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->vlan_enable)
|
if (priv->vlan_enable)
|
||||||
rctrl |= RCTRL_VLAN;
|
rctrl |= RCTRL_VLAN;
|
||||||
|
|
||||||
|
if (priv->padding) {
|
||||||
|
rctrl &= ~RCTRL_PAL_MASK;
|
||||||
|
rctrl |= RCTRL_PADDING(priv->padding);
|
||||||
|
}
|
||||||
|
|
||||||
/* Init rctrl based on our settings */
|
/* Init rctrl based on our settings */
|
||||||
gfar_write(&priv->regs->rctrl, rctrl);
|
gfar_write(&priv->regs->rctrl, rctrl);
|
||||||
|
|
||||||
if (dev->features & NETIF_F_IP_CSUM)
|
if (dev->features & NETIF_F_IP_CSUM)
|
||||||
gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
|
gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
|
||||||
|
|
||||||
|
/* Set the extraction length and index */
|
||||||
|
attrs = ATTRELI_EL(priv->rx_stash_size) |
|
||||||
|
ATTRELI_EI(priv->rx_stash_index);
|
||||||
|
|
||||||
|
gfar_write(&priv->regs->attreli, attrs);
|
||||||
|
|
||||||
|
/* Start with defaults, and add stashing or locking
|
||||||
|
* depending on the approprate variables */
|
||||||
|
attrs = ATTR_INIT_SETTINGS;
|
||||||
|
|
||||||
|
if (priv->bd_stash_en)
|
||||||
|
attrs |= ATTR_BDSTASH;
|
||||||
|
|
||||||
|
if (priv->rx_stash_size != 0)
|
||||||
|
attrs |= ATTR_BUFSTASH;
|
||||||
|
|
||||||
|
gfar_write(&priv->regs->attr, attrs);
|
||||||
|
|
||||||
|
gfar_write(&priv->regs->fifo_tx_thr, priv->fifo_threshold);
|
||||||
|
gfar_write(&priv->regs->fifo_tx_starve, priv->fifo_starve);
|
||||||
|
gfar_write(&priv->regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
|
||||||
|
|
||||||
|
/* Start the controller */
|
||||||
gfar_start(dev);
|
gfar_start(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -851,34 +871,32 @@ static int gfar_enet_open(struct net_device *dev)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
|
static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
|
||||||
{
|
{
|
||||||
struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
|
struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
|
||||||
|
|
||||||
memset(fcb, 0, GMAC_FCB_LEN);
|
memset(fcb, 0, GMAC_FCB_LEN);
|
||||||
|
|
||||||
/* Flag the bd so the controller looks for the FCB */
|
|
||||||
bdp->status |= TXBD_TOE;
|
|
||||||
|
|
||||||
return fcb;
|
return fcb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
|
static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
|
||||||
{
|
{
|
||||||
int len;
|
u8 flags = 0;
|
||||||
|
|
||||||
/* If we're here, it's a IP packet with a TCP or UDP
|
/* If we're here, it's a IP packet with a TCP or UDP
|
||||||
* payload. We set it to checksum, using a pseudo-header
|
* payload. We set it to checksum, using a pseudo-header
|
||||||
* we provide
|
* we provide
|
||||||
*/
|
*/
|
||||||
fcb->ip = 1;
|
flags = TXFCB_DEFAULT;
|
||||||
fcb->tup = 1;
|
|
||||||
fcb->ctu = 1;
|
|
||||||
fcb->nph = 1;
|
|
||||||
|
|
||||||
/* Notify the controller what the protocol is */
|
/* Tell the controller what the protocol is */
|
||||||
if (skb->nh.iph->protocol == IPPROTO_UDP)
|
/* And provide the already calculated phcs */
|
||||||
fcb->udp = 1;
|
if (skb->nh.iph->protocol == IPPROTO_UDP) {
|
||||||
|
flags |= TXFCB_UDP;
|
||||||
|
fcb->phcs = skb->h.uh->check;
|
||||||
|
} else
|
||||||
|
fcb->phcs = skb->h.th->check;
|
||||||
|
|
||||||
/* l3os is the distance between the start of the
|
/* l3os is the distance between the start of the
|
||||||
* frame (skb->data) and the start of the IP hdr.
|
* frame (skb->data) and the start of the IP hdr.
|
||||||
|
@ -887,17 +905,12 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
|
||||||
fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
|
fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
|
||||||
fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
|
fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
|
||||||
|
|
||||||
len = skb->nh.iph->tot_len - fcb->l4os;
|
fcb->flags = flags;
|
||||||
|
|
||||||
/* Provide the pseudoheader csum */
|
|
||||||
fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
|
|
||||||
skb->nh.iph->daddr, len,
|
|
||||||
skb->nh.iph->protocol, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
|
void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
|
||||||
{
|
{
|
||||||
fcb->vln = 1;
|
fcb->flags |= TXFCB_VLN;
|
||||||
fcb->vlctl = vlan_tx_tag_get(skb);
|
fcb->vlctl = vlan_tx_tag_get(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -908,6 +921,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
struct txfcb *fcb = NULL;
|
struct txfcb *fcb = NULL;
|
||||||
struct txbd8 *txbdp;
|
struct txbd8 *txbdp;
|
||||||
|
u16 status;
|
||||||
|
|
||||||
/* Update transmit stats */
|
/* Update transmit stats */
|
||||||
priv->stats.tx_bytes += skb->len;
|
priv->stats.tx_bytes += skb->len;
|
||||||
|
@ -919,19 +933,22 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
txbdp = priv->cur_tx;
|
txbdp = priv->cur_tx;
|
||||||
|
|
||||||
/* Clear all but the WRAP status flags */
|
/* Clear all but the WRAP status flags */
|
||||||
txbdp->status &= TXBD_WRAP;
|
status = txbdp->status & TXBD_WRAP;
|
||||||
|
|
||||||
/* Set up checksumming */
|
/* Set up checksumming */
|
||||||
if ((dev->features & NETIF_F_IP_CSUM)
|
if (likely((dev->features & NETIF_F_IP_CSUM)
|
||||||
&& (CHECKSUM_HW == skb->ip_summed)) {
|
&& (CHECKSUM_HW == skb->ip_summed))) {
|
||||||
fcb = gfar_add_fcb(skb, txbdp);
|
fcb = gfar_add_fcb(skb, txbdp);
|
||||||
|
status |= TXBD_TOE;
|
||||||
gfar_tx_checksum(skb, fcb);
|
gfar_tx_checksum(skb, fcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->vlan_enable &&
|
if (priv->vlan_enable &&
|
||||||
unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
|
unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
|
||||||
if (NULL == fcb)
|
if (unlikely(NULL == fcb)) {
|
||||||
fcb = gfar_add_fcb(skb, txbdp);
|
fcb = gfar_add_fcb(skb, txbdp);
|
||||||
|
status |= TXBD_TOE;
|
||||||
|
}
|
||||||
|
|
||||||
gfar_tx_vlan(skb, fcb);
|
gfar_tx_vlan(skb, fcb);
|
||||||
}
|
}
|
||||||
|
@ -949,14 +966,16 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
(priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size);
|
(priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size);
|
||||||
|
|
||||||
/* Flag the BD as interrupt-causing */
|
/* Flag the BD as interrupt-causing */
|
||||||
txbdp->status |= TXBD_INTERRUPT;
|
status |= TXBD_INTERRUPT;
|
||||||
|
|
||||||
/* Flag the BD as ready to go, last in frame, and */
|
/* Flag the BD as ready to go, last in frame, and */
|
||||||
/* in need of CRC */
|
/* in need of CRC */
|
||||||
txbdp->status |= (TXBD_READY | TXBD_LAST | TXBD_CRC);
|
status |= (TXBD_READY | TXBD_LAST | TXBD_CRC);
|
||||||
|
|
||||||
dev->trans_start = jiffies;
|
dev->trans_start = jiffies;
|
||||||
|
|
||||||
|
txbdp->status = status;
|
||||||
|
|
||||||
/* If this was the last BD in the ring, the next one */
|
/* If this was the last BD in the ring, the next one */
|
||||||
/* is at the beginning of the ring */
|
/* is at the beginning of the ring */
|
||||||
if (txbdp->status & TXBD_WRAP)
|
if (txbdp->status & TXBD_WRAP)
|
||||||
|
@ -1010,21 +1029,7 @@ static struct net_device_stats * gfar_get_stats(struct net_device *dev)
|
||||||
/* Changes the mac address if the controller is not running. */
|
/* Changes the mac address if the controller is not running. */
|
||||||
int gfar_set_mac_address(struct net_device *dev)
|
int gfar_set_mac_address(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
|
||||||
int i;
|
|
||||||
char tmpbuf[MAC_ADDR_LEN];
|
|
||||||
u32 tempval;
|
|
||||||
|
|
||||||
/* Now copy it into the mac registers backwards, cuz */
|
|
||||||
/* little endian is silly */
|
|
||||||
for (i = 0; i < MAC_ADDR_LEN; i++)
|
|
||||||
tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->dev_addr[i];
|
|
||||||
|
|
||||||
gfar_write(&priv->regs->macstnaddr1, *((u32 *) (tmpbuf)));
|
|
||||||
|
|
||||||
tempval = *((u32 *) (tmpbuf + 4));
|
|
||||||
|
|
||||||
gfar_write(&priv->regs->macstnaddr2, tempval);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1110,7 +1115,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
INCREMENTAL_BUFFER_SIZE;
|
INCREMENTAL_BUFFER_SIZE;
|
||||||
|
|
||||||
/* Only stop and start the controller if it isn't already
|
/* Only stop and start the controller if it isn't already
|
||||||
* stopped */
|
* stopped, and we changed something */
|
||||||
if ((oldsize != tempsize) && (dev->flags & IFF_UP))
|
if ((oldsize != tempsize) && (dev->flags & IFF_UP))
|
||||||
stop_gfar(dev);
|
stop_gfar(dev);
|
||||||
|
|
||||||
|
@ -1220,6 +1225,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
|
|
||||||
struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
|
struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
|
||||||
{
|
{
|
||||||
|
unsigned int alignamount;
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
struct sk_buff *skb = NULL;
|
struct sk_buff *skb = NULL;
|
||||||
unsigned int timeout = SKB_ALLOC_TIMEOUT;
|
unsigned int timeout = SKB_ALLOC_TIMEOUT;
|
||||||
|
@ -1231,18 +1237,18 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
|
||||||
if (NULL == skb)
|
if (NULL == skb)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
alignamount = RXBUF_ALIGNMENT -
|
||||||
|
(((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1));
|
||||||
|
|
||||||
/* We need the data buffer to be aligned properly. We will reserve
|
/* We need the data buffer to be aligned properly. We will reserve
|
||||||
* as many bytes as needed to align the data properly
|
* as many bytes as needed to align the data properly
|
||||||
*/
|
*/
|
||||||
skb_reserve(skb,
|
skb_reserve(skb, alignamount);
|
||||||
RXBUF_ALIGNMENT -
|
|
||||||
(((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1)));
|
|
||||||
|
|
||||||
skb->dev = dev;
|
skb->dev = dev;
|
||||||
|
|
||||||
bdp->bufPtr = dma_map_single(NULL, skb->data,
|
bdp->bufPtr = dma_map_single(NULL, skb->data,
|
||||||
priv->rx_buffer_size + RXBUF_ALIGNMENT,
|
priv->rx_buffer_size, DMA_FROM_DEVICE);
|
||||||
DMA_FROM_DEVICE);
|
|
||||||
|
|
||||||
bdp->length = 0;
|
bdp->length = 0;
|
||||||
|
|
||||||
|
@ -1350,7 +1356,7 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
|
||||||
/* If valid headers were found, and valid sums
|
/* If valid headers were found, and valid sums
|
||||||
* were verified, then we tell the kernel that no
|
* were verified, then we tell the kernel that no
|
||||||
* checksumming is necessary. Otherwise, it is */
|
* checksumming is necessary. Otherwise, it is */
|
||||||
if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
|
if ((fcb->flags & RXFCB_CSUM_MASK) == (RXFCB_CIP | RXFCB_CTU))
|
||||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||||
else
|
else
|
||||||
skb->ip_summed = CHECKSUM_NONE;
|
skb->ip_summed = CHECKSUM_NONE;
|
||||||
|
@ -1401,7 +1407,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
|
||||||
skb->protocol = eth_type_trans(skb, dev);
|
skb->protocol = eth_type_trans(skb, dev);
|
||||||
|
|
||||||
/* Send the packet up the stack */
|
/* Send the packet up the stack */
|
||||||
if (unlikely(priv->vlgrp && fcb->vln))
|
if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN)))
|
||||||
ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
|
ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
|
||||||
else
|
else
|
||||||
ret = RECEIVE(skb);
|
ret = RECEIVE(skb);
|
||||||
|
@ -1620,6 +1626,7 @@ static void adjust_link(struct net_device *dev)
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
if (phydev->link) {
|
if (phydev->link) {
|
||||||
u32 tempval = gfar_read(®s->maccfg2);
|
u32 tempval = gfar_read(®s->maccfg2);
|
||||||
|
u32 ecntrl = gfar_read(®s->ecntrl);
|
||||||
|
|
||||||
/* Now we make sure that we can be in full duplex mode.
|
/* Now we make sure that we can be in full duplex mode.
|
||||||
* If not, we operate in half-duplex mode. */
|
* If not, we operate in half-duplex mode. */
|
||||||
|
@ -1644,6 +1651,13 @@ static void adjust_link(struct net_device *dev)
|
||||||
case 10:
|
case 10:
|
||||||
tempval =
|
tempval =
|
||||||
((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
|
((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
|
||||||
|
|
||||||
|
/* Reduced mode distinguishes
|
||||||
|
* between 10 and 100 */
|
||||||
|
if (phydev->speed == SPEED_100)
|
||||||
|
ecntrl |= ECNTRL_R100;
|
||||||
|
else
|
||||||
|
ecntrl &= ~(ECNTRL_R100);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (netif_msg_link(priv))
|
if (netif_msg_link(priv))
|
||||||
|
@ -1657,6 +1671,7 @@ static void adjust_link(struct net_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
gfar_write(®s->maccfg2, tempval);
|
gfar_write(®s->maccfg2, tempval);
|
||||||
|
gfar_write(®s->ecntrl, ecntrl);
|
||||||
|
|
||||||
if (!priv->oldlink) {
|
if (!priv->oldlink) {
|
||||||
new_state = 1;
|
new_state = 1;
|
||||||
|
@ -1721,6 +1736,9 @@ static void gfar_set_multi(struct net_device *dev)
|
||||||
gfar_write(®s->gaddr6, 0xffffffff);
|
gfar_write(®s->gaddr6, 0xffffffff);
|
||||||
gfar_write(®s->gaddr7, 0xffffffff);
|
gfar_write(®s->gaddr7, 0xffffffff);
|
||||||
} else {
|
} else {
|
||||||
|
int em_num;
|
||||||
|
int idx;
|
||||||
|
|
||||||
/* zero out the hash */
|
/* zero out the hash */
|
||||||
gfar_write(®s->igaddr0, 0x0);
|
gfar_write(®s->igaddr0, 0x0);
|
||||||
gfar_write(®s->igaddr1, 0x0);
|
gfar_write(®s->igaddr1, 0x0);
|
||||||
|
@ -1739,18 +1757,47 @@ static void gfar_set_multi(struct net_device *dev)
|
||||||
gfar_write(®s->gaddr6, 0x0);
|
gfar_write(®s->gaddr6, 0x0);
|
||||||
gfar_write(®s->gaddr7, 0x0);
|
gfar_write(®s->gaddr7, 0x0);
|
||||||
|
|
||||||
|
/* If we have extended hash tables, we need to
|
||||||
|
* clear the exact match registers to prepare for
|
||||||
|
* setting them */
|
||||||
|
if (priv->extended_hash) {
|
||||||
|
em_num = GFAR_EM_NUM + 1;
|
||||||
|
gfar_clear_exact_match(dev);
|
||||||
|
idx = 1;
|
||||||
|
} else {
|
||||||
|
idx = 0;
|
||||||
|
em_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(dev->mc_count == 0)
|
if(dev->mc_count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Parse the list, and set the appropriate bits */
|
/* Parse the list, and set the appropriate bits */
|
||||||
for(mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
|
for(mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
|
||||||
gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr);
|
if (idx < em_num) {
|
||||||
|
gfar_set_mac_for_addr(dev, idx,
|
||||||
|
mc_ptr->dmi_addr);
|
||||||
|
idx++;
|
||||||
|
} else
|
||||||
|
gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Clears each of the exact match registers to zero, so they
|
||||||
|
* don't interfere with normal reception */
|
||||||
|
static void gfar_clear_exact_match(struct net_device *dev)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
u8 zero_arr[MAC_ADDR_LEN] = {0,0,0,0,0,0};
|
||||||
|
|
||||||
|
for(idx = 1;idx < GFAR_EM_NUM + 1;idx++)
|
||||||
|
gfar_set_mac_for_addr(dev, idx, (u8 *)zero_arr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the appropriate hash bit for the given addr */
|
/* Set the appropriate hash bit for the given addr */
|
||||||
/* The algorithm works like so:
|
/* The algorithm works like so:
|
||||||
* 1) Take the Destination Address (ie the multicast address), and
|
* 1) Take the Destination Address (ie the multicast address), and
|
||||||
|
@ -1781,6 +1828,32 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* There are multiple MAC Address register pairs on some controllers
|
||||||
|
* This function sets the numth pair to a given address
|
||||||
|
*/
|
||||||
|
static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
|
||||||
|
{
|
||||||
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
|
int idx;
|
||||||
|
char tmpbuf[MAC_ADDR_LEN];
|
||||||
|
u32 tempval;
|
||||||
|
u32 *macptr = &priv->regs->macstnaddr1;
|
||||||
|
|
||||||
|
macptr += num*2;
|
||||||
|
|
||||||
|
/* Now copy it into the mac registers backwards, cuz */
|
||||||
|
/* little endian is silly */
|
||||||
|
for (idx = 0; idx < MAC_ADDR_LEN; idx++)
|
||||||
|
tmpbuf[MAC_ADDR_LEN - 1 - idx] = addr[idx];
|
||||||
|
|
||||||
|
gfar_write(macptr, *((u32 *) (tmpbuf)));
|
||||||
|
|
||||||
|
tempval = *((u32 *) (tmpbuf + 4));
|
||||||
|
|
||||||
|
gfar_write(macptr+1, tempval);
|
||||||
|
}
|
||||||
|
|
||||||
/* GFAR error interrupt handler */
|
/* GFAR error interrupt handler */
|
||||||
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
|
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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[];
|
||||||
|
|
||||||
#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[];
|
||||||
|
|
||||||
#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[];
|
||||||
#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[];
|
||||||
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[];
|
||||||
#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
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
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 {
|
||||||
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);
|
||||||
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 */
|
||||||
|
|
|
@ -125,7 +125,7 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
|
||||||
static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
|
static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
|
|
||||||
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
|
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
|
||||||
memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
|
memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
|
||||||
else
|
else
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
311
drivers/net/gianfar_sysfs.c
Normal file
311
drivers/net/gianfar_sysfs.c
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue