Merge tag 'platform-drivers-x86-v4.20-1' of git://git.infradead.org/linux-platform...
[sfrench/cifs-2.6.git] / drivers / platform / goldfish / goldfish_pipe.c
index 8747ec330b7b051ed5529b23a24367544ee1fb49..7c639006252ec912058b8f7c1933b2c2db5dc454 100644 (file)
@@ -59,7 +59,6 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/io.h>
-#include <linux/goldfish.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
 #include <linux/acpi.h>
@@ -82,8 +81,6 @@ enum {
 };
 
 struct goldfish_pipe_dev;
-struct goldfish_pipe;
-struct goldfish_pipe_command;
 
 /* A per-pipe command structure, shared with the host */
 struct goldfish_pipe_command {
@@ -172,6 +169,9 @@ struct goldfish_pipe {
  * waiting to be awoken.
  */
 struct goldfish_pipe_dev {
+       /* A magic number to check if this is an instance of this struct */
+       void *magic;
+
        /*
         * Global device spinlock. Protects the following members:
         *  - pipes, pipes_capacity
@@ -211,9 +211,12 @@ struct goldfish_pipe_dev {
        int irq;
        int version;
        unsigned char __iomem *base;
-};
 
-struct goldfish_pipe_dev goldfish_pipe_dev;
+       /* an irq tasklet to run goldfish_interrupt_task */
+       struct tasklet_struct irq_tasklet;
+
+       struct miscdevice miscdev;
+};
 
 static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe,
                                    enum PipeCmdCode cmd)
@@ -585,14 +588,14 @@ static struct goldfish_pipe *signalled_pipes_pop_front(
        return pipe;
 }
 
-static void goldfish_interrupt_task(unsigned long unused)
+static void goldfish_interrupt_task(unsigned long dev_addr)
 {
        /* Iterate over the signalled pipes and wake them one by one */
+       struct goldfish_pipe_dev *dev = (struct goldfish_pipe_dev *)dev_addr;
        struct goldfish_pipe *pipe;
        int wakes;
 
-       while ((pipe = signalled_pipes_pop_front(&goldfish_pipe_dev, &wakes)) !=
-                       NULL) {
+       while ((pipe = signalled_pipes_pop_front(dev, &wakes)) != NULL) {
                if (wakes & PIPE_WAKE_CLOSED) {
                        pipe->flags = 1 << BIT_CLOSED_ON_HOST;
                } else {
@@ -608,7 +611,9 @@ static void goldfish_interrupt_task(unsigned long unused)
                wake_up_interruptible(&pipe->wake_queue);
        }
 }
-static DECLARE_TASKLET(goldfish_interrupt_tasklet, goldfish_interrupt_task, 0);
+
+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
+                                       struct goldfish_pipe_dev *dev);
 
 /*
  * The general idea of the interrupt handling:
@@ -630,7 +635,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
        unsigned long flags;
        struct goldfish_pipe_dev *dev = dev_id;
 
-       if (dev != &goldfish_pipe_dev)
+       if (dev->magic != &goldfish_pipe_device_deinit)
                return IRQ_NONE;
 
        /* Request the signalled pipes from the device */
@@ -651,7 +656,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       tasklet_schedule(&goldfish_interrupt_tasklet);
+       tasklet_schedule(&dev->irq_tasklet);
        return IRQ_HANDLED;
 }
 
@@ -682,6 +687,14 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
        return id;
 }
 
