fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / myri_sbus.c
index c4c9cb2..ee26ef5 100644 (file)
@@ -1,13 +1,12 @@
-/* myri_sbus.h: MyriCOM MyriNET SBUS card driver.
+/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
  *
- * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
  */
 
 static char version[] =
-        "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+        "myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n";
 
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -22,6 +21,7 @@ static char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <net/dst.h>
 #include <net/arp.h>
@@ -29,7 +29,6 @@ static char version[] =
 #include <net/ipv6.h>
 
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
@@ -40,7 +39,6 @@ static char version[] =
 #include <asm/auxio.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/checksum.h>
 
 #include "myri_sbus.h"
 #include "myri_code.h"
@@ -81,11 +79,7 @@ static char version[] =
 #define DHDR(x)
 #endif
 
-#ifdef MODULE
-static struct myri_eth *root_myri_dev;
-#endif
-
-static void myri_reset_off(unsigned long lp, unsigned long cregs)
+static void myri_reset_off(void __iomem *lp, void __iomem *cregs)
 {
        /* Clear IRQ mask. */
        sbus_writel(0, lp + LANAI_EIMASK);
@@ -94,7 +88,7 @@ static void myri_reset_off(unsigned long lp, unsigned long cregs)
        sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL);
 }
 
-static void myri_reset_on(unsigned long cregs)
+static void myri_reset_on(void __iomem *cregs)
 {
        /* Enable RESET function. */
        sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL);
@@ -103,14 +97,14 @@ static void myri_reset_on(unsigned long cregs)
        sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);
 }
 
-static void myri_disable_irq(unsigned long lp, unsigned long cregs)
+static void myri_disable_irq(void __iomem *lp, void __iomem *cregs)
 {
        sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);
        sbus_writel(0, lp + LANAI_EIMASK);
        sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT);
 }
 
-static void myri_enable_irq(unsigned long lp, unsigned long cregs)
+static void myri_enable_irq(void __iomem *lp, void __iomem *cregs)
 {
        sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL);
        sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK);
@@ -118,8 +112,8 @@ static void myri_enable_irq(unsigned long lp, unsigned long cregs)
 
 static inline void bang_the_chip(struct myri_eth *mp)
 {
-       struct myri_shmem *shmem        = mp->shmem;
-       unsigned long cregs             = mp->cregs;
+       struct myri_shmem __iomem *shmem = mp->shmem;
+       void __iomem *cregs             = mp->cregs;
 
        sbus_writel(1, &shmem->send);
        sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL);
@@ -127,9 +121,9 @@ static inline void bang_the_chip(struct myri_eth *mp)
 
 static int myri_do_handshake(struct myri_eth *mp)
 {
-       struct myri_shmem *shmem        = mp->shmem;
-       unsigned long cregs = mp->cregs;
-       struct myri_channel *chan       = &shmem->channel;
+       struct myri_shmem __iomem *shmem = mp->shmem;
+       void __iomem *cregs = mp->cregs;
+       struct myri_channel __iomem *chan = &shmem->channel;
        int tick                        = 0;
 
        DET(("myri_do_handshake: "));
@@ -173,30 +167,30 @@ static int myri_do_handshake(struct myri_eth *mp)
        return 0;
 }
 
