fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / 7990.c
index 0e5aec0..2d5ba07 100644 (file)
@@ -1,7 +1,7 @@
-/* 
- * 7990.c -- LANCE ethernet IC generic routines. 
+/*
+ * 7990.c -- LANCE ethernet IC generic routines.
  * This is an attempt to separate out the bits of various ethernet
- * drivers that are common because they all use the AMD 7990 LANCE 
+ * drivers that are common because they all use the AMD 7990 LANCE
  * (Local Area Network Controller for Ethernet) chip.
  *
  * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
@@ -9,12 +9,11 @@
  * Most of this stuff was obtained by looking at other LANCE drivers,
  * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
  * NB: this was made easy by the fact that Jes Sorensen had cleaned up
- * most of a2025 and sunlance with the aim of merging them, so the 
+ * most of a2025 and sunlance with the aim of merging them, so the
  * common code was pretty obvious.
  */
 #include <linux/crc32.h>
 #include <linux/delay.h>
-#include <linux/dio.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
+#include <asm/irq.h>
 /* Used for the temporal inet entries and routing */
 #include <linux/socket.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
+#ifdef CONFIG_HP300
+#include <asm/blinken.h>
+#endif
 
 #include "7990.h"
 
+#define WRITERAP(lp,x) out_be16(lp->base + LANCE_RAP, (x))
+#define WRITERDP(lp,x) out_be16(lp->base + LANCE_RDP, (x))
+#define READRDP(lp) in_be16(lp->base + LANCE_RDP)
+
+#if defined(CONFIG_HPLANCE) || defined(CONFIG_HPLANCE_MODULE)
+#include "hplance.h"
+
+#undef WRITERAP
+#undef WRITERDP
+#undef READRDP
+
+#if defined(CONFIG_MVME147_NET) || defined(CONFIG_MVME147_NET_MODULE)
+
 /* Lossage Factor Nine, Mr Sulu. */
-#define WRITERAP(x) (lp->writerap(lp,x))
-#define WRITERDP(x) (lp->writerdp(lp,x))
-#define READRDP() (lp->readrdp(lp))
-/* These used to be ll->rap = x, ll->rdp = x, and (ll->rdp). Sigh. 
- * If you want to switch them back then 
- * #define DECLARE_LL volatile struct lance_regs *ll = lp->ll
- */
-#define DECLARE_LL /* nothing to declare */
+#define WRITERAP(lp,x) (lp->writerap(lp,x))
+#define WRITERDP(lp,x) (lp->writerdp(lp,x))
+#define READRDP(lp) (lp->readrdp(lp))
+
+#else
+
+/* These inlines can be used if only CONFIG_HPLANCE is defined */
+static inline void WRITERAP(struct lance_private *lp, __u16 value)
+{
+       do {
+               out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
+}
+
+static inline void WRITERDP(struct lance_private *lp, __u16 value)
+{
+       do {
+               out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
+}
+
+static inline __u16 READRDP(struct lance_private *lp)
+{
+       __u16 value;
+       do {
+               value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
+       } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
+       return value;
+}
+
+#endif
+#endif /* CONFIG_HPLANCE || CONFIG_HPLANCE_MODULE */
 
 /* debugging output macros, various flavours */
 /* #define TEST_HITS */
@@ -69,29 +109,28 @@ do { \
                        ib->btx_ring[t].length,\
                        ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\
         }\
-} while (0) 
+} while (0)
 #else
 #define PRINT_RINGS()
-#endif        
+#endif
 
 /* Load the CSR registers. The LANCE has to be STOPped when we do this! */
 static void load_csrs (struct lance_private *lp)
 {
         volatile struct lance_init_block *aib = lp->lance_init_block;
         int leptr;
-        DECLARE_LL;
 
         leptr = LANCE_ADDR (aib);
 
-        WRITERAP(LE_CSR1);                        /* load address of init block */
-        WRITERDP(leptr & 0xFFFF);
-        WRITERAP(LE_CSR2);
-        WRITERDP(leptr >> 16);
-        WRITERAP(LE_CSR3);
-        WRITERDP(lp->busmaster_regval);           /* set byteswap/ALEctrl/byte ctrl */
+        WRITERAP(lp, LE_CSR1);                    /* load address of init block */
+        WRITERDP(lp, leptr & 0xFFFF);
+        WRITERAP(lp, LE_CSR2);
+        WRITERDP(lp, leptr >> 16);
+        WRITERAP(lp, LE_CSR3);
+        WRITERDP(lp, lp->busmaster_regval);       /* set byteswap/ALEctrl/byte ctrl */
 
         /* Point back to csr0 */
-        WRITERAP(LE_CSR0);
+        WRITERAP(lp, LE_CSR0);
 }
 
 /* #define to 0 or 1 appropriately */
