Commit 1caf73f0 authored by Jeff Garzik's avatar Jeff Garzik

Update 8139cp net driver for the following:

* Merge VLAN defines and support from vger, ifdef'd out until
  API appears in main tree.
* Support RX checksumming.
* Correct CP_MAX_MTU.
* Clarify CP_MIN_MTU issues.
parent 03789917
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* /*
Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com>
Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c]
Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c] Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
Copyright 2001 Manfred Spraul [natsemi.c] Copyright 2001 Manfred Spraul [natsemi.c]
Copyright 1999-2001 by Donald Becker. [natsemi.c] Copyright 1999-2001 by Donald Becker. [natsemi.c]
...@@ -29,8 +30,8 @@ ...@@ -29,8 +30,8 @@
* Consider Rx interrupt mitigation using TimerIntr * Consider Rx interrupt mitigation using TimerIntr
* Implement 8139C+ statistics dump; maybe not... * Implement 8139C+ statistics dump; maybe not...
h/w stats can be reset only by software reset h/w stats can be reset only by software reset
* Rx checksumming
* Tx checksumming * Tx checksumming
* Handle netif_rx return value
* ETHTOOL_GREGS, ETHTOOL_[GS]WOL, * ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
* Investigate using skb->priority with h/w VLAN priority * Investigate using skb->priority with h/w VLAN priority
* Investigate using High Priority Tx Queue with skb->priority * Investigate using High Priority Tx Queue with skb->priority
...@@ -38,8 +39,8 @@ ...@@ -38,8 +39,8 @@
* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error * Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
* Implement Tx software interrupt mitigation via * Implement Tx software interrupt mitigation via
Tx descriptor bit Tx descriptor bit
* Determine correct value for CP_{MIN,MAX}_MTU, instead of * The real minimum of CP_MIN_MTU is 4 bytes. However,
using conservative guesses. for this to be supported, one must(?) turn on packet padding.
*/ */
...@@ -48,8 +49,10 @@ ...@@ -48,8 +49,10 @@
#define DRV_RELDATE "Feb 27, 2002" #define DRV_RELDATE "Feb 27, 2002"
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -57,9 +60,15 @@ ...@@ -57,9 +60,15 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/crc32.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define CP_VLAN_TAG_USED 0
#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
do { (tx_desc)->opts2 = 0; } while (0)
/* These identify the driver base version and may not be removed. */ /* These identify the driver base version and may not be removed. */
static char version[] __devinitdata = static char version[] __devinitdata =
KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
...@@ -110,8 +119,8 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered mul ...@@ -110,8 +119,8 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered mul
#define TX_TIMEOUT (6*HZ) #define TX_TIMEOUT (6*HZ)
/* hardware minimum and maximum for a single frame's data payload */ /* hardware minimum and maximum for a single frame's data payload */
#define CP_MIN_MTU 60 /* FIXME: this is a guess */ #define CP_MIN_MTU 60 /* TODO: allow lower, but pad */
#define CP_MAX_MTU 1500 /* FIXME: this is a guess */ #define CP_MAX_MTU 4096
enum { enum {
/* NIC register offsets */ /* NIC register offsets */
...@@ -153,12 +162,17 @@ enum { ...@@ -153,12 +162,17 @@ enum {
IPCS = (1 << 18), /* Calculate IP checksum */ IPCS = (1 << 18), /* Calculate IP checksum */
UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ UDPCS = (1 << 17), /* Calculate UDP/IP checksum */
TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ TCPCS = (1 << 16), /* Calculate TCP/IP checksum */
TxVlanTag = (1 << 17), /* Add VLAN tag */
RxVlanTagged = (1 << 16), /* Rx VLAN tag available */
IPFail = (1 << 15), /* IP checksum failed */ IPFail = (1 << 15), /* IP checksum failed */
UDPFail = (1 << 14), /* UDP/IP checksum failed */ UDPFail = (1 << 14), /* UDP/IP checksum failed */
TCPFail = (1 << 13), /* TCP/IP checksum failed */ TCPFail = (1 << 13), /* TCP/IP checksum failed */
NormalTxPoll = (1 << 6), /* One or more normal Tx packets to send */ NormalTxPoll = (1 << 6), /* One or more normal Tx packets to send */
PID1 = (1 << 17), /* 2 protocol id bits: 0==non-IP, */ PID1 = (1 << 17), /* 2 protocol id bits: 0==non-IP, */
PID0 = (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */ PID0 = (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
RxProtoTCP = 2,
RxProtoUDP = 1,
RxProtoIP = 3,
TxFIFOUnder = (1 << 25), /* Tx FIFO underrun */ TxFIFOUnder = (1 << 25), /* Tx FIFO underrun */
TxOWC = (1 << 22), /* Tx Out-of-window collision */ TxOWC = (1 << 22), /* Tx Out-of-window collision */
TxLinkFail = (1 << 21), /* Link failed during Tx of packet */ TxLinkFail = (1 << 21), /* Link failed during Tx of packet */
...@@ -208,6 +222,7 @@ enum { ...@@ -208,6 +222,7 @@ enum {
TxOn = (1 << 2), /* Tx mode enable */ TxOn = (1 << 2), /* Tx mode enable */
/* C+ mode command register */ /* C+ mode command register */
RxVlanOn = (1 << 6), /* Rx VLAN de-tagging enable */
RxChkSum = (1 << 5), /* Rx checksum offload enable */ RxChkSum = (1 << 5), /* Rx checksum offload enable */
PCIMulRW = (1 << 3), /* Enable PCI read/write multiple */ PCIMulRW = (1 << 3), /* Enable PCI read/write multiple */
CpRxOn = (1 << 1), /* Rx mode enable */ CpRxOn = (1 << 1), /* Rx mode enable */
...@@ -278,6 +293,10 @@ struct cp_private { ...@@ -278,6 +293,10 @@ struct cp_private {
unsigned rx_buf_sz; unsigned rx_buf_sz;
dma_addr_t ring_dma; dma_addr_t ring_dma;
#if CP_VLAN_TAG_USED
struct vlan_group *vlgrp;
#endif
u32 msg_enable; u32 msg_enable;
struct net_device_stats net_stats; struct net_device_stats net_stats;
...@@ -335,14 +354,21 @@ static inline void cp_set_rxbufsize (struct cp_private *cp) ...@@ -335,14 +354,21 @@ static inline void cp_set_rxbufsize (struct cp_private *cp)
cp->rx_buf_sz = PKT_BUF_SZ; cp->rx_buf_sz = PKT_BUF_SZ;
} }
static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb) static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
struct cp_desc *desc)
{ {
skb->protocol = eth_type_trans (skb, cp->dev); skb->protocol = eth_type_trans (skb, cp->dev);
cp->net_stats.rx_packets++; cp->net_stats.rx_packets++;
cp->net_stats.rx_bytes += skb->len; cp->net_stats.rx_bytes += skb->len;
cp->dev->last_rx = jiffies; cp->dev->last_rx = jiffies;
netif_rx (skb);
#if CP_VLAN_TAG_USED
if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {
vlan_hwaccel_rx(skb, cp->vlgrp, desc->opts2 & 0xffff);
} else
#endif
netif_rx(skb);
} }
static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail, static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
...@@ -425,13 +451,26 @@ static void cp_rx_frag (struct cp_private *cp, unsigned rx_tail, ...@@ -425,13 +451,26 @@ static void cp_rx_frag (struct cp_private *cp, unsigned rx_tail,
cp_rx_err_acct(cp, rx_tail, status, len); cp_rx_err_acct(cp, rx_tail, status, len);
dev_kfree_skb_irq(copy_skb); dev_kfree_skb_irq(copy_skb);
} else } else
cp_rx_skb(cp, copy_skb); cp_rx_skb(cp, copy_skb, &cp->rx_ring[rx_tail]);
cp->frag_skb = NULL; cp->frag_skb = NULL;
} else { } else {
cp->frag_skb = copy_skb; cp->frag_skb = copy_skb;
} }
} }
static inline unsigned int cp_rx_csum_ok (u32 status)
{
unsigned int protocol = (status >> 16) & 0x3;
if (likely((protocol == RxProtoTCP) && (!(status & TCPFail))))
return 1;
else if ((protocol == RxProtoUDP) && (!(status & UDPFail)))
return 1;
else if ((protocol == RxProtoIP) && (!(status & IPFail)))
return 1;
return 0;
}
static void cp_rx (struct cp_private *cp) static void cp_rx (struct cp_private *cp)
{ {
unsigned rx_tail = cp->rx_tail; unsigned rx_tail = cp->rx_tail;
...@@ -441,13 +480,15 @@ static void cp_rx (struct cp_private *cp) ...@@ -441,13 +480,15 @@ static void cp_rx (struct cp_private *cp)
u32 status, len; u32 status, len;
dma_addr_t mapping; dma_addr_t mapping;
struct sk_buff *skb, *new_skb; struct sk_buff *skb, *new_skb;
struct cp_desc *desc;
unsigned buflen; unsigned buflen;
skb = cp->rx_skb[rx_tail].skb; skb = cp->rx_skb[rx_tail].skb;
if (!skb) if (!skb)
BUG(); BUG();
rmb();
status = le32_to_cpu(cp->rx_ring[rx_tail].opts1); desc = &cp->rx_ring[rx_tail];
status = le32_to_cpu(desc->opts1);
if (status & DescOwn) if (status & DescOwn)
break; break;
...@@ -480,7 +521,13 @@ static void cp_rx (struct cp_private *cp) ...@@ -480,7 +521,13 @@ static void cp_rx (struct cp_private *cp)
pci_unmap_single(cp->pdev, mapping, pci_unmap_single(cp->pdev, mapping,
buflen, PCI_DMA_FROMDEVICE); buflen, PCI_DMA_FROMDEVICE);
skb->ip_summed = CHECKSUM_NONE;
/* Handle checksum offloading for incoming packets. */
if (cp_rx_csum_ok(status))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
skb_put(skb, len); skb_put(skb, len);
mapping = mapping =
...@@ -489,15 +536,14 @@ static void cp_rx (struct cp_private *cp) ...@@ -489,15 +536,14 @@ static void cp_rx (struct cp_private *cp)
buflen, PCI_DMA_FROMDEVICE); buflen, PCI_DMA_FROMDEVICE);
cp->rx_skb[rx_tail].skb = new_skb; cp->rx_skb[rx_tail].skb = new_skb;
cp_rx_skb(cp, skb); cp_rx_skb(cp, skb, desc);
rx_next: rx_next:
if (rx_tail == (CP_RX_RING_SIZE - 1)) if (rx_tail == (CP_RX_RING_SIZE - 1))
cp->rx_ring[rx_tail].opts1 = desc->opts1 = cpu_to_le32(DescOwn | RingEnd |
cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz); cp->rx_buf_sz);
else else
cp->rx_ring[rx_tail].opts1 = desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
cpu_to_le32(DescOwn | cp->rx_buf_sz);
cp->rx_ring[rx_tail].opts2 = 0; cp->rx_ring[rx_tail].opts2 = 0;
cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping); cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping);
rx_tail = NEXT_RX(rx_tail); rx_tail = NEXT_RX(rx_tail);
...@@ -606,6 +652,9 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -606,6 +652,9 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
struct cp_private *cp = dev->priv; struct cp_private *cp = dev->priv;
unsigned entry; unsigned entry;
u32 eor; u32 eor;
#if CP_VLAN_TAG_USED
u32 vlan_tag = 0;
#endif
spin_lock_irq(&cp->lock); spin_lock_irq(&cp->lock);
...@@ -615,6 +664,11 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -615,6 +664,11 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
return 1; return 1;
} }
#if CP_VLAN_TAG_USED
if (cp->vlgrp && vlan_tx_tag_present(skb))
vlan_tag = TxVlanTag | vlan_tx_tag_get(skb);
#endif
entry = cp->tx_head; entry = cp->tx_head;
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
if (skb_shinfo(skb)->nr_frags == 0) { if (skb_shinfo(skb)->nr_frags == 0) {
...@@ -624,7 +678,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -624,7 +678,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
len = skb->len; len = skb->len;
mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE); mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
txd->opts2 = 0; CP_VLAN_TX_TAG(txd, vlan_tag);
txd->addr_lo = cpu_to_le32(mapping); txd->addr_lo = cpu_to_le32(mapping);
wmb(); wmb();
...@@ -677,7 +731,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -677,7 +731,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
ctrl |= LastFrag; ctrl |= LastFrag;
txd = &cp->tx_ring[entry]; txd = &cp->tx_ring[entry];
txd->opts2 = 0; CP_VLAN_TX_TAG(txd, vlan_tag);
txd->addr_lo = cpu_to_le32(mapping); txd->addr_lo = cpu_to_le32(mapping);
wmb(); wmb();
...@@ -691,7 +745,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) ...@@ -691,7 +745,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
} }
txd = &cp->tx_ring[first_entry]; txd = &cp->tx_ring[first_entry];
txd->opts2 = 0; CP_VLAN_TX_TAG(txd, vlan_tag);
txd->addr_lo = cpu_to_le32(first_mapping); txd->addr_lo = cpu_to_le32(first_mapping);
wmb(); wmb();
...@@ -826,7 +880,7 @@ static void cp_reset_hw (struct cp_private *cp) ...@@ -826,7 +880,7 @@ static void cp_reset_hw (struct cp_private *cp)
static inline void cp_start_hw (struct cp_private *cp) static inline void cp_start_hw (struct cp_private *cp)
{ {
cpw8(Cmd, RxOn | TxOn); cpw8(Cmd, RxOn | TxOn);
cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn); cpw16(CpCmd, PCIMulRW | RxChkSum | CpRxOn | CpTxOn);
} }
static void cp_init_hw (struct cp_private *cp) static void cp_init_hw (struct cp_private *cp)
...@@ -1171,7 +1225,30 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1171,7 +1225,30 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
return rc; return rc;
} }
#if CP_VLAN_TAG_USED
static int cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
struct cp_private *cp = dev->priv;
spin_lock_irq(&cp->lock);
cp->vlgrp = grp;
cpw16(CpCmd, cpr16(CpCmd) | RxVlanOn);
spin_unlock_irq(&cp->lock);
return 0;
}
static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct cp_private *cp = dev->priv;
spin_lock_irq(&cp->lock);
cpw16(CpCmd, cpr16(CpCmd) & ~RxVlanOn);
if (cp->vlgrp)
cp->vlgrp->vlan_devices[vid] = NULL;
spin_unlock_irq(&cp->lock);
}
#endif
/* Serial EEPROM section. */ /* Serial EEPROM section. */
...@@ -1337,6 +1414,11 @@ static int __devinit cp_init_one (struct pci_dev *pdev, ...@@ -1337,6 +1414,11 @@ static int __devinit cp_init_one (struct pci_dev *pdev,
#ifdef CP_TX_CHECKSUM #ifdef CP_TX_CHECKSUM
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
#endif #endif
#if CP_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->vlan_rx_register = cp_vlan_rx_register;
dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid;
#endif
dev->irq = pdev->irq; dev->irq = pdev->irq;
......
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