virtio: add virtio disk geometry feature
[safe/jmp/linux-2.6] / drivers / block / xsysace.c
index 555939b..4a7a059 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/platform_device.h>
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 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;
@@ -1154,6 +1158,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
  */
 static int __init ace_init(void)
@@ -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");
 }