@@ -118,7 +157,7 @@ static void lance_init_ring (struct net_device *dev)
          * a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
          * However, the datasheet says that the BSWAP bit doesn't affect
          * the init block, so surely it should be low byte first for
-         * everybody? Um.] 
+         * everybody? Um.]
          * We could define the ib->physaddr as three 16bit values and
          * use (addr[1] << 8) | addr[0] & co, but this is more efficient.
          */
@@ -132,11 +171,11 @@ static void lance_init_ring (struct net_device *dev)
 #else
         for (i=0; i<6; i++)
            ib->phys_addr[i] = dev->dev_addr[i];
-#endif        
+#endif
 
         if (DEBUG_IRING)
                 printk ("TX rings:\n");
-    
+
        lp->tx_full = 0;
         /* Setup the Tx ring entries */
         for (i = 0; i < (1<<lp->lance_log_tx_bufs); i++) {
@@ -146,7 +185,7 @@ static void lance_init_ring (struct net_device *dev)
                 ib->btx_ring [i].tmd1_bits = 0;
                 ib->btx_ring [i].length    = 0xf000; /* The ones required by tmd2 */
                 ib->btx_ring [i].misc      = 0;
-                if (DEBUG_IRING) 
+                if (DEBUG_IRING)
                    printk ("%d: 0x%8.8x\n", i, leptr);
         }
 
@@ -167,14 +206,14 @@ static void lance_init_ring (struct net_device *dev)
         }
 
         /* Setup the initialization block */
-    
+
         /* Setup rx descriptor pointer */
         leptr = LANCE_ADDR(&aib->brx_ring);
         ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
         ib->rx_ptr = leptr;
         if (DEBUG_IRING)
                 printk ("RX ptr: %8.8x\n", leptr);
-    
+
         /* Setup tx descriptor pointer */
         leptr = LANCE_ADDR(&aib->btx_ring);
         ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
@@ -192,24 +231,23 @@ static void lance_init_ring (struct net_device *dev)
 static int init_restart_lance (struct lance_private *lp)
 {
         int i;
-        DECLARE_LL;
 
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_INIT);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_INIT);
 
         /* Need a hook here for sunlance ledma stuff */
 
         /* Wait for the lance to complete initialization */
-        for (i = 0; (i < 100) && !(READRDP() & (LE_C0_ERR | LE_C0_IDON)); i++)
+        for (i = 0; (i < 100) && !(READRDP(lp) & (LE_C0_ERR | LE_C0_IDON)); i++)
                 barrier();
-        if ((i == 100) || (READRDP() & LE_C0_ERR)) {
-                printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP());
+        if ((i == 100) || (READRDP(lp) & LE_C0_ERR)) {
+                printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP(lp));
                 return -1;
         }
 
         /* Clear IDON by writing a "1", enable interrupts and start lance */
-        WRITERDP(LE_C0_IDON);
-        WRITERDP(LE_C0_INEA | LE_C0_STRT);
+        WRITERDP(lp, LE_C0_IDON);
+        WRITERDP(lp, LE_C0_INEA | LE_C0_STRT);
 
         return 0;
 }
@@ -218,11 +256,10 @@ static int lance_reset (struct net_device *dev)
 {
         struct lance_private *lp = netdev_priv(dev);
         int status;
-        DECLARE_LL;
-    
+
         /* Stop the lance */
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_STOP);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_STOP);
 
         load_csrs (lp);
         lance_init_ring (dev);
@@ -245,7 +282,6 @@ static int lance_rx (struct net_device *dev)
 #ifdef TEST_HITS
         int i;
 #endif
-        DECLARE_LL;
 
 #ifdef TEST_HITS
         printk ("[");
@@ -259,8 +295,10 @@ static int lance_rx (struct net_device *dev)
         }
         printk ("]");
 #endif
-    
-        WRITERDP(LE_C0_RINT | LE_C0_INEA);     /* ack Rx int, reenable ints */
+#ifdef CONFIG_HP300
+       blinken_leds(0x40, 0);
+#endif
+        WRITERDP(lp, LE_C0_RINT | LE_C0_INEA);     /* ack Rx int, reenable ints */
         for (rd = &ib->brx_ring [lp->rx_new];     /* For each Rx ring we own... */
              !((bits = rd->rmd1_bits) & LE_R1_OWN);
              rd = &ib->brx_ring [lp->rx_new]) {
@@ -292,7 +330,7 @@ static int lance_rx (struct net_device *dev)
                                 lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
                                 return 0;
                         }
