#include <linux/atmdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/poison.h>
+#include <linux/bitrev.h>
#include <asm/atomic.h>
#include <asm/io.h>
#endif
#define UCODE2(x) #x
-static u32 __initdata ucode_start =
+static u32 __devinitdata ucode_start =
#include UCODE(start)
;
-static region __initdata ucode_regions[] = {
+static region __devinitdata ucode_regions[] = {
#include UCODE(regions)
{ 0, 0 }
};
-static u32 __initdata ucode_data[] = {
+static u32 __devinitdata ucode_data[] = {
#include UCODE(data)
0xdeadbeef
};
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;
}
static inline void wr_mem (const amb_dev * dev, size_t addr, u32 data) {
- u32 be = cpu_to_be32 (data);
+ __be32 be = cpu_to_be32 (data);
PRINTD (DBG_FLOW|DBG_REGS, "wr: %08zx <- %08x b[%08x]", addr, data, be);
#ifdef AMB_MMIO
dev->membase[addr / sizeof(u32)] = be;
static inline u32 rd_mem (const amb_dev * dev, size_t addr) {
#ifdef AMB_MMIO
- u32 be = dev->membase[addr / sizeof(u32)];
+ __be32 be = dev->membase[addr / sizeof(u32)];
#else
- u32 be = inl (dev->iobase + addr);
+ __be32 be = inl (dev->iobase + addr);
#endif
u32 data = be32_to_cpu (be);
PRINTD (DBG_FLOW|DBG_REGS, "rd: %08zx -> %08x b[%08x]", addr, data, be);
// VC layer stats
atomic_inc(&atm_vcc->stats->rx);
- do_gettimeofday(&skb->stamp);
+ __net_timestamp(skb);
// end of our responsability
atm_vcc->push (atm_vcc, skb);
return;
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);
// 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) {
drain_rx_pool (dev, pool);
}
-static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority) {
+static inline void fill_rx_pool (amb_dev * dev, unsigned char pool,
+ gfp_t priority)
+{
rx_in rx;
amb_rxq * rxq;
/********** interrupt handling **********/
-static irqreturn_t interrupt_handler(int irq, void *dev_id,
- struct pt_regs *pt_regs) {
- amb_dev * dev = amb_devs;
- (void) pt_regs;
+static irqreturn_t interrupt_handler(int irq, void *dev_id) {
+ amb_dev * dev = dev_id;
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id);
- if (!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));
/********** make rate (not quite as much fun as Horizon) **********/
-static unsigned int make_rate (unsigned int rate, rounding r,
- u16 * bits, unsigned int * actual) {
+static int make_rate (unsigned int rate, rounding r,
+ u16 * bits, unsigned int * actual) {
unsigned char exp = -1; // hush gcc
unsigned int man = -1; // hush gcc
}
case round_up: {
// check all bits that we are discarding
- if (man & (-1>>9)) {
+ if (man & (~0U>>9)) {
man = (man>>(32-9)) + 1;
if (man == (1<<9)) {
// no need to check for round up outside of range
} 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;
}
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();
/********** 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;
}
/********** creation of communication queues **********/
-static int __init create_queues (amb_dev * dev, unsigned int cmds,
+static int __devinit create_queues (amb_dev * dev, unsigned int cmds,
unsigned int txs, unsigned int * rxs,
unsigned int * rx_buffer_sizes) {
unsigned char pool;
}
/********** 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 int __init do_loader_command (volatile loader_block * lb,
+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 __devinit 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;
// 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);
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));
/* loader: determine loader version */
-static int __init get_loader_version (loader_block * lb,
+static int __devinit get_loader_version (loader_block * lb,
const amb_dev * dev, u32 * version) {
int res;
/* loader: write memory data blocks */
-static int __init loader_write (loader_block * lb,
+static int __devinit loader_write (loader_block * lb,
const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
/* loader: verify memory data blocks */
-static int __init loader_verify (loader_block * lb,
+static int __devinit loader_verify (loader_block * lb,
const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
/* loader: start microcode */
-static int __init loader_start (loader_block * lb,
+static int __devinit loader_start (loader_block * lb,
const amb_dev * dev, u32 address) {
PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");
/********** 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;
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;
// 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)
/********** transfer and start the microcode **********/
-static int __init ucode_init (loader_block * lb, amb_dev * dev) {
+static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
unsigned int i = 0;
unsigned int total = 0;
const u32 * pointer = ucode_data;
}
i += 1;
}
- if (*pointer == 0xdeadbeef) {
+ if (*pointer == ATM_POISON) {
return loader_start (lb, dev, ucode_start);
} else {
// cast needed as there is no %? for pointer differnces
}
/********** give adapter parameters **********/
+
+static inline __be32 bus_addr(void * addr) {
+ return cpu_to_be32 (virt_to_bus (addr));
+}
-static int __init amb_talk (amb_dev * dev) {
+static int __devinit 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);
}
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;
}
// get microcode version
-static void __init amb_ucode_version (amb_dev * dev) {
+static void __devinit amb_ucode_version (amb_dev * dev) {
u32 major;
u32 minor;
command cmd;
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) {
+static void __devinit 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) {
- const u8 swap[] = {
- 0x0, 0x8, 0x4, 0xc,
- 0x2, 0xa, 0x6, 0xe,
- 0x1, 0x9, 0x5, 0xd,
- 0x3, 0xb, 0x7, 0xf
- };
- return ((swap[byte & 0xf]<<4) | swap[byte>>4]);
- }
-
cmd.request = cpu_to_be32 (SRB_GET_BIA);
while (command_do (dev, &cmd)) {
set_current_state(TASK_UNINTERRUPTIBLE);
PRINTDB (DBG_INIT, "ESI:");
for (i = 0; i < ESI_LEN; ++i) {
if (i < 4)
- esi[i] = bit_swap (lower4>>(8*i));
+ esi[i] = bitrev8(lower4>>(8*i));
else
- esi[i] = bit_swap (upper2>>(8*(i-4)));
+ esi[i] = bitrev8(upper2>>(8*(i-4)));
PRINTDM (DBG_INIT, " %02x", esi[i]);
}
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 __devinit 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");
} /* 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;
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 %llx, IRQ %u, MEM %p",
+ (unsigned long long)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, IRQF_SHARED, 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) {
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");
/********** 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
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_register_driver(&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;
+
+ pci_unregister_driver(&amb_driver);
}
module_init(amb_module_init);