-static int myri_load_lanai(struct myri_eth *mp)
+static int __devinit myri_load_lanai(struct myri_eth *mp)
 {
        struct net_device       *dev = mp->dev;
-       struct myri_shmem       *shmem = mp->shmem;
-       unsigned char           *rptr;
+       struct myri_shmem __iomem *shmem = mp->shmem;
+       void __iomem            *rptr;
        int                     i;
 
        myri_disable_irq(mp->lregs, mp->cregs);
        myri_reset_on(mp->cregs);
 
-       rptr = (unsigned char *) mp->lanai;
+       rptr = mp->lanai;
        for (i = 0; i < mp->eeprom.ramsz; i++)
-               sbus_writeb(0, &rptr[i]);
+               sbus_writeb(0, rptr + i);
 
        if (mp->eeprom.cpuvers >= CPUVERS_3_0)
                sbus_writel(mp->eeprom.cval, mp->lregs + LANAI_CVAL);
 
        /* Load executable code. */
        for (i = 0; i < sizeof(lanai4_code); i++)
-               sbus_writeb(lanai4_code[i], &rptr[(lanai4_code_off * 2) + i]);
+               sbus_writeb(lanai4_code[i], rptr + (lanai4_code_off * 2) + i);
 
        /* Load data segment. */
        for (i = 0; i < sizeof(lanai4_data); i++)
-               sbus_writeb(lanai4_data[i], &rptr[(lanai4_data_off * 2) + i]);
+               sbus_writeb(lanai4_data[i], rptr + (lanai4_data_off * 2) + i);
 
        /* Set device address. */
        sbus_writeb(0, &shmem->addr[0]);
@@ -237,15 +231,15 @@ static int myri_load_lanai(struct myri_eth *mp)
 
 static void myri_clean_rings(struct myri_eth *mp)
 {
-       struct sendq *sq = mp->sq;
-       struct recvq *rq = mp->rq;
+       struct sendq __iomem *sq = mp->sq;
+       struct recvq __iomem *rq = mp->rq;
        int i;
 
        sbus_writel(0, &rq->tail);
        sbus_writel(0, &rq->head);
        for (i = 0; i < (RX_RING_SIZE+1); i++) {
                if (mp->rx_skbs[i] != NULL) {
-                       struct myri_rxd *rxd = &rq->myri_rxd[i];
+                       struct myri_rxd __iomem *rxd = &rq->myri_rxd[i];
                        u32 dma_addr;
 
                        dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
@@ -261,7 +255,7 @@ static void myri_clean_rings(struct myri_eth *mp)
        for (i = 0; i < TX_RING_SIZE; i++) {
                if (mp->tx_skbs[i] != NULL) {
                        struct sk_buff *skb = mp->tx_skbs[i];
-                       struct myri_txd *txd = &sq->myri_txd[i];
+                       struct myri_txd __iomem *txd = &sq->myri_txd[i];
                        u32 dma_addr;
 
                        dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
@@ -274,10 +268,10 @@ static void myri_clean_rings(struct myri_eth *mp)
 
 static void myri_init_rings(struct myri_eth *mp, int from_irq)
 {
-       struct recvq *rq = mp->rq;
-       struct myri_rxd *rxd = &rq->myri_rxd[0];
+       struct recvq __iomem *rq = mp->rq;
+       struct myri_rxd __iomem *rxd = &rq->myri_rxd[0];
        struct net_device *dev = mp->dev;
-       int gfp_flags = GFP_KERNEL;
+       gfp_t gfp_flags = GFP_KERNEL;
        int i;
 
        if (from_irq || in_interrupt())
@@ -343,7 +337,7 @@ static void dump_ehdr_and_myripad(unsigned char *stuff)
 
 static void myri_tx(struct myri_eth *mp, struct net_device *dev)
 {
-       struct sendq *sq        = mp->sq;
+       struct sendq __iomem *sq= mp->sq;
        int entry               = mp->tx_old;
        int limit               = sbus_readl(&sq->head);
 
@@ -365,19 +359,19 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
        mp->tx_old = entry;
 }
 
-/* Determine the packet's protocol ID. The rule here is that we 
+/* Determine the packet's protocol ID. The rule here is that we
  * assume 802.3 if the type field is short enough to be a length.
  * This is normal practice and works for any 'now in use' protocol.
  */
-static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        struct ethhdr *eth;
        unsigned char *rawp;
-       
+
        skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN);
        skb_pull(skb, dev->hard_header_len);
-       eth = skb->mac.ethernet;
-       
+       eth = eth_hdr(skb);
+
 #ifdef DEBUG_HEADER
        DHDR(("myri_type_trans: "));
        dump_ehdr(eth);
@@ -391,12 +385,12 @@ static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *de
                if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
                        skb->pkt_type = PACKET_OTHERHOST;
        }
-       
+
        if (ntohs(eth->h_proto) >= 1536)
                return eth->h_proto;
-               
+
        rawp = skb->data;
-       
+
        /* This is a magic hack to spot IPX packets. Older Novell breaks
         * the protocol design and runs IPX over 802.3 without an 802.2 LLC
         * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
@@ -404,15 +398,15 @@ static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *de
         */
        if (*(unsigned short *)rawp == 0xFFFF)
                return htons(ETH_P_802_3);
-               
+
        /* Real 802.2 LLC */
        return htons(ETH_P_802_2);
 }
 
 static void myri_rx(struct myri_eth *mp, struct net_device *dev)
 {
-       struct recvq *rq        = mp->rq;
-       struct recvq *rqa       = mp->rqack;
+       struct recvq __iomem *rq = mp->rq;
+       struct recvq __iomem *rqa = mp->rqack;
        int entry               = sbus_readl(&rqa->head);
        int limit               = sbus_readl(&rqa->tail);
        int drops;
@@ -423,11 +417,11 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
        drops = 0;
        DRX(("\n"));
        while (entry != limit) {
-               struct myri_rxd *rxdack = &rqa->myri_rxd[entry];
+               struct myri_rxd __iomem *rxdack = &rqa->myri_rxd[entry];
                u32 csum                = sbus_readl(&rxdack->csum);
                int len                 = sbus_readl(&rxdack->myri_scatters[0].len);
                int index               = sbus_readl(&rxdack->ctx);
-               struct myri_rxd *rxd    = &rq->myri_rxd[rq->tail];
+               struct myri_rxd __iomem *rxd = &rq->myri_rxd[sbus_readl(&rq->tail)];
                struct sk_buff *skb     = mp->rx_skbs[index];
 
                /* Ack it. */
@@ -541,12 +535,12 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
        }
 }
 
-static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t myri_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev          = (struct net_device *) dev_id;
        struct myri_eth *mp             = (struct myri_eth *) dev->priv;
-       unsigned long lregs             = mp->lregs;
-       struct myri_channel *chan       = &mp->shmem->channel;
+       void __iomem *lregs             = mp->lregs;
+       struct myri_channel __iomem *chan = &mp->shmem->channel;
        unsigned long flags;
        u32 status;
        int handled = 0;
@@ -610,8 +604,8 @@ static void myri_tx_timeout(struct net_device *dev)
 static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct myri_eth *mp = (struct myri_eth *) dev->priv;
-       struct sendq *sq = mp->sq;
-       struct myri_txd *txd;
+       struct sendq __iomem *sq = mp->sq;
+       struct myri_txd __iomem *txd;
        unsigned long flags;
        unsigned int head, tail;
        int len, entry;
@@ -683,7 +677,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
-/* Create the MyriNet MAC header for an arbitrary protocol layer 
+/* Create the MyriNet MAC header for an arbitrary protocol layer
  *
  * saddr=NULL  means use device source address
  * daddr=NULL  means leave destination address (eg unresolved arp)
@@ -706,7 +700,7 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned sho
        /* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
         * in here instead. It is up to the 802.2 layer to carry protocol information.
         */
-       if (type != ETH_P_802_3) 
+       if (type != ETH_P_802_3)
                eth->h_proto = htons(type);
        else
                eth->h_proto = htons(len);
@@ -724,7 +718,7 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned sho
                        eth->h_dest[i] = 0;
                return(dev->hard_header_len);
        }
-       
+
        if (daddr) {
                memcpy(eth->h_dest, daddr, dev->addr_len);
                return dev->hard_header_len;
@@ -759,16 +753,16 @@ static int myri_rebuild_header(struct sk_buff *skb)
 #endif
 
        default:
-               printk(KERN_DEBUG 
-                      "%s: unable to resolve type %X addresses.\n", 
+               printk(KERN_DEBUG
+                      "%s: unable to resolve type %X addresses.\n",
                       dev->name, (int)eth->h_proto);
-               
+
                memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
                return 0;
                break;
        }
 
-       return 0;       
+       return 0;
 }
 
 int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
@@ -896,8 +890,9 @@ static void dump_eeprom(struct myri_eth *mp)
 }
 #endif
 
-static int __init myri_ether_init(struct sbus_dev *sdev, int num)
+static int __devinit myri_ether_init(struct sbus_dev *sdev)
 {
+       static int num;
        static unsigned version_printed;
        struct net_device *dev;
        struct myri_eth *mp;
@@ -913,6 +908,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
        if (version_printed++ == 0)
                printk(version);
 
+       SET_MODULE_OWNER(dev);
+       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+
        mp = (struct myri_eth *) dev->priv;
        spin_lock_init(&mp->irq_lock);
        mp->myri_sdev = sdev;
@@ -998,22 +996,20 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
                        printk("MyriCOM: Cannot map MyriCOM registers.\n");
                        goto err;
                }
-               mp->lanai = (unsigned short *) (mp->regs + (256 * 1024));
-               mp->lanai3 = (unsigned int *) mp->lanai;
-               mp->lregs = (unsigned long) &mp->lanai[0x10000];
+               mp->lanai = mp->regs + (256 * 1024);
+               mp->lregs = mp->lanai + (0x10000 * 2);
        } else {
                DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n"));
                mp->cregs = sbus_ioremap(&sdev->resource[0], 0,
                                         PAGE_SIZE, "MyriCOM Control Regs");
                mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024),
                                         PAGE_SIZE, "MyriCOM LANAI Regs");
