fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / jazzsonic.c
index 7046c43..d34afb5 100644 (file)
@@ -1,11 +1,16 @@
 /*
- * sonic.c
+ * jazzsonic.c
+ *
+ * (C) 2005 Finn Thain
+ *
+ * Converted to DMA API, and (from the mac68k project) introduced
+ * dhd's support for 16-bit cards.
  *
  * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- * 
+ *
  * This driver is based on work from Andreas Busse, but most of
  * the code is rewritten.
- * 
+ *
  * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
  *
  * A driver for the onboard Sonic ethernet controller on Mips Jazz
@@ -14,6 +19,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
@@ -27,7 +33,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
 #include <asm/jazz.h>
 #include <asm/jazzdma.h>
 
-#define DRV_NAME "jazzsonic"
+static char jazz_sonic_string[] = "jazzsonic";
+static struct platform_device *jazz_sonic_device;
 
-#define SREGS_PAD(n)    u16 n;
+#define SONIC_MEM_SIZE 0x100
 
 #include "sonic.h"
 
 /*
  * Macros to access SONIC registers
  */
-#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg))
+#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
 
 #define SONIC_WRITE(reg,val)                                           \
 do {                                                                   \
-       *((volatile unsigned int *)base_addr+reg) = val;                \
-}
+       *((volatile unsigned int *)dev->base_addr+(reg)) = (val);               \
+} while (0)
 
 
-/* use 0 for production, 1 for verification, >2 for debug */
+/* use 0 for production, 1 for verification, >1 for debug */
 #ifdef SONIC_DEBUG
 static unsigned int sonic_debug = SONIC_DEBUG;
-#else 
+#else
 static unsigned int sonic_debug = 1;
 #endif
 
