Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1445331 > unrolled thread
| Started by | Anup Patel <anup.patel@broadcom.com> |
|---|---|
| First post | 2016-07-18 11:20 +0200 |
| Last post | 2016-07-18 11:20 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v2 0/8] Cache-coherent DMA access using UIO Anup Patel <anup.patel@broadcom.com> - 2016-07-18 11:20 +0200
[PATCH v2 7/8] uio: bind uio_dmem_genirq via OF Anup Patel <anup.patel@broadcom.com> - 2016-07-18 11:20 +0200
| From | Anup Patel <anup.patel@broadcom.com> |
|---|---|
| Date | 2016-07-18 11:20 +0200 |
| Subject | [PATCH v2 0/8] Cache-coherent DMA access using UIO |
| Message-ID | <rWcSt-4kE-3@gated-at.bofh.it> |
The goal of this patchset is to improve UIO framework and UIO dmem
driver to allow cache-coherent DMA accesses from user-space.
This patchset is based on two previous patchsets:
1) [PATCH v5 0/6] UIO driver for APM X-Gene QMTM
(Refer, http://www.spinics.net/lists/devicetree/msg58244.html)
2) [PATCH 0/4] Fix and extend uio_dmem_genirq
(Refer, https://lkml.org/lkml/2016/5/17/141)
We have adopted only patch0-3 of patchset1 which was abandoned
long time back. We have taken care of last few unaddressed comments
on these patches.
The patchset2 is quite recent has been adopted entirely. We have
taken care review comments on these patches too.
This patchset is based on v4.7-rc7 tag and it is available in uio-v2
branch of https://github.com/Broadcom/arm64-linux.git
Changes since v1:
- Make patch5 as first patch1 and mark it for linux-stable
- Get UIO dmem dynamic region details as module parameter instead
of getting it from DT node
Ankit Jindal (3):
uio: code style cleanup
uio: Add new UIO_MEM_PHYS_CACHE type for mem regions
Documentation: Update documentation for UIO_MEM_PHYS_CACHE and
UIO_MEM_DEVICE
Anup Patel (2):
uio: Add new UIO_MEM_DEVICE type for mem regions
uio: Use new memtypes in uio_dmem_genirq
Jan Viktorin (3):
uio: fix dmem_region_start computation
uio: UIO_IRQ_NONE is a valid option for uioinfo->irq
uio: bind uio_dmem_genirq via OF
Documentation/DocBook/uio-howto.tmpl | 6 +-
drivers/uio/uio.c | 32 ++++--
drivers/uio/uio_dmem_genirq.c | 190 +++++++++++++++++++++++++++--------
include/linux/uio_driver.h | 10 +-
4 files changed, 182 insertions(+), 56 deletions(-)
--
1.9.1
[toc] | [next] | [standalone]
| From | Anup Patel <anup.patel@broadcom.com> |
|---|---|
| Date | 2016-07-18 11:20 +0200 |
| Subject | [PATCH v2 7/8] uio: bind uio_dmem_genirq via OF |
| Message-ID | <rWcSu-4kE-25@gated-at.bofh.it> |
| In reply to | #1445331 |
From: Jan Viktorin <viktorin@rehivetech.com>
The uio_dmem_genirq works in a similar ways as uio_pdrv_genirq now.
It accepts the of_id module parameter to specify UIO compatible
string as module parameter. There are few other module parameters
to specify number bits in DMA mask and sizes dynamic regions.
Following are the newly added module parameters:
1) of_id: The UIO compatible string to be used for DT probing
2) dmem_dma_bits: This is the number of DMA mask bits for UIO device.
3) dmem_sizes: This is a formatted string specifying sizes of dynamic
required by some of the UIO devices.
Below are few examples of formatted string for dmem_sizes:
a) UIO dmem device with 3 dynamic regions:
uio_dmem_genirq.dmem_sizes=abc:4K,16K,4M
b) Two UIO dmem devices with different number of dynamic regions:
uio_dmem_genirq.dmem_sizes=abc:4K,16K,4M;xyz:8K
Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
Signed-off-by: Anup Patel <anup.patel@broadcom.com>
---
drivers/uio/uio_dmem_genirq.c | 162 +++++++++++++++++++++++++++++++++++-------
1 file changed, 135 insertions(+), 27 deletions(-)
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index a4d6d81..1db2559 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -12,6 +12,27 @@
* the Free Software Foundation.
*/
+/*
+ * For DeviceTree based platform devices, the compatible string, the DMA mask
+ * bits and sizes of dynamic regions are derived from kernel command-line.
+ *
+ * The format for specifying dynamic region sizes in kernel command line
+ * is as follows:
+ *
+ * uio_dmem_genirq.dmem_sizes := <uio_dmem_sizes_def>[;<uio_dmem_sizes_def>]
+ * <uio_dmem_sizes_def> := <uio_name>:<size>[,<size>]
+ * <uio_name> := name as shown in /sys/class/uio/uioX/name
+ * <size> := standard linux memsize
+ *
+ * Examples:
+ *
+ * 1) UIO dmem device with 3 dynamic regions:
+ * uio_dmem_genirq.dmem_sizes=abc:4K,16K,4M
+ *
+ * 2) Two UIO dmem devices with different number of dynamic regions:
+ * uio_dmem_genirq.dmem_sizes=abc:4K,16K,4M;xyz:8K
+ */
+
#include <linux/platform_device.h>
#include <linux/uio_driver.h>
#include <linux/spinlock.h>
@@ -144,46 +165,134 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
return 0;
}
+static unsigned int uio_dmem_dma_bits = 32;
+static char uio_dmem_sizes[256];
+
+static int uio_dmem_genirq_alloc_platdata(struct platform_device *pdev)
+{
+ int ret, name_len;
+ u32 regions = 0;
+ char *s, *name, *sz;
+ char *sizes_str = NULL, *sizes_endstr = NULL;
+ struct uio_dmem_genirq_pdata pdata;
+ unsigned long long sizes[MAX_UIO_MAPS];
+
+ memset(&pdata, 0, sizeof(pdata));
+
+ /* Set DMA coherent mask */
+ if (uio_dmem_dma_bits > 64)
+ uio_dmem_dma_bits = 64;
+ ret = dma_set_coherent_mask(&pdev->dev,
+ DMA_BIT_MASK(uio_dmem_dma_bits));
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to dma_set_coherent_mask\n");
+ return ret;
+ }
+
+ /* Find-out start and end of sizes list */
+ s = uio_dmem_sizes;
+ while (*s != '\0') {
+ name = s;
+ s = strchr(s, ':');
+ if (!s)
+ break;
+ name_len = s - name;
+ s++;
+ if (*s == '\0')
+ break;
+ sz = s;
+ s = strchr(s, ';');
+ if (!s)
+ s = &uio_dmem_sizes[strlen(uio_dmem_sizes)];
+ if (strncmp(name, pdev->dev.of_node->name, name_len) == 0) {
+ sizes_str = sz;
+ sizes_endstr = s;
+ break;
+ }
+ s++;
+ }
+
+ /* Parse dynamic regions from sizes list */
+ regions = 0;
+ sizes[0] = 0;
+ while (sizes_str && sizes_endstr &&
+ (sizes_str < sizes_endstr) &&
+ (*sizes_str != '\0') &&
+ (*sizes_str != ';') &&
+ (regions < MAX_UIO_MAPS)) {
+ if (*sizes_str == ',') {
+ sizes_str++;
+ continue;
+ }
+ sizes[regions] = memparse(sizes_str, &sizes_str);
+ if (sizes[regions])
+ regions++;
+ }
+
+ /* Populate platform data */
+ pdata.num_dynamic_regions = regions;
+ pdata.dynamic_region_sizes = devm_kzalloc(&pdev->dev,
+ sizeof(*pdata.dynamic_region_sizes) *
+ pdata.num_dynamic_regions, GFP_KERNEL);
+ if (!pdata.dynamic_region_sizes) {
+ dev_err(&pdev->dev, "Unable to alloc dynamic_region_sizes\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ while (regions--)
+ pdata.dynamic_region_sizes[regions] = sizes[regions];
+
+ pdata.uioinfo.name = pdev->dev.of_node->name;
+ pdata.uioinfo.version = "devicetree";
+
+ return platform_device_add_data(pdev, &pdata, sizeof(pdata));
+}
+
static int uio_dmem_genirq_probe(struct platform_device *pdev)
{
- struct uio_dmem_genirq_pdata *pdata = dev_get_platdata(&pdev->dev);
- struct uio_info *uioinfo = &pdata->uioinfo;
- struct uio_dmem_genirq_platdata *priv;
- struct uio_mem *uiomem;
- int ret = -EINVAL;
int i;
+ int ret = -EINVAL;
+ struct uio_mem *uiomem;
+ struct uio_info *uioinfo;
+ struct uio_dmem_genirq_pdata *pdata;
+ struct uio_dmem_genirq_platdata *priv;
if (pdev->dev.of_node) {
- /* alloc uioinfo for one device */
- uioinfo = kzalloc(sizeof(*uioinfo), GFP_KERNEL);
- if (!uioinfo) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "unable to kmalloc\n");
+ ret = uio_dmem_genirq_alloc_platdata(pdev);
+ if (ret)
goto bad2;
- }
- uioinfo->name = pdev->dev.of_node->name;
- uioinfo->version = "devicetree";
}
+ pdata = dev_get_platdata(&pdev->dev);
+ uioinfo = &pdata->uioinfo;
+
if (!uioinfo || !uioinfo->name || !uioinfo->version) {
dev_err(&pdev->dev, "missing platform_data\n");
- goto bad0;
+ goto bad2;
}
if (uioinfo->handler || uioinfo->irqcontrol ||
uioinfo->irq_flags & IRQF_SHARED) {
dev_err(&pdev->dev, "interrupt configuration error\n");
- goto bad0;
+ goto bad2;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
dev_err(&pdev->dev, "unable to kmalloc\n");
- goto bad0;
+ goto bad2;
}
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (!pdev->dev.of_node) {
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "unable to dma_set_coherent_mask\n");
+ goto bad1;
+ }
+ }
priv->uioinfo = uioinfo;
spin_lock_init(&priv->lock);
@@ -278,10 +387,6 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev)
return 0;
bad1:
kfree(priv);
- bad0:
- /* kfree uioinfo for OF */
- if (pdev->dev.of_node)
- kfree(uioinfo);
bad2:
return ret;
}
@@ -296,10 +401,6 @@ static int uio_dmem_genirq_remove(struct platform_device *pdev)
priv->uioinfo->handler = NULL;
priv->uioinfo->irqcontrol = NULL;
- /* kfree uioinfo for OF */
- if (pdev->dev.of_node)
- kfree(priv->uioinfo);
-
kfree(priv);
return 0;
}
@@ -327,10 +428,17 @@ static const struct dev_pm_ops uio_dmem_genirq_dev_pm_ops = {
};
#ifdef CONFIG_OF
-static const struct of_device_id uio_of_genirq_match[] = {
- { /* empty for now */ },
+static struct of_device_id uio_of_genirq_match[] = {
+ { /* This is filled with module_parm */ },
+ { /* end of list */ },
};
MODULE_DEVICE_TABLE(of, uio_of_genirq_match);
+module_param_string(of_id, uio_of_genirq_match[0].compatible, 128, 0);
+MODULE_PARM_DESC(of_id, "Openfirmware id of the device to be handled by uio");
+module_param_named(dmem_dma_bits, uio_dmem_dma_bits, uint, 0);
+MODULE_PARM_DESC(dmem_dma_bits, "Number of bits in DMA mask");
+module_param_string(dmem_sizes, uio_dmem_sizes, 256, 0);
+MODULE_PARM_DESC(dmem_sizes, "Comma separated dynamic region sizes");
#endif
static struct platform_driver uio_dmem_genirq = {
--
1.9.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web