-               mp->lanai = (unsigned short *)
+               mp->lanai =
                        sbus_ioremap(&sdev->resource[0], (512 * 1024),
                                     mp->eeprom.ramsz, "MyriCOM SRAM");
-               mp->lanai3 = (unsigned int *) mp->lanai;
        }
-       DET(("Registers mapped: cregs[%lx] lregs[%lx] lanai[%p] lanai3[%p]\n",
-            mp->cregs, mp->lregs, mp->lanai, mp->lanai3));
+       DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n",
+            mp->cregs, mp->lregs, mp->lanai));
 
        if (mp->eeprom.cpuvers >= CPUVERS_4_0)
                mp->shmem_base = 0xf000;
@@ -1022,7 +1018,8 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
 
        DET(("Shared memory base is %04x, ", mp->shmem_base));
 
-       mp->shmem = (struct myri_shmem *) &mp->lanai[mp->shmem_base];
+       mp->shmem = (struct myri_shmem __iomem *)
+               (mp->lanai + (mp->shmem_base * 2));
        DET(("shmem mapped at %p\n", mp->shmem));
 
        mp->rqack       = &mp->shmem->channel.recvqa;
@@ -1071,7 +1068,7 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
        /* Register interrupt handler now. */
        DET(("Requesting MYRIcom IRQ line.\n"));
        if (request_irq(dev->irq, &myri_interrupt,
-                       SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) {
+                       IRQF_SHARED, "MyriCOM Ethernet", (void *) dev)) {
                printk("MyriCOM: Cannot register interrupt handler.\n");
                goto err;
        }
