X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fkernel%2Fecard.c;h=00aa225e8d95ede70807e0f901bdb89d6da757a8;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=3f6b4b529aa9fecb18204a58bd9514c32eb38148;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 3f6b4b529..00aa225e8 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -85,27 +86,21 @@ static struct expcard_blacklist __initdata blacklist[] = { }; asmlinkage extern int -ecard_loader_reset(volatile unsigned char *pa, loader_t loader); +ecard_loader_reset(unsigned long base, loader_t loader); asmlinkage extern int -ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); +ecard_loader_read(int off, unsigned long base, loader_t loader); -static const struct ecard_id * -ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec); - -static inline unsigned short -ecard_getu16(unsigned char *v) +static inline unsigned short ecard_getu16(unsigned char *v) { return v[0] | v[1] << 8; } -static inline signed long -ecard_gets24(unsigned char *v) +static inline signed long ecard_gets24(unsigned char *v) { return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); } -static inline ecard_t * -slot_to_ecard(unsigned int slot) +static inline ecard_t *slot_to_ecard(unsigned int slot) { return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; } @@ -122,26 +117,31 @@ slot_to_ecard(unsigned int slot) * From a security standpoint, we trust the card vendors. This * may be a misplaced trust. */ -#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) -#define POD_INT_ADDR(x) ((volatile unsigned char *)\ - ((BUS_ADDR((x)) - IO_BASE) + IO_START)) - static void ecard_task_reset(struct ecard_request *req) { struct expansion_card *ec = req->ec; - if (ec->loader) - ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader); + struct resource *res; + + res = ec->slot_no == 8 + ? &ec->resource[ECARD_RES_MEMC] + : ec->type == ECARD_EASI + ? &ec->resource[ECARD_RES_EASI] + : &ec->resource[ECARD_RES_IOCSYNC]; + + ecard_loader_reset(res->start, ec->loader); } static void ecard_task_readbytes(struct ecard_request *req) { - unsigned char *buf = (unsigned char *)req->buffer; - volatile unsigned char *base_addr = - (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr); + struct expansion_card *ec = req->ec; + unsigned char *buf = req->buffer; unsigned int len = req->length; unsigned int off = req->address; - if (req->ec->slot_no == 8) { + if (ec->slot_no == 8) { + void __iomem *base = (void __iomem *) + ec->resource[ECARD_RES_MEMC].start; + /* * The card maintains an index which increments the address * into a 4096-byte page on each access. We need to keep @@ -161,7 +161,7 @@ static void ecard_task_readbytes(struct ecard_request *req) * greater than the offset, reset the hardware index counter. */ if (off == 0 || index > off) { - *base_addr = 0; + writeb(0, base); index = 0; } @@ -170,21 +170,24 @@ static void ecard_task_readbytes(struct ecard_request *req) * required offset. The read bytes are discarded. */ while (index < off) { - unsigned char byte; - byte = base_addr[page]; + readb(base + page); index += 1; } while (len--) { - *buf++ = base_addr[page]; + *buf++ = readb(base + page); index += 1; } } else { + unsigned long base = (ec->type == ECARD_EASI + ? &ec->resource[ECARD_RES_EASI] + : &ec->resource[ECARD_RES_IOCSYNC])->start; + void __iomem *pbase = (void __iomem *)base; - if (!req->use_loader || !req->ec->loader) { + if (!req->use_loader || !ec->loader) { off *= 4; while (len--) { - *buf++ = base_addr[off]; + *buf++ = readb(pbase + off); off += 4; } } else { @@ -194,8 +197,8 @@ static void ecard_task_readbytes(struct ecard_request *req) * expansion card loader programs. */ *(unsigned long *)0x108 = 0; - *buf++ = ecard_loader_read(off++, base_addr, - req->ec->loader); + *buf++ = ecard_loader_read(off++, base, + ec->loader); } } } @@ -204,7 +207,7 @@ static void ecard_task_readbytes(struct ecard_request *req) static DECLARE_WAIT_QUEUE_HEAD(ecard_wait); static struct ecard_request *ecard_req; -static DECLARE_MUTEX(ecard_sem); +static DEFINE_MUTEX(ecard_mutex); /* * Set up the expansion card daemon's page tables. @@ -226,7 +229,7 @@ static void ecard_init_pgtables(struct mm_struct *mm) */ pgd_t *src_pgd, *dst_pgd; - src_pgd = pgd_offset(mm, IO_BASE); + src_pgd = pgd_offset(mm, (unsigned long)IO_BASE); dst_pgd = pgd_offset(mm, IO_START); memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE)); @@ -297,7 +300,7 @@ static void ecard_call(struct ecard_request *req) req->complete = &completion; - down(&ecard_sem); + mutex_lock(&ecard_mutex); ecard_req = req; wake_up(&ecard_wait); @@ -305,7 +308,7 @@ static void ecard_call(struct ecard_request *req) * Now wait for kecardd to run. */ wait_for_completion(&completion); - up(&ecard_sem); + mutex_unlock(&ecard_mutex); } /* ======================= Mid-level card control ===================== */ @@ -406,7 +409,7 @@ static void ecard_def_irq_disable(ecard_t *ec, int irqnr) static int ecard_def_irq_pending(ecard_t *ec) { - return !ec->irqmask || ec->irqaddr[0] & ec->irqmask; + return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask; } static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) @@ -421,7 +424,7 @@ static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) static int ecard_def_fiq_pending(ecard_t *ec) { - return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask; + return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask; } static expansioncard_ops_t ecard_default_ops = { @@ -522,7 +525,7 @@ static void ecard_dump_irq_state(void) ec->ops->irqpending(ec) ? "" : "not "); else printk("irqaddr %p, mask = %02X, status = %02X\n", - ec->irqaddr, ec->irqmask, *ec->irqaddr); + ec->irqaddr, ec->irqmask, readb(ec->irqaddr)); } } @@ -583,7 +586,7 @@ ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) if (pending) { struct irqdesc *d = irq_desc + ec->irq; - d->handle(ec->irq, d, regs); + desc_handle_irq(ec->irq, d, regs); called ++; } } @@ -630,7 +633,7 @@ ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg * Serial cards should go in 0/1, ethernet/scsi in 2/3 * otherwise you will lose serial data at high speeds! */ - d->handle(ec->irq, d, regs); + desc_handle_irq(ec->irq, d, regs); } else { printk(KERN_WARNING "card%d: interrupt from unclaimed " "card???\n", slot); @@ -675,7 +678,7 @@ static int __init ecard_probeirqhw(void) #define IO_EC_MEMC8_BASE 0 #endif -unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) +unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) { unsigned long address = 0; int slot = ec->slot_no; @@ -779,74 +782,102 @@ static void ecard_proc_init(void) get_ecard_dev_info); } -#define ec_set_resource(ec,nr,st,sz,flg) \ +#define ec_set_resource(ec,nr,st,sz) \ do { \ (ec)->resource[nr].name = ec->dev.bus_id; \ (ec)->resource[nr].start = st; \ (ec)->resource[nr].end = (st) + (sz) - 1; \ - (ec)->resource[nr].flags = flg; \ + (ec)->resource[nr].flags = IORESOURCE_MEM; \ } while (0) -static void __init ecard_init_resources(struct expansion_card *ec) +static void __init ecard_free_card(struct expansion_card *ec) +{ + int i; + + for (i = 0; i < ECARD_NUM_RESOURCES; i++) + if (ec->resource[i].flags) + release_resource(&ec->resource[i]); + + kfree(ec); +} + +static struct expansion_card *__init ecard_alloc_card(int type, int slot) { - unsigned long base = PODSLOT_IOC4_BASE; - unsigned int slot = ec->slot_no; + struct expansion_card *ec; + unsigned long base; int i; + ec = kzalloc(sizeof(ecard_t), GFP_KERNEL); + if (!ec) { + ec = ERR_PTR(-ENOMEM); + goto nomem; + } + + ec->slot_no = slot; + ec->type = type; + ec->irq = NO_IRQ; + ec->fiq = NO_IRQ; + ec->dma = NO_DMA; + ec->ops = &ecard_default_ops; + + snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); + ec->dev.parent = NULL; + ec->dev.bus = &ecard_bus_type; + ec->dev.dma_mask = &ec->dma_mask; + ec->dma_mask = (u64)0xffffffff; + if (slot < 4) { ec_set_resource(ec, ECARD_RES_MEMC, PODSLOT_MEMC_BASE + (slot << 14), - PODSLOT_MEMC_SIZE, IORESOURCE_MEM); - base = PODSLOT_IOC0_BASE; - } + PODSLOT_MEMC_SIZE); + base = PODSLOT_IOC0_BASE + (slot << 14); + } else + base = PODSLOT_IOC4_BASE + ((slot - 4) << 14); #ifdef CONFIG_ARCH_RPC if (slot < 8) { ec_set_resource(ec, ECARD_RES_EASI, PODSLOT_EASI_BASE + (slot << 24), - PODSLOT_EASI_SIZE, IORESOURCE_MEM); + PODSLOT_EASI_SIZE); } if (slot == 8) { - ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, - NETSLOT_SIZE, IORESOURCE_MEM); + ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE); } else #endif - for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) { + for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) ec_set_resource(ec, i + ECARD_RES_IOCSLOW, - base + (slot << 14) + (i << 19), - PODSLOT_IOC_SIZE, IORESOURCE_MEM); - } + base + (i << 19), PODSLOT_IOC_SIZE); for (i = 0; i < ECARD_NUM_RESOURCES; i++) { - if (ec->resource[i].start && + if (ec->resource[i].flags && request_resource(&iomem_resource, &ec->resource[i])) { printk(KERN_ERR "%s: resource(s) not available\n", ec->dev.bus_id); ec->resource[i].end -= ec->resource[i].start; ec->resource[i].start = 0; + ec->resource[i].flags = 0; } } + + nomem: + return ec; } -static ssize_t ecard_show_irq(struct device *dev, char *buf) +static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->irq); } -static DEVICE_ATTR(irq, S_IRUGO, ecard_show_irq, NULL); - -static ssize_t ecard_show_dma(struct device *dev, char *buf) +static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->dma); } -static DEVICE_ATTR(dma, S_IRUGO, ecard_show_dma, NULL); - -static ssize_t ecard_show_resources(struct device *dev, char *buf) +static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); char *str = buf; @@ -861,23 +892,33 @@ static ssize_t ecard_show_resources(struct device *dev, char *buf) return str - buf; } -static DEVICE_ATTR(resource, S_IRUGO, ecard_show_resources, NULL); - -static ssize_t ecard_show_vendor(struct device *dev, char *buf) +static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.manufacturer); } -static DEVICE_ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL); - -static ssize_t ecard_show_device(struct device *dev, char *buf) +static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); return sprintf(buf, "%u\n", ec->cid.product); } -static DEVICE_ATTR(device, S_IRUGO, ecard_show_device, NULL); +static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); +} + +static struct device_attribute ecard_dev_attrs[] = { + __ATTR(device, S_IRUGO, ecard_show_device, NULL), + __ATTR(dma, S_IRUGO, ecard_show_dma, NULL), + __ATTR(irq, S_IRUGO, ecard_show_irq, NULL), + __ATTR(resource, S_IRUGO, ecard_show_resources, NULL), + __ATTR(type, S_IRUGO, ecard_show_type, NULL), + __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL), + __ATTR_NULL, +}; int ecard_request_resources(struct expansion_card *ec) @@ -927,21 +968,13 @@ ecard_probe(int slot, card_type_t type) ecard_t **ecp; ecard_t *ec; struct ex_ecid cid; - int i, rc = -ENOMEM; + int i, rc; - ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); - if (!ec) + ec = ecard_alloc_card(type, slot); + if (IS_ERR(ec)) { + rc = PTR_ERR(ec); goto nomem; - - memset(ec, 0, sizeof(ecard_t)); - - ec->slot_no = slot; - ec->type = type; - ec->irq = NO_IRQ; - ec->fiq = NO_IRQ; - ec->dma = NO_DMA; - ec->card_desc = NULL; - ec->ops = &ecard_default_ops; + } rc = -ENODEV; if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) @@ -964,7 +997,7 @@ ecard_probe(int slot, card_type_t type) ec->cid.fiqmask = cid.r_fiqmask; ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); ec->fiqaddr = - ec->irqaddr = (unsigned char *)ioaddr(ec->podaddr); + ec->irqaddr = (void __iomem *)ioaddr(ec->podaddr); if (ec->cid.is) { ec->irqmask = ec->cid.irqmask; @@ -983,14 +1016,6 @@ ecard_probe(int slot, card_type_t type) break; } - snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); - ec->dev.parent = NULL; - ec->dev.bus = &ecard_bus_type; - ec->dev.dma_mask = &ec->dma_mask; - ec->dma_mask = (u64)0xffffffff; - - ecard_init_resources(ec); - /* * hook the interrupt handlers */ @@ -1017,17 +1042,12 @@ ecard_probe(int slot, card_type_t type) slot_to_expcard[slot] = ec; device_register(&ec->dev); - device_create_file(&ec->dev, &dev_attr_dma); - device_create_file(&ec->dev, &dev_attr_irq); - device_create_file(&ec->dev, &dev_attr_resource); - device_create_file(&ec->dev, &dev_attr_vendor); - device_create_file(&ec->dev, &dev_attr_device); return 0; -nodev: - kfree(ec); -nomem: + nodev: + ecard_free_card(ec); + nomem: return rc; } @@ -1125,20 +1145,25 @@ static void ecard_drv_shutdown(struct device *dev) struct ecard_driver *drv = ECARD_DRV(dev->driver); struct ecard_request req; - if (drv->shutdown) - drv->shutdown(ec); - ecard_release(ec); - req.fn = ecard_task_reset; - req.ec = ec; - ecard_call(&req); + if (dev->driver) { + if (drv->shutdown) + drv->shutdown(ec); + ecard_release(ec); + } + + /* + * If this card has a loader, call the reset handler. + */ + if (ec->loader) { + req.fn = ecard_task_reset; + req.ec = ec; + ecard_call(&req); + } } int ecard_register_driver(struct ecard_driver *drv) { drv->drv.bus = &ecard_bus_type; - drv->drv.probe = ecard_drv_probe; - drv->drv.remove = ecard_drv_remove; - drv->drv.shutdown = ecard_drv_shutdown; return driver_register(&drv->drv); } @@ -1164,8 +1189,12 @@ static int ecard_match(struct device *_dev, struct device_driver *_drv) } struct bus_type ecard_bus_type = { - .name = "ecard", - .match = ecard_match, + .name = "ecard", + .dev_attrs = ecard_dev_attrs, + .match = ecard_match, + .probe = ecard_drv_probe, + .remove = ecard_drv_remove, + .shutdown = ecard_drv_shutdown, }; static int ecard_bus_init(void) @@ -1176,7 +1205,7 @@ static int ecard_bus_init(void) postcore_initcall(ecard_bus_init); EXPORT_SYMBOL(ecard_readchunk); -EXPORT_SYMBOL(ecard_address); +EXPORT_SYMBOL(__ecard_address); EXPORT_SYMBOL(ecard_register_driver); EXPORT_SYMBOL(ecard_remove_driver); EXPORT_SYMBOL(ecard_bus_type);