patch-2.4.0-test2 linux/drivers/net/am79c961a.c
Next file: linux/drivers/net/apne.c
Previous file: linux/drivers/net/aironet4500_card.c
Back to the patch index
Back to the overall index
- Lines: 324
- Date:
Mon Jun 19 13:30:57 2000
- Orig file:
v2.4.0-test1/linux/drivers/net/am79c961a.c
- Orig date:
Tue May 23 15:31:35 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c
@@ -39,8 +39,6 @@
#include "am79c961a.h"
static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static void am79c961_rx (struct net_device *dev, struct dev_priv *priv);
-static void am79c961_tx (struct net_device *dev, struct dev_priv *priv);
static unsigned int net_debug = NET_DEBUG;
@@ -57,11 +55,21 @@
" : : "r" (val), "r" (reg), "r" (0xf0000464));
}
+static inline unsigned short
+read_rreg (unsigned int base_addr, unsigned int reg)
+{
+ unsigned short v;
+ __asm__("str%?h %1, [%2] @ NET_RAP
+ ldr%?h %0, [%2, #-4] @ NET_RDP
+ " : "=r" (v): "r" (reg), "r" (0xf0000464));
+ return v;
+}
+
static inline void
write_ireg (unsigned long base, unsigned int reg, unsigned short val)
{
__asm__("str%?h %1, [%2] @ NET_RAP
- str%?h %0, [%2, #8] @ NET_RDP
+ str%?h %0, [%2, #8] @ NET_IDP
" : : "r" (val), "r" (reg), "r" (0xf0000464));
}
@@ -70,7 +78,7 @@
"r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
static inline void
-am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
+am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
{
offset = 0xe0000000 + (offset << 1);
length = (length + 1) & ~1;
@@ -102,18 +110,11 @@
}
}
-static inline unsigned short
-read_rreg (unsigned int base_addr, unsigned int reg)
-{
- unsigned short v;
- __asm__("str%?h %1, [%2] @ NET_RAP
- ldr%?h %0, [%2, #-4] @ NET_IDP
- " : "=r" (v): "r" (reg), "r" (0xf0000464));
- return v;
-}
-
-static inline unsigned short
-am_readword (struct net_device *dev, unsigned long off)
+/*
+ * This reads a 16-bit quantity in little-endian
+ * mode from the am79c961 buffer.
+ */
+static inline unsigned short am_readword(struct net_device *dev, u_int off)
{
unsigned long address = 0xe0000000 + (off << 1);
unsigned short val;
@@ -123,7 +124,7 @@
}
static inline void
-am_readbuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
+am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
{
offset = 0xe0000000 + (offset << 1);
length = (length + 1) & ~1;
@@ -198,18 +199,35 @@
am79c961_init_for_open(struct net_device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
- unsigned long hdr_addr, first_free_addr;
unsigned long flags;
unsigned char *p;
+ u_int hdr_addr, first_free_addr;
int i;
save_flags_cli (flags);
-
- write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
-
restore_flags (flags);
+ write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */
+ write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */
+ write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */
+ write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
+
+ for (i = LADRL; i <= LADRH; i++)
+ write_rreg (dev->base_addr, i, 0);
+
+ for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
+ write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
+
+ i = MODE_PORT_10BT;
+ if (dev->flags & IFF_PROMISC)
+ i |= MODE_PROMISC;
+
+ write_rreg (dev->base_addr, MODE, i);
+ write_rreg (dev->base_addr, POLLINT, 0);
+ write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
+ write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
+
first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
hdr_addr = 0;
@@ -232,31 +250,17 @@
for (i = 0; i < TX_BUFFERS; i++) {
priv->txbuffer[i] = first_free_addr;
am_writeword (dev, hdr_addr, first_free_addr);
- am_writeword (dev, hdr_addr + 2, 0);
- am_writeword (dev, hdr_addr + 4, 0);
+ am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP);
+ am_writeword (dev, hdr_addr + 4, 0xf000);
am_writeword (dev, hdr_addr + 6, 0);
first_free_addr += 1600;
hdr_addr += 8;
}
- for (i = LADRL; i <= LADRH; i++)
- write_rreg (dev->base_addr, i, 0);
-
- for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
- write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
-
- i = MODE_PORT0;
- if (dev->flags & IFF_PROMISC)
- i |= MODE_PROMISC;
-
- write_rreg (dev->base_addr, MODE, i);
write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
write_rreg (dev->base_addr, BASERXH, 0);
write_rreg (dev->base_addr, BASETXL, priv->txhdr);
write_rreg (dev->base_addr, BASERXH, 0);
- write_rreg (dev->base_addr, POLLINT, 0);
- write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
- write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
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, CSR0, CSR0_IENA|CSR0_STRT);
@@ -303,7 +307,6 @@
save_flags_cli (flags);
- write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
@@ -369,7 +372,7 @@
unsigned short multi_hash[4], mode;
int i, stopped;
- mode = MODE_PORT0;
+ mode = MODE_PORT_10BT;
if (dev->flags & IFF_PROMISC) {
mode |= MODE_PROMISC;
@@ -466,54 +469,32 @@
dev->trans_start = jiffies;
restore_flags (flags);
- if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
+ /*
+ * If the next packet is owned by the ethernet device,
+ * then the tx ring is full and we can't add another
+ * packet.
+ */
+ if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) {
+ printk(KERN_DEBUG"tx ring full, stopping queue\n");
netif_stop_queue(dev);
+ }
dev_kfree_skb(skb);
return 0;
}
-static void
-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;
- unsigned int status;
-
-#if NET_DEBUG > 1
- if(net_debug & DEBUG_INT)
- printk(KERN_DEBUG "am79c961irq: %d ", irq);
-#endif
-
- status = read_rreg (dev->base_addr, CSR0);
- write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
-
- if (status & CSR0_RINT) /* Got a packet(s). */
- am79c961_rx (dev, priv);
- if (status & CSR0_TINT) /* Packets transmitted */
- am79c961_tx (dev, priv);
- if (status & CSR0_MISS)
- priv->stats.rx_dropped ++;
-
-#if NET_DEBUG > 1
- if(net_debug & DEBUG_INT)
- printk("done\n");
-#endif
-}
-
/*
* If we have a good packet(s), get it/them out of the buffers.
*/
static void
am79c961_rx(struct net_device *dev, struct dev_priv *priv)
{
- unsigned long hdraddr;
- unsigned long pktaddr;
-
do {
- unsigned long status;
struct sk_buff *skb;
+ u_int hdraddr;
+ u_int pktaddr;
+ u_int status;
int len;
hdraddr = priv->rxhdr + (priv->rxtail << 3);
@@ -540,20 +521,19 @@
continue;
}
- len = am_readword (dev, hdraddr + 6);
- skb = dev_alloc_skb (len + 2);
+ len = am_readword(dev, hdraddr + 6);
+ skb = dev_alloc_skb(len + 2);
if (skb) {
- unsigned char *buf;
-
skb->dev = dev;
- skb_reserve (skb, 2);
- buf = skb_put (skb, len);
+ skb_reserve(skb, 2);
- am_readbuffer (dev, pktaddr, buf, len);
- am_writeword (dev, hdraddr + 2, RMD_OWN);
+ am_readbuffer(dev, pktaddr, skb_put(skb, len), len);
+ am_writeword(dev, hdraddr + 2, RMD_OWN);
skb->protocol = eth_type_trans(skb, dev);
- netif_rx (skb);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ priv->stats.rx_bytes += len;
priv->stats.rx_packets ++;
} else {
am_writeword (dev, hdraddr + 2, RMD_OWN);
@@ -571,9 +551,11 @@
am79c961_tx(struct net_device *dev, struct dev_priv *priv)
{
do {
- unsigned long hdraddr;
- unsigned long status;
+ u_int hdraddr;
+ u_int status;
+int bufnum;
+bufnum = priv->txtail;
hdraddr = priv->txhdr + (priv->txtail << 3);
status = am_readword (dev, hdraddr + 2);
if (status & TMD_OWN)
@@ -584,11 +566,15 @@
priv->txtail = 0;
if (status & TMD_ERR) {
- unsigned long status2;
+ u_int status2;
priv->stats.tx_errors ++;
status2 = am_readword (dev, hdraddr + 6);
+
+ /*
+ * Clear the error byte
+ */
am_writeword (dev, hdraddr + 6, 0);
if (status2 & TST_RTRY)
@@ -607,6 +593,24 @@
netif_wake_queue(dev);
}
+static void
+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;
+
+ status = read_rreg(dev->base_addr, CSR0);
+ write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
+
+ if (status & CSR0_RINT)
+ am79c961_rx(dev, priv);
+ if (status & CSR0_TINT)
+ am79c961_tx(dev, priv);
+ if (status & CSR0_MISS)
+ priv->stats.rx_dropped ++;
+}
+
static int
am79c961_hw_init(struct net_device *dev)
{
@@ -617,7 +621,6 @@
save_flags_cli (flags);
- write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)