Commit 9db0e5a0 authored by Russell King's avatar Russell King

[ARM] Update ARM ethernet drivers

- Forward-port ETH_ZLEN fixes from 2.4
- Add AM79c961A link status detection
- Add AM79c961A Tx byte accounting
parent 947af82f
...@@ -74,6 +74,17 @@ static inline void write_ireg(u_long base, u_int reg, u_int val) ...@@ -74,6 +74,17 @@ static inline void write_ireg(u_long base, u_int reg, u_int val)
" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
} }
static inline unsigned short read_ireg(u_long base_addr, u_int reg)
{
u_short v;
__asm__(
"str%?h %1, [%2] @ NAT_RAP\n\t"
"str%?h %0, [%2, #8] @ NET_IDP\n\t"
: "=r" (v)
: "r" (reg), "r" (ISAIO_BASE + 0x0464));
return v;
}
#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1)) #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
#define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1)) #define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1))
...@@ -253,9 +264,27 @@ am79c961_init_for_open(struct net_device *dev) ...@@ -253,9 +264,27 @@ am79c961_init_for_open(struct net_device *dev)
write_rreg (dev->base_addr, BASERXH, 0); write_rreg (dev->base_addr, BASERXH, 0);
write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR0, CSR0_STOP);
write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO); write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
write_rreg (dev->base_addr, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM);
write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
} }
static void am79c961_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct dev_priv *priv = (struct dev_priv *)dev->priv;
unsigned int lnkstat, carrier;
lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
carrier = netif_carrier_ok(dev);
if (lnkstat && !carrier)
netif_carrier_on(dev);
else if (!lnkstat && carrier)
netif_carrier_off(dev);
mod_timer(&priv->timer, jiffies + 5*HZ);
}
/* /*
* Open/initialize the board. * Open/initialize the board.
*/ */
...@@ -273,6 +302,11 @@ am79c961_open(struct net_device *dev) ...@@ -273,6 +302,11 @@ am79c961_open(struct net_device *dev)
am79c961_init_for_open(dev); am79c961_init_for_open(dev);
netif_carrier_off(dev);
priv->timer.expires = jiffies;
add_timer(&priv->timer);
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;
...@@ -287,7 +321,10 @@ am79c961_close(struct net_device *dev) ...@@ -287,7 +321,10 @@ am79c961_close(struct net_device *dev)
struct dev_priv *priv = (struct dev_priv *)dev->priv; struct dev_priv *priv = (struct dev_priv *)dev->priv;
unsigned long flags; unsigned long flags;
del_timer_sync(&priv->timer);
netif_stop_queue(dev); netif_stop_queue(dev);
netif_carrier_off(dev);
spin_lock_irqsave(priv->chip_lock, flags); spin_lock_irqsave(priv->chip_lock, flags);
write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR0, CSR0_STOP);
...@@ -408,18 +445,9 @@ static int ...@@ -408,18 +445,9 @@ static int
am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
{ {
struct dev_priv *priv = (struct dev_priv *)dev->priv; struct dev_priv *priv = (struct dev_priv *)dev->priv;
unsigned int length = skb->len;
unsigned int hdraddr, bufaddr; unsigned int hdraddr, bufaddr;
unsigned int head; unsigned int head;
unsigned long flags; unsigned long flags;
/* FIXME: I thought the 79c961 could do padding - RMK ??? */
if (length < ETH_ZLEN) {
skb = skb_padto(skb, ETH_ZLEN);
if (skb == NULL)
return 0;
length = ETH_ZLEN;
}
head = priv->txhead; head = priv->txhead;
hdraddr = priv->txhdr + (head << 3); hdraddr = priv->txhdr + (head << 3);
...@@ -428,8 +456,8 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) ...@@ -428,8 +456,8 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
if (head >= TX_BUFFERS) if (head >= TX_BUFFERS)
head = 0; head = 0;
am_writebuffer (dev, bufaddr, skb->data, length); am_writebuffer (dev, bufaddr, skb->data, skb->len);
am_writeword (dev, hdraddr + 4, -length); am_writeword (dev, hdraddr + 4, -skb->len);
am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
priv->txhead = head; priv->txhead = head;
...@@ -518,6 +546,7 @@ static void ...@@ -518,6 +546,7 @@ static void
am79c961_tx(struct net_device *dev, struct dev_priv *priv) am79c961_tx(struct net_device *dev, struct dev_priv *priv)
{ {
do { do {
short len;
u_int hdraddr; u_int hdraddr;
u_int status; u_int status;
...@@ -553,6 +582,8 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv) ...@@ -553,6 +582,8 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
continue; continue;
} }
priv->stats.tx_packets ++; priv->stats.tx_packets ++;
len = am_readword (dev, hdraddr + 4);
priv->stats.tx_bytes += -len;
} while (priv->txtail != priv->txhead); } while (priv->txtail != priv->txhead);
netif_wake_queue(dev); netif_wake_queue(dev);
...@@ -563,24 +594,32 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -563,24 +594,32 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct net_device *dev = (struct net_device *)dev_id; struct net_device *dev = (struct net_device *)dev_id;
struct dev_priv *priv = (struct dev_priv *)dev->priv; struct dev_priv *priv = (struct dev_priv *)dev->priv;
u_int status; u_int status, n = 100;
int handled = 0; int handled = 0;
status = read_rreg(dev->base_addr, CSR0); do {
write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA)); status = read_rreg(dev->base_addr, CSR0);
write_rreg(dev->base_addr, CSR0, status &
(CSR0_IENA|CSR0_TINT|CSR0_RINT|
CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL));
if (status & CSR0_RINT) {
handled = 1;
am79c961_rx(dev, priv);
}
if (status & CSR0_TINT) {
handled = 1;
am79c961_tx(dev, priv);
}
if (status & CSR0_MISS) {
handled = 1;
priv->stats.rx_dropped ++;
}
if (status & CSR0_CERR) {
handled = 1;
mod_timer(&priv->timer, jiffies);
} while (--n && status & (CSR0_RINT | CSR0_TINT));
if (status & CSR0_RINT) {
handled = 1;
am79c961_rx(dev, priv);
}
if (status & CSR0_TINT) {
handled = 1;
am79c961_tx(dev, priv);
}
if (status & CSR0_MISS) {
handled = 1;
priv->stats.rx_dropped ++;
}
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
...@@ -593,10 +632,10 @@ am79c961_hw_init(struct net_device *dev) ...@@ -593,10 +632,10 @@ am79c961_hw_init(struct net_device *dev)
{ {
struct dev_priv *priv = (struct dev_priv *)dev->priv; struct dev_priv *priv = (struct dev_priv *)dev->priv;
spin_lock_irq(priv->chip_lock); spin_lock_irq(&priv->chip_lock);
write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR0, CSR0_STOP);
write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
spin_unlock_irq(priv->chip_lock); spin_unlock_irq(&priv->chip_lock);
am79c961_ramtest(dev, 0x66); am79c961_ramtest(dev, 0x66);
am79c961_ramtest(dev, 0x99); am79c961_ramtest(dev, 0x99);
...@@ -661,6 +700,11 @@ static int __init am79c961_init(void) ...@@ -661,6 +700,11 @@ static int __init am79c961_init(void)
printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
} }
spin_lock_init(&priv->chip_lock);
init_timer(&priv->timer);
priv->timer.data = (unsigned long)dev;
priv->timer.function = am79c961_timer;
if (am79c961_hw_init(dev)) if (am79c961_hw_init(dev))
goto release; goto release;
......
...@@ -58,6 +58,18 @@ ...@@ -58,6 +58,18 @@
#define CSR3_BABLM 0x4000 #define CSR3_BABLM 0x4000
#define CSR3_MASKALL 0x5F00 #define CSR3_MASKALL 0x5F00
#define CSR4 4
#define CSR4_JABM 0x0001
#define CSR4_JAB 0x0002
#define CSR4_TXSTRTM 0x0004
#define CSR4_TXSTRT 0x0008
#define CSR4_RCVCCOM 0x0010
#define CSR4_RCVCCO 0x0020
#define CSR4_MFCOM 0x0100
#define CSR4_MFCO 0x0200
#define CSR4_ASTRP_RCV 0x0400
#define CSR4_APAD_XMIT 0x0800
#define CTRL1 5 #define CTRL1 5
#define CTRL1_SPND 0x0001 #define CTRL1_SPND 0x0001
...@@ -93,6 +105,8 @@ ...@@ -93,6 +105,8 @@
#define SIZERXR 76 #define SIZERXR 76
#define SIZETXR 78 #define SIZETXR 78
#define CSR_MFC 112
#define RMD_ENP 0x0100 #define RMD_ENP 0x0100
#define RMD_STP 0x0200 #define RMD_STP 0x0200
#define RMD_CRC 0x0800 #define RMD_CRC 0x0800
...@@ -112,6 +126,9 @@ ...@@ -112,6 +126,9 @@
#define TST_UFLO 0x4000 #define TST_UFLO 0x4000
#define TST_BUFF 0x8000 #define TST_BUFF 0x8000
#define ISALED0 0x0004
#define ISALED0_LNKST 0x8000
struct dev_priv { struct dev_priv {
struct net_device_stats stats; struct net_device_stats stats;
unsigned long rxbuffer[RX_BUFFERS]; unsigned long rxbuffer[RX_BUFFERS];
...@@ -123,6 +140,7 @@ struct dev_priv { ...@@ -123,6 +140,7 @@ struct dev_priv {
unsigned long rxhdr; unsigned long rxhdr;
unsigned long txhdr; unsigned long txhdr;
spinlock_t chip_lock; spinlock_t chip_lock;
struct timer_list timer;
}; };
extern int am79c961_probe (struct net_device *dev); extern int am79c961_probe (struct net_device *dev);
......
...@@ -687,7 +687,6 @@ static int ...@@ -687,7 +687,6 @@ static int
ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
{ {
struct ether1_priv *priv = (struct ether1_priv *)dev->priv; struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
unsigned long flags; unsigned long flags;
tx_t tx; tx_t tx;
...@@ -705,12 +704,18 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) ...@@ -705,12 +704,18 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
priv->restart = 0; priv->restart = 0;
} }
if (skb->len < ETH_ZLEN) {
skb = skb_padto(skb, ETH_ZLEN);
if (skb == NULL)
goto out;
}
/* /*
* insert packet followed by a nop * insert packet followed by a nop
*/ */
txaddr = ether1_txalloc (dev, TX_SIZE); txaddr = ether1_txalloc (dev, TX_SIZE);
tbdaddr = ether1_txalloc (dev, TBD_SIZE); tbdaddr = ether1_txalloc (dev, TBD_SIZE);
dataddr = ether1_txalloc (dev, len); dataddr = ether1_txalloc (dev, skb->len);
nopaddr = ether1_txalloc (dev, NOP_SIZE); nopaddr = ether1_txalloc (dev, NOP_SIZE);
tx.tx_status = 0; tx.tx_status = 0;
...@@ -728,7 +733,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) ...@@ -728,7 +733,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
local_irq_save(flags); local_irq_save(flags);
ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
ether1_writebuffer (dev, skb->data, dataddr, len); ether1_writebuffer (dev, skb->data, dataddr, skb->len);
ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE); ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
tmp = priv->tx_link; tmp = priv->tx_link;
priv->tx_link = nopaddr; priv->tx_link = nopaddr;
...@@ -750,6 +755,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) ...@@ -750,6 +755,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
if (tst == -1) if (tst == -1)
netif_stop_queue(dev); netif_stop_queue(dev);
out:
return 0; return 0;
} }
......
...@@ -523,8 +523,6 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) ...@@ -523,8 +523,6 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned int ptr, next_ptr; unsigned int ptr, next_ptr;
length = (length + 1) & ~1;
if (priv->broken) { if (priv->broken) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
priv->stats.tx_dropped ++; priv->stats.tx_dropped ++;
...@@ -532,6 +530,13 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) ...@@ -532,6 +530,13 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
length = (length + 1) & ~1;
if (length != skb->len) {
skb = skb_padto(skb, length);
if (skb == NULL)
goto out;
}
next_ptr = (priv->tx_head + 1) & 15; next_ptr = (priv->tx_head + 1) & 15;
local_irq_save(flags); local_irq_save(flags);
...@@ -573,6 +578,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) ...@@ -573,6 +578,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
if (priv->tx_tail == next_ptr) if (priv->tx_tail == next_ptr)
netif_stop_queue(dev); netif_stop_queue(dev);
out:
return 0; return 0;
} }
......
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