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)
" : : "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_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1))
......@@ -253,9 +264,27 @@ am79c961_init_for_open(struct net_device *dev)
write_rreg (dev->base_addr, BASERXH, 0);
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, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM);
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.
*/
......@@ -273,6 +302,11 @@ am79c961_open(struct net_device *dev)
am79c961_init_for_open(dev);
netif_carrier_off(dev);
priv->timer.expires = jiffies;
add_timer(&priv->timer);
netif_start_queue(dev);
return 0;
......@@ -287,7 +321,10 @@ am79c961_close(struct net_device *dev)
struct dev_priv *priv = (struct dev_priv *)dev->priv;
unsigned long flags;
del_timer_sync(&priv->timer);
netif_stop_queue(dev);
netif_carrier_off(dev);
spin_lock_irqsave(priv->chip_lock, flags);
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
......@@ -408,19 +445,10 @@ static int
am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
unsigned int length = skb->len;
unsigned int hdraddr, bufaddr;
unsigned int head;
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;
hdraddr = priv->txhdr + (head << 3);
bufaddr = priv->txbuffer[head];
......@@ -428,8 +456,8 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
if (head >= TX_BUFFERS)
head = 0;
am_writebuffer (dev, bufaddr, skb->data, length);
am_writeword (dev, hdraddr + 4, -length);
am_writebuffer (dev, bufaddr, skb->data, skb->len);
am_writeword (dev, hdraddr + 4, -skb->len);
am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
priv->txhead = head;
......@@ -518,6 +546,7 @@ static void
am79c961_tx(struct net_device *dev, struct dev_priv *priv)
{
do {
short len;
u_int hdraddr;
u_int status;
......@@ -553,6 +582,8 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
continue;
}
priv->stats.tx_packets ++;
len = am_readword (dev, hdraddr + 4);
priv->stats.tx_bytes += -len;
} while (priv->txtail != priv->txhead);
netif_wake_queue(dev);
......@@ -563,11 +594,14 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *)dev_id;
struct dev_priv *priv = (struct dev_priv *)dev->priv;
u_int status;
u_int status, n = 100;
int handled = 0;
do {
status = read_rreg(dev->base_addr, CSR0);
write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
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;
......@@ -581,6 +615,11 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
handled = 1;
priv->stats.rx_dropped ++;
}
if (status & CSR0_CERR) {
handled = 1;
mod_timer(&priv->timer, jiffies);
} while (--n && status & (CSR0_RINT | CSR0_TINT));
return IRQ_RETVAL(handled);
}
......@@ -593,10 +632,10 @@ am79c961_hw_init(struct net_device *dev)
{
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, CSR3, CSR3_MASKALL);
spin_unlock_irq(priv->chip_lock);
spin_unlock_irq(&priv->chip_lock);
am79c961_ramtest(dev, 0x66);
am79c961_ramtest(dev, 0x99);
......@@ -661,6 +700,11 @@ static int __init am79c961_init(void)
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))
goto release;
......
......@@ -58,6 +58,18 @@
#define CSR3_BABLM 0x4000
#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_SPND 0x0001
......@@ -93,6 +105,8 @@
#define SIZERXR 76
#define SIZETXR 78
#define CSR_MFC 112
#define RMD_ENP 0x0100
#define RMD_STP 0x0200
#define RMD_CRC 0x0800
......@@ -112,6 +126,9 @@
#define TST_UFLO 0x4000
#define TST_BUFF 0x8000
#define ISALED0 0x0004
#define ISALED0_LNKST 0x8000
struct dev_priv {
struct net_device_stats stats;
unsigned long rxbuffer[RX_BUFFERS];
......@@ -123,6 +140,7 @@ struct dev_priv {
unsigned long rxhdr;
unsigned long txhdr;
spinlock_t chip_lock;
struct timer_list timer;
};
extern int am79c961_probe (struct net_device *dev);
......
......@@ -687,7 +687,6 @@ static int
ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
{
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;
unsigned long flags;
tx_t tx;
......@@ -705,12 +704,18 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
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
*/
txaddr = ether1_txalloc (dev, TX_SIZE);
tbdaddr = ether1_txalloc (dev, TBD_SIZE);
dataddr = ether1_txalloc (dev, len);
dataddr = ether1_txalloc (dev, skb->len);
nopaddr = ether1_txalloc (dev, NOP_SIZE);
tx.tx_status = 0;
......@@ -728,7 +733,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
local_irq_save(flags);
ether1_writebuffer (dev, &tx, txaddr, TX_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);
tmp = priv->tx_link;
priv->tx_link = nopaddr;
......@@ -750,6 +755,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
if (tst == -1)
netif_stop_queue(dev);
out:
return 0;
}
......
......@@ -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 ptr, next_ptr;
length = (length + 1) & ~1;
if (priv->broken) {
dev_kfree_skb(skb);
priv->stats.tx_dropped ++;
......@@ -532,6 +530,13 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
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;
local_irq_save(flags);
......@@ -573,6 +578,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
if (priv->tx_tail == next_ptr)
netif_stop_queue(dev);
out:
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