[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 5/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver



Hi,

On 09/02/18 03:10, Sameer Goel wrote:
This driver follows an approach similar to smmu driver. The intent here
is to reuse as much Linux code as possible.
- Glue code has been introduced to bridge the API calls.
- Called Linux functions from the Xen IOMMU function calls.
- Xen modifications are preceded by /*Xen: comment */
- xen/linux_compat: Add a Linux compat header
   For porting files directly from Linux it is useful to have a function mapping
   definitions from Linux to Xen. This file adds common API functions and
   other defines that are needed for porting arm SMMU drivers.

I understand Roger asked for it, but that was not a really wise choice given the size of this patch. Anyway, let's keep it like that.


Signed-off-by: Sameer Goel <sameer.goel@xxxxxxxxxx>
---
  xen/arch/arm/p2m.c                    |   1 +
  xen/drivers/Kconfig                   |   2 +
  xen/drivers/passthrough/arm/Kconfig   |   8 +
  xen/drivers/passthrough/arm/Makefile  |   1 +
  xen/drivers/passthrough/arm/smmu-v3.c | 892 ++++++++++++++++++++++++++++++++--
  xen/include/xen/linux_compat.h        |  84 ++++

You need to CC the REST maintainers for that.

  6 files changed, 959 insertions(+), 29 deletions(-)
  create mode 100644 xen/drivers/passthrough/arm/Kconfig
  create mode 100644 xen/include/xen/linux_compat.h

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 65e8b9c6ea..fef7605fd6 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -1460,6 +1460,7 @@ err:
  static void __init setup_virt_paging_one(void *data)
  {
      unsigned long val = (unsigned long)data;
+    /* SMMUv3 S2 cfg vtcr reuses the following value */
      WRITE_SYSREG32(val, VTCR_EL2);
      isb();
  }
diff --git a/xen/drivers/Kconfig b/xen/drivers/Kconfig
index bc3a54f0ea..612655386d 100644
--- a/xen/drivers/Kconfig
+++ b/xen/drivers/Kconfig
@@ -12,4 +12,6 @@ source "drivers/pci/Kconfig"
source "drivers/video/Kconfig" +source "drivers/passthrough/arm/Kconfig"
+
  endmenu
diff --git a/xen/drivers/passthrough/arm/Kconfig 
b/xen/drivers/passthrough/arm/Kconfig
new file mode 100644
index 0000000000..cda899f608
--- /dev/null
+++ b/xen/drivers/passthrough/arm/Kconfig
@@ -0,0 +1,8 @@
+
+config ARM_SMMU_v3
+       bool "ARM SMMUv3 Support"
+       depends on ARM_64

Why the dependency on Arm64 here?

+       help
+        Support for implementations of the ARM System MMU architecture
+        version 3.
+
diff --git a/xen/drivers/passthrough/arm/Makefile 
b/xen/drivers/passthrough/arm/Makefile
index f4cd26e15d..e14732b55c 100644
--- a/xen/drivers/passthrough/arm/Makefile
+++ b/xen/drivers/passthrough/arm/Makefile
@@ -1,2 +1,3 @@
  obj-y += iommu.o
  obj-y += smmu.o
+obj-$(CONFIG_ARM_SMMU_v3) += smmu-v3.o
diff --git a/xen/drivers/passthrough/arm/smmu-v3.c 
b/xen/drivers/passthrough/arm/smmu-v3.c
index e67ba6c40f..f43485fe6e 100644
--- a/xen/drivers/passthrough/arm/smmu-v3.c
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
@@ -18,28 +18,414 @@
   * Author: Will Deacon <will.deacon@xxxxxxx>
   *
   * This driver is powered by bad coffee and bombay mix.
+ *
+ *
+ * Based on Linux drivers/iommu/arm-smmu-v3.c
+ * => commit 7aa8619a66aea52b145e04cbab4f8d6a4e5f3f3b
+ *
+ * Xen modifications:
+ * Sameer Goel <sameer.goel@xxxxxxxxxx>
+ * Copyright (C) 2017, The Linux Foundation, All rights reserved.
+ *
+ */

[...]

+static void *dmam_alloc_coherent(struct device *dev, size_t size,
+                          dma_addr_t *dma_handle, gfp_t gfp)
+{
+       void *vaddr;
+       unsigned long alignment = size;
+
+       /*
+        * _xzalloc requires that the (align & (align -1)) = 0. Most of the
+        * allocations in SMMU code should send the right value for size. In
+        * case this is not true print a warning and align to the size of a
+        * (void *)
+        */
+       if (size & (size - 1)) {
+               dev_warn(dev, "Fixing alignment for the DMA buffer\n");
+               alignment = sizeof(void *);
+       }
+
+       vaddr = _xzalloc(size, alignment);
+       if (!vaddr) {
+               dev_err(dev, "DMA allocation failed\n");
+               return NULL;
+       }
+
+       *dma_handle = virt_to_maddr(vaddr);
+
+       return vaddr;
+}
+
+

One newline should be enough.

+static void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
+                       dma_addr_t dma_handle)
+{
+       xfree(vaddr);
+}
+
+/* Xen: Stub out DMA domain related functions */
+#define iommu_get_dma_cookie(dom) 0
+#define iommu_put_dma_cookie(dom)
+
+/* Xen: Stub out module param related function */
+#define module_param_named(a, b, c, d)
+#define MODULE_PARM_DESC(a, b)
+
+#define dma_set_mask_and_coherent(d, b) 0
+
+#define of_dma_is_coherent(n) 0
+
+#define MODULE_DEVICE_TABLE(type, name)
+
+static void __iomem *devm_ioremap_resource(struct device *dev,
+                                          struct resource *res)
+{
+       void __iomem *ptr;
+
+       if (!res || res->type != IORESOURCE_MEM) {
+               dev_err(dev, "Invalid resource\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       ptr = ioremap_nocache(res->addr, res->size);
+       if (!ptr) {
+               dev_err(dev,
+                       "ioremap failed (addr 0x%"PRIx64" size 0x%"PRIx64")\n",
+                       res->addr, res->size);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return ptr;
+}
+
+/* Xen: Compatibility define for iommu_domain_geometry.*/
+struct iommu_domain_geometry {
+       dma_addr_t aperture_start; /* First address that can be mapped    */
+       dma_addr_t aperture_end;   /* Last address that can be mapped     */
+       bool force_aperture;       /* DMA only allowed in mappable range? */
+};
+
+

Same here.

[...]

+
+/*
+ * Xen: The pgtable_ops are used by the S1 translations, so return the dummy
+ * address.
+ */
+#define alloc_io_pgtable_ops(f, c, o) ((struct io_pgtable_ops *)0x0)

I am slightly confused, on a previous e-mail you suggested that 0x0 is not possible to use. The comment in arm_smmu-domain_finalise seems to confirm that. So why the 0x0 here?

+#define free_io_pgtable_ops(o)

Please use do { } while (0)

[...]

@@ -1232,7 +1634,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device 
*smmu, u64 *evt)
dev_info(smmu->dev, "unexpected PRI request received:\n");
        dev_info(smmu->dev,
-                "\tsid 0x%08x.0x%05x: [%u%s] %sprivileged %s%s%s access at iova 
0x%016llx\n",
+                "\tsid 0x%08x.0x%05x: [%u%s] %sprivileged %s%s%s access at iova %#" 
PRIx64 "\n",
                 sid, ssid, grpid, last ? "L" : "",
                 evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
                 evt[0] & PRIQ_0_PERM_READ ? "R" : "",
@@ -1346,6 +1748,8 @@ static irqreturn_t arm_smmu_combined_irq_handler(int irq, 
void *dev)
  {
        arm_smmu_gerror_handler(irq, dev);
        arm_smmu_cmdq_sync_handler(irq, dev);
+       /*Xen: No threaded irq. So call the required function from here */

NIT: /* Xen: ... */

+       arm_smmu_combined_irq_thread(irq, dev);
        return IRQ_WAKE_THREAD;
  }

[...]

@@ -1783,7 +2239,14 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device 
*smmu, u32 sid)
        return sid < limit;
  }
+/* Xen: Unused */
+#if 0
  static struct iommu_ops arm_smmu_ops;
+#endif
+
+/* Xen: Redefine arm_smmu_ops to what fwspec should evaluate */
+static const struct iommu_ops arm_smmu_iommu_ops;
+#define arm_smmu_ops arm_smmu_iommu_ops

Hmmmmm. Why is that necessary? arm_smmu_iommu_ops is added in this patch. So can't you just name the structure arm_smmu_ops?

Furthermore, I would be ok to leave to remove the const as Linux does not do it.

static int arm_smmu_add_device(struct device *dev)
  {
@@ -1791,8 +2254,11 @@ static int arm_smmu_add_device(struct device *dev)
        struct arm_smmu_device *smmu;
        struct arm_smmu_master_data *master;
        struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+#if 0 /*Xen: iommu_group is not needed */
        struct iommu_group *group;
+#endif
+ /* Xen: fwspec->ops are not needed */

You don't change this code. So why this comment?

        if (!fwspec || fwspec->ops != &arm_smmu_ops)
                return -ENODEV;
        /*
@@ -1830,6 +2296,11 @@ static int arm_smmu_add_device(struct device *dev)
                }
        }
+/*
+ * Xen: Do not need an iommu group as the stream data is carried by the SMMU

NIT: "We don't need...".

+ * master device object

NIT: Missing full stop.

+ */
+#if 0
        group = iommu_group_get_for_dev(dev);
        if (!IS_ERR(group)) {
                iommu_group_put(group);

[...]

@@ -2316,9 +2800,13 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device 
*smmu)
                 * Cavium ThunderX2 implementation doesn't not support unique
                 * irq lines. Use single irq line for all the SMMUv3 interrupts.
                 */
-               ret = devm_request_threaded_irq(smmu->dev, irq,
+               /*
+                * Xen: Does not support threaded irqs, so serialise the setup.
+                * This is the same for pris and event interrupt lines on other
+                * systems
+                */
+               ret = devm_request_irq(smmu->dev, irq,
                                        arm_smmu_combined_irq_handler,
-                                       arm_smmu_combined_irq_thread,
                                        IRQF_ONESHOT,
                                        "arm-smmu-v3-combined-irq", smmu);

On "RFC v4", I asked a question which was left unanswered. Here the conversation:

Me: Above you did implemented a dummy implementation of
    devm_request_threaded_irq(...). So why did you replace the code here?

You: The replacement worked well for other functions, where the handler was not defined. So, the wrapper function calls devm_request_irq with the argument passed in as thread. In this case really the handler hits first and it calls the thread in response. I can modify the code to make this fit into the api but in that case I will need to swap around the functions so number of line changes will stay the same. Tell me your preference.

Me: I don't understand what you mean here. Would it be possible to give a concrete example?

                if (ret < 0)

[...]

@@ -2703,7 +3200,7 @@ static inline int arm_smmu_device_acpi_probe(struct 
platform_device *pdev,
  static int arm_smmu_device_dt_probe(struct platform_device *pdev,
                                    struct arm_smmu_device *smmu)
  {
-       struct device *dev = &pdev->dev;
+       struct device *dev = pdev;
        u32 cells;
        int ret = -EINVAL;
@@ -2716,6 +3213,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev, parse_driver_options(smmu); + /* Xen: of_dma_is_coherent is a stub till dt support is introduced */
        if (of_dma_is_coherent(dev->of_node))

On RFC v4, I requested to move the message on top of of_dma_is_coherent stub and add a WARN/WARN_ON(). Please address it.

                smmu->features |= ARM_SMMU_FEAT_COHERENCY;

[...]

@@ -2844,9 +3351,20 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
                if (ret)
                        return ret;
        }
+#endif
+       /*
+        * Xen: Keep a list of all probed devices. This will be used to query
+        * the smmu devices based on the fwnode.
+        */
+       INIT_LIST_HEAD(&smmu->devices);
+       spin_lock(&arm_smmu_devices_lock);
+       list_add(&smmu->devices, &arm_smmu_devices);
+       spin_unlock(&arm_smmu_devices_lock);
        return 0;
  }
+/* Xen: Unused function */
+#if 0
  static int arm_smmu_device_remove(struct platform_device *pdev)
  {
        struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
@@ -2860,6 +3378,8 @@ static void arm_smmu_device_shutdown(struct 
platform_device *pdev)
  {
        arm_smmu_device_remove(pdev);
  }
+#endif
+

Newline not necessary.

   >   static const struct of_device_id arm_smmu_of_match[] = {
        { .compatible = "arm,smmu-v3", },

[...]

diff --git a/xen/include/xen/linux_compat.h b/xen/include/xen/linux_compat.h
new file mode 100644
index 0000000000..8037be0a3e
--- /dev/null
+++ b/xen/include/xen/linux_compat.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * include/xen/linux_compat.h
+ *
+ * Compatibility defines for porting code from Linux to Xen
+ *
+ * Copyright (c) 2017 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __XEN_LINUX_COMPAT_H__
+#define __XEN_LINUX_COMPAT_H__
+
+#include <asm/types.h>
+
+typedef paddr_t phys_addr_t;
+typedef paddr_t dma_addr_t;
+
+typedef unsigned int gfp_t;
+#define GFP_KERNEL 0
+#define __GFP_ZERO 0x01U

No need to the hexa here. 1U is much clearer.

+
+/* Helpers for IRQ functions */
+#define free_irq release_irq
+
+enum irqreturn {
+    IRQ_NONE,
+    IRQ_HANDLED,
+    IRQ_WAKE_THREAD,
+};
+
+typedef enum irqreturn irqreturn_t;
+
+/* Device logger functions */
+#define dev_dbg(dev, fmt, ...) printk(XENLOG_DEBUG fmt, ## __VA_ARGS__)
+#define dev_notice(dev, fmt, ...) printk(XENLOG_INFO fmt, ## __VA_ARGS__)
+#define dev_warn(dev, fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
+#define dev_err(dev, fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
+#define dev_info(dev, fmt, ...) printk(XENLOG_INFO fmt, ## __VA_ARGS__)
+
+#define dev_err_ratelimited(dev, fmt, ...)                  \
+     printk(XENLOG_ERR fmt, ## __VA_ARGS__)
+
+#define dev_name(dev) dt_node_full_name(dev_to_dt(dev))
+
+/* Alias to Xen allocation helpers */
+#define kfree xfree
+#define kmalloc(size, flags) ({\
+       void *__ret_alloc = NULL; \
+       if (flags & __GFP_ZERO) \
+               __ret_alloc = _xzalloc(size, sizeof(void *)); \

That's Xen code, so please avoid using hard tabs.

+       else \
+               __ret_alloc = _xmalloc(size, sizeof(void *)); \
+       __ret_alloc; \
+})

Could we make at least kmalloc and kmalloc_array static inline? This will add safety and make easier to read (the \ are not indented at all).

+#define kzalloc(size, flags)        _xzalloc(size, sizeof(void *))
+#define devm_kzalloc(dev, size, flags)  _xzalloc(size, sizeof(void *))
+#define kmalloc_array(size, n, flags) ({\
+       void *__ret_alloc = NULL; \
+       if (flags & __GFP_ZERO) \
+               __ret_alloc = _xzalloc_array(size, sizeof(void *), n); \
+       else \
+               __ret_alloc = _xmalloc_array(size, sizeof(void *), n); \
+       __ret_alloc; \
+})
+
+/* Alias to Xen time functions */
+#define ktime_t s_time_t
+#define ktime_get()             (NOW())
+#define ktime_add_us(t,i)       (t + MICROSECS(i))
+#define ktime_compare(t,i)      (t > (i))
+
+#endif /* __XEN_LINUX_COMPAT_H__ */


Cheers,

--
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.