@@ -72,7 +80,7 @@ static struct {
 /*
  * We cannot use station (ethernet) address prefixes to detect the
  * sonic controller since these are board manufacturer depended.
- * So we check for known Silicon Revision IDs instead. 
+ * So we check for known Silicon Revision IDs instead.
  */
 static unsigned short known_revisions[] =
 {
@@ -80,81 +88,18 @@ static unsigned short known_revisions[] =
        0xffff                  /* end of list */
 };
 
-/* Index to functions, as function prototypes. */
-
-static int sonic_probe1(struct net_device *dev, unsigned int base_addr,
-                        unsigned int irq);
-
-
-/*
- * Probe for a SONIC ethernet controller on a Mips Jazz board.
- * Actually probing is superfluous but we're paranoid.
- */
-struct net_device * __init sonic_probe(int unit)
-{
-       struct net_device *dev;
-       struct sonic_local *lp;
-       unsigned int base_addr;
-       int err = 0;
-       int i;
-
-       /*
-        * Don't probe if we're not running on a Jazz board.
-        */
-       if (mips_machgroup != MACH_GROUP_JAZZ)
-               return ERR_PTR(-ENODEV);
-
-       dev = alloc_etherdev(0);
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       sprintf(dev->name, "eth%d", unit);
-       netdev_boot_setup_check(dev);
-       base_addr = dev->base_addr;
-
-       if (base_addr >= KSEG0) { /* Check a single specified location. */
-               err = sonic_probe1(dev, base_addr, dev->irq);
-       } else if (base_addr != 0) { /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-               for (i = 0; sonic_portlist[i].port; i++) {
-                       int io = sonic_portlist[i].port;
-                       if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0)
-                               break;
-               }
-               if (!sonic_portlist[i].port)
-                       err = -ENODEV;
-       }
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       lp = dev->priv;
-       vdma_free(lp->rba_laddr);
-       kfree(lp->rba);
-       vdma_free(lp->cda_laddr);
-       kfree(lp);
-       release_region(dev->base_addr, 0x100);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
-                               unsigned int irq)
+static int __init sonic_probe1(struct net_device *dev)
 {
        static unsigned version_printed;
        unsigned int silicon_revision;
        unsigned int val;
-       struct sonic_local *lp;
+       struct sonic_local *lp = netdev_priv(dev);
        int err = -ENODEV;
        int i;
 
-       if (!request_region(base_addr, 0x100, DRV_NAME))
+       if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
                return -EBUSY;
+
        /*
         * get the Silicon Revision ID. If this is one of the known
         * one assume that we found a SONIC ethernet controller at
@@ -174,15 +119,11 @@ static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
                       silicon_revision);
                goto out;
        }
-    
+
        if (sonic_debug  &&  version_printed++ == 0)
                printk(version);
 
-       printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr);
-
-       /* Fill in the 'dev' fields. */
-       dev->base_addr = base_addr;
-       dev->irq = irq;
+       printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr);
 
        /*
         * Put the sonic into software reset, then
@@ -196,84 +137,44 @@ static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
                dev->dev_addr[i*2+1] = val >> 8;
        }
 
-       printk("HW Address ");
-       for (i = 0; i < 6; i++) {
-               printk("%2.2x", dev->dev_addr[i]);
-               if (i<5)
-                       printk(":");
-       }
-
-       printk(" IRQ %d\n", irq);
-
        err = -ENOMEM;
-    
-       /* Initialize the device structure. */
-       if (dev->priv == NULL) {
-               /*
-                * the memory be located in the same 64kb segment
-                */
-               lp = NULL;
-               i = 0;
-               do {
-                       lp = kmalloc(sizeof(*lp), GFP_KERNEL);
-                       if ((unsigned long) lp >> 16
-                           != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
-                               /* FIXME, free the memory later */
-                               kfree(lp);
-                               lp = NULL;
-                       }
-               } while (lp == NULL && i++ < 20);
-
-               if (lp == NULL) {
-                       printk("%s: couldn't allocate memory for descriptors\n",
-                              dev->name);
-                       goto out;
-               }
 
-               memset(lp, 0, sizeof(struct sonic_local));
-
-               /* get the virtual dma address */
-               lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
-               if (lp->cda_laddr == ~0UL) {
-                       printk("%s: couldn't get DMA page entry for "
-                              "descriptors\n", dev->name);
-                       goto out1;
-               }
-
-               lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
-               lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
-               lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
-       
-               /* allocate receive buffer area */
-               /* FIXME, maybe we should use skbs */
-               lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL);
-               if (!lp->rba) {
-                       printk("%s: couldn't allocate receive buffers\n",
-                              dev->name);
-                       goto out2;
-               }
+       /* Initialize the device structure. */
 
-               /* get virtual dma address */
-               lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),
-                                          SONIC_NUM_RRS * SONIC_RBSIZE);
-               if (lp->rba_laddr == ~0UL) {
-                       printk("%s: couldn't get DMA page entry for receive "
-                              "buffers\n",dev->name);
-                       goto out3;
-               }
+       lp->dma_bitmode = SONIC_BITMODE32;
 