-            
+
                         skb->dev = dev;
                         skb_reserve (skb, 2);           /* 16 byte align */
                         skb_put (skb, len);             /* make room */
@@ -321,10 +359,12 @@ static int lance_tx (struct net_device *dev)
         volatile struct lance_tx_desc *td;
         int i, j;
         int status;
-        DECLARE_LL;
 
+#ifdef CONFIG_HP300
+       blinken_leds(0x80, 0);
+#endif
         /* csr0 is 2f3 */
-        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
         /* csr0 is 73 */
 
         j = lp->tx_old;
@@ -334,10 +374,10 @@ static int lance_tx (struct net_device *dev)
                 /* If we hit a packet not owned by us, stop */
                 if (td->tmd1_bits & LE_T1_OWN)
                         break;
-                
+
                 if (td->tmd1_bits & LE_T1_ERR) {
                         status = td->misc;
-            
+
                         lp->stats.tx_errors++;
                         if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
                         if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
@@ -349,8 +389,8 @@ static int lance_tx (struct net_device *dev)
                                         printk("%s: Carrier Lost, trying %s\n",
                                                dev->name, lp->tpe?"TPE":"AUI");
                                         /* Stop the lance */
-                                        WRITERAP(LE_CSR0);
-                                        WRITERDP(LE_C0_STOP);
+                                        WRITERAP(lp, LE_CSR0);
+                                        WRITERDP(lp, LE_C0_STOP);
                                         lance_init_ring (dev);
                                         load_csrs (lp);
                                         init_restart_lance (lp);
@@ -366,8 +406,8 @@ static int lance_tx (struct net_device *dev)
                                 printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
                                         dev->name);
                                 /* Stop the lance */
-                                WRITERAP(LE_CSR0);
-                                WRITERDP(LE_C0_STOP);
+                                WRITERAP(lp, LE_CSR0);
+                                WRITERDP(lp, LE_C0_STOP);
                                 lance_init_ring (dev);
                                 load_csrs (lp);
                                 init_restart_lance (lp);
@@ -389,40 +429,39 @@ static int lance_tx (struct net_device *dev)
 
                         lp->stats.tx_packets++;
                 }
-        
+
                 j = (j + 1) & lp->tx_ring_mod_mask;
         }
         lp->tx_old = j;
-        WRITERDP(LE_C0_TINT | LE_C0_INEA);
+        WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
         return 0;
 }
 
 static irqreturn_t
-lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+lance_interrupt (int irq, void *dev_id)
 {
         struct net_device *dev = (struct net_device *)dev_id;
         struct lance_private *lp = netdev_priv(dev);
         int csr0;
-        DECLARE_LL;
 
        spin_lock (&lp->devlock);
 
-        WRITERAP(LE_CSR0);              /* LANCE Controller Status */
-        csr0 = READRDP();
+        WRITERAP(lp, LE_CSR0);              /* LANCE Controller Status */
+        csr0 = READRDP(lp);
 
         PRINT_RINGS();
-        
+
         if (!(csr0 & LE_C0_INTR)) {     /* Check if any interrupt has */
-               spin_lock (&lp->devlock);
+               spin_unlock (&lp->devlock);
                 return IRQ_NONE;        /* been generated by the Lance. */
        }
 
         /* Acknowledge all the interrupt sources ASAP */
-        WRITERDP(csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
+        WRITERDP(lp, csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
 
         if ((csr0 & LE_C0_ERR)) {
                 /* Clear the error condition */
-                WRITERDP(LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
+                WRITERDP(lp, LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
         }
 
         if (csr0 & LE_C0_RINT)
@@ -437,19 +476,19 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
         if (csr0 & LE_C0_MISS)
                 lp->stats.rx_errors++;       /* Missed a Rx frame. */
         if (csr0 & LE_C0_MERR) {
-                printk("%s: Bus master arbitration failure, status %4.4x.\n", 
+                printk("%s: Bus master arbitration failure, status %4.4x.\n",
                        dev->name, csr0);
                 /* Restart the chip. */
-                WRITERDP(LE_C0_STRT);
+                WRITERDP(lp, LE_C0_STRT);
         }
 
         if (lp->tx_full && netif_queue_stopped(dev) && (TX_BUFFS_AVAIL >= 0)) {
                lp->tx_full = 0;
                netif_wake_queue (dev);
         }
-        
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
+
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
 
        spin_unlock (&lp->devlock);
        return IRQ_HANDLED;
@@ -459,14 +498,13 @@ int lance_open (struct net_device *dev)
 {
         struct lance_private *lp = netdev_priv(dev);
        int res;
-        DECLARE_LL;
-        
+
         /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
-        if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
+        if (request_irq(lp->irq, lance_interrupt, SA_SHIRQ, lp->name, dev))
                 return -EAGAIN;
 
         res = lance_reset(dev);
-       lp->devlock = SPIN_LOCK_UNLOCKED;
+       spin_lock_init(&lp->devlock);
        netif_start_queue (dev);
 
        return res;
@@ -475,13 +513,12 @@ int lance_open (struct net_device *dev)
 int lance_close (struct net_device *dev)
 {
         struct lance_private *lp = netdev_priv(dev);
-        DECLARE_LL;
-        
+
        netif_stop_queue (dev);
 
         /* Stop the LANCE */
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_STOP);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_STOP);
 
         free_irq(lp->irq, dev);
 
@@ -504,7 +541,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
         int entry, skblen, len;
         static int outs;
        unsigned long flags;
-        DECLARE_LL;
 
         if (!TX_BUFFS_AVAIL)
                 return -1;
@@ -517,7 +553,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
         /* dump the packet */
         {
                 int i;
-        
+
                 for (i = 0; i < 64; i++) {
                         if ((i % 16) == 0)
                                 printk ("\n");
@@ -529,21 +565,21 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
         entry = lp->tx_new & lp->tx_ring_mod_mask;
         ib->btx_ring [entry].length = (-len) | 0xf000;
         ib->btx_ring [entry].misc = 0;
-    
+
        if (skb->len < ETH_ZLEN)
                memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
         memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
-    
+
         /* Now, give the packet to the lance */
         ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
         lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
 
         outs++;
         /* Kick the lance: transmit now */
-        WRITERDP(LE_C0_INEA | LE_C0_TDMD);
+        WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
         dev->trans_start = jiffies;
         dev_kfree_skb (skb);
-    
+
        spin_lock_irqsave (&lp->devlock, flags);
         if (TX_BUFFS_AVAIL)
                netif_start_queue (dev);
@@ -571,9 +607,9 @@ static void lance_load_multicast (struct net_device *dev)
         char *addrs;
         int i;
         u32 crc;
-        
+
         /* set all multicast bits */
-        if (dev->flags & IFF_ALLMULTI){ 
+        if (dev->flags & IFF_ALLMULTI){
                 ib->filter [0] = 0xffffffff;
                 ib->filter [1] = 0xffffffff;
                 return;
@@ -590,7 +626,7 @@ static void lance_load_multicast (struct net_device *dev)
                 /* multicast address? */
                 if (!(*addrs & 1))
                         continue;
-                
+
                crc = ether_crc_le(6, addrs);
                 crc = crc >> 26;
                 mcast_table [crc >> 4] |= 1 << (crc & 0xf);
@@ -604,7 +640,6 @@ void lance_set_multicast (struct net_device *dev)
         struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
        int stopped;
-        DECLARE_LL;
 
        stopped = netif_queue_stopped(dev);
        if (!stopped)
@@ -613,8 +648,8 @@ void lance_set_multicast (struct net_device *dev)
         while (lp->tx_old != lp->tx_new)
                 schedule();
 
-        WRITERAP(LE_CSR0);
-        WRITERDP(LE_C0_STOP);
+        WRITERAP(lp, LE_CSR0);
+        WRITERDP(lp, LE_C0_STOP);
         lance_init_ring (dev);
 
         if (dev->flags & IFF_PROMISC) {
@@ -630,4 +665,17 @@ void lance_set_multicast (struct net_device *dev)
                netif_start_queue (dev);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+void lance_poll(struct net_device *dev)
+{
+       struct lance_private *lp = netdev_priv(dev);
+
+       spin_lock (&lp->devlock);
+       WRITERAP(lp, LE_CSR0);
+       WRITERDP(lp, LE_C0_STRT);
+       spin_unlock (&lp->devlock);
+       lance_interrupt(dev->irq, dev);
+}
+#endif
+
 MODULE_LICENSE("GPL");