X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fatm%2Fambassador.c;h=3870e3787b7b4fee3a0d323ae6f99fc53f79b001;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=b293bb7f9e4fe205a5da85edd9932ef8885dcc4f;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index b293bb7f9..3870e3787 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -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)); @@ -1126,7 +1098,7 @@ static int amb_open (struct atm_vcc * atm_vcc) } else { r = round_up; } - error = make_rate (pcr, r, &tx_rate_bits, 0); + error = make_rate (pcr, r, &tx_rate_bits, NULL); tx_vc_bits = TX_UBR_CAPPED; tx_frame_bits = TX_FRAME_CAPPED; } @@ -1333,7 +1305,7 @@ static void amb_close (struct atm_vcc * atm_vcc) { PRINTK (KERN_ERR, "%s vcc=%p rxer[vci]=%p", "arghhh! we're going to die!", vcc, dev->rxer[vci]); - dev->rxer[vci] = 0; + dev->rxer[vci] = NULL; while (command_do (dev, &cmd)) schedule(); @@ -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; } @@ -1706,105 +1669,108 @@ static void destroy_queues (amb_dev * dev) { } /********** basic loader commands and error handling **********/ +// centisecond timeouts - guessing away here +static unsigned int command_timeouts [] = { + [host_memory_test] = 15, + [read_adapter_memory] = 2, + [write_adapter_memory] = 2, + [adapter_start] = 50, + [get_version_number] = 10, + [interrupt_host] = 1, + [flash_erase_sector] = 1, + [adap_download_block] = 1, + [adap_erase_flash] = 1, + [adap_run_in_iram] = 1, + [adap_end_download] = 1 +}; + + +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, + [adapter_start] = COMMAND_COMPLETE, + [get_version_number] = COMMAND_COMPLETE, + [interrupt_host] = COMMAND_COMPLETE, + [flash_erase_sector] = COMMAND_COMPLETE, + [adap_download_block] = COMMAND_COMPLETE, + [adap_erase_flash] = COMMAND_COMPLETE, + [adap_run_in_iram] = COMMAND_COMPLETE, + [adap_end_download] = COMMAND_COMPLETE +}; + +static int decode_loader_result (loader_command cmd, u32 result) +{ + int res; + const char *msg; + + if (result == command_successes[cmd]) + return 0; + + switch (result) { + case BAD_COMMAND: + res = -EINVAL; + msg = "bad command"; + break; + case COMMAND_IN_PROGRESS: + res = -ETIMEDOUT; + msg = "command in progress"; + break; + case COMMAND_PASSED_TEST: + res = 0; + msg = "command passed test"; + break; + case COMMAND_FAILED_TEST: + res = -EIO; + msg = "command failed test"; + break; + case COMMAND_READ_DATA_OK: + res = 0; + msg = "command read data ok"; + break; + case COMMAND_READ_BAD_ADDRESS: + res = -EINVAL; + msg = "command read bad address"; + break; + case COMMAND_WRITE_DATA_OK: + res = 0; + msg = "command write data ok"; + break; + case COMMAND_WRITE_BAD_ADDRESS: + res = -EINVAL; + msg = "command write bad address"; + break; + case COMMAND_WRITE_FLASH_FAILURE: + res = -EIO; + msg = "command write flash failure"; + break; + case COMMAND_COMPLETE: + res = 0; + msg = "command complete"; + break; + case COMMAND_FLASH_ERASE_FAILURE: + res = -EIO; + msg = "command flash erase failure"; + break; + case COMMAND_WRITE_BAD_DATA: + res = -EINVAL; + msg = "command write bad data"; + break; + default: + res = -EINVAL; + msg = "unknown error"; + PRINTD (DBG_LOAD|DBG_ERR, + "decode_loader_result got %d=%x !", + result, result); + break; + } + + PRINTK (KERN_ERR, "%s", msg); + return res; +} static int __init do_loader_command (volatile loader_block * lb, const amb_dev * dev, loader_command cmd) { - // centisecond timeouts - guessing away here - unsigned int command_timeouts [] = { - [host_memory_test] = 15, - [read_adapter_memory] = 2, - [write_adapter_memory] = 2, - [adapter_start] = 50, - [get_version_number] = 10, - [interrupt_host] = 1, - [flash_erase_sector] = 1, - [adap_download_block] = 1, - [adap_erase_flash] = 1, - [adap_run_in_iram] = 1, - [adap_end_download] = 1 - }; - - unsigned int command_successes [] = { - [host_memory_test] = COMMAND_PASSED_TEST, - [read_adapter_memory] = COMMAND_READ_DATA_OK, - [write_adapter_memory] = COMMAND_WRITE_DATA_OK, - [adapter_start] = COMMAND_COMPLETE, - [get_version_number] = COMMAND_COMPLETE, - [interrupt_host] = COMMAND_COMPLETE, - [flash_erase_sector] = COMMAND_COMPLETE, - [adap_download_block] = COMMAND_COMPLETE, - [adap_erase_flash] = COMMAND_COMPLETE, - [adap_run_in_iram] = COMMAND_COMPLETE, - [adap_end_download] = COMMAND_COMPLETE - }; - - int decode_loader_result (loader_command cmd, u32 result) { - int res; - const char * msg; - - if (result == command_successes[cmd]) - return 0; - - switch (result) { - case BAD_COMMAND: - res = -EINVAL; - msg = "bad command"; - break; - case COMMAND_IN_PROGRESS: - res = -ETIMEDOUT; - msg = "command in progress"; - break; - case COMMAND_PASSED_TEST: - res = 0; - msg = "command passed test"; - break; - case COMMAND_FAILED_TEST: - res = -EIO; - msg = "command failed test"; - break; - case COMMAND_READ_DATA_OK: - res = 0; - msg = "command read data ok"; - break; - case COMMAND_READ_BAD_ADDRESS: - res = -EINVAL; - msg = "command read bad address"; - break; - case COMMAND_WRITE_DATA_OK: - res = 0; - msg = "command write data ok"; - break; - case COMMAND_WRITE_BAD_ADDRESS: - res = -EINVAL; - msg = "command write bad address"; - break; - case COMMAND_WRITE_FLASH_FAILURE: - res = -EIO; - msg = "command write flash failure"; - break; - case COMMAND_COMPLETE: - res = 0; - msg = "command complete"; - break; - case COMMAND_FLASH_ERASE_FAILURE: - res = -EIO; - msg = "command flash erase failure"; - break; - case COMMAND_WRITE_BAD_DATA: - res = -EINVAL; - msg = "command write bad data"; - break; - default: - res = -EINVAL; - msg = "unknown error"; - PRINTD (DBG_LOAD|DBG_ERR, "decode_loader_result got %d=%x !", - result, result); - break; - } - - PRINTK (KERN_ERR, "%s", msg); - return res; - } unsigned long timeout; @@ -1826,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); @@ -1841,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)); @@ -1930,6 +1895,11 @@ static int __init loader_start (loader_block * lb, /********** reset card **********/ +static inline void sf (const char * msg) +{ + PRINTK (KERN_ERR, "self-test failed: %s", msg); +} + static int amb_reset (amb_dev * dev, int diags) { u32 word; @@ -1954,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; @@ -1974,9 +1939,6 @@ static int amb_reset (amb_dev * dev, int diags) { // XXX double check byte-order word = rd_mem (dev, offsetof(amb_mem, mb.loader.result)); if (word & SELF_TEST_FAILURE) { - void sf (const char * msg) { - PRINTK (KERN_ERR, "self-test failed: %s", msg); - } if (word & GPINT_TST_FAILURE) sf ("interrupt"); if (word & SUNI_DATA_PATTERN_FAILURE) @@ -2044,31 +2006,31 @@ static int __init ucode_init (loader_block * lb, amb_dev * dev) { } /********** give adapter parameters **********/ + +static inline u32 bus_addr(void * addr) { + return cpu_to_be32 (virt_to_bus (addr)); +} static int __init amb_talk (amb_dev * dev) { adap_talk_block a; unsigned char pool; unsigned long timeout; - u32 x (void * addr) { - return cpu_to_be32 (virt_to_bus (addr)); - } - PRINTD (DBG_FLOW, "amb_talk %p", dev); - a.command_start = x (dev->cq.ptrs.start); - a.command_end = x (dev->cq.ptrs.limit); - a.tx_start = x (dev->txq.in.start); - a.tx_end = x (dev->txq.in.limit); - a.txcom_start = x (dev->txq.out.start); - a.txcom_end = x (dev->txq.out.limit); + a.command_start = bus_addr (dev->cq.ptrs.start); + a.command_end = bus_addr (dev->cq.ptrs.limit); + a.tx_start = bus_addr (dev->txq.in.start); + a.tx_end = bus_addr (dev->txq.in.limit); + a.txcom_start = bus_addr (dev->txq.out.start); + a.txcom_end = bus_addr (dev->txq.out.limit); for (pool = 0; pool < NUM_RX_POOLS; ++pool) { // the other "a" items are set up by the adapter - a.rec_struct[pool].buffer_start = x (dev->rxq[pool].in.start); - a.rec_struct[pool].buffer_end = x (dev->rxq[pool].in.limit); - a.rec_struct[pool].rx_start = x (dev->rxq[pool].out.start); - a.rec_struct[pool].rx_end = x (dev->rxq[pool].out.limit); + a.rec_struct[pool].buffer_start = bus_addr (dev->rxq[pool].in.start); + a.rec_struct[pool].buffer_end = bus_addr (dev->rxq[pool].in.limit); + a.rec_struct[pool].rx_start = bus_addr (dev->rxq[pool].out.start); + a.rec_struct[pool].rx_end = bus_addr (dev->rxq[pool].out.limit); a.rec_struct[pool].buffer_size = cpu_to_be32 (dev->rxq[pool].buffer_size); } @@ -2081,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; @@ -2111,15 +2071,10 @@ static void __init amb_ucode_version (amb_dev * dev) { minor = be32_to_cpu (cmd.args.version.minor); PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor); } - -// get end station address -static void __init amb_esi (amb_dev * dev, u8 * esi) { - u32 lower4; - u16 upper2; - command cmd; - // swap bits within byte to get Ethernet ordering - u8 bit_swap (u8 byte) { +// swap bits within byte to get Ethernet ordering +static u8 bit_swap (u8 byte) +{ const u8 swap[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, @@ -2127,7 +2082,13 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) { 0x3, 0xb, 0x7, 0xf }; return ((swap[byte & 0xf]<<4) | swap[byte>>4]); - } +} + +// get end station address +static void __init amb_esi (amb_dev * dev, u8 * esi) { + u32 lower4; + u16 upper2; + command cmd; cmd.request = cpu_to_be32 (SRB_GET_BIA); while (command_do (dev, &cmd)) { @@ -2155,29 +2116,31 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) { return; } + +static void fixup_plx_window (amb_dev *dev, loader_block *lb) +{ + // fix up the PLX-mapped window base address to match the block + unsigned long blb; + u32 mapreg; + blb = virt_to_bus(lb); + // the kernel stack had better not ever cross a 1Gb boundary! + mapreg = rd_plain (dev, offsetof(amb_mem, stuff[10])); + mapreg &= ~onegigmask; + mapreg |= blb & onegigmask; + wr_plain (dev, offsetof(amb_mem, stuff[10]), mapreg); + return; +} -static int __init amb_init (amb_dev * dev) { +static int __init amb_init (amb_dev * dev) +{ loader_block lb; - void fixup_plx_window (void) { - // fix up the PLX-mapped window base address to match the block - unsigned long blb; - u32 mapreg; - blb = virt_to_bus (&lb); - // the kernel stack had better not ever cross a 1Gb boundary! - mapreg = rd_plain (dev, offsetof(amb_mem, stuff[10])); - mapreg &= ~onegigmask; - mapreg |= blb & onegigmask; - wr_plain (dev, offsetof(amb_mem, stuff[10]), mapreg); - return; - } - u32 version; if (amb_reset (dev, 1)) { PRINTK (KERN_ERR, "card reset failed!"); } else { - fixup_plx_window (); + fixup_plx_window (dev, &lb); if (get_loader_version (&lb, dev, &version)) { PRINTK (KERN_INFO, "failed to get loader version"); @@ -2207,31 +2170,21 @@ static int __init amb_init (amb_dev * dev) { } /* amb_reset */ - return -1; + return -EINVAL; } -static int __init amb_probe (void) { - struct pci_dev * pci_dev; - int devs; - - void __init do_pci_device (void) { - amb_dev * dev; - - // read resources from PCI configuration space - u8 irq = pci_dev->irq; - u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 0)); - u32 iobase = pci_resource_start (pci_dev, 1); - - void setup_dev (void) { +static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev) +{ unsigned char pool; memset (dev, 0, sizeof(amb_dev)); // set up known dev items straight away dev->pci_dev = pci_dev; + pci_set_drvdata(pci_dev, dev); - dev->iobase = iobase; - dev->irq = irq; - dev->membase = membase; + dev->iobase = pci_resource_start (pci_dev, 1); + dev->irq = pci_dev->irq; + dev->membase = bus_to_virt(pci_resource_start(pci_dev, 0)); // flags (currently only dead) dev->flags = 0; @@ -2258,118 +2211,145 @@ static int __init amb_probe (void) { spin_lock_init (&dev->txq.lock); for (pool = 0; pool < NUM_RX_POOLS; ++pool) spin_lock_init (&dev->rxq[pool].lock); - } - - void setup_pci_dev (void) { - unsigned char lat; - - /* XXX check return value */ - pci_enable_device (pci_dev); +} - // enable bus master accesses - pci_set_master (pci_dev); - - // frobnicate latency (upwards, usually) - pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); - if (pci_lat) { - PRINTD (DBG_INIT, "%s PCI latency timer from %hu to %hu", - "changing", lat, pci_lat); - pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, pci_lat); - } else if (lat < MIN_PCI_LATENCY) { - PRINTK (KERN_INFO, "%s PCI latency timer from %hu to %hu", - "increasing", lat, MIN_PCI_LATENCY); - pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); - } - } - - PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at" - " IO %x, IRQ %u, MEM %p", iobase, irq, membase); - - // check IO region - if (!request_region (iobase, AMB_EXTENT, DEV_LABEL)) { - PRINTK (KERN_ERR, "IO range already in use!"); - return; - } - - dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); - if (!dev) { - // perhaps we should be nice: deregister all adapters and abort? - PRINTK (KERN_ERR, "out of memory!"); - release_region (iobase, AMB_EXTENT); - return; - } - - setup_dev(); - - if (amb_init (dev)) { - PRINTK (KERN_ERR, "adapter initialisation failure"); - } else { +static void setup_pci_dev(struct pci_dev *pci_dev) +{ + unsigned char lat; - setup_pci_dev(); + // enable bus master accesses + pci_set_master(pci_dev); + + // frobnicate latency (upwards, usually) + pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); + + if (!pci_lat) + pci_lat = (lat < MIN_PCI_LATENCY) ? MIN_PCI_LATENCY : lat; + + if (lat != pci_lat) { + PRINTK (KERN_INFO, "Changing PCI latency timer from %hu to %hu", + lat, pci_lat); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat); + } +} + +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; - // grab (but share) IRQ and install handler - if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) { - PRINTK (KERN_ERR, "request IRQ failed!"); - // free_irq is at "endif" - } else { - + 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 + 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 %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_disable; + } + + dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); + if (!dev) { + PRINTK (KERN_ERR, "out of memory!"); + err = -ENOMEM; + goto out_release; + } + + setup_dev(dev, pci_dev); + + err = amb_init(dev); + if (err < 0) { + PRINTK (KERN_ERR, "adapter initialisation failure"); + goto out_free; + } + + 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_reset; + } + dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL); if (!dev->atm_dev) { - PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); - } else { - - PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", - dev->atm_dev->number, dev, dev->atm_dev); - dev->atm_dev->dev_data = (void *) dev; - - // register our address - amb_esi (dev, dev->atm_dev->esi); - - // 0 bits for vpi, 10 bits for vci - dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS; - dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS; - - // update count and linked list - ++devs; - dev->prev = amb_devs; - amb_devs = dev; - - // enable host interrupts - interrupts_on (dev); - - // success - return; - - // not currently reached - atm_dev_deregister (dev->atm_dev); - } /* atm_dev_register */ - - free_irq (irq, dev); - } /* request_irq */ - - amb_reset (dev, 0); - } /* amb_init */ - - kfree (dev); - release_region (iobase, AMB_EXTENT); - } /* kmalloc, end-of-fn */ - - 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) - )) - do_pci_device(); - - 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; + PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); + err = -EINVAL; + goto out_free_irq; + } + + PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", + dev->atm_dev->number, dev, dev->atm_dev); + dev->atm_dev->dev_data = (void *) dev; + + // register our address + amb_esi (dev, dev->atm_dev->esi); + + // 0 bits for vpi, 10 bits for vci + dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS; + dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS; + + 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); + +out: + return err; + +out_free_irq: + free_irq(irq, 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 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) { @@ -2417,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"); @@ -2434,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 @@ -2451,45 +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) { - dev = amb_devs; - 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); - destroy_queues (dev); - atm_dev_deregister (dev->atm_dev); - free_irq (dev->irq, dev); - release_region (dev->iobase, AMB_EXTENT); - kfree (dev); - } - - return; + return pci_unregister_driver(&amb_driver); } module_init(amb_module_init);