@@ -1093,10 +1090,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
                goto err_free_irq;
        }
 
-#ifdef MODULE
-       mp->next_module = root_myri_dev;
-       root_myri_dev = mp;
-#endif
+       dev_set_drvdata(&sdev->ofdev.dev, mp);
+
+       num++;
 
        printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
 
@@ -1115,61 +1111,68 @@ err:
        return -ENODEV;
 }
 
-static int __init myri_sbus_match(struct sbus_dev *sdev)
-{
-       char *name = sdev->prom_name;
 
-       if (!strcmp(name, "MYRICOM,mlanai") ||
-           !strcmp(name, "myri"))
-               return 1;
+static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
 
-       return 0;
+       return myri_ether_init(sdev);
 }
 
-static int __init myri_sbus_probe(void)
+static int __devexit myri_sbus_remove(struct of_device *dev)
 {
-       struct sbus_bus *bus;
-       struct sbus_dev *sdev = NULL;
-       static int called;
-       int cards = 0, v;
+       struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+       struct net_device *net_dev = mp->dev;
 
-#ifdef MODULE
-       root_myri_dev = NULL;
-#endif
+       unregister_netdevice(net_dev);
 
-       if (called)
-               return -ENODEV;
-       called++;
-
-       for_each_sbus(bus) {
-               for_each_sbusdev(sdev, bus) {
-                       if (myri_sbus_match(sdev)) {
-                               cards++;
-                               DET(("Found myricom myrinet as %s\n", sdev->prom_name));
-                               if ((v = myri_ether_init(sdev, (cards - 1))))
-                                       return v;
-                       }
-               }
+       free_irq(net_dev->irq, net_dev);
+
+       if (mp->eeprom.cpuvers < CPUVERS_4_0) {
+               sbus_iounmap(mp->regs, mp->reg_size);
+       } else {
+               sbus_iounmap(mp->cregs, PAGE_SIZE);
+               sbus_iounmap(mp->lregs, (256 * 1024));
+               sbus_iounmap(mp->lanai, (512 * 1024));
        }
-       if (!cards)
-               return -ENODEV;
+
+       free_netdev(net_dev);
+
+       dev_set_drvdata(&dev->dev, NULL);
+
        return 0;
 }
 
-static void __exit myri_sbus_cleanup(void)
+static struct of_device_id myri_sbus_match[] = {
+       {
+               .name = "MYRICOM,mlanai",
+       },
+       {
+               .name = "myri",
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, myri_sbus_match);
+
+static struct of_platform_driver myri_sbus_driver = {
+       .name           = "myri",
+       .match_table    = myri_sbus_match,
+       .probe          = myri_sbus_probe,
+       .remove         = __devexit_p(myri_sbus_remove),
+};
+
+static int __init myri_sbus_init(void)
+{
+       return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit myri_sbus_exit(void)
 {
-#ifdef MODULE
-       while (root_myri_dev) {
-               struct myri_eth *next = root_myri_dev->next_module;
-
-               unregister_netdev(root_myri_dev->dev);
-               /* this will also free the co-allocated 'root_myri_dev' */
-               free_netdev(root_myri_dev->dev);
-               root_myri_dev = next;
-       }
-#endif /* MODULE */
+       of_unregister_driver(&myri_sbus_driver);
 }
 
-module_init(myri_sbus_probe);
-module_exit(myri_sbus_cleanup);
+module_init(myri_sbus_init);
+module_exit(myri_sbus_exit);
+
 MODULE_LICENSE("GPL");