linux/drivers/uio/uio_pdrv_genirq.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * drivers/uio/uio_pdrv_genirq.c
   4 *
   5 * Userspace I/O platform driver with generic IRQ handling code.
   6 *
   7 * Copyright (C) 2008 Magnus Damm
   8 *
   9 * Based on uio_pdrv.c by Uwe Kleine-Koenig,
  10 * Copyright (C) 2008 by Digi International Inc.
  11 * All rights reserved.
  12 */
  13
  14#include <linux/platform_device.h>
  15#include <linux/uio_driver.h>
  16#include <linux/spinlock.h>
  17#include <linux/bitops.h>
  18#include <linux/module.h>
  19#include <linux/interrupt.h>
  20#include <linux/stringify.h>
  21#include <linux/pm_runtime.h>
  22#include <linux/slab.h>
  23#include <linux/irq.h>
  24
  25#include <linux/of.h>
  26#include <linux/of_platform.h>
  27#include <linux/of_address.h>
  28
  29#define DRIVER_NAME "uio_pdrv_genirq"
  30
  31struct uio_pdrv_genirq_platdata {
  32        struct uio_info *uioinfo;
  33        spinlock_t lock;
  34        unsigned long flags;
  35        struct platform_device *pdev;
  36};
  37
  38/* Bits in uio_pdrv_genirq_platdata.flags */
  39enum {
  40        UIO_IRQ_DISABLED = 0,
  41};
  42
  43static int uio_pdrv_genirq_open(struct uio_info *info, struct inode *inode)
  44{
  45        struct uio_pdrv_genirq_platdata *priv = info->priv;
  46
  47        /* Wait until the Runtime PM code has woken up the device */
  48        pm_runtime_get_sync(&priv->pdev->dev);
  49        return 0;
  50}
  51
  52static int uio_pdrv_genirq_release(struct uio_info *info, struct inode *inode)
  53{
  54        struct uio_pdrv_genirq_platdata *priv = info->priv;
  55
  56        /* Tell the Runtime PM code that the device has become idle */
  57        pm_runtime_put_sync(&priv->pdev->dev);
  58        return 0;
  59}
  60
  61static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info)
  62{
  63        struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
  64
  65        /* Just disable the interrupt in the interrupt controller, and
  66         * remember the state so we can allow user space to enable it later.
  67         */
  68
  69        spin_lock(&priv->lock);
  70        if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
  71                disable_irq_nosync(irq);
  72        spin_unlock(&priv->lock);
  73
  74        return IRQ_HANDLED;
  75}
  76
  77static int uio_pdrv_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
  78{
  79        struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
  80        unsigned long flags;
  81
  82        /* Allow user space to enable and disable the interrupt
  83         * in the interrupt controller, but keep track of the
  84         * state to prevent per-irq depth damage.
  85         *
  86         * Serialize this operation to support multiple tasks and concurrency
  87         * with irq handler on SMP systems.
  88         */
  89
  90        spin_lock_irqsave(&priv->lock, flags);
  91        if (irq_on) {
  92                if (__test_and_clear_bit(UIO_IRQ_DISABLED, &priv->flags))
  93                        enable_irq(dev_info->irq);
  94        } else {
  95                if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
  96                        disable_irq_nosync(dev_info->irq);
  97        }
  98        spin_unlock_irqrestore(&priv->lock, flags);
  99
 100        return 0;
 101}
 102
 103static void uio_pdrv_genirq_cleanup(void *data)
 104{
 105        struct device *dev = data;
 106
 107        pm_runtime_disable(dev);
 108}
 109
 110static int uio_pdrv_genirq_probe(struct platform_device *pdev)
 111{
 112        struct uio_info *uioinfo = dev_get_platdata(&pdev->dev);
 113        struct device_node *node = pdev->dev.of_node;
 114        struct uio_pdrv_genirq_platdata *priv;
 115        struct uio_mem *uiomem;
 116        int ret = -EINVAL;
 117        int i;
 118
 119        if (node) {
 120                const char *name;
 121
 122                /* alloc uioinfo for one device */
 123                uioinfo = devm_kzalloc(&pdev->dev, sizeof(*uioinfo),
 124                                       GFP_KERNEL);
 125                if (!uioinfo) {
 126                        dev_err(&pdev->dev, "unable to kmalloc\n");
 127                        return -ENOMEM;
 128                }
 129
 130                if (!of_property_read_string(node, "linux,uio-name", &name))
 131                        uioinfo->name = devm_kstrdup(&pdev->dev, name, GFP_KERNEL);
 132                else
 133                        uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
 134                                                       "%pOFn", node);
 135
 136                uioinfo->version = "devicetree";
 137                /* Multiple IRQs are not supported */
 138        }
 139
 140        if (!uioinfo || !uioinfo->name || !uioinfo->version) {
 141                dev_err(&pdev->dev, "missing platform_data\n");
 142                return ret;
 143        }
 144
 145        if (uioinfo->handler || uioinfo->irqcontrol ||
 146            uioinfo->irq_flags & IRQF_SHARED) {
 147                dev_err(&pdev->dev, "interrupt configuration error\n");
 148                return ret;
 149        }
 150
 151        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 152        if (!priv) {
 153                dev_err(&pdev->dev, "unable to kmalloc\n");
 154                return -ENOMEM;
 155        }
 156
 157        priv->uioinfo = uioinfo;
 158        spin_lock_init(&priv->lock);
 159        priv->flags = 0; /* interrupt is enabled to begin with */
 160        priv->pdev = pdev;
 161
 162        if (!uioinfo->irq) {
 163                ret = platform_get_irq_optional(pdev, 0);
 164                uioinfo->irq = ret;
 165                if (ret == -ENXIO)
 166                        uioinfo->irq = UIO_IRQ_NONE;
 167                else if (ret == -EPROBE_DEFER)
 168                        return ret;
 169                else if (ret < 0) {
 170                        dev_err(&pdev->dev, "failed to get IRQ\n");
 171                        return ret;
 172                }
 173        }
 174
 175        if (uioinfo->irq) {
 176                struct irq_data *irq_data = irq_get_irq_data(uioinfo->irq);
 177
 178                /*
 179                 * If a level interrupt, dont do lazy disable. Otherwise the
 180                 * irq will fire again since clearing of the actual cause, on
 181                 * device level, is done in userspace
 182                 * irqd_is_level_type() isn't used since isn't valid until
 183                 * irq is configured.
 184                 */
 185                if (irq_data &&
 186                    irqd_get_trigger_type(irq_data) & IRQ_TYPE_LEVEL_MASK) {
 187                        dev_dbg(&pdev->dev, "disable lazy unmask\n");
 188                        irq_set_status_flags(uioinfo->irq, IRQ_DISABLE_UNLAZY);
 189                }
 190        }
 191
 192        uiomem = &uioinfo->mem[0];
 193
 194        for (i = 0; i < pdev->num_resources; ++i) {
 195                struct resource *r = &pdev->resource[i];
 196
 197                if (r->flags != IORESOURCE_MEM)
 198                        continue;
 199
 200                if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
 201                        dev_warn(&pdev->dev, "device has more than "
 202                                        __stringify(MAX_UIO_MAPS)
 203                                        " I/O memory resources.\n");
 204                        break;
 205                }
 206
 207                uiomem->memtype = UIO_MEM_PHYS;
 208                uiomem->addr = r->start & PAGE_MASK;
 209                uiomem->offs = r->start & ~PAGE_MASK;
 210                uiomem->size = (uiomem->offs + resource_size(r)
 211                                + PAGE_SIZE - 1) & PAGE_MASK;
 212                uiomem->name = r->name;
 213                ++uiomem;
 214        }
 215
 216        while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
 217                uiomem->size = 0;
 218                ++uiomem;
 219        }
 220
 221        /* This driver requires no hardware specific kernel code to handle
 222         * interrupts. Instead, the interrupt handler simply disables the
 223         * interrupt in the interrupt controller. User space is responsible
 224         * for performing hardware specific acknowledge and re-enabling of
 225         * the interrupt in the interrupt controller.
 226         *
 227         * Interrupt sharing is not supported.
 228         */
 229
 230        uioinfo->handler = uio_pdrv_genirq_handler;
 231        uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol;
 232        uioinfo->open = uio_pdrv_genirq_open;
 233        uioinfo->release = uio_pdrv_genirq_release;
 234        uioinfo->priv = priv;
 235
 236        /* Enable Runtime PM for this device:
 237         * The device starts in suspended state to allow the hardware to be
 238         * turned off by default. The Runtime PM bus code should power on the
 239         * hardware and enable clocks at open().
 240         */
 241        pm_runtime_enable(&pdev->dev);
 242
 243        ret = devm_add_action_or_reset(&pdev->dev, uio_pdrv_genirq_cleanup,
 244                                       &pdev->dev);
 245        if (ret)
 246                return ret;
 247
 248        ret = devm_uio_register_device(&pdev->dev, priv->uioinfo);
 249        if (ret)
 250                dev_err(&pdev->dev, "unable to register uio device\n");
 251
 252        return ret;
 253}
 254
 255static int uio_pdrv_genirq_runtime_nop(struct device *dev)
 256{
 257        /* Runtime PM callback shared between ->runtime_suspend()
 258         * and ->runtime_resume(). Simply returns success.
 259         *
 260         * In this driver pm_runtime_get_sync() and pm_runtime_put_sync()
 261         * are used at open() and release() time. This allows the
 262         * Runtime PM code to turn off power to the device while the
 263         * device is unused, ie before open() and after release().
 264         *
 265         * This Runtime PM callback does not need to save or restore
 266         * any registers since user space is responsbile for hardware
 267         * register reinitialization after open().
 268         */
 269        return 0;
 270}
 271
 272static const struct dev_pm_ops uio_pdrv_genirq_dev_pm_ops = {
 273        .runtime_suspend = uio_pdrv_genirq_runtime_nop,
 274        .runtime_resume = uio_pdrv_genirq_runtime_nop,
 275};
 276
 277#ifdef CONFIG_OF
 278static struct of_device_id uio_of_genirq_match[] = {
 279        { /* This is filled with module_parm */ },
 280        { /* Sentinel */ },
 281};
 282MODULE_DEVICE_TABLE(of, uio_of_genirq_match);
 283module_param_string(of_id, uio_of_genirq_match[0].compatible, 128, 0);
 284MODULE_PARM_DESC(of_id, "Openfirmware id of the device to be handled by uio");
 285#endif
 286
 287static struct platform_driver uio_pdrv_genirq = {
 288        .probe = uio_pdrv_genirq_probe,
 289        .driver = {
 290                .name = DRIVER_NAME,
 291                .pm = &uio_pdrv_genirq_dev_pm_ops,
 292                .of_match_table = of_match_ptr(uio_of_genirq_match),
 293        },
 294};
 295
 296module_platform_driver(uio_pdrv_genirq);
 297
 298MODULE_AUTHOR("Magnus Damm");
 299MODULE_DESCRIPTION("Userspace I/O platform driver with generic IRQ handling");
 300MODULE_LICENSE("GPL v2");
 301MODULE_ALIAS("platform:" DRIVER_NAME);
 302