+/* A helper function to get the instance of goldfish_pipe_dev from file */
+static struct goldfish_pipe_dev *to_goldfish_pipe_dev(struct file *file)
+{
+       struct miscdevice *miscdev = file->private_data;
+
+       return container_of(miscdev, struct goldfish_pipe_dev, miscdev);
+}
+
 /**
  *     goldfish_pipe_open - open a channel to the AVD
  *     @inode: inode of device
@@ -695,13 +708,14 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
  */
 static int goldfish_pipe_open(struct inode *inode, struct file *file)
 {
-       struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
+       struct goldfish_pipe_dev *dev = to_goldfish_pipe_dev(file);
        unsigned long flags;
        int id;
        int status;
 
        /* Allocate new pipe kernel object */
        struct goldfish_pipe *pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
+
        if (!pipe)
                return -ENOMEM;
 
@@ -786,11 +800,14 @@ static const struct file_operations goldfish_pipe_fops = {
        .release = goldfish_pipe_release,
 };
 
-static struct miscdevice goldfish_pipe_miscdev = {
-       .minor = MISC_DYNAMIC_MINOR,
-       .name = "goldfish_pipe",
-       .fops = &goldfish_pipe_fops,
-};
+static void init_miscdevice(struct miscdevice *miscdev)
+{
+       memset(miscdev, 0, sizeof(*miscdev));
+
+       miscdev->minor = MISC_DYNAMIC_MINOR;
+       miscdev->name = "goldfish_pipe";
+       miscdev->fops = &goldfish_pipe_fops;
+}
 
 static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
 {
@@ -800,18 +817,24 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
        writel(lower_32_bits(paddr), portl);
 }
 
-static int goldfish_pipe_device_init(struct platform_device *pdev)
+static int goldfish_pipe_device_init(struct platform_device *pdev,
+                                    struct goldfish_pipe_dev *dev)
 {
-       struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
-       int err = devm_request_irq(&pdev->dev, dev->irq,
-                               goldfish_pipe_interrupt,
-                               IRQF_SHARED, "goldfish_pipe", dev);
+       int err;
+
+       tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task,
+                    (unsigned long)dev);
+
+       err = devm_request_irq(&pdev->dev, dev->irq,
+                              goldfish_pipe_interrupt,
+                              IRQF_SHARED, "goldfish_pipe", dev);
        if (err) {
                dev_err(&pdev->dev, "unable to allocate IRQ for v2\n");
                return err;
        }
 
-       err = misc_register(&goldfish_pipe_miscdev);
+       init_miscdevice(&dev->miscdev);
+       err = misc_register(&dev->miscdev);
        if (err) {
                dev_err(&pdev->dev, "unable to register v2 device\n");
                return err;
@@ -822,8 +845,10 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
        dev->pipes_capacity = INITIAL_PIPES_CAPACITY;
        dev->pipes = kcalloc(dev->pipes_capacity, sizeof(*dev->pipes),
                             GFP_KERNEL);
-       if (!dev->pipes)
+       if (!dev->pipes) {
+               misc_deregister(&dev->miscdev);
                return -ENOMEM;
+       }
 
        /*
         * We're going to pass two buffers, open_command_params and
@@ -836,6 +861,7 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
                __get_free_page(GFP_KERNEL);
        if (!dev->buffers) {
                kfree(dev->pipes);
+               misc_deregister(&dev->miscdev);
                return -ENOMEM;
        }
 
@@ -851,25 +877,29 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
                      dev->base + PIPE_REG_OPEN_BUFFER,
                      dev->base + PIPE_REG_OPEN_BUFFER_HIGH);
 
+       platform_set_drvdata(pdev, dev);
        return 0;
 }
 
-static void goldfish_pipe_device_deinit(struct platform_device *pdev)
+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
+                                       struct goldfish_pipe_dev *dev)
 {
-       misc_deregister(&goldfish_pipe_miscdev);
-       kfree(goldfish_pipe_dev.pipes);
-       free_page((unsigned long)goldfish_pipe_dev.buffers);
+       misc_deregister(&dev->miscdev);
+       tasklet_kill(&dev->irq_tasklet);
+       kfree(dev->pipes);
+       free_page((unsigned long)dev->buffers);
 }
 
 static int goldfish_pipe_probe(struct platform_device *pdev)
 {
-       int err;
        struct resource *r;
-       struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
+       struct goldfish_pipe_dev *dev;
 
-       /* not thread safe, but this should not happen */
-       WARN_ON(dev->base);
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
 
+       dev->magic = &goldfish_pipe_device_deinit;
        spin_lock_init(&dev->lock);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -884,10 +914,9 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
        }
 
        r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!r) {
-               err = -EINVAL;
-               goto error;
-       }
+       if (!r)
+               return -EINVAL;
+
        dev->irq = r->start;
 
        /*
@@ -897,25 +926,19 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
         *  reading device version back: this allows the host implementation to
         *  detect the old driver (if there was no version write before read).
         */
-       writel((u32)PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION);
+       writel(PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION);
        dev->version = readl(dev->base + PIPE_REG_VERSION);
        if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION))
                return -EINVAL;
 
-       err = goldfish_pipe_device_init(pdev);
-       if (!err)
-               return 0;
-
-error:
-       dev->base = NULL;
-       return err;
+       return goldfish_pipe_device_init(pdev, dev);
 }
 
 static int goldfish_pipe_remove(struct platform_device *pdev)
 {
-       struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
-       goldfish_pipe_device_deinit(pdev);
-       dev->base = NULL;
+       struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev);
+
+       goldfish_pipe_device_deinit(pdev, dev);
        return 0;
 }