-               /* now convert pointer to KSEG1 pointer */
-               lp->rba = (char *)KSEG1ADDR(lp->rba);
-               flush_cache_all();
-               dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
+       /* Allocate the entire chunk of memory for the descriptors.
+           Note that this cannot cross a 64K boundary. */
+       if ((lp->descriptors = dma_alloc_coherent(lp->device,
+                               SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                               &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
+               goto out;
        }
 
-       lp = (struct sonic_local *)dev->priv;
+       /* Now set up the pointers to point to the appropriate places */
+       lp->cda = lp->descriptors;
+       lp->tda = lp->cda + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+       lp->cda_laddr = lp->descriptors_laddr;
+       lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+
        dev->open = sonic_open;
        dev->stop = sonic_close;
        dev->hard_start_xmit = sonic_send_packet;
-       dev->get_stats  = sonic_get_stats;
+       dev->get_stats = sonic_get_stats;
        dev->set_multicast_list = &sonic_multicast_list;
+       dev->tx_timeout = sonic_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
 
        /*
@@ -284,23 +185,142 @@ static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
        SONIC_WRITE(SONIC_MPT,0xffff);
 
        return 0;
-out3:
-       kfree(lp->rba);
-out2:
-       vdma_free(lp->cda_laddr);
-out1:
-       kfree(lp);
 out:
-       release_region(base_addr, 0x100);
+       release_region(dev->base_addr, SONIC_MEM_SIZE);
        return err;
 }
 
 /*
- *      SONIC uses a normal IRQ
+ * Probe for a SONIC ethernet controller on a Mips Jazz board.
+ * Actually probing is superfluous but we're paranoid.
  */
-#define sonic_request_irq       request_irq
-#define sonic_free_irq          free_irq
+static int __init jazz_sonic_probe(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct sonic_local *lp;
+       int err = 0;
+       int i;
+
+       /*
+        * Don't probe if we're not running on a Jazz board.
+        */
+       if (mips_machgroup != MACH_GROUP_JAZZ)
+               return -ENODEV;
 
-#define sonic_chiptomem(x)      KSEG1ADDR(vdma_log2phys(x))
+       dev = alloc_etherdev(sizeof(struct sonic_local));
+       if (!dev)
+               return -ENOMEM;
+
+       lp = netdev_priv(dev);
+       lp->device = &pdev->dev;
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       SET_MODULE_OWNER(dev);
+
+       netdev_boot_setup_check(dev);
+
+       if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
+               err = sonic_probe1(dev);
+       } else if (dev->base_addr != 0) { /* Don't probe at all. */
+               err = -ENXIO;
+       } else {
+               for (i = 0; sonic_portlist[i].port; i++) {
+                       dev->base_addr = sonic_portlist[i].port;
+                       dev->irq = sonic_portlist[i].irq;
+                       if (sonic_probe1(dev) == 0)
+                               break;
+               }
+               if (!sonic_portlist[i].port)
+                       err = -ENODEV;
+       }
+       if (err)
+               goto out;
+       err = register_netdev(dev);
+       if (err)
+               goto out1;
+
+       printk("%s: MAC ", dev->name);
+       for (i = 0; i < 6; i++) {
+               printk("%2.2x", dev->dev_addr[i]);
+               if (i < 5)
+                       printk(":");
+       }
+       printk(" IRQ %d\n", dev->irq);
+
+       return 0;
+
+out1:
+       release_region(dev->base_addr, SONIC_MEM_SIZE);
+out:
+       free_netdev(dev);
+
+       return err;
+}
+
+MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
+module_param(sonic_debug, int, 0);
+MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
+
+#define SONIC_IRQ_FLAG IRQF_DISABLED
 
 #include "sonic.c"
+
+static int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct sonic_local* lp = netdev_priv(dev);
+
+       unregister_netdev (dev);
+       dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                         lp->descriptors, lp->descriptors_laddr);
+       release_region (dev->base_addr, SONIC_MEM_SIZE);
+       free_netdev (dev);
+
+       return 0;
+}
+
+static struct platform_driver jazz_sonic_driver = {
+       .probe  = jazz_sonic_probe,
+       .remove = __devexit_p(jazz_sonic_device_remove),
+       .driver = {
+               .name   = jazz_sonic_string,
+       },
+};
+
+static int __init jazz_sonic_init_module(void)
+{
+       int err;
+
+       if ((err = platform_driver_register(&jazz_sonic_driver))) {
+               printk(KERN_ERR "Driver registration failed\n");
+               return err;
+       }
+
+       jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0);
+       if (!jazz_sonic_device)
+               goto out_unregister;
+
+       if (platform_device_add(jazz_sonic_device)) {
+               platform_device_put(jazz_sonic_device);
+               jazz_sonic_device = NULL;
+       }
+
+       return 0;
+
+out_unregister:
+       platform_driver_unregister(&jazz_sonic_driver);
+
+       return -ENOMEM;
+}
+
+static void __exit jazz_sonic_cleanup_module(void)
+{
+       platform_driver_unregister(&jazz_sonic_driver);
+
+       if (jazz_sonic_device) {
+               platform_device_unregister(jazz_sonic_device);
+               jazz_sonic_device = NULL;
+       }
+}
+
+module_init(jazz_sonic_init_module);
+module_exit(jazz_sonic_cleanup_module);