Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / atm / fore200e.c
index b2f1375..05983a3 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
 #include <linux/dma-mapping.h>
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
 #include <linux/dma-mapping.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/string.h>
 #include <asm/page.h>
 #include <asm/io.h>
 #include <asm/string.h>
 #include <asm/page.h>
 
 #define FORE200E_NEXT_ENTRY(index, modulo)         (index = ++(index) % (modulo))
 
 
 #define FORE200E_NEXT_ENTRY(index, modulo)         (index = ++(index) % (modulo))
 
-
-#define MSECS(ms)  (((ms)*HZ/1000)+1)
-
-
 #if 1
 #define ASSERT(expr)     if (!(expr)) { \
                             printk(FORE200E "assertion failed! %s[%d]: %s\n", \
 #if 1
 #define ASSERT(expr)     if (!(expr)) { \
                             printk(FORE200E "assertion failed! %s[%d]: %s\n", \
 static const struct atmdev_ops   fore200e_ops;
 static const struct fore200e_bus fore200e_bus[];
 
 static const struct atmdev_ops   fore200e_ops;
 static const struct fore200e_bus fore200e_bus[];
 
-static struct fore200e* fore200e_boards = NULL;
+static LIST_HEAD(fore200e_boards);
 
 
 MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");
 
 
 MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");
@@ -181,14 +178,12 @@ fore200e_irq_itoa(int irq)
 
 
 static void*
 
 
 static void*
-fore200e_kmalloc(int size, int flags)
+fore200e_kmalloc(int size, gfp_t flags)
 {
 {
-    void* chunk = kmalloc(size, flags);
+    void *chunk = kzalloc(size, flags);
 
 
-    if (chunk)
-       memset(chunk, 0x00, size);
-    else
-       printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags);
+    if (!chunk)
+       printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n",                        size, flags);
     
     return chunk;
 }
     
     return chunk;
 }
@@ -245,7 +240,7 @@ fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
 static void
 fore200e_spin(int msecs)
 {
 static void
 fore200e_spin(int msecs)
 {
-    unsigned long timeout = jiffies + MSECS(msecs);
+    unsigned long timeout = jiffies + msecs_to_jiffies(msecs);
     while (time_before(jiffies, timeout));
 }
 
     while (time_before(jiffies, timeout));
 }
 
@@ -253,7 +248,7 @@ fore200e_spin(int msecs)
 static int
 fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs)
 {
 static int
 fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs)
 {
-    unsigned long timeout = jiffies + MSECS(msecs);
+    unsigned long timeout = jiffies + msecs_to_jiffies(msecs);
     int           ok;
 
     mb();
     int           ok;
 
     mb();
@@ -275,9 +270,9 @@ fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs)
 
 
 static int
 
 
 static int
