hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/uio/uio_dmem_genirq.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * drivers/uio/uio_dmem_genirq.c
34 *
....@@ -6,10 +7,6 @@
67 * Copyright (C) 2012 Damian Hobson-Garcia
78 *
89 * Based on uio_pdrv_genirq.c by Magnus Damm
9
- *
10
- * This program is free software; you can redistribute it and/or modify it
11
- * under the terms of the GNU General Public License version 2 as published by
12
- * the Free Software Foundation.
1310 */
1411
1512 #include <linux/platform_device.h>
....@@ -23,6 +20,7 @@
2320 #include <linux/pm_runtime.h>
2421 #include <linux/dma-mapping.h>
2522 #include <linux/slab.h>
23
+#include <linux/irq.h>
2624
2725 #include <linux/of.h>
2826 #include <linux/of_platform.h>
....@@ -47,7 +45,6 @@
4745 {
4846 struct uio_dmem_genirq_platdata *priv = info->priv;
4947 struct uio_mem *uiomem;
50
- int ret = 0;
5148 int dmem_region = priv->dmem_region_start;
5249
5350 uiomem = &priv->uioinfo->mem[priv->dmem_region_start];
....@@ -71,7 +68,7 @@
7168 mutex_unlock(&priv->alloc_lock);
7269 /* Wait until the Runtime PM code has woken up the device */
7370 pm_runtime_get_sync(&priv->pdev->dev);
74
- return ret;
71
+ return 0;
7572 }
7673
7774 static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
....@@ -113,8 +110,10 @@
113110 * remember the state so we can allow user space to enable it later.
114111 */
115112
113
+ spin_lock(&priv->lock);
116114 if (!test_and_set_bit(0, &priv->flags))
117115 disable_irq_nosync(irq);
116
+ spin_unlock(&priv->lock);
118117
119118 return IRQ_HANDLED;
120119 }
....@@ -128,20 +127,19 @@
128127 * in the interrupt controller, but keep track of the
129128 * state to prevent per-irq depth damage.
130129 *
131
- * Serialize this operation to support multiple tasks.
130
+ * Serialize this operation to support multiple tasks and concurrency
131
+ * with irq handler on SMP systems.
132132 */
133133
134134 spin_lock_irqsave(&priv->lock, flags);
135135 if (irq_on) {
136136 if (test_and_clear_bit(0, &priv->flags))
137137 enable_irq(dev_info->irq);
138
- spin_unlock_irqrestore(&priv->lock, flags);
139138 } else {
140
- if (!test_and_set_bit(0, &priv->flags)) {
141
- spin_unlock_irqrestore(&priv->lock, flags);
142
- disable_irq(dev_info->irq);
143
- }
139
+ if (!test_and_set_bit(0, &priv->flags))
140
+ disable_irq_nosync(dev_info->irq);
144141 }
142
+ spin_unlock_irqrestore(&priv->lock, flags);
145143
146144 return 0;
147145 }
....@@ -156,8 +154,6 @@
156154 int i;
157155
158156 if (pdev->dev.of_node) {
159
- int irq;
160
-
161157 /* alloc uioinfo for one device */
162158 uioinfo = kzalloc(sizeof(*uioinfo), GFP_KERNEL);
163159 if (!uioinfo) {
....@@ -165,15 +161,9 @@
165161 dev_err(&pdev->dev, "unable to kmalloc\n");
166162 goto bad2;
167163 }
168
- uioinfo->name = pdev->dev.of_node->name;
164
+ uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn",
165
+ pdev->dev.of_node);
169166 uioinfo->version = "devicetree";
170
-
171
- /* Multiple IRQs are not supported */
172
- irq = platform_get_irq(pdev, 0);
173
- if (irq == -ENXIO)
174
- uioinfo->irq = UIO_IRQ_NONE;
175
- else
176
- uioinfo->irq = irq;
177167 }
178168
179169 if (!uioinfo || !uioinfo->name || !uioinfo->version) {
....@@ -203,13 +193,32 @@
203193 mutex_init(&priv->alloc_lock);
204194
205195 if (!uioinfo->irq) {
196
+ /* Multiple IRQs are not supported */
206197 ret = platform_get_irq(pdev, 0);
207
- if (ret < 0) {
208
- dev_err(&pdev->dev, "failed to get IRQ\n");
198
+ if (ret == -ENXIO && pdev->dev.of_node)
199
+ ret = UIO_IRQ_NONE;
200
+ else if (ret < 0)
209201 goto bad1;
210
- }
211202 uioinfo->irq = ret;
212203 }
204
+
205
+ if (uioinfo->irq) {
206
+ struct irq_data *irq_data = irq_get_irq_data(uioinfo->irq);
207
+
208
+ /*
209
+ * If a level interrupt, dont do lazy disable. Otherwise the
210
+ * irq will fire again since clearing of the actual cause, on
211
+ * device level, is done in userspace
212
+ * irqd_is_level_type() isn't used since isn't valid until
213
+ * irq is configured.
214
+ */
215
+ if (irq_data &&
216
+ irqd_get_trigger_type(irq_data) & IRQ_TYPE_LEVEL_MASK) {
217
+ dev_dbg(&pdev->dev, "disable lazy unmask\n");
218
+ irq_set_status_flags(uioinfo->irq, IRQ_DISABLE_UNLAZY);
219
+ }
220
+ }
221
+
213222 uiomem = &uioinfo->mem[0];
214223
215224 for (i = 0; i < pdev->num_resources; ++i) {