fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / arm / am79c961a.c
index 8bd25b9..ddd12d4 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/fcntl.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
 
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/irq.h>
+#include <asm/hardware.h>
 #include <asm/io.h>
-#include <asm/dma.h>
+#include <asm/system.h>
 
 #define TX_BUFFERS 15
 #define RX_BUFFERS 25
@@ -41,7 +38,7 @@
 #include "am79c961a.h"
 
 static irqreturn_t
-am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+am79c961_interrupt (int irq, void *dev_id);
 
 static unsigned int net_debug = NET_DEBUG;
 
@@ -53,25 +50,31 @@ static const char version[] =
 #ifdef __arm__
 static void write_rreg(u_long base, u_int reg, u_int val)
 {
-       __asm__("str%?h %1, [%2]        @ NET_RAP
-               str%?h  %0, [%2, #-4]   @ NET_RDP
-               " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
+       __asm__(
+       "str%?h %1, [%2]        @ NET_RAP\n\t"
+       "str%?h %0, [%2, #-4]   @ NET_RDP"
+       :
+       : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
 
 static inline unsigned short read_rreg(u_long base_addr, u_int reg)
 {
        unsigned short v;
-       __asm__("str%?h %1, [%2]        @ NET_RAP
-               ldr%?h  %0, [%2, #-4]   @ NET_RDP
-               " : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
+       __asm__(
+       "str%?h %1, [%2]        @ NET_RAP\n\t"
+       "ldr%?h %0, [%2, #-4]   @ NET_RDP"
+       : "=r" (v)
+       : "r" (reg), "r" (ISAIO_BASE + 0x0464));
        return v;
 }
 
 static inline void write_ireg(u_long base, u_int reg, u_int val)
 {
-       __asm__("str%?h %1, [%2]        @ NET_RAP
-               str%?h  %0, [%2, #8]    @ NET_IDP
-               " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
+       __asm__(
+       "str%?h %1, [%2]        @ NET_RAP\n\t"
+       "str%?h %0, [%2, #8]    @ NET_IDP"
+       :
+       : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
 
 static inline unsigned short read_ireg(u_long base_addr, u_int reg)
@@ -79,7 +82,7 @@ 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"
+       "ldr%?h %0, [%2, #8]    @ NET_IDP\n\t"
        : "=r" (v)
        : "r" (reg), "r" (ISAIO_BASE + 0x0464));
        return v;
@@ -101,16 +104,16 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne
        }
        while (length > 8) {
                unsigned int tmp, tmp2;
-               __asm__ __volatile__("
-                       ldm%?ia %1!, {%2, %3}
-                       str%?h  %2, [%0], #4
-                       mov%?   %2, %2, lsr #16
-                       str%?h  %2, [%0], #4
-                       str%?h  %3, [%0], #4
-                       mov%?   %3, %3, lsr #16
-                       str%?h  %3, [%0], #4
-               : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
-                 : "0" (offset), "1" (buf));
+               __asm__ __volatile__(
+                       "ldm%?ia        %1!, {%2, %3}\n\t"
+                       "str%?h %2, [%0], #4\n\t"
+                       "mov%?  %2, %2, lsr #16\n\t"
+                       "str%?h %2, [%0], #4\n\t"
+                       "str%?h %3, [%0], #4\n\t"
+                       "mov%?  %3, %3, lsr #16\n\t"
+                       "str%?h %3, [%0], #4"
+               : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
+               : "0" (offset), "1" (buf));
                length -= 8;
        }
        while (length > 0) {
@@ -128,36 +131,36 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
        length = (length + 1) & ~1;
        if ((int)buf & 2) {
                unsigned int tmp;
-               __asm__ __volatile__("
-                       ldr%?h  %2, [%0], #4
-                       str%?b  %2, [%1], #1
-                       mov%?   %2, %2, lsr #8
-                       str%?b  %2, [%1], #1
-               : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
+               __asm__ __volatile__(
+                       "ldr%?h %2, [%0], #4\n\t"
+                       "str%?b %2, [%1], #1\n\t"
+                       "mov%?  %2, %2, lsr #8\n\t"
+                       "str%?b %2, [%1], #1"
+               : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
                length -= 2;
        }
        while (length > 8) {
                unsigned int tmp, tmp2, tmp3;
-               __asm__ __volatile__("
-                       ldr%?h  %2, [%0], #4
-                       ldr%?h  %3, [%0], #4
-                       orr%?   %2, %2, %3, lsl #16
-                       ldr%?h  %3, [%0], #4
-                       ldr%?h  %4, [%0], #4
-                       orr%?   %3, %3, %4, lsl #16
-                       stm%?ia %1!, {%2, %3}
-               : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
-                 : "0" (offset), "1" (buf));
+               __asm__ __volatile__(
+                       "ldr%?h %2, [%0], #4\n\t"
+                       "ldr%?h %3, [%0], #4\n\t"
+                       "orr%?  %2, %2, %3, lsl #16\n\t"
+                       "ldr%?h %3, [%0], #4\n\t"
+                       "ldr%?h %4, [%0], #4\n\t"
+                       "orr%?  %3, %3, %4, lsl #16\n\t"
+                       "stm%?ia        %1!, {%2, %3}"
+               : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
+               : "0" (offset), "1" (buf));
                length -= 8;
        }
        while (length > 0) {
                unsigned int tmp;
-               __asm__ __volatile__("
-                       ldr%?h  %2, [%0], #4
-                       str%?b  %2, [%1], #1
-                       mov%?   %2, %2, lsr #8
-                       str%?b  %2, [%1], #1
-               : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
+               __asm__ __volatile__(
+                       "ldr%?h %2, [%0], #4\n\t"
+                       "str%?b %2, [%1], #1\n\t"
+                       "mov%?  %2, %2, lsr #8\n\t"
+                       "str%?b %2, [%1], #1"
+               : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
                length -= 2;
        }
 }
@@ -277,12 +280,15 @@ static void am79c961_timer(unsigned long data)
        lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
        carrier = netif_carrier_ok(dev);
 
-       if (lnkstat && !carrier)
+       if (lnkstat && !carrier) {
                netif_carrier_on(dev);
-       else if (!lnkstat && carrier)
+               printk("%s: link up\n", dev->name);
+       } else if (!lnkstat && carrier) {
                netif_carrier_off(dev);
+               printk("%s: link down\n", dev->name);
+       }
 
-       mod_timer(&priv->timer, jiffies + 5*HZ);
+       mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500));
 }
 
 /*
@@ -590,7 +596,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
 }
 
 static irqreturn_t
-am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+am79c961_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *)dev_id;
        struct dev_priv *priv = netdev_priv(dev);
@@ -618,11 +624,22 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                if (status & CSR0_CERR) {
                        handled = 1;
                        mod_timer(&priv->timer, jiffies);
+               }
        } while (--n && status & (CSR0_RINT | CSR0_TINT));
 
        return IRQ_RETVAL(handled);
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void am79c961_poll_controller(struct net_device *dev)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       am79c961_interrupt(dev->irq, dev, NULL);
+       local_irq_restore(flags);
+}
+#endif
+
 /*
  * Initialise the chip.  Note that we always expect
  * to be entered with interrupts enabled.
@@ -651,17 +668,24 @@ static void __init am79c961_banner(void)
                printk(KERN_INFO "%s", version);
 }
 
-static int __init am79c961_init(void)
+static int __init am79c961_probe(struct platform_device *pdev)
 {
+       struct resource *res;
        struct net_device *dev;
        struct dev_priv *priv;
        int i, ret;
 
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res)
+               return -ENODEV;
+
        dev = alloc_etherdev(sizeof(struct dev_priv));
        ret = -ENOMEM;
        if (!dev)
                goto out;
 
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
        priv = netdev_priv(dev);
 
        /*
@@ -669,10 +693,12 @@ static int __init am79c961_init(void)
         * The PNP initialisation should have been
         * done by the ether bootp loader.
         */
-       dev->base_addr = 0x220;
-       dev->irq = IRQ_EBSA110_ETHERNET;
+       dev->base_addr = res->start;
+       dev->irq = platform_get_irq(pdev, 0);
 
-       ret = -ENODEV;
+       ret = -ENODEV;
+       if (dev->irq < 0)
+               goto nodev;
        if (!request_region(dev->base_addr, 0x18, dev->name))
                goto nodev;
 
@@ -691,14 +717,10 @@ static int __init am79c961_init(void)
            inb(dev->base_addr + 4) != 0x2b)
                goto release;
 
-       am79c961_banner();
-       printk(KERN_INFO "%s: ether address ", dev->name);
-
-       /* Retrive and print the ethernet address. */
-       for (i = 0; i < 6; i++) {
+       for (i = 0; i < 6; i++)
                dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
-               printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
-       }
+
+       am79c961_banner();
 
        spin_lock_init(&priv->chip_lock);
        init_timer(&priv->timer);
@@ -714,10 +736,20 @@ static int __init am79c961_init(void)
        dev->get_stats          = am79c961_getstats;
        dev->set_multicast_list = am79c961_setmulticastlist;
        dev->tx_timeout         = am79c961_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller    = am79c961_poll_controller;
+#endif
 
        ret = register_netdev(dev);
-       if (ret == 0)
+       if (ret == 0) {
+               printk(KERN_INFO "%s: ether address ", dev->name);
+
+               /* Retrive and print the ethernet address. */
+               for (i = 0; i < 6; i++)
+                       printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+
                return 0;
+       }
 
 release:
        release_region(dev->base_addr, 0x18);
@@ -727,4 +759,16 @@ out:
        return ret;
 }
 
+static struct platform_driver am79c961_driver = {
+       .probe          = am79c961_probe,
+       .driver         = {
+               .name   = "am79c961",
+       },
+};
+
+static int __init am79c961_init(void)
+{
+       return platform_driver_register(&am79c961_driver);
+}
+
 __initcall(am79c961_init);