vserver 1.9.5.x5
[linux-2.6.git] / drivers / atm / ambassador.c
index 9be4013..3870e37 100644 (file)
@@ -313,9 +313,6 @@ static u32 __initdata ucode_data[] = {
 static void do_housekeeping (unsigned long arg);
 /********** globals **********/
 
-static amb_dev * amb_devs = NULL;
-static struct timer_list housekeeping = TIMER_INITIALIZER(do_housekeeping, 0, 1);
-
 static unsigned short debug = 0;
 static unsigned int cmds = 8;
 static unsigned int txs = 32;
@@ -577,7 +574,6 @@ static int command_do (amb_dev * dev, command * cmd) {
   amb_cq * cq = &dev->cq;
   volatile amb_cq_ptrs * ptrs = &cq->ptrs;
   command * my_slot;
-  unsigned long timeout;
   
   PRINTD (DBG_FLOW|DBG_CMD, "command_do %p", dev);
   
@@ -602,20 +598,14 @@ static int command_do (amb_dev * dev, command * cmd) {
     // mail the command
     wr_mem (dev, offsetof(amb_mem, mb.adapter.cmd_address), virt_to_bus (ptrs->in));
     
-    // prepare to wait for cq->pending milliseconds
-    // effectively one centisecond on i386
-    timeout = (cq->pending*HZ+999)/1000;
-    
     if (cq->pending > cq->high)
       cq->high = cq->pending;
     spin_unlock (&cq->lock);
     
-    while (timeout) {
-      // go to sleep
-      // PRINTD (DBG_CMD, "wait: sleeping %lu for command", timeout);
-      set_current_state(TASK_UNINTERRUPTIBLE);
-      timeout = schedule_timeout (timeout);
-    }
+    // these comments were in a while-loop before, msleep removes the loop
+    // go to sleep
+    // PRINTD (DBG_CMD, "wait: sleeping %lu for command", timeout);
+    msleep(cq->pending);
     
     // wait for my slot to be reached (all waiters are here or above, until...)
     while (ptrs->out != my_slot) {
@@ -870,7 +860,7 @@ static inline void interrupts_off (amb_dev * dev) {
 
 static irqreturn_t interrupt_handler(int irq, void *dev_id,
                                        struct pt_regs *pt_regs) {
-  amb_dev * dev = amb_devs;
+  amb_dev * dev = (amb_dev *) dev_id;
   (void) pt_regs;
   
   PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id);
@@ -879,24 +869,6 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id,
     PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq);
     return IRQ_NONE;
   }
-  // Did one of our cards generate the interrupt?
-  while (dev) {
-    if (dev == dev_id)
-      break;
-    dev = dev->prev;
-  }
-  // impossible - unless we add the device to our list after both
-  // registering the IRQ handler for it and enabling interrupts, AND
-  // the card generates an IRQ at startup - should not happen again
-  if (!dev) {
-    PRINTD (DBG_IRQ, "irq for unknown device: %d", irq);
-    return IRQ_NONE;
-  }
-  // impossible - unless we have memory corruption of dev or kernel
-  if (irq != dev->irq) {
-    PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq);
-    return IRQ_NONE;
-  }
   
   {
     u32 interrupt = rd_plain (dev, offsetof(amb_mem, interrupt));
@@ -1554,22 +1526,13 @@ static const struct atmdev_ops amb_ops = {
 
 /********** housekeeping **********/
 static void do_housekeeping (unsigned long arg) {
-  amb_dev * dev = amb_devs;
-  // data is set to zero at module unload
-  (void) arg;
+  amb_dev * dev = (amb_dev *) arg;
   
-  if (housekeeping.data) {
-    while (dev) {
-      
-      // could collect device-specific (not driver/atm-linux) stats here
+  // could collect device-specific (not driver/atm-linux) stats here
       
-      // last resort refill once every ten seconds
-      fill_rx_pools (dev);
-      
-      dev = dev->prev;
-    }
-    mod_timer(&housekeeping, jiffies + 10*HZ);
-  }
+  // last resort refill once every ten seconds
+  fill_rx_pools (dev);
+  mod_timer(&dev->housekeeping, jiffies + 10*HZ);
   
   return;
 }
@@ -1722,7 +1685,7 @@ static unsigned int command_timeouts [] = {
 };
 
 
-unsigned int command_successes [] = {
+static unsigned int command_successes [] = {
        [host_memory_test]     = COMMAND_PASSED_TEST,
        [read_adapter_memory]  = COMMAND_READ_DATA_OK,
        [write_adapter_memory] = COMMAND_WRITE_DATA_OK,
@@ -1829,12 +1792,11 @@ static int __init do_loader_command (volatile loader_block * lb,
   // dump_loader_block (lb);
   wr_mem (dev, offsetof(amb_mem, doorbell), virt_to_bus (lb) & ~onegigmask);
   
-  timeout = command_timeouts[cmd] * HZ/100;
+  timeout = command_timeouts[cmd] * 10;
   
   while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS))
     if (timeout) {
-      set_current_state(TASK_UNINTERRUPTIBLE);
-      timeout = schedule_timeout (timeout);
+      timeout = msleep_interruptible(timeout);
     } else {
       PRINTD (DBG_LOAD|DBG_ERR, "command %d timed out", cmd);
       dump_registers (dev);
@@ -1844,10 +1806,10 @@ static int __init do_loader_command (volatile loader_block * lb,
   
   if (cmd == adapter_start) {
     // wait for start command to acknowledge...
-    timeout = HZ/10;
+    timeout = 100;
     while (rd_plain (dev, offsetof(amb_mem, doorbell)))
       if (timeout) {
-       timeout = schedule_timeout (timeout);
+       timeout = msleep_interruptible(timeout);
       } else {
        PRINTD (DBG_LOAD|DBG_ERR, "start command did not clear doorbell, res=%08x",
                be32_to_cpu (lb->result));
@@ -1962,17 +1924,12 @@ static int amb_reset (amb_dev * dev, int diags) {
   if (diags) { 
     unsigned long timeout;
     // 4.2 second wait
-    timeout = HZ*42/10;
-    while (timeout) {
-      set_current_state(TASK_UNINTERRUPTIBLE);
-      timeout = schedule_timeout (timeout);
-    }
+    msleep(4200);
     // half second time-out
-    timeout = HZ/2;
+    timeout = 500;
     while (!rd_plain (dev, offsetof(amb_mem, mb.loader.ready)))
       if (timeout) {
-        set_current_state(TASK_UNINTERRUPTIBLE);
-       timeout = schedule_timeout (timeout);
+       timeout = msleep_interruptible(timeout);
       } else {
        PRINTD (DBG_LOAD|DBG_ERR, "reset timed out");
        return -ETIMEDOUT;
@@ -2086,14 +2043,12 @@ static int __init amb_talk (amb_dev * dev) {
   wr_mem (dev, offsetof(amb_mem, doorbell), virt_to_bus (&a));
   
   // 2.2 second wait (must not touch doorbell during 2 second DMA test)
-  timeout = HZ*22/10;
-  while (timeout)
-    timeout = schedule_timeout (timeout);
+  msleep(2200);
   // give the adapter another half second?
-  timeout = HZ/2;
+  timeout = 500;
   while (rd_plain (dev, offsetof(amb_mem, doorbell)))
     if (timeout) {
-      timeout = schedule_timeout (timeout);
+      timeout = msleep_interruptible(timeout);
     } else {
       PRINTD (DBG_INIT|DBG_ERR, "adapter init timed out");
       return -ETIMEDOUT;
@@ -2118,7 +2073,7 @@ static void __init amb_ucode_version (amb_dev * dev) {
 }
   
 // swap bits within byte to get Ethernet ordering
-u8 bit_swap (u8 byte)
+static u8 bit_swap (u8 byte)
 {
     const u8 swap[] = {
       0x0, 0x8, 0x4, 0xc,
@@ -2225,6 +2180,7 @@ static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev)
       
       // set up known dev items straight away
       dev->pci_dev = pci_dev; 
+      pci_set_drvdata(pci_dev, dev);
       
       dev->iobase = pci_resource_start (pci_dev, 1);
       dev->irq = pci_dev->irq; 
@@ -2257,17 +2213,12 @@ static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev)
        spin_lock_init (&dev->rxq[pool].lock);
 }
 
-static int setup_pci_dev(struct pci_dev *pci_dev)
+static void setup_pci_dev(struct pci_dev *pci_dev)
 {
        unsigned char lat;
-       int ret;
       
        // enable bus master accesses
        pci_set_master(pci_dev);
-      
-       ret = pci_enable_device(pci_dev);
-       if (ret < 0)
-               goto out;
 
        // frobnicate latency (upwards, usually)
        pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
@@ -2280,27 +2231,38 @@ static int setup_pci_dev(struct pci_dev *pci_dev)
                        lat, pci_lat);
                pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat);
        }
-out:
-       return ret;
 }
 
-static int __init do_pci_device(struct pci_dev *pci_dev)
+static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
 {
        amb_dev * dev;
        int err;
+       unsigned int irq;
+      
+       err = pci_enable_device(pci_dev);
+       if (err < 0) {
+               PRINTK (KERN_ERR, "skipped broken (PLX rev 2) card");
+               goto out;
+       }
 
        // read resources from PCI configuration space
-       u8 irq = pci_dev->irq;
+       irq = pci_dev->irq;
+
+       if (pci_dev->device == PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD) {
+               PRINTK (KERN_ERR, "skipped broken (PLX rev 2) card");
+               err = -EINVAL;
+               goto out_disable;
+       }
 
        PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"
-               " IO %x, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1),
+               " IO %lx, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1),
                irq, bus_to_virt(pci_resource_start(pci_dev, 0)));
 
        // check IO region
        err = pci_request_region(pci_dev, 1, DEV_LABEL);
        if (err < 0) {
                PRINTK (KERN_ERR, "IO range already in use!");
-               goto out;
+               goto out_disable;
        }
 
        dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
@@ -2318,15 +2280,13 @@ static int __init do_pci_device(struct pci_dev *pci_dev)
                goto out_free;
        }
 
-       err = setup_pci_dev(pci_dev);
-       if (err < 0)
-               goto out_reset;
+       setup_pci_dev(pci_dev);
 
        // grab (but share) IRQ and install handler
        err = request_irq(irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev);
        if (err < 0) {
                PRINTK (KERN_ERR, "request IRQ failed!");
-               goto out_disable;
+               goto out_reset;
        }
 
        dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
@@ -2347,9 +2307,10 @@ static int __init do_pci_device(struct pci_dev *pci_dev)
        dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
        dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
 
-       // update linked list
-       dev->prev = amb_devs;
-       amb_devs = dev;
+       init_timer(&dev->housekeeping);
+       dev->housekeeping.function = do_housekeeping;
+       dev->housekeeping.data = (unsigned long) dev;
+       mod_timer(&dev->housekeeping, jiffies);
 
        // enable host interrupts
        interrupts_on (dev);
@@ -2359,40 +2320,36 @@ out:
 
 out_free_irq:
        free_irq(irq, dev);
-out_disable:
-       pci_disable_device(pci_dev);
 out_reset:
        amb_reset(dev, 0);
 out_free:
        kfree(dev);
 out_release:
        pci_release_region(pci_dev, 1);
+out_disable:
+       pci_disable_device(pci_dev);
        goto out;
 }
 
-static int __init amb_probe (void) {
-  struct pci_dev * pci_dev;
-  int devs;
-  
-  PRINTD (DBG_FLOW, "amb_probe");
-  
-  devs = 0;
-  pci_dev = NULL;
-  while ((pci_dev = pci_find_device
-          (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR, pci_dev)
-          )) {
-       if (do_pci_device(pci_dev) == 0)
-               devs++;
-  }
 
-  
-  pci_dev = NULL;
-  while ((pci_dev = pci_find_device
-          (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD, pci_dev)
-          ))
-    PRINTK (KERN_ERR, "skipped broken (PLX rev 2) card");
-  
-  return devs;
+static void __devexit amb_remove_one(struct pci_dev *pci_dev)
+{
+       struct amb_dev *dev;
+
+       dev = pci_get_drvdata(pci_dev);
+
+       PRINTD(DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
+       del_timer_sync(&dev->housekeeping);
+       // the drain should not be necessary
+       drain_rx_pools(dev);
+       interrupts_off(dev);
+       amb_reset(dev, 0);
+       free_irq(dev->irq, dev);
+       pci_disable_device(pci_dev);
+       destroy_queues(dev);
+       atm_dev_deregister(dev->atm_dev);
+       kfree(dev);
+       pci_release_region(pci_dev, 1);
 }
 
 static void __init amb_check_args (void) {
@@ -2440,13 +2397,13 @@ static void __init amb_check_args (void) {
 MODULE_AUTHOR(maintainer_string);
 MODULE_DESCRIPTION(description_string);
 MODULE_LICENSE("GPL");
-MODULE_PARM(debug,   "h");
-MODULE_PARM(cmds,    "i");
-MODULE_PARM(txs,     "i");
-MODULE_PARM(rxs,     __MODULE_STRING(NUM_RX_POOLS) "i");
-MODULE_PARM(rxs_bs,  __MODULE_STRING(NUM_RX_POOLS) "i");
-MODULE_PARM(rx_lats, "i");
-MODULE_PARM(pci_lat, "b");
+module_param(debug,   ushort, 0644);
+module_param(cmds,    uint, 0);
+module_param(txs,     uint, 0);
+module_param_array(rxs,     uint, NULL, 0);
+module_param_array(rxs_bs,  uint, NULL, 0);
+module_param(rx_lats, uint, 0);
+module_param(pci_lat, byte, 0);
 MODULE_PARM_DESC(debug,   "debug bitmap, see .h file");
 MODULE_PARM_DESC(cmds,    "number of command queue entries");
 MODULE_PARM_DESC(txs,     "number of TX queue entries");
@@ -2457,9 +2414,25 @@ MODULE_PARM_DESC(pci_lat, "PCI latency in bus cycles");
 
 /********** module entry **********/
 
-static int __init amb_module_init (void) {
-  int devs;
-  
+static struct pci_device_id amb_pci_tbl[] = {
+       { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR, PCI_ANY_ID, PCI_ANY_ID,
+         0, 0, 0 },
+       { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD, PCI_ANY_ID, PCI_ANY_ID,
+         0, 0, 0 },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, amb_pci_tbl);
+
+static struct pci_driver amb_driver = {
+       .name =         "amb",
+       .probe =        amb_probe,
+       .remove =       __devexit_p(amb_remove_one),
+       .id_table =     amb_pci_tbl,
+};
+
+static int __init amb_module_init (void)
+{
   PRINTD (DBG_FLOW|DBG_INIT, "init_module");
   
   // sanity check - cast needed as printk does not support %Zu
@@ -2474,49 +2447,16 @@ static int __init amb_module_init (void) {
   amb_check_args();
   
   // get the juice
-  devs = amb_probe();
-  
-  if (devs) {
-    mod_timer (&housekeeping, jiffies);
-  } else {
-    PRINTK (KERN_INFO, "no (usable) adapters found");
-  }
-  
-  return devs ? 0 : -ENODEV;
+  return pci_module_init(&amb_driver);
 }
 
 /********** module exit **********/
 
-static void __exit amb_module_exit (void) {
-  amb_dev * dev;
-  
+static void __exit amb_module_exit (void)
+{
   PRINTD (DBG_FLOW|DBG_INIT, "cleanup_module");
   
-  // paranoia
-  housekeeping.data = 0;
-  del_timer_sync(&housekeeping);
-  
-  while (amb_devs) {
-    struct pci_dev *pdev;
-
-    dev = amb_devs;
-    pdev = dev->pci_dev;
-    amb_devs = dev->prev;
-    
-    PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
-    // the drain should not be necessary
-    drain_rx_pools (dev);
-    interrupts_off (dev);
-    amb_reset (dev, 0);
-    free_irq (dev->irq, dev);
-    pci_disable_device (pdev);
-    destroy_queues (dev);
-    atm_dev_deregister (dev->atm_dev);
-    kfree (dev);
-    pci_release_region (pdev, 1);
-  }
-  
-  return;
+  return pci_unregister_driver(&amb_driver);
 }
 
 module_init(amb_module_init);