Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * drivers/uio/uio_pdrv_genirq.c
0004  *
0005  * Userspace I/O platform driver with generic IRQ handling code.
0006  *
0007  * Copyright (C) 2008 Magnus Damm
0008  *
0009  * Based on uio_pdrv.c by Uwe Kleine-Koenig,
0010  * Copyright (C) 2008 by Digi International Inc.
0011  * All rights reserved.
0012  */
0013 
0014 #include <linux/platform_device.h>
0015 #include <linux/uio_driver.h>
0016 #include <linux/spinlock.h>
0017 #include <linux/bitops.h>
0018 #include <linux/module.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/stringify.h>
0021 #include <linux/pm_runtime.h>
0022 #include <linux/slab.h>
0023 #include <linux/irq.h>
0024 
0025 #include <linux/of.h>
0026 #include <linux/of_platform.h>
0027 #include <linux/of_address.h>
0028 
0029 #define DRIVER_NAME "uio_pdrv_genirq"
0030 
0031 struct uio_pdrv_genirq_platdata {
0032     struct uio_info *uioinfo;
0033     spinlock_t lock;
0034     unsigned long flags;
0035     struct platform_device *pdev;
0036 };
0037 
0038 /* Bits in uio_pdrv_genirq_platdata.flags */
0039 enum {
0040     UIO_IRQ_DISABLED = 0,
0041 };
0042 
0043 static int uio_pdrv_genirq_open(struct uio_info *info, struct inode *inode)
0044 {
0045     struct uio_pdrv_genirq_platdata *priv = info->priv;
0046 
0047     /* Wait until the Runtime PM code has woken up the device */
0048     pm_runtime_get_sync(&priv->pdev->dev);
0049     return 0;
0050 }
0051 
0052 static int uio_pdrv_genirq_release(struct uio_info *info, struct inode *inode)
0053 {
0054     struct uio_pdrv_genirq_platdata *priv = info->priv;
0055 
0056     /* Tell the Runtime PM code that the device has become idle */
0057     pm_runtime_put_sync(&priv->pdev->dev);
0058     return 0;
0059 }
0060 
0061 static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info)
0062 {
0063     struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
0064 
0065     /* Just disable the interrupt in the interrupt controller, and
0066      * remember the state so we can allow user space to enable it later.
0067      */
0068 
0069     spin_lock(&priv->lock);
0070     if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
0071         disable_irq_nosync(irq);
0072     spin_unlock(&priv->lock);
0073 
0074     return IRQ_HANDLED;
0075 }
0076 
0077 static int uio_pdrv_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
0078 {
0079     struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
0080     unsigned long flags;
0081 
0082     /* Allow user space to enable and disable the interrupt
0083      * in the interrupt controller, but keep track of the
0084      * state to prevent per-irq depth damage.
0085      *
0086      * Serialize this operation to support multiple tasks and concurrency
0087      * with irq handler on SMP systems.
0088      */
0089 
0090     spin_lock_irqsave(&priv->lock, flags);
0091     if (irq_on) {
0092         if (__test_and_clear_bit(UIO_IRQ_DISABLED, &priv->flags))
0093             enable_irq(dev_info->irq);
0094     } else {
0095         if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
0096             disable_irq_nosync(dev_info->irq);
0097     }
0098     spin_unlock_irqrestore(&priv->lock, flags);
0099 
0100     return 0;
0101 }
0102 
0103 static void uio_pdrv_genirq_cleanup(void *data)
0104 {
0105     struct device *dev = data;
0106 
0107     pm_runtime_disable(dev);
0108 }
0109 
0110 static int uio_pdrv_genirq_probe(struct platform_device *pdev)
0111 {
0112     struct uio_info *uioinfo = dev_get_platdata(&pdev->dev);
0113     struct device_node *node = pdev->dev.of_node;
0114     struct uio_pdrv_genirq_platdata *priv;
0115     struct uio_mem *uiomem;
0116     int ret = -EINVAL;
0117     int i;
0118 
0119     if (node) {
0120         const char *name;
0121 
0122         /* alloc uioinfo for one device */
0123         uioinfo = devm_kzalloc(&pdev->dev, sizeof(*uioinfo),
0124                        GFP_KERNEL);
0125         if (!uioinfo) {
0126             dev_err(&pdev->dev, "unable to kmalloc\n");
0127             return -ENOMEM;
0128         }
0129 
0130         if (!of_property_read_string(node, "linux,uio-name", &name))
0131             uioinfo->name = devm_kstrdup(&pdev->dev, name, GFP_KERNEL);
0132         else
0133             uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
0134                                "%pOFn", node);
0135 
0136         uioinfo->version = "devicetree";
0137         /* Multiple IRQs are not supported */
0138     }
0139 
0140     if (!uioinfo || !uioinfo->name || !uioinfo->version) {
0141         dev_err(&pdev->dev, "missing platform_data\n");
0142         return ret;
0143     }
0144 
0145     if (uioinfo->handler || uioinfo->irqcontrol ||
0146         uioinfo->irq_flags & IRQF_SHARED) {
0147         dev_err(&pdev->dev, "interrupt configuration error\n");
0148         return ret;
0149     }
0150 
0151     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0152     if (!priv) {
0153         dev_err(&pdev->dev, "unable to kmalloc\n");
0154         return -ENOMEM;
0155     }
0156 
0157     priv->uioinfo = uioinfo;
0158     spin_lock_init(&priv->lock);
0159     priv->flags = 0; /* interrupt is enabled to begin with */
0160     priv->pdev = pdev;
0161 
0162     if (!uioinfo->irq) {
0163         ret = platform_get_irq_optional(pdev, 0);
0164         uioinfo->irq = ret;
0165         if (ret == -ENXIO)
0166             uioinfo->irq = UIO_IRQ_NONE;
0167         else if (ret == -EPROBE_DEFER)
0168             return ret;
0169         else if (ret < 0) {
0170             dev_err(&pdev->dev, "failed to get IRQ\n");
0171             return ret;
0172         }
0173     }
0174 
0175     if (uioinfo->irq) {
0176         struct irq_data *irq_data = irq_get_irq_data(uioinfo->irq);
0177 
0178         /*
0179          * If a level interrupt, dont do lazy disable. Otherwise the
0180          * irq will fire again since clearing of the actual cause, on
0181          * device level, is done in userspace
0182          * irqd_is_level_type() isn't used since isn't valid until
0183          * irq is configured.
0184          */
0185         if (irq_data &&
0186             irqd_get_trigger_type(irq_data) & IRQ_TYPE_LEVEL_MASK) {
0187             dev_dbg(&pdev->dev, "disable lazy unmask\n");
0188             irq_set_status_flags(uioinfo->irq, IRQ_DISABLE_UNLAZY);
0189         }
0190     }
0191 
0192     uiomem = &uioinfo->mem[0];
0193 
0194     for (i = 0; i < pdev->num_resources; ++i) {
0195         struct resource *r = &pdev->resource[i];
0196 
0197         if (r->flags != IORESOURCE_MEM)
0198             continue;
0199 
0200         if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
0201             dev_warn(&pdev->dev, "device has more than "
0202                     __stringify(MAX_UIO_MAPS)
0203                     " I/O memory resources.\n");
0204             break;
0205         }
0206 
0207         uiomem->memtype = UIO_MEM_PHYS;
0208         uiomem->addr = r->start & PAGE_MASK;
0209         uiomem->offs = r->start & ~PAGE_MASK;
0210         uiomem->size = (uiomem->offs + resource_size(r)
0211                 + PAGE_SIZE - 1) & PAGE_MASK;
0212         uiomem->name = r->name;
0213         ++uiomem;
0214     }
0215 
0216     while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
0217         uiomem->size = 0;
0218         ++uiomem;
0219     }
0220 
0221     /* This driver requires no hardware specific kernel code to handle
0222      * interrupts. Instead, the interrupt handler simply disables the
0223      * interrupt in the interrupt controller. User space is responsible
0224      * for performing hardware specific acknowledge and re-enabling of
0225      * the interrupt in the interrupt controller.
0226      *
0227      * Interrupt sharing is not supported.
0228      */
0229 
0230     uioinfo->handler = uio_pdrv_genirq_handler;
0231     uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol;
0232     uioinfo->open = uio_pdrv_genirq_open;
0233     uioinfo->release = uio_pdrv_genirq_release;
0234     uioinfo->priv = priv;
0235 
0236     /* Enable Runtime PM for this device:
0237      * The device starts in suspended state to allow the hardware to be
0238      * turned off by default. The Runtime PM bus code should power on the
0239      * hardware and enable clocks at open().
0240      */
0241     pm_runtime_enable(&pdev->dev);
0242 
0243     ret = devm_add_action_or_reset(&pdev->dev, uio_pdrv_genirq_cleanup,
0244                        &pdev->dev);
0245     if (ret)
0246         return ret;
0247 
0248     ret = devm_uio_register_device(&pdev->dev, priv->uioinfo);
0249     if (ret)
0250         dev_err(&pdev->dev, "unable to register uio device\n");
0251 
0252     return ret;
0253 }
0254 
0255 static int uio_pdrv_genirq_runtime_nop(struct device *dev)
0256 {
0257     /* Runtime PM callback shared between ->runtime_suspend()
0258      * and ->runtime_resume(). Simply returns success.
0259      *
0260      * In this driver pm_runtime_get_sync() and pm_runtime_put_sync()
0261      * are used at open() and release() time. This allows the
0262      * Runtime PM code to turn off power to the device while the
0263      * device is unused, ie before open() and after release().
0264      *
0265      * This Runtime PM callback does not need to save or restore
0266      * any registers since user space is responsbile for hardware
0267      * register reinitialization after open().
0268      */
0269     return 0;
0270 }
0271 
0272 static const struct dev_pm_ops uio_pdrv_genirq_dev_pm_ops = {
0273     .runtime_suspend = uio_pdrv_genirq_runtime_nop,
0274     .runtime_resume = uio_pdrv_genirq_runtime_nop,
0275 };
0276 
0277 #ifdef CONFIG_OF
0278 static struct of_device_id uio_of_genirq_match[] = {
0279     { /* This is filled with module_parm */ },
0280     { /* Sentinel */ },
0281 };
0282 MODULE_DEVICE_TABLE(of, uio_of_genirq_match);
0283 module_param_string(of_id, uio_of_genirq_match[0].compatible, 128, 0);
0284 MODULE_PARM_DESC(of_id, "Openfirmware id of the device to be handled by uio");
0285 #endif
0286 
0287 static struct platform_driver uio_pdrv_genirq = {
0288     .probe = uio_pdrv_genirq_probe,
0289     .driver = {
0290         .name = DRIVER_NAME,
0291         .pm = &uio_pdrv_genirq_dev_pm_ops,
0292         .of_match_table = of_match_ptr(uio_of_genirq_match),
0293     },
0294 };
0295 
0296 module_platform_driver(uio_pdrv_genirq);
0297 
0298 MODULE_AUTHOR("Magnus Damm");
0299 MODULE_DESCRIPTION("Userspace I/O platform driver with generic IRQ handling");
0300 MODULE_LICENSE("GPL v2");
0301 MODULE_ALIAS("platform:" DRIVER_NAME);