-fore200e_io_poll(struct fore200e* fore200e, volatile u32addr, u32 val, int msecs)
+fore200e_io_poll(struct fore200e* fore200e, volatile u32 __iomem *addr, u32 val, int msecs)
 {
 {
-    unsigned long timeout = jiffies + MSECS(msecs);
+    unsigned long timeout = jiffies + msecs_to_jiffies(msecs);
     int           ok;
 
     do {
     int           ok;
 
     do {
@@ -347,7 +342,7 @@ fore200e_reset(struct fore200e* fore200e, int diag)
 {
     int ok;
 
 {
     int ok;
 
-    fore200e->cp_monitor = (struct cp_monitor*)(fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET);
+    fore200e->cp_monitor = fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET;
     
     fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat);
 
     
     fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat);
 
@@ -386,8 +381,7 @@ fore200e_shutdown(struct fore200e* fore200e)
     switch(fore200e->state) {
 
     case FORE200E_STATE_COMPLETE:
     switch(fore200e->state) {
 
     case FORE200E_STATE_COMPLETE:
-       if (fore200e->stats)
-           kfree(fore200e->stats);
+       kfree(fore200e->stats);
 
     case FORE200E_STATE_IRQ:
        free_irq(fore200e->irq, fore200e->atm_dev);
 
     case FORE200E_STATE_IRQ:
        free_irq(fore200e->irq, fore200e->atm_dev);
@@ -440,7 +434,7 @@ fore200e_shutdown(struct fore200e* fore200e)
 
 #ifdef CONFIG_ATM_FORE200E_PCA
 
 
 #ifdef CONFIG_ATM_FORE200E_PCA
 
-static u32 fore200e_pca_read(volatile u32addr)
+static u32 fore200e_pca_read(volatile u32 __iomem *addr)
 {
     /* on big-endian hosts, the board is configured to convert
        the endianess of slave RAM accesses  */
 {
     /* on big-endian hosts, the board is configured to convert
        the endianess of slave RAM accesses  */
@@ -448,7 +442,7 @@ static u32 fore200e_pca_read(volatile u32* addr)
 }
 
 
 }
 
 
-static void fore200e_pca_write(u32 val, volatile u32addr)
+static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr)
 {
     /* on big-endian hosts, the board is configured to convert
        the endianess of slave RAM accesses  */
 {
     /* on big-endian hosts, the board is configured to convert
        the endianess of slave RAM accesses  */
@@ -561,7 +555,7 @@ fore200e_pca_reset(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_pca_map(struct fore200e* fore200e)
 {
     DPRINTK(2, "device %s being mapped in memory\n", fore200e->name);
 fore200e_pca_map(struct fore200e* fore200e)
 {
     DPRINTK(2, "device %s being mapped in memory\n", fore200e->name);
@@ -576,9 +570,9 @@ fore200e_pca_map(struct fore200e* fore200e)
     DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
 
     /* gain access to the PCA specific registers  */
     DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
 
     /* gain access to the PCA specific registers  */
-    fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET);
-    fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET);
-    fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET);
+    fore200e->regs.pca.hcr = fore200e->virt_base + PCA200E_HCR_OFFSET;
+    fore200e->regs.pca.imr = fore200e->virt_base + PCA200E_IMR_OFFSET;
+    fore200e->regs.pca.psr = fore200e->virt_base + PCA200E_PSR_OFFSET;
 
     fore200e->state = FORE200E_STATE_MAP;
     return 0;
 
     fore200e->state = FORE200E_STATE_MAP;
     return 0;
@@ -595,7 +589,7 @@ fore200e_pca_unmap(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_pca_configure(struct fore200e* fore200e)
 {
     struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
 fore200e_pca_configure(struct fore200e* fore200e)
 {
     struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
@@ -636,39 +630,6 @@ fore200e_pca_configure(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static struct fore200e* __init
-fore200e_pca_detect(const struct fore200e_bus* bus, int index)
-{
-    struct fore200e* fore200e;
-    struct pci_dev*  pci_dev = NULL;
-    int              count = index;
-    
-    do {
-       pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev);
-       if (pci_dev == NULL)
-           return NULL;
-    } while (count--);
-
-    if (pci_enable_device(pci_dev))
-       return NULL;
-    
-    fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
-    if (fore200e == NULL)
-       return NULL;
-
-    fore200e->bus       = bus;
-    fore200e->bus_dev   = pci_dev;    
-    fore200e->irq       = pci_dev->irq;
-    fore200e->phys_base = pci_resource_start(pci_dev, 0);
-
-    sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
-
-    pci_set_master(pci_dev);
-
-    return fore200e;
-}
-
-
 static int __init
 fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
 {
 static int __init
 fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
 {
@@ -689,7 +650,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
     
     *entry->status = STATUS_PENDING;
 
     
     *entry->status = STATUS_PENDING;
 
-    fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.prom_block.opcode);
+    fore200e->bus->write(*(u32*)&opcode, (u32 __iomem *)&entry->cp_entry->cmd.prom_block.opcode);
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
 
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
 
@@ -730,14 +691,14 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
 #ifdef CONFIG_ATM_FORE200E_SBA
 
 static u32
 #ifdef CONFIG_ATM_FORE200E_SBA
 
 static u32
-fore200e_sba_read(volatile u32addr)
+fore200e_sba_read(volatile u32 __iomem *addr)
 {
     return sbus_readl(addr);
 }
 
 
 static void
 {
     return sbus_readl(addr);
 }
 
 
 static void
-fore200e_sba_write(u32 val, volatile u32addr)
+fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
 {
     sbus_writel(val, addr);
 }
 {
     sbus_writel(val, addr);
 }
@@ -856,10 +817,10 @@ fore200e_sba_map(struct fore200e* fore200e)
     unsigned int bursts;
 
     /* gain access to the SBA specific registers  */
     unsigned int bursts;
 
     /* gain access to the SBA specific registers  */
-    fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
-    fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
-    fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
-    fore200e->virt_base    = (u32*)sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
+    fore200e->regs.sba.hcr = sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
+    fore200e->regs.sba.bsr = sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
+    fore200e->regs.sba.isr = sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
+    fore200e->virt_base    = sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
 
     if (fore200e->virt_base == NULL) {
        printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
 
     if (fore200e->virt_base == NULL) {
        printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
@@ -884,10 +845,10 @@ fore200e_sba_map(struct fore200e* fore200e)
 static void
 fore200e_sba_unmap(struct fore200e* fore200e)
 {
 static void
 fore200e_sba_unmap(struct fore200e* fore200e)
 {
-    sbus_iounmap((ulong)fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
-    sbus_iounmap((ulong)fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
-    sbus_iounmap((ulong)fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
-    sbus_iounmap((ulong)fore200e->virt_base,    SBA200E_RAM_LENGTH);
+    sbus_iounmap(fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
+    sbus_iounmap(fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
+    sbus_iounmap(fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
+    sbus_iounmap(fore200e->virt_base,    SBA200E_RAM_LENGTH);
 }
 
 
 }
 
 
@@ -999,8 +960,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
                entry, txq->tail, entry->vc_map, entry->skb);
 
        /* free copy of misaligned data */
                entry, txq->tail, entry->vc_map, entry->skb);
 
        /* free copy of misaligned data */
-       if (entry->data)
-           kfree(entry->data);
+       kfree(entry->data);
        
        /* remove DMA mapping */
        fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
        
        /* remove DMA mapping */
        fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
@@ -1026,7 +986,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
                /* when a vcc is closed, some PDUs may be still pending in the tx queue.
                   if the same vcc is immediately re-opened, those pending PDUs must
                   not be popped after the completion of their emission, as they refer
                /* when a vcc is closed, some PDUs may be still pending in the tx queue.
                   if the same vcc is immediately re-opened, those pending PDUs must
                   not be popped after the completion of their emission, as they refer
-                  to the prior incarnation of that vcc. otherwise, vcc->sk->sk_wmem_alloc
+                  to the prior incarnation of that vcc. otherwise, sk_atm(vcc)->sk_wmem_alloc
                   would be decremented by the size of the (unrelated) skb, possibly
                   leading to a negative sk->sk_wmem_alloc count, ultimately freezing the vcc.
                   we thus bind the tx entry to the current incarnation of the vcc
                   would be decremented by the size of the (unrelated) skb, possibly
                   leading to a negative sk->sk_wmem_alloc count, ultimately freezing the vcc.
                   we thus bind the tx entry to the current incarnation of the vcc
@@ -1053,8 +1013,8 @@ fore200e_tx_irq(struct fore200e* fore200e)
                }
 #if 1
                /* race fixed by the above incarnation mechanism, but... */
                }
 #if 1
                /* race fixed by the above incarnation mechanism, but... */
-               if (atomic_read(&vcc->sk->sk_wmem_alloc) < 0) {
-                   atomic_set(&vcc->sk->sk_wmem_alloc, 0);
+               if (atomic_read(&sk_atm(vcc)->sk_wmem_alloc) < 0) {
+                   atomic_set(&sk_atm(vcc)->sk_wmem_alloc, 0);
                }
 #endif
                /* check error condition */
                }
 #endif
                /* check error condition */
@@ -1214,7 +1174,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp
        return -ENOMEM;
     } 
 
        return -ENOMEM;
     } 
 
-    do_gettimeofday(&skb->stamp);
+    __net_timestamp(skb);
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
@@ -1257,12 +1217,12 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp
        return -ENOMEM;
     }
 
        return -ENOMEM;
     }
 
-    ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
+    ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
 
     vcc->push(vcc, skb);
     atomic_inc(&vcc->stats->rx);
 
 
     vcc->push(vcc, skb);
     atomic_inc(&vcc->stats->rx);
 
-    ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
+    ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
 
     return 0;
 }
 
     return 0;
 }
@@ -1477,12 +1437,12 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc*
 #endif
        /* the MTU is not used by the cp, except in the case of AAL0 */
        fore200e->bus->write(mtu,                        &entry->cp_entry->cmd.activate_block.mtu);
 #endif
        /* the MTU is not used by the cp, except in the case of AAL0 */
        fore200e->bus->write(mtu,                        &entry->cp_entry->cmd.activate_block.mtu);
-       fore200e->bus->write(*(u32*)&vpvc,         (u32*)&entry->cp_entry->cmd.activate_block.vpvc);
-       fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode);
+       fore200e->bus->write(*(u32*)&vpvc,         (u32 __iomem *)&entry->cp_entry->cmd.activate_block.vpvc);
+       fore200e->bus->write(*(u32*)&activ_opcode, (u32 __iomem *)&entry->cp_entry->cmd.activate_block.opcode);
     }
     else {
     }
     else {
-       fore200e->bus->write(*(u32*)&vpvc,           (u32*)&entry->cp_entry->cmd.deactivate_block.vpvc);
-       fore200e->bus->write(*(u32*)&deactiv_opcode, (u32*)&entry->cp_entry->cmd.deactivate_block.opcode);
+       fore200e->bus->write(*(u32*)&vpvc,         (u32 __iomem *)&entry->cp_entry->cmd.deactivate_block.vpvc);
+       fore200e->bus->write(*(u32*)&deactiv_opcode, (u32 __iomem *)&entry->cp_entry->cmd.deactivate_block.opcode);
     }
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
     }
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
@@ -1699,7 +1659,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
     unsigned long           flags;
 
     ASSERT(vcc);
     unsigned long           flags;
 
     ASSERT(vcc);
-    ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
+    ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
     ASSERT(fore200e);
     ASSERT(fore200e_vcc);
 
     ASSERT(fore200e);
     ASSERT(fore200e_vcc);
 
@@ -1779,7 +1739,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
 
            /* retry once again? */
            if (--retry > 0) {
 
            /* retry once again? */
            if (--retry > 0) {
-               schedule();
+               udelay(50);
                goto retry_here;
            }
 
                goto retry_here;
            }
 
@@ -1858,7 +1818,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
     tpd_haddr.haddr = entry->tpd_dma >> TPD_HADDR_SHIFT;          /* shift the address, as we are in a bitfield */
 
     *entry->status = STATUS_PENDING;
     tpd_haddr.haddr = entry->tpd_dma >> TPD_HADDR_SHIFT;          /* shift the address, as we are in a bitfield */
 
     *entry->status = STATUS_PENDING;
-    fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr);
+    fore200e->bus->write(*(u32*)&tpd_haddr, (u32 __iomem *)&entry->cp_entry->tpd_haddr);
 
     spin_unlock_irqrestore(&fore200e->q_lock, flags);
 
 
     spin_unlock_irqrestore(&fore200e->q_lock, flags);
 
@@ -1893,7 +1853,7 @@ fore200e_getstats(struct fore200e* fore200e)
     
     *entry->status = STATUS_PENDING;
 
     
     *entry->status = STATUS_PENDING;
 
-    fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.stats_block.opcode);
+    fore200e->bus->write(*(u32*)&opcode, (u32 __iomem *)&entry->cp_entry->cmd.stats_block.opcode);
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
 
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
 
@@ -1996,7 +1956,7 @@ fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask)
     
     *entry->status = STATUS_PENDING;
 
     
     *entry->status = STATUS_PENDING;
 
-    fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode);
+    fore200e->bus->write(*(u32*)&opcode, (u32 __iomem *)&entry->cp_entry->cmd.oc3_block.opcode);
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
 
 
     ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
 
@@ -2165,7 +2125,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
 }
     
 
 }
     
 
-static int __init
+static int __devinit
 fore200e_irq_request(struct fore200e* fore200e)
 {
     if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) {
 fore200e_irq_request(struct fore200e* fore200e)
 {
     if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) {
@@ -2188,7 +2148,7 @@ fore200e_irq_request(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_get_esi(struct fore200e* fore200e)
 {
     struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA);
 fore200e_get_esi(struct fore200e* fore200e)
 {
     struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA);
@@ -2220,7 +2180,7 @@ fore200e_get_esi(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_alloc_rx_buf(struct fore200e* fore200e)
 {
     int scheme, magn, nbr, size, i;
 fore200e_alloc_rx_buf(struct fore200e* fore200e)
 {
     int scheme, magn, nbr, size, i;
@@ -2285,13 +2245,13 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_init_bs_queue(struct fore200e* fore200e)
 {
     int scheme, magn, i;
 
     struct host_bsq*     bsq;
 fore200e_init_bs_queue(struct fore200e* fore200e)
 {
     int scheme, magn, i;
 
     struct host_bsq*     bsq;
-    struct cp_bsq_entry* cp_entry;
+    struct cp_bsq_entry __iomem * cp_entry;
 
     for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) {
        for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) {
 
     for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) {
        for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) {
@@ -2321,8 +2281,8 @@ fore200e_init_bs_queue(struct fore200e* fore200e)
            }
            
            /* get the base address of the cp resident buffer supply queue entries */
            }
            
            /* get the base address of the cp resident buffer supply queue entries */
-           cp_entry = (struct cp_bsq_entry*)(fore200e->virt_base + 
-                      fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ]));
+           cp_entry = fore200e->virt_base + 
+                      fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ]);
            
            /* fill the host resident and cp resident buffer supply queue entries */
            for (i = 0; i < QUEUE_SIZE_BS; i++) {
            
            /* fill the host resident and cp resident buffer supply queue entries */
            for (i = 0; i < QUEUE_SIZE_BS; i++) {
@@ -2348,11 +2308,11 @@ fore200e_init_bs_queue(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_init_rx_queue(struct fore200e* fore200e)
 {
     struct host_rxq*     rxq =  &fore200e->host_rxq;
 fore200e_init_rx_queue(struct fore200e* fore200e)
 {
     struct host_rxq*     rxq =  &fore200e->host_rxq;
-    struct cp_rxq_entry* cp_entry;
+    struct cp_rxq_entry __iomem * cp_entry;
     int i;
 
     DPRINTK(2, "receive queue is being initialized\n");
     int i;
 
     DPRINTK(2, "receive queue is being initialized\n");
@@ -2378,8 +2338,7 @@ fore200e_init_rx_queue(struct fore200e* fore200e)
     }
 
     /* get the base address of the cp resident rx queue entries */
     }
 
     /* get the base address of the cp resident rx queue entries */
-    cp_entry = (struct cp_rxq_entry*)(fore200e->virt_base + 
-                                     fore200e->bus->read(&fore200e->cp_queues->cp_rxq));
+    cp_entry = fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_rxq);
 
     /* fill the host resident and cp resident rx entries */
     for (i=0; i < QUEUE_SIZE_RX; i++) {
 
     /* fill the host resident and cp resident rx entries */
     for (i=0; i < QUEUE_SIZE_RX; i++) {
@@ -2409,11 +2368,11 @@ fore200e_init_rx_queue(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_init_tx_queue(struct fore200e* fore200e)
 {
     struct host_txq*     txq =  &fore200e->host_txq;
 fore200e_init_tx_queue(struct fore200e* fore200e)
 {
     struct host_txq*     txq =  &fore200e->host_txq;
-    struct cp_txq_entry* cp_entry;
+    struct cp_txq_entry __iomem * cp_entry;
     int i;
 
     DPRINTK(2, "transmit queue is being initialized\n");
     int i;
 
     DPRINTK(2, "transmit queue is being initialized\n");
@@ -2439,8 +2398,7 @@ fore200e_init_tx_queue(struct fore200e* fore200e)
     }
 
     /* get the base address of the cp resident tx queue entries */
     }
 
     /* get the base address of the cp resident tx queue entries */
-    cp_entry = (struct cp_txq_entry*)(fore200e->virt_base + 
-                                     fore200e->bus->read(&fore200e->cp_queues->cp_txq));
+    cp_entry = fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_txq);
 
     /* fill the host resident and cp resident tx entries */
     for (i=0; i < QUEUE_SIZE_TX; i++) {
 
     /* fill the host resident and cp resident tx entries */
     for (i=0; i < QUEUE_SIZE_TX; i++) {
@@ -2473,11 +2431,11 @@ fore200e_init_tx_queue(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_init_cmd_queue(struct fore200e* fore200e)
 {
     struct host_cmdq*     cmdq =  &fore200e->host_cmdq;
 fore200e_init_cmd_queue(struct fore200e* fore200e)
 {
     struct host_cmdq*     cmdq =  &fore200e->host_cmdq;
-    struct cp_cmdq_entry* cp_entry;
+    struct cp_cmdq_entry __iomem * cp_entry;
     int i;
 
     DPRINTK(2, "command queue is being initialized\n");
     int i;
 
     DPRINTK(2, "command queue is being initialized\n");
@@ -2492,8 +2450,7 @@ fore200e_init_cmd_queue(struct fore200e* fore200e)
     }
     
     /* get the base address of the cp resident cmd queue entries */
     }
     
     /* get the base address of the cp resident cmd queue entries */
-    cp_entry = (struct cp_cmdq_entry*)(fore200e->virt_base + 
-                                      fore200e->bus->read(&fore200e->cp_queues->cp_cmdq));
+    cp_entry = fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_cmdq);
 
     /* fill the host resident and cp resident cmd entries */
     for (i=0; i < QUEUE_SIZE_CMD; i++) {
 
     /* fill the host resident and cp resident cmd entries */
     for (i=0; i < QUEUE_SIZE_CMD; i++) {
@@ -2521,7 +2478,7 @@ fore200e_param_bs_queue(struct fore200e* fore200e,
                        enum buffer_scheme scheme, enum buffer_magn magn,
                        int queue_length, int pool_size, int supply_blksize)
 {
                        enum buffer_scheme scheme, enum buffer_magn magn,
                        int queue_length, int pool_size, int supply_blksize)
 {
-    struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ];
+    struct bs_spec __iomem * bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ];
 
     fore200e->bus->write(queue_length,                           &bs_spec->queue_length);
     fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size);
 
     fore200e->bus->write(queue_length,                           &bs_spec->queue_length);
     fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size);
@@ -2530,10 +2487,10 @@ fore200e_param_bs_queue(struct fore200e* fore200e,
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_initialize(struct fore200e* fore200e)
 {
 fore200e_initialize(struct fore200e* fore200e)
 {
-    struct cp_queues* cpq;
+    struct cp_queues __iomem * cpq;
     int               ok, scheme, magn;
 
     DPRINTK(2, "device %s being initialized\n", fore200e->name);
     int               ok, scheme, magn;
 
     DPRINTK(2, "device %s being initialized\n", fore200e->name);
@@ -2541,7 +2498,7 @@ fore200e_initialize(struct fore200e* fore200e)
     init_MUTEX(&fore200e->rate_sf);
     spin_lock_init(&fore200e->q_lock);
 
     init_MUTEX(&fore200e->rate_sf);
     spin_lock_init(&fore200e->q_lock);
 
-    cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET);
+    cpq = fore200e->cp_queues = fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET;
 
     /* enable cp to host interrupts */
     fore200e->bus->write(1, &cpq->imask);
 
     /* enable cp to host interrupts */
     fore200e->bus->write(1, &cpq->imask);
@@ -2582,10 +2539,10 @@ fore200e_initialize(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static void __init
+static void __devinit
 fore200e_monitor_putc(struct fore200e* fore200e, char c)
 {
 fore200e_monitor_putc(struct fore200e* fore200e, char c)
 {
-    struct cp_monitor* monitor = fore200e->cp_monitor;
+    struct cp_monitor __iomem * monitor = fore200e->cp_monitor;
 
 #if 0
     printk("%c", c);
 
 #if 0
     printk("%c", c);
@@ -2594,11 +2551,11 @@ fore200e_monitor_putc(struct fore200e* fore200e, char c)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_monitor_getc(struct fore200e* fore200e)
 {
 fore200e_monitor_getc(struct fore200e* fore200e)
 {
-    struct cp_monitor* monitor = fore200e->cp_monitor;
-    unsigned long      timeout = jiffies + MSECS(50);
+    struct cp_monitor __iomem * monitor = fore200e->cp_monitor;
+    unsigned long      timeout = jiffies + msecs_to_jiffies(50);
     int                c;
 
     while (time_before(jiffies, timeout)) {
     int                c;
 
     while (time_before(jiffies, timeout)) {
@@ -2619,7 +2576,7 @@ fore200e_monitor_getc(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static void __init
+static void __devinit
 fore200e_monitor_puts(struct fore200e* fore200e, char* str)
 {
     while (*str) {
 fore200e_monitor_puts(struct fore200e* fore200e, char* str)
 {
     while (*str) {
@@ -2634,7 +2591,7 @@ fore200e_monitor_puts(struct fore200e* fore200e, char* str)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_start_fw(struct fore200e* fore200e)
 {
     int               ok;
 fore200e_start_fw(struct fore200e* fore200e)
 {
     int               ok;
@@ -2665,7 +2622,7 @@ fore200e_start_fw(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_load_fw(struct fore200e* fore200e)
 {
     u32* fw_data = (u32*) fore200e->bus->fw_data;
 fore200e_load_fw(struct fore200e* fore200e)
 {
     u32* fw_data = (u32*) fore200e->bus->fw_data;
@@ -2673,7 +2630,7 @@ fore200e_load_fw(struct fore200e* fore200e)
 
     struct fw_header* fw_header = (struct fw_header*) fw_data;
 
 
     struct fw_header* fw_header = (struct fw_header*) fw_data;
 
-    u32load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset);
+    u32 __iomem *load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset);
 
     DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", 
            fore200e->name, load_addr, fw_size);
 
     DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", 
            fore200e->name, load_addr, fw_size);
@@ -2691,7 +2648,7 @@ fore200e_load_fw(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_register(struct fore200e* fore200e)
 {
     struct atm_dev* atm_dev;
 fore200e_register(struct fore200e* fore200e)
 {
     struct atm_dev* atm_dev;
@@ -2718,7 +2675,7 @@ fore200e_register(struct fore200e* fore200e)
 }
 
 
 }
 
 
-static int __init
+static int __devinit
 fore200e_init(struct fore200e* fore200e)
 {
     if (fore200e_register(fore200e) < 0)
 fore200e_init(struct fore200e* fore200e)
 {
     if (fore200e_register(fore200e) < 0)
@@ -2764,26 +2721,111 @@ fore200e_init(struct fore200e* fore200e)
        return -EBUSY;
 
     fore200e_supply(fore200e);
        return -EBUSY;
 
     fore200e_supply(fore200e);
-    
+
     /* all done, board initialization is now complete */
     fore200e->state = FORE200E_STATE_COMPLETE;
     return 0;
 }
 
     /* all done, board initialization is now complete */
     fore200e->state = FORE200E_STATE_COMPLETE;
     return 0;
 }
 
+
+static int __devinit
+fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
+{
+    const struct fore200e_bus* bus = (struct fore200e_bus*) pci_ent->driver_data;
+    struct fore200e* fore200e;
+    int err = 0;
+    static int index = 0;
+
+    if (pci_enable_device(pci_dev)) {
+       err = -EINVAL;
+       goto out;
+    }
+    
+    fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
+    if (fore200e == NULL) {
+       err = -ENOMEM;
+       goto out_disable;
+    }
+
+    fore200e->bus       = bus;
+    fore200e->bus_dev   = pci_dev;    
+    fore200e->irq       = pci_dev->irq;
+    fore200e->phys_base = pci_resource_start(pci_dev, 0);
+
+    sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+
+    pci_set_master(pci_dev);
+
+    printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
+          fore200e->bus->model_name, 
+          fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
+
+    sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+
+    err = fore200e_init(fore200e);
+    if (err < 0) {
+       fore200e_shutdown(fore200e);
+       goto out_free;
+    }
+
+    ++index;
+    pci_set_drvdata(pci_dev, fore200e);
+
+out:
+    return err;
+
+out_free:
+    kfree(fore200e);
+out_disable:
+    pci_disable_device(pci_dev);
+    goto out;
+}
+
+
+static void __devexit fore200e_pca_remove_one(struct pci_dev *pci_dev)
+{
+    struct fore200e *fore200e;
+
+    fore200e = pci_get_drvdata(pci_dev);
+
+    fore200e_shutdown(fore200e);
+    kfree(fore200e);
+    pci_disable_device(pci_dev);
+}
+
+
+#ifdef CONFIG_ATM_FORE200E_PCA
+static struct pci_device_id fore200e_pca_tbl[] = {
+    { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID,
+      0, 0, (unsigned long) &fore200e_bus[0] },
+    { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, fore200e_pca_tbl);
+
+static struct pci_driver fore200e_pca_driver = {
+    .name =     "fore_200e",
+    .probe =    fore200e_pca_detect,
+    .remove =   __devexit_p(fore200e_pca_remove_one),
+    .id_table = fore200e_pca_tbl,
+};
+#endif
+
+
 static int __init
 fore200e_module_init(void)
 {
     const struct fore200e_bus* bus;
     struct       fore200e*     fore200e;
 static int __init
 fore200e_module_init(void)
 {
     const struct fore200e_bus* bus;
     struct       fore200e*     fore200e;
-    int                        index, link;
+    int                        index;
 
     printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
 
     /* for each configured bus interface */
 
     printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
 
     /* for each configured bus interface */
-    for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
+    for (bus = fore200e_bus; bus->model_name; bus++) {
 
        /* detect all boards present on that bus */
 
        /* detect all boards present on that bus */
-       for (index = 0; (fore200e = bus->detect(bus, index)); index++) {
+       for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) {
            
            printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
                   fore200e->bus->model_name, 
            
            printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
                   fore200e->bus->model_name, 
@@ -2797,15 +2839,18 @@ fore200e_module_init(void)
                break;
            }
 
                break;
            }
 
-           link++;
-
-           fore200e->next  = fore200e_boards;
-           fore200e_boards = fore200e;
+           list_add(&fore200e->entry, &fore200e_boards);
        }
     }
 
        }
     }
 
-    if (link)
-        return 0;
+#ifdef CONFIG_ATM_FORE200E_PCA
+    if (!pci_register_driver(&fore200e_pca_driver))
+       return 0;
+#endif
+
+    if (!list_empty(&fore200e_boards))
+       return 0;
+
     return -ENODEV;
 }
 
     return -ENODEV;
 }
 
@@ -2813,11 +2858,14 @@ fore200e_module_init(void)
 static void __exit
 fore200e_module_cleanup(void)
 {
 static void __exit
 fore200e_module_cleanup(void)
 {
-    while (fore200e_boards) {
-        struct fore200e* fore200e = fore200e_boards;
+    struct fore200e *fore200e, *next;
+
+#ifdef CONFIG_ATM_FORE200E_PCA
+    pci_unregister_driver(&fore200e_pca_driver);
+#endif
 
 
+    list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) {
        fore200e_shutdown(fore200e);
        fore200e_shutdown(fore200e);
-       fore200e_boards = fore200e->next;
        kfree(fore200e);
     }
     DPRINTK(1, "module being removed\n");
        kfree(fore200e);
     }
     DPRINTK(1, "module being removed\n");
@@ -2854,7 +2902,7 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
                "   board serial number:\t\t%d\n\n",
                fore200e_irq_itoa(fore200e->irq),
                (void*)fore200e->phys_base,
                "   board serial number:\t\t%d\n\n",
                fore200e_irq_itoa(fore200e->irq),
                (void*)fore200e->phys_base,
-               (void*)fore200e->virt_base,
+               fore200e->virt_base,
                fore200e->esi[0], fore200e->esi[1], fore200e->esi[2],
                fore200e->esi[3], fore200e->esi[4], fore200e->esi[5],
                fore200e->esi[4] * 256 + fore200e->esi[5]);
                fore200e->esi[0], fore200e->esi[1], fore200e->esi[2],
                fore200e->esi[3], fore200e->esi[4], fore200e->esi[5],
                fore200e->esi[4] * 256 + fore200e->esi[5]);
@@ -2938,7 +2986,7 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
     }
 
     if (!left--) {
     }
 
     if (!left--) {
-       struct cp_monitor* cp_monitor = fore200e->cp_monitor;
+       struct cp_monitor __iomem * cp_monitor = fore200e->cp_monitor;
 
        return sprintf(page,
                       "\n\n"
 
        return sprintf(page,
                       "\n\n"
@@ -3152,7 +3200,7 @@ static const struct fore200e_bus fore200e_bus[] = {
       fore200e_pca_dma_sync_for_device,
       fore200e_pca_dma_chunk_alloc,
       fore200e_pca_dma_chunk_free,
       fore200e_pca_dma_sync_for_device,
       fore200e_pca_dma_chunk_alloc,
       fore200e_pca_dma_chunk_free,
-      fore200e_pca_detect,
+      NULL,
       fore200e_pca_configure,
       fore200e_pca_map,
       fore200e_pca_reset,
       fore200e_pca_configure,
       fore200e_pca_map,
       fore200e_pca_reset,