X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fblock%2Fxsysace.c;h=4a7a059ebaf70b83f564430883ad517966c635de;hb=2fdc86901d2ab30a12402b46238951d2a7891590;hp=555939bd2d53b0ce012585ddedb497305a5c8972;hpb=1b455466549f46bab0a75a7a296a9331a38fd6fa;p=linux-2.6 diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 555939bd2d..4a7a059eba 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -91,6 +91,10 @@ #include #include #include +#if defined(CONFIG_OF) +#include +#include +#endif MODULE_AUTHOR("Grant Likely "); MODULE_DESCRIPTION("Xilinx SystemACE device driver"); @@ -158,6 +162,9 @@ MODULE_LICENSE("GPL"); #define ACE_FIFO_SIZE (32) #define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE) +#define ACE_BUS_WIDTH_8 0 +#define ACE_BUS_WIDTH_16 1 + struct ace_reg_ops; struct ace_device { @@ -188,7 +195,7 @@ struct ace_device { /* Details of hardware device */ unsigned long physaddr; - void *baseaddr; + void __iomem *baseaddr; int irq; int bus_width; /* 0 := 8 bit; 1 := 16 bit */ struct ace_reg_ops *reg_ops; @@ -220,20 +227,20 @@ struct ace_reg_ops { /* 8 Bit bus width */ static u16 ace_in_8(struct ace_device *ace, int reg) { - void *r = ace->baseaddr + reg; + void __iomem *r = ace->baseaddr + reg; return in_8(r) | (in_8(r + 1) << 8); } static void ace_out_8(struct ace_device *ace, int reg, u16 val) { - void *r = ace->baseaddr + reg; + void __iomem *r = ace->baseaddr + reg; out_8(r, val); out_8(r + 1, val >> 8); } static void ace_datain_8(struct ace_device *ace) { - void *r = ace->baseaddr + 0x40; + void __iomem *r = ace->baseaddr + 0x40; u8 *dst = ace->data_ptr; int i = ACE_FIFO_SIZE; while (i--) @@ -243,7 +250,7 @@ static void ace_datain_8(struct ace_device *ace) static void ace_dataout_8(struct ace_device *ace) { - void *r = ace->baseaddr + 0x40; + void __iomem *r = ace->baseaddr + 0x40; u8 *src = ace->data_ptr; int i = ACE_FIFO_SIZE; while (i--) @@ -383,8 +390,8 @@ static inline void ace_dump_mem(void *base, int len) static void ace_dump_regs(struct ace_device *ace) { dev_info(ace->dev, " ctrl: %.8x seccnt/cmd: %.4x ver:%.4x\n" - " status:%.8x mpu_lba:%.8x busmode:%4x\n" - " error: %.8x cfg_lba:%.8x fatstat:%.4x\n", + KERN_INFO " status:%.8x mpu_lba:%.8x busmode:%4x\n" + KERN_INFO " error: %.8x cfg_lba:%.8x fatstat:%.4x\n", ace_in32(ace, ACE_CTRL), ace_in(ace, ACE_SECCNTCMD), ace_in(ace, ACE_VERSION), @@ -476,7 +483,6 @@ static void ace_fsm_dostate(struct ace_device *ace) u32 status; u16 val; int count; - int i; #if defined(DEBUG) dev_dbg(ace->dev, "fsm_state=%i, id_req_count=%i\n", @@ -681,7 +687,6 @@ static void ace_fsm_dostate(struct ace_device *ace) } /* Transfer the next buffer */ - i = 16; if (ace->fsm_task == ACE_TASK_WRITE) ace->reg_ops->dataout(ace); else @@ -695,8 +700,8 @@ static void ace_fsm_dostate(struct ace_device *ace) } /* bio finished; is there another one? */ - i = ace->req->current_nr_sectors; - if (end_that_request_first(ace->req, 1, i)) { + if (__blk_end_request(ace->req, 0, + blk_rq_cur_bytes(ace->req))) { /* dev_dbg(ace->dev, "next block; h=%li c=%i\n", * ace->req->hard_nr_sectors, * ace->req->current_nr_sectors); @@ -711,9 +716,6 @@ static void ace_fsm_dostate(struct ace_device *ace) break; case ACE_FSM_STATE_REQ_COMPLETE: - /* Complete the block request */ - blkdev_dequeue_request(ace->req); - end_that_request_last(ace->req, 1); ace->req = NULL; /* Finished request; go to idle state */ @@ -931,9 +933,11 @@ static int __devinit ace_setup(struct ace_device *ace) { u16 version; u16 val; - int rc; + dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace); + dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq); + spin_lock_init(&ace->lock); init_completion(&ace->id_completion); @@ -944,15 +948,6 @@ static int __devinit ace_setup(struct ace_device *ace) if (!ace->baseaddr) goto err_ioremap; - if (ace->irq != NO_IRQ) { - rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); - if (rc) { - /* Failure - fall back to polled mode */ - dev_err(ace->dev, "request_irq failed\n"); - ace->irq = NO_IRQ; - } - } - /* * Initialize the state machine tasklet and stall timer */ @@ -982,7 +977,7 @@ static int __devinit ace_setup(struct ace_device *ace) snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); /* set bus width */ - if (ace->bus_width == 1) { + if (ace->bus_width == ACE_BUS_WIDTH_16) { /* 0x0101 should work regardless of endianess */ ace_out_le16(ace, ACE_BUSMODE, 0x0101); @@ -1005,6 +1000,16 @@ static int __devinit ace_setup(struct ace_device *ace) ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE | ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ); + /* Now we can hook up the irq handler */ + if (ace->irq != NO_IRQ) { + rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); + if (rc) { + /* Failure - fall back to polled mode */ + dev_err(ace->dev, "request_irq failed\n"); + ace->irq = NO_IRQ; + } + } + /* Enable interrupts */ val = ace_in(ace, ACE_CTRL); val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; @@ -1024,15 +1029,13 @@ static int __devinit ace_setup(struct ace_device *ace) return 0; - err_read: +err_read: put_disk(ace->gd); - err_alloc_disk: +err_alloc_disk: blk_cleanup_queue(ace->queue); - err_blk_initq: +err_blk_initq: iounmap(ace->baseaddr); - if (ace->irq != NO_IRQ) - free_irq(ace->irq, ace); - err_ioremap: +err_ioremap: dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", ace->physaddr); return -ENOMEM; @@ -1083,17 +1086,18 @@ ace_alloc(struct device *dev, int id, unsigned long physaddr, ace->bus_width = bus_width; /* Call the setup code */ - if ((rc = ace_setup(ace)) != 0) + rc = ace_setup(ace); + if (rc) goto err_setup; dev_set_drvdata(dev, ace); return 0; - err_setup: +err_setup: dev_set_drvdata(dev, NULL); kfree(ace); - err_alloc: - err_noreg: +err_alloc: +err_noreg: dev_err(dev, "could not initialize device, err=%i\n", rc); return rc; } @@ -1117,7 +1121,7 @@ static void __devexit ace_free(struct device *dev) static int __devinit ace_probe(struct platform_device *dev) { unsigned long physaddr = 0; - int bus_width = 1; /* FIXME: should not be hard coded */ + int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */ int id = dev->id; int irq = NO_IRQ; int i; @@ -1153,6 +1157,87 @@ static struct platform_driver ace_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF_Platform Bus Support + */ + +#if defined(CONFIG_OF) +static int __devinit +ace_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + unsigned long physaddr; + const u32 *id; + int irq, bus_width, rc; + + dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match); + + /* device id */ + id = of_get_property(op->node, "port-number", NULL); + + /* physaddr */ + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return rc; + } + physaddr = res.start; + + /* irq */ + irq = irq_of_parse_and_map(op->node, 0); + + /* bus width */ + bus_width = ACE_BUS_WIDTH_16; + if (of_find_property(op->node, "8-bit", NULL)) + bus_width = ACE_BUS_WIDTH_8; + + /* Call the bus-independant setup code */ + return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width); +} + +static int __devexit ace_of_remove(struct of_device *op) +{ + ace_free(&op->dev); + return 0; +} + +/* Match table for of_platform binding */ +static struct of_device_id ace_of_match[] __devinitdata = { + { .compatible = "xlnx,opb-sysace-1.00.b", }, + { .compatible = "xlnx,opb-sysace-1.00.c", }, + { .compatible = "xlnx,xps-sysace-1.00.a", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ace_of_match); + +static struct of_platform_driver ace_of_driver = { + .owner = THIS_MODULE, + .name = "xsysace", + .match_table = ace_of_match, + .probe = ace_of_probe, + .remove = __devexit_p(ace_of_remove), + .driver = { + .name = "xsysace", + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init ace_of_register(void) +{ + pr_debug("xsysace: registering OF binding\n"); + return of_register_platform_driver(&ace_of_driver); +} + +static inline void __exit ace_of_unregister(void) +{ + of_unregister_platform_driver(&ace_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init ace_of_register(void) { return 0; } +static inline void __exit ace_of_unregister(void) { } +#endif /* CONFIG_OF */ + /* --------------------------------------------------------------------- * Module init/exit routines */ @@ -1166,15 +1251,23 @@ static int __init ace_init(void) goto err_blk; } - if ((rc = platform_driver_register(&ace_platform_driver)) != 0) + rc = ace_of_register(); + if (rc) + goto err_of; + + pr_debug("xsysace: registering platform binding\n"); + rc = platform_driver_register(&ace_platform_driver); + if (rc) goto err_plat; pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); return 0; - err_plat: +err_plat: + ace_of_unregister(); +err_of: unregister_blkdev(ace_major, "xsysace"); - err_blk: +err_blk: printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); return rc; } @@ -1183,6 +1276,7 @@ static void __exit ace_exit(void) { pr_debug("Unregistering Xilinx SystemACE driver\n"); platform_driver_unregister(&ace_platform_driver); + ace_of_unregister(); unregister_blkdev(ace_major, "xsysace"); }