All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 0/7] SMMUv3 driver and the supporting framework
@ 2017-09-21  0:37 Sameer Goel
  2017-09-21  0:37 ` [RFC v2 1/7] passthrough/arm: Modify SMMU driver to use generic device definition Sameer Goel
                   ` (7 more replies)
  0 siblings, 8 replies; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

This change incoporates most of the review comments from [1] and adds the
proposed SMMUv3 driver.

List of changes:
- Introduce the iommu_fwspec implementation - No change from the last RFC
- IORT port from linux. The differences are as under:
	* Modified the code for creating the SMMU devices. This code also
	  initializes the discoverd SMMU devices.
	* MSI code is left as is, but this code is untested.
	* IORT node data parsing is delegated to the driver. Looking for comments
      on enabling the code in IORT driver. This will need a standard resource
      object. (Direct port from Linux or a new define for Xen?)
    * Assumptions on PCI IORT SMMU interaction. PCI assign device will call
      iort_iommu_configure to setup the streamids.Then it will call SMMU
      assign device with the right struct device argument.
- SMMUv3 port from Linux. The list of changes are as under:
	* The Xen iommu_ops list is at parity with SMMUv2.
	* There is generally no need for an IOMMU group, but have kept a dummy
	  define for now.
	* Have commented out the S1 translation code.
	* MSI code is commented out.
	* Page table ops are commented out as the driver shares the page tables
	  with the cpu.
	* The list of SMMU devices is maintained from the driver code.

Open questions:
- IORT regeneration for DOM0. I was hoping to get some update on [2].
- We also need a notification framework to get the Named node information from DSDT.
- Should we port over code for non-hsared page tables from the kernel or leverage [3].


[1] "[RFC 0/6] IORT support and introduce fwspec"
[2] "[Xen-devel] [RFC] [PATCH] arm-acpi: Hide SMMU from IORT for hardware domain"
[3] "Non-shared" IOMMU support on ARM"

Sameer Goel (7):
  passthrough/arm: Modify SMMU driver to use generic device definition
  arm64: Add definitions for fwnode_handle
  xen/passthrough/arm: Introduce iommu_fwspec
  ACPI: arm: Support for IORT
  acpi:arm64: Add support for parsing IORT table
  Add verbatim copy of arm-smmu-v3.c from Linux
  xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver

 xen/arch/arm/setup.c                  |    3 +
 xen/drivers/acpi/Makefile             |    1 +
 xen/drivers/acpi/arm/Makefile         |    1 +
 xen/drivers/acpi/arm/iort.c           |  986 ++++++++++
 xen/drivers/passthrough/arm/Makefile  |    1 +
 xen/drivers/passthrough/arm/iommu.c   |   66 +
 xen/drivers/passthrough/arm/smmu-v3.c | 3412 +++++++++++++++++++++++++++++++++
 xen/drivers/passthrough/arm/smmu.c    |   13 +-
 xen/include/acpi/acpi_iort.h          |   61 +
 xen/include/asm-arm/device.h          |    5 +
 xen/include/xen/acpi.h                |   21 +
 xen/include/xen/fwnode.h              |   33 +
 xen/include/xen/iommu.h               |   29 +
 xen/include/xen/pci.h                 |    8 +
 14 files changed, 4634 insertions(+), 6 deletions(-)
 create mode 100644 xen/drivers/acpi/arm/Makefile
 create mode 100644 xen/drivers/acpi/arm/iort.c
 create mode 100644 xen/drivers/passthrough/arm/smmu-v3.c
 create mode 100644 xen/include/acpi/acpi_iort.h
 create mode 100644 xen/include/xen/fwnode.h

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC v2 1/7] passthrough/arm: Modify SMMU driver to use generic device definition
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
@ 2017-09-21  0:37 ` Sameer Goel
  2017-09-21  0:37 ` [RFC v2 2/7] arm64: Add definitions for fwnode_handle Sameer Goel
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

Modify the SMMU code to use generic device instead of dt_device_node for
functions that can be used for ACPI based systems too.

Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
---
 xen/drivers/passthrough/arm/smmu.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
index 74c09b0..362d578 100644
--- a/xen/drivers/passthrough/arm/smmu.c
+++ b/xen/drivers/passthrough/arm/smmu.c
@@ -76,7 +76,7 @@ struct resource
 
 #define resource_size(res) (res)->size;
 
-#define platform_device dt_device_node
+#define platform_device device
 
 #define IORESOURCE_MEM 0
 #define IORESOURCE_IRQ 1
@@ -97,12 +97,12 @@ static struct resource *platform_get_resource(struct platform_device *pdev,
 
 	switch (type) {
 	case IORESOURCE_MEM:
-		ret = dt_device_get_address(pdev, num, &res.addr, &res.size);
+		ret = dt_device_get_address(dev_to_dt(pdev), num, &res.addr, &res.size);
 
 		return ((ret) ? NULL : &res);
 
 	case IORESOURCE_IRQ:
-		ret = platform_get_irq(pdev, num);
+		ret = platform_get_irq(dev_to_dt(pdev), num);
 		if (ret < 0)
 			return NULL;
 
@@ -2285,7 +2285,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 	const struct of_device_id *of_id;
 	struct resource *res;
 	struct arm_smmu_device *smmu;
-	struct device *dev = &pdev->dev;
+	struct device *dev = pdev;
 	struct rb_node *node;
 	struct of_phandle_args masterspec;
 	int num_irqs, i, err;
@@ -2338,7 +2338,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
 	}
 
 	for (i = 0; i < num_irqs; ++i) {
-		int irq = platform_get_irq(pdev, i);
+		int irq = platform_get_irq(dev_to_dt(pdev), i);
 
 		if (irq < 0) {
 			dev_err(dev, "failed to get irq index %d\n", i);
@@ -2819,7 +2819,7 @@ static __init int arm_smmu_dt_init(struct dt_device_node *dev,
 	 */
 	dt_device_set_used_by(dev, DOMID_XEN);
 
-	rc = arm_smmu_device_dt_probe(dev);
+	rc = arm_smmu_device_dt_probe(dt_to_dev(dev));
 	if (rc)
 		return rc;
 
-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [RFC v2 2/7] arm64: Add definitions for fwnode_handle
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
  2017-09-21  0:37 ` [RFC v2 1/7] passthrough/arm: Modify SMMU driver to use generic device definition Sameer Goel
@ 2017-09-21  0:37 ` Sameer Goel
  2017-10-12 12:45   ` Julien Grall
  2017-09-21  0:37 ` [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec Sameer Goel
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

This will be used as a device property to match the DMA capable devices
with the associated SMMU. The header file is a port from linux. The code
was changed to remove the types that were not needed for Xen.

Linux ChangeId:ce793486e23e: driver core / ACPI: Represent ACPI
companions using fwnode_handle

Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
---
 xen/include/asm-arm/device.h |  2 ++
 xen/include/xen/fwnode.h     | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 xen/include/xen/fwnode.h

diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
index 6734ae8..78c38fe 100644
--- a/xen/include/asm-arm/device.h
+++ b/xen/include/asm-arm/device.h
@@ -2,6 +2,7 @@
 #define __ASM_ARM_DEVICE_H
 
 #include <xen/init.h>
+#include <xen/fwnode.h>
 
 enum device_type
 {
@@ -19,6 +20,7 @@ struct device
 #ifdef CONFIG_HAS_DEVICE_TREE
     struct dt_device_node *of_node; /* Used by drivers imported from Linux */
 #endif
+    struct fwnode_handle *fwnode; /*fw device node identifier */
     struct dev_archdata archdata;
 };
 
diff --git a/xen/include/xen/fwnode.h b/xen/include/xen/fwnode.h
new file mode 100644
index 0000000..0fed958
--- /dev/null
+++ b/xen/include/xen/fwnode.h
@@ -0,0 +1,33 @@
+/*
+ * fwnode.h - Firmware device node object handle type definition.
+ *
+ * Copyright (C) 2015, Intel Corporation
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Ported from Linux include/linux/fwnode.h
+ *  => commit ce793486e23e0162a732c605189c8028e0910e86
+ *
+ * No functional Xen modifications.
+ */
+
+#ifndef __XEN_FWNODE_H_
+#define __XEN_FWNODE_H_
+
+enum fwnode_type {
+	FWNODE_INVALID = 0,
+	FWNODE_OF,
+	FWNODE_ACPI,
+	FWNODE_ACPI_STATIC,
+	FWNODE_IRQCHIP
+};
+
+struct fwnode_handle {
+	enum fwnode_type type;
+	struct fwnode_handle *secondary;
+};
+
+#endif
-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
  2017-09-21  0:37 ` [RFC v2 1/7] passthrough/arm: Modify SMMU driver to use generic device definition Sameer Goel
  2017-09-21  0:37 ` [RFC v2 2/7] arm64: Add definitions for fwnode_handle Sameer Goel
@ 2017-09-21  0:37 ` Sameer Goel
  2017-10-12 13:05   ` Julien Grall
  2017-09-21  0:37 ` [RFC v2 4/7] ACPI: arm: Support for IORT Sameer Goel
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

Introduce a common structure to hold the fw (ACPI or DT) defined
configuration for SMMU hw. The current use case is for arm SMMUs. So,
making this architecture specific.

Based on Linux kernel commit 57f98d2f61e1: iommu: Introduce iommu_fwspec
Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
---
 xen/drivers/passthrough/arm/iommu.c | 66 +++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/device.h        |  1 +
 xen/include/xen/iommu.h             | 29 ++++++++++++++++
 3 files changed, 96 insertions(+)

diff --git a/xen/drivers/passthrough/arm/iommu.c b/xen/drivers/passthrough/arm/iommu.c
index 95b1abb..41c6497 100644
--- a/xen/drivers/passthrough/arm/iommu.c
+++ b/xen/drivers/passthrough/arm/iommu.c
@@ -73,3 +73,69 @@ int arch_iommu_populate_page_table(struct domain *d)
     /* The IOMMU shares the p2m with the CPU */
     return -ENOSYS;
 }
+
+const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
+{
+    return iommu_get_ops();
+}
+
+int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
+        const struct iommu_ops *ops)
+{
+    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+
+    if ( fwspec )
+        return ops == fwspec->ops ? 0 : -EINVAL;
+
+    fwspec = _xzalloc(sizeof(struct iommu_fwspec), sizeof(void *));
+    if ( !fwspec )
+        return -ENOMEM;
+
+    fwspec->iommu_fwnode = iommu_fwnode;
+    fwspec->ops = ops;
+    dev->iommu_fwspec = fwspec;
+
+    return 0;
+}
+
+void iommu_fwspec_free(struct device *dev)
+{
+    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+
+    if ( fwspec )
+    {
+        xfree(fwspec);
+        dev->iommu_fwspec = NULL;
+    }
+}
+
+int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
+{
+    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+    struct iommu_fwspec *fwspec_n = NULL;
+    size_t size, size_n;
+    int i;
+
+    if ( !fwspec )
+        return -EINVAL;
+
+    size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids]);
+    size_n = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
+    if ( size_n > size )
+    {
+        fwspec_n = _xzalloc(size_n, sizeof(void *));
+        if ( !fwspec_n )
+            return -ENOMEM;
+
+        memcpy(fwspec_n, fwspec, size);
+        xfree(fwspec);
+    }
+
+    for (i = 0; i < num_ids; i++)
+        fwspec_n->ids[fwspec_n->num_ids + i] = ids[i];
+
+    fwspec_n->num_ids += num_ids;
+    dev->iommu_fwspec = fwspec_n;
+
+    return 0;
+}
diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
index 78c38fe..5027c87 100644
--- a/xen/include/asm-arm/device.h
+++ b/xen/include/asm-arm/device.h
@@ -21,6 +21,7 @@ struct device
     struct dt_device_node *of_node; /* Used by drivers imported from Linux */
 #endif
     struct fwnode_handle *fwnode; /*fw device node identifier */
+    struct iommu_fwspec *iommu_fwspec;
     struct dev_archdata archdata;
 };
 
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 0dac4f3..34e8d68 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -208,4 +208,33 @@ DECLARE_PER_CPU(bool_t, iommu_dont_flush_iotlb);
 extern struct spinlock iommu_pt_cleanup_lock;
 extern struct page_list_head iommu_pt_cleanup_list;
 
+/**
+ * Following block was ported from Linux to help with the implementation of
+ * arm64 iommu devices. Hence the architecture specific compile
+ */
+
+#if defined(CONFIG_ARM)
+/**
+ * struct iommu_fwspec - per-device IOMMU instance data
+ * @ops: ops for this device's IOMMU
+ * @iommu_fwnode: firmware handle for this device's IOMMU
+ * @iommu_priv: IOMMU driver private data for this device
+ * @num_ids: number of associated device IDs
+ * @ids: IDs which this device may present to the IOMMU
+ */
+struct iommu_fwspec {
+    const struct iommu_ops *ops;
+    struct fwnode_handle   *iommu_fwnode;
+    void                   *iommu_priv;
+    unsigned int           num_ids;
+    u32                    ids[1];
+};
+
+int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
+		      const struct iommu_ops *ops);
+void iommu_fwspec_free(struct device *dev);
+int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode);
+
+#endif
 #endif /* _IOMMU_H_ */
-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [RFC v2 4/7] ACPI: arm: Support for IORT
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
                   ` (2 preceding siblings ...)
  2017-09-21  0:37 ` [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec Sameer Goel
@ 2017-09-21  0:37 ` Sameer Goel
  2017-09-21  0:37 ` [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table Sameer Goel
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

Verbatim files from Linux kernel.
iort.c: commit d89cf2e41826: ACPI/IORT: Fix the indentation in
iort_scan_node()
acpi_iort.h: commit 18b709beb503:ACPI/IORT: Make dma masks set-up IORT
specific

Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
---
 xen/drivers/acpi/arm/iort.c  | 961 +++++++++++++++++++++++++++++++++++++++++++
 xen/include/acpi/acpi_iort.h |  58 +++
 2 files changed, 1019 insertions(+)
 create mode 100644 xen/drivers/acpi/arm/iort.c
 create mode 100644 xen/include/acpi/acpi_iort.h

diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
new file mode 100644
index 0000000..2e368a6
--- /dev/null
+++ b/xen/drivers/acpi/arm/iort.c
@@ -0,0 +1,961 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * This file implements early detection/parsing of I/O mapping
+ * reported to OS through firmware via I/O Remapping Table (IORT)
+ * IORT document number: ARM DEN 0049A
+ */
+
+#define pr_fmt(fmt)	"ACPI: IORT: " fmt
+
+#include <linux/acpi_iort.h>
+#include <linux/iommu.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define IORT_TYPE_MASK(type)	(1 << (type))
+#define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
+#define IORT_IOMMU_TYPE		((1 << ACPI_IORT_NODE_SMMU) |	\
+				(1 << ACPI_IORT_NODE_SMMU_V3))
+
+struct iort_its_msi_chip {
+	struct list_head	list;
+	struct fwnode_handle	*fw_node;
+	u32			translation_id;
+};
+
+struct iort_fwnode {
+	struct list_head list;
+	struct acpi_iort_node *iort_node;
+	struct fwnode_handle *fwnode;
+};
+static LIST_HEAD(iort_fwnode_list);
+static DEFINE_SPINLOCK(iort_fwnode_lock);
+
+/**
+ * iort_set_fwnode() - Create iort_fwnode and use it to register
+ *		       iommu data in the iort_fwnode_list
+ *
+ * @node: IORT table node associated with the IOMMU
+ * @fwnode: fwnode associated with the IORT node
+ *
+ * Returns: 0 on success
+ *          <0 on failure
+ */
+static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
+				  struct fwnode_handle *fwnode)
+{
+	struct iort_fwnode *np;
+
+	np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);
+
+	if (WARN_ON(!np))
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&np->list);
+	np->iort_node = iort_node;
+	np->fwnode = fwnode;
+
+	spin_lock(&iort_fwnode_lock);
+	list_add_tail(&np->list, &iort_fwnode_list);
+	spin_unlock(&iort_fwnode_lock);
+
+	return 0;
+}
+
+/**
+ * iort_get_fwnode() - Retrieve fwnode associated with an IORT node
+ *
+ * @node: IORT table node to be looked-up
+ *
+ * Returns: fwnode_handle pointer on success, NULL on failure
+ */
+static inline
+struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
+{
+	struct iort_fwnode *curr;
+	struct fwnode_handle *fwnode = NULL;
+
+	spin_lock(&iort_fwnode_lock);
+	list_for_each_entry(curr, &iort_fwnode_list, list) {
+		if (curr->iort_node == node) {
+			fwnode = curr->fwnode;
+			break;
+		}
+	}
+	spin_unlock(&iort_fwnode_lock);
+
+	return fwnode;
+}
+
+/**
+ * iort_delete_fwnode() - Delete fwnode associated with an IORT node
+ *
+ * @node: IORT table node associated with fwnode to delete
+ */
+static inline void iort_delete_fwnode(struct acpi_iort_node *node)
+{
+	struct iort_fwnode *curr, *tmp;
+
+	spin_lock(&iort_fwnode_lock);
+	list_for_each_entry_safe(curr, tmp, &iort_fwnode_list, list) {
+		if (curr->iort_node == node) {
+			list_del(&curr->list);
+			kfree(curr);
+			break;
+		}
+	}
+	spin_unlock(&iort_fwnode_lock);
+}
+
+typedef acpi_status (*iort_find_node_callback)
+	(struct acpi_iort_node *node, void *context);
+
+/* Root pointer to the mapped IORT table */
+static struct acpi_table_header *iort_table;
+
+static LIST_HEAD(iort_msi_chip_list);
+static DEFINE_SPINLOCK(iort_msi_chip_lock);
+
+/**
+ * iort_register_domain_token() - register domain token and related ITS ID
+ * to the list from where we can get it back later on.
+ * @trans_id: ITS ID.
+ * @fw_node: Domain token.
+ *
+ * Returns: 0 on success, -ENOMEM if no memory when allocating list element
+ */
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+{
+	struct iort_its_msi_chip *its_msi_chip;
+
+	its_msi_chip = kzalloc(sizeof(*its_msi_chip), GFP_KERNEL);
+	if (!its_msi_chip)
+		return -ENOMEM;
+
+	its_msi_chip->fw_node = fw_node;
+	its_msi_chip->translation_id = trans_id;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_add(&its_msi_chip->list, &iort_msi_chip_list);
+	spin_unlock(&iort_msi_chip_lock);
+
+	return 0;
+}
+
+/**
+ * iort_deregister_domain_token() - Deregister domain token based on ITS ID
+ * @trans_id: ITS ID.
+ *
+ * Returns: none.
+ */
+void iort_deregister_domain_token(int trans_id)
+{
+	struct iort_its_msi_chip *its_msi_chip, *t;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_for_each_entry_safe(its_msi_chip, t, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == trans_id) {
+			list_del(&its_msi_chip->list);
+			kfree(its_msi_chip);
+			break;
+		}
+	}
+	spin_unlock(&iort_msi_chip_lock);
+}
+
+/**
+ * iort_find_domain_token() - Find domain token based on given ITS ID
+ * @trans_id: ITS ID.
+ *
+ * Returns: domain token when find on the list, NULL otherwise
+ */
+struct fwnode_handle *iort_find_domain_token(int trans_id)
+{
+	struct fwnode_handle *fw_node = NULL;
+	struct iort_its_msi_chip *its_msi_chip;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == trans_id) {
+			fw_node = its_msi_chip->fw_node;
+			break;
+		}
+	}
+	spin_unlock(&iort_msi_chip_lock);
+
+	return fw_node;
+}
+
+static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
+					     iort_find_node_callback callback,
+					     void *context)
+{
+	struct acpi_iort_node *iort_node, *iort_end;
+	struct acpi_table_iort *iort;
+	int i;
+
+	if (!iort_table)
+		return NULL;
+
+	/* Get the first IORT node */
+	iort = (struct acpi_table_iort *)iort_table;
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				iort_table->length);
+
+	for (i = 0; i < iort->node_count; i++) {
+		if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
+			       "IORT node pointer overflows, bad table!\n"))
+			return NULL;
+
+		if (iort_node->type == type &&
+		    ACPI_SUCCESS(callback(iort_node, context)))
+			return iort_node;
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+
+	return NULL;
+}
+
+static acpi_status
+iort_match_type_callback(struct acpi_iort_node *node, void *context)
+{
+	return AE_OK;
+}
+
+bool iort_node_match(u8 type)
+{
+	struct acpi_iort_node *node;
+
+	node = iort_scan_node(type, iort_match_type_callback, NULL);
+
+	return node != NULL;
+}
+
+static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
+					    void *context)
+{
+	struct device *dev = context;
+	acpi_status status;
+
+	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
+		struct acpi_iort_named_component *ncomp;
+
+		if (!adev) {
+			status = AE_NOT_FOUND;
+			goto out;
+		}
+
+		status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
+		if (ACPI_FAILURE(status)) {
+			dev_warn(dev, "Can't get device full path name\n");
+			goto out;
+		}
+
+		ncomp = (struct acpi_iort_named_component *)node->node_data;
+		status = !strcmp(ncomp->device_name, buf.pointer) ?
+							AE_OK : AE_NOT_FOUND;
+		acpi_os_free(buf.pointer);
+	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+		struct acpi_iort_root_complex *pci_rc;
+		struct pci_bus *bus;
+
+		bus = to_pci_bus(dev);
+		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
+
+		/*
+		 * It is assumed that PCI segment numbers maps one-to-one
+		 * with root complexes. Each segment number can represent only
+		 * one root complex.
+		 */
+		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
+							AE_OK : AE_NOT_FOUND;
+	} else {
+		status = AE_NOT_FOUND;
+	}
+out:
+	return status;
+}
+
+static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
+		       u32 *rid_out)
+{
+	/* Single mapping does not care for input id */
+	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+		if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+			*rid_out = map->output_base;
+			return 0;
+		}
+
+		pr_warn(FW_BUG "[map %p] SINGLE MAPPING flag not allowed for node type %d, skipping ID map\n",
+			map, type);
+		return -ENXIO;
+	}
+
+	if (rid_in < map->input_base ||
+	    (rid_in >= map->input_base + map->id_count))
+		return -ENXIO;
+
+	*rid_out = map->output_base + (rid_in - map->input_base);
+	return 0;
+}
+
+static
+struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
+					u32 *id_out, u8 type_mask,
+					int index)
+{
+	struct acpi_iort_node *parent;
+	struct acpi_iort_id_mapping *map;
+
+	if (!node->mapping_offset || !node->mapping_count ||
+				     index >= node->mapping_count)
+		return NULL;
+
+	map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+			   node->mapping_offset + index * sizeof(*map));
+
+	/* Firmware bug! */
+	if (!map->output_reference) {
+		pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+		       node, node->type);
+		return NULL;
+	}
+
+	parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+			       map->output_reference);
+
+	if (!(IORT_TYPE_MASK(parent->type) & type_mask))
+		return NULL;
+
+	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+			*id_out = map->output_base;
+			return parent;
+		}
+	}
+
+	return NULL;
+}
+
+static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
+						u32 rid_in, u32 *rid_out,
+						u8 type_mask)
+{
+	u32 rid = rid_in;
+
+	/* Parse the ID mapping tree to find specified node type */
+	while (node) {
+		struct acpi_iort_id_mapping *map;
+		int i;
+
+		if (IORT_TYPE_MASK(node->type) & type_mask) {
+			if (rid_out)
+				*rid_out = rid;
+			return node;
+		}
+
+		if (!node->mapping_offset || !node->mapping_count)
+			goto fail_map;
+
+		map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+				   node->mapping_offset);
+
+		/* Firmware bug! */
+		if (!map->output_reference) {
+			pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+			       node, node->type);
+			goto fail_map;
+		}
+
+		/* Do the RID translation */
+		for (i = 0; i < node->mapping_count; i++, map++) {
+			if (!iort_id_map(map, node->type, rid, &rid))
+				break;
+		}
+
+		if (i == node->mapping_count)
+			goto fail_map;
+
+		node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				    map->output_reference);
+	}
+
+fail_map:
+	/* Map input RID to output RID unchanged on mapping failure*/
+	if (rid_out)
+		*rid_out = rid_in;
+
+	return NULL;
+}
+
+static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
+{
+	struct pci_bus *pbus;
+
+	if (!dev_is_pci(dev))
+		return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+				      iort_match_node_callback, dev);
+
+	/* Find a PCI root bus */
+	pbus = to_pci_dev(dev)->bus;
+	while (!pci_is_root_bus(pbus))
+		pbus = pbus->parent;
+
+	return iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+			      iort_match_node_callback, &pbus->dev);
+}
+
+/**
+ * iort_msi_map_rid() - Map a MSI requester ID for a device
+ * @dev: The device for which the mapping is to be done.
+ * @req_id: The device requester ID.
+ *
+ * Returns: mapped MSI RID on success, input requester ID otherwise
+ */
+u32 iort_msi_map_rid(struct device *dev, u32 req_id)
+{
+	struct acpi_iort_node *node;
+	u32 dev_id;
+
+	node = iort_find_dev_node(dev);
+	if (!node)
+		return req_id;
+
+	iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE);
+	return dev_id;
+}
+
+/**
+ * iort_dev_find_its_id() - Find the ITS identifier for a device
+ * @dev: The device.
+ * @idx: Index of the ITS identifier list.
+ * @its_id: ITS identifier.
+ *
+ * Returns: 0 on success, appropriate error value otherwise
+ */
+static int iort_dev_find_its_id(struct device *dev, u32 req_id,
+				unsigned int idx, int *its_id)
+{
+	struct acpi_iort_its_group *its;
+	struct acpi_iort_node *node;
+
+	node = iort_find_dev_node(dev);
+	if (!node)
+		return -ENXIO;
+
+	node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE);
+	if (!node)
+		return -ENXIO;
+
+	/* Move to ITS specific data */
+	its = (struct acpi_iort_its_group *)node->node_data;
+	if (idx > its->its_count) {
+		dev_err(dev, "requested ITS ID index [%d] is greater than available [%d]\n",
+			idx, its->its_count);
+		return -ENXIO;
+	}
+
+	*its_id = its->identifiers[idx];
+	return 0;
+}
+
+/**
+ * iort_get_device_domain() - Find MSI domain related to a device
+ * @dev: The device.
+ * @req_id: Requester ID for the device.
+ *
+ * Returns: the MSI domain for this device, NULL otherwise
+ */
+struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
+{
+	struct fwnode_handle *handle;
+	int its_id;
+
+	if (iort_dev_find_its_id(dev, req_id, 0, &its_id))
+		return NULL;
+
+	handle = iort_find_domain_token(its_id);
+	if (!handle)
+		return NULL;
+
+	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
+}
+
+static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
+{
+	u32 *rid = data;
+
+	*rid = alias;
+	return 0;
+}
+
+static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
+			       struct fwnode_handle *fwnode,
+			       const struct iommu_ops *ops)
+{
+	int ret = iommu_fwspec_init(dev, fwnode, ops);
+
+	if (!ret)
+		ret = iommu_fwspec_add_ids(dev, &streamid, 1);
+
+	return ret;
+}
+
+static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
+					struct acpi_iort_node *node,
+					u32 streamid)
+{
+	const struct iommu_ops *ops = NULL;
+	int ret = -ENODEV;
+	struct fwnode_handle *iort_fwnode;
+
+	if (node) {
+		iort_fwnode = iort_get_fwnode(node);
+		if (!iort_fwnode)
+			return NULL;
+
+		ops = iommu_ops_from_fwnode(iort_fwnode);
+		if (!ops)
+			return NULL;
+
+		ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
+	}
+
+	return ret ? NULL : ops;
+}
+
+/**
+ * iort_set_dma_mask - Set-up dma mask for a device.
+ *
+ * @dev: device to configure
+ */
+void iort_set_dma_mask(struct device *dev)
+{
+	/*
+	 * Set default coherent_dma_mask to 32 bit.  Drivers are expected to
+	 * setup the correct supported mask.
+	 */
+	if (!dev->coherent_dma_mask)
+		dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	/*
+	 * Set it to coherent_dma_mask by default if the architecture
+	 * code has not set it.
+	 */
+	if (!dev->dma_mask)
+		dev->dma_mask = &dev->coherent_dma_mask;
+}
+
+/**
+ * iort_iommu_configure - Set-up IOMMU configuration for a device.
+ *
+ * @dev: device to configure
+ *
+ * Returns: iommu_ops pointer on configuration success
+ *          NULL on configuration failure
+ */
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{
+	struct acpi_iort_node *node, *parent;
+	const struct iommu_ops *ops = NULL;
+	u32 streamid = 0;
+
+	if (dev_is_pci(dev)) {
+		struct pci_bus *bus = to_pci_dev(dev)->bus;
+		u32 rid;
+
+		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
+				       &rid);
+
+		node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+				      iort_match_node_callback, &bus->dev);
+		if (!node)
+			return NULL;
+
+		parent = iort_node_map_rid(node, rid, &streamid,
+					   IORT_IOMMU_TYPE);
+
+		ops = iort_iommu_xlate(dev, parent, streamid);
+
+	} else {
+		int i = 0;
+
+		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+				      iort_match_node_callback, dev);
+		if (!node)
+			return NULL;
+
+		parent = iort_node_get_id(node, &streamid,
+					  IORT_IOMMU_TYPE, i++);
+
+		while (parent) {
+			ops = iort_iommu_xlate(dev, parent, streamid);
+
+			parent = iort_node_get_id(node, &streamid,
+						  IORT_IOMMU_TYPE, i++);
+		}
+	}
+
+	return ops;
+}
+
+static void __init acpi_iort_register_irq(int hwirq, const char *name,
+					  int trigger,
+					  struct resource *res)
+{
+	int irq = acpi_register_gsi(NULL, hwirq, trigger,
+				    ACPI_ACTIVE_HIGH);
+
+	if (irq <= 0) {
+		pr_err("could not register gsi hwirq %d name [%s]\n", hwirq,
+								      name);
+		return;
+	}
+
+	res->start = irq;
+	res->end = irq;
+	res->flags = IORESOURCE_IRQ;
+	res->name = name;
+}
+
+static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
+{
+	struct acpi_iort_smmu_v3 *smmu;
+	/* Always present mem resource */
+	int num_res = 1;
+
+	/* Retrieve SMMUv3 specific data */
+	smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+	if (smmu->event_gsiv)
+		num_res++;
+
+	if (smmu->pri_gsiv)
+		num_res++;
+
+	if (smmu->gerr_gsiv)
+		num_res++;
+
+	if (smmu->sync_gsiv)
+		num_res++;
+
+	return num_res;
+}
+
+static void __init arm_smmu_v3_init_resources(struct resource *res,
+					      struct acpi_iort_node *node)
+{
+	struct acpi_iort_smmu_v3 *smmu;
+	int num_res = 0;
+
+	/* Retrieve SMMUv3 specific data */
+	smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+	res[num_res].start = smmu->base_address;
+	res[num_res].end = smmu->base_address + SZ_128K - 1;
+	res[num_res].flags = IORESOURCE_MEM;
+
+	num_res++;
+
+	if (smmu->event_gsiv)
+		acpi_iort_register_irq(smmu->event_gsiv, "eventq",
+				       ACPI_EDGE_SENSITIVE,
+				       &res[num_res++]);
+
+	if (smmu->pri_gsiv)
+		acpi_iort_register_irq(smmu->pri_gsiv, "priq",
+				       ACPI_EDGE_SENSITIVE,
+				       &res[num_res++]);
+
+	if (smmu->gerr_gsiv)
+		acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
+				       ACPI_EDGE_SENSITIVE,
+				       &res[num_res++]);
+
+	if (smmu->sync_gsiv)
+		acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
+				       ACPI_EDGE_SENSITIVE,
+				       &res[num_res++]);
+}
+
+static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
+{
+	struct acpi_iort_smmu_v3 *smmu;
+
+	/* Retrieve SMMUv3 specific data */
+	smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+	return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
+}
+
+static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
+{
+	struct acpi_iort_smmu *smmu;
+
+	/* Retrieve SMMU specific data */
+	smmu = (struct acpi_iort_smmu *)node->node_data;
+
+	/*
+	 * Only consider the global fault interrupt and ignore the
+	 * configuration access interrupt.
+	 *
+	 * MMIO address and global fault interrupt resources are always
+	 * present so add them to the context interrupt count as a static
+	 * value.
+	 */
+	return smmu->context_interrupt_count + 2;
+}
+
+static void __init arm_smmu_init_resources(struct resource *res,
+					   struct acpi_iort_node *node)
+{
+	struct acpi_iort_smmu *smmu;
+	int i, hw_irq, trigger, num_res = 0;
+	u64 *ctx_irq, *glb_irq;
+
+	/* Retrieve SMMU specific data */
+	smmu = (struct acpi_iort_smmu *)node->node_data;
+
+	res[num_res].start = smmu->base_address;
+	res[num_res].end = smmu->base_address + smmu->span - 1;
+	res[num_res].flags = IORESOURCE_MEM;
+	num_res++;
+
+	glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+	/* Global IRQs */
+	hw_irq = IORT_IRQ_MASK(glb_irq[0]);
+	trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]);
+
+	acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+				     &res[num_res++]);
+
+	/* Context IRQs */
+	ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset);
+	for (i = 0; i < smmu->context_interrupt_count; i++) {
+		hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
+		trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);
+
+		acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger,
+				       &res[num_res++]);
+	}
+}
+
+static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node)
+{
+	struct acpi_iort_smmu *smmu;
+
+	/* Retrieve SMMU specific data */
+	smmu = (struct acpi_iort_smmu *)node->node_data;
+
+	return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK;
+}
+
+struct iort_iommu_config {
+	const char *name;
+	int (*iommu_init)(struct acpi_iort_node *node);
+	bool (*iommu_is_coherent)(struct acpi_iort_node *node);
+	int (*iommu_count_resources)(struct acpi_iort_node *node);
+	void (*iommu_init_resources)(struct resource *res,
+				     struct acpi_iort_node *node);
+};
+
+static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
+	.name = "arm-smmu-v3",
+	.iommu_is_coherent = arm_smmu_v3_is_coherent,
+	.iommu_count_resources = arm_smmu_v3_count_resources,
+	.iommu_init_resources = arm_smmu_v3_init_resources
+};
+
+static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = {
+	.name = "arm-smmu",
+	.iommu_is_coherent = arm_smmu_is_coherent,
+	.iommu_count_resources = arm_smmu_count_resources,
+	.iommu_init_resources = arm_smmu_init_resources
+};
+
+static __init
+const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
+{
+	switch (node->type) {
+	case ACPI_IORT_NODE_SMMU_V3:
+		return &iort_arm_smmu_v3_cfg;
+	case ACPI_IORT_NODE_SMMU:
+		return &iort_arm_smmu_cfg;
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
+ * @node: Pointer to SMMU ACPI IORT node
+ *
+ * Returns: 0 on success, <0 failure
+ */
+static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
+{
+	struct fwnode_handle *fwnode;
+	struct platform_device *pdev;
+	struct resource *r;
+	enum dev_dma_attr attr;
+	int ret, count;
+	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
+
+	if (!ops)
+		return -ENODEV;
+
+	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return -ENOMEM;
+
+	count = ops->iommu_count_resources(node);
+
+	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
+	if (!r) {
+		ret = -ENOMEM;
+		goto dev_put;
+	}
+
+	ops->iommu_init_resources(r, node);
+
+	ret = platform_device_add_resources(pdev, r, count);
+	/*
+	 * Resources are duplicated in platform_device_add_resources,
+	 * free their allocated memory
+	 */
+	kfree(r);
+
+	if (ret)
+		goto dev_put;
+
+	/*
+	 * Add a copy of IORT node pointer to platform_data to
+	 * be used to retrieve IORT data information.
+	 */
+	ret = platform_device_add_data(pdev, &node, sizeof(node));
+	if (ret)
+		goto dev_put;
+
+	/*
+	 * We expect the dma masks to be equivalent for
+	 * all SMMUs set-ups
+	 */
+	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+	fwnode = iort_get_fwnode(node);
+
+	if (!fwnode) {
+		ret = -ENODEV;
+		goto dev_put;
+	}
+
+	pdev->dev.fwnode = fwnode;
+
+	attr = ops->iommu_is_coherent(node) ?
+			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
+
+	/* Configure DMA for the page table walker */
+	acpi_dma_configure(&pdev->dev, attr);
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto dma_deconfigure;
+
+	return 0;
+
+dma_deconfigure:
+	acpi_dma_deconfigure(&pdev->dev);
+dev_put:
+	platform_device_put(pdev);
+
+	return ret;
+}
+
+static void __init iort_init_platform_devices(void)
+{
+	struct acpi_iort_node *iort_node, *iort_end;
+	struct acpi_table_iort *iort;
+	struct fwnode_handle *fwnode;
+	int i, ret;
+
+	/*
+	 * iort_table and iort both point to the start of IORT table, but
+	 * have different struct types
+	 */
+	iort = (struct acpi_table_iort *)iort_table;
+
+	/* Get the first IORT node */
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				iort_table->length);
+
+	for (i = 0; i < iort->node_count; i++) {
+		if (iort_node >= iort_end) {
+			pr_err("iort node pointer overflows, bad table\n");
+			return;
+		}
+
+		if ((iort_node->type == ACPI_IORT_NODE_SMMU) ||
+			(iort_node->type == ACPI_IORT_NODE_SMMU_V3)) {
+
+			fwnode = acpi_alloc_fwnode_static();
+			if (!fwnode)
+				return;
+
+			iort_set_fwnode(iort_node, fwnode);
+
+			ret = iort_add_smmu_platform_device(iort_node);
+			if (ret) {
+				iort_delete_fwnode(iort_node);
+				acpi_free_fwnode_static(fwnode);
+				return;
+			}
+		}
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+}
+
+void __init acpi_iort_init(void)
+{
+	acpi_status status;
+
+	status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			const char *msg = acpi_format_exception(status);
+
+			pr_err("Failed to get table, %s\n", msg);
+		}
+
+		return;
+	}
+
+	iort_init_platform_devices();
+
+	acpi_probe_device_table(iort);
+}
diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
new file mode 100644
index 0000000..77e0809
--- /dev/null
+++ b/xen/include/acpi/acpi_iort.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __ACPI_IORT_H__
+#define __ACPI_IORT_H__
+
+#include <linux/acpi.h>
+#include <linux/fwnode.h>
+#include <linux/irqdomain.h>
+
+#define IORT_IRQ_MASK(irq)		(irq & 0xffffffffULL)
+#define IORT_IRQ_TRIGGER_MASK(irq)	((irq >> 32) & 0xffffffffULL)
+
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
+void iort_deregister_domain_token(int trans_id);
+struct fwnode_handle *iort_find_domain_token(int trans_id);
+#ifdef CONFIG_ACPI_IORT
+void acpi_iort_init(void);
+bool iort_node_match(u8 type);
+u32 iort_msi_map_rid(struct device *dev, u32 req_id);
+struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
+/* IOMMU interface */
+void iort_set_dma_mask(struct device *dev);
+const struct iommu_ops *iort_iommu_configure(struct device *dev);
+#else
+static inline void acpi_iort_init(void) { }
+static inline bool iort_node_match(u8 type) { return false; }
+static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
+{ return req_id; }
+static inline struct irq_domain *iort_get_device_domain(struct device *dev,
+							u32 req_id)
+{ return NULL; }
+/* IOMMU interface */
+static inline void iort_set_dma_mask(struct device *dev) { }
+static inline
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{ return NULL; }
+#endif
+
+#define IORT_ACPI_DECLARE(name, table_id, fn)		\
+	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
+
+#endif /* __ACPI_IORT_H__ */
-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
                   ` (3 preceding siblings ...)
  2017-09-21  0:37 ` [RFC v2 4/7] ACPI: arm: Support for IORT Sameer Goel
@ 2017-09-21  0:37 ` Sameer Goel
  2017-10-10 12:36   ` Manish Jaggi
                     ` (3 more replies)
  2017-09-21  0:37 ` [RFC v2 6/7] Add verbatim copy of arm-smmu-v3.c from Linux Sameer Goel
                   ` (2 subsequent siblings)
  7 siblings, 4 replies; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

Add support for parsing IORT table to initialize SMMU devices.
* The code for creating an SMMU device has been modified, so that the SMMU
device can be initialized.
* The NAMED NODE code has been commented out as this will need DOM0 kernel
support.
* ITS code has been included but it has not been tested.

Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
---
 xen/arch/arm/setup.c               |   3 +
 xen/drivers/acpi/Makefile          |   1 +
 xen/drivers/acpi/arm/Makefile      |   1 +
 xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
 xen/drivers/passthrough/arm/smmu.c |   1 +
 xen/include/acpi/acpi_iort.h       |  17 ++--
 xen/include/asm-arm/device.h       |   2 +
 xen/include/xen/acpi.h             |  21 +++++
 xen/include/xen/pci.h              |   8 ++
 9 files changed, 146 insertions(+), 81 deletions(-)
 create mode 100644 xen/drivers/acpi/arm/Makefile

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 92f173b..4ba09b2 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -49,6 +49,7 @@
 #include <asm/setup.h>
 #include <xsm/xsm.h>
 #include <asm/acpi.h>
+#include <acpi/acpi_iort.h>
 
 struct bootinfo __initdata bootinfo;
 
@@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     tasklet_subsys_init();
 
+    /* Parse the ACPI iort data */
+    acpi_iort_init();
 
     xsm_dt_init();
 
diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
index 444b11d..e7ffd82 100644
--- a/xen/drivers/acpi/Makefile
+++ b/xen/drivers/acpi/Makefile
@@ -1,5 +1,6 @@
 subdir-y += tables
 subdir-y += utilities
+subdir-$(CONFIG_ARM) += arm
 subdir-$(CONFIG_X86) += apei
 
 obj-bin-y += tables.init.o
diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
new file mode 100644
index 0000000..7c039bb
--- /dev/null
+++ b/xen/drivers/acpi/arm/Makefile
@@ -0,0 +1 @@
+obj-y += iort.o
diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
index 2e368a6..7f54062 100644
--- a/xen/drivers/acpi/arm/iort.c
+++ b/xen/drivers/acpi/arm/iort.c
@@ -14,17 +14,47 @@
  * This file implements early detection/parsing of I/O mapping
  * reported to OS through firmware via I/O Remapping Table (IORT)
  * IORT document number: ARM DEN 0049A
+ *
+ * Based on Linux drivers/acpi/arm64/iort.c
+ * => commit ca78d3173cff3503bcd15723b049757f75762d15
+ *
+ * Xen modification:
+ * Sameer Goel <sgoel@codeaurora.org>
+ * Copyright (C) 2017, The Linux Foundation, All rights reserved.
+ *
  */
 
-#define pr_fmt(fmt)	"ACPI: IORT: " fmt
-
-#include <linux/acpi_iort.h>
-#include <linux/iommu.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <xen/acpi.h>
+#include <acpi/acpi_iort.h>
+#include <xen/fwnode.h>
+#include <xen/iommu.h>
+#include <xen/lib.h>
+#include <xen/list.h>
+#include <xen/pci.h>
+
+#include <asm/device.h>
+
+/* Xen: Define compatibility functions */
+#define FW_BUG		"[Firmware Bug]: "
+#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
+#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
+
+/* Alias to Xen allocation helpers */
+#define kfree xfree
+#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
+#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))
+
+/* Redefine WARN macros */
+#undef WARN
+#undef WARN_ON
+#define WARN(condition, format...) ({					\
+	int __ret_warn_on = !!(condition);				\
+	if (unlikely(__ret_warn_on))					\
+		printk(format);						\
+	unlikely(__ret_warn_on);					\
+})
+#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
+#define WARN_ON(cond)                      (!!cond)
 
 #define IORT_TYPE_MASK(type)	(1 << (type))
 #define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
@@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
 	acpi_status status;
 
 	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+		status = AE_NOT_IMPLEMENTED;
+/*
+ * We need the namespace object name from dsdt to match the iort node, this
+ * will need additions to the kernel xen bus notifiers.
+ * So, disabling the named node code till a proposal is approved.
+ */
+#if 0
 		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
 		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
 		struct acpi_iort_named_component *ncomp;
@@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
 		status = !strcmp(ncomp->device_name, buf.pointer) ?
 							AE_OK : AE_NOT_FOUND;
 		acpi_os_free(buf.pointer);
+#endif
 	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
 		struct acpi_iort_root_complex *pci_rc;
-		struct pci_bus *bus;
+		struct pci_dev *pci_dev;
 
-		bus = to_pci_bus(dev);
+		pci_dev = to_pci_dev(dev);
 		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
 
 		/*
@@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
 		 * with root complexes. Each segment number can represent only
 		 * one root complex.
 		 */
-		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
+		status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
 							AE_OK : AE_NOT_FOUND;
 	} else {
 		status = AE_NOT_FOUND;
 	}
-out:
 	return status;
 }
 
@@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
 	return 0;
 }
 
+/*
+ * Named components are not supported yet so we do not need the
+ * iort_node_get_id function
+ */
+#if 0
 static
 struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
 					u32 *id_out, u8 type_mask,
@@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
 
 	return NULL;
 }
+#endif
 
 static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
 						u32 rid_in, u32 *rid_out,
@@ -410,6 +453,10 @@ fail_map:
 	return NULL;
 }
 
+/* Xen: Comment out the NamedComponent and ITS mapping code till the support
+ * is available.
+ */
+#if 0
 static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
 {
 	struct pci_bus *pbus;
@@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
 	return 0;
 }
 
-/**
+/*
  * iort_get_device_domain() - Find MSI domain related to a device
  * @dev: The device.
  * @req_id: Requester ID for the device.
@@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
 	*rid = alias;
 	return 0;
 }
-
+#endif
 static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
 			       struct fwnode_handle *fwnode,
 			       const struct iommu_ops *ops)
@@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
 	return ret ? NULL : ops;
 }
 
+#if 0 /* Xen: We do not need this function for Xen */
 /**
  * iort_set_dma_mask - Set-up dma mask for a device.
  *
@@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
 	if (!dev->dma_mask)
 		dev->dma_mask = &dev->coherent_dma_mask;
 }
-
+#endif
 /**
  * iort_iommu_configure - Set-up IOMMU configuration for a device.
  *
@@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
 	u32 streamid = 0;
 
 	if (dev_is_pci(dev)) {
-		struct pci_bus *bus = to_pci_dev(dev)->bus;
+		struct pci_dev *pci_device = to_pci_dev(dev);
 		u32 rid;
 
-		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
-				       &rid);
+		rid = PCI_BDF2(pci_device->bus, pci_device->devfn);
 
 		node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
-				      iort_match_node_callback, &bus->dev);
+				      iort_match_node_callback, dev);
 		if (!node)
 			return NULL;
 
@@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
 		ops = iort_iommu_xlate(dev, parent, streamid);
 
 	} else {
+		return NULL;
+/*
+ * We need the namespace object name from dsdt to match the iort node, this
+ * will need additions to the kernel xen bus notifiers.
+ * So, disabling the named node code till a proposal is approved.
+ */
+#if 0
 		int i = 0;
 
 		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
@@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
 			parent = iort_node_get_id(node, &streamid,
 						  IORT_IOMMU_TYPE, i++);
 		}
+#endif
 	}
 
 	return ops;
 }
 
+/*
+ * Xen: Not using the parsing ops for now. Need to check and see if it will
+ * be useful to use these in some form, or let the driver parse IORT node.
+ */
+#if 0
 static void __init acpi_iort_register_irq(int hwirq, const char *name,
 					  int trigger,
 					  struct resource *res)
@@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
 		return NULL;
 	}
 }
-
+#endif
 /**
  * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
  * @node: Pointer to SMMU ACPI IORT node
@@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
 static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
 {
 	struct fwnode_handle *fwnode;
-	struct platform_device *pdev;
-	struct resource *r;
-	enum dev_dma_attr attr;
-	int ret, count;
-	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
-
-	if (!ops)
-		return -ENODEV;
-
-	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
-	if (!pdev)
-		return -ENOMEM;
-
-	count = ops->iommu_count_resources(node);
-
-	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
-	if (!r) {
-		ret = -ENOMEM;
-		goto dev_put;
-	}
-
-	ops->iommu_init_resources(r, node);
+	struct device *dev;
+	int ret;
 
-	ret = platform_device_add_resources(pdev, r, count);
 	/*
-	 * Resources are duplicated in platform_device_add_resources,
-	 * free their allocated memory
+	 * Not enabling the parsing ops for now. The corresponding driver
+	 * can parse this information as needed, so deleting relevant code as
+	 * compared to base revision.
 	 */
-	kfree(r);
 
-	if (ret)
-		goto dev_put;
+	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
 
 	/*
 	 * Add a copy of IORT node pointer to platform_data to
 	 * be used to retrieve IORT data information.
 	 */
-	ret = platform_device_add_data(pdev, &node, sizeof(node));
-	if (ret)
-		goto dev_put;
-
-	/*
-	 * We expect the dma masks to be equivalent for
-	 * all SMMUs set-ups
-	 */
-	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+	dev->type = DEV_ACPI;
+	dev->acpi_node = node;
 
 	fwnode = iort_get_fwnode(node);
 
 	if (!fwnode) {
 		ret = -ENODEV;
-		goto dev_put;
+		goto error;
 	}
 
-	pdev->dev.fwnode = fwnode;
-
-	attr = ops->iommu_is_coherent(node) ?
-			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
-
-	/* Configure DMA for the page table walker */
-	acpi_dma_configure(&pdev->dev, attr);
+	dev->fwnode = fwnode;
 
-	ret = platform_device_add(pdev);
-	if (ret)
-		goto dma_deconfigure;
+	/* Call the acpi init functions for IOMMU devices */
+	ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
 
 	return 0;
 
-dma_deconfigure:
-	acpi_dma_deconfigure(&pdev->dev);
-dev_put:
-	platform_device_put(pdev);
+error:
+	kfree(dev);
 
 	return ret;
 }
@@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
 
 	iort_init_platform_devices();
 
-	acpi_probe_device_table(iort);
+	/* Xen; Do not need a device table probe */
+	/* acpi_probe_device_table(iort);*/
 }
diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
index 362d578..ad956d5 100644
--- a/xen/drivers/passthrough/arm/smmu.c
+++ b/xen/drivers/passthrough/arm/smmu.c
@@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
  * Xen: PCI functions
  * TODO: It should be implemented when PCI will be supported
  */
+#undef to_pci_dev
 #define to_pci_dev(dev)	(NULL)
 static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
 					 int (*fn) (struct pci_dev *pdev,
diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
index 77e0809..d4315a4 100644
--- a/xen/include/acpi/acpi_iort.h
+++ b/xen/include/acpi/acpi_iort.h
@@ -19,27 +19,32 @@
 #ifndef __ACPI_IORT_H__
 #define __ACPI_IORT_H__
 
-#include <linux/acpi.h>
-#include <linux/fwnode.h>
-#include <linux/irqdomain.h>
+#include <xen/acpi.h>
+#include <asm/device.h>
 
+/* Xen: Not using IORT IRQ bindings */
+#if 0
 #define IORT_IRQ_MASK(irq)		(irq & 0xffffffffULL)
 #define IORT_IRQ_TRIGGER_MASK(irq)	((irq >> 32) & 0xffffffffULL)
 
 int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
 void iort_deregister_domain_token(int trans_id);
 struct fwnode_handle *iort_find_domain_token(int trans_id);
-#ifdef CONFIG_ACPI_IORT
+#endif
+#ifdef CONFIG_ARM_64
 void acpi_iort_init(void);
 bool iort_node_match(u8 type);
+#if 0
 u32 iort_msi_map_rid(struct device *dev, u32 req_id);
 struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
 /* IOMMU interface */
 void iort_set_dma_mask(struct device *dev);
+#endif
 const struct iommu_ops *iort_iommu_configure(struct device *dev);
 #else
 static inline void acpi_iort_init(void) { }
 static inline bool iort_node_match(u8 type) { return false; }
+#if 0
 static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 { return req_id; }
 static inline struct irq_domain *iort_get_device_domain(struct device *dev,
@@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
 { return NULL; }
 /* IOMMU interface */
 static inline void iort_set_dma_mask(struct device *dev) { }
+#endif
 static inline
 const struct iommu_ops *iort_iommu_configure(struct device *dev)
 { return NULL; }
 #endif
 
-#define IORT_ACPI_DECLARE(name, table_id, fn)		\
-	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
-
 #endif /* __ACPI_IORT_H__ */
diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
index 5027c87..4eef9ce 100644
--- a/xen/include/asm-arm/device.h
+++ b/xen/include/asm-arm/device.h
@@ -7,6 +7,7 @@
 enum device_type
 {
     DEV_DT,
+    DEV_ACPI,
 };
 
 struct dev_archdata {
@@ -20,6 +21,7 @@ struct device
 #ifdef CONFIG_HAS_DEVICE_TREE
     struct dt_device_node *of_node; /* Used by drivers imported from Linux */
 #endif
+    void *acpi_node; /*Current use case is acpi_iort_node */
     struct fwnode_handle *fwnode; /*fw device node identifier */
     struct iommu_fwspec *iommu_fwspec;
     struct dev_archdata archdata;
diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
index 9409350..2f6aae1 100644
--- a/xen/include/xen/acpi.h
+++ b/xen/include/xen/acpi.h
@@ -32,6 +32,7 @@
 
 #include <acpi/acpi.h>
 #include <asm/acpi.h>
+#include <xen/fwnode.h>
 
 #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
 	(ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
@@ -49,6 +50,26 @@
                 (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
                 (entry)->header.length < sizeof(*(entry)))
 
+static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
+{
+	struct fwnode_handle *fwnode;
+
+	fwnode = xzalloc(struct fwnode_handle);
+	if (!fwnode)
+		return NULL;
+
+	fwnode->type = FWNODE_ACPI_STATIC;
+
+	return fwnode;
+}
+
+static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
+{
+	if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
+		return;
+
+	xfree(fwnode);
+}
 #ifdef CONFIG_ACPI
 
 enum acpi_interrupt_id {
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index 43f2125..182b1a5 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -92,8 +92,16 @@ struct pci_dev {
 #define PT_FAULT_THRESHOLD 10
     } fault;
     u64 vf_rlen[6];
+#ifdef CONFIG_ARM
+    struct device dev;
+#endif
 };
 
+#ifdef CONFIG_ARM
+#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
+#define pci_domain_nr(dev) dev->seg
+#endif
+
 #define for_each_pdev(domain, pdev) \
     list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
 
-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [RFC v2 6/7] Add verbatim copy of arm-smmu-v3.c from Linux
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
                   ` (4 preceding siblings ...)
  2017-09-21  0:37 ` [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table Sameer Goel
@ 2017-09-21  0:37 ` Sameer Goel
  2017-09-21  0:37 ` [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver Sameer Goel
  2017-09-21  5:43 ` [RFC v2 0/7] SMMUv3 driver and the supporting framework Manish Jaggi
  7 siblings, 0 replies; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

Based on commit bdf95923086fb359ccb44c815724c3ace1611c90

This is a verbatim snapshot of arm-smmu-v3.c from Linux kernel source
code.

No Xen code has been added and the file is not built.

Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
---
 xen/drivers/passthrough/arm/smmu-v3.c | 2791 +++++++++++++++++++++++++++++++++
 1 file changed, 2791 insertions(+)
 create mode 100644 xen/drivers/passthrough/arm/smmu-v3.c

diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
new file mode 100644
index 0000000..380969a
--- /dev/null
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
@@ -0,0 +1,2791 @@
+/*
+ * IOMMU API for ARM architected SMMUv3 implementations.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/>.
+ *
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This driver is powered by bad coffee and bombay mix.
+ */
+
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
+#include <linux/delay.h>
+#include <linux/dma-iommu.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_iommu.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <linux/amba/bus.h>
+
+#include "io-pgtable.h"
+
+/* MMIO registers */
+#define ARM_SMMU_IDR0			0x0
+#define IDR0_ST_LVL_SHIFT		27
+#define IDR0_ST_LVL_MASK		0x3
+#define IDR0_ST_LVL_2LVL		(1 << IDR0_ST_LVL_SHIFT)
+#define IDR0_STALL_MODEL_SHIFT		24
+#define IDR0_STALL_MODEL_MASK		0x3
+#define IDR0_STALL_MODEL_STALL		(0 << IDR0_STALL_MODEL_SHIFT)
+#define IDR0_STALL_MODEL_FORCE		(2 << IDR0_STALL_MODEL_SHIFT)
+#define IDR0_TTENDIAN_SHIFT		21
+#define IDR0_TTENDIAN_MASK		0x3
+#define IDR0_TTENDIAN_LE		(2 << IDR0_TTENDIAN_SHIFT)
+#define IDR0_TTENDIAN_BE		(3 << IDR0_TTENDIAN_SHIFT)
+#define IDR0_TTENDIAN_MIXED		(0 << IDR0_TTENDIAN_SHIFT)
+#define IDR0_CD2L			(1 << 19)
+#define IDR0_VMID16			(1 << 18)
+#define IDR0_PRI			(1 << 16)
+#define IDR0_SEV			(1 << 14)
+#define IDR0_MSI			(1 << 13)
+#define IDR0_ASID16			(1 << 12)
+#define IDR0_ATS			(1 << 10)
+#define IDR0_HYP			(1 << 9)
+#define IDR0_COHACC			(1 << 4)
+#define IDR0_TTF_SHIFT			2
+#define IDR0_TTF_MASK			0x3
+#define IDR0_TTF_AARCH64		(2 << IDR0_TTF_SHIFT)
+#define IDR0_TTF_AARCH32_64		(3 << IDR0_TTF_SHIFT)
+#define IDR0_S1P			(1 << 1)
+#define IDR0_S2P			(1 << 0)
+
+#define ARM_SMMU_IDR1			0x4
+#define IDR1_TABLES_PRESET		(1 << 30)
+#define IDR1_QUEUES_PRESET		(1 << 29)
+#define IDR1_REL			(1 << 28)
+#define IDR1_CMDQ_SHIFT			21
+#define IDR1_CMDQ_MASK			0x1f
+#define IDR1_EVTQ_SHIFT			16
+#define IDR1_EVTQ_MASK			0x1f
+#define IDR1_PRIQ_SHIFT			11
+#define IDR1_PRIQ_MASK			0x1f
+#define IDR1_SSID_SHIFT			6
+#define IDR1_SSID_MASK			0x1f
+#define IDR1_SID_SHIFT			0
+#define IDR1_SID_MASK			0x3f
+
+#define ARM_SMMU_IDR5			0x14
+#define IDR5_STALL_MAX_SHIFT		16
+#define IDR5_STALL_MAX_MASK		0xffff
+#define IDR5_GRAN64K			(1 << 6)
+#define IDR5_GRAN16K			(1 << 5)
+#define IDR5_GRAN4K			(1 << 4)
+#define IDR5_OAS_SHIFT			0
+#define IDR5_OAS_MASK			0x7
+#define IDR5_OAS_32_BIT			(0 << IDR5_OAS_SHIFT)
+#define IDR5_OAS_36_BIT			(1 << IDR5_OAS_SHIFT)
+#define IDR5_OAS_40_BIT			(2 << IDR5_OAS_SHIFT)
+#define IDR5_OAS_42_BIT			(3 << IDR5_OAS_SHIFT)
+#define IDR5_OAS_44_BIT			(4 << IDR5_OAS_SHIFT)
+#define IDR5_OAS_48_BIT			(5 << IDR5_OAS_SHIFT)
+
+#define ARM_SMMU_CR0			0x20
+#define CR0_CMDQEN			(1 << 3)
+#define CR0_EVTQEN			(1 << 2)
+#define CR0_PRIQEN			(1 << 1)
+#define CR0_SMMUEN			(1 << 0)
+
+#define ARM_SMMU_CR0ACK			0x24
+
+#define ARM_SMMU_CR1			0x28
+#define CR1_SH_NSH			0
+#define CR1_SH_OSH			2
+#define CR1_SH_ISH			3
+#define CR1_CACHE_NC			0
+#define CR1_CACHE_WB			1
+#define CR1_CACHE_WT			2
+#define CR1_TABLE_SH_SHIFT		10
+#define CR1_TABLE_OC_SHIFT		8
+#define CR1_TABLE_IC_SHIFT		6
+#define CR1_QUEUE_SH_SHIFT		4
+#define CR1_QUEUE_OC_SHIFT		2
+#define CR1_QUEUE_IC_SHIFT		0
+
+#define ARM_SMMU_CR2			0x2c
+#define CR2_PTM				(1 << 2)
+#define CR2_RECINVSID			(1 << 1)
+#define CR2_E2H				(1 << 0)
+
+#define ARM_SMMU_GBPA			0x44
+#define GBPA_ABORT			(1 << 20)
+#define GBPA_UPDATE			(1 << 31)
+
+#define ARM_SMMU_IRQ_CTRL		0x50
+#define IRQ_CTRL_EVTQ_IRQEN		(1 << 2)
+#define IRQ_CTRL_PRIQ_IRQEN		(1 << 1)
+#define IRQ_CTRL_GERROR_IRQEN		(1 << 0)
+
+#define ARM_SMMU_IRQ_CTRLACK		0x54
+
+#define ARM_SMMU_GERROR			0x60
+#define GERROR_SFM_ERR			(1 << 8)
+#define GERROR_MSI_GERROR_ABT_ERR	(1 << 7)
+#define GERROR_MSI_PRIQ_ABT_ERR		(1 << 6)
+#define GERROR_MSI_EVTQ_ABT_ERR		(1 << 5)
+#define GERROR_MSI_CMDQ_ABT_ERR		(1 << 4)
+#define GERROR_PRIQ_ABT_ERR		(1 << 3)
+#define GERROR_EVTQ_ABT_ERR		(1 << 2)
+#define GERROR_CMDQ_ERR			(1 << 0)
+#define GERROR_ERR_MASK			0xfd
+
+#define ARM_SMMU_GERRORN		0x64
+
+#define ARM_SMMU_GERROR_IRQ_CFG0	0x68
+#define ARM_SMMU_GERROR_IRQ_CFG1	0x70
+#define ARM_SMMU_GERROR_IRQ_CFG2	0x74
+
+#define ARM_SMMU_STRTAB_BASE		0x80
+#define STRTAB_BASE_RA			(1UL << 62)
+#define STRTAB_BASE_ADDR_SHIFT		6
+#define STRTAB_BASE_ADDR_MASK		0x3ffffffffffUL
+
+#define ARM_SMMU_STRTAB_BASE_CFG	0x88
+#define STRTAB_BASE_CFG_LOG2SIZE_SHIFT	0
+#define STRTAB_BASE_CFG_LOG2SIZE_MASK	0x3f
+#define STRTAB_BASE_CFG_SPLIT_SHIFT	6
+#define STRTAB_BASE_CFG_SPLIT_MASK	0x1f
+#define STRTAB_BASE_CFG_FMT_SHIFT	16
+#define STRTAB_BASE_CFG_FMT_MASK	0x3
+#define STRTAB_BASE_CFG_FMT_LINEAR	(0 << STRTAB_BASE_CFG_FMT_SHIFT)
+#define STRTAB_BASE_CFG_FMT_2LVL	(1 << STRTAB_BASE_CFG_FMT_SHIFT)
+
+#define ARM_SMMU_CMDQ_BASE		0x90
+#define ARM_SMMU_CMDQ_PROD		0x98
+#define ARM_SMMU_CMDQ_CONS		0x9c
+
+#define ARM_SMMU_EVTQ_BASE		0xa0
+#define ARM_SMMU_EVTQ_PROD		0x100a8
+#define ARM_SMMU_EVTQ_CONS		0x100ac
+#define ARM_SMMU_EVTQ_IRQ_CFG0		0xb0
+#define ARM_SMMU_EVTQ_IRQ_CFG1		0xb8
+#define ARM_SMMU_EVTQ_IRQ_CFG2		0xbc
+
+#define ARM_SMMU_PRIQ_BASE		0xc0
+#define ARM_SMMU_PRIQ_PROD		0x100c8
+#define ARM_SMMU_PRIQ_CONS		0x100cc
+#define ARM_SMMU_PRIQ_IRQ_CFG0		0xd0
+#define ARM_SMMU_PRIQ_IRQ_CFG1		0xd8
+#define ARM_SMMU_PRIQ_IRQ_CFG2		0xdc
+
+/* Common MSI config fields */
+#define MSI_CFG0_ADDR_SHIFT		2
+#define MSI_CFG0_ADDR_MASK		0x3fffffffffffUL
+#define MSI_CFG2_SH_SHIFT		4
+#define MSI_CFG2_SH_NSH			(0UL << MSI_CFG2_SH_SHIFT)
+#define MSI_CFG2_SH_OSH			(2UL << MSI_CFG2_SH_SHIFT)
+#define MSI_CFG2_SH_ISH			(3UL << MSI_CFG2_SH_SHIFT)
+#define MSI_CFG2_MEMATTR_SHIFT		0
+#define MSI_CFG2_MEMATTR_DEVICE_nGnRE	(0x1 << MSI_CFG2_MEMATTR_SHIFT)
+
+#define Q_IDX(q, p)			((p) & ((1 << (q)->max_n_shift) - 1))
+#define Q_WRP(q, p)			((p) & (1 << (q)->max_n_shift))
+#define Q_OVERFLOW_FLAG			(1 << 31)
+#define Q_OVF(q, p)			((p) & Q_OVERFLOW_FLAG)
+#define Q_ENT(q, p)			((q)->base +			\
+					 Q_IDX(q, p) * (q)->ent_dwords)
+
+#define Q_BASE_RWA			(1UL << 62)
+#define Q_BASE_ADDR_SHIFT		5
+#define Q_BASE_ADDR_MASK		0xfffffffffffUL
+#define Q_BASE_LOG2SIZE_SHIFT		0
+#define Q_BASE_LOG2SIZE_MASK		0x1fUL
+
+/*
+ * Stream table.
+ *
+ * Linear: Enough to cover 1 << IDR1.SIDSIZE entries
+ * 2lvl: 128k L1 entries,
+ *       256 lazy entries per table (each table covers a PCI bus)
+ */
+#define STRTAB_L1_SZ_SHIFT		20
+#define STRTAB_SPLIT			8
+
+#define STRTAB_L1_DESC_DWORDS		1
+#define STRTAB_L1_DESC_SPAN_SHIFT	0
+#define STRTAB_L1_DESC_SPAN_MASK	0x1fUL
+#define STRTAB_L1_DESC_L2PTR_SHIFT	6
+#define STRTAB_L1_DESC_L2PTR_MASK	0x3ffffffffffUL
+
+#define STRTAB_STE_DWORDS		8
+#define STRTAB_STE_0_V			(1UL << 0)
+#define STRTAB_STE_0_CFG_SHIFT		1
+#define STRTAB_STE_0_CFG_MASK		0x7UL
+#define STRTAB_STE_0_CFG_ABORT		(0UL << STRTAB_STE_0_CFG_SHIFT)
+#define STRTAB_STE_0_CFG_BYPASS		(4UL << STRTAB_STE_0_CFG_SHIFT)
+#define STRTAB_STE_0_CFG_S1_TRANS	(5UL << STRTAB_STE_0_CFG_SHIFT)
+#define STRTAB_STE_0_CFG_S2_TRANS	(6UL << STRTAB_STE_0_CFG_SHIFT)
+
+#define STRTAB_STE_0_S1FMT_SHIFT	4
+#define STRTAB_STE_0_S1FMT_LINEAR	(0UL << STRTAB_STE_0_S1FMT_SHIFT)
+#define STRTAB_STE_0_S1CTXPTR_SHIFT	6
+#define STRTAB_STE_0_S1CTXPTR_MASK	0x3ffffffffffUL
+#define STRTAB_STE_0_S1CDMAX_SHIFT	59
+#define STRTAB_STE_0_S1CDMAX_MASK	0x1fUL
+
+#define STRTAB_STE_1_S1C_CACHE_NC	0UL
+#define STRTAB_STE_1_S1C_CACHE_WBRA	1UL
+#define STRTAB_STE_1_S1C_CACHE_WT	2UL
+#define STRTAB_STE_1_S1C_CACHE_WB	3UL
+#define STRTAB_STE_1_S1C_SH_NSH		0UL
+#define STRTAB_STE_1_S1C_SH_OSH		2UL
+#define STRTAB_STE_1_S1C_SH_ISH		3UL
+#define STRTAB_STE_1_S1CIR_SHIFT	2
+#define STRTAB_STE_1_S1COR_SHIFT	4
+#define STRTAB_STE_1_S1CSH_SHIFT	6
+
+#define STRTAB_STE_1_S1STALLD		(1UL << 27)
+
+#define STRTAB_STE_1_EATS_ABT		0UL
+#define STRTAB_STE_1_EATS_TRANS		1UL
+#define STRTAB_STE_1_EATS_S1CHK		2UL
+#define STRTAB_STE_1_EATS_SHIFT		28
+
+#define STRTAB_STE_1_STRW_NSEL1		0UL
+#define STRTAB_STE_1_STRW_EL2		2UL
+#define STRTAB_STE_1_STRW_SHIFT		30
+
+#define STRTAB_STE_1_SHCFG_INCOMING	1UL
+#define STRTAB_STE_1_SHCFG_SHIFT	44
+
+#define STRTAB_STE_2_S2VMID_SHIFT	0
+#define STRTAB_STE_2_S2VMID_MASK	0xffffUL
+#define STRTAB_STE_2_VTCR_SHIFT		32
+#define STRTAB_STE_2_VTCR_MASK		0x7ffffUL
+#define STRTAB_STE_2_S2AA64		(1UL << 51)
+#define STRTAB_STE_2_S2ENDI		(1UL << 52)
+#define STRTAB_STE_2_S2PTW		(1UL << 54)
+#define STRTAB_STE_2_S2R		(1UL << 58)
+
+#define STRTAB_STE_3_S2TTB_SHIFT	4
+#define STRTAB_STE_3_S2TTB_MASK		0xfffffffffffUL
+
+/* Context descriptor (stage-1 only) */
+#define CTXDESC_CD_DWORDS		8
+#define CTXDESC_CD_0_TCR_T0SZ_SHIFT	0
+#define ARM64_TCR_T0SZ_SHIFT		0
+#define ARM64_TCR_T0SZ_MASK		0x1fUL
+#define CTXDESC_CD_0_TCR_TG0_SHIFT	6
+#define ARM64_TCR_TG0_SHIFT		14
+#define ARM64_TCR_TG0_MASK		0x3UL
+#define CTXDESC_CD_0_TCR_IRGN0_SHIFT	8
+#define ARM64_TCR_IRGN0_SHIFT		8
+#define ARM64_TCR_IRGN0_MASK		0x3UL
+#define CTXDESC_CD_0_TCR_ORGN0_SHIFT	10
+#define ARM64_TCR_ORGN0_SHIFT		10
+#define ARM64_TCR_ORGN0_MASK		0x3UL
+#define CTXDESC_CD_0_TCR_SH0_SHIFT	12
+#define ARM64_TCR_SH0_SHIFT		12
+#define ARM64_TCR_SH0_MASK		0x3UL
+#define CTXDESC_CD_0_TCR_EPD0_SHIFT	14
+#define ARM64_TCR_EPD0_SHIFT		7
+#define ARM64_TCR_EPD0_MASK		0x1UL
+#define CTXDESC_CD_0_TCR_EPD1_SHIFT	30
+#define ARM64_TCR_EPD1_SHIFT		23
+#define ARM64_TCR_EPD1_MASK		0x1UL
+
+#define CTXDESC_CD_0_ENDI		(1UL << 15)
+#define CTXDESC_CD_0_V			(1UL << 31)
+
+#define CTXDESC_CD_0_TCR_IPS_SHIFT	32
+#define ARM64_TCR_IPS_SHIFT		32
+#define ARM64_TCR_IPS_MASK		0x7UL
+#define CTXDESC_CD_0_TCR_TBI0_SHIFT	38
+#define ARM64_TCR_TBI0_SHIFT		37
+#define ARM64_TCR_TBI0_MASK		0x1UL
+
+#define CTXDESC_CD_0_AA64		(1UL << 41)
+#define CTXDESC_CD_0_R			(1UL << 45)
+#define CTXDESC_CD_0_A			(1UL << 46)
+#define CTXDESC_CD_0_ASET_SHIFT		47
+#define CTXDESC_CD_0_ASET_SHARED	(0UL << CTXDESC_CD_0_ASET_SHIFT)
+#define CTXDESC_CD_0_ASET_PRIVATE	(1UL << CTXDESC_CD_0_ASET_SHIFT)
+#define CTXDESC_CD_0_ASID_SHIFT		48
+#define CTXDESC_CD_0_ASID_MASK		0xffffUL
+
+#define CTXDESC_CD_1_TTB0_SHIFT		4
+#define CTXDESC_CD_1_TTB0_MASK		0xfffffffffffUL
+
+#define CTXDESC_CD_3_MAIR_SHIFT		0
+
+/* Convert between AArch64 (CPU) TCR format and SMMU CD format */
+#define ARM_SMMU_TCR2CD(tcr, fld)					\
+	(((tcr) >> ARM64_TCR_##fld##_SHIFT & ARM64_TCR_##fld##_MASK)	\
+	 << CTXDESC_CD_0_TCR_##fld##_SHIFT)
+
+/* Command queue */
+#define CMDQ_ENT_DWORDS			2
+#define CMDQ_MAX_SZ_SHIFT		8
+
+#define CMDQ_ERR_SHIFT			24
+#define CMDQ_ERR_MASK			0x7f
+#define CMDQ_ERR_CERROR_NONE_IDX	0
+#define CMDQ_ERR_CERROR_ILL_IDX		1
+#define CMDQ_ERR_CERROR_ABT_IDX		2
+
+#define CMDQ_0_OP_SHIFT			0
+#define CMDQ_0_OP_MASK			0xffUL
+#define CMDQ_0_SSV			(1UL << 11)
+
+#define CMDQ_PREFETCH_0_SID_SHIFT	32
+#define CMDQ_PREFETCH_1_SIZE_SHIFT	0
+#define CMDQ_PREFETCH_1_ADDR_MASK	~0xfffUL
+
+#define CMDQ_CFGI_0_SID_SHIFT		32
+#define CMDQ_CFGI_0_SID_MASK		0xffffffffUL
+#define CMDQ_CFGI_1_LEAF		(1UL << 0)
+#define CMDQ_CFGI_1_RANGE_SHIFT		0
+#define CMDQ_CFGI_1_RANGE_MASK		0x1fUL
+
+#define CMDQ_TLBI_0_VMID_SHIFT		32
+#define CMDQ_TLBI_0_ASID_SHIFT		48
+#define CMDQ_TLBI_1_LEAF		(1UL << 0)
+#define CMDQ_TLBI_1_VA_MASK		~0xfffUL
+#define CMDQ_TLBI_1_IPA_MASK		0xfffffffff000UL
+
+#define CMDQ_PRI_0_SSID_SHIFT		12
+#define CMDQ_PRI_0_SSID_MASK		0xfffffUL
+#define CMDQ_PRI_0_SID_SHIFT		32
+#define CMDQ_PRI_0_SID_MASK		0xffffffffUL
+#define CMDQ_PRI_1_GRPID_SHIFT		0
+#define CMDQ_PRI_1_GRPID_MASK		0x1ffUL
+#define CMDQ_PRI_1_RESP_SHIFT		12
+#define CMDQ_PRI_1_RESP_DENY		(0UL << CMDQ_PRI_1_RESP_SHIFT)
+#define CMDQ_PRI_1_RESP_FAIL		(1UL << CMDQ_PRI_1_RESP_SHIFT)
+#define CMDQ_PRI_1_RESP_SUCC		(2UL << CMDQ_PRI_1_RESP_SHIFT)
+
+#define CMDQ_SYNC_0_CS_SHIFT		12
+#define CMDQ_SYNC_0_CS_NONE		(0UL << CMDQ_SYNC_0_CS_SHIFT)
+#define CMDQ_SYNC_0_CS_SEV		(2UL << CMDQ_SYNC_0_CS_SHIFT)
+
+/* Event queue */
+#define EVTQ_ENT_DWORDS			4
+#define EVTQ_MAX_SZ_SHIFT		7
+
+#define EVTQ_0_ID_SHIFT			0
+#define EVTQ_0_ID_MASK			0xffUL
+
+/* PRI queue */
+#define PRIQ_ENT_DWORDS			2
+#define PRIQ_MAX_SZ_SHIFT		8
+
+#define PRIQ_0_SID_SHIFT		0
+#define PRIQ_0_SID_MASK			0xffffffffUL
+#define PRIQ_0_SSID_SHIFT		32
+#define PRIQ_0_SSID_MASK		0xfffffUL
+#define PRIQ_0_PERM_PRIV		(1UL << 58)
+#define PRIQ_0_PERM_EXEC		(1UL << 59)
+#define PRIQ_0_PERM_READ		(1UL << 60)
+#define PRIQ_0_PERM_WRITE		(1UL << 61)
+#define PRIQ_0_PRG_LAST			(1UL << 62)
+#define PRIQ_0_SSID_V			(1UL << 63)
+
+#define PRIQ_1_PRG_IDX_SHIFT		0
+#define PRIQ_1_PRG_IDX_MASK		0x1ffUL
+#define PRIQ_1_ADDR_SHIFT		12
+#define PRIQ_1_ADDR_MASK		0xfffffffffffffUL
+
+/* High-level queue structures */
+#define ARM_SMMU_POLL_TIMEOUT_US	100
+
+#define MSI_IOVA_BASE			0x8000000
+#define MSI_IOVA_LENGTH			0x100000
+
+static bool disable_bypass;
+module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO);
+MODULE_PARM_DESC(disable_bypass,
+	"Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
+
+enum pri_resp {
+	PRI_RESP_DENY,
+	PRI_RESP_FAIL,
+	PRI_RESP_SUCC,
+};
+
+enum arm_smmu_msi_index {
+	EVTQ_MSI_INDEX,
+	GERROR_MSI_INDEX,
+	PRIQ_MSI_INDEX,
+	ARM_SMMU_MAX_MSIS,
+};
+
+static phys_addr_t arm_smmu_msi_cfg[ARM_SMMU_MAX_MSIS][3] = {
+	[EVTQ_MSI_INDEX] = {
+		ARM_SMMU_EVTQ_IRQ_CFG0,
+		ARM_SMMU_EVTQ_IRQ_CFG1,
+		ARM_SMMU_EVTQ_IRQ_CFG2,
+	},
+	[GERROR_MSI_INDEX] = {
+		ARM_SMMU_GERROR_IRQ_CFG0,
+		ARM_SMMU_GERROR_IRQ_CFG1,
+		ARM_SMMU_GERROR_IRQ_CFG2,
+	},
+	[PRIQ_MSI_INDEX] = {
+		ARM_SMMU_PRIQ_IRQ_CFG0,
+		ARM_SMMU_PRIQ_IRQ_CFG1,
+		ARM_SMMU_PRIQ_IRQ_CFG2,
+	},
+};
+
+struct arm_smmu_cmdq_ent {
+	/* Common fields */
+	u8				opcode;
+	bool				substream_valid;
+
+	/* Command-specific fields */
+	union {
+		#define CMDQ_OP_PREFETCH_CFG	0x1
+		struct {
+			u32			sid;
+			u8			size;
+			u64			addr;
+		} prefetch;
+
+		#define CMDQ_OP_CFGI_STE	0x3
+		#define CMDQ_OP_CFGI_ALL	0x4
+		struct {
+			u32			sid;
+			union {
+				bool		leaf;
+				u8		span;
+			};
+		} cfgi;
+
+		#define CMDQ_OP_TLBI_NH_ASID	0x11
+		#define CMDQ_OP_TLBI_NH_VA	0x12
+		#define CMDQ_OP_TLBI_EL2_ALL	0x20
+		#define CMDQ_OP_TLBI_S12_VMALL	0x28
+		#define CMDQ_OP_TLBI_S2_IPA	0x2a
+		#define CMDQ_OP_TLBI_NSNH_ALL	0x30
+		struct {
+			u16			asid;
+			u16			vmid;
+			bool			leaf;
+			u64			addr;
+		} tlbi;
+
+		#define CMDQ_OP_PRI_RESP	0x41
+		struct {
+			u32			sid;
+			u32			ssid;
+			u16			grpid;
+			enum pri_resp		resp;
+		} pri;
+
+		#define CMDQ_OP_CMD_SYNC	0x46
+	};
+};
+
+struct arm_smmu_queue {
+	int				irq; /* Wired interrupt */
+
+	__le64				*base;
+	dma_addr_t			base_dma;
+	u64				q_base;
+
+	size_t				ent_dwords;
+	u32				max_n_shift;
+	u32				prod;
+	u32				cons;
+
+	u32 __iomem			*prod_reg;
+	u32 __iomem			*cons_reg;
+};
+
+struct arm_smmu_cmdq {
+	struct arm_smmu_queue		q;
+	spinlock_t			lock;
+};
+
+struct arm_smmu_evtq {
+	struct arm_smmu_queue		q;
+	u32				max_stalls;
+};
+
+struct arm_smmu_priq {
+	struct arm_smmu_queue		q;
+};
+
+/* High-level stream table and context descriptor structures */
+struct arm_smmu_strtab_l1_desc {
+	u8				span;
+
+	__le64				*l2ptr;
+	dma_addr_t			l2ptr_dma;
+};
+
+struct arm_smmu_s1_cfg {
+	__le64				*cdptr;
+	dma_addr_t			cdptr_dma;
+
+	struct arm_smmu_ctx_desc {
+		u16	asid;
+		u64	ttbr;
+		u64	tcr;
+		u64	mair;
+	}				cd;
+};
+
+struct arm_smmu_s2_cfg {
+	u16				vmid;
+	u64				vttbr;
+	u64				vtcr;
+};
+
+struct arm_smmu_strtab_ent {
+	/*
+	 * An STE is "assigned" if the master emitting the corresponding SID
+	 * is attached to a domain. The behaviour of an unassigned STE is
+	 * determined by the disable_bypass parameter, whereas an assigned
+	 * STE behaves according to s1_cfg/s2_cfg, which themselves are
+	 * configured according to the domain type.
+	 */
+	bool				assigned;
+	struct arm_smmu_s1_cfg		*s1_cfg;
+	struct arm_smmu_s2_cfg		*s2_cfg;
+};
+
+struct arm_smmu_strtab_cfg {
+	__le64				*strtab;
+	dma_addr_t			strtab_dma;
+	struct arm_smmu_strtab_l1_desc	*l1_desc;
+	unsigned int			num_l1_ents;
+
+	u64				strtab_base;
+	u32				strtab_base_cfg;
+};
+
+/* An SMMUv3 instance */
+struct arm_smmu_device {
+	struct device			*dev;
+	void __iomem			*base;
+
+#define ARM_SMMU_FEAT_2_LVL_STRTAB	(1 << 0)
+#define ARM_SMMU_FEAT_2_LVL_CDTAB	(1 << 1)
+#define ARM_SMMU_FEAT_TT_LE		(1 << 2)
+#define ARM_SMMU_FEAT_TT_BE		(1 << 3)
+#define ARM_SMMU_FEAT_PRI		(1 << 4)
+#define ARM_SMMU_FEAT_ATS		(1 << 5)
+#define ARM_SMMU_FEAT_SEV		(1 << 6)
+#define ARM_SMMU_FEAT_MSI		(1 << 7)
+#define ARM_SMMU_FEAT_COHERENCY		(1 << 8)
+#define ARM_SMMU_FEAT_TRANS_S1		(1 << 9)
+#define ARM_SMMU_FEAT_TRANS_S2		(1 << 10)
+#define ARM_SMMU_FEAT_STALLS		(1 << 11)
+#define ARM_SMMU_FEAT_HYP		(1 << 12)
+	u32				features;
+
+#define ARM_SMMU_OPT_SKIP_PREFETCH	(1 << 0)
+	u32				options;
+
+	struct arm_smmu_cmdq		cmdq;
+	struct arm_smmu_evtq		evtq;
+	struct arm_smmu_priq		priq;
+
+	int				gerr_irq;
+
+	unsigned long			ias; /* IPA */
+	unsigned long			oas; /* PA */
+	unsigned long			pgsize_bitmap;
+
+#define ARM_SMMU_MAX_ASIDS		(1 << 16)
+	unsigned int			asid_bits;
+	DECLARE_BITMAP(asid_map, ARM_SMMU_MAX_ASIDS);
+
+#define ARM_SMMU_MAX_VMIDS		(1 << 16)
+	unsigned int			vmid_bits;
+	DECLARE_BITMAP(vmid_map, ARM_SMMU_MAX_VMIDS);
+
+	unsigned int			ssid_bits;
+	unsigned int			sid_bits;
+
+	struct arm_smmu_strtab_cfg	strtab_cfg;
+
+	/* IOMMU core code handle */
+	struct iommu_device		iommu;
+};
+
+/* SMMU private data for each master */
+struct arm_smmu_master_data {
+	struct arm_smmu_device		*smmu;
+	struct arm_smmu_strtab_ent	ste;
+};
+
+/* SMMU private data for an IOMMU domain */
+enum arm_smmu_domain_stage {
+	ARM_SMMU_DOMAIN_S1 = 0,
+	ARM_SMMU_DOMAIN_S2,
+	ARM_SMMU_DOMAIN_NESTED,
+	ARM_SMMU_DOMAIN_BYPASS,
+};
+
+struct arm_smmu_domain {
+	struct arm_smmu_device		*smmu;
+	struct mutex			init_mutex; /* Protects smmu pointer */
+
+	struct io_pgtable_ops		*pgtbl_ops;
+	spinlock_t			pgtbl_lock;
+
+	enum arm_smmu_domain_stage	stage;
+	union {
+		struct arm_smmu_s1_cfg	s1_cfg;
+		struct arm_smmu_s2_cfg	s2_cfg;
+	};
+
+	struct iommu_domain		domain;
+};
+
+struct arm_smmu_option_prop {
+	u32 opt;
+	const char *prop;
+};
+
+static struct arm_smmu_option_prop arm_smmu_options[] = {
+	{ ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" },
+	{ 0, NULL},
+};
+
+static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
+{
+	return container_of(dom, struct arm_smmu_domain, domain);
+}
+
+static void parse_driver_options(struct arm_smmu_device *smmu)
+{
+	int i = 0;
+
+	do {
+		if (of_property_read_bool(smmu->dev->of_node,
+						arm_smmu_options[i].prop)) {
+			smmu->options |= arm_smmu_options[i].opt;
+			dev_notice(smmu->dev, "option %s\n",
+				arm_smmu_options[i].prop);
+		}
+	} while (arm_smmu_options[++i].opt);
+}
+
+/* Low-level queue manipulation functions */
+static bool queue_full(struct arm_smmu_queue *q)
+{
+	return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
+	       Q_WRP(q, q->prod) != Q_WRP(q, q->cons);
+}
+
+static bool queue_empty(struct arm_smmu_queue *q)
+{
+	return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
+	       Q_WRP(q, q->prod) == Q_WRP(q, q->cons);
+}
+
+static void queue_sync_cons(struct arm_smmu_queue *q)
+{
+	q->cons = readl_relaxed(q->cons_reg);
+}
+
+static void queue_inc_cons(struct arm_smmu_queue *q)
+{
+	u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1;
+
+	q->cons = Q_OVF(q, q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
+	writel(q->cons, q->cons_reg);
+}
+
+static int queue_sync_prod(struct arm_smmu_queue *q)
+{
+	int ret = 0;
+	u32 prod = readl_relaxed(q->prod_reg);
+
+	if (Q_OVF(q, prod) != Q_OVF(q, q->prod))
+		ret = -EOVERFLOW;
+
+	q->prod = prod;
+	return ret;
+}
+
+static void queue_inc_prod(struct arm_smmu_queue *q)
+{
+	u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + 1;
+
+	q->prod = Q_OVF(q, q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod);
+	writel(q->prod, q->prod_reg);
+}
+
+/*
+ * Wait for the SMMU to consume items. If drain is true, wait until the queue
+ * is empty. Otherwise, wait until there is at least one free slot.
+ */
+static int queue_poll_cons(struct arm_smmu_queue *q, bool drain, bool wfe)
+{
+	ktime_t timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US);
+
+	while (queue_sync_cons(q), (drain ? !queue_empty(q) : queue_full(q))) {
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			return -ETIMEDOUT;
+
+		if (wfe) {
+			wfe();
+		} else {
+			cpu_relax();
+			udelay(1);
+		}
+	}
+
+	return 0;
+}
+
+static void queue_write(__le64 *dst, u64 *src, size_t n_dwords)
+{
+	int i;
+
+	for (i = 0; i < n_dwords; ++i)
+		*dst++ = cpu_to_le64(*src++);
+}
+
+static int queue_insert_raw(struct arm_smmu_queue *q, u64 *ent)
+{
+	if (queue_full(q))
+		return -ENOSPC;
+
+	queue_write(Q_ENT(q, q->prod), ent, q->ent_dwords);
+	queue_inc_prod(q);
+	return 0;
+}
+
+static void queue_read(__le64 *dst, u64 *src, size_t n_dwords)
+{
+	int i;
+
+	for (i = 0; i < n_dwords; ++i)
+		*dst++ = le64_to_cpu(*src++);
+}
+
+static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent)
+{
+	if (queue_empty(q))
+		return -EAGAIN;
+
+	queue_read(ent, Q_ENT(q, q->cons), q->ent_dwords);
+	queue_inc_cons(q);
+	return 0;
+}
+
+/* High-level queue accessors */
+static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
+{
+	memset(cmd, 0, CMDQ_ENT_DWORDS << 3);
+	cmd[0] |= (ent->opcode & CMDQ_0_OP_MASK) << CMDQ_0_OP_SHIFT;
+
+	switch (ent->opcode) {
+	case CMDQ_OP_TLBI_EL2_ALL:
+	case CMDQ_OP_TLBI_NSNH_ALL:
+		break;
+	case CMDQ_OP_PREFETCH_CFG:
+		cmd[0] |= (u64)ent->prefetch.sid << CMDQ_PREFETCH_0_SID_SHIFT;
+		cmd[1] |= ent->prefetch.size << CMDQ_PREFETCH_1_SIZE_SHIFT;
+		cmd[1] |= ent->prefetch.addr & CMDQ_PREFETCH_1_ADDR_MASK;
+		break;
+	case CMDQ_OP_CFGI_STE:
+		cmd[0] |= (u64)ent->cfgi.sid << CMDQ_CFGI_0_SID_SHIFT;
+		cmd[1] |= ent->cfgi.leaf ? CMDQ_CFGI_1_LEAF : 0;
+		break;
+	case CMDQ_OP_CFGI_ALL:
+		/* Cover the entire SID range */
+		cmd[1] |= CMDQ_CFGI_1_RANGE_MASK << CMDQ_CFGI_1_RANGE_SHIFT;
+		break;
+	case CMDQ_OP_TLBI_NH_VA:
+		cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT;
+		cmd[1] |= ent->tlbi.leaf ? CMDQ_TLBI_1_LEAF : 0;
+		cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK;
+		break;
+	case CMDQ_OP_TLBI_S2_IPA:
+		cmd[0] |= (u64)ent->tlbi.vmid << CMDQ_TLBI_0_VMID_SHIFT;
+		cmd[1] |= ent->tlbi.leaf ? CMDQ_TLBI_1_LEAF : 0;
+		cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK;
+		break;
+	case CMDQ_OP_TLBI_NH_ASID:
+		cmd[0] |= (u64)ent->tlbi.asid << CMDQ_TLBI_0_ASID_SHIFT;
+		/* Fallthrough */
+	case CMDQ_OP_TLBI_S12_VMALL:
+		cmd[0] |= (u64)ent->tlbi.vmid << CMDQ_TLBI_0_VMID_SHIFT;
+		break;
+	case CMDQ_OP_PRI_RESP:
+		cmd[0] |= ent->substream_valid ? CMDQ_0_SSV : 0;
+		cmd[0] |= ent->pri.ssid << CMDQ_PRI_0_SSID_SHIFT;
+		cmd[0] |= (u64)ent->pri.sid << CMDQ_PRI_0_SID_SHIFT;
+		cmd[1] |= ent->pri.grpid << CMDQ_PRI_1_GRPID_SHIFT;
+		switch (ent->pri.resp) {
+		case PRI_RESP_DENY:
+			cmd[1] |= CMDQ_PRI_1_RESP_DENY;
+			break;
+		case PRI_RESP_FAIL:
+			cmd[1] |= CMDQ_PRI_1_RESP_FAIL;
+			break;
+		case PRI_RESP_SUCC:
+			cmd[1] |= CMDQ_PRI_1_RESP_SUCC;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case CMDQ_OP_CMD_SYNC:
+		cmd[0] |= CMDQ_SYNC_0_CS_SEV;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
+{
+	static const char *cerror_str[] = {
+		[CMDQ_ERR_CERROR_NONE_IDX]	= "No error",
+		[CMDQ_ERR_CERROR_ILL_IDX]	= "Illegal command",
+		[CMDQ_ERR_CERROR_ABT_IDX]	= "Abort on command fetch",
+	};
+
+	int i;
+	u64 cmd[CMDQ_ENT_DWORDS];
+	struct arm_smmu_queue *q = &smmu->cmdq.q;
+	u32 cons = readl_relaxed(q->cons_reg);
+	u32 idx = cons >> CMDQ_ERR_SHIFT & CMDQ_ERR_MASK;
+	struct arm_smmu_cmdq_ent cmd_sync = {
+		.opcode = CMDQ_OP_CMD_SYNC,
+	};
+
+	dev_err(smmu->dev, "CMDQ error (cons 0x%08x): %s\n", cons,
+		idx < ARRAY_SIZE(cerror_str) ?  cerror_str[idx] : "Unknown");
+
+	switch (idx) {
+	case CMDQ_ERR_CERROR_ABT_IDX:
+		dev_err(smmu->dev, "retrying command fetch\n");
+	case CMDQ_ERR_CERROR_NONE_IDX:
+		return;
+	case CMDQ_ERR_CERROR_ILL_IDX:
+		/* Fallthrough */
+	default:
+		break;
+	}
+
+	/*
+	 * We may have concurrent producers, so we need to be careful
+	 * not to touch any of the shadow cmdq state.
+	 */
+	queue_read(cmd, Q_ENT(q, cons), q->ent_dwords);
+	dev_err(smmu->dev, "skipping command in error state:\n");
+	for (i = 0; i < ARRAY_SIZE(cmd); ++i)
+		dev_err(smmu->dev, "\t0x%016llx\n", (unsigned long long)cmd[i]);
+
+	/* Convert the erroneous command into a CMD_SYNC */
+	if (arm_smmu_cmdq_build_cmd(cmd, &cmd_sync)) {
+		dev_err(smmu->dev, "failed to convert to CMD_SYNC\n");
+		return;
+	}
+
+	queue_write(Q_ENT(q, cons), cmd, q->ent_dwords);
+}
+
+static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
+				    struct arm_smmu_cmdq_ent *ent)
+{
+	u64 cmd[CMDQ_ENT_DWORDS];
+	unsigned long flags;
+	bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV);
+	struct arm_smmu_queue *q = &smmu->cmdq.q;
+
+	if (arm_smmu_cmdq_build_cmd(cmd, ent)) {
+		dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n",
+			 ent->opcode);
+		return;
+	}
+
+	spin_lock_irqsave(&smmu->cmdq.lock, flags);
+	while (queue_insert_raw(q, cmd) == -ENOSPC) {
+		if (queue_poll_cons(q, false, wfe))
+			dev_err_ratelimited(smmu->dev, "CMDQ timeout\n");
+	}
+
+	if (ent->opcode == CMDQ_OP_CMD_SYNC && queue_poll_cons(q, true, wfe))
+		dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n");
+	spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
+}
+
+/* Context descriptor manipulation functions */
+static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
+{
+	u64 val = 0;
+
+	/* Repack the TCR. Just care about TTBR0 for now */
+	val |= ARM_SMMU_TCR2CD(tcr, T0SZ);
+	val |= ARM_SMMU_TCR2CD(tcr, TG0);
+	val |= ARM_SMMU_TCR2CD(tcr, IRGN0);
+	val |= ARM_SMMU_TCR2CD(tcr, ORGN0);
+	val |= ARM_SMMU_TCR2CD(tcr, SH0);
+	val |= ARM_SMMU_TCR2CD(tcr, EPD0);
+	val |= ARM_SMMU_TCR2CD(tcr, EPD1);
+	val |= ARM_SMMU_TCR2CD(tcr, IPS);
+	val |= ARM_SMMU_TCR2CD(tcr, TBI0);
+
+	return val;
+}
+
+static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
+				    struct arm_smmu_s1_cfg *cfg)
+{
+	u64 val;
+
+	/*
+	 * We don't need to issue any invalidation here, as we'll invalidate
+	 * the STE when installing the new entry anyway.
+	 */
+	val = arm_smmu_cpu_tcr_to_cd(cfg->cd.tcr) |
+#ifdef __BIG_ENDIAN
+	      CTXDESC_CD_0_ENDI |
+#endif
+	      CTXDESC_CD_0_R | CTXDESC_CD_0_A | CTXDESC_CD_0_ASET_PRIVATE |
+	      CTXDESC_CD_0_AA64 | (u64)cfg->cd.asid << CTXDESC_CD_0_ASID_SHIFT |
+	      CTXDESC_CD_0_V;
+	cfg->cdptr[0] = cpu_to_le64(val);
+
+	val = cfg->cd.ttbr & CTXDESC_CD_1_TTB0_MASK << CTXDESC_CD_1_TTB0_SHIFT;
+	cfg->cdptr[1] = cpu_to_le64(val);
+
+	cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair << CTXDESC_CD_3_MAIR_SHIFT);
+}
+
+/* Stream table manipulation functions */
+static void
+arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
+{
+	u64 val = 0;
+
+	val |= (desc->span & STRTAB_L1_DESC_SPAN_MASK)
+		<< STRTAB_L1_DESC_SPAN_SHIFT;
+	val |= desc->l2ptr_dma &
+	       STRTAB_L1_DESC_L2PTR_MASK << STRTAB_L1_DESC_L2PTR_SHIFT;
+
+	*dst = cpu_to_le64(val);
+}
+
+static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	struct arm_smmu_cmdq_ent cmd = {
+		.opcode	= CMDQ_OP_CFGI_STE,
+		.cfgi	= {
+			.sid	= sid,
+			.leaf	= true,
+		},
+	};
+
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+	cmd.opcode = CMDQ_OP_CMD_SYNC;
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+}
+
+static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
+				      __le64 *dst, struct arm_smmu_strtab_ent *ste)
+{
+	/*
+	 * This is hideously complicated, but we only really care about
+	 * three cases at the moment:
+	 *
+	 * 1. Invalid (all zero) -> bypass/fault (init)
+	 * 2. Bypass/fault -> translation/bypass (attach)
+	 * 3. Translation/bypass -> bypass/fault (detach)
+	 *
+	 * Given that we can't update the STE atomically and the SMMU
+	 * doesn't read the thing in a defined order, that leaves us
+	 * with the following maintenance requirements:
+	 *
+	 * 1. Update Config, return (init time STEs aren't live)
+	 * 2. Write everything apart from dword 0, sync, write dword 0, sync
+	 * 3. Update Config, sync
+	 */
+	u64 val = le64_to_cpu(dst[0]);
+	bool ste_live = false;
+	struct arm_smmu_cmdq_ent prefetch_cmd = {
+		.opcode		= CMDQ_OP_PREFETCH_CFG,
+		.prefetch	= {
+			.sid	= sid,
+		},
+	};
+
+	if (val & STRTAB_STE_0_V) {
+		u64 cfg;
+
+		cfg = val & STRTAB_STE_0_CFG_MASK << STRTAB_STE_0_CFG_SHIFT;
+		switch (cfg) {
+		case STRTAB_STE_0_CFG_BYPASS:
+			break;
+		case STRTAB_STE_0_CFG_S1_TRANS:
+		case STRTAB_STE_0_CFG_S2_TRANS:
+			ste_live = true;
+			break;
+		case STRTAB_STE_0_CFG_ABORT:
+			if (disable_bypass)
+				break;
+		default:
+			BUG(); /* STE corruption */
+		}
+	}
+
+	/* Nuke the existing STE_0 value, as we're going to rewrite it */
+	val = STRTAB_STE_0_V;
+
+	/* Bypass/fault */
+	if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) {
+		if (!ste->assigned && disable_bypass)
+			val |= STRTAB_STE_0_CFG_ABORT;
+		else
+			val |= STRTAB_STE_0_CFG_BYPASS;
+
+		dst[0] = cpu_to_le64(val);
+		dst[1] = cpu_to_le64(STRTAB_STE_1_SHCFG_INCOMING
+			 << STRTAB_STE_1_SHCFG_SHIFT);
+		dst[2] = 0; /* Nuke the VMID */
+		if (ste_live)
+			arm_smmu_sync_ste_for_sid(smmu, sid);
+		return;
+	}
+
+	if (ste->s1_cfg) {
+		BUG_ON(ste_live);
+		dst[1] = cpu_to_le64(
+			 STRTAB_STE_1_S1C_CACHE_WBRA
+			 << STRTAB_STE_1_S1CIR_SHIFT |
+			 STRTAB_STE_1_S1C_CACHE_WBRA
+			 << STRTAB_STE_1_S1COR_SHIFT |
+			 STRTAB_STE_1_S1C_SH_ISH << STRTAB_STE_1_S1CSH_SHIFT |
+#ifdef CONFIG_PCI_ATS
+			 STRTAB_STE_1_EATS_TRANS << STRTAB_STE_1_EATS_SHIFT |
+#endif
+			 STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT);
+
+		if (smmu->features & ARM_SMMU_FEAT_STALLS)
+			dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
+
+		val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK
+		        << STRTAB_STE_0_S1CTXPTR_SHIFT) |
+			STRTAB_STE_0_CFG_S1_TRANS;
+	}
+
+	if (ste->s2_cfg) {
+		BUG_ON(ste_live);
+		dst[2] = cpu_to_le64(
+			 ste->s2_cfg->vmid << STRTAB_STE_2_S2VMID_SHIFT |
+			 (ste->s2_cfg->vtcr & STRTAB_STE_2_VTCR_MASK)
+			  << STRTAB_STE_2_VTCR_SHIFT |
+#ifdef __BIG_ENDIAN
+			 STRTAB_STE_2_S2ENDI |
+#endif
+			 STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2AA64 |
+			 STRTAB_STE_2_S2R);
+
+		dst[3] = cpu_to_le64(ste->s2_cfg->vttbr &
+			 STRTAB_STE_3_S2TTB_MASK << STRTAB_STE_3_S2TTB_SHIFT);
+
+		val |= STRTAB_STE_0_CFG_S2_TRANS;
+	}
+
+	arm_smmu_sync_ste_for_sid(smmu, sid);
+	dst[0] = cpu_to_le64(val);
+	arm_smmu_sync_ste_for_sid(smmu, sid);
+
+	/* It's likely that we'll want to use the new STE soon */
+	if (!(smmu->options & ARM_SMMU_OPT_SKIP_PREFETCH))
+		arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
+}
+
+static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
+{
+	unsigned int i;
+	struct arm_smmu_strtab_ent ste = { .assigned = false };
+
+	for (i = 0; i < nent; ++i) {
+		arm_smmu_write_strtab_ent(NULL, -1, strtab, &ste);
+		strtab += STRTAB_STE_DWORDS;
+	}
+}
+
+static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+{
+	size_t size;
+	void *strtab;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
+
+	if (desc->l2ptr)
+		return 0;
+
+	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
+	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
+
+	desc->span = STRTAB_SPLIT + 1;
+	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
+					  GFP_KERNEL | __GFP_ZERO);
+	if (!desc->l2ptr) {
+		dev_err(smmu->dev,
+			"failed to allocate l2 stream table for SID %u\n",
+			sid);
+		return -ENOMEM;
+	}
+
+	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
+	arm_smmu_write_strtab_l1_desc(strtab, desc);
+	return 0;
+}
+
+/* IRQ and event handlers */
+static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
+{
+	int i;
+	struct arm_smmu_device *smmu = dev;
+	struct arm_smmu_queue *q = &smmu->evtq.q;
+	u64 evt[EVTQ_ENT_DWORDS];
+
+	do {
+		while (!queue_remove_raw(q, evt)) {
+			u8 id = evt[0] >> EVTQ_0_ID_SHIFT & EVTQ_0_ID_MASK;
+
+			dev_info(smmu->dev, "event 0x%02x received:\n", id);
+			for (i = 0; i < ARRAY_SIZE(evt); ++i)
+				dev_info(smmu->dev, "\t0x%016llx\n",
+					 (unsigned long long)evt[i]);
+
+		}
+
+		/*
+		 * Not much we can do on overflow, so scream and pretend we're
+		 * trying harder.
+		 */
+		if (queue_sync_prod(q) == -EOVERFLOW)
+			dev_err(smmu->dev, "EVTQ overflow detected -- events lost\n");
+	} while (!queue_empty(q));
+
+	/* Sync our overflow flag, as we believe we're up to speed */
+	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
+	return IRQ_HANDLED;
+}
+
+static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
+{
+	u32 sid, ssid;
+	u16 grpid;
+	bool ssv, last;
+
+	sid = evt[0] >> PRIQ_0_SID_SHIFT & PRIQ_0_SID_MASK;
+	ssv = evt[0] & PRIQ_0_SSID_V;
+	ssid = ssv ? evt[0] >> PRIQ_0_SSID_SHIFT & PRIQ_0_SSID_MASK : 0;
+	last = evt[0] & PRIQ_0_PRG_LAST;
+	grpid = evt[1] >> PRIQ_1_PRG_IDX_SHIFT & PRIQ_1_PRG_IDX_MASK;
+
+	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",
+		 sid, ssid, grpid, last ? "L" : "",
+		 evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
+		 evt[0] & PRIQ_0_PERM_READ ? "R" : "",
+		 evt[0] & PRIQ_0_PERM_WRITE ? "W" : "",
+		 evt[0] & PRIQ_0_PERM_EXEC ? "X" : "",
+		 evt[1] & PRIQ_1_ADDR_MASK << PRIQ_1_ADDR_SHIFT);
+
+	if (last) {
+		struct arm_smmu_cmdq_ent cmd = {
+			.opcode			= CMDQ_OP_PRI_RESP,
+			.substream_valid	= ssv,
+			.pri			= {
+				.sid	= sid,
+				.ssid	= ssid,
+				.grpid	= grpid,
+				.resp	= PRI_RESP_DENY,
+			},
+		};
+
+		arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+	}
+}
+
+static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
+{
+	struct arm_smmu_device *smmu = dev;
+	struct arm_smmu_queue *q = &smmu->priq.q;
+	u64 evt[PRIQ_ENT_DWORDS];
+
+	do {
+		while (!queue_remove_raw(q, evt))
+			arm_smmu_handle_ppr(smmu, evt);
+
+		if (queue_sync_prod(q) == -EOVERFLOW)
+			dev_err(smmu->dev, "PRIQ overflow detected -- requests lost\n");
+	} while (!queue_empty(q));
+
+	/* Sync our overflow flag, as we believe we're up to speed */
+	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t arm_smmu_cmdq_sync_handler(int irq, void *dev)
+{
+	/* We don't actually use CMD_SYNC interrupts for anything */
+	return IRQ_HANDLED;
+}
+
+static int arm_smmu_device_disable(struct arm_smmu_device *smmu);
+
+static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
+{
+	u32 gerror, gerrorn, active;
+	struct arm_smmu_device *smmu = dev;
+
+	gerror = readl_relaxed(smmu->base + ARM_SMMU_GERROR);
+	gerrorn = readl_relaxed(smmu->base + ARM_SMMU_GERRORN);
+
+	active = gerror ^ gerrorn;
+	if (!(active & GERROR_ERR_MASK))
+		return IRQ_NONE; /* No errors pending */
+
+	dev_warn(smmu->dev,
+		 "unexpected global error reported (0x%08x), this could be serious\n",
+		 active);
+
+	if (active & GERROR_SFM_ERR) {
+		dev_err(smmu->dev, "device has entered Service Failure Mode!\n");
+		arm_smmu_device_disable(smmu);
+	}
+
+	if (active & GERROR_MSI_GERROR_ABT_ERR)
+		dev_warn(smmu->dev, "GERROR MSI write aborted\n");
+
+	if (active & GERROR_MSI_PRIQ_ABT_ERR)
+		dev_warn(smmu->dev, "PRIQ MSI write aborted\n");
+
+	if (active & GERROR_MSI_EVTQ_ABT_ERR)
+		dev_warn(smmu->dev, "EVTQ MSI write aborted\n");
+
+	if (active & GERROR_MSI_CMDQ_ABT_ERR) {
+		dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
+		arm_smmu_cmdq_sync_handler(irq, smmu->dev);
+	}
+
+	if (active & GERROR_PRIQ_ABT_ERR)
+		dev_err(smmu->dev, "PRIQ write aborted -- events may have been lost\n");
+
+	if (active & GERROR_EVTQ_ABT_ERR)
+		dev_err(smmu->dev, "EVTQ write aborted -- events may have been lost\n");
+
+	if (active & GERROR_CMDQ_ERR)
+		arm_smmu_cmdq_skip_err(smmu);
+
+	writel(gerror, smmu->base + ARM_SMMU_GERRORN);
+	return IRQ_HANDLED;
+}
+
+/* IO_PGTABLE API */
+static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
+{
+	struct arm_smmu_cmdq_ent cmd;
+
+	cmd.opcode = CMDQ_OP_CMD_SYNC;
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+}
+
+static void arm_smmu_tlb_sync(void *cookie)
+{
+	struct arm_smmu_domain *smmu_domain = cookie;
+	__arm_smmu_tlb_sync(smmu_domain->smmu);
+}
+
+static void arm_smmu_tlb_inv_context(void *cookie)
+{
+	struct arm_smmu_domain *smmu_domain = cookie;
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_cmdq_ent cmd;
+
+	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
+		cmd.opcode	= CMDQ_OP_TLBI_NH_ASID;
+		cmd.tlbi.asid	= smmu_domain->s1_cfg.cd.asid;
+		cmd.tlbi.vmid	= 0;
+	} else {
+		cmd.opcode	= CMDQ_OP_TLBI_S12_VMALL;
+		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
+	}
+
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+	__arm_smmu_tlb_sync(smmu);
+}
+
+static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
+					  size_t granule, bool leaf, void *cookie)
+{
+	struct arm_smmu_domain *smmu_domain = cookie;
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_cmdq_ent cmd = {
+		.tlbi = {
+			.leaf	= leaf,
+			.addr	= iova,
+		},
+	};
+
+	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
+		cmd.opcode	= CMDQ_OP_TLBI_NH_VA;
+		cmd.tlbi.asid	= smmu_domain->s1_cfg.cd.asid;
+	} else {
+		cmd.opcode	= CMDQ_OP_TLBI_S2_IPA;
+		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
+	}
+
+	do {
+		arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+		cmd.tlbi.addr += granule;
+	} while (size -= granule);
+}
+
+static const struct iommu_gather_ops arm_smmu_gather_ops = {
+	.tlb_flush_all	= arm_smmu_tlb_inv_context,
+	.tlb_add_flush	= arm_smmu_tlb_inv_range_nosync,
+	.tlb_sync	= arm_smmu_tlb_sync,
+};
+
+/* IOMMU API */
+static bool arm_smmu_capable(enum iommu_cap cap)
+{
+	switch (cap) {
+	case IOMMU_CAP_CACHE_COHERENCY:
+		return true;
+	case IOMMU_CAP_NOEXEC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
+{
+	struct arm_smmu_domain *smmu_domain;
+
+	if (type != IOMMU_DOMAIN_UNMANAGED &&
+	    type != IOMMU_DOMAIN_DMA &&
+	    type != IOMMU_DOMAIN_IDENTITY)
+		return NULL;
+
+	/*
+	 * Allocate the domain and initialise some of its data structures.
+	 * We can't really do anything meaningful until we've added a
+	 * master.
+	 */
+	smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
+	if (!smmu_domain)
+		return NULL;
+
+	if (type == IOMMU_DOMAIN_DMA &&
+	    iommu_get_dma_cookie(&smmu_domain->domain)) {
+		kfree(smmu_domain);
+		return NULL;
+	}
+
+	mutex_init(&smmu_domain->init_mutex);
+	spin_lock_init(&smmu_domain->pgtbl_lock);
+	return &smmu_domain->domain;
+}
+
+static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
+{
+	int idx, size = 1 << span;
+
+	do {
+		idx = find_first_zero_bit(map, size);
+		if (idx == size)
+			return -ENOSPC;
+	} while (test_and_set_bit(idx, map));
+
+	return idx;
+}
+
+static void arm_smmu_bitmap_free(unsigned long *map, int idx)
+{
+	clear_bit(idx, map);
+}
+
+static void arm_smmu_domain_free(struct iommu_domain *domain)
+{
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+
+	iommu_put_dma_cookie(domain);
+	free_io_pgtable_ops(smmu_domain->pgtbl_ops);
+
+	/* Free the CD and ASID, if we allocated them */
+	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
+		struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
+
+		if (cfg->cdptr) {
+			dmam_free_coherent(smmu_domain->smmu->dev,
+					   CTXDESC_CD_DWORDS << 3,
+					   cfg->cdptr,
+					   cfg->cdptr_dma);
+
+			arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
+		}
+	} else {
+		struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
+		if (cfg->vmid)
+			arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
+	}
+
+	kfree(smmu_domain);
+}
+
+static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
+				       struct io_pgtable_cfg *pgtbl_cfg)
+{
+	int ret;
+	int asid;
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
+
+	asid = arm_smmu_bitmap_alloc(smmu->asid_map, smmu->asid_bits);
+	if (asid < 0)
+		return asid;
+
+	cfg->cdptr = dmam_alloc_coherent(smmu->dev, CTXDESC_CD_DWORDS << 3,
+					 &cfg->cdptr_dma,
+					 GFP_KERNEL | __GFP_ZERO);
+	if (!cfg->cdptr) {
+		dev_warn(smmu->dev, "failed to allocate context descriptor\n");
+		ret = -ENOMEM;
+		goto out_free_asid;
+	}
+
+	cfg->cd.asid	= (u16)asid;
+	cfg->cd.ttbr	= pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
+	cfg->cd.tcr	= pgtbl_cfg->arm_lpae_s1_cfg.tcr;
+	cfg->cd.mair	= pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
+	return 0;
+
+out_free_asid:
+	arm_smmu_bitmap_free(smmu->asid_map, asid);
+	return ret;
+}
+
+static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
+				       struct io_pgtable_cfg *pgtbl_cfg)
+{
+	int vmid;
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
+
+	vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
+	if (vmid < 0)
+		return vmid;
+
+	cfg->vmid	= (u16)vmid;
+	cfg->vttbr	= pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
+	cfg->vtcr	= pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
+	return 0;
+}
+
+static int arm_smmu_domain_finalise(struct iommu_domain *domain)
+{
+	int ret;
+	unsigned long ias, oas;
+	enum io_pgtable_fmt fmt;
+	struct io_pgtable_cfg pgtbl_cfg;
+	struct io_pgtable_ops *pgtbl_ops;
+	int (*finalise_stage_fn)(struct arm_smmu_domain *,
+				 struct io_pgtable_cfg *);
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+
+	if (domain->type == IOMMU_DOMAIN_IDENTITY) {
+		smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS;
+		return 0;
+	}
+
+	/* Restrict the stage to what we can actually support */
+	if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1))
+		smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
+	if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2))
+		smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
+
+	switch (smmu_domain->stage) {
+	case ARM_SMMU_DOMAIN_S1:
+		ias = VA_BITS;
+		oas = smmu->ias;
+		fmt = ARM_64_LPAE_S1;
+		finalise_stage_fn = arm_smmu_domain_finalise_s1;
+		break;
+	case ARM_SMMU_DOMAIN_NESTED:
+	case ARM_SMMU_DOMAIN_S2:
+		ias = smmu->ias;
+		oas = smmu->oas;
+		fmt = ARM_64_LPAE_S2;
+		finalise_stage_fn = arm_smmu_domain_finalise_s2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	pgtbl_cfg = (struct io_pgtable_cfg) {
+		.pgsize_bitmap	= smmu->pgsize_bitmap,
+		.ias		= ias,
+		.oas		= oas,
+		.tlb		= &arm_smmu_gather_ops,
+		.iommu_dev	= smmu->dev,
+	};
+
+	pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
+	if (!pgtbl_ops)
+		return -ENOMEM;
+
+	domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
+	domain->geometry.aperture_end = (1UL << ias) - 1;
+	domain->geometry.force_aperture = true;
+	smmu_domain->pgtbl_ops = pgtbl_ops;
+
+	ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
+	if (ret < 0)
+		free_io_pgtable_ops(pgtbl_ops);
+
+	return ret;
+}
+
+static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__le64 *step;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		struct arm_smmu_strtab_l1_desc *l1_desc;
+		int idx;
+
+		/* Two-level walk */
+		idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
+		l1_desc = &cfg->l1_desc[idx];
+		idx = (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_DWORDS;
+		step = &l1_desc->l2ptr[idx];
+	} else {
+		/* Simple linear lookup */
+		step = &cfg->strtab[sid * STRTAB_STE_DWORDS];
+	}
+
+	return step;
+}
+
+static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec)
+{
+	int i;
+	struct arm_smmu_master_data *master = fwspec->iommu_priv;
+	struct arm_smmu_device *smmu = master->smmu;
+
+	for (i = 0; i < fwspec->num_ids; ++i) {
+		u32 sid = fwspec->ids[i];
+		__le64 *step = arm_smmu_get_step_for_sid(smmu, sid);
+
+		arm_smmu_write_strtab_ent(smmu, sid, step, &master->ste);
+	}
+}
+
+static void arm_smmu_detach_dev(struct device *dev)
+{
+	struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv;
+
+	master->ste.assigned = false;
+	arm_smmu_install_ste_for_dev(dev->iommu_fwspec);
+}
+
+static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+	int ret = 0;
+	struct arm_smmu_device *smmu;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct arm_smmu_master_data *master;
+	struct arm_smmu_strtab_ent *ste;
+
+	if (!dev->iommu_fwspec)
+		return -ENOENT;
+
+	master = dev->iommu_fwspec->iommu_priv;
+	smmu = master->smmu;
+	ste = &master->ste;
+
+	/* Already attached to a different domain? */
+	if (ste->assigned)
+		arm_smmu_detach_dev(dev);
+
+	mutex_lock(&smmu_domain->init_mutex);
+
+	if (!smmu_domain->smmu) {
+		smmu_domain->smmu = smmu;
+		ret = arm_smmu_domain_finalise(domain);
+		if (ret) {
+			smmu_domain->smmu = NULL;
+			goto out_unlock;
+		}
+	} else if (smmu_domain->smmu != smmu) {
+		dev_err(dev,
+			"cannot attach to SMMU %s (upstream of %s)\n",
+			dev_name(smmu_domain->smmu->dev),
+			dev_name(smmu->dev));
+		ret = -ENXIO;
+		goto out_unlock;
+	}
+
+	ste->assigned = true;
+
+	if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS) {
+		ste->s1_cfg = NULL;
+		ste->s2_cfg = NULL;
+	} else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
+		ste->s1_cfg = &smmu_domain->s1_cfg;
+		ste->s2_cfg = NULL;
+		arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
+	} else {
+		ste->s1_cfg = NULL;
+		ste->s2_cfg = &smmu_domain->s2_cfg;
+	}
+
+	arm_smmu_install_ste_for_dev(dev->iommu_fwspec);
+out_unlock:
+	mutex_unlock(&smmu_domain->init_mutex);
+	return ret;
+}
+
+static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
+			phys_addr_t paddr, size_t size, int prot)
+{
+	int ret;
+	unsigned long flags;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+	if (!ops)
+		return -ENODEV;
+
+	spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+	ret = ops->map(ops, iova, paddr, size, prot);
+	spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
+	return ret;
+}
+
+static size_t
+arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
+{
+	size_t ret;
+	unsigned long flags;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+	if (!ops)
+		return 0;
+
+	spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+	ret = ops->unmap(ops, iova, size);
+	spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
+	return ret;
+}
+
+static phys_addr_t
+arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
+{
+	phys_addr_t ret;
+	unsigned long flags;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+	if (domain->type == IOMMU_DOMAIN_IDENTITY)
+		return iova;
+
+	if (!ops)
+		return 0;
+
+	spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+	ret = ops->iova_to_phys(ops, iova);
+	spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
+
+	return ret;
+}
+
+static struct platform_driver arm_smmu_driver;
+
+static int arm_smmu_match_node(struct device *dev, void *data)
+{
+	return dev->fwnode == data;
+}
+
+static
+struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
+						fwnode, arm_smmu_match_node);
+	put_device(dev);
+	return dev ? dev_get_drvdata(dev) : NULL;
+}
+
+static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
+{
+	unsigned long limit = smmu->strtab_cfg.num_l1_ents;
+
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
+		limit *= 1UL << STRTAB_SPLIT;
+
+	return sid < limit;
+}
+
+static struct iommu_ops arm_smmu_ops;
+
+static int arm_smmu_add_device(struct device *dev)
+{
+	int i, ret;
+	struct arm_smmu_device *smmu;
+	struct arm_smmu_master_data *master;
+	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+	struct iommu_group *group;
+
+	if (!fwspec || fwspec->ops != &arm_smmu_ops)
+		return -ENODEV;
+	/*
+	 * We _can_ actually withstand dodgy bus code re-calling add_device()
+	 * without an intervening remove_device()/of_xlate() sequence, but
+	 * we're not going to do so quietly...
+	 */
+	if (WARN_ON_ONCE(fwspec->iommu_priv)) {
+		master = fwspec->iommu_priv;
+		smmu = master->smmu;
+	} else {
+		smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
+		if (!smmu)
+			return -ENODEV;
+		master = kzalloc(sizeof(*master), GFP_KERNEL);
+		if (!master)
+			return -ENOMEM;
+
+		master->smmu = smmu;
+		fwspec->iommu_priv = master;
+	}
+
+	/* Check the SIDs are in range of the SMMU and our stream table */
+	for (i = 0; i < fwspec->num_ids; i++) {
+		u32 sid = fwspec->ids[i];
+
+		if (!arm_smmu_sid_in_range(smmu, sid))
+			return -ERANGE;
+
+		/* Ensure l2 strtab is initialised */
+		if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+			ret = arm_smmu_init_l2_strtab(smmu, sid);
+			if (ret)
+				return ret;
+		}
+	}
+
+	group = iommu_group_get_for_dev(dev);
+	if (!IS_ERR(group)) {
+		iommu_group_put(group);
+		iommu_device_link(&smmu->iommu, dev);
+	}
+
+	return PTR_ERR_OR_ZERO(group);
+}
+
+static void arm_smmu_remove_device(struct device *dev)
+{
+	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+	struct arm_smmu_master_data *master;
+	struct arm_smmu_device *smmu;
+
+	if (!fwspec || fwspec->ops != &arm_smmu_ops)
+		return;
+
+	master = fwspec->iommu_priv;
+	smmu = master->smmu;
+	if (master && master->ste.assigned)
+		arm_smmu_detach_dev(dev);
+	iommu_group_remove_device(dev);
+	iommu_device_unlink(&smmu->iommu, dev);
+	kfree(master);
+	iommu_fwspec_free(dev);
+}
+
+static struct iommu_group *arm_smmu_device_group(struct device *dev)
+{
+	struct iommu_group *group;
+
+	/*
+	 * We don't support devices sharing stream IDs other than PCI RID
+	 * aliases, since the necessary ID-to-device lookup becomes rather
+	 * impractical given a potential sparse 32-bit stream ID space.
+	 */
+	if (dev_is_pci(dev))
+		group = pci_device_group(dev);
+	else
+		group = generic_device_group(dev);
+
+	return group;
+}
+
+static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
+				    enum iommu_attr attr, void *data)
+{
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+	if (domain->type != IOMMU_DOMAIN_UNMANAGED)
+		return -EINVAL;
+
+	switch (attr) {
+	case DOMAIN_ATTR_NESTING:
+		*(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
+		return 0;
+	default:
+		return -ENODEV;
+	}
+}
+
+static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
+				    enum iommu_attr attr, void *data)
+{
+	int ret = 0;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+	if (domain->type != IOMMU_DOMAIN_UNMANAGED)
+		return -EINVAL;
+
+	mutex_lock(&smmu_domain->init_mutex);
+
+	switch (attr) {
+	case DOMAIN_ATTR_NESTING:
+		if (smmu_domain->smmu) {
+			ret = -EPERM;
+			goto out_unlock;
+		}
+
+		if (*(int *)data)
+			smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
+		else
+			smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
+
+		break;
+	default:
+		ret = -ENODEV;
+	}
+
+out_unlock:
+	mutex_unlock(&smmu_domain->init_mutex);
+	return ret;
+}
+
+static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+	return iommu_fwspec_add_ids(dev, args->args, 1);
+}
+
+static void arm_smmu_get_resv_regions(struct device *dev,
+				      struct list_head *head)
+{
+	struct iommu_resv_region *region;
+	int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+	region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
+					 prot, IOMMU_RESV_SW_MSI);
+	if (!region)
+		return;
+
+	list_add_tail(&region->list, head);
+
+	iommu_dma_get_resv_regions(dev, head);
+}
+
+static void arm_smmu_put_resv_regions(struct device *dev,
+				      struct list_head *head)
+{
+	struct iommu_resv_region *entry, *next;
+
+	list_for_each_entry_safe(entry, next, head, list)
+		kfree(entry);
+}
+
+static struct iommu_ops arm_smmu_ops = {
+	.capable		= arm_smmu_capable,
+	.domain_alloc		= arm_smmu_domain_alloc,
+	.domain_free		= arm_smmu_domain_free,
+	.attach_dev		= arm_smmu_attach_dev,
+	.map			= arm_smmu_map,
+	.unmap			= arm_smmu_unmap,
+	.map_sg			= default_iommu_map_sg,
+	.iova_to_phys		= arm_smmu_iova_to_phys,
+	.add_device		= arm_smmu_add_device,
+	.remove_device		= arm_smmu_remove_device,
+	.device_group		= arm_smmu_device_group,
+	.domain_get_attr	= arm_smmu_domain_get_attr,
+	.domain_set_attr	= arm_smmu_domain_set_attr,
+	.of_xlate		= arm_smmu_of_xlate,
+	.get_resv_regions	= arm_smmu_get_resv_regions,
+	.put_resv_regions	= arm_smmu_put_resv_regions,
+	.pgsize_bitmap		= -1UL, /* Restricted during device attach */
+};
+
+/* Probing and initialisation functions */
+static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
+				   struct arm_smmu_queue *q,
+				   unsigned long prod_off,
+				   unsigned long cons_off,
+				   size_t dwords)
+{
+	size_t qsz = ((1 << q->max_n_shift) * dwords) << 3;
+
+	q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL);
+	if (!q->base) {
+		dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes)\n",
+			qsz);
+		return -ENOMEM;
+	}
+
+	q->prod_reg	= smmu->base + prod_off;
+	q->cons_reg	= smmu->base + cons_off;
+	q->ent_dwords	= dwords;
+
+	q->q_base  = Q_BASE_RWA;
+	q->q_base |= q->base_dma & Q_BASE_ADDR_MASK << Q_BASE_ADDR_SHIFT;
+	q->q_base |= (q->max_n_shift & Q_BASE_LOG2SIZE_MASK)
+		     << Q_BASE_LOG2SIZE_SHIFT;
+
+	q->prod = q->cons = 0;
+	return 0;
+}
+
+static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
+{
+	int ret;
+
+	/* cmdq */
+	spin_lock_init(&smmu->cmdq.lock);
+	ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD,
+				      ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS);
+	if (ret)
+		return ret;
+
+	/* evtq */
+	ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD,
+				      ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS);
+	if (ret)
+		return ret;
+
+	/* priq */
+	if (!(smmu->features & ARM_SMMU_FEAT_PRI))
+		return 0;
+
+	return arm_smmu_init_one_queue(smmu, &smmu->priq.q, ARM_SMMU_PRIQ_PROD,
+				       ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS);
+}
+
+static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
+{
+	unsigned int i;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+	size_t size = sizeof(*cfg->l1_desc) * cfg->num_l1_ents;
+	void *strtab = smmu->strtab_cfg.strtab;
+
+	cfg->l1_desc = devm_kzalloc(smmu->dev, size, GFP_KERNEL);
+	if (!cfg->l1_desc) {
+		dev_err(smmu->dev, "failed to allocate l1 stream table desc\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < cfg->num_l1_ents; ++i) {
+		arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
+		strtab += STRTAB_L1_DESC_DWORDS << 3;
+	}
+
+	return 0;
+}
+
+static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
+{
+	void *strtab;
+	u64 reg;
+	u32 size, l1size;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	/* Calculate the L1 size, capped to the SIDSIZE. */
+	size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
+	size = min(size, smmu->sid_bits - STRTAB_SPLIT);
+	cfg->num_l1_ents = 1 << size;
+
+	size += STRTAB_SPLIT;
+	if (size < smmu->sid_bits)
+		dev_warn(smmu->dev,
+			 "2-level strtab only covers %u/%u bits of SID\n",
+			 size, smmu->sid_bits);
+
+	l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
+	strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
+				     GFP_KERNEL | __GFP_ZERO);
+	if (!strtab) {
+		dev_err(smmu->dev,
+			"failed to allocate l1 stream table (%u bytes)\n",
+			size);
+		return -ENOMEM;
+	}
+	cfg->strtab = strtab;
+
+	/* Configure strtab_base_cfg for 2 levels */
+	reg  = STRTAB_BASE_CFG_FMT_2LVL;
+	reg |= (size & STRTAB_BASE_CFG_LOG2SIZE_MASK)
+		<< STRTAB_BASE_CFG_LOG2SIZE_SHIFT;
+	reg |= (STRTAB_SPLIT & STRTAB_BASE_CFG_SPLIT_MASK)
+		<< STRTAB_BASE_CFG_SPLIT_SHIFT;
+	cfg->strtab_base_cfg = reg;
+
+	return arm_smmu_init_l1_strtab(smmu);
+}
+
+static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
+{
+	void *strtab;
+	u64 reg;
+	u32 size;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3);
+	strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma,
+				     GFP_KERNEL | __GFP_ZERO);
+	if (!strtab) {
+		dev_err(smmu->dev,
+			"failed to allocate linear stream table (%u bytes)\n",
+			size);
+		return -ENOMEM;
+	}
+	cfg->strtab = strtab;
+	cfg->num_l1_ents = 1 << smmu->sid_bits;
+
+	/* Configure strtab_base_cfg for a linear table covering all SIDs */
+	reg  = STRTAB_BASE_CFG_FMT_LINEAR;
+	reg |= (smmu->sid_bits & STRTAB_BASE_CFG_LOG2SIZE_MASK)
+		<< STRTAB_BASE_CFG_LOG2SIZE_SHIFT;
+	cfg->strtab_base_cfg = reg;
+
+	arm_smmu_init_bypass_stes(strtab, cfg->num_l1_ents);
+	return 0;
+}
+
+static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
+{
+	u64 reg;
+	int ret;
+
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
+		ret = arm_smmu_init_strtab_2lvl(smmu);
+	else
+		ret = arm_smmu_init_strtab_linear(smmu);
+
+	if (ret)
+		return ret;
+
+	/* Set the strtab base address */
+	reg  = smmu->strtab_cfg.strtab_dma &
+	       STRTAB_BASE_ADDR_MASK << STRTAB_BASE_ADDR_SHIFT;
+	reg |= STRTAB_BASE_RA;
+	smmu->strtab_cfg.strtab_base = reg;
+
+	/* Allocate the first VMID for stage-2 bypass STEs */
+	set_bit(0, smmu->vmid_map);
+	return 0;
+}
+
+static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
+{
+	int ret;
+
+	ret = arm_smmu_init_queues(smmu);
+	if (ret)
+		return ret;
+
+	return arm_smmu_init_strtab(smmu);
+}
+
+static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val,
+				   unsigned int reg_off, unsigned int ack_off)
+{
+	u32 reg;
+
+	writel_relaxed(val, smmu->base + reg_off);
+	return readl_relaxed_poll_timeout(smmu->base + ack_off, reg, reg == val,
+					  1, ARM_SMMU_POLL_TIMEOUT_US);
+}
+
+/* GBPA is "special" */
+static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
+{
+	int ret;
+	u32 reg, __iomem *gbpa = smmu->base + ARM_SMMU_GBPA;
+
+	ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
+					 1, ARM_SMMU_POLL_TIMEOUT_US);
+	if (ret)
+		return ret;
+
+	reg &= ~clr;
+	reg |= set;
+	writel_relaxed(reg | GBPA_UPDATE, gbpa);
+	return readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
+					  1, ARM_SMMU_POLL_TIMEOUT_US);
+}
+
+static void arm_smmu_free_msis(void *data)
+{
+	struct device *dev = data;
+	platform_msi_domain_free_irqs(dev);
+}
+
+static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+	phys_addr_t doorbell;
+	struct device *dev = msi_desc_to_dev(desc);
+	struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+	phys_addr_t *cfg = arm_smmu_msi_cfg[desc->platform.msi_index];
+
+	doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo;
+	doorbell &= MSI_CFG0_ADDR_MASK << MSI_CFG0_ADDR_SHIFT;
+
+	writeq_relaxed(doorbell, smmu->base + cfg[0]);
+	writel_relaxed(msg->data, smmu->base + cfg[1]);
+	writel_relaxed(MSI_CFG2_MEMATTR_DEVICE_nGnRE, smmu->base + cfg[2]);
+}
+
+static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
+{
+	struct msi_desc *desc;
+	int ret, nvec = ARM_SMMU_MAX_MSIS;
+	struct device *dev = smmu->dev;
+
+	/* Clear the MSI address regs */
+	writeq_relaxed(0, smmu->base + ARM_SMMU_GERROR_IRQ_CFG0);
+	writeq_relaxed(0, smmu->base + ARM_SMMU_EVTQ_IRQ_CFG0);
+
+	if (smmu->features & ARM_SMMU_FEAT_PRI)
+		writeq_relaxed(0, smmu->base + ARM_SMMU_PRIQ_IRQ_CFG0);
+	else
+		nvec--;
+
+	if (!(smmu->features & ARM_SMMU_FEAT_MSI))
+		return;
+
+	/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
+	ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
+	if (ret) {
+		dev_warn(dev, "failed to allocate MSIs\n");
+		return;
+	}
+
+	for_each_msi_entry(desc, dev) {
+		switch (desc->platform.msi_index) {
+		case EVTQ_MSI_INDEX:
+			smmu->evtq.q.irq = desc->irq;
+			break;
+		case GERROR_MSI_INDEX:
+			smmu->gerr_irq = desc->irq;
+			break;
+		case PRIQ_MSI_INDEX:
+			smmu->priq.q.irq = desc->irq;
+			break;
+		default:	/* Unknown */
+			continue;
+		}
+	}
+
+	/* Add callback to free MSIs on teardown */
+	devm_add_action(dev, arm_smmu_free_msis, dev);
+}
+
+static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
+{
+	int ret, irq;
+	u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
+
+	/* Disable IRQs first */
+	ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL,
+				      ARM_SMMU_IRQ_CTRLACK);
+	if (ret) {
+		dev_err(smmu->dev, "failed to disable irqs\n");
+		return ret;
+	}
+
+	arm_smmu_setup_msis(smmu);
+
+	/* Request interrupt lines */
+	irq = smmu->evtq.q.irq;
+	if (irq) {
+		ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
+						arm_smmu_evtq_thread,
+						IRQF_ONESHOT,
+						"arm-smmu-v3-evtq", smmu);
+		if (ret < 0)
+			dev_warn(smmu->dev, "failed to enable evtq irq\n");
+	}
+
+	irq = smmu->cmdq.q.irq;
+	if (irq) {
+		ret = devm_request_irq(smmu->dev, irq,
+				       arm_smmu_cmdq_sync_handler, 0,
+				       "arm-smmu-v3-cmdq-sync", smmu);
+		if (ret < 0)
+			dev_warn(smmu->dev, "failed to enable cmdq-sync irq\n");
+	}
+
+	irq = smmu->gerr_irq;
+	if (irq) {
+		ret = devm_request_irq(smmu->dev, irq, arm_smmu_gerror_handler,
+				       0, "arm-smmu-v3-gerror", smmu);
+		if (ret < 0)
+			dev_warn(smmu->dev, "failed to enable gerror irq\n");
+	}
+
+	if (smmu->features & ARM_SMMU_FEAT_PRI) {
+		irq = smmu->priq.q.irq;
+		if (irq) {
+			ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
+							arm_smmu_priq_thread,
+							IRQF_ONESHOT,
+							"arm-smmu-v3-priq",
+							smmu);
+			if (ret < 0)
+				dev_warn(smmu->dev,
+					 "failed to enable priq irq\n");
+			else
+				irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
+		}
+	}
+
+	/* Enable interrupt generation on the SMMU */
+	ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
+				      ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK);
+	if (ret)
+		dev_warn(smmu->dev, "failed to enable irqs\n");
+
+	return 0;
+}
+
+static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
+{
+	int ret;
+
+	ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_CR0, ARM_SMMU_CR0ACK);
+	if (ret)
+		dev_err(smmu->dev, "failed to clear cr0\n");
+
+	return ret;
+}
+
+static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
+{
+	int ret;
+	u32 reg, enables;
+	struct arm_smmu_cmdq_ent cmd;
+
+	/* Clear CR0 and sync (disables SMMU and queue processing) */
+	reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
+	if (reg & CR0_SMMUEN)
+		dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
+
+	ret = arm_smmu_device_disable(smmu);
+	if (ret)
+		return ret;
+
+	/* CR1 (table and queue memory attributes) */
+	reg = (CR1_SH_ISH << CR1_TABLE_SH_SHIFT) |
+	      (CR1_CACHE_WB << CR1_TABLE_OC_SHIFT) |
+	      (CR1_CACHE_WB << CR1_TABLE_IC_SHIFT) |
+	      (CR1_SH_ISH << CR1_QUEUE_SH_SHIFT) |
+	      (CR1_CACHE_WB << CR1_QUEUE_OC_SHIFT) |
+	      (CR1_CACHE_WB << CR1_QUEUE_IC_SHIFT);
+	writel_relaxed(reg, smmu->base + ARM_SMMU_CR1);
+
+	/* CR2 (random crap) */
+	reg = CR2_PTM | CR2_RECINVSID | CR2_E2H;
+	writel_relaxed(reg, smmu->base + ARM_SMMU_CR2);
+
+	/* Stream table */
+	writeq_relaxed(smmu->strtab_cfg.strtab_base,
+		       smmu->base + ARM_SMMU_STRTAB_BASE);
+	writel_relaxed(smmu->strtab_cfg.strtab_base_cfg,
+		       smmu->base + ARM_SMMU_STRTAB_BASE_CFG);
+
+	/* Command queue */
+	writeq_relaxed(smmu->cmdq.q.q_base, smmu->base + ARM_SMMU_CMDQ_BASE);
+	writel_relaxed(smmu->cmdq.q.prod, smmu->base + ARM_SMMU_CMDQ_PROD);
+	writel_relaxed(smmu->cmdq.q.cons, smmu->base + ARM_SMMU_CMDQ_CONS);
+
+	enables = CR0_CMDQEN;
+	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
+				      ARM_SMMU_CR0ACK);
+	if (ret) {
+		dev_err(smmu->dev, "failed to enable command queue\n");
+		return ret;
+	}
+
+	/* Invalidate any cached configuration */
+	cmd.opcode = CMDQ_OP_CFGI_ALL;
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+	cmd.opcode = CMDQ_OP_CMD_SYNC;
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+
+	/* Invalidate any stale TLB entries */
+	if (smmu->features & ARM_SMMU_FEAT_HYP) {
+		cmd.opcode = CMDQ_OP_TLBI_EL2_ALL;
+		arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+	}
+
+	cmd.opcode = CMDQ_OP_TLBI_NSNH_ALL;
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+	cmd.opcode = CMDQ_OP_CMD_SYNC;
+	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+
+	/* Event queue */
+	writeq_relaxed(smmu->evtq.q.q_base, smmu->base + ARM_SMMU_EVTQ_BASE);
+	writel_relaxed(smmu->evtq.q.prod, smmu->base + ARM_SMMU_EVTQ_PROD);
+	writel_relaxed(smmu->evtq.q.cons, smmu->base + ARM_SMMU_EVTQ_CONS);
+
+	enables |= CR0_EVTQEN;
+	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
+				      ARM_SMMU_CR0ACK);
+	if (ret) {
+		dev_err(smmu->dev, "failed to enable event queue\n");
+		return ret;
+	}
+
+	/* PRI queue */
+	if (smmu->features & ARM_SMMU_FEAT_PRI) {
+		writeq_relaxed(smmu->priq.q.q_base,
+			       smmu->base + ARM_SMMU_PRIQ_BASE);
+		writel_relaxed(smmu->priq.q.prod,
+			       smmu->base + ARM_SMMU_PRIQ_PROD);
+		writel_relaxed(smmu->priq.q.cons,
+			       smmu->base + ARM_SMMU_PRIQ_CONS);
+
+		enables |= CR0_PRIQEN;
+		ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
+					      ARM_SMMU_CR0ACK);
+		if (ret) {
+			dev_err(smmu->dev, "failed to enable PRI queue\n");
+			return ret;
+		}
+	}
+
+	ret = arm_smmu_setup_irqs(smmu);
+	if (ret) {
+		dev_err(smmu->dev, "failed to setup irqs\n");
+		return ret;
+	}
+
+
+	/* Enable the SMMU interface, or ensure bypass */
+	if (!bypass || disable_bypass) {
+		enables |= CR0_SMMUEN;
+	} else {
+		ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
+		if (ret) {
+			dev_err(smmu->dev, "GBPA not responding to update\n");
+			return ret;
+		}
+	}
+	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
+				      ARM_SMMU_CR0ACK);
+	if (ret) {
+		dev_err(smmu->dev, "failed to enable SMMU interface\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
+{
+	u32 reg;
+	bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY;
+
+	/* IDR0 */
+	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
+
+	/* 2-level structures */
+	if ((reg & IDR0_ST_LVL_MASK << IDR0_ST_LVL_SHIFT) == IDR0_ST_LVL_2LVL)
+		smmu->features |= ARM_SMMU_FEAT_2_LVL_STRTAB;
+
+	if (reg & IDR0_CD2L)
+		smmu->features |= ARM_SMMU_FEAT_2_LVL_CDTAB;
+
+	/*
+	 * Translation table endianness.
+	 * We currently require the same endianness as the CPU, but this
+	 * could be changed later by adding a new IO_PGTABLE_QUIRK.
+	 */
+	switch (reg & IDR0_TTENDIAN_MASK << IDR0_TTENDIAN_SHIFT) {
+	case IDR0_TTENDIAN_MIXED:
+		smmu->features |= ARM_SMMU_FEAT_TT_LE | ARM_SMMU_FEAT_TT_BE;
+		break;
+#ifdef __BIG_ENDIAN
+	case IDR0_TTENDIAN_BE:
+		smmu->features |= ARM_SMMU_FEAT_TT_BE;
+		break;
+#else
+	case IDR0_TTENDIAN_LE:
+		smmu->features |= ARM_SMMU_FEAT_TT_LE;
+		break;
+#endif
+	default:
+		dev_err(smmu->dev, "unknown/unsupported TT endianness!\n");
+		return -ENXIO;
+	}
+
+	/* Boolean feature flags */
+	if (IS_ENABLED(CONFIG_PCI_PRI) && reg & IDR0_PRI)
+		smmu->features |= ARM_SMMU_FEAT_PRI;
+
+	if (IS_ENABLED(CONFIG_PCI_ATS) && reg & IDR0_ATS)
+		smmu->features |= ARM_SMMU_FEAT_ATS;
+
+	if (reg & IDR0_SEV)
+		smmu->features |= ARM_SMMU_FEAT_SEV;
+
+	if (reg & IDR0_MSI)
+		smmu->features |= ARM_SMMU_FEAT_MSI;
+
+	if (reg & IDR0_HYP)
+		smmu->features |= ARM_SMMU_FEAT_HYP;
+
+	/*
+	 * The coherency feature as set by FW is used in preference to the ID
+	 * register, but warn on mismatch.
+	 */
+	if (!!(reg & IDR0_COHACC) != coherent)
+		dev_warn(smmu->dev, "IDR0.COHACC overridden by dma-coherent property (%s)\n",
+			 coherent ? "true" : "false");
+
+	switch (reg & IDR0_STALL_MODEL_MASK << IDR0_STALL_MODEL_SHIFT) {
+	case IDR0_STALL_MODEL_STALL:
+		/* Fallthrough */
+	case IDR0_STALL_MODEL_FORCE:
+		smmu->features |= ARM_SMMU_FEAT_STALLS;
+	}
+
+	if (reg & IDR0_S1P)
+		smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
+
+	if (reg & IDR0_S2P)
+		smmu->features |= ARM_SMMU_FEAT_TRANS_S2;
+
+	if (!(reg & (IDR0_S1P | IDR0_S2P))) {
+		dev_err(smmu->dev, "no translation support!\n");
+		return -ENXIO;
+	}
+
+	/* We only support the AArch64 table format at present */
+	switch (reg & IDR0_TTF_MASK << IDR0_TTF_SHIFT) {
+	case IDR0_TTF_AARCH32_64:
+		smmu->ias = 40;
+		/* Fallthrough */
+	case IDR0_TTF_AARCH64:
+		break;
+	default:
+		dev_err(smmu->dev, "AArch64 table format not supported!\n");
+		return -ENXIO;
+	}
+
+	/* ASID/VMID sizes */
+	smmu->asid_bits = reg & IDR0_ASID16 ? 16 : 8;
+	smmu->vmid_bits = reg & IDR0_VMID16 ? 16 : 8;
+
+	/* IDR1 */
+	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR1);
+	if (reg & (IDR1_TABLES_PRESET | IDR1_QUEUES_PRESET | IDR1_REL)) {
+		dev_err(smmu->dev, "embedded implementation not supported\n");
+		return -ENXIO;
+	}
+
+	/* Queue sizes, capped at 4k */
+	smmu->cmdq.q.max_n_shift = min((u32)CMDQ_MAX_SZ_SHIFT,
+				       reg >> IDR1_CMDQ_SHIFT & IDR1_CMDQ_MASK);
+	if (!smmu->cmdq.q.max_n_shift) {
+		/* Odd alignment restrictions on the base, so ignore for now */
+		dev_err(smmu->dev, "unit-length command queue not supported\n");
+		return -ENXIO;
+	}
+
+	smmu->evtq.q.max_n_shift = min((u32)EVTQ_MAX_SZ_SHIFT,
+				       reg >> IDR1_EVTQ_SHIFT & IDR1_EVTQ_MASK);
+	smmu->priq.q.max_n_shift = min((u32)PRIQ_MAX_SZ_SHIFT,
+				       reg >> IDR1_PRIQ_SHIFT & IDR1_PRIQ_MASK);
+
+	/* SID/SSID sizes */
+	smmu->ssid_bits = reg >> IDR1_SSID_SHIFT & IDR1_SSID_MASK;
+	smmu->sid_bits = reg >> IDR1_SID_SHIFT & IDR1_SID_MASK;
+
+	/*
+	 * If the SMMU supports fewer bits than would fill a single L2 stream
+	 * table, use a linear table instead.
+	 */
+	if (smmu->sid_bits <= STRTAB_SPLIT)
+		smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB;
+
+	/* IDR5 */
+	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
+
+	/* Maximum number of outstanding stalls */
+	smmu->evtq.max_stalls = reg >> IDR5_STALL_MAX_SHIFT
+				& IDR5_STALL_MAX_MASK;
+
+	/* Page sizes */
+	if (reg & IDR5_GRAN64K)
+		smmu->pgsize_bitmap |= SZ_64K | SZ_512M;
+	if (reg & IDR5_GRAN16K)
+		smmu->pgsize_bitmap |= SZ_16K | SZ_32M;
+	if (reg & IDR5_GRAN4K)
+		smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
+
+	if (arm_smmu_ops.pgsize_bitmap == -1UL)
+		arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
+	else
+		arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
+
+	/* Output address size */
+	switch (reg & IDR5_OAS_MASK << IDR5_OAS_SHIFT) {
+	case IDR5_OAS_32_BIT:
+		smmu->oas = 32;
+		break;
+	case IDR5_OAS_36_BIT:
+		smmu->oas = 36;
+		break;
+	case IDR5_OAS_40_BIT:
+		smmu->oas = 40;
+		break;
+	case IDR5_OAS_42_BIT:
+		smmu->oas = 42;
+		break;
+	case IDR5_OAS_44_BIT:
+		smmu->oas = 44;
+		break;
+	default:
+		dev_info(smmu->dev,
+			"unknown output address size. Truncating to 48-bit\n");
+		/* Fallthrough */
+	case IDR5_OAS_48_BIT:
+		smmu->oas = 48;
+	}
+
+	/* Set the DMA mask for our table walker */
+	if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas)))
+		dev_warn(smmu->dev,
+			 "failed to set DMA mask for table walker\n");
+
+	smmu->ias = max(smmu->ias, smmu->oas);
+
+	dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n",
+		 smmu->ias, smmu->oas, smmu->features);
+	return 0;
+}
+
+#ifdef CONFIG_ACPI
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+				      struct arm_smmu_device *smmu)
+{
+	struct acpi_iort_smmu_v3 *iort_smmu;
+	struct device *dev = smmu->dev;
+	struct acpi_iort_node *node;
+
+	node = *(struct acpi_iort_node **)dev_get_platdata(dev);
+
+	/* Retrieve SMMUv3 specific data */
+	iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+	if (iort_smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE)
+		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+
+	return 0;
+}
+#else
+static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+					     struct arm_smmu_device *smmu)
+{
+	return -ENODEV;
+}
+#endif
+
+static int arm_smmu_device_dt_probe(struct platform_device *pdev,
+				    struct arm_smmu_device *smmu)
+{
+	struct device *dev = &pdev->dev;
+	u32 cells;
+	int ret = -EINVAL;
+
+	if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
+		dev_err(dev, "missing #iommu-cells property\n");
+	else if (cells != 1)
+		dev_err(dev, "invalid #iommu-cells value (%d)\n", cells);
+	else
+		ret = 0;
+
+	parse_driver_options(smmu);
+
+	if (of_dma_is_coherent(dev->of_node))
+		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+
+	return ret;
+}
+
+static int arm_smmu_device_probe(struct platform_device *pdev)
+{
+	int irq, ret;
+	struct resource *res;
+	resource_size_t ioaddr;
+	struct arm_smmu_device *smmu;
+	struct device *dev = &pdev->dev;
+	bool bypass;
+
+	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+	if (!smmu) {
+		dev_err(dev, "failed to allocate arm_smmu_device\n");
+		return -ENOMEM;
+	}
+	smmu->dev = dev;
+
+	/* Base address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (resource_size(res) + 1 < SZ_128K) {
+		dev_err(dev, "MMIO region too small (%pr)\n", res);
+		return -EINVAL;
+	}
+	ioaddr = res->start;
+
+	smmu->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(smmu->base))
+		return PTR_ERR(smmu->base);
+
+	/* Interrupt lines */
+	irq = platform_get_irq_byname(pdev, "eventq");
+	if (irq > 0)
+		smmu->evtq.q.irq = irq;
+
+	irq = platform_get_irq_byname(pdev, "priq");
+	if (irq > 0)
+		smmu->priq.q.irq = irq;
+
+	irq = platform_get_irq_byname(pdev, "cmdq-sync");
+	if (irq > 0)
+		smmu->cmdq.q.irq = irq;
+
+	irq = platform_get_irq_byname(pdev, "gerror");
+	if (irq > 0)
+		smmu->gerr_irq = irq;
+
+	if (dev->of_node) {
+		ret = arm_smmu_device_dt_probe(pdev, smmu);
+	} else {
+		ret = arm_smmu_device_acpi_probe(pdev, smmu);
+		if (ret == -ENODEV)
+			return ret;
+	}
+
+	/* Set bypass mode according to firmware probing result */
+	bypass = !!ret;
+
+	/* Probe the h/w */
+	ret = arm_smmu_device_hw_probe(smmu);
+	if (ret)
+		return ret;
+
+	/* Initialise in-memory data structures */
+	ret = arm_smmu_init_structures(smmu);
+	if (ret)
+		return ret;
+
+	/* Record our private device structure */
+	platform_set_drvdata(pdev, smmu);
+
+	/* Reset the device */
+	ret = arm_smmu_device_reset(smmu, bypass);
+	if (ret)
+		return ret;
+
+	/* And we're up. Go go go! */
+	ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
+				     "smmu3.%pa", &ioaddr);
+	if (ret)
+		return ret;
+
+	iommu_device_set_ops(&smmu->iommu, &arm_smmu_ops);
+	iommu_device_set_fwnode(&smmu->iommu, dev->fwnode);
+
+	ret = iommu_device_register(&smmu->iommu);
+
+#ifdef CONFIG_PCI
+	if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
+		pci_request_acs();
+		ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
+		if (ret)
+			return ret;
+	}
+#endif
+#ifdef CONFIG_ARM_AMBA
+	if (amba_bustype.iommu_ops != &arm_smmu_ops) {
+		ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+		if (ret)
+			return ret;
+	}
+#endif
+	if (platform_bus_type.iommu_ops != &arm_smmu_ops) {
+		ret = bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int arm_smmu_device_remove(struct platform_device *pdev)
+{
+	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+
+	arm_smmu_device_disable(smmu);
+	return 0;
+}
+
+static struct of_device_id arm_smmu_of_match[] = {
+	{ .compatible = "arm,smmu-v3", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+
+static struct platform_driver arm_smmu_driver = {
+	.driver	= {
+		.name		= "arm-smmu-v3",
+		.of_match_table	= of_match_ptr(arm_smmu_of_match),
+	},
+	.probe	= arm_smmu_device_probe,
+	.remove	= arm_smmu_device_remove,
+};
+module_platform_driver(arm_smmu_driver);
+
+IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", NULL);
+
+MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
+MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
+MODULE_LICENSE("GPL v2");
-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
                   ` (5 preceding siblings ...)
  2017-09-21  0:37 ` [RFC v2 6/7] Add verbatim copy of arm-smmu-v3.c from Linux Sameer Goel
@ 2017-09-21  0:37 ` Sameer Goel
  2017-09-26  0:03   ` Goel, Sameer
  2017-10-12 16:36   ` Julien Grall
  2017-09-21  5:43 ` [RFC v2 0/7] SMMUv3 driver and the supporting framework Manish Jaggi
  7 siblings, 2 replies; 34+ messages in thread
From: Sameer Goel @ 2017-09-21  0:37 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Sameer Goel, Ian.Jackson, nd, robin.murphy, shankerd

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 */

Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
---
 xen/drivers/passthrough/arm/Makefile  |   1 +
 xen/drivers/passthrough/arm/smmu-v3.c | 853 +++++++++++++++++++++++++++++-----
 2 files changed, 738 insertions(+), 116 deletions(-)

diff --git a/xen/drivers/passthrough/arm/Makefile b/xen/drivers/passthrough/arm/Makefile
index f4cd26e..57a6da6 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-y += smmu-v3.o
diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
index 380969a..8f3b43d 100644
--- a/xen/drivers/passthrough/arm/smmu-v3.c
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
@@ -18,28 +18,266 @@
  * Author: Will Deacon <will.deacon@arm.com>
  *
  * This driver is powered by bad coffee and bombay mix.
+ *
+ *
+ * Based on Linux drivers/iommu/arm-smmu-v3.c
+ * => commit bdf95923086fb359ccb44c815724c3ace1611c90
+ *
+ * Xen modifications:
+ * Sameer Goel <sgoel@codeaurora.org>
+ * Copyright (C) 2017, The Linux Foundation, All rights reserved.
+ *
  */
 
-#include <linux/acpi.h>
-#include <linux/acpi_iort.h>
-#include <linux/delay.h>
-#include <linux/dma-iommu.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/iommu.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/msi.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_iommu.h>
-#include <linux/of_platform.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-
-#include <linux/amba/bus.h>
-
-#include "io-pgtable.h"
+#include <xen/config.h>
+#include <xen/delay.h>
+#include <xen/errno.h>
+#include <xen/err.h>
+#include <xen/irq.h>
+#include <xen/lib.h>
+#include <xen/list.h>
+#include <xen/mm.h>
+#include <xen/vmap.h>
+#include <xen/rbtree.h>
+#include <xen/sched.h>
+#include <xen/sizes.h>
+#include <asm/atomic.h>
+#include <asm/device.h>
+#include <asm/io.h>
+#include <asm/platform.h>
+#include <xen/acpi.h>
+
+typedef paddr_t phys_addr_t;
+typedef paddr_t dma_addr_t;
+
+/* Alias to Xen device tree helpers */
+#define device_node dt_device_node
+#define of_phandle_args dt_phandle_args
+#define of_device_id dt_device_match
+#define of_match_node dt_match_node
+#define of_property_read_u32(np, pname, out) (!dt_property_read_u32(np, pname, out))
+#define of_property_read_bool dt_property_read_bool
+#define of_parse_phandle_with_args dt_parse_phandle_with_args
+#define mutex spinlock_t
+#define mutex_init spin_lock_init
+#define mutex_lock spin_lock
+#define mutex_unlock spin_unlock
+
+/* Xen: Helpers to get device MMIO and IRQs */
+struct resource {
+	u64 addr;
+	u64 size;
+	unsigned int type;
+};
+
+#define resource_size(res) ((res)->size)
+
+#define platform_device device
+
+#define IORESOURCE_MEM 0
+#define IORESOURCE_IRQ 1
+
+static struct resource *platform_get_resource(struct platform_device *pdev,
+					      unsigned int type,
+					      unsigned int num)
+{
+	/*
+	 * The resource is only used between 2 calls of platform_get_resource.
+	 * It's quite ugly but it's avoid to add too much code in the part
+	 * imported from Linux
+	 */
+	static struct resource res;
+	struct acpi_iort_node *iort_node;
+	struct acpi_iort_smmu_v3 *node_smmu_data;
+	int ret = 0;
+
+	res.type = type;
+
+	switch (type) {
+	case IORESOURCE_MEM:
+		if (pdev->type == DEV_ACPI) {
+			ret = 1;
+			iort_node = pdev->acpi_node;
+			node_smmu_data =
+				(struct acpi_iort_smmu_v3 *)iort_node->node_data;
+
+			if (node_smmu_data != NULL) {
+				res.addr = node_smmu_data->base_address;
+				res.size = SZ_128K;
+				ret = 0;
+			}
+		} else {
+			ret = dt_device_get_address(dev_to_dt(pdev), num,
+						    &res.addr, &res.size);
+		}
+
+		return ((ret) ? NULL : &res);
+
+	case IORESOURCE_IRQ:
+		ret = platform_get_irq(dev_to_dt(pdev), num);
+
+		if (ret < 0)
+			return NULL;
+
+		res.addr = ret;
+		res.size = 1;
+
+		return &res;
+
+	default:
+		return NULL;
+	}
+}
+
+static int platform_get_irq_byname(struct platform_device *pdev, const char *name)
+{
+	const struct dt_property *dtprop;
+	struct acpi_iort_node *iort_node;
+	struct acpi_iort_smmu_v3 *node_smmu_data;
+	int ret = 0;
+
+	if (pdev->type == DEV_ACPI) {
+		iort_node = pdev->acpi_node;
+		node_smmu_data = (struct acpi_iort_smmu_v3 *)iort_node->node_data;
+
+		if (node_smmu_data != NULL) {
+			if (!strcmp(name, "eventq"))
+				ret = node_smmu_data->event_gsiv;
+			else if (!strcmp(name, "priq"))
+				ret = node_smmu_data->pri_gsiv;
+			else if (!strcmp(name, "cmdq-sync"))
+				ret = node_smmu_data->sync_gsiv;
+			else if (!strcmp(name, "gerror"))
+				ret = node_smmu_data->gerr_gsiv;
+			else
+				ret = -EINVAL;
+		}
+	} else {
+		dtprop = dt_find_property(dev_to_dt(pdev), "interrupt-names", NULL);
+		if (!dtprop)
+			return -EINVAL;
+
+		if (!dtprop->value)
+			return -ENODATA;
+	}
+
+	return ret;
+}
+
+#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \
+({ \
+	s_time_t deadline = NOW() + MICROSECS(timeout_us); \
+	for (;;) { \
+		(val) = op(addr); \
+		if (cond) \
+			break; \
+		if (NOW() > deadline) { \
+			(val) = op(addr); \
+			break; \
+		} \
+		cpu_relax(); \
+		udelay(sleep_us); \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+#define readl_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
+	readx_poll_timeout(readl_relaxed, addr, val, cond, delay_us, timeout_us)
+
+/* Xen: Helpers for IRQ functions */
+#define request_irq(irq, func, flags, name, dev) request_irq(irq, flags, func, name, dev)
+#define free_irq release_irq
+
+enum irqreturn {
+	IRQ_NONE	= (0 << 0),
+	IRQ_HANDLED	= (1 << 0),
+};
+
+typedef enum irqreturn irqreturn_t;
+
+/* Device logger functions */
+#define dev_print(dev, lvl, fmt, ...)						\
+	 printk(lvl "smmu: " fmt, ## __VA_ARGS__)
+
+#define dev_dbg(dev, fmt, ...) dev_print(dev, XENLOG_DEBUG, fmt, ## __VA_ARGS__)
+#define dev_notice(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
+#define dev_warn(dev, fmt, ...) dev_print(dev, XENLOG_WARNING, fmt, ## __VA_ARGS__)
+#define dev_err(dev, fmt, ...) dev_print(dev, XENLOG_ERR, fmt, ## __VA_ARGS__)
+#define dev_info(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
+
+#define dev_err_ratelimited(dev, fmt, ...)					\
+	 dev_print(dev, 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)		_xmalloc(size, sizeof(void *))
+#define kzalloc(size, flags)		_xzalloc(size, sizeof(void *))
+#define devm_kzalloc(dev, size, flags)	_xzalloc(size, sizeof(void *))
+#define kmalloc_array(size, n, flags)	_xmalloc_array(size, sizeof(void *), n)
+
+/* Compatibility defines */
+#undef WARN_ON
+#define WARN_ON(cond) (!!cond)
+#define WARN_ON_ONCE(cond) WARN_ON(cond)
+
+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: Dummy iommu_domain */
+struct iommu_domain {
+	/* Runtime SMMU configuration for this iommu_domain */
+	struct arm_smmu_domain		*priv;
+	unsigned int			type;
+
+	atomic_t ref;
+	/* Used to link iommu_domain contexts for a same domain.
+	 * There is at least one per-SMMU to used by the domain.
+	 */
+	struct list_head		list;
+};
+/* Xen: Domain type definitions. Not really needed for Xen, defining to port
+ * Linux code as-is
+ */
+#define IOMMU_DOMAIN_UNMANAGED 0
+#define IOMMU_DOMAIN_DMA 1
+#define IOMMU_DOMAIN_IDENTITY 2
+
+/* Xen: Describes information required for a Xen domain */
+struct arm_smmu_xen_domain {
+	spinlock_t			lock;
+	/* List of iommu domains associated to this domain */
+	struct list_head		iommu_domains;
+};
+
+/*
+ * Xen: Information about each device stored in dev->archdata.iommu
+ *
+ * The dev->archdata.iommu stores the iommu_domain (runtime configuration of
+ * the SMMU).
+ */
+struct arm_smmu_xen_device {
+	struct iommu_domain *domain;
+};
 
 /* MMIO registers */
 #define ARM_SMMU_IDR0			0x0
@@ -412,10 +650,12 @@
 #define MSI_IOVA_BASE			0x8000000
 #define MSI_IOVA_LENGTH			0x100000
 
+#if 0 /* Not applicable for Xen */
 static bool disable_bypass;
 module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO);
 MODULE_PARM_DESC(disable_bypass,
 	"Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
+#endif
 
 enum pri_resp {
 	PRI_RESP_DENY,
@@ -423,6 +663,7 @@ enum pri_resp {
 	PRI_RESP_SUCC,
 };
 
+#if 0 /* Xen: No MSI support in this iteration */
 enum arm_smmu_msi_index {
 	EVTQ_MSI_INDEX,
 	GERROR_MSI_INDEX,
@@ -447,6 +688,7 @@ static phys_addr_t arm_smmu_msi_cfg[ARM_SMMU_MAX_MSIS][3] = {
 		ARM_SMMU_PRIQ_IRQ_CFG2,
 	},
 };
+#endif
 
 struct arm_smmu_cmdq_ent {
 	/* Common fields */
@@ -551,6 +793,8 @@ struct arm_smmu_s2_cfg {
 	u16				vmid;
 	u64				vttbr;
 	u64				vtcr;
+	/* Xen: Domain associated to this configuration */
+	struct domain			*domain;
 };
 
 struct arm_smmu_strtab_ent {
@@ -623,9 +867,20 @@ struct arm_smmu_device {
 	struct arm_smmu_strtab_cfg	strtab_cfg;
 
 	/* IOMMU core code handle */
-	struct iommu_device		iommu;
+	//struct iommu_device		iommu;
+
+	/* Xen: Need to keep a list of SMMU devices */
+	struct list_head                devices;
 };
 
+/* Xen: Keep a list of devices associated with this driver */
+static DEFINE_SPINLOCK(arm_smmu_devices_lock);
+static LIST_HEAD(arm_smmu_devices);
+/* Xen: Helper for finding a device using fwnode */
+static
+struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode);
+
+
 /* SMMU private data for each master */
 struct arm_smmu_master_data {
 	struct arm_smmu_device		*smmu;
@@ -642,7 +897,7 @@ enum arm_smmu_domain_stage {
 
 struct arm_smmu_domain {
 	struct arm_smmu_device		*smmu;
-	struct mutex			init_mutex; /* Protects smmu pointer */
+	mutex			init_mutex; /* Protects smmu pointer */
 
 	struct io_pgtable_ops		*pgtbl_ops;
 	spinlock_t			pgtbl_lock;
@@ -737,15 +992,16 @@ static void queue_inc_prod(struct arm_smmu_queue *q)
  */
 static int queue_poll_cons(struct arm_smmu_queue *q, bool drain, bool wfe)
 {
-	ktime_t timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US);
+	s_time_t deadline = NOW() + MICROSECS(ARM_SMMU_POLL_TIMEOUT_US);
 
 	while (queue_sync_cons(q), (drain ? !queue_empty(q) : queue_full(q))) {
-		if (ktime_compare(ktime_get(), timeout) > 0)
+
+		if (NOW() > deadline)
 			return -ETIMEDOUT;
 
-		if (wfe) {
+		if (wfe)
 			wfe();
-		} else {
+		else {
 			cpu_relax();
 			udelay(1);
 		}
@@ -931,7 +1187,7 @@ static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
 		dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n");
 	spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
 }
-
+#if 0
 /* Context descriptor manipulation functions */
 static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
 {
@@ -974,7 +1230,7 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
 
 	cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair << CTXDESC_CD_3_MAIR_SHIFT);
 }
-
+#endif
 /* Stream table manipulation functions */
 static void
 arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
@@ -1044,7 +1300,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
 			ste_live = true;
 			break;
 		case STRTAB_STE_0_CFG_ABORT:
-			if (disable_bypass)
+			//No bypass override for Xen
 				break;
 		default:
 			BUG(); /* STE corruption */
@@ -1056,7 +1312,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
 
 	/* Bypass/fault */
 	if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) {
-		if (!ste->assigned && disable_bypass)
+		if (!ste->assigned)
 			val |= STRTAB_STE_0_CFG_ABORT;
 		else
 			val |= STRTAB_STE_0_CFG_BYPASS;
@@ -1135,16 +1391,20 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
 	void *strtab;
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
 	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
+	u32 alignment = 0;
 
 	if (desc->l2ptr)
 		return 0;
 
-	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
+	size = 1 << (STRTAB_SPLIT + LOG_2(STRTAB_STE_DWORDS) + 3);
 	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
 
 	desc->span = STRTAB_SPLIT + 1;
-	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
-					  GFP_KERNEL | __GFP_ZERO);
+
+	alignment = 1 << ((5 + (desc->span - 1)));
+	desc->l2ptr = _xzalloc(size, alignment);
+	desc->l2ptr_dma = virt_to_maddr(desc->l2ptr);
+
 	if (!desc->l2ptr) {
 		dev_err(smmu->dev,
 			"failed to allocate l2 stream table for SID %u\n",
@@ -1158,7 +1418,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
 }
 
 /* IRQ and event handlers */
-static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
+static void arm_smmu_evtq_thread(int irq, void *dev, struct cpu_user_regs *regs)
 {
 	int i;
 	struct arm_smmu_device *smmu = dev;
@@ -1186,7 +1446,6 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 
 	/* Sync our overflow flag, as we believe we're up to speed */
 	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
-	return IRQ_HANDLED;
 }
 
 static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
@@ -1203,7 +1462,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 0x%016lx\n",
 		 sid, ssid, grpid, last ? "L" : "",
 		 evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
 		 evt[0] & PRIQ_0_PERM_READ ? "R" : "",
@@ -1227,7 +1486,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
 	}
 }
 
-static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
+static void arm_smmu_priq_thread(int irq, void *dev, struct cpu_user_regs *regs)
 {
 	struct arm_smmu_device *smmu = dev;
 	struct arm_smmu_queue *q = &smmu->priq.q;
@@ -1243,18 +1502,16 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
 
 	/* Sync our overflow flag, as we believe we're up to speed */
 	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
-	return IRQ_HANDLED;
 }
 
-static irqreturn_t arm_smmu_cmdq_sync_handler(int irq, void *dev)
+static void arm_smmu_cmdq_sync_handler(int irq, void *dev, struct cpu_user_regs *regs)
 {
 	/* We don't actually use CMD_SYNC interrupts for anything */
-	return IRQ_HANDLED;
 }
 
 static int arm_smmu_device_disable(struct arm_smmu_device *smmu);
 
-static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
+static void arm_smmu_gerror_handler(int irq, void *dev, struct cpu_user_regs *regs)
 {
 	u32 gerror, gerrorn, active;
 	struct arm_smmu_device *smmu = dev;
@@ -1264,7 +1521,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
 
 	active = gerror ^ gerrorn;
 	if (!(active & GERROR_ERR_MASK))
-		return IRQ_NONE; /* No errors pending */
+		return; /* No errors pending */
 
 	dev_warn(smmu->dev,
 		 "unexpected global error reported (0x%08x), this could be serious\n",
@@ -1286,7 +1543,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
 
 	if (active & GERROR_MSI_CMDQ_ABT_ERR) {
 		dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
-		arm_smmu_cmdq_sync_handler(irq, smmu->dev);
+		arm_smmu_cmdq_sync_handler(irq, smmu->dev, NULL);
 	}
 
 	if (active & GERROR_PRIQ_ABT_ERR)
@@ -1299,7 +1556,6 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
 		arm_smmu_cmdq_skip_err(smmu);
 
 	writel(gerror, smmu->base + ARM_SMMU_GERRORN);
-	return IRQ_HANDLED;
 }
 
 /* IO_PGTABLE API */
@@ -1311,11 +1567,13 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
 	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
 }
 
+#if 0 /*Xen: Unused function */
 static void arm_smmu_tlb_sync(void *cookie)
 {
 	struct arm_smmu_domain *smmu_domain = cookie;
 	__arm_smmu_tlb_sync(smmu_domain->smmu);
 }
+#endif
 
 static void arm_smmu_tlb_inv_context(void *cookie)
 {
@@ -1336,6 +1594,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
 	__arm_smmu_tlb_sync(smmu);
 }
 
+#if 0 /*Xen: Unused functionality */
 static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
 					  size_t granule, bool leaf, void *cookie)
 {
@@ -1362,7 +1621,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
 	} while (size -= granule);
 }
 
-static const struct iommu_gather_ops arm_smmu_gather_ops = {
+static struct iommu_gather_ops arm_smmu_gather_ops = {
 	.tlb_flush_all	= arm_smmu_tlb_inv_context,
 	.tlb_add_flush	= arm_smmu_tlb_inv_range_nosync,
 	.tlb_sync	= arm_smmu_tlb_sync,
@@ -1380,6 +1639,11 @@ static bool arm_smmu_capable(enum iommu_cap cap)
 		return false;
 	}
 }
+#endif
+/* Xen: Stub out DMA domain related functions */
+#define iommu_get_dma_cookie(dom) 0
+#define iommu_put_dma_cookie(dom) 0
+
 
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 {
@@ -1410,6 +1674,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 	return &smmu_domain->domain;
 }
 
+#if 0
 static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
 {
 	int idx, size = 1 << span;
@@ -1427,36 +1692,20 @@ static void arm_smmu_bitmap_free(unsigned long *map, int idx)
 {
 	clear_bit(idx, map);
 }
+#endif
 
 static void arm_smmu_domain_free(struct iommu_domain *domain)
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-
-	iommu_put_dma_cookie(domain);
-	free_io_pgtable_ops(smmu_domain->pgtbl_ops);
-
-	/* Free the CD and ASID, if we allocated them */
-	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
-		struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
-
-		if (cfg->cdptr) {
-			dmam_free_coherent(smmu_domain->smmu->dev,
-					   CTXDESC_CD_DWORDS << 3,
-					   cfg->cdptr,
-					   cfg->cdptr_dma);
-
-			arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
-		}
-	} else {
-		struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
-		if (cfg->vmid)
-			arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
-	}
+	/*
+	 * Xen: Remove the free functions that are not used and code related
+	 * to S1 translation. We just need to free the domain here.
+	 */
 
 	kfree(smmu_domain);
 }
 
+#if 0
 static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
 				       struct io_pgtable_cfg *pgtbl_cfg)
 {
@@ -1488,33 +1737,30 @@ out_free_asid:
 	arm_smmu_bitmap_free(smmu->asid_map, asid);
 	return ret;
 }
+#endif
 
-static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
-				       struct io_pgtable_cfg *pgtbl_cfg)
+static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain)
 {
-	int vmid;
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
 	struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
 
-	vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
-	if (vmid < 0)
-		return vmid;
+	/* Xen: Set the values as needed */
 
-	cfg->vmid	= (u16)vmid;
-	cfg->vttbr	= pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
-	cfg->vtcr	= pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
+	cfg->vmid	= cfg->domain->arch.p2m.vmid;
+	cfg->vttbr	= page_to_maddr(cfg->domain->arch.p2m.root);
+	cfg->vtcr	= READ_SYSREG32(VTCR_EL2);
 	return 0;
 }
 
 static int arm_smmu_domain_finalise(struct iommu_domain *domain)
 {
 	int ret;
+#if 0	/* Xen: pgtbl_cfg not needed. So modify the function as needed */
 	unsigned long ias, oas;
 	enum io_pgtable_fmt fmt;
 	struct io_pgtable_cfg pgtbl_cfg;
 	struct io_pgtable_ops *pgtbl_ops;
-	int (*finalise_stage_fn)(struct arm_smmu_domain *,
-				 struct io_pgtable_cfg *);
+	int (*finalise_stage_fn)(struct arm_smmu_domain *);
+#endif
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 	struct arm_smmu_device *smmu = smmu_domain->smmu;
 
@@ -1529,6 +1775,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
 	if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2))
 		smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
 
+#if 0
 	switch (smmu_domain->stage) {
 	case ARM_SMMU_DOMAIN_S1:
 		ias = VA_BITS;
@@ -1563,10 +1810,11 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
 	domain->geometry.aperture_end = (1UL << ias) - 1;
 	domain->geometry.force_aperture = true;
 	smmu_domain->pgtbl_ops = pgtbl_ops;
-
 	ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
 	if (ret < 0)
 		free_io_pgtable_ops(pgtbl_ops);
+#endif
+	ret = arm_smmu_domain_finalise_s2(smmu_domain);
 
 	return ret;
 }
@@ -1660,7 +1908,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	} else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
 		ste->s1_cfg = &smmu_domain->s1_cfg;
 		ste->s2_cfg = NULL;
-		arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
+		/*Xen: S1 configuratio not needed */
+		//arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
 	} else {
 		ste->s1_cfg = NULL;
 		ste->s2_cfg = &smmu_domain->s2_cfg;
@@ -1672,6 +1921,7 @@ out_unlock:
 	return ret;
 }
 
+#if 0
 static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
 			phys_addr_t paddr, size_t size, int prot)
 {
@@ -1737,11 +1987,13 @@ static int arm_smmu_match_node(struct device *dev, void *data)
 static
 struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
 {
+	/* Xen; Function modified as needed for Xen.*/
 	struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
 						fwnode, arm_smmu_match_node);
 	put_device(dev);
 	return dev ? dev_get_drvdata(dev) : NULL;
 }
+#endif
 
 static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
 {
@@ -1752,8 +2004,9 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
 
 	return sid < limit;
 }
-
+#if 0
 static struct iommu_ops arm_smmu_ops;
+#endif
 
 static int arm_smmu_add_device(struct device *dev)
 {
@@ -1761,9 +2014,9 @@ 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;
-	struct iommu_group *group;
 
-	if (!fwspec || fwspec->ops != &arm_smmu_ops)
+	/* Xen: fwspec->ops are not needed */
+	if (!fwspec)
 		return -ENODEV;
 	/*
 	 * We _can_ actually withstand dodgy bus code re-calling add_device()
@@ -1800,6 +2053,12 @@ static int arm_smmu_add_device(struct device *dev)
 		}
 	}
 
+#if 0
+/*
+ * Xen: Do not need an iommu group as the stream data is carried by the SMMU
+ * master device object
+ */
+
 	group = iommu_group_get_for_dev(dev);
 	if (!IS_ERR(group)) {
 		iommu_group_put(group);
@@ -1807,8 +2066,16 @@ static int arm_smmu_add_device(struct device *dev)
 	}
 
 	return PTR_ERR_OR_ZERO(group);
+#endif
+	return 0;
 }
 
+/*
+ * Xen: We can potentially support this function and destroy a device. This
+ * will be relevant for PCI hotplug. So, will be implemented as needed after
+ * passthrough support is available.
+ */
+#if 0
 static void arm_smmu_remove_device(struct device *dev)
 {
 	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
@@ -1944,7 +2211,7 @@ static struct iommu_ops arm_smmu_ops = {
 	.put_resv_regions	= arm_smmu_put_resv_regions,
 	.pgsize_bitmap		= -1UL, /* Restricted during device attach */
 };
-
+#endif
 /* Probing and initialisation functions */
 static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
 				   struct arm_smmu_queue *q,
@@ -1954,7 +2221,12 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
 {
 	size_t qsz = ((1 << q->max_n_shift) * dwords) << 3;
 
-	q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL);
+	/* The SMMU cache coherency property is always set. Since we are sharing the CPU translation tables
+	 * just make a regular allocation.
+	 */
+	q->base = _xzalloc(qsz, sizeof(void *));
+	q->base_dma = virt_to_maddr(q->base);
+
 	if (!q->base) {
 		dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes)\n",
 			qsz);
@@ -2025,10 +2297,11 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
 	void *strtab;
 	u64 reg;
 	u32 size, l1size;
+	u32 alignment;
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
 
 	/* Calculate the L1 size, capped to the SIDSIZE. */
-	size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
+	size = STRTAB_L1_SZ_SHIFT - (LOG_2(STRTAB_L1_DESC_DWORDS) + 3);
 	size = min(size, smmu->sid_bits - STRTAB_SPLIT);
 	cfg->num_l1_ents = 1 << size;
 
@@ -2039,8 +2312,13 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
 			 size, smmu->sid_bits);
 
 	l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
-	strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
-				     GFP_KERNEL | __GFP_ZERO);
+
+	alignment = max_t(u32, cfg->num_l1_ents, 64);
+	//strtab = _xzalloc(l1size, sizeof(void *));
+	strtab = _xzalloc(l1size, l1size);
+	cfg->strtab_dma = virt_to_maddr(strtab);
+
+	//dsb(sy);
 	if (!strtab) {
 		dev_err(smmu->dev,
 			"failed to allocate l1 stream table (%u bytes)\n",
@@ -2068,8 +2346,9 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
 
 	size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3);
-	strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma,
-				     GFP_KERNEL | __GFP_ZERO);
+	strtab = _xzalloc(size, size);
+	cfg->strtab_dma = virt_to_maddr(strtab);
+
 	if (!strtab) {
 		dev_err(smmu->dev,
 			"failed to allocate linear stream table (%u bytes)\n",
@@ -2152,6 +2431,8 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
 					  1, ARM_SMMU_POLL_TIMEOUT_US);
 }
 
+/* Xen: There is no MSI support as yet */
+#if 0
 static void arm_smmu_free_msis(void *data)
 {
 	struct device *dev = data;
@@ -2217,7 +2498,7 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
 	/* Add callback to free MSIs on teardown */
 	devm_add_action(dev, arm_smmu_free_msis, dev);
 }
-
+#endif
 static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
 {
 	int ret, irq;
@@ -2231,31 +2512,31 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
 		return ret;
 	}
 
-	arm_smmu_setup_msis(smmu);
+	//arm_smmu_setup_msis(smmu);
 
 	/* Request interrupt lines */
 	irq = smmu->evtq.q.irq;
 	if (irq) {
-		ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
-						arm_smmu_evtq_thread,
-						IRQF_ONESHOT,
-						"arm-smmu-v3-evtq", smmu);
+		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
+		ret = request_irq(irq, arm_smmu_evtq_thread,
+						0, "arm-smmu-v3-evtq", smmu);
 		if (ret < 0)
 			dev_warn(smmu->dev, "failed to enable evtq irq\n");
 	}
 
 	irq = smmu->cmdq.q.irq;
 	if (irq) {
-		ret = devm_request_irq(smmu->dev, irq,
-				       arm_smmu_cmdq_sync_handler, 0,
-				       "arm-smmu-v3-cmdq-sync", smmu);
+		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
+		ret = request_irq(irq, arm_smmu_cmdq_sync_handler,
+				0, "arm-smmu-v3-cmdq-sync", smmu);
 		if (ret < 0)
 			dev_warn(smmu->dev, "failed to enable cmdq-sync irq\n");
 	}
 
 	irq = smmu->gerr_irq;
 	if (irq) {
-		ret = devm_request_irq(smmu->dev, irq, arm_smmu_gerror_handler,
+		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
+		ret = request_irq(irq, arm_smmu_gerror_handler,
 				       0, "arm-smmu-v3-gerror", smmu);
 		if (ret < 0)
 			dev_warn(smmu->dev, "failed to enable gerror irq\n");
@@ -2263,12 +2544,13 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
 
 	if (smmu->features & ARM_SMMU_FEAT_PRI) {
 		irq = smmu->priq.q.irq;
+		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
 		if (irq) {
-			ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
-							arm_smmu_priq_thread,
-							IRQF_ONESHOT,
-							"arm-smmu-v3-priq",
-							smmu);
+			ret = request_irq(irq,
+					  arm_smmu_priq_thread,
+					  0,
+					  "arm-smmu-v3-priq",
+					  smmu);
 			if (ret < 0)
 				dev_warn(smmu->dev,
 					 "failed to enable priq irq\n");
@@ -2400,7 +2682,7 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 
 
 	/* Enable the SMMU interface, or ensure bypass */
-	if (!bypass || disable_bypass) {
+	if (!bypass) {
 		enables |= CR0_SMMUEN;
 	} else {
 		ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
@@ -2488,8 +2770,11 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 		smmu->features |= ARM_SMMU_FEAT_STALLS;
 	}
 
+#if 0/* Xen: Do not enable Stage 1 translations */
+
 	if (reg & IDR0_S1P)
 		smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
+#endif
 
 	if (reg & IDR0_S2P)
 		smmu->features |= ARM_SMMU_FEAT_TRANS_S2;
@@ -2562,10 +2847,12 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 	if (reg & IDR5_GRAN4K)
 		smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
 
+#if 0 /* Xen: SMMU ops do not have a pgsize_bitmap member for Xen */
 	if (arm_smmu_ops.pgsize_bitmap == -1UL)
 		arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
 	else
 		arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
+#endif
 
 	/* Output address size */
 	switch (reg & IDR5_OAS_MASK << IDR5_OAS_SHIFT) {
@@ -2592,10 +2879,12 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
 		smmu->oas = 48;
 	}
 
+#if 0 /* Xen: There is no support for DMA mask */
 	/* Set the DMA mask for our table walker */
 	if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas)))
 		dev_warn(smmu->dev,
 			 "failed to set DMA mask for table walker\n");
+#endif
 
 	smmu->ias = max(smmu->ias, smmu->oas);
 
@@ -2612,7 +2901,8 @@ static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
 	struct device *dev = smmu->dev;
 	struct acpi_iort_node *node;
 
-	node = *(struct acpi_iort_node **)dev_get_platdata(dev);
+	/* Xen: Modification to get iort_node */
+	node = (struct acpi_iort_node *)dev->acpi_node;
 
 	/* Retrieve SMMUv3 specific data */
 	iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
@@ -2633,7 +2923,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;
 
@@ -2646,8 +2936,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
 
 	parse_driver_options(smmu);
 
-	if (of_dma_is_coherent(dev->of_node))
-		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+	/* Xen: Set the COHERNECY feature */
+	smmu->features |= ARM_SMMU_FEAT_COHERENCY;
 
 	return ret;
 }
@@ -2656,9 +2946,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 {
 	int irq, ret;
 	struct resource *res;
-	resource_size_t ioaddr;
+	/*Xen: Do not need to setup sysfs */
+	/* resource_size_t ioaddr;*/
 	struct arm_smmu_device *smmu;
-	struct device *dev = &pdev->dev;
+	struct device *dev = pdev;/* Xen: dev is ignored */
 	bool bypass;
 
 	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
@@ -2674,7 +2965,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		dev_err(dev, "MMIO region too small (%pr)\n", res);
 		return -EINVAL;
 	}
-	ioaddr = res->start;
+	/*ioaddr = res->start;*/
 
 	smmu->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(smmu->base))
@@ -2719,13 +3010,15 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		return ret;
 
 	/* Record our private device structure */
-	platform_set_drvdata(pdev, smmu);
+	/* platform_set_drvdata(pdev, smmu); */
 
 	/* Reset the device */
 	ret = arm_smmu_device_reset(smmu, bypass);
 	if (ret)
 		return ret;
 
+/* Xen: Not creating an IOMMU device list for Xen */
+#if 0
 	/* And we're up. Go go go! */
 	ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
 				     "smmu3.%pa", &ioaddr);
@@ -2757,9 +3050,18 @@ 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;
 }
-
+#if 0
 static int arm_smmu_device_remove(struct platform_device *pdev)
 {
 	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
@@ -2767,6 +3069,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
 	arm_smmu_device_disable(smmu);
 	return 0;
 }
+#endif
+#define MODULE_DEVICE_TABLE(type, name)
+#define of_device_id dt_device_match
 
 static struct of_device_id arm_smmu_of_match[] = {
 	{ .compatible = "arm,smmu-v3", },
@@ -2774,6 +3079,7 @@ static struct of_device_id arm_smmu_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
 
+#if 0
 static struct platform_driver arm_smmu_driver = {
 	.driver	= {
 		.name		= "arm-smmu-v3",
@@ -2789,3 +3095,318 @@ IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", NULL);
 MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
 MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
 MODULE_LICENSE("GPL v2");
+
+#endif
+/***** Start of Xen specific code *****/
+
+static int __must_check arm_smmu_iotlb_flush_all(struct domain *d)
+{
+	struct arm_smmu_xen_domain *smmu_domain = dom_iommu(d)->arch.priv;
+	struct iommu_domain *cfg;
+
+	spin_lock(&smmu_domain->lock);
+	list_for_each_entry(cfg, &smmu_domain->iommu_domains, list) {
+		/*
+		 * Only invalidate the context when SMMU is present.
+		 * This is because the context initialization is delayed
+		 * until a master has been added.
+		 */
+		if (unlikely(!ACCESS_ONCE(cfg->priv->smmu)))
+			continue;
+		arm_smmu_tlb_inv_context(cfg->priv);
+	}
+	spin_unlock(&smmu_domain->lock);
+	return 0;
+}
+
+static int __must_check arm_smmu_iotlb_flush(struct domain *d,
+					     unsigned long gfn,
+					     unsigned int page_count)
+{
+	return arm_smmu_iotlb_flush_all(d);
+}
+
+static struct iommu_domain *arm_smmu_get_domain(struct domain *d,
+						struct device *dev)
+{
+	struct iommu_domain *domain;
+	struct arm_smmu_xen_domain *xen_domain;
+	struct arm_smmu_device *smmu;
+	struct arm_smmu_domain *smmu_domain;
+
+	xen_domain = dom_iommu(d)->arch.priv;
+
+	smmu = arm_smmu_get_by_fwnode(dev->iommu_fwspec->iommu_fwnode);
+	if (!smmu)
+		return NULL;
+
+	/*
+	 * Loop through the &xen_domain->contexts to locate a context
+	 * assigned to this SMMU
+	 */
+	list_for_each_entry(domain, &xen_domain->iommu_domains, list) {
+		smmu_domain = to_smmu_domain(domain);
+		if (smmu_domain->smmu == smmu)
+			return domain;
+	}
+
+	return NULL;
+}
+
+static void arm_smmu_destroy_iommu_domain(struct iommu_domain *domain)
+{
+	list_del(&domain->list);
+	xfree(domain);
+}
+
+static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
+			       struct device *dev, u32 flag)
+{
+	int ret = 0;
+	struct iommu_domain *domain;
+	struct arm_smmu_xen_domain *xen_domain;
+	struct arm_smmu_domain *arm_smmu;
+
+	xen_domain = dom_iommu(d)->arch.priv;
+
+	if (!dev->archdata.iommu) {
+		dev->archdata.iommu = xzalloc(struct arm_smmu_xen_device);
+		if (!dev->archdata.iommu)
+			return -ENOMEM;
+	}
+
+	ret = arm_smmu_add_device(dev);
+	if (ret)
+		return ret;
+
+	spin_lock(&xen_domain->lock);
+
+	/*
+	 * Check to see if an iommu_domain already exists for this xen domain
+	 * under the same SMMU
+	 */
+	domain = arm_smmu_get_domain(d, dev);
+	if (!domain) {
+
+		domain = arm_smmu_domain_alloc(IOMMU_DOMAIN_DMA);
+		if (!domain) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		arm_smmu = to_smmu_domain(domain);
+		arm_smmu->s2_cfg.domain = d;
+
+		/* Chain the new context to the domain */
+		list_add(&domain->list, &xen_domain->iommu_domains);
+
+	}
+
+	ret = arm_smmu_attach_dev(domain, dev);
+	if (ret) {
+		if (domain->ref.counter == 0)
+			arm_smmu_destroy_iommu_domain(domain);
+	} else {
+		atomic_inc(&domain->ref);
+	}
+
+out:
+	spin_unlock(&xen_domain->lock);
+	return ret;
+}
+
+static int arm_smmu_deassign_dev(struct domain *d, struct device *dev)
+{
+	struct iommu_domain *domain = arm_smmu_get_domain(d, dev);
+	struct arm_smmu_xen_domain *xen_domain;
+	struct arm_smmu_domain *arm_smmu = to_smmu_domain(domain);
+
+	xen_domain = dom_iommu(d)->arch.priv;
+
+	if (!arm_smmu || arm_smmu->s2_cfg.domain != d) {
+		dev_err(dev, " not attached to domain %d\n", d->domain_id);
+		return -ESRCH;
+	}
+
+	spin_lock(&xen_domain->lock);
+
+	arm_smmu_detach_dev(dev);
+	atomic_dec(&domain->ref);
+
+	if (domain->ref.counter == 0)
+		arm_smmu_destroy_iommu_domain(domain);
+
+	spin_unlock(&xen_domain->lock);
+
+
+
+	return 0;
+}
+
+static int arm_smmu_reassign_dev(struct domain *s, struct domain *t,
+				 u8 devfn,  struct device *dev)
+{
+	int ret = 0;
+
+	/* Don't allow remapping on other domain than hwdom */
+	if (t && t != hardware_domain)
+		return -EPERM;
+
+	if (t == s)
+		return 0;
+
+	ret = arm_smmu_deassign_dev(s, dev);
+	if (ret)
+		return ret;
+
+	if (t) {
+		/* No flags are defined for ARM. */
+		ret = arm_smmu_assign_dev(t, devfn, dev, 0);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int arm_smmu_iommu_domain_init(struct domain *d)
+{
+	struct arm_smmu_xen_domain *xen_domain;
+
+	xen_domain = xzalloc(struct arm_smmu_xen_domain);
+	if (!xen_domain)
+		return -ENOMEM;
+
+	spin_lock_init(&xen_domain->lock);
+	INIT_LIST_HEAD(&xen_domain->iommu_domains);
+
+	dom_iommu(d)->arch.priv = xen_domain;
+
+	return 0;
+}
+
+static void __hwdom_init arm_smmu_iommu_hwdom_init(struct domain *d)
+{
+}
+
+static void arm_smmu_iommu_domain_teardown(struct domain *d)
+{
+	struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv;
+
+	ASSERT(list_empty(&xen_domain->iommu_domains));
+	xfree(xen_domain);
+}
+
+static int __must_check arm_smmu_map_page(struct domain *d, unsigned long gfn,
+			unsigned long mfn, unsigned int flags)
+{
+	p2m_type_t t;
+
+	/*
+	 * Grant mappings can be used for DMA requests. The dev_bus_addr
+	 * returned by the hypercall is the MFN (not the IPA). For device
+	 * protected by an IOMMU, Xen needs to add a 1:1 mapping in the domain
+	 * p2m to allow DMA request to work.
+	 * This is only valid when the domain is directed mapped. Hence this
+	 * function should only be used by gnttab code with gfn == mfn.
+	 */
+	BUG_ON(!is_domain_direct_mapped(d));
+	BUG_ON(mfn != gfn);
+
+	/* We only support readable and writable flags */
+	if (!(flags & (IOMMUF_readable | IOMMUF_writable)))
+		return -EINVAL;
+
+	t = (flags & IOMMUF_writable) ? p2m_iommu_map_rw : p2m_iommu_map_ro;
+
+	/*
+	 * The function guest_physmap_add_entry replaces the current mapping
+	 * if there is already one...
+	 */
+	return guest_physmap_add_entry(d, _gfn(gfn), _mfn(mfn), 0, t);
+}
+
+static int __must_check arm_smmu_unmap_page(struct domain *d, unsigned long gfn)
+{
+	/*
+	 * This function should only be used by gnttab code when the domain
+	 * is direct mapped
+	 */
+	if (!is_domain_direct_mapped(d))
+		return -EINVAL;
+
+	return guest_physmap_remove_page(d, _gfn(gfn), _mfn(gfn), 0);
+}
+
+static const struct iommu_ops arm_smmu_iommu_ops = {
+	.init = arm_smmu_iommu_domain_init,
+	.hwdom_init = arm_smmu_iommu_hwdom_init,
+	.teardown = arm_smmu_iommu_domain_teardown,
+	.iotlb_flush = arm_smmu_iotlb_flush,
+	.iotlb_flush_all = arm_smmu_iotlb_flush_all,
+	.assign_device = arm_smmu_assign_dev,
+	.reassign_device = arm_smmu_reassign_dev,
+	.map_page = arm_smmu_map_page,
+	.unmap_page = arm_smmu_unmap_page,
+};
+
+static
+struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
+{
+	struct arm_smmu_device *smmu = NULL;
+
+	spin_lock(&arm_smmu_devices_lock);
+	list_for_each_entry(smmu, &arm_smmu_devices, devices) {
+		if (smmu->dev->fwnode == fwnode)
+			break;
+	}
+	spin_unlock(&arm_smmu_devices_lock);
+
+	return smmu;
+}
+
+static __init int arm_smmu_dt_init(struct dt_device_node *dev,
+				   const void *data)
+{
+	int rc;
+
+	/*
+	 * Even if the device can't be initialized, we don't want to
+	 * give the SMMU device to dom0.
+	 */
+	dt_device_set_used_by(dev, DOMID_XEN);
+
+	rc = arm_smmu_device_probe(dt_to_dev(dev));
+	if (rc)
+		return rc;
+
+	iommu_set_ops(&arm_smmu_iommu_ops);
+
+	return 0;
+}
+
+DT_DEVICE_START(smmuv3, "ARM SMMU V3", DEVICE_IOMMU)
+	.dt_match = arm_smmu_of_match,
+	.init = arm_smmu_dt_init,
+DT_DEVICE_END
+
+#ifdef CONFIG_ACPI
+/* Set up the IOMMU */
+static int __init arm_smmu_acpi_init(const void *data)
+{
+	int rc;
+	rc = arm_smmu_device_probe((struct device *)data);
+
+	if (rc)
+		return rc;
+
+	iommu_set_ops(&arm_smmu_iommu_ops);
+	return 0;
+}
+
+ACPI_DEVICE_START(asmmuv3, "ARM SMMU V3", DEVICE_IOMMU)
+	.class_type = ACPI_IORT_NODE_SMMU_V3,
+	.init = arm_smmu_acpi_init,
+ACPI_DEVICE_END
+
+#endif
-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [RFC v2 0/7] SMMUv3 driver and the supporting framework
  2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
                   ` (6 preceding siblings ...)
  2017-09-21  0:37 ` [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver Sameer Goel
@ 2017-09-21  5:43 ` Manish Jaggi
  7 siblings, 0 replies; 34+ messages in thread
From: Manish Jaggi @ 2017-09-21  5:43 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 9/21/2017 6:07 AM, Sameer Goel wrote:
> This change incoporates most of the review comments from [1] and adds the
> proposed SMMUv3 driver.
>
> List of changes:
> - Introduce the iommu_fwspec implementation - No change from the last RFC
> - IORT port from linux. The differences are as under:
> 	* Modified the code for creating the SMMU devices. This code also
> 	  initializes the discoverd SMMU devices.
> 	* MSI code is left as is, but this code is untested.
> 	* IORT node data parsing is delegated to the driver. Looking for comments
>        on enabling the code in IORT driver. This will need a standard resource
>        object. (Direct port from Linux or a new define for Xen?)
>      * Assumptions on PCI IORT SMMU interaction. PCI assign device will call
>        iort_iommu_configure to setup the streamids.Then it will call SMMU
>        assign device with the right struct device argument.
> - SMMUv3 port from Linux. The list of changes are as under:
> 	* The Xen iommu_ops list is at parity with SMMUv2.
> 	* There is generally no need for an IOMMU group, but have kept a dummy
> 	  define for now.
> 	* Have commented out the S1 translation code.
> 	* MSI code is commented out.
> 	* Page table ops are commented out as the driver shares the page tables
> 	  with the cpu.
> 	* The list of SMMU devices is maintained from the driver code.
>
> Open questions:
> - IORT regeneration for DOM0. I was hoping to get some update on [2].
Please see v2 patch set
https://lists.xen.org/archives/html/xen-devel/2017-09/msg01143.html
> - We also need a notification framework to get the Named node information from DSDT.
> - Should we port over code for non-hsared page tables from the kernel or leverage [3].
>
>
> [1] "[RFC 0/6] IORT support and introduce fwspec"
> [2] "[Xen-devel] [RFC] [PATCH] arm-acpi: Hide SMMU from IORT for hardware domain"
> [3] "Non-shared" IOMMU support on ARM"
>
> Sameer Goel (7):
>    passthrough/arm: Modify SMMU driver to use generic device definition
>    arm64: Add definitions for fwnode_handle
>    xen/passthrough/arm: Introduce iommu_fwspec
>    ACPI: arm: Support for IORT
>    acpi:arm64: Add support for parsing IORT table
>    Add verbatim copy of arm-smmu-v3.c from Linux
>    xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
>
>   xen/arch/arm/setup.c                  |    3 +
>   xen/drivers/acpi/Makefile             |    1 +
>   xen/drivers/acpi/arm/Makefile         |    1 +
>   xen/drivers/acpi/arm/iort.c           |  986 ++++++++++
>   xen/drivers/passthrough/arm/Makefile  |    1 +
>   xen/drivers/passthrough/arm/iommu.c   |   66 +
>   xen/drivers/passthrough/arm/smmu-v3.c | 3412 +++++++++++++++++++++++++++++++++
>   xen/drivers/passthrough/arm/smmu.c    |   13 +-
>   xen/include/acpi/acpi_iort.h          |   61 +
>   xen/include/asm-arm/device.h          |    5 +
>   xen/include/xen/acpi.h                |   21 +
>   xen/include/xen/fwnode.h              |   33 +
>   xen/include/xen/iommu.h               |   29 +
>   xen/include/xen/pci.h                 |    8 +
>   14 files changed, 4634 insertions(+), 6 deletions(-)
>   create mode 100644 xen/drivers/acpi/arm/Makefile
>   create mode 100644 xen/drivers/acpi/arm/iort.c
>   create mode 100644 xen/drivers/passthrough/arm/smmu-v3.c
>   create mode 100644 xen/include/acpi/acpi_iort.h
>   create mode 100644 xen/include/xen/fwnode.h
>


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-09-21  0:37 ` [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver Sameer Goel
@ 2017-09-26  0:03   ` Goel, Sameer
  2017-10-12 16:36   ` Julien Grall
  1 sibling, 0 replies; 34+ messages in thread
From: Goel, Sameer @ 2017-09-26  0:03 UTC (permalink / raw)
  To: xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 9/20/2017 6:37 PM, 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 */
> 
> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
> ---
>  xen/drivers/passthrough/arm/Makefile  |   1 +
>  xen/drivers/passthrough/arm/smmu-v3.c | 853 +++++++++++++++++++++++++++++-----
>  2 files changed, 738 insertions(+), 116 deletions(-)
> 
> diff --git a/xen/drivers/passthrough/arm/Makefile b/xen/drivers/passthrough/arm/Makefile
> index f4cd26e..57a6da6 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-y += smmu-v3.o
> diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
> index 380969a..8f3b43d 100644
> --- a/xen/drivers/passthrough/arm/smmu-v3.c
> +++ b/xen/drivers/passthrough/arm/smmu-v3.c
> @@ -18,28 +18,266 @@
>   * Author: Will Deacon <will.deacon@arm.com>
>   *
>   * This driver is powered by bad coffee and bombay mix.
> + *
> + *
> + * Based on Linux drivers/iommu/arm-smmu-v3.c
> + * => commit bdf95923086fb359ccb44c815724c3ace1611c90
> + *
> + * Xen modifications:
> + * Sameer Goel <sgoel@codeaurora.org>
> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
> + *
>   */
>  
> -#include <linux/acpi.h>
> -#include <linux/acpi_iort.h>
> -#include <linux/delay.h>
> -#include <linux/dma-iommu.h>
> -#include <linux/err.h>
> -#include <linux/interrupt.h>
> -#include <linux/iommu.h>
> -#include <linux/iopoll.h>
> -#include <linux/module.h>
> -#include <linux/msi.h>
> -#include <linux/of.h>
> -#include <linux/of_address.h>
> -#include <linux/of_iommu.h>
> -#include <linux/of_platform.h>
> -#include <linux/pci.h>
> -#include <linux/platform_device.h>
> -
> -#include <linux/amba/bus.h>
> -
> -#include "io-pgtable.h"
> +#include <xen/config.h>
> +#include <xen/delay.h>
> +#include <xen/errno.h>
> +#include <xen/err.h>
> +#include <xen/irq.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/mm.h>
> +#include <xen/vmap.h>
> +#include <xen/rbtree.h>
> +#include <xen/sched.h>
> +#include <xen/sizes.h>
> +#include <asm/atomic.h>
> +#include <asm/device.h>
> +#include <asm/io.h>
> +#include <asm/platform.h>
> +#include <xen/acpi.h>
> +
> +typedef paddr_t phys_addr_t;
> +typedef paddr_t dma_addr_t;
> +
> +/* Alias to Xen device tree helpers */
> +#define device_node dt_device_node
> +#define of_phandle_args dt_phandle_args
> +#define of_device_id dt_device_match
> +#define of_match_node dt_match_node
> +#define of_property_read_u32(np, pname, out) (!dt_property_read_u32(np, pname, out))
> +#define of_property_read_bool dt_property_read_bool
> +#define of_parse_phandle_with_args dt_parse_phandle_with_args
> +#define mutex spinlock_t
> +#define mutex_init spin_lock_init
> +#define mutex_lock spin_lock
> +#define mutex_unlock spin_unlock
> +
> +/* Xen: Helpers to get device MMIO and IRQs */
> +struct resource {
> +	u64 addr;
> +	u64 size;
> +	unsigned int type;
> +};
> +
> +#define resource_size(res) ((res)->size)
> +
> +#define platform_device device
> +
> +#define IORESOURCE_MEM 0
> +#define IORESOURCE_IRQ 1
> +
> +static struct resource *platform_get_resource(struct platform_device *pdev,
> +					      unsigned int type,
> +					      unsigned int num)
> +{
> +	/*
> +	 * The resource is only used between 2 calls of platform_get_resource.
> +	 * It's quite ugly but it's avoid to add too much code in the part
> +	 * imported from Linux
> +	 */
> +	static struct resource res;
> +	struct acpi_iort_node *iort_node;
> +	struct acpi_iort_smmu_v3 *node_smmu_data;
> +	int ret = 0;
> +
> +	res.type = type;
> +
> +	switch (type) {
> +	case IORESOURCE_MEM:
> +		if (pdev->type == DEV_ACPI) {
> +			ret = 1;
> +			iort_node = pdev->acpi_node;
> +			node_smmu_data =
> +				(struct acpi_iort_smmu_v3 *)iort_node->node_data;
> +
> +			if (node_smmu_data != NULL) {
> +				res.addr = node_smmu_data->base_address;
> +				res.size = SZ_128K;
> +				ret = 0;
> +			}
> +		} else {
> +			ret = dt_device_get_address(dev_to_dt(pdev), num,
> +						    &res.addr, &res.size);
> +		}
> +
> +		return ((ret) ? NULL : &res);
> +
> +	case IORESOURCE_IRQ:
> +		ret = platform_get_irq(dev_to_dt(pdev), num);
> +
> +		if (ret < 0)
> +			return NULL;
> +
> +		res.addr = ret;
> +		res.size = 1;
> +
> +		return &res;
> +
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +static int platform_get_irq_byname(struct platform_device *pdev, const char *name)
> +{
> +	const struct dt_property *dtprop;
> +	struct acpi_iort_node *iort_node;
> +	struct acpi_iort_smmu_v3 *node_smmu_data;
> +	int ret = 0;
> +
> +	if (pdev->type == DEV_ACPI) {
> +		iort_node = pdev->acpi_node;
> +		node_smmu_data = (struct acpi_iort_smmu_v3 *)iort_node->node_data;
> +
> +		if (node_smmu_data != NULL) {
> +			if (!strcmp(name, "eventq"))
> +				ret = node_smmu_data->event_gsiv;
> +			else if (!strcmp(name, "priq"))
> +				ret = node_smmu_data->pri_gsiv;
> +			else if (!strcmp(name, "cmdq-sync"))
> +				ret = node_smmu_data->sync_gsiv;
> +			else if (!strcmp(name, "gerror"))
> +				ret = node_smmu_data->gerr_gsiv;
> +			else
> +				ret = -EINVAL;
> +		}
> +	} else {
> +		dtprop = dt_find_property(dev_to_dt(pdev), "interrupt-names", NULL);
> +		if (!dtprop)
> +			return -EINVAL;
> +
> +		if (!dtprop->value)
> +			return -ENODATA;
> +	}
> +
> +	return ret;
> +}
> +
> +#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \
> +({ \
> +	s_time_t deadline = NOW() + MICROSECS(timeout_us); \
> +	for (;;) { \
> +		(val) = op(addr); \
> +		if (cond) \
> +			break; \
> +		if (NOW() > deadline) { \
> +			(val) = op(addr); \
> +			break; \
> +		} \
> +		cpu_relax(); \
> +		udelay(sleep_us); \
> +	} \
> +	(cond) ? 0 : -ETIMEDOUT; \
> +})
> +
> +#define readl_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
> +	readx_poll_timeout(readl_relaxed, addr, val, cond, delay_us, timeout_us)
> +
> +/* Xen: Helpers for IRQ functions */
> +#define request_irq(irq, func, flags, name, dev) request_irq(irq, flags, func, name, dev)
> +#define free_irq release_irq
> +
> +enum irqreturn {
> +	IRQ_NONE	= (0 << 0),
> +	IRQ_HANDLED	= (1 << 0),
> +};
> +
> +typedef enum irqreturn irqreturn_t;
> +
> +/* Device logger functions */
> +#define dev_print(dev, lvl, fmt, ...)						\
> +	 printk(lvl "smmu: " fmt, ## __VA_ARGS__)
> +
> +#define dev_dbg(dev, fmt, ...) dev_print(dev, XENLOG_DEBUG, fmt, ## __VA_ARGS__)
> +#define dev_notice(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
> +#define dev_warn(dev, fmt, ...) dev_print(dev, XENLOG_WARNING, fmt, ## __VA_ARGS__)
> +#define dev_err(dev, fmt, ...) dev_print(dev, XENLOG_ERR, fmt, ## __VA_ARGS__)
> +#define dev_info(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
> +
> +#define dev_err_ratelimited(dev, fmt, ...)					\
> +	 dev_print(dev, 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)		_xmalloc(size, sizeof(void *))
> +#define kzalloc(size, flags)		_xzalloc(size, sizeof(void *))
> +#define devm_kzalloc(dev, size, flags)	_xzalloc(size, sizeof(void *))
> +#define kmalloc_array(size, n, flags)	_xmalloc_array(size, sizeof(void *), n)
> +
> +/* Compatibility defines */
> +#undef WARN_ON
> +#define WARN_ON(cond) (!!cond)
> +#define WARN_ON_ONCE(cond) WARN_ON(cond)
> +
> +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: Dummy iommu_domain */
> +struct iommu_domain {
> +	/* Runtime SMMU configuration for this iommu_domain */
> +	struct arm_smmu_domain		*priv;
> +	unsigned int			type;
> +
> +	atomic_t ref;
> +	/* Used to link iommu_domain contexts for a same domain.
> +	 * There is at least one per-SMMU to used by the domain.
> +	 */
> +	struct list_head		list;
> +};
> +/* Xen: Domain type definitions. Not really needed for Xen, defining to port
> + * Linux code as-is
> + */
> +#define IOMMU_DOMAIN_UNMANAGED 0
> +#define IOMMU_DOMAIN_DMA 1
> +#define IOMMU_DOMAIN_IDENTITY 2
> +
> +/* Xen: Describes information required for a Xen domain */
> +struct arm_smmu_xen_domain {
> +	spinlock_t			lock;
> +	/* List of iommu domains associated to this domain */
> +	struct list_head		iommu_domains;
> +};
> +
> +/*
> + * Xen: Information about each device stored in dev->archdata.iommu
> + *
> + * The dev->archdata.iommu stores the iommu_domain (runtime configuration of
> + * the SMMU).
> + */
> +struct arm_smmu_xen_device {
> +	struct iommu_domain *domain;
> +};
>  
>  /* MMIO registers */
>  #define ARM_SMMU_IDR0			0x0
> @@ -412,10 +650,12 @@
>  #define MSI_IOVA_BASE			0x8000000
>  #define MSI_IOVA_LENGTH			0x100000
>  
> +#if 0 /* Not applicable for Xen */
>  static bool disable_bypass;
>  module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO);
>  MODULE_PARM_DESC(disable_bypass,
>  	"Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
> +#endif
>  
>  enum pri_resp {
>  	PRI_RESP_DENY,
> @@ -423,6 +663,7 @@ enum pri_resp {
>  	PRI_RESP_SUCC,
>  };
>  
> +#if 0 /* Xen: No MSI support in this iteration */
>  enum arm_smmu_msi_index {
>  	EVTQ_MSI_INDEX,
>  	GERROR_MSI_INDEX,
> @@ -447,6 +688,7 @@ static phys_addr_t arm_smmu_msi_cfg[ARM_SMMU_MAX_MSIS][3] = {
>  		ARM_SMMU_PRIQ_IRQ_CFG2,
>  	},
>  };
> +#endif
>  
>  struct arm_smmu_cmdq_ent {
>  	/* Common fields */
> @@ -551,6 +793,8 @@ struct arm_smmu_s2_cfg {
>  	u16				vmid;
>  	u64				vttbr;
>  	u64				vtcr;
> +	/* Xen: Domain associated to this configuration */
> +	struct domain			*domain;
>  };
>  
>  struct arm_smmu_strtab_ent {
> @@ -623,9 +867,20 @@ struct arm_smmu_device {
>  	struct arm_smmu_strtab_cfg	strtab_cfg;
>  
>  	/* IOMMU core code handle */
> -	struct iommu_device		iommu;
> +	//struct iommu_device		iommu;
> +
> +	/* Xen: Need to keep a list of SMMU devices */
> +	struct list_head                devices;
>  };
>  
> +/* Xen: Keep a list of devices associated with this driver */
> +static DEFINE_SPINLOCK(arm_smmu_devices_lock);
> +static LIST_HEAD(arm_smmu_devices);
> +/* Xen: Helper for finding a device using fwnode */
> +static
> +struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode);
> +
> +
>  /* SMMU private data for each master */
>  struct arm_smmu_master_data {
>  	struct arm_smmu_device		*smmu;
> @@ -642,7 +897,7 @@ enum arm_smmu_domain_stage {
>  
>  struct arm_smmu_domain {
>  	struct arm_smmu_device		*smmu;
> -	struct mutex			init_mutex; /* Protects smmu pointer */
> +	mutex			init_mutex; /* Protects smmu pointer */
>  
>  	struct io_pgtable_ops		*pgtbl_ops;
>  	spinlock_t			pgtbl_lock;
> @@ -737,15 +992,16 @@ static void queue_inc_prod(struct arm_smmu_queue *q)
>   */
>  static int queue_poll_cons(struct arm_smmu_queue *q, bool drain, bool wfe)
>  {
> -	ktime_t timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US);
> +	s_time_t deadline = NOW() + MICROSECS(ARM_SMMU_POLL_TIMEOUT_US);
>  
>  	while (queue_sync_cons(q), (drain ? !queue_empty(q) : queue_full(q))) {
> -		if (ktime_compare(ktime_get(), timeout) > 0)
> +
> +		if (NOW() > deadline)
>  			return -ETIMEDOUT;
>  
> -		if (wfe) {
> +		if (wfe)
>  			wfe();
> -		} else {
> +		else {
>  			cpu_relax();
>  			udelay(1);
>  		}
> @@ -931,7 +1187,7 @@ static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
>  		dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n");
>  	spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
>  }
> -
> +#if 0
>  /* Context descriptor manipulation functions */
>  static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
>  {
> @@ -974,7 +1230,7 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
>  
>  	cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair << CTXDESC_CD_3_MAIR_SHIFT);
>  }
> -
> +#endif
>  /* Stream table manipulation functions */
>  static void
>  arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
> @@ -1044,7 +1300,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
>  			ste_live = true;
>  			break;
>  		case STRTAB_STE_0_CFG_ABORT:
> -			if (disable_bypass)
> +			//No bypass override for Xen
>  				break;
>  		default:
>  			BUG(); /* STE corruption */
> @@ -1056,7 +1312,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
>  
>  	/* Bypass/fault */
>  	if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) {
> -		if (!ste->assigned && disable_bypass)
> +		if (!ste->assigned)
>  			val |= STRTAB_STE_0_CFG_ABORT;
>  		else
>  			val |= STRTAB_STE_0_CFG_BYPASS;
> @@ -1135,16 +1391,20 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>  	void *strtab;
>  	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>  	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
> +	u32 alignment = 0;
>  
>  	if (desc->l2ptr)
>  		return 0;
>  
> -	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
> +	size = 1 << (STRTAB_SPLIT + LOG_2(STRTAB_STE_DWORDS) + 3);
>  	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>  
>  	desc->span = STRTAB_SPLIT + 1;
> -	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
> -					  GFP_KERNEL | __GFP_ZERO);
> +
> +	alignment = 1 << ((5 + (desc->span - 1)));
> +	desc->l2ptr = _xzalloc(size, alignment);
> +	desc->l2ptr_dma = virt_to_maddr(desc->l2ptr);
> +
>  	if (!desc->l2ptr) {
>  		dev_err(smmu->dev,
>  			"failed to allocate l2 stream table for SID %u\n",
> @@ -1158,7 +1418,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>  }
>  
>  /* IRQ and event handlers */
> -static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
> +static void arm_smmu_evtq_thread(int irq, void *dev, struct cpu_user_regs *regs)
>  {
>  	int i;
>  	struct arm_smmu_device *smmu = dev;
> @@ -1186,7 +1446,6 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>  
>  	/* Sync our overflow flag, as we believe we're up to speed */
>  	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
> -	return IRQ_HANDLED;
>  }
>  
>  static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
> @@ -1203,7 +1462,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 0x%016lx\n",
>  		 sid, ssid, grpid, last ? "L" : "",
>  		 evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
>  		 evt[0] & PRIQ_0_PERM_READ ? "R" : "",
> @@ -1227,7 +1486,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
>  	}
>  }
>  
> -static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
> +static void arm_smmu_priq_thread(int irq, void *dev, struct cpu_user_regs *regs)
>  {
>  	struct arm_smmu_device *smmu = dev;
>  	struct arm_smmu_queue *q = &smmu->priq.q;
> @@ -1243,18 +1502,16 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
>  
>  	/* Sync our overflow flag, as we believe we're up to speed */
>  	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
> -	return IRQ_HANDLED;
>  }
>  
> -static irqreturn_t arm_smmu_cmdq_sync_handler(int irq, void *dev)
> +static void arm_smmu_cmdq_sync_handler(int irq, void *dev, struct cpu_user_regs *regs)
>  {
>  	/* We don't actually use CMD_SYNC interrupts for anything */
> -	return IRQ_HANDLED;
>  }
>  
>  static int arm_smmu_device_disable(struct arm_smmu_device *smmu);
>  
> -static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
> +static void arm_smmu_gerror_handler(int irq, void *dev, struct cpu_user_regs *regs)
>  {
>  	u32 gerror, gerrorn, active;
>  	struct arm_smmu_device *smmu = dev;
> @@ -1264,7 +1521,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>  
>  	active = gerror ^ gerrorn;
>  	if (!(active & GERROR_ERR_MASK))
> -		return IRQ_NONE; /* No errors pending */
> +		return; /* No errors pending */
>  
>  	dev_warn(smmu->dev,
>  		 "unexpected global error reported (0x%08x), this could be serious\n",
> @@ -1286,7 +1543,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>  
>  	if (active & GERROR_MSI_CMDQ_ABT_ERR) {
>  		dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
> -		arm_smmu_cmdq_sync_handler(irq, smmu->dev);
> +		arm_smmu_cmdq_sync_handler(irq, smmu->dev, NULL);
>  	}
>  
>  	if (active & GERROR_PRIQ_ABT_ERR)
> @@ -1299,7 +1556,6 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>  		arm_smmu_cmdq_skip_err(smmu);
>  
>  	writel(gerror, smmu->base + ARM_SMMU_GERRORN);
> -	return IRQ_HANDLED;
>  }
>  
>  /* IO_PGTABLE API */
> @@ -1311,11 +1567,13 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
>  	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
>  }
>  
> +#if 0 /*Xen: Unused function */
>  static void arm_smmu_tlb_sync(void *cookie)
>  {
>  	struct arm_smmu_domain *smmu_domain = cookie;
>  	__arm_smmu_tlb_sync(smmu_domain->smmu);
>  }
> +#endif
>  
>  static void arm_smmu_tlb_inv_context(void *cookie)
>  {
> @@ -1336,6 +1594,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
>  	__arm_smmu_tlb_sync(smmu);
>  }
>  
> +#if 0 /*Xen: Unused functionality */
>  static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
>  					  size_t granule, bool leaf, void *cookie)
>  {
> @@ -1362,7 +1621,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
>  	} while (size -= granule);
>  }
>  
> -static const struct iommu_gather_ops arm_smmu_gather_ops = {
> +static struct iommu_gather_ops arm_smmu_gather_ops = {
>  	.tlb_flush_all	= arm_smmu_tlb_inv_context,
>  	.tlb_add_flush	= arm_smmu_tlb_inv_range_nosync,
>  	.tlb_sync	= arm_smmu_tlb_sync,
> @@ -1380,6 +1639,11 @@ static bool arm_smmu_capable(enum iommu_cap cap)
>  		return false;
>  	}
>  }
> +#endif
> +/* Xen: Stub out DMA domain related functions */
> +#define iommu_get_dma_cookie(dom) 0
> +#define iommu_put_dma_cookie(dom) 0
> +
>  
>  static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  {
> @@ -1410,6 +1674,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  	return &smmu_domain->domain;
>  }
>  
> +#if 0
>  static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
>  {
>  	int idx, size = 1 << span;
> @@ -1427,36 +1692,20 @@ static void arm_smmu_bitmap_free(unsigned long *map, int idx)
>  {
>  	clear_bit(idx, map);
>  }
> +#endif
>  
>  static void arm_smmu_domain_free(struct iommu_domain *domain)
>  {
>  	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
> -	struct arm_smmu_device *smmu = smmu_domain->smmu;
> -
> -	iommu_put_dma_cookie(domain);
> -	free_io_pgtable_ops(smmu_domain->pgtbl_ops);
> -
> -	/* Free the CD and ASID, if we allocated them */
> -	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
> -		struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
> -
> -		if (cfg->cdptr) {
> -			dmam_free_coherent(smmu_domain->smmu->dev,
> -					   CTXDESC_CD_DWORDS << 3,
> -					   cfg->cdptr,
> -					   cfg->cdptr_dma);
> -
> -			arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
> -		}
> -	} else {
> -		struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
> -		if (cfg->vmid)
> -			arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
> -	}
> +	/*
> +	 * Xen: Remove the free functions that are not used and code related
> +	 * to S1 translation. We just need to free the domain here.
> +	 */
>  
>  	kfree(smmu_domain);
>  }
>  
> +#if 0
>  static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
>  				       struct io_pgtable_cfg *pgtbl_cfg)
>  {
> @@ -1488,33 +1737,30 @@ out_free_asid:
>  	arm_smmu_bitmap_free(smmu->asid_map, asid);
>  	return ret;
>  }
> +#endif
>  
> -static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
> -				       struct io_pgtable_cfg *pgtbl_cfg)
> +static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain)
>  {
> -	int vmid;
> -	struct arm_smmu_device *smmu = smmu_domain->smmu;
>  	struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>  
> -	vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
> -	if (vmid < 0)
> -		return vmid;
> +	/* Xen: Set the values as needed */
>  
> -	cfg->vmid	= (u16)vmid;
> -	cfg->vttbr	= pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
> -	cfg->vtcr	= pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
> +	cfg->vmid	= cfg->domain->arch.p2m.vmid;
> +	cfg->vttbr	= page_to_maddr(cfg->domain->arch.p2m.root);
> +	cfg->vtcr	= READ_SYSREG32(VTCR_EL2);
>  	return 0;
>  }
>  
>  static int arm_smmu_domain_finalise(struct iommu_domain *domain)
>  {
>  	int ret;
> +#if 0	/* Xen: pgtbl_cfg not needed. So modify the function as needed */
>  	unsigned long ias, oas;
>  	enum io_pgtable_fmt fmt;
>  	struct io_pgtable_cfg pgtbl_cfg;
>  	struct io_pgtable_ops *pgtbl_ops;
> -	int (*finalise_stage_fn)(struct arm_smmu_domain *,
> -				 struct io_pgtable_cfg *);
> +	int (*finalise_stage_fn)(struct arm_smmu_domain *);
> +#endif
>  	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>  	struct arm_smmu_device *smmu = smmu_domain->smmu;
>  
> @@ -1529,6 +1775,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
>  	if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2))
>  		smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
>  
> +#if 0
>  	switch (smmu_domain->stage) {
>  	case ARM_SMMU_DOMAIN_S1:
>  		ias = VA_BITS;
> @@ -1563,10 +1810,11 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
>  	domain->geometry.aperture_end = (1UL << ias) - 1;
>  	domain->geometry.force_aperture = true;
>  	smmu_domain->pgtbl_ops = pgtbl_ops;
> -
>  	ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
>  	if (ret < 0)
>  		free_io_pgtable_ops(pgtbl_ops);
> +#endif
> +	ret = arm_smmu_domain_finalise_s2(smmu_domain);
>  
>  	return ret;
>  }
> @@ -1660,7 +1908,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  	} else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>  		ste->s1_cfg = &smmu_domain->s1_cfg;
>  		ste->s2_cfg = NULL;
> -		arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
> +		/*Xen: S1 configuratio not needed */
> +		//arm_smmu_write_ctx_desc(smmu, ste->s1_cfg);
>  	} else {
>  		ste->s1_cfg = NULL;
>  		ste->s2_cfg = &smmu_domain->s2_cfg;
> @@ -1672,6 +1921,7 @@ out_unlock:
>  	return ret;
>  }
>  
> +#if 0
>  static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
>  			phys_addr_t paddr, size_t size, int prot)
>  {
> @@ -1737,11 +1987,13 @@ static int arm_smmu_match_node(struct device *dev, void *data)
>  static
>  struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
>  {
> +	/* Xen; Function modified as needed for Xen.*/
>  	struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
>  						fwnode, arm_smmu_match_node);
>  	put_device(dev);
>  	return dev ? dev_get_drvdata(dev) : NULL;
>  }
> +#endif
>  
>  static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
>  {
> @@ -1752,8 +2004,9 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
>  
>  	return sid < limit;
>  }
> -
> +#if 0
>  static struct iommu_ops arm_smmu_ops;
> +#endif
>  
>  static int arm_smmu_add_device(struct device *dev)
>  {
> @@ -1761,9 +2014,9 @@ 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;
> -	struct iommu_group *group;
>  
> -	if (!fwspec || fwspec->ops != &arm_smmu_ops)
> +	/* Xen: fwspec->ops are not needed */
> +	if (!fwspec)
>  		return -ENODEV;
>  	/*
>  	 * We _can_ actually withstand dodgy bus code re-calling add_device()
> @@ -1800,6 +2053,12 @@ static int arm_smmu_add_device(struct device *dev)
>  		}
>  	}
>  
> +#if 0
> +/*
> + * Xen: Do not need an iommu group as the stream data is carried by the SMMU
> + * master device object
> + */
> +
>  	group = iommu_group_get_for_dev(dev);
>  	if (!IS_ERR(group)) {
>  		iommu_group_put(group);
> @@ -1807,8 +2066,16 @@ static int arm_smmu_add_device(struct device *dev)
>  	}
>  
>  	return PTR_ERR_OR_ZERO(group);
> +#endif
> +	return 0;
>  }
>  
> +/*
> + * Xen: We can potentially support this function and destroy a device. This
> + * will be relevant for PCI hotplug. So, will be implemented as needed after
> + * passthrough support is available.
> + */
> +#if 0
>  static void arm_smmu_remove_device(struct device *dev)
>  {
>  	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
> @@ -1944,7 +2211,7 @@ static struct iommu_ops arm_smmu_ops = {
>  	.put_resv_regions	= arm_smmu_put_resv_regions,
>  	.pgsize_bitmap		= -1UL, /* Restricted during device attach */
>  };
> -
> +#endif
>  /* Probing and initialisation functions */
>  static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
>  				   struct arm_smmu_queue *q,
> @@ -1954,7 +2221,12 @@ static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
>  {
>  	size_t qsz = ((1 << q->max_n_shift) * dwords) << 3;
>  
> -	q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL);
> +	/* The SMMU cache coherency property is always set. Since we are sharing the CPU translation tables
> +	 * just make a regular allocation.
> +	 */
> +	q->base = _xzalloc(qsz, sizeof(void *));
> +	q->base_dma = virt_to_maddr(q->base);
> +
>  	if (!q->base) {
>  		dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes)\n",
>  			qsz);
> @@ -2025,10 +2297,11 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
>  	void *strtab;
>  	u64 reg;
>  	u32 size, l1size;
> +	u32 alignment;
>  	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>  
>  	/* Calculate the L1 size, capped to the SIDSIZE. */
> -	size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
> +	size = STRTAB_L1_SZ_SHIFT - (LOG_2(STRTAB_L1_DESC_DWORDS) + 3);
>  	size = min(size, smmu->sid_bits - STRTAB_SPLIT);
>  	cfg->num_l1_ents = 1 << size;
>  
> @@ -2039,8 +2312,13 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
>  			 size, smmu->sid_bits);
>  
>  	l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
> -	strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
> -				     GFP_KERNEL | __GFP_ZERO);
> +
> +	alignment = max_t(u32, cfg->num_l1_ents, 64);
> +	//strtab = _xzalloc(l1size, sizeof(void *));
> +	strtab = _xzalloc(l1size, l1size);
> +	cfg->strtab_dma = virt_to_maddr(strtab);
> +
> +	//dsb(sy);
>  	if (!strtab) {
>  		dev_err(smmu->dev,
>  			"failed to allocate l1 stream table (%u bytes)\n",
> @@ -2068,8 +2346,9 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
>  	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>  
>  	size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3);
> -	strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma,
> -				     GFP_KERNEL | __GFP_ZERO);
> +	strtab = _xzalloc(size, size);
> +	cfg->strtab_dma = virt_to_maddr(strtab);
> +
>  	if (!strtab) {
>  		dev_err(smmu->dev,
>  			"failed to allocate linear stream table (%u bytes)\n",
> @@ -2152,6 +2431,8 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
>  					  1, ARM_SMMU_POLL_TIMEOUT_US);
>  }
>  
> +/* Xen: There is no MSI support as yet */
> +#if 0
>  static void arm_smmu_free_msis(void *data)
>  {
>  	struct device *dev = data;
> @@ -2217,7 +2498,7 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
>  	/* Add callback to free MSIs on teardown */
>  	devm_add_action(dev, arm_smmu_free_msis, dev);
>  }
> -
> +#endif
>  static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
>  {
>  	int ret, irq;
> @@ -2231,31 +2512,31 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
>  		return ret;
>  	}
>  
> -	arm_smmu_setup_msis(smmu);
> +	//arm_smmu_setup_msis(smmu);
>  
>  	/* Request interrupt lines */
>  	irq = smmu->evtq.q.irq;
>  	if (irq) {
> -		ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
> -						arm_smmu_evtq_thread,
> -						IRQF_ONESHOT,
> -						"arm-smmu-v3-evtq", smmu);
> +		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
> +		ret = request_irq(irq, arm_smmu_evtq_thread,
> +						0, "arm-smmu-v3-evtq", smmu);
>  		if (ret < 0)
>  			dev_warn(smmu->dev, "failed to enable evtq irq\n");
>  	}
>  
>  	irq = smmu->cmdq.q.irq;
>  	if (irq) {
> -		ret = devm_request_irq(smmu->dev, irq,
> -				       arm_smmu_cmdq_sync_handler, 0,
> -				       "arm-smmu-v3-cmdq-sync", smmu);
> +		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
> +		ret = request_irq(irq, arm_smmu_cmdq_sync_handler,
> +				0, "arm-smmu-v3-cmdq-sync", smmu);
>  		if (ret < 0)
>  			dev_warn(smmu->dev, "failed to enable cmdq-sync irq\n");
>  	}
>  
>  	irq = smmu->gerr_irq;
>  	if (irq) {
> -		ret = devm_request_irq(smmu->dev, irq, arm_smmu_gerror_handler,
> +		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
> +		ret = request_irq(irq, arm_smmu_gerror_handler,
>  				       0, "arm-smmu-v3-gerror", smmu);
>  		if (ret < 0)
>  			dev_warn(smmu->dev, "failed to enable gerror irq\n");
> @@ -2263,12 +2544,13 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
>  
>  	if (smmu->features & ARM_SMMU_FEAT_PRI) {
>  		irq = smmu->priq.q.irq;
> +		irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
>  		if (irq) {
> -			ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
> -							arm_smmu_priq_thread,
> -							IRQF_ONESHOT,
> -							"arm-smmu-v3-priq",
> -							smmu);
> +			ret = request_irq(irq,
> +					  arm_smmu_priq_thread,
> +					  0,
> +					  "arm-smmu-v3-priq",
> +					  smmu);
>  			if (ret < 0)
>  				dev_warn(smmu->dev,
>  					 "failed to enable priq irq\n");
> @@ -2400,7 +2682,7 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
>  
>  
>  	/* Enable the SMMU interface, or ensure bypass */
> -	if (!bypass || disable_bypass) {
> +	if (!bypass) {
>  		enables |= CR0_SMMUEN;
>  	} else {
>  		ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
> @@ -2488,8 +2770,11 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
>  		smmu->features |= ARM_SMMU_FEAT_STALLS;
>  	}
>  
> +#if 0/* Xen: Do not enable Stage 1 translations */
> +
>  	if (reg & IDR0_S1P)
>  		smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
> +#endif
>  
>  	if (reg & IDR0_S2P)
>  		smmu->features |= ARM_SMMU_FEAT_TRANS_S2;
> @@ -2562,10 +2847,12 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
>  	if (reg & IDR5_GRAN4K)
>  		smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
>  
> +#if 0 /* Xen: SMMU ops do not have a pgsize_bitmap member for Xen */
>  	if (arm_smmu_ops.pgsize_bitmap == -1UL)
>  		arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
>  	else
>  		arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
> +#endif
>  
>  	/* Output address size */
>  	switch (reg & IDR5_OAS_MASK << IDR5_OAS_SHIFT) {
> @@ -2592,10 +2879,12 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
>  		smmu->oas = 48;
>  	}
>  
> +#if 0 /* Xen: There is no support for DMA mask */
>  	/* Set the DMA mask for our table walker */
>  	if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas)))
>  		dev_warn(smmu->dev,
>  			 "failed to set DMA mask for table walker\n");
> +#endif
>  
>  	smmu->ias = max(smmu->ias, smmu->oas);
>  
> @@ -2612,7 +2901,8 @@ static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
>  	struct device *dev = smmu->dev;
>  	struct acpi_iort_node *node;
>  
> -	node = *(struct acpi_iort_node **)dev_get_platdata(dev);
> +	/* Xen: Modification to get iort_node */
> +	node = (struct acpi_iort_node *)dev->acpi_node;
>  
>  	/* Retrieve SMMUv3 specific data */
>  	iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
> @@ -2633,7 +2923,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;
>  
> @@ -2646,8 +2936,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
>  
>  	parse_driver_options(smmu);
>  
> -	if (of_dma_is_coherent(dev->of_node))
> -		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
> +	/* Xen: Set the COHERNECY feature */
> +	smmu->features |= ARM_SMMU_FEAT_COHERENCY;
>  
>  	return ret;
>  }
> @@ -2656,9 +2946,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  {
>  	int irq, ret;
>  	struct resource *res;
> -	resource_size_t ioaddr;
> +	/*Xen: Do not need to setup sysfs */
> +	/* resource_size_t ioaddr;*/
>  	struct arm_smmu_device *smmu;
> -	struct device *dev = &pdev->dev;
> +	struct device *dev = pdev;/* Xen: dev is ignored */
>  	bool bypass;
>  
>  	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
> @@ -2674,7 +2965,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  		dev_err(dev, "MMIO region too small (%pr)\n", res);
>  		return -EINVAL;
>  	}
> -	ioaddr = res->start;
> +	/*ioaddr = res->start;*/
>  
>  	smmu->base = devm_ioremap_resource(dev, res);
>  	if (IS_ERR(smmu->base))
> @@ -2719,13 +3010,15 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	/* Record our private device structure */
> -	platform_set_drvdata(pdev, smmu);
> +	/* platform_set_drvdata(pdev, smmu); */
>  
>  	/* Reset the device */
>  	ret = arm_smmu_device_reset(smmu, bypass);
>  	if (ret)
>  		return ret;
>  
> +/* Xen: Not creating an IOMMU device list for Xen */
> +#if 0
>  	/* And we're up. Go go go! */
>  	ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
>  				     "smmu3.%pa", &ioaddr);
> @@ -2757,9 +3050,18 @@ 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;
>  }
> -
> +#if 0
>  static int arm_smmu_device_remove(struct platform_device *pdev)
>  {
>  	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
> @@ -2767,6 +3069,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
>  	arm_smmu_device_disable(smmu);
>  	return 0;
>  }
> +#endif
> +#define MODULE_DEVICE_TABLE(type, name)
> +#define of_device_id dt_device_match
>  
>  static struct of_device_id arm_smmu_of_match[] = {
>  	{ .compatible = "arm,smmu-v3", },
> @@ -2774,6 +3079,7 @@ static struct of_device_id arm_smmu_of_match[] = {
>  };
>  MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
>  
> +#if 0
>  static struct platform_driver arm_smmu_driver = {
>  	.driver	= {
>  		.name		= "arm-smmu-v3",
> @@ -2789,3 +3095,318 @@ IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", NULL);
>  MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
>  MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
>  MODULE_LICENSE("GPL v2");
> +
> +#endif
> +/***** Start of Xen specific code *****/
> +
> +static int __must_check arm_smmu_iotlb_flush_all(struct domain *d)
> +{
> +	struct arm_smmu_xen_domain *smmu_domain = dom_iommu(d)->arch.priv;
> +	struct iommu_domain *cfg;
> +
> +	spin_lock(&smmu_domain->lock);
> +	list_for_each_entry(cfg, &smmu_domain->iommu_domains, list) {
> +		/*
> +		 * Only invalidate the context when SMMU is present.
> +		 * This is because the context initialization is delayed
> +		 * until a master has been added.
> +		 */
> +		if (unlikely(!ACCESS_ONCE(cfg->priv->smmu)))
> +			continue;
> +		arm_smmu_tlb_inv_context(cfg->priv);
> +	}
> +	spin_unlock(&smmu_domain->lock);
> +	return 0;
> +}
> +
> +static int __must_check arm_smmu_iotlb_flush(struct domain *d,
> +					     unsigned long gfn,
> +					     unsigned int page_count)
> +{
> +	return arm_smmu_iotlb_flush_all(d);
> +}
> +
> +static struct iommu_domain *arm_smmu_get_domain(struct domain *d,
> +						struct device *dev)
> +{
> +	struct iommu_domain *domain;
> +	struct arm_smmu_xen_domain *xen_domain;
> +	struct arm_smmu_device *smmu;
> +	struct arm_smmu_domain *smmu_domain;
> +
> +	xen_domain = dom_iommu(d)->arch.priv;
> +
> +	smmu = arm_smmu_get_by_fwnode(dev->iommu_fwspec->iommu_fwnode);
> +	if (!smmu)
> +		return NULL;
> +
> +	/*
> +	 * Loop through the &xen_domain->contexts to locate a context
> +	 * assigned to this SMMU
> +	 */
> +	list_for_each_entry(domain, &xen_domain->iommu_domains, list) {
> +		smmu_domain = to_smmu_domain(domain);
> +		if (smmu_domain->smmu == smmu)
> +			return domain;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void arm_smmu_destroy_iommu_domain(struct iommu_domain *domain)
> +{
> +	list_del(&domain->list);
> +	xfree(domain);
> +}
The above function needs to call arm_smmu_domain_free(domain) instead of xfree(domain).

> +
> +static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
> +			       struct device *dev, u32 flag)
> +{
> +	int ret = 0;
> +	struct iommu_domain *domain;
> +	struct arm_smmu_xen_domain *xen_domain;
> +	struct arm_smmu_domain *arm_smmu;
> +
> +	xen_domain = dom_iommu(d)->arch.priv;
> +
> +	if (!dev->archdata.iommu) {
> +		dev->archdata.iommu = xzalloc(struct arm_smmu_xen_device);
> +		if (!dev->archdata.iommu)
> +			return -ENOMEM;
> +	}
> +
> +	ret = arm_smmu_add_device(dev);
> +	if (ret)
> +		return ret;
> +
> +	spin_lock(&xen_domain->lock);
> +
> +	/*
> +	 * Check to see if an iommu_domain already exists for this xen domain
> +	 * under the same SMMU
> +	 */
> +	domain = arm_smmu_get_domain(d, dev);
> +	if (!domain) {
> +
> +		domain = arm_smmu_domain_alloc(IOMMU_DOMAIN_DMA);
> +		if (!domain) {
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +
> +		arm_smmu = to_smmu_domain(domain);
> +		arm_smmu->s2_cfg.domain = d;
> +
> +		/* Chain the new context to the domain */
> +		list_add(&domain->list, &xen_domain->iommu_domains);
> +
> +	}
> +
> +	ret = arm_smmu_attach_dev(domain, dev);
> +	if (ret) {
> +		if (domain->ref.counter == 0)
> +			arm_smmu_destroy_iommu_domain(domain);
> +	} else {
> +		atomic_inc(&domain->ref);
> +	}
> +
> +out:
> +	spin_unlock(&xen_domain->lock);
> +	return ret;
> +}
> +
> +static int arm_smmu_deassign_dev(struct domain *d, struct device *dev)
> +{
> +	struct iommu_domain *domain = arm_smmu_get_domain(d, dev);
> +	struct arm_smmu_xen_domain *xen_domain;
> +	struct arm_smmu_domain *arm_smmu = to_smmu_domain(domain);
> +
> +	xen_domain = dom_iommu(d)->arch.priv;
> +
> +	if (!arm_smmu || arm_smmu->s2_cfg.domain != d) {
> +		dev_err(dev, " not attached to domain %d\n", d->domain_id);
> +		return -ESRCH;
> +	}
> +
> +	spin_lock(&xen_domain->lock);
> +
> +	arm_smmu_detach_dev(dev);
> +	atomic_dec(&domain->ref);
> +
> +	if (domain->ref.counter == 0)
> +		arm_smmu_destroy_iommu_domain(domain);
> +
> +	spin_unlock(&xen_domain->lock);
> +
> +
> +
> +	return 0;
> +}
> +
> +static int arm_smmu_reassign_dev(struct domain *s, struct domain *t,
> +				 u8 devfn,  struct device *dev)
> +{
> +	int ret = 0;
> +
> +	/* Don't allow remapping on other domain than hwdom */
> +	if (t && t != hardware_domain)
> +		return -EPERM;
> +
> +	if (t == s)
> +		return 0;
> +
> +	ret = arm_smmu_deassign_dev(s, dev);
> +	if (ret)
> +		return ret;
> +
> +	if (t) {
> +		/* No flags are defined for ARM. */
> +		ret = arm_smmu_assign_dev(t, devfn, dev, 0);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int arm_smmu_iommu_domain_init(struct domain *d)
> +{
> +	struct arm_smmu_xen_domain *xen_domain;
> +
> +	xen_domain = xzalloc(struct arm_smmu_xen_domain);
> +	if (!xen_domain)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&xen_domain->lock);
> +	INIT_LIST_HEAD(&xen_domain->iommu_domains);
> +
> +	dom_iommu(d)->arch.priv = xen_domain;
> +
> +	return 0;
> +}
> +
> +static void __hwdom_init arm_smmu_iommu_hwdom_init(struct domain *d)
> +{
> +}
> +
> +static void arm_smmu_iommu_domain_teardown(struct domain *d)
> +{
> +	struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv;
> +
> +	ASSERT(list_empty(&xen_domain->iommu_domains));
> +	xfree(xen_domain);
> +}
> +
> +static int __must_check arm_smmu_map_page(struct domain *d, unsigned long gfn,
> +			unsigned long mfn, unsigned int flags)
> +{
> +	p2m_type_t t;
> +
> +	/*
> +	 * Grant mappings can be used for DMA requests. The dev_bus_addr
> +	 * returned by the hypercall is the MFN (not the IPA). For device
> +	 * protected by an IOMMU, Xen needs to add a 1:1 mapping in the domain
> +	 * p2m to allow DMA request to work.
> +	 * This is only valid when the domain is directed mapped. Hence this
> +	 * function should only be used by gnttab code with gfn == mfn.
> +	 */
> +	BUG_ON(!is_domain_direct_mapped(d));
> +	BUG_ON(mfn != gfn);
> +
> +	/* We only support readable and writable flags */
> +	if (!(flags & (IOMMUF_readable | IOMMUF_writable)))
> +		return -EINVAL;
> +
> +	t = (flags & IOMMUF_writable) ? p2m_iommu_map_rw : p2m_iommu_map_ro;
> +
> +	/*
> +	 * The function guest_physmap_add_entry replaces the current mapping
> +	 * if there is already one...
> +	 */
> +	return guest_physmap_add_entry(d, _gfn(gfn), _mfn(mfn), 0, t);
> +}
> +
> +static int __must_check arm_smmu_unmap_page(struct domain *d, unsigned long gfn)
> +{
> +	/*
> +	 * This function should only be used by gnttab code when the domain
> +	 * is direct mapped
> +	 */
> +	if (!is_domain_direct_mapped(d))
> +		return -EINVAL;
> +
> +	return guest_physmap_remove_page(d, _gfn(gfn), _mfn(gfn), 0);
> +}
> +
> +static const struct iommu_ops arm_smmu_iommu_ops = {
> +	.init = arm_smmu_iommu_domain_init,
> +	.hwdom_init = arm_smmu_iommu_hwdom_init,
> +	.teardown = arm_smmu_iommu_domain_teardown,
> +	.iotlb_flush = arm_smmu_iotlb_flush,
> +	.iotlb_flush_all = arm_smmu_iotlb_flush_all,
> +	.assign_device = arm_smmu_assign_dev,
> +	.reassign_device = arm_smmu_reassign_dev,
> +	.map_page = arm_smmu_map_page,
> +	.unmap_page = arm_smmu_unmap_page,
> +};
> +
> +static
> +struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
> +{
> +	struct arm_smmu_device *smmu = NULL;
> +
> +	spin_lock(&arm_smmu_devices_lock);
> +	list_for_each_entry(smmu, &arm_smmu_devices, devices) {
> +		if (smmu->dev->fwnode == fwnode)
> +			break;
> +	}
> +	spin_unlock(&arm_smmu_devices_lock);
> +
> +	return smmu;
> +}
> +
> +static __init int arm_smmu_dt_init(struct dt_device_node *dev,
> +				   const void *data)
> +{
> +	int rc;
> +
> +	/*
> +	 * Even if the device can't be initialized, we don't want to
> +	 * give the SMMU device to dom0.
> +	 */
> +	dt_device_set_used_by(dev, DOMID_XEN);
> +
> +	rc = arm_smmu_device_probe(dt_to_dev(dev));
> +	if (rc)
> +		return rc;
> +
> +	iommu_set_ops(&arm_smmu_iommu_ops);
> +
> +	return 0;
> +}
> +
> +DT_DEVICE_START(smmuv3, "ARM SMMU V3", DEVICE_IOMMU)
> +	.dt_match = arm_smmu_of_match,
> +	.init = arm_smmu_dt_init,
> +DT_DEVICE_END
> +
> +#ifdef CONFIG_ACPI
> +/* Set up the IOMMU */
> +static int __init arm_smmu_acpi_init(const void *data)
> +{
> +	int rc;
> +	rc = arm_smmu_device_probe((struct device *)data);
> +
> +	if (rc)
> +		return rc;
> +
> +	iommu_set_ops(&arm_smmu_iommu_ops);
> +	return 0;
> +}
> +
> +ACPI_DEVICE_START(asmmuv3, "ARM SMMU V3", DEVICE_IOMMU)
> +	.class_type = ACPI_IORT_NODE_SMMU_V3,
> +	.init = arm_smmu_acpi_init,
> +ACPI_DEVICE_END
> +
> +#endif
> 

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-09-21  0:37 ` [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table Sameer Goel
@ 2017-10-10 12:36   ` Manish Jaggi
  2017-10-19 15:00     ` Goel, Sameer
  2017-10-12 14:06   ` Julien Grall
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 34+ messages in thread
From: Manish Jaggi @ 2017-10-10 12:36 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,
On 9/21/2017 6:07 AM, Sameer Goel wrote:
> Add support for parsing IORT table to initialize SMMU devices.
> * The code for creating an SMMU device has been modified, so that the SMMU
> device can be initialized.
> * The NAMED NODE code has been commented out as this will need DOM0 kernel
> support.
> * ITS code has been included but it has not been tested.
Could you please refactor this patch into another set of two patches.
I am planning to rebase my IORT for Dom0 Hiding patch rework on this patch.
Thanks,
Manish
> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
> ---
>   xen/arch/arm/setup.c               |   3 +
>   xen/drivers/acpi/Makefile          |   1 +
>   xen/drivers/acpi/arm/Makefile      |   1 +
>   xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
>   xen/drivers/passthrough/arm/smmu.c |   1 +
>   xen/include/acpi/acpi_iort.h       |  17 ++--
>   xen/include/asm-arm/device.h       |   2 +
>   xen/include/xen/acpi.h             |  21 +++++
>   xen/include/xen/pci.h              |   8 ++
>   9 files changed, 146 insertions(+), 81 deletions(-)
>   create mode 100644 xen/drivers/acpi/arm/Makefile
>
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index 92f173b..4ba09b2 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -49,6 +49,7 @@
>   #include <asm/setup.h>
>   #include <xsm/xsm.h>
>   #include <asm/acpi.h>
> +#include <acpi/acpi_iort.h>
>   
>   struct bootinfo __initdata bootinfo;
>   
> @@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
>   
>       tasklet_subsys_init();
>   
> +    /* Parse the ACPI iort data */
> +    acpi_iort_init();
>   
>       xsm_dt_init();
>   
> diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
> index 444b11d..e7ffd82 100644
> --- a/xen/drivers/acpi/Makefile
> +++ b/xen/drivers/acpi/Makefile
> @@ -1,5 +1,6 @@
>   subdir-y += tables
>   subdir-y += utilities
> +subdir-$(CONFIG_ARM) += arm
>   subdir-$(CONFIG_X86) += apei
>   
>   obj-bin-y += tables.init.o
> diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
> new file mode 100644
> index 0000000..7c039bb
> --- /dev/null
> +++ b/xen/drivers/acpi/arm/Makefile
> @@ -0,0 +1 @@
> +obj-y += iort.o
> diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
> index 2e368a6..7f54062 100644
> --- a/xen/drivers/acpi/arm/iort.c
> +++ b/xen/drivers/acpi/arm/iort.c
> @@ -14,17 +14,47 @@
>    * This file implements early detection/parsing of I/O mapping
>    * reported to OS through firmware via I/O Remapping Table (IORT)
>    * IORT document number: ARM DEN 0049A
> + *
> + * Based on Linux drivers/acpi/arm64/iort.c
> + * => commit ca78d3173cff3503bcd15723b049757f75762d15
> + *
> + * Xen modification:
> + * Sameer Goel <sgoel@codeaurora.org>
> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
> + *
>    */
>   
> -#define pr_fmt(fmt)	"ACPI: IORT: " fmt
> -
> -#include <linux/acpi_iort.h>
> -#include <linux/iommu.h>
> -#include <linux/kernel.h>
> -#include <linux/list.h>
> -#include <linux/pci.h>
> -#include <linux/platform_device.h>
> -#include <linux/slab.h>
> +#include <xen/acpi.h>
> +#include <acpi/acpi_iort.h>
> +#include <xen/fwnode.h>
> +#include <xen/iommu.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/pci.h>
> +
> +#include <asm/device.h>
> +
> +/* Xen: Define compatibility functions */
> +#define FW_BUG		"[Firmware Bug]: "
> +#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
> +#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
> +
> +/* Alias to Xen allocation helpers */
> +#define kfree xfree
> +#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
> +#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))
> +
> +/* Redefine WARN macros */
> +#undef WARN
> +#undef WARN_ON
> +#define WARN(condition, format...) ({					\
> +	int __ret_warn_on = !!(condition);				\
> +	if (unlikely(__ret_warn_on))					\
> +		printk(format);						\
> +	unlikely(__ret_warn_on);					\
> +})
> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
> +#define WARN_ON(cond)                      (!!cond)
>   
>   #define IORT_TYPE_MASK(type)	(1 << (type))
>   #define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   	acpi_status status;
>   
>   	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
> +		status = AE_NOT_IMPLEMENTED;
> +/*
> + * We need the namespace object name from dsdt to match the iort node, this
> + * will need additions to the kernel xen bus notifiers.
> + * So, disabling the named node code till a proposal is approved.
> + */
> +#if 0
>   		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>   		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>   		struct acpi_iort_named_component *ncomp;
> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   		status = !strcmp(ncomp->device_name, buf.pointer) ?
>   							AE_OK : AE_NOT_FOUND;
>   		acpi_os_free(buf.pointer);
> +#endif
>   	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>   		struct acpi_iort_root_complex *pci_rc;
> -		struct pci_bus *bus;
> +		struct pci_dev *pci_dev;
>   
> -		bus = to_pci_bus(dev);
> +		pci_dev = to_pci_dev(dev);
>   		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>   
>   		/*
> @@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   		 * with root complexes. Each segment number can represent only
>   		 * one root complex.
>   		 */
> -		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
> +		status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
>   							AE_OK : AE_NOT_FOUND;
>   	} else {
>   		status = AE_NOT_FOUND;
>   	}
> -out:
>   	return status;
>   }
>   
> @@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
>   	return 0;
>   }
>   
> +/*
> + * Named components are not supported yet so we do not need the
> + * iort_node_get_id function
> + */
> +#if 0
>   static
>   struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>   					u32 *id_out, u8 type_mask,
> @@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>   
>   	return NULL;
>   }
> +#endif
>   
>   static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
>   						u32 rid_in, u32 *rid_out,
> @@ -410,6 +453,10 @@ fail_map:
>   	return NULL;
>   }
>   
> +/* Xen: Comment out the NamedComponent and ITS mapping code till the support
> + * is available.
> + */
> +#if 0
>   static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
>   {
>   	struct pci_bus *pbus;
> @@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
>   	return 0;
>   }
>   
> -/**
> +/*
>    * iort_get_device_domain() - Find MSI domain related to a device
>    * @dev: The device.
>    * @req_id: Requester ID for the device.
> @@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>   	*rid = alias;
>   	return 0;
>   }
> -
> +#endif
>   static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>   			       struct fwnode_handle *fwnode,
>   			       const struct iommu_ops *ops)
> @@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>   	return ret ? NULL : ops;
>   }
>   
> +#if 0 /* Xen: We do not need this function for Xen */
>   /**
>    * iort_set_dma_mask - Set-up dma mask for a device.
>    *
> @@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
>   	if (!dev->dma_mask)
>   		dev->dma_mask = &dev->coherent_dma_mask;
>   }
> -
> +#endif
>   /**
>    * iort_iommu_configure - Set-up IOMMU configuration for a device.
>    *
> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   	u32 streamid = 0;
>   
>   	if (dev_is_pci(dev)) {
> -		struct pci_bus *bus = to_pci_dev(dev)->bus;
> +		struct pci_dev *pci_device = to_pci_dev(dev);
>   		u32 rid;
>   
> -		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
> -				       &rid);
> +		rid = PCI_BDF2(pci_device->bus, pci_device->devfn);
>   
>   		node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
> -				      iort_match_node_callback, &bus->dev);
> +				      iort_match_node_callback, dev);
>   		if (!node)
>   			return NULL;
>   
> @@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   		ops = iort_iommu_xlate(dev, parent, streamid);
>   
>   	} else {
> +		return NULL;
> +/*
> + * We need the namespace object name from dsdt to match the iort node, this
> + * will need additions to the kernel xen bus notifiers.
> + * So, disabling the named node code till a proposal is approved.
> + */
> +#if 0
>   		int i = 0;
>   
>   		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
> @@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   			parent = iort_node_get_id(node, &streamid,
>   						  IORT_IOMMU_TYPE, i++);
>   		}
> +#endif
>   	}
>   
>   	return ops;
>   }
>   
> +/*
> + * Xen: Not using the parsing ops for now. Need to check and see if it will
> + * be useful to use these in some form, or let the driver parse IORT node.
> + */
> +#if 0
>   static void __init acpi_iort_register_irq(int hwirq, const char *name,
>   					  int trigger,
>   					  struct resource *res)
> @@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>   		return NULL;
>   	}
>   }
> -
> +#endif
>   /**
>    * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>    * @node: Pointer to SMMU ACPI IORT node
> @@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>   static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
>   {
>   	struct fwnode_handle *fwnode;
> -	struct platform_device *pdev;
> -	struct resource *r;
> -	enum dev_dma_attr attr;
> -	int ret, count;
> -	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
> -
> -	if (!ops)
> -		return -ENODEV;
> -
> -	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
> -	if (!pdev)
> -		return -ENOMEM;
> -
> -	count = ops->iommu_count_resources(node);
> -
> -	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
> -	if (!r) {
> -		ret = -ENOMEM;
> -		goto dev_put;
> -	}
> -
> -	ops->iommu_init_resources(r, node);
> +	struct device *dev;
> +	int ret;
>   
> -	ret = platform_device_add_resources(pdev, r, count);
>   	/*
> -	 * Resources are duplicated in platform_device_add_resources,
> -	 * free their allocated memory
> +	 * Not enabling the parsing ops for now. The corresponding driver
> +	 * can parse this information as needed, so deleting relevant code as
> +	 * compared to base revision.
>   	 */
> -	kfree(r);
>   
> -	if (ret)
> -		goto dev_put;
> +	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
> +	if (!dev)
> +		return -ENOMEM;
>   
>   	/*
>   	 * Add a copy of IORT node pointer to platform_data to
>   	 * be used to retrieve IORT data information.
>   	 */
> -	ret = platform_device_add_data(pdev, &node, sizeof(node));
> -	if (ret)
> -		goto dev_put;
> -
> -	/*
> -	 * We expect the dma masks to be equivalent for
> -	 * all SMMUs set-ups
> -	 */
> -	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
> +	dev->type = DEV_ACPI;
> +	dev->acpi_node = node;
>   
>   	fwnode = iort_get_fwnode(node);
>   
>   	if (!fwnode) {
>   		ret = -ENODEV;
> -		goto dev_put;
> +		goto error;
>   	}
>   
> -	pdev->dev.fwnode = fwnode;
> -
> -	attr = ops->iommu_is_coherent(node) ?
> -			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
> -
> -	/* Configure DMA for the page table walker */
> -	acpi_dma_configure(&pdev->dev, attr);
> +	dev->fwnode = fwnode;
>   
> -	ret = platform_device_add(pdev);
> -	if (ret)
> -		goto dma_deconfigure;
> +	/* Call the acpi init functions for IOMMU devices */
> +	ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
>   
>   	return 0;
>   
> -dma_deconfigure:
> -	acpi_dma_deconfigure(&pdev->dev);
> -dev_put:
> -	platform_device_put(pdev);
> +error:
> +	kfree(dev);
>   
>   	return ret;
>   }
> @@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
>   
>   	iort_init_platform_devices();
>   
> -	acpi_probe_device_table(iort);
> +	/* Xen; Do not need a device table probe */
> +	/* acpi_probe_device_table(iort);*/
>   }
> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
> index 362d578..ad956d5 100644
> --- a/xen/drivers/passthrough/arm/smmu.c
> +++ b/xen/drivers/passthrough/arm/smmu.c
> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>    * Xen: PCI functions
>    * TODO: It should be implemented when PCI will be supported
>    */
> +#undef to_pci_dev
>   #define to_pci_dev(dev)	(NULL)
>   static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
>   					 int (*fn) (struct pci_dev *pdev,
> diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
> index 77e0809..d4315a4 100644
> --- a/xen/include/acpi/acpi_iort.h
> +++ b/xen/include/acpi/acpi_iort.h
> @@ -19,27 +19,32 @@
>   #ifndef __ACPI_IORT_H__
>   #define __ACPI_IORT_H__
>   
> -#include <linux/acpi.h>
> -#include <linux/fwnode.h>
> -#include <linux/irqdomain.h>
> +#include <xen/acpi.h>
> +#include <asm/device.h>
>   
> +/* Xen: Not using IORT IRQ bindings */
> +#if 0
>   #define IORT_IRQ_MASK(irq)		(irq & 0xffffffffULL)
>   #define IORT_IRQ_TRIGGER_MASK(irq)	((irq >> 32) & 0xffffffffULL)
>   
>   int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
>   void iort_deregister_domain_token(int trans_id);
>   struct fwnode_handle *iort_find_domain_token(int trans_id);
> -#ifdef CONFIG_ACPI_IORT
> +#endif
> +#ifdef CONFIG_ARM_64
>   void acpi_iort_init(void);
>   bool iort_node_match(u8 type);
> +#if 0
>   u32 iort_msi_map_rid(struct device *dev, u32 req_id);
>   struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
>   /* IOMMU interface */
>   void iort_set_dma_mask(struct device *dev);
> +#endif
>   const struct iommu_ops *iort_iommu_configure(struct device *dev);
>   #else
>   static inline void acpi_iort_init(void) { }
>   static inline bool iort_node_match(u8 type) { return false; }
> +#if 0
>   static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>   { return req_id; }
>   static inline struct irq_domain *iort_get_device_domain(struct device *dev,
> @@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>   { return NULL; }
>   /* IOMMU interface */
>   static inline void iort_set_dma_mask(struct device *dev) { }
> +#endif
>   static inline
>   const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   { return NULL; }
>   #endif
>   
> -#define IORT_ACPI_DECLARE(name, table_id, fn)		\
> -	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
> -
>   #endif /* __ACPI_IORT_H__ */
> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
> index 5027c87..4eef9ce 100644
> --- a/xen/include/asm-arm/device.h
> +++ b/xen/include/asm-arm/device.h
> @@ -7,6 +7,7 @@
>   enum device_type
>   {
>       DEV_DT,
> +    DEV_ACPI,
>   };
>   
>   struct dev_archdata {
> @@ -20,6 +21,7 @@ struct device
>   #ifdef CONFIG_HAS_DEVICE_TREE
>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>   #endif
> +    void *acpi_node; /*Current use case is acpi_iort_node */
>       struct fwnode_handle *fwnode; /*fw device node identifier */
>       struct iommu_fwspec *iommu_fwspec;
>       struct dev_archdata archdata;
> diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
> index 9409350..2f6aae1 100644
> --- a/xen/include/xen/acpi.h
> +++ b/xen/include/xen/acpi.h
> @@ -32,6 +32,7 @@
>   
>   #include <acpi/acpi.h>
>   #include <asm/acpi.h>
> +#include <xen/fwnode.h>
>   
>   #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
>   	(ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
> @@ -49,6 +50,26 @@
>                   (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
>                   (entry)->header.length < sizeof(*(entry)))
>   
> +static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
> +{
> +	struct fwnode_handle *fwnode;
> +
> +	fwnode = xzalloc(struct fwnode_handle);
> +	if (!fwnode)
> +		return NULL;
> +
> +	fwnode->type = FWNODE_ACPI_STATIC;
> +
> +	return fwnode;
> +}
> +
> +static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
> +{
> +	if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
> +		return;
> +
> +	xfree(fwnode);
> +}
>   #ifdef CONFIG_ACPI
>   
>   enum acpi_interrupt_id {
> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
> index 43f2125..182b1a5 100644
> --- a/xen/include/xen/pci.h
> +++ b/xen/include/xen/pci.h
> @@ -92,8 +92,16 @@ struct pci_dev {
>   #define PT_FAULT_THRESHOLD 10
>       } fault;
>       u64 vf_rlen[6];
> +#ifdef CONFIG_ARM
> +    struct device dev;
> +#endif
>   };
>   
> +#ifdef CONFIG_ARM
> +#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
> +#define pci_domain_nr(dev) dev->seg
> +#endif
> +
>   #define for_each_pdev(domain, pdev) \
>       list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
>   


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 2/7] arm64: Add definitions for fwnode_handle
  2017-09-21  0:37 ` [RFC v2 2/7] arm64: Add definitions for fwnode_handle Sameer Goel
@ 2017-10-12 12:45   ` Julien Grall
  2017-10-19 14:53     ` Goel, Sameer
  0 siblings, 1 reply; 34+ messages in thread
From: Julien Grall @ 2017-10-12 12:45 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi,

On 21/09/17 01:37, Sameer Goel wrote:
> This will be used as a device property to match the DMA capable devices
> with the associated SMMU. The header file is a port from linux. The code
> was changed to remove the types that were not needed for Xen.

I think you probably want a bit more context in the commit message about 
implement fwnode.h in common code.

Within this series, fwnode seems to only be used by Arm. So what would 
be the advantage to get that in xen/? Is it going to be used by x86 or 
taken advantage in common code?

> 
> Linux ChangeId:ce793486e23e: driver core / ACPI: Represent ACPI
> companions using fwnode_handle
> 
> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
> ---
>   xen/include/asm-arm/device.h |  2 ++
>   xen/include/xen/fwnode.h     | 33 +++++++++++++++++++++++++++++++++
>   2 files changed, 35 insertions(+)
>   create mode 100644 xen/include/xen/fwnode.h
> 
> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
> index 6734ae8..78c38fe 100644
> --- a/xen/include/asm-arm/device.h
> +++ b/xen/include/asm-arm/device.h
> @@ -2,6 +2,7 @@
>   #define __ASM_ARM_DEVICE_H
>   
>   #include <xen/init.h>
> +#include <xen/fwnode.h>
>   
>   enum device_type
>   {
> @@ -19,6 +20,7 @@ struct device
>   #ifdef CONFIG_HAS_DEVICE_TREE
>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */

I was expecting a todo in the code after the discussion about leave 
of_node here.

>   #endif
> +    struct fwnode_handle *fwnode; /*fw device node identifier */

Space missing before "fw".

>       struct dev_archdata archdata;
>   };
>   
> diff --git a/xen/include/xen/fwnode.h b/xen/include/xen/fwnode.h
> new file mode 100644
> index 0000000..0fed958
> --- /dev/null
> +++ b/xen/include/xen/fwnode.h
> @@ -0,0 +1,33 @@
> +/*
> + * fwnode.h - Firmware device node object handle type definition.
> + *
> + * Copyright (C) 2015, Intel Corporation
> + * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Ported from Linux include/linux/fwnode.h
> + *  => commit ce793486e23e0162a732c605189c8028e0910e86
> + *
> + * No functional Xen modifications.
> + */
> +
> +#ifndef __XEN_FWNODE_H_
> +#define __XEN_FWNODE_H_
> +
> +enum fwnode_type {
> +	FWNODE_INVALID = 0,
> +	FWNODE_OF,
> +	FWNODE_ACPI,
> +	FWNODE_ACPI_STATIC,
> +	FWNODE_IRQCHIP
> +};
> +

Looking at Linux code, the fwnode_type already disappeared from Linux 
(see commit db3e50f3234b "device property: Get rid of struct 
fwnode_handle type field").

I understand the goal on using fwnode is to help porting drivers from 
Linux. So how much this has changed now?

Cheers,

> +struct fwnode_handle {
> +	enum fwnode_type type;
> +	struct fwnode_handle *secondary;
> +};
> +
> +#endif
> 

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec
  2017-09-21  0:37 ` [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec Sameer Goel
@ 2017-10-12 13:05   ` Julien Grall
  2017-10-12 13:36     ` Julien Grall
  2017-10-19 14:58     ` Goel, Sameer
  0 siblings, 2 replies; 34+ messages in thread
From: Julien Grall @ 2017-10-12 13:05 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi,

On 21/09/17 01:37, Sameer Goel wrote:
> Introduce a common structure to hold the fw (ACPI or DT) defined
> configuration for SMMU hw. The current use case is for arm SMMUs. So,
> making this architecture specific.
> 
> Based on Linux kernel commit 57f98d2f61e1: iommu: Introduce iommu_fwspec
> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
> ---
>   xen/drivers/passthrough/arm/iommu.c | 66 +++++++++++++++++++++++++++++++++++++
>   xen/include/asm-arm/device.h        |  1 +
>   xen/include/xen/iommu.h             | 29 ++++++++++++++++
>   3 files changed, 96 insertions(+)
> 
> diff --git a/xen/drivers/passthrough/arm/iommu.c b/xen/drivers/passthrough/arm/iommu.c
> index 95b1abb..41c6497 100644
> --- a/xen/drivers/passthrough/arm/iommu.c
> +++ b/xen/drivers/passthrough/arm/iommu.c
> @@ -73,3 +73,69 @@ int arch_iommu_populate_page_table(struct domain *d)
>       /* The IOMMU shares the p2m with the CPU */
>       return -ENOSYS;
>   }
> +
> +const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
> +{
> +    return iommu_get_ops();

Can you please add a comment explain why you always return iommu_get_ops()?

Would it be possible that the device is not behind an IOMMU?

> +}
> +
> +int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
> +        const struct iommu_ops *ops)
> +{
> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
> +
> +    if ( fwspec )
> +        return ops == fwspec->ops ? 0 : -EINVAL;
> +
> +    fwspec = _xzalloc(sizeof(struct iommu_fwspec), sizeof(void *));

On the previous version this was xzalloc(struct iommu_fwspec), why?

I also don't understand the align on sizeof(void *).

> +    if ( !fwspec )
> +        return -ENOMEM;
> +
> +    fwspec->iommu_fwnode = iommu_fwnode;
> +    fwspec->ops = ops;
> +    dev->iommu_fwspec = fwspec;
> +
> +    return 0;
> +}
> +
> +void iommu_fwspec_free(struct device *dev)
> +{
> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
> +
> +    if ( fwspec )
> +    {

Linux is dropping the reference on the iommu_fwnode. Are we never 
expecting to take reference on the it in Xen?

> +        xfree(fwspec);
> +        dev->iommu_fwspec = NULL;
> +    }
> +}
> +
> +int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
> +{
> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
> +    struct iommu_fwspec *fwspec_n = NULL;
> +    size_t size, size_n;
> +    int i;
> +
> +    if ( !fwspec )
> +        return -EINVAL;
> +
> +    size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids]);
> +    size_n = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
> +    if ( size_n > size )
> +    { > +        fwspec_n = _xzalloc(size_n, sizeof(void *));

Same question about _xzalloc() here.

> +        if ( !fwspec_n )
> +            return -ENOMEM;
> +
> +        memcpy(fwspec_n, fwspec, size);
> +        xfree(fwspec);
> +    }
> +
> +    for (i = 0; i < num_ids; i++)
> +        fwspec_n->ids[fwspec_n->num_ids + i] = ids[i];
> +
> +    fwspec_n->num_ids += num_ids;
> +    dev->iommu_fwspec = fwspec_n;
> +
> +    return 0;
> +}
> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
> index 78c38fe..5027c87 100644
> --- a/xen/include/asm-arm/device.h
> +++ b/xen/include/asm-arm/device.h
> @@ -21,6 +21,7 @@ struct device
>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>   #endif
>       struct fwnode_handle *fwnode; /*fw device node identifier */
> +    struct iommu_fwspec *iommu_fwspec;
>       struct dev_archdata archdata;
>   };
>   
> diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
> index 0dac4f3..34e8d68 100644
> --- a/xen/include/xen/iommu.h
> +++ b/xen/include/xen/iommu.h
> @@ -208,4 +208,33 @@ DECLARE_PER_CPU(bool_t, iommu_dont_flush_iotlb);
>   extern struct spinlock iommu_pt_cleanup_lock;
>   extern struct page_list_head iommu_pt_cleanup_list;
>   
> +/**
> + * Following block was ported from Linux to help with the implementation of
> + * arm64 iommu devices. Hence the architecture specific compile
> + */
> +
> +#if defined(CONFIG_ARM)

If it is Arm only, then it should be moved in asm-arm/iommu.h.

> +/**
> + * struct iommu_fwspec - per-device IOMMU instance data
> + * @ops: ops for this device's IOMMU
> + * @iommu_fwnode: firmware handle for this device's IOMMU
> + * @iommu_priv: IOMMU driver private data for this device
> + * @num_ids: number of associated device IDs
> + * @ids: IDs which this device may present to the IOMMU
> + */
> +struct iommu_fwspec {
> +    const struct iommu_ops *ops;
> +    struct fwnode_handle   *iommu_fwnode;
> +    void                   *iommu_priv;
> +    unsigned int           num_ids;
> +    u32                    ids[1];
> +};
> +
> +int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
> +		      const struct iommu_ops *ops);
> +void iommu_fwspec_free(struct device *dev);
> +int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
> +const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode);
> +
> +#endif
>   #endif /* _IOMMU_H_ */
> 

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec
  2017-10-12 13:05   ` Julien Grall
@ 2017-10-12 13:36     ` Julien Grall
  2017-10-19 14:58     ` Goel, Sameer
  1 sibling, 0 replies; 34+ messages in thread
From: Julien Grall @ 2017-10-12 13:36 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi,

On 12/10/17 14:05, Julien Grall wrote:
> Hi,
> 
> On 21/09/17 01:37, Sameer Goel wrote:
>> Introduce a common structure to hold the fw (ACPI or DT) defined
>> configuration for SMMU hw. The current use case is for arm SMMUs. So,
>> making this architecture specific.
>>
>> Based on Linux kernel commit 57f98d2f61e1: iommu: Introduce iommu_fwspec
>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>> ---
>>   xen/drivers/passthrough/arm/iommu.c | 66 
>> +++++++++++++++++++++++++++++++++++++
>>   xen/include/asm-arm/device.h        |  1 +
>>   xen/include/xen/iommu.h             | 29 ++++++++++++++++
>>   3 files changed, 96 insertions(+)
>>
>> diff --git a/xen/drivers/passthrough/arm/iommu.c 
>> b/xen/drivers/passthrough/arm/iommu.c
>> index 95b1abb..41c6497 100644
>> --- a/xen/drivers/passthrough/arm/iommu.c
>> +++ b/xen/drivers/passthrough/arm/iommu.c
>> @@ -73,3 +73,69 @@ int arch_iommu_populate_page_table(struct domain *d)
>>       /* The IOMMU shares the p2m with the CPU */
>>       return -ENOSYS;
>>   }
>> +
>> +const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle 
>> *fwnode)
>> +{
>> +    return iommu_get_ops();
> 
> Can you please add a comment explain why you always return iommu_get_ops()?
> 
> Would it be possible that the device is not behind an IOMMU?
> 
>> +}
>> +
>> +int iommu_fwspec_init(struct device *dev, struct fwnode_handle 
>> *iommu_fwnode,
>> +        const struct iommu_ops *ops)
>> +{
>> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>> +
>> +    if ( fwspec )
>> +        return ops == fwspec->ops ? 0 : -EINVAL;
>> +
>> +    fwspec = _xzalloc(sizeof(struct iommu_fwspec), sizeof(void *));
> 
> On the previous version this was xzalloc(struct iommu_fwspec), why?
> 
> I also don't understand the align on sizeof(void *).
> 
>> +    if ( !fwspec )
>> +        return -ENOMEM;
>> +
>> +    fwspec->iommu_fwnode = iommu_fwnode;
>> +    fwspec->ops = ops;
>> +    dev->iommu_fwspec = fwspec;
>> +
>> +    return 0;
>> +}
>> +
>> +void iommu_fwspec_free(struct device *dev)
>> +{
>> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>> +
>> +    if ( fwspec )
>> +    {
> 
> Linux is dropping the reference on the iommu_fwnode. Are we never 
> expecting to take reference on the it in Xen?
> 
>> +        xfree(fwspec);
>> +        dev->iommu_fwspec = NULL;
>> +    }
>> +}
>> +
>> +int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
>> +{
>> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>> +    struct iommu_fwspec *fwspec_n = NULL;
>> +    size_t size, size_n;
>> +    int i;
>> +
>> +    if ( !fwspec )
>> +        return -EINVAL;
>> +
>> +    size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids]);
>> +    size_n = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + 
>> num_ids]);
>> +    if ( size_n > size )
>> +    { > +        fwspec_n = _xzalloc(size_n, sizeof(void *));
> 
> Same question about _xzalloc() here.

Also, please see the comment I just made on "[RFC 3/6] Introduce _xrealloc".

I would prefer to explore the possibility of a generic helper rather 
than open-coding it. I think we have enough information in hand to get 
the size of the old region.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-09-21  0:37 ` [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table Sameer Goel
  2017-10-10 12:36   ` Manish Jaggi
@ 2017-10-12 14:06   ` Julien Grall
  2017-10-19 15:21     ` Goel, Sameer
  2017-10-12 14:23   ` Julien Grall
  2017-11-08 14:41   ` Manish Jaggi
  3 siblings, 1 reply; 34+ messages in thread
From: Julien Grall @ 2017-10-12 14:06 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 21/09/17 01:37, Sameer Goel wrote:
> Add support for parsing IORT table to initialize SMMU devices.
> * The code for creating an SMMU device has been modified, so that the SMMU
> device can be initialized.
> * The NAMED NODE code has been commented out as this will need DOM0 kernel
> support.
> * ITS code has been included but it has not been tested.
> 
> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
> ---
>   xen/arch/arm/setup.c               |   3 +
>   xen/drivers/acpi/Makefile          |   1 +
>   xen/drivers/acpi/arm/Makefile      |   1 +
>   xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
>   xen/drivers/passthrough/arm/smmu.c |   1 +
>   xen/include/acpi/acpi_iort.h       |  17 ++--
>   xen/include/asm-arm/device.h       |   2 +
>   xen/include/xen/acpi.h             |  21 +++++
>   xen/include/xen/pci.h              |   8 ++
>   9 files changed, 146 insertions(+), 81 deletions(-)
>   create mode 100644 xen/drivers/acpi/arm/Makefile
> 
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index 92f173b..4ba09b2 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -49,6 +49,7 @@
>   #include <asm/setup.h>
>   #include <xsm/xsm.h>
>   #include <asm/acpi.h>
> +#include <acpi/acpi_iort.h>
>   
>   struct bootinfo __initdata bootinfo;
>   
> @@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
>   
>       tasklet_subsys_init();
>   
> +    /* Parse the ACPI iort data */
> +    acpi_iort_init();
>   
>       xsm_dt_init();
>   
> diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
> index 444b11d..e7ffd82 100644
> --- a/xen/drivers/acpi/Makefile
> +++ b/xen/drivers/acpi/Makefile
> @@ -1,5 +1,6 @@
>   subdir-y += tables
>   subdir-y += utilities
> +subdir-$(CONFIG_ARM) += arm
>   subdir-$(CONFIG_X86) += apei
>   
>   obj-bin-y += tables.init.o
> diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
> new file mode 100644
> index 0000000..7c039bb
> --- /dev/null
> +++ b/xen/drivers/acpi/arm/Makefile
> @@ -0,0 +1 @@
> +obj-y += iort.o
> diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
> index 2e368a6..7f54062 100644
> --- a/xen/drivers/acpi/arm/iort.c
> +++ b/xen/drivers/acpi/arm/iort.c
> @@ -14,17 +14,47 @@
>    * This file implements early detection/parsing of I/O mapping
>    * reported to OS through firmware via I/O Remapping Table (IORT)
>    * IORT document number: ARM DEN 0049A
> + *
> + * Based on Linux drivers/acpi/arm64/iort.c
> + * => commit ca78d3173cff3503bcd15723b049757f75762d15
> + *
> + * Xen modification:
> + * Sameer Goel <sgoel@codeaurora.org>
> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
> + *
>    */
>   
> -#define pr_fmt(fmt)	"ACPI: IORT: " fmt
> -
> -#include <linux/acpi_iort.h>
> -#include <linux/iommu.h>
> -#include <linux/kernel.h>
> -#include <linux/list.h>
> -#include <linux/pci.h>
> -#include <linux/platform_device.h>
> -#include <linux/slab.h>
> +#include <xen/acpi.h>
> +#include <acpi/acpi_iort.h>

Why do you need to include there? Can't this be done after all the <xen/> ?

> +#include <xen/fwnode.h>
> +#include <xen/iommu.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/pci.h>
> +
> +#include <asm/device.h>
> +
> +/* Xen: Define compatibility functions */
> +#define FW_BUG		"[Firmware Bug]: "
> +#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
> +#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
> +
> +/* Alias to Xen allocation helpers */
> +#define kfree xfree
> +#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
> +#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))

Likely you would need the same macros in the SMMUv3 driver. Could we 
think of a common headers implementing the Linux compat layer?

> +
> +/* Redefine WARN macros */
> +#undef WARN
> +#undef WARN_ON
> +#define WARN(condition, format...) ({					\
> +	int __ret_warn_on = !!(condition);				\
> +	if (unlikely(__ret_warn_on))					\
> +		printk(format);						\
> +	unlikely(__ret_warn_on);					\
> +})

Again, you should at least try to modify the common code version before 
deciding to redefine it here.

> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
> +#define WARN_ON(cond)                      (!!cond)
>   
>   #define IORT_TYPE_MASK(type)	(1 << (type))
>   #define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   	acpi_status status;
>   
>   	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
> +		status = AE_NOT_IMPLEMENTED;
> +/*
> + * We need the namespace object name from dsdt to match the iort node, this

Please add a "Xen: TODO:" in front.

> + * will need additions to the kernel xen bus notifiers.
> + * So, disabling the named node code till a proposal is approved.
> + */
> +#if 0
>   		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>   		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>   		struct acpi_iort_named_component *ncomp;
> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   		status = !strcmp(ncomp->device_name, buf.pointer) ?
>   							AE_OK : AE_NOT_FOUND;
>   		acpi_os_free(buf.pointer);
> +#endif
>   	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>   		struct acpi_iort_root_complex *pci_rc;
> -		struct pci_bus *bus;
> +		struct pci_dev *pci_dev;

Do you really need to modify the code? Wouldn't it be possible to do

#define pci_bus pci_dev

With an explanation why you do that on top.

>   
> -		bus = to_pci_bus(dev);
> +		pci_dev = to_pci_dev(dev);

Same here?

>   		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>   
>   		/*
> @@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   		 * with root complexes. Each segment number can represent only
>   		 * one root complex.
>   		 */
> -		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
> +		status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
>   							AE_OK : AE_NOT_FOUND;
>   	} else {
>   		status = AE_NOT_FOUND;
>   	}
> -out:
>   	return status;
>   }
>   
> @@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
>   	return 0;
>   }
>   
> +/*
> + * Named components are not supported yet so we do not need the
> + * iort_node_get_id function

Missing full stop + TODO.

> + */
> +#if 0
>   static
>   struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>   					u32 *id_out, u8 type_mask,
> @@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>   
>   	return NULL;
>   }
> +#endif
>   
>   static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
>   						u32 rid_in, u32 *rid_out,
> @@ -410,6 +453,10 @@ fail_map:
>   	return NULL;
>   }
>   
> +/* Xen: Comment out the NamedComponent and ITS mapping code till the support

+ TODO here please.

> + * is available.
> + */
> +#if 0
>   static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
>   {
>   	struct pci_bus *pbus;
> @@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
>   	return 0;
>   }
>   
> -/**
> +/*

Why this change?

>    * iort_get_device_domain() - Find MSI domain related to a device
>    * @dev: The device.
>    * @req_id: Requester ID for the device.
> @@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>   	*rid = alias;
>   	return 0;
>   }
> -
> +#endif

Please avoid dropping newline.

>   static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>   			       struct fwnode_handle *fwnode,
>   			       const struct iommu_ops *ops)
> @@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>   	return ret ? NULL : ops;
>   }
>   
> +#if 0 /* Xen: We do not need this function for Xen */
>   /**
>    * iort_set_dma_mask - Set-up dma mask for a device.
>    *
> @@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
>   	if (!dev->dma_mask)
>   		dev->dma_mask = &dev->coherent_dma_mask;
>   }
> -
> +#endif

Same here.

>   /**
>    * iort_iommu_configure - Set-up IOMMU configuration for a device.
>    *
> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   	u32 streamid = 0;
>   
>   	if (dev_is_pci(dev)) {
> -		struct pci_bus *bus = to_pci_dev(dev)->bus;
> +		struct pci_dev *pci_device = to_pci_dev(dev);

See above.

>   		u32 rid;
>   
> -		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
> -				       &rid);
> +		rid = PCI_BDF2(pci_device->bus, pci_device->devfn);

I believe we had a discussion on v1 explaining why this is wrong. So I 
don't understand why

>   
>   		node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
> -				      iort_match_node_callback, &bus->dev);
> +				      iort_match_node_callback, dev);
>   		if (!node)
>   			return NULL;
>   
> @@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   		ops = iort_iommu_xlate(dev, parent, streamid);
>   
>   	} else {
> +		return NULL;
> +/*
> + * We need the namespace object name from dsdt to match the iort node, this

Xen:

> + * will need additions to the kernel xen bus notifiers.
> + * So, disabling the named node code till a proposal is approved.
> + */
> +#if 0
>   		int i = 0;
>   
>   		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
> @@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   			parent = iort_node_get_id(node, &streamid,
>   						  IORT_IOMMU_TYPE, i++);
>   		}
> +#endif
>   	}
>   
>   	return ops;
>   }
>   
> +/*
> + * Xen: Not using the parsing ops for now. Need to check and see if it will
> + * be useful to use these in some form, or let the driver parse IORT node.
> + */
> +#if 0
>   static void __init acpi_iort_register_irq(int hwirq, const char *name,
>   					  int trigger,
>   					  struct resource *res)
> @@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>   		return NULL;
>   	}
>   }
> -
> +#endif

Please avoid dropping newline.

>   /**
>    * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>    * @node: Pointer to SMMU ACPI IORT node
> @@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>   static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)

Looking at the changes in this function. You basically rewrite 
everything. I would prefer if you comment the current one and implement 
from scratch the Xen version.

>   {
>   	struct fwnode_handle *fwnode;
> -	struct platform_device *pdev;
> -	struct resource *r;
> -	enum dev_dma_attr attr;
> -	int ret, count;
> -	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
> -
> -	if (!ops)
> -		return -ENODEV;
> -
> -	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
> -	if (!pdev)
> -		return -ENOMEM;
> -
> -	count = ops->iommu_count_resources(node);
> -
> -	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
> -	if (!r) {
> -		ret = -ENOMEM;
> -		goto dev_put;
> -	}
> -
> -	ops->iommu_init_resources(r, node);
> +	struct device *dev;
> +	int ret;
>   
> -	ret = platform_device_add_resources(pdev, r, count);
>   	/*
> -	 * Resources are duplicated in platform_device_add_resources,
> -	 * free their allocated memory
> +	 * Not enabling the parsing ops for now. The corresponding driver
> +	 * can parse this information as needed, so deleting relevant code as
> +	 * compared to base revision.
>   	 */
> -	kfree(r);
>   
> -	if (ret)
> -		goto dev_put;
> +	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
> +	if (!dev)
> +		return -ENOMEM;
>   
>   	/*
>   	 * Add a copy of IORT node pointer to platform_data to
>   	 * be used to retrieve IORT data information.
>   	 */
> -	ret = platform_device_add_data(pdev, &node, sizeof(node));
> -	if (ret)
> -		goto dev_put;
> -
> -	/*
> -	 * We expect the dma masks to be equivalent for
> -	 * all SMMUs set-ups
> -	 */
> -	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
> +	dev->type = DEV_ACPI;
> +	dev->acpi_node = node;
>   
>   	fwnode = iort_get_fwnode(node);
>   
>   	if (!fwnode) {
>   		ret = -ENODEV;
> -		goto dev_put;
> +		goto error;
>   	}
>   
> -	pdev->dev.fwnode = fwnode;
> -
> -	attr = ops->iommu_is_coherent(node) ?
> -			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
> -
> -	/* Configure DMA for the page table walker */
> -	acpi_dma_configure(&pdev->dev, attr);
> +	dev->fwnode = fwnode;
>   
> -	ret = platform_device_add(pdev);
> -	if (ret)
> -		goto dma_deconfigure;
> +	/* Call the acpi init functions for IOMMU devices */
> +	ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
>   
>   	return 0;
>   
> -dma_deconfigure:
> -	acpi_dma_deconfigure(&pdev->dev);
> -dev_put:
> -	platform_device_put(pdev);
> +error:
> +	kfree(dev);
>   
>   	return ret;
>   }
> @@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
>   
>   	iort_init_platform_devices();
>   
> -	acpi_probe_device_table(iort);
> +	/* Xen; Do not need a device table probe */
> +	/* acpi_probe_device_table(iort);*/

Please use either

#if 0

#endif

or introduce a dummy acpi_probe_device_table(...) at the start.

>   }
> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
> index 362d578..ad956d5 100644
> --- a/xen/drivers/passthrough/arm/smmu.c
> +++ b/xen/drivers/passthrough/arm/smmu.c
> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>    * Xen: PCI functions
>    * TODO: It should be implemented when PCI will be supported
>    */
> +#undef to_pci_dev

Why this change?

>   #define to_pci_dev(dev)	(NULL)
>   static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
>   					 int (*fn) (struct pci_dev *pdev,
> diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
> index 77e0809..d4315a4 100644
> --- a/xen/include/acpi/acpi_iort.h
> +++ b/xen/include/acpi/acpi_iort.h

You probably want to re-sync this headers as it changed quite a bit and 
would avoid some specific #if 0 for Xen.

> @@ -19,27 +19,32 @@
>   #ifndef __ACPI_IORT_H__
>   #define __ACPI_IORT_H__
>   
> -#include <linux/acpi.h>
> -#include <linux/fwnode.h>
> -#include <linux/irqdomain.h>
> +#include <xen/acpi.h>
> +#include <asm/device.h>
>   
> +/* Xen: Not using IORT IRQ bindings */
> +#if 0
>   #define IORT_IRQ_MASK(irq)		(irq & 0xffffffffULL)
>   #define IORT_IRQ_TRIGGER_MASK(irq)	((irq >> 32) & 0xffffffffULL)
>   
>   int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
>   void iort_deregister_domain_token(int trans_id);
>   struct fwnode_handle *iort_find_domain_token(int trans_id);
> -#ifdef CONFIG_ACPI_IORT
> +#endif
> +#ifdef CONFIG_ARM_64

As said in the first version, I see no point of replacing 
CONFIG_ACPI_IORT with CONFIG_ARM_64. You should instead take advantage 
of the Kconfig to add a new config ACPI_IORT and select on Arm64 with ACPI.

>   void acpi_iort_init(void);
>   bool iort_node_match(u8 type);
> +#if 0
>   u32 iort_msi_map_rid(struct device *dev, u32 req_id);
>   struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
>   /* IOMMU interface */
>   void iort_set_dma_mask(struct device *dev);
> +#endif
>   const struct iommu_ops *iort_iommu_configure(struct device *dev);
>   #else
>   static inline void acpi_iort_init(void) { }
>   static inline bool iort_node_match(u8 type) { return false; }
> +#if 0
>   static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>   { return req_id; }
>   static inline struct irq_domain *iort_get_device_domain(struct device *dev,
> @@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>   { return NULL; }
>   /* IOMMU interface */
>   static inline void iort_set_dma_mask(struct device *dev) { }
> +#endif
>   static inline
>   const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   { return NULL; }
>   #endif
>   
> -#define IORT_ACPI_DECLARE(name, table_id, fn)		\
> -	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
> -
>   #endif /* __ACPI_IORT_H__ */
> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
> index 5027c87..4eef9ce 100644
> --- a/xen/include/asm-arm/device.h
> +++ b/xen/include/asm-arm/device.h
> @@ -7,6 +7,7 @@
>   enum device_type
>   {
>       DEV_DT,
> +    DEV_ACPI,
>   };
>   
>   struct dev_archdata {
> @@ -20,6 +21,7 @@ struct device
>   #ifdef CONFIG_HAS_DEVICE_TREE
>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>   #endif
> +    void *acpi_node; /*Current use case is acpi_iort_node */

Can you explain why you need that? After the creation of fwnode, I was 
expecting of_node to disappear. So I don't really fancy see acpi_node 
here more it does not exist in Linux.

>       struct fwnode_handle *fwnode; /*fw device node identifier */
>       struct iommu_fwspec *iommu_fwspec;
>       struct dev_archdata archdata;
> diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
> index 9409350..2f6aae1 100644
> --- a/xen/include/xen/acpi.h
> +++ b/xen/include/xen/acpi.h
> @@ -32,6 +32,7 @@
>   
>   #include <acpi/acpi.h>
>   #include <asm/acpi.h>
> +#include <xen/fwnode.h>

I think this and ...

>   
>   #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
>   	(ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
> @@ -49,6 +50,26 @@
>                   (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
>                   (entry)->header.length < sizeof(*(entry)))
>   
> +static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
> +{
> +	struct fwnode_handle *fwnode;
> +
> +	fwnode = xzalloc(struct fwnode_handle);
> +	if (!fwnode)
> +		return NULL;
> +
> +	fwnode->type = FWNODE_ACPI_STATIC;
> +
> +	return fwnode;
> +}
> +
> +static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
> +{
> +	if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
> +		return;
> +
> +	xfree(fwnode);
> +}

... those 2 helpers should go in asm/acpi.h.

>   #ifdef CONFIG_ACPI
>   
>   enum acpi_interrupt_id {
> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
> index 43f2125..182b1a5 100644
> --- a/xen/include/xen/pci.h
> +++ b/xen/include/xen/pci.h
> @@ -92,8 +92,16 @@ struct pci_dev {
>   #define PT_FAULT_THRESHOLD 10
>       } fault;
>       u64 vf_rlen[6];
> +#ifdef CONFIG_ARM
> +    struct device dev;
> +#endif

There are a part of PCI that is already per-arch. See arch_pci_dev in 
asm-arm/pci.h.

Please define the field dev in it rather than here.

>   };
>   
> +#ifdef CONFIG_ARM
> +#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
> +#define pci_domain_nr(dev) dev->seg
> +#endif

Similarly, this should be moved in asm-arm/pci.h.

> +
>   #define for_each_pdev(domain, pdev) \
>       list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
>   
> 

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-09-21  0:37 ` [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table Sameer Goel
  2017-10-10 12:36   ` Manish Jaggi
  2017-10-12 14:06   ` Julien Grall
@ 2017-10-12 14:23   ` Julien Grall
  2017-11-08 14:41   ` Manish Jaggi
  3 siblings, 0 replies; 34+ messages in thread
From: Julien Grall @ 2017-10-12 14:23 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 21/09/17 01:37, Sameer Goel wrote:
> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   	u32 streamid = 0;
>   
>   	if (dev_is_pci(dev)) {
> -		struct pci_bus *bus = to_pci_dev(dev)->bus;
> +		struct pci_dev *pci_device = to_pci_dev(dev);
>   		u32 rid;
>   
> -		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
> -				       &rid);
> +		rid = PCI_BDF2(pci_device->bus, pci_device->devfn);

I forgot to answer on this bit. On the previous it was mentioned this 
was wrong, but still there.

Whilst I can understand that implementing pci_for_each_dma_alias could 
require some work in Xen, I don't want to see rid = PCI_BDF2(...) 
spreading the code. So what's the plan?

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-09-21  0:37 ` [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver Sameer Goel
  2017-09-26  0:03   ` Goel, Sameer
@ 2017-10-12 16:36   ` Julien Grall
  2017-11-19  7:45     ` Goel, Sameer
  1 sibling, 1 reply; 34+ messages in thread
From: Julien Grall @ 2017-10-12 16:36 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

Given this is all Arm specific. I am not sure why people like Andrew, 
Jan have been added.

Please use scripts/get_maintainers to find the list of maintainers per 
patches and avoid to CC all of them on each patches.

On 21/09/17 01:37, 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 */
> 
> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
> ---
>   xen/drivers/passthrough/arm/Makefile  |   1 +
>   xen/drivers/passthrough/arm/smmu-v3.c | 853 +++++++++++++++++++++++++++++-----

This is based on an old SMMUv3 version and I have been told there are 
some changes may benefits Xen (such as increasing the timeout for sync) 
and some optimisations also exist on the ML and will be queued soon.

So maybe you want to re-sync at least to master.

>   2 files changed, 738 insertions(+), 116 deletions(-)
> 
> diff --git a/xen/drivers/passthrough/arm/Makefile b/xen/drivers/passthrough/arm/Makefile
> index f4cd26e..57a6da6 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-y += smmu-v3.o

Do we want SMMUv3 to be built on Arm32? Maybe we should introduce a new 
Kconfig to let the user select.

> diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
> index 380969a..8f3b43d 100644
> --- a/xen/drivers/passthrough/arm/smmu-v3.c
> +++ b/xen/drivers/passthrough/arm/smmu-v3.c
> @@ -18,28 +18,266 @@
>    * Author: Will Deacon <will.deacon@arm.com>
>    *
>    * This driver is powered by bad coffee and bombay mix.
> + *
> + *
> + * Based on Linux drivers/iommu/arm-smmu-v3.c
> + * => commit bdf95923086fb359ccb44c815724c3ace1611c90
> + *
> + * Xen modifications:
> + * Sameer Goel <sgoel@codeaurora.org>
> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
> + *
>    */
>   
> -#include <linux/acpi.h>
> -#include <linux/acpi_iort.h>
> -#include <linux/delay.h>
> -#include <linux/dma-iommu.h>
> -#include <linux/err.h>
> -#include <linux/interrupt.h>
> -#include <linux/iommu.h>
> -#include <linux/iopoll.h>
> -#include <linux/module.h>
> -#include <linux/msi.h>
> -#include <linux/of.h>
> -#include <linux/of_address.h>
> -#include <linux/of_iommu.h>
> -#include <linux/of_platform.h>
> -#include <linux/pci.h>
> -#include <linux/platform_device.h>
> -
> -#include <linux/amba/bus.h>
> -
> -#include "io-pgtable.h"
> +#include <xen/config.h>

This is not necessary.

> +#include <xen/delay.h>
> +#include <xen/errno.h>
> +#include <xen/err.h>
> +#include <xen/irq.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/mm.h>
> +#include <xen/vmap.h>
> +#include <xen/rbtree.h>
> +#include <xen/sched.h>
> +#include <xen/sizes.h>
> +#include <asm/atomic.h>
> +#include <asm/device.h>
> +#include <asm/io.h>
> +#include <asm/platform.h>
> +#include <xen/acpi.h>

Please order the includes alphabetically with xen/* first then asm/*

> +
> +typedef paddr_t phys_addr_t;
> +typedef paddr_t dma_addr_t;
> +
> +/* Alias to Xen device tree helpers */
> +#define device_node dt_device_node
> +#define of_phandle_args dt_phandle_args
> +#define of_device_id dt_device_match
> +#define of_match_node dt_match_node
> +#define of_property_read_u32(np, pname, out) (!dt_property_read_u32(np, pname, out))
> +#define of_property_read_bool dt_property_read_bool
> +#define of_parse_phandle_with_args dt_parse_phandle_with_args
> +#define mutex spinlock_t
> +#define mutex_init spin_lock_init
> +#define mutex_lock spin_lock
> +#define mutex_unlock spin_unlock

mutex and spinlock are not the same. The former is sleeping whilst the 
later is not.

Can you please explain why this is fine and possibly add that in a comment?

> +
> +/* Xen: Helpers to get device MMIO and IRQs */
> +struct resource {
> +	u64 addr;
> +	u64 size;
> +	unsigned int type;
> +};

Likely we want a compat header for defining Linux helpers. This would 
avoid replicating it everywhere.

> +
> +#define resource_size(res) ((res)->size)
> +
> +#define platform_device device
> +
> +#define IORESOURCE_MEM 0
> +#define IORESOURCE_IRQ 1
> +
> +static struct resource *platform_get_resource(struct platform_device *pdev,
> +					      unsigned int type,
> +					      unsigned int num)
> +{
> +	/*
> +	 * The resource is only used between 2 calls of platform_get_resource.
> +	 * It's quite ugly but it's avoid to add too much code in the part
> +	 * imported from Linux
> +	 */
> +	static struct resource res;
> +	struct acpi_iort_node *iort_node;
> +	struct acpi_iort_smmu_v3 *node_smmu_data;
> +	int ret = 0;
> +
> +	res.type = type;
> +
> +	switch (type) {
> +	case IORESOURCE_MEM:
> +		if (pdev->type == DEV_ACPI) {
> +			ret = 1;
> +			iort_node = pdev->acpi_node;
> +			node_smmu_data =
> +				(struct acpi_iort_smmu_v3 *)iort_node->node_data;
> +
> +			if (node_smmu_data != NULL) {
> +				res.addr = node_smmu_data->base_address;
> +				res.size = SZ_128K;
> +				ret = 0;
> +			}
> +		} else {
> +			ret = dt_device_get_address(dev_to_dt(pdev), num,
> +						    &res.addr, &res.size);
> +		}
> +
> +		return ((ret) ? NULL : &res);
> +
> +	case IORESOURCE_IRQ:
> +		ret = platform_get_irq(dev_to_dt(pdev), num);

No IRQ for ACPI?

> +
> +		if (ret < 0)
> +			return NULL;
> +
> +		res.addr = ret;
> +		res.size = 1;
> +
> +		return &res;
> +
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +static int platform_get_irq_byname(struct platform_device *pdev, const char *name)
> +{
> +	const struct dt_property *dtprop;
> +	struct acpi_iort_node *iort_node;
> +	struct acpi_iort_smmu_v3 *node_smmu_data;
> +	int ret = 0;
> +
> +	if (pdev->type == DEV_ACPI) {
> +		iort_node = pdev->acpi_node;
> +		node_smmu_data = (struct acpi_iort_smmu_v3 *)iort_node->node_data;
> +
> +		if (node_smmu_data != NULL) {
> +			if (!strcmp(name, "eventq"))
> +				ret = node_smmu_data->event_gsiv;
> +			else if (!strcmp(name, "priq"))
> +				ret = node_smmu_data->pri_gsiv;
> +			else if (!strcmp(name, "cmdq-sync"))
> +				ret = node_smmu_data->sync_gsiv;
> +			else if (!strcmp(name, "gerror"))
> +				ret = node_smmu_data->gerr_gsiv;
> +			else
> +				ret = -EINVAL;
> +		}
> +	} else {
> +		dtprop = dt_find_property(dev_to_dt(pdev), "interrupt-names", NULL);
> +		if (!dtprop)
> +			return -EINVAL;
> +
> +		if (!dtprop->value)
> +			return -ENODATA;
> +	}
> +
> +	return ret;
> +}
> +
> +#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \
> +({ \
> +	s_time_t deadline = NOW() + MICROSECS(timeout_us); \
> +	for (;;) { \
> +		(val) = op(addr); \
> +		if (cond) \
> +			break; \
> +		if (NOW() > deadline) { \
> +			(val) = op(addr); \
> +			break; \
> +		} \
> +		cpu_relax(); \

I don't think calling cpu_relax() is correct here.

> +		udelay(sleep_us); \
> +	} \
> +	(cond) ? 0 : -ETIMEDOUT; \
> +})
> +
> +#define readl_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
> +	readx_poll_timeout(readl_relaxed, addr, val, cond, delay_us, timeout_us)
> +
> +/* Xen: Helpers for IRQ functions */
> +#define request_irq(irq, func, flags, name, dev) request_irq(irq, flags, func, name, dev)
> +#define free_irq release_irq
> +
> +enum irqreturn {
> +	IRQ_NONE	= (0 << 0),
> +	IRQ_HANDLED	= (1 << 0),
> +};
> +
> +typedef enum irqreturn irqreturn_t;
> +
> +/* Device logger functions */
> +#define dev_print(dev, lvl, fmt, ...)						\
> +	 printk(lvl "smmu: " fmt, ## __VA_ARGS__)
> +
> +#define dev_dbg(dev, fmt, ...) dev_print(dev, XENLOG_DEBUG, fmt, ## __VA_ARGS__)
> +#define dev_notice(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
> +#define dev_warn(dev, fmt, ...) dev_print(dev, XENLOG_WARNING, fmt, ## __VA_ARGS__)
> +#define dev_err(dev, fmt, ...) dev_print(dev, XENLOG_ERR, fmt, ## __VA_ARGS__)
> +#define dev_info(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
> +
> +#define dev_err_ratelimited(dev, fmt, ...)					\
> +	 dev_print(dev, 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)		_xmalloc(size, sizeof(void *))
> +#define kzalloc(size, flags)		_xzalloc(size, sizeof(void *))
> +#define devm_kzalloc(dev, size, flags)	_xzalloc(size, sizeof(void *))
> +#define kmalloc_array(size, n, flags)	_xmalloc_array(size, sizeof(void *), n)
> +
> +/* Compatibility defines */
> +#undef WARN_ON
> +#define WARN_ON(cond) (!!cond)

Why do you redefine WARN_ON?

> +#define WARN_ON_ONCE(cond) WARN_ON(cond)

Hmmm, can't we implement a common WARN_ON_ONCE?

> +
> +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: Dummy iommu_domain */
> +struct iommu_domain {
> +	/* Runtime SMMU configuration for this iommu_domain */
> +	struct arm_smmu_domain		*priv;
> +	unsigned int			type;
> +
> +	atomic_t ref;
> +	/* Used to link iommu_domain contexts for a same domain.
> +	 * There is at least one per-SMMU to used by the domain.
> +	 */
> +	struct list_head		list;
> +};

This is very similar to the SMMU version. Could we share some bits?

> +/* Xen: Domain type definitions. Not really needed for Xen, defining to port
> + * Linux code as-is
> + */
> +#define IOMMU_DOMAIN_UNMANAGED 0
> +#define IOMMU_DOMAIN_DMA 1
> +#define IOMMU_DOMAIN_IDENTITY 2
> +
> +/* Xen: Describes information required for a Xen domain */
> +struct arm_smmu_xen_domain {
> +	spinlock_t			lock;
> +	/* List of iommu domains associated to this domain */
> +	struct list_head		iommu_domains;
> +};

Ditoo.

> +
> +/*
> + * Xen: Information about each device stored in dev->archdata.iommu
> + *
> + * The dev->archdata.iommu stores the iommu_domain (runtime configuration of
> + * the SMMU).
> + */
> +struct arm_smmu_xen_device {
> +	struct iommu_domain *domain;
> +};

Ditto.

>   
>   /* MMIO registers */
>   #define ARM_SMMU_IDR0			0x0
> @@ -412,10 +650,12 @@
>   #define MSI_IOVA_BASE			0x8000000
>   #define MSI_IOVA_LENGTH			0x100000
>   
> +#if 0 /* Not applicable for Xen */

While the module_param_name() is not applicable in Xen, I don't see any 
reason to remove the variable.

>   static bool disable_bypass; >   module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO);
>   MODULE_PARM_DESC(disable_bypass,
>   	"Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
> +#endif
>   
>   enum pri_resp {
>   	PRI_RESP_DENY,
> @@ -423,6 +663,7 @@ enum pri_resp {
>   	PRI_RESP_SUCC,
>   };
>   
> +#if 0 /* Xen: No MSI support in this iteration */
>   enum arm_smmu_msi_index {
>   	EVTQ_MSI_INDEX,
>   	GERROR_MSI_INDEX,
> @@ -447,6 +688,7 @@ static phys_addr_t arm_smmu_msi_cfg[ARM_SMMU_MAX_MSIS][3] = {
>   		ARM_SMMU_PRIQ_IRQ_CFG2,
>   	},
>   };
> +#endif
>   
>   struct arm_smmu_cmdq_ent {
>   	/* Common fields */
> @@ -551,6 +793,8 @@ struct arm_smmu_s2_cfg {
>   	u16				vmid;
>   	u64				vttbr;
>   	u64				vtcr;
> +	/* Xen: Domain associated to this configuration */
> +	struct domain			*domain;
>   };
>   
>   struct arm_smmu_strtab_ent {
> @@ -623,9 +867,20 @@ struct arm_smmu_device {
>   	struct arm_smmu_strtab_cfg	strtab_cfg;
>   
>   	/* IOMMU core code handle */
> -	struct iommu_device		iommu;
> +	//struct iommu_device		iommu;

#if 0 but no // please.

> +
> +	/* Xen: Need to keep a list of SMMU devices */
> +	struct list_head                devices;
>   };
>   
> +/* Xen: Keep a list of devices associated with this driver */
> +static DEFINE_SPINLOCK(arm_smmu_devices_lock);
> +static LIST_HEAD(arm_smmu_devices);
> +/* Xen: Helper for finding a device using fwnode */
> +static
> +struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode);
> +
> +
>   /* SMMU private data for each master */
>   struct arm_smmu_master_data {
>   	struct arm_smmu_device		*smmu;
> @@ -642,7 +897,7 @@ enum arm_smmu_domain_stage {
>   
>   struct arm_smmu_domain {
>   	struct arm_smmu_device		*smmu;
> -	struct mutex			init_mutex; /* Protects smmu pointer */
> +	mutex			init_mutex; /* Protects smmu pointer */
>   
>   	struct io_pgtable_ops		*pgtbl_ops;
>   	spinlock_t			pgtbl_lock;
> @@ -737,15 +992,16 @@ static void queue_inc_prod(struct arm_smmu_queue *q)
>    */
>   static int queue_poll_cons(struct arm_smmu_queue *q, bool drain, bool wfe)
>   {
> -	ktime_t timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US);
> +	s_time_t deadline = NOW() + MICROSECS(ARM_SMMU_POLL_TIMEOUT_US);

Please introduce proper wrappers to avoid the modification of the code.

>   
>   	while (queue_sync_cons(q), (drain ? !queue_empty(q) : queue_full(q))) {
> -		if (ktime_compare(ktime_get(), timeout) > 0)
> +
> +		if (NOW() > deadline)

Ditto.

>   			return -ETIMEDOUT;
>   
> -		if (wfe) {
> +		if (wfe)

Please avoid to drop {

>   			wfe();
> -		} else {

Ditto.

> +		else {
>   			cpu_relax();

Hmmm I now see why you added cpu_relax() at the top. Well, on Xen 
cpu_relax is just a barrier. On Linux it is used to yield.

And that bit is worrying me. The Linux code will allow context switching 
to another tasks if the code is taking too much time.

Xen is not preemptible, so is it fine?

>   			udelay(1);
>   		}
> @@ -931,7 +1187,7 @@ static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
>   		dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n");
>   	spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
>   }
> -
> +#if 0

Please avoid dropping newline and explain why the #if 0.

>   /* Context descriptor manipulation functions */
>   static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
>   {
> @@ -974,7 +1230,7 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
>   
>   	cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair << CTXDESC_CD_3_MAIR_SHIFT);
>   }
> -
> +#endif

Ditto for the newline.

>   /* Stream table manipulation functions */
>   static void
>   arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
> @@ -1044,7 +1300,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
>   			ste_live = true;
>   			break;
>   		case STRTAB_STE_0_CFG_ABORT:
> -			if (disable_bypass)
> +			//No bypass override for Xen

Why no leaving the variable on top with a comment. This would avoid such 
change.

>   				break;
>   		default:
>   			BUG(); /* STE corruption */
> @@ -1056,7 +1312,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
>   
>   	/* Bypass/fault */
>   	if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) {
> -		if (!ste->assigned && disable_bypass)
> +		if (!ste->assigned)

Ditto.

>   			val |= STRTAB_STE_0_CFG_ABORT;
>   		else
>   			val |= STRTAB_STE_0_CFG_BYPASS;
> @@ -1135,16 +1391,20 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>   	void *strtab;
>   	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>   	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
> +	u32 alignment = 0;
>   
>   	if (desc->l2ptr)
>   		return 0;
>   
> -	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
> +	size = 1 << (STRTAB_SPLIT + LOG_2(STRTAB_STE_DWORDS) + 3);

I would prefer if you introduce ilog2.

>   	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>   
>   	desc->span = STRTAB_SPLIT + 1;
> -	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
> -					  GFP_KERNEL | __GFP_ZERO);
> +
> +	alignment = 1 << ((5 + (desc->span - 1)));

Do you mind explaining the 5? Also, does the shift will always be < 32?

> +	desc->l2ptr = _xzalloc(size, alignment);
> +	desc->l2ptr_dma = virt_to_maddr(desc->l2ptr);

_xzalloc can fail and virt_to_maddr will result to a panic.

> +
>   	if (!desc->l2ptr) {
>   		dev_err(smmu->dev,
>   			"failed to allocate l2 stream table for SID %u\n",
> @@ -1158,7 +1418,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>   }
>   
>   /* IRQ and event handlers */
> -static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
> +static void arm_smmu_evtq_thread(int irq, void *dev, struct cpu_user_regs *regs)

Could you please introduce a wrapper instead as it was done in smmu.c?

>   {
>   	int i;
>   	struct arm_smmu_device *smmu = dev;
> @@ -1186,7 +1446,6 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>   
>   	/* Sync our overflow flag, as we believe we're up to speed */
>   	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
> -	return IRQ_HANDLED;
>   }
>   
>   static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
> @@ -1203,7 +1462,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 0x%016lx\n",

Hmmm why?

>   		 sid, ssid, grpid, last ? "L" : "",
>   		 evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
>   		 evt[0] & PRIQ_0_PERM_READ ? "R" : "",
> @@ -1227,7 +1486,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
>   	}
>   }
>   
> -static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
> +static void arm_smmu_priq_thread(int irq, void *dev, struct cpu_user_regs *regs)

Ditto about the prototype.

>   {
>   	struct arm_smmu_device *smmu = dev;
>   	struct arm_smmu_queue *q = &smmu->priq.q;
> @@ -1243,18 +1502,16 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
>   
>   	/* Sync our overflow flag, as we believe we're up to speed */
>   	q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
> -	return IRQ_HANDLED;
>   }
>   
> -static irqreturn_t arm_smmu_cmdq_sync_handler(int irq, void *dev)
> +static void arm_smmu_cmdq_sync_handler(int irq, void *dev, struct cpu_user_regs *regs)

Ditto.

>   {
>   	/* We don't actually use CMD_SYNC interrupts for anything */
> -	return IRQ_HANDLED;
>   }
>   
>   static int arm_smmu_device_disable(struct arm_smmu_device *smmu);
>   
> -static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
> +static void arm_smmu_gerror_handler(int irq, void *dev, struct cpu_user_regs *regs)

Ditto.

>   {
>   	u32 gerror, gerrorn, active;
>   	struct arm_smmu_device *smmu = dev;
> @@ -1264,7 +1521,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>   
>   	active = gerror ^ gerrorn;
>   	if (!(active & GERROR_ERR_MASK))
> -		return IRQ_NONE; /* No errors pending */
> +		return; /* No errors pending */
>   
>   	dev_warn(smmu->dev,
>   		 "unexpected global error reported (0x%08x), this could be serious\n",
> @@ -1286,7 +1543,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>   
>   	if (active & GERROR_MSI_CMDQ_ABT_ERR) {
>   		dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
> -		arm_smmu_cmdq_sync_handler(irq, smmu->dev);
> +		arm_smmu_cmdq_sync_handler(irq, smmu->dev, NULL);
>   	}
>   
>   	if (active & GERROR_PRIQ_ABT_ERR)
> @@ -1299,7 +1556,6 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>   		arm_smmu_cmdq_skip_err(smmu);
>   
>   	writel(gerror, smmu->base + ARM_SMMU_GERRORN);
> -	return IRQ_HANDLED;
>   }
>   
>   /* IO_PGTABLE API */
> @@ -1311,11 +1567,13 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
>   	arm_smmu_cmdq_issue_cmd(smmu, &cmd);
>   }
>   
> +#if 0 /*Xen: Unused function */
>   static void arm_smmu_tlb_sync(void *cookie)
>   {
>   	struct arm_smmu_domain *smmu_domain = cookie;
>   	__arm_smmu_tlb_sync(smmu_domain->smmu);
>   }
> +#endif
>   
>   static void arm_smmu_tlb_inv_context(void *cookie)
>   {
> @@ -1336,6 +1594,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
>   	__arm_smmu_tlb_sync(smmu);
>   }
>   
> +#if 0 /*Xen: Unused functionality */
>   static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
>   					  size_t granule, bool leaf, void *cookie)
>   {
> @@ -1362,7 +1621,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
>   	} while (size -= granule);
>   }
>   
> -static const struct iommu_gather_ops arm_smmu_gather_ops = {
> +static struct iommu_gather_ops arm_smmu_gather_ops = {
>   	.tlb_flush_all	= arm_smmu_tlb_inv_context,
>   	.tlb_add_flush	= arm_smmu_tlb_inv_range_nosync,
>   	.tlb_sync	= arm_smmu_tlb_sync,
> @@ -1380,6 +1639,11 @@ static bool arm_smmu_capable(enum iommu_cap cap)
>   		return false;
>   	}
>   }
> +#endif
> +/* Xen: Stub out DMA domain related functions */
> +#define iommu_get_dma_cookie(dom) 0
> +#define iommu_put_dma_cookie(dom) 0

Please stub them at the top of the file.

> +
>   
>   static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>   {
> @@ -1410,6 +1674,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>   	return &smmu_domain->domain;
>   }
>   
> +#if 0

Please explain the #if 0

>   static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
>   {
>   	int idx, size = 1 << span;
> @@ -1427,36 +1692,20 @@ static void arm_smmu_bitmap_free(unsigned long *map, int idx)
>   {
>   	clear_bit(idx, map);
>   }
> +#endif
>   
>   static void arm_smmu_domain_free(struct iommu_domain *domain)
>   {
>   	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
> -	struct arm_smmu_device *smmu = smmu_domain->smmu;
> -
> -	iommu_put_dma_cookie(domain);
> -	free_io_pgtable_ops(smmu_domain->pgtbl_ops);
> -
> -	/* Free the CD and ASID, if we allocated them */
> -	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
> -		struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
> -
> -		if (cfg->cdptr) {
> -			dmam_free_coherent(smmu_domain->smmu->dev,
> -					   CTXDESC_CD_DWORDS << 3,
> -					   cfg->cdptr,
> -					   cfg->cdptr_dma);
> -
> -			arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
> -		}
> -	} else {
> -		struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
> -		if (cfg->vmid)
> -			arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
> -	}
> +	/*
> +	 * Xen: Remove the free functions that are not used and code related
> +	 * to S1 translation. We just need to free the domain here.
> +	 */

Please use #if 0 rather than removing the code + comment on top. But I 
am not sure why you drop the S2 free code. Shouldn't we allocate VMID 
from the SMMU?

>   
>   	kfree(smmu_domain);
>   }
>   
> +#if 0
>   static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
>   				       struct io_pgtable_cfg *pgtbl_cfg)
>   {
> @@ -1488,33 +1737,30 @@ out_free_asid:
>   	arm_smmu_bitmap_free(smmu->asid_map, asid);
>   	return ret;
>   }
> +#endif
>   
> -static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
> -				       struct io_pgtable_cfg *pgtbl_cfg)
> +static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain)
>   {
> -	int vmid;
> -	struct arm_smmu_device *smmu = smmu_domain->smmu;
>   	struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>   
> -	vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
> -	if (vmid < 0)
> -		return vmid;
> +	/* Xen: Set the values as needed */
>   
> -	cfg->vmid	= (u16)vmid;
> -	cfg->vttbr	= pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
> -	cfg->vtcr	= pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
> +	cfg->vmid	= cfg->domain->arch.p2m.vmid;

See my comment above.

> +	cfg->vttbr	= page_to_maddr(cfg->domain->arch.p2m.root);
> +	cfg->vtcr	= READ_SYSREG32(VTCR_EL2);

This looks a bit suspicious. Looking at the specs, the bits does not 
seem to correspond here.

I will look at the rest either tomorrow or Monday.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 2/7] arm64: Add definitions for fwnode_handle
  2017-10-12 12:45   ` Julien Grall
@ 2017-10-19 14:53     ` Goel, Sameer
  2017-10-24 14:08       ` Julien Grall
  0 siblings, 1 reply; 34+ messages in thread
From: Goel, Sameer @ 2017-10-19 14:53 UTC (permalink / raw)
  To: Julien Grall, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 10/12/2017 6:45 AM, Julien Grall wrote:
> Hi,
> 
> On 21/09/17 01:37, Sameer Goel wrote:
>> This will be used as a device property to match the DMA capable devices
>> with the associated SMMU. The header file is a port from linux. The code
>> was changed to remove the types that were not needed for Xen.
> 
> I think you probably want a bit more context in the commit message about implement fwnode.h in common code.
> 
> Within this series, fwnode seems to only be used by Arm. So what would be the advantage to get that in xen/? Is it going to be used by x86 or taken advantage in common code?
> 
>>
>> Linux ChangeId:ce793486e23e: driver core / ACPI: Represent ACPI
>> companions using fwnode_handle
>>
>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>> ---
>>   xen/include/asm-arm/device.h |  2 ++
>>   xen/include/xen/fwnode.h     | 33 +++++++++++++++++++++++++++++++++
>>   2 files changed, 35 insertions(+)
>>   create mode 100644 xen/include/xen/fwnode.h
>>
>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>> index 6734ae8..78c38fe 100644
>> --- a/xen/include/asm-arm/device.h
>> +++ b/xen/include/asm-arm/device.h
>> @@ -2,6 +2,7 @@
>>   #define __ASM_ARM_DEVICE_H
>>     #include <xen/init.h>
>> +#include <xen/fwnode.h>
>>     enum device_type
>>   {
>> @@ -19,6 +20,7 @@ struct device
>>   #ifdef CONFIG_HAS_DEVICE_TREE
>>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
> 
> I was expecting a todo in the code after the discussion about leave of_node here.
> 
>>   #endif
>> +    struct fwnode_handle *fwnode; /*fw device node identifier */
The fwnode handle was provide a match cookie for the SMMUs and not much else. Even with this around we will need the 
dt info in the device node. I agree that this rolls up into fw spec and I can look at the code cleanup for the next patch.
> 
> Space missing before "fw".
> 
>>       struct dev_archdata archdata;
>>   };
>>   diff --git a/xen/include/xen/fwnode.h b/xen/include/xen/fwnode.h
>> new file mode 100644
>> index 0000000..0fed958
>> --- /dev/null
>> +++ b/xen/include/xen/fwnode.h
>> @@ -0,0 +1,33 @@
>> +/*
>> + * fwnode.h - Firmware device node object handle type definition.
>> + *
>> + * Copyright (C) 2015, Intel Corporation
>> + * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * Ported from Linux include/linux/fwnode.h
>> + *  => commit ce793486e23e0162a732c605189c8028e0910e86
>> + *
>> + * No functional Xen modifications.
>> + */
>> +
>> +#ifndef __XEN_FWNODE_H_
>> +#define __XEN_FWNODE_H_
>> +
>> +enum fwnode_type {
>> +    FWNODE_INVALID = 0,
>> +    FWNODE_OF,
>> +    FWNODE_ACPI,
>> +    FWNODE_ACPI_STATIC,
>> +    FWNODE_IRQCHIP
>> +};
>> +
> 
> Looking at Linux code, the fwnode_type already disappeared from Linux (see commit db3e50f3234b "device property: Get rid of struct fwnode_handle type field").
> 
> I understand the goal on using fwnode is to help porting drivers from Linux. So how much this has changed now?
This was not very useful in any case. So, I will move over to the new version.

> 
> Cheers,
> 
>> +struct fwnode_handle {
>> +    enum fwnode_type type;
>> +    struct fwnode_handle *secondary;
>> +};
>> +
>> +#endif
>>
> 

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec
  2017-10-12 13:05   ` Julien Grall
  2017-10-12 13:36     ` Julien Grall
@ 2017-10-19 14:58     ` Goel, Sameer
  1 sibling, 0 replies; 34+ messages in thread
From: Goel, Sameer @ 2017-10-19 14:58 UTC (permalink / raw)
  To: Julien Grall, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 10/12/2017 7:05 AM, Julien Grall wrote:
> Hi,
> 
> On 21/09/17 01:37, Sameer Goel wrote:
>> Introduce a common structure to hold the fw (ACPI or DT) defined
>> configuration for SMMU hw. The current use case is for arm SMMUs. So,
>> making this architecture specific.
>>
>> Based on Linux kernel commit 57f98d2f61e1: iommu: Introduce iommu_fwspec
>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>> ---
>>   xen/drivers/passthrough/arm/iommu.c | 66 +++++++++++++++++++++++++++++++++++++
>>   xen/include/asm-arm/device.h        |  1 +
>>   xen/include/xen/iommu.h             | 29 ++++++++++++++++
>>   3 files changed, 96 insertions(+)
>>
>> diff --git a/xen/drivers/passthrough/arm/iommu.c b/xen/drivers/passthrough/arm/iommu.c
>> index 95b1abb..41c6497 100644
>> --- a/xen/drivers/passthrough/arm/iommu.c
>> +++ b/xen/drivers/passthrough/arm/iommu.c
>> @@ -73,3 +73,69 @@ int arch_iommu_populate_page_table(struct domain *d)
>>       /* The IOMMU shares the p2m with the CPU */
>>       return -ENOSYS;
>>   }
>> +
>> +const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
>> +{
>> +    return iommu_get_ops();
> 
> Can you please add a comment explain why you always return iommu_get_ops()?
> 
> Would it be possible that the device is not behind an IOMMU?
That is true. I will fix this.
> 
>> +}
>> +
>> +int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
>> +        const struct iommu_ops *ops)
>> +{
>> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>> +
>> +    if ( fwspec )
>> +        return ops == fwspec->ops ? 0 : -EINVAL;
>> +
>> +    fwspec = _xzalloc(sizeof(struct iommu_fwspec), sizeof(void *));
> 
> On the previous version this was xzalloc(struct iommu_fwspec), why?
> 
> I also don't understand the align on sizeof(void *).
Forgot why I did this. I will change it back. I just copied the alignment value from xzalloc.
> 
>> +    if ( !fwspec )
>> +        return -ENOMEM;
>> +
>> +    fwspec->iommu_fwnode = iommu_fwnode;
>> +    fwspec->ops = ops;
>> +    dev->iommu_fwspec = fwspec;
>> +
>> +    return 0;
>> +}
>> +
>> +void iommu_fwspec_free(struct device *dev)
>> +{
>> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>> +
>> +    if ( fwspec )
>> +    {
> 
> Linux is dropping the reference on the iommu_fwnode. Are we never expecting to take reference on the it in Xen?
I will fix this.
> 
>> +        xfree(fwspec);
>> +        dev->iommu_fwspec = NULL;
>> +    }
>> +}
>> +
>> +int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
>> +{
>> +    struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>> +    struct iommu_fwspec *fwspec_n = NULL;
>> +    size_t size, size_n;
>> +    int i;
>> +
>> +    if ( !fwspec )
>> +        return -EINVAL;
>> +
>> +    size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids]);
>> +    size_n = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
>> +    if ( size_n > size )
>> +    { > +        fwspec_n = _xzalloc(size_n, sizeof(void *));
> 
> Same question about _xzalloc() here.
> 
See above.
>> +        if ( !fwspec_n )
>> +            return -ENOMEM;
>> +
>> +        memcpy(fwspec_n, fwspec, size);
>> +        xfree(fwspec);
>> +    }
>> +
>> +    for (i = 0; i < num_ids; i++)
>> +        fwspec_n->ids[fwspec_n->num_ids + i] = ids[i];
>> +
>> +    fwspec_n->num_ids += num_ids;
>> +    dev->iommu_fwspec = fwspec_n;
>> +
>> +    return 0;
>> +}
>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>> index 78c38fe..5027c87 100644
>> --- a/xen/include/asm-arm/device.h
>> +++ b/xen/include/asm-arm/device.h
>> @@ -21,6 +21,7 @@ struct device
>>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>>   #endif
>>       struct fwnode_handle *fwnode; /*fw device node identifier */
>> +    struct iommu_fwspec *iommu_fwspec;
>>       struct dev_archdata archdata;
>>   };
>>   diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
>> index 0dac4f3..34e8d68 100644
>> --- a/xen/include/xen/iommu.h
>> +++ b/xen/include/xen/iommu.h
>> @@ -208,4 +208,33 @@ DECLARE_PER_CPU(bool_t, iommu_dont_flush_iotlb);
>>   extern struct spinlock iommu_pt_cleanup_lock;
>>   extern struct page_list_head iommu_pt_cleanup_list;
>>   +/**
>> + * Following block was ported from Linux to help with the implementation of
>> + * arm64 iommu devices. Hence the architecture specific compile
>> + */
>> +
>> +#if defined(CONFIG_ARM)
> 
> If it is Arm only, then it should be moved in asm-arm/iommu.h.
Will do.
> 
>> +/**
>> + * struct iommu_fwspec - per-device IOMMU instance data
>> + * @ops: ops for this device's IOMMU
>> + * @iommu_fwnode: firmware handle for this device's IOMMU
>> + * @iommu_priv: IOMMU driver private data for this device
>> + * @num_ids: number of associated device IDs
>> + * @ids: IDs which this device may present to the IOMMU
>> + */
>> +struct iommu_fwspec {
>> +    const struct iommu_ops *ops;
>> +    struct fwnode_handle   *iommu_fwnode;
>> +    void                   *iommu_priv;
>> +    unsigned int           num_ids;
>> +    u32                    ids[1];
>> +};
>> +
>> +int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
>> +              const struct iommu_ops *ops);
>> +void iommu_fwspec_free(struct device *dev);
>> +int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
>> +const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode);
>> +
>> +#endif
>>   #endif /* _IOMMU_H_ */
>>
> 
> Cheers,
> 

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-10-10 12:36   ` Manish Jaggi
@ 2017-10-19 15:00     ` Goel, Sameer
  2017-10-20  6:25       ` Manish Jaggi
  0 siblings, 1 reply; 34+ messages in thread
From: Goel, Sameer @ 2017-10-19 15:00 UTC (permalink / raw)
  To: Manish Jaggi, xen-devel, julien.grall
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd


On 10/10/2017 6:36 AM, Manish Jaggi wrote:
> Hi Sameer,
> On 9/21/2017 6:07 AM, Sameer Goel wrote:
>> Add support for parsing IORT table to initialize SMMU devices.
>> * The code for creating an SMMU device has been modified, so that the SMMU
>> device can be initialized.
>> * The NAMED NODE code has been commented out as this will need DOM0 kernel
>> support.
>> * ITS code has been included but it has not been tested.
> Could you please refactor this patch into another set of two patches.
> I am planning to rebase my IORT for Dom0 Hiding patch rework on this patch.

I will try to break this up. Lets discuss this a bit more next week.
> Thanks,
> Manish
>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>> ---
>>   xen/arch/arm/setup.c               |   3 +
>>   xen/drivers/acpi/Makefile          |   1 +
>>   xen/drivers/acpi/arm/Makefile      |   1 +
>>   xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
>>   xen/drivers/passthrough/arm/smmu.c |   1 +
>>   xen/include/acpi/acpi_iort.h       |  17 ++--
>>   xen/include/asm-arm/device.h       |   2 +
>>   xen/include/xen/acpi.h             |  21 +++++
>>   xen/include/xen/pci.h              |   8 ++
>>   9 files changed, 146 insertions(+), 81 deletions(-)
>>   create mode 100644 xen/drivers/acpi/arm/Makefile
>>
>> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
>> index 92f173b..4ba09b2 100644
>> --- a/xen/arch/arm/setup.c
>> +++ b/xen/arch/arm/setup.c
>> @@ -49,6 +49,7 @@
>>   #include <asm/setup.h>
>>   #include <xsm/xsm.h>
>>   #include <asm/acpi.h>
>> +#include <acpi/acpi_iort.h>
>>     struct bootinfo __initdata bootinfo;
>>   @@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
>>         tasklet_subsys_init();
>>   +    /* Parse the ACPI iort data */
>> +    acpi_iort_init();
>>         xsm_dt_init();
>>   diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
>> index 444b11d..e7ffd82 100644
>> --- a/xen/drivers/acpi/Makefile
>> +++ b/xen/drivers/acpi/Makefile
>> @@ -1,5 +1,6 @@
>>   subdir-y += tables
>>   subdir-y += utilities
>> +subdir-$(CONFIG_ARM) += arm
>>   subdir-$(CONFIG_X86) += apei
>>     obj-bin-y += tables.init.o
>> diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
>> new file mode 100644
>> index 0000000..7c039bb
>> --- /dev/null
>> +++ b/xen/drivers/acpi/arm/Makefile
>> @@ -0,0 +1 @@
>> +obj-y += iort.o
>> diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
>> index 2e368a6..7f54062 100644
>> --- a/xen/drivers/acpi/arm/iort.c
>> +++ b/xen/drivers/acpi/arm/iort.c
>> @@ -14,17 +14,47 @@
>>    * This file implements early detection/parsing of I/O mapping
>>    * reported to OS through firmware via I/O Remapping Table (IORT)
>>    * IORT document number: ARM DEN 0049A
>> + *
>> + * Based on Linux drivers/acpi/arm64/iort.c
>> + * => commit ca78d3173cff3503bcd15723b049757f75762d15
>> + *
>> + * Xen modification:
>> + * Sameer Goel <sgoel@codeaurora.org>
>> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
>> + *
>>    */
>>   -#define pr_fmt(fmt)    "ACPI: IORT: " fmt
>> -
>> -#include <linux/acpi_iort.h>
>> -#include <linux/iommu.h>
>> -#include <linux/kernel.h>
>> -#include <linux/list.h>
>> -#include <linux/pci.h>
>> -#include <linux/platform_device.h>
>> -#include <linux/slab.h>
>> +#include <xen/acpi.h>
>> +#include <acpi/acpi_iort.h>
>> +#include <xen/fwnode.h>
>> +#include <xen/iommu.h>
>> +#include <xen/lib.h>
>> +#include <xen/list.h>
>> +#include <xen/pci.h>
>> +
>> +#include <asm/device.h>
>> +
>> +/* Xen: Define compatibility functions */
>> +#define FW_BUG        "[Firmware Bug]: "
>> +#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
>> +#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
>> +
>> +/* Alias to Xen allocation helpers */
>> +#define kfree xfree
>> +#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
>> +#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))
>> +
>> +/* Redefine WARN macros */
>> +#undef WARN
>> +#undef WARN_ON
>> +#define WARN(condition, format...) ({                    \
>> +    int __ret_warn_on = !!(condition);                \
>> +    if (unlikely(__ret_warn_on))                    \
>> +        printk(format);                        \
>> +    unlikely(__ret_warn_on);                    \
>> +})
>> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
>> +#define WARN_ON(cond)                      (!!cond)
>>     #define IORT_TYPE_MASK(type)    (1 << (type))
>>   #define IORT_MSI_TYPE        (1 << ACPI_IORT_NODE_ITS_GROUP)
>> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>       acpi_status status;
>>         if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
>> +        status = AE_NOT_IMPLEMENTED;
>> +/*
>> + * We need the namespace object name from dsdt to match the iort node, this
>> + * will need additions to the kernel xen bus notifiers.
>> + * So, disabling the named node code till a proposal is approved.
>> + */
>> +#if 0
>>           struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>>           struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>>           struct acpi_iort_named_component *ncomp;
>> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>           status = !strcmp(ncomp->device_name, buf.pointer) ?
>>                               AE_OK : AE_NOT_FOUND;
>>           acpi_os_free(buf.pointer);
>> +#endif
>>       } else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>>           struct acpi_iort_root_complex *pci_rc;
>> -        struct pci_bus *bus;
>> +        struct pci_dev *pci_dev;
>>   -        bus = to_pci_bus(dev);
>> +        pci_dev = to_pci_dev(dev);
>>           pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>             /*
>> @@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>            * with root complexes. Each segment number can represent only
>>            * one root complex.
>>            */
>> -        status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
>> +        status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
>>                               AE_OK : AE_NOT_FOUND;
>>       } else {
>>           status = AE_NOT_FOUND;
>>       }
>> -out:
>>       return status;
>>   }
>>   @@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
>>       return 0;
>>   }
>>   +/*
>> + * Named components are not supported yet so we do not need the
>> + * iort_node_get_id function
>> + */
>> +#if 0
>>   static
>>   struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>                       u32 *id_out, u8 type_mask,
>> @@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>         return NULL;
>>   }
>> +#endif
>>     static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
>>                           u32 rid_in, u32 *rid_out,
>> @@ -410,6 +453,10 @@ fail_map:
>>       return NULL;
>>   }
>>   +/* Xen: Comment out the NamedComponent and ITS mapping code till the support
>> + * is available.
>> + */
>> +#if 0
>>   static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
>>   {
>>       struct pci_bus *pbus;
>> @@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
>>       return 0;
>>   }
>>   -/**
>> +/*
>>    * iort_get_device_domain() - Find MSI domain related to a device
>>    * @dev: The device.
>>    * @req_id: Requester ID for the device.
>> @@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>>       *rid = alias;
>>       return 0;
>>   }
>> -
>> +#endif
>>   static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>>                      struct fwnode_handle *fwnode,
>>                      const struct iommu_ops *ops)
>> @@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>>       return ret ? NULL : ops;
>>   }
>>   +#if 0 /* Xen: We do not need this function for Xen */
>>   /**
>>    * iort_set_dma_mask - Set-up dma mask for a device.
>>    *
>> @@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
>>       if (!dev->dma_mask)
>>           dev->dma_mask = &dev->coherent_dma_mask;
>>   }
>> -
>> +#endif
>>   /**
>>    * iort_iommu_configure - Set-up IOMMU configuration for a device.
>>    *
>> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>       u32 streamid = 0;
>>         if (dev_is_pci(dev)) {
>> -        struct pci_bus *bus = to_pci_dev(dev)->bus;
>> +        struct pci_dev *pci_device = to_pci_dev(dev);
>>           u32 rid;
>>   -        pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
>> -                       &rid);
>> +        rid = PCI_BDF2(pci_device->bus, pci_device->devfn);
>>             node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
>> -                      iort_match_node_callback, &bus->dev);
>> +                      iort_match_node_callback, dev);
>>           if (!node)
>>               return NULL;
>>   @@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>           ops = iort_iommu_xlate(dev, parent, streamid);
>>         } else {
>> +        return NULL;
>> +/*
>> + * We need the namespace object name from dsdt to match the iort node, this
>> + * will need additions to the kernel xen bus notifiers.
>> + * So, disabling the named node code till a proposal is approved.
>> + */
>> +#if 0
>>           int i = 0;
>>             node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
>> @@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>               parent = iort_node_get_id(node, &streamid,
>>                             IORT_IOMMU_TYPE, i++);
>>           }
>> +#endif
>>       }
>>         return ops;
>>   }
>>   +/*
>> + * Xen: Not using the parsing ops for now. Need to check and see if it will
>> + * be useful to use these in some form, or let the driver parse IORT node.
>> + */
>> +#if 0
>>   static void __init acpi_iort_register_irq(int hwirq, const char *name,
>>                         int trigger,
>>                         struct resource *res)
>> @@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>           return NULL;
>>       }
>>   }
>> -
>> +#endif
>>   /**
>>    * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>>    * @node: Pointer to SMMU ACPI IORT node
>> @@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>   static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
>>   {
>>       struct fwnode_handle *fwnode;
>> -    struct platform_device *pdev;
>> -    struct resource *r;
>> -    enum dev_dma_attr attr;
>> -    int ret, count;
>> -    const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
>> -
>> -    if (!ops)
>> -        return -ENODEV;
>> -
>> -    pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
>> -    if (!pdev)
>> -        return -ENOMEM;
>> -
>> -    count = ops->iommu_count_resources(node);
>> -
>> -    r = kcalloc(count, sizeof(*r), GFP_KERNEL);
>> -    if (!r) {
>> -        ret = -ENOMEM;
>> -        goto dev_put;
>> -    }
>> -
>> -    ops->iommu_init_resources(r, node);
>> +    struct device *dev;
>> +    int ret;
>>   -    ret = platform_device_add_resources(pdev, r, count);
>>       /*
>> -     * Resources are duplicated in platform_device_add_resources,
>> -     * free their allocated memory
>> +     * Not enabling the parsing ops for now. The corresponding driver
>> +     * can parse this information as needed, so deleting relevant code as
>> +     * compared to base revision.
>>        */
>> -    kfree(r);
>>   -    if (ret)
>> -        goto dev_put;
>> +    dev = kzalloc(sizeof(struct device), GFP_KERNEL);
>> +    if (!dev)
>> +        return -ENOMEM;
>>         /*
>>        * Add a copy of IORT node pointer to platform_data to
>>        * be used to retrieve IORT data information.
>>        */
>> -    ret = platform_device_add_data(pdev, &node, sizeof(node));
>> -    if (ret)
>> -        goto dev_put;
>> -
>> -    /*
>> -     * We expect the dma masks to be equivalent for
>> -     * all SMMUs set-ups
>> -     */
>> -    pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
>> +    dev->type = DEV_ACPI;
>> +    dev->acpi_node = node;
>>         fwnode = iort_get_fwnode(node);
>>         if (!fwnode) {
>>           ret = -ENODEV;
>> -        goto dev_put;
>> +        goto error;
>>       }
>>   -    pdev->dev.fwnode = fwnode;
>> -
>> -    attr = ops->iommu_is_coherent(node) ?
>> -                 DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
>> -
>> -    /* Configure DMA for the page table walker */
>> -    acpi_dma_configure(&pdev->dev, attr);
>> +    dev->fwnode = fwnode;
>>   -    ret = platform_device_add(pdev);
>> -    if (ret)
>> -        goto dma_deconfigure;
>> +    /* Call the acpi init functions for IOMMU devices */
>> +    ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
>>         return 0;
>>   -dma_deconfigure:
>> -    acpi_dma_deconfigure(&pdev->dev);
>> -dev_put:
>> -    platform_device_put(pdev);
>> +error:
>> +    kfree(dev);
>>         return ret;
>>   }
>> @@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
>>         iort_init_platform_devices();
>>   -    acpi_probe_device_table(iort);
>> +    /* Xen; Do not need a device table probe */
>> +    /* acpi_probe_device_table(iort);*/
>>   }
>> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
>> index 362d578..ad956d5 100644
>> --- a/xen/drivers/passthrough/arm/smmu.c
>> +++ b/xen/drivers/passthrough/arm/smmu.c
>> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>>    * Xen: PCI functions
>>    * TODO: It should be implemented when PCI will be supported
>>    */
>> +#undef to_pci_dev
>>   #define to_pci_dev(dev)    (NULL)
>>   static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
>>                        int (*fn) (struct pci_dev *pdev,
>> diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
>> index 77e0809..d4315a4 100644
>> --- a/xen/include/acpi/acpi_iort.h
>> +++ b/xen/include/acpi/acpi_iort.h
>> @@ -19,27 +19,32 @@
>>   #ifndef __ACPI_IORT_H__
>>   #define __ACPI_IORT_H__
>>   -#include <linux/acpi.h>
>> -#include <linux/fwnode.h>
>> -#include <linux/irqdomain.h>
>> +#include <xen/acpi.h>
>> +#include <asm/device.h>
>>   +/* Xen: Not using IORT IRQ bindings */
>> +#if 0
>>   #define IORT_IRQ_MASK(irq)        (irq & 0xffffffffULL)
>>   #define IORT_IRQ_TRIGGER_MASK(irq)    ((irq >> 32) & 0xffffffffULL)
>>     int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
>>   void iort_deregister_domain_token(int trans_id);
>>   struct fwnode_handle *iort_find_domain_token(int trans_id);
>> -#ifdef CONFIG_ACPI_IORT
>> +#endif
>> +#ifdef CONFIG_ARM_64
>>   void acpi_iort_init(void);
>>   bool iort_node_match(u8 type);
>> +#if 0
>>   u32 iort_msi_map_rid(struct device *dev, u32 req_id);
>>   struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
>>   /* IOMMU interface */
>>   void iort_set_dma_mask(struct device *dev);
>> +#endif
>>   const struct iommu_ops *iort_iommu_configure(struct device *dev);
>>   #else
>>   static inline void acpi_iort_init(void) { }
>>   static inline bool iort_node_match(u8 type) { return false; }
>> +#if 0
>>   static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>>   { return req_id; }
>>   static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>> @@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>>   { return NULL; }
>>   /* IOMMU interface */
>>   static inline void iort_set_dma_mask(struct device *dev) { }
>> +#endif
>>   static inline
>>   const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>   { return NULL; }
>>   #endif
>>   -#define IORT_ACPI_DECLARE(name, table_id, fn)        \
>> -    ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
>> -
>>   #endif /* __ACPI_IORT_H__ */
>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>> index 5027c87..4eef9ce 100644
>> --- a/xen/include/asm-arm/device.h
>> +++ b/xen/include/asm-arm/device.h
>> @@ -7,6 +7,7 @@
>>   enum device_type
>>   {
>>       DEV_DT,
>> +    DEV_ACPI,
>>   };
>>     struct dev_archdata {
>> @@ -20,6 +21,7 @@ struct device
>>   #ifdef CONFIG_HAS_DEVICE_TREE
>>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>>   #endif
>> +    void *acpi_node; /*Current use case is acpi_iort_node */
>>       struct fwnode_handle *fwnode; /*fw device node identifier */
>>       struct iommu_fwspec *iommu_fwspec;
>>       struct dev_archdata archdata;
>> diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
>> index 9409350..2f6aae1 100644
>> --- a/xen/include/xen/acpi.h
>> +++ b/xen/include/xen/acpi.h
>> @@ -32,6 +32,7 @@
>>     #include <acpi/acpi.h>
>>   #include <asm/acpi.h>
>> +#include <xen/fwnode.h>
>>     #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
>>       (ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
>> @@ -49,6 +50,26 @@
>>                   (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
>>                   (entry)->header.length < sizeof(*(entry)))
>>   +static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
>> +{
>> +    struct fwnode_handle *fwnode;
>> +
>> +    fwnode = xzalloc(struct fwnode_handle);
>> +    if (!fwnode)
>> +        return NULL;
>> +
>> +    fwnode->type = FWNODE_ACPI_STATIC;
>> +
>> +    return fwnode;
>> +}
>> +
>> +static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
>> +{
>> +    if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
>> +        return;
>> +
>> +    xfree(fwnode);
>> +}
>>   #ifdef CONFIG_ACPI
>>     enum acpi_interrupt_id {
>> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
>> index 43f2125..182b1a5 100644
>> --- a/xen/include/xen/pci.h
>> +++ b/xen/include/xen/pci.h
>> @@ -92,8 +92,16 @@ struct pci_dev {
>>   #define PT_FAULT_THRESHOLD 10
>>       } fault;
>>       u64 vf_rlen[6];
>> +#ifdef CONFIG_ARM
>> +    struct device dev;
>> +#endif
>>   };
>>   +#ifdef CONFIG_ARM
>> +#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
>> +#define pci_domain_nr(dev) dev->seg
>> +#endif
>> +
>>   #define for_each_pdev(domain, pdev) \
>>       list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
>>   
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-10-12 14:06   ` Julien Grall
@ 2017-10-19 15:21     ` Goel, Sameer
  2017-10-24 14:26       ` Julien Grall
  0 siblings, 1 reply; 34+ messages in thread
From: Goel, Sameer @ 2017-10-19 15:21 UTC (permalink / raw)
  To: Julien Grall, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 10/12/2017 8:06 AM, Julien Grall wrote:
> Hi Sameer,
> 
> On 21/09/17 01:37, Sameer Goel wrote:
>> Add support for parsing IORT table to initialize SMMU devices.
>> * The code for creating an SMMU device has been modified, so that the SMMU
>> device can be initialized.
>> * The NAMED NODE code has been commented out as this will need DOM0 kernel
>> support.
>> * ITS code has been included but it has not been tested.
>>
>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>> ---
>>   xen/arch/arm/setup.c               |   3 +
>>   xen/drivers/acpi/Makefile          |   1 +
>>   xen/drivers/acpi/arm/Makefile      |   1 +
>>   xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
>>   xen/drivers/passthrough/arm/smmu.c |   1 +
>>   xen/include/acpi/acpi_iort.h       |  17 ++--
>>   xen/include/asm-arm/device.h       |   2 +
>>   xen/include/xen/acpi.h             |  21 +++++
>>   xen/include/xen/pci.h              |   8 ++
>>   9 files changed, 146 insertions(+), 81 deletions(-)
>>   create mode 100644 xen/drivers/acpi/arm/Makefile
>>
>> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
>> index 92f173b..4ba09b2 100644
>> --- a/xen/arch/arm/setup.c
>> +++ b/xen/arch/arm/setup.c
>> @@ -49,6 +49,7 @@
>>   #include <asm/setup.h>
>>   #include <xsm/xsm.h>
>>   #include <asm/acpi.h>
>> +#include <acpi/acpi_iort.h>
>>     struct bootinfo __initdata bootinfo;
>>   @@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
>>         tasklet_subsys_init();
>>   +    /* Parse the ACPI iort data */
>> +    acpi_iort_init();
>>         xsm_dt_init();
>>   diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
>> index 444b11d..e7ffd82 100644
>> --- a/xen/drivers/acpi/Makefile
>> +++ b/xen/drivers/acpi/Makefile
>> @@ -1,5 +1,6 @@
>>   subdir-y += tables
>>   subdir-y += utilities
>> +subdir-$(CONFIG_ARM) += arm
>>   subdir-$(CONFIG_X86) += apei
>>     obj-bin-y += tables.init.o
>> diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
>> new file mode 100644
>> index 0000000..7c039bb
>> --- /dev/null
>> +++ b/xen/drivers/acpi/arm/Makefile
>> @@ -0,0 +1 @@
>> +obj-y += iort.o
>> diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
>> index 2e368a6..7f54062 100644
>> --- a/xen/drivers/acpi/arm/iort.c
>> +++ b/xen/drivers/acpi/arm/iort.c
>> @@ -14,17 +14,47 @@
>>    * This file implements early detection/parsing of I/O mapping
>>    * reported to OS through firmware via I/O Remapping Table (IORT)
>>    * IORT document number: ARM DEN 0049A
>> + *
>> + * Based on Linux drivers/acpi/arm64/iort.c
>> + * => commit ca78d3173cff3503bcd15723b049757f75762d15
>> + *
>> + * Xen modification:
>> + * Sameer Goel <sgoel@codeaurora.org>
>> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
>> + *
>>    */
>>   -#define pr_fmt(fmt)    "ACPI: IORT: " fmt
>> -
>> -#include <linux/acpi_iort.h>
>> -#include <linux/iommu.h>
>> -#include <linux/kernel.h>
>> -#include <linux/list.h>
>> -#include <linux/pci.h>
>> -#include <linux/platform_device.h>
>> -#include <linux/slab.h>
>> +#include <xen/acpi.h>
>> +#include <acpi/acpi_iort.h>
> 
> Why do you need to include there? Can't this be done after all the <xen/> ?
I was just clubbing the acpi includes. I can move this after all xen/
> 
>> +#include <xen/fwnode.h>
>> +#include <xen/iommu.h>
>> +#include <xen/lib.h>
>> +#include <xen/list.h>
>> +#include <xen/pci.h>
>> +
>> +#include <asm/device.h>
>> +
>> +/* Xen: Define compatibility functions */
>> +#define FW_BUG        "[Firmware Bug]: "
>> +#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
>> +#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
>> +
>> +/* Alias to Xen allocation helpers */
>> +#define kfree xfree
>> +#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
>> +#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))
> 
> Likely you would need the same macros in the SMMUv3 driver. Could we think of a common headers implementing the Linux compat layer?
I agree that this will be a very useful. i'll try to propose something.
> 
>> +
>> +/* Redefine WARN macros */
>> +#undef WARN
>> +#undef WARN_ON
>> +#define WARN(condition, format...) ({                    \
>> +    int __ret_warn_on = !!(condition);                \
>> +    if (unlikely(__ret_warn_on))                    \
>> +        printk(format);                        \
>> +    unlikely(__ret_warn_on);                    \
>> +})
> 
> Again, you should at least try to modify the common code version before deciding to redefine it here.
The xen macro seems such that it explicitly tries to block a return by wrapping this macro in a loop. I had changed the common function in the last iteration and there seemed to be a pushback. 
> 
>> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
>> +#define WARN_ON(cond)                      (!!cond)
>>     #define IORT_TYPE_MASK(type)    (1 << (type))
>>   #define IORT_MSI_TYPE        (1 << ACPI_IORT_NODE_ITS_GROUP)
>> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>       acpi_status status;
>>         if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
>> +        status = AE_NOT_IMPLEMENTED;
>> +/*
>> + * We need the namespace object name from dsdt to match the iort node, this
> 
> Please add a "Xen: TODO:" in front.
Ok.
> 
>> + * will need additions to the kernel xen bus notifiers.
>> + * So, disabling the named node code till a proposal is approved.
>> + */
>> +#if 0
>>           struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>>           struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>>           struct acpi_iort_named_component *ncomp;
>> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>           status = !strcmp(ncomp->device_name, buf.pointer) ?
>>                               AE_OK : AE_NOT_FOUND;
>>           acpi_os_free(buf.pointer);
>> +#endif
>>       } else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>>           struct acpi_iort_root_complex *pci_rc;
>> -        struct pci_bus *bus;
>> +        struct pci_dev *pci_dev;
> 
> Do you really need to modify the code? Wouldn't it be possible to do
> 
> #define pci_bus pci_dev
The pci_dev is the container for the generic device. I wanted to call this out explicitly here. We can do the above if you insist :).
> 
> With an explanation why you do that on top.
> 
>>   -        bus = to_pci_bus(dev);
>> +        pci_dev = to_pci_dev(dev);
> 
> Same here?
> 
>>           pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>             /*
>> @@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>            * with root complexes. Each segment number can represent only
>>            * one root complex.
>>            */
>> -        status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
>> +        status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
>>                               AE_OK : AE_NOT_FOUND;
>>       } else {
>>           status = AE_NOT_FOUND;
>>       }
>> -out:
>>       return status;
>>   }
>>   @@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
>>       return 0;
>>   }
>>   +/*
>> + * Named components are not supported yet so we do not need the
>> + * iort_node_get_id function
> 
> Missing full stop + TODO.
Ok.
> 
>> + */
>> +#if 0
>>   static
>>   struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>                       u32 *id_out, u8 type_mask,
>> @@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>         return NULL;
>>   }
>> +#endif
>>     static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
>>                           u32 rid_in, u32 *rid_out,
>> @@ -410,6 +453,10 @@ fail_map:
>>       return NULL;
>>   }
>>   +/* Xen: Comment out the NamedComponent and ITS mapping code till the support
> 
> + TODO here please.
> 
Ok.
>> + * is available.
>> + */
>> +#if 0
>>   static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
>>   {
>>       struct pci_bus *pbus;
>> @@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
>>       return 0;
>>   }
>>   -/**
>> +/*
> 
> Why this change?
Oversight.
> 
>>    * iort_get_device_domain() - Find MSI domain related to a device
>>    * @dev: The device.
>>    * @req_id: Requester ID for the device.
>> @@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>>       *rid = alias;
>>       return 0;
>>   }
>> -
>> +#endif
> 
> Please avoid dropping newline.
> 
>>   static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>>                      struct fwnode_handle *fwnode,
>>                      const struct iommu_ops *ops)
>> @@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>>       return ret ? NULL : ops;
>>   }
>>   +#if 0 /* Xen: We do not need this function for Xen */
>>   /**
>>    * iort_set_dma_mask - Set-up dma mask for a device.
>>    *
>> @@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
>>       if (!dev->dma_mask)
>>           dev->dma_mask = &dev->coherent_dma_mask;
>>   }
>> -
>> +#endif
> 
> Same here.
> 
>>   /**
>>    * iort_iommu_configure - Set-up IOMMU configuration for a device.
>>    *
>> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>       u32 streamid = 0;
>>         if (dev_is_pci(dev)) {
>> -        struct pci_bus *bus = to_pci_dev(dev)->bus;
>> +        struct pci_dev *pci_device = to_pci_dev(dev);
> 
> See above.
> 
>>           u32 rid;
>>   -        pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
>> -                       &rid);
>> +        rid = PCI_BDF2(pci_device->bus, pci_device->devfn);
> 
> I believe we had a discussion on v1 explaining why this is wrong. So I don't understand why
The intent here was to have some working support code to get the SMMUv3 driver ready for a first review. I still need to research on how to fix this correctly based on the v1 comments. I'll fix it in the next RFC.
> 
>>             node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
>> -                      iort_match_node_callback, &bus->dev);
>> +                      iort_match_node_callback, dev);
>>           if (!node)
>>               return NULL;
>>   @@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>           ops = iort_iommu_xlate(dev, parent, streamid);
>>         } else {
>> +        return NULL;
>> +/*
>> + * We need the namespace object name from dsdt to match the iort node, this
> 
> Xen:
> 
>> + * will need additions to the kernel xen bus notifiers.
>> + * So, disabling the named node code till a proposal is approved.
>> + */
>> +#if 0
>>           int i = 0;
>>             node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
>> @@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>               parent = iort_node_get_id(node, &streamid,
>>                             IORT_IOMMU_TYPE, i++);
>>           }
>> +#endif
>>       }
>>         return ops;
>>   }
>>   +/*
>> + * Xen: Not using the parsing ops for now. Need to check and see if it will
>> + * be useful to use these in some form, or let the driver parse IORT node.
>> + */
>> +#if 0
>>   static void __init acpi_iort_register_irq(int hwirq, const char *name,
>>                         int trigger,
>>                         struct resource *res)
>> @@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>           return NULL;
>>       }
>>   }
>> -
>> +#endif
> 
> Please avoid dropping newline.
> 
>>   /**
>>    * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>>    * @node: Pointer to SMMU ACPI IORT node
>> @@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>   static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
> 
> Looking at the changes in this function. You basically rewrite everything. I would prefer if you comment the current one and implement from scratch the Xen version.
Agree.
> 
>>   {
>>       struct fwnode_handle *fwnode;
>> -    struct platform_device *pdev;
>> -    struct resource *r;
>> -    enum dev_dma_attr attr;
>> -    int ret, count;
>> -    const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
>> -
>> -    if (!ops)
>> -        return -ENODEV;
>> -
>> -    pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
>> -    if (!pdev)
>> -        return -ENOMEM;
>> -
>> -    count = ops->iommu_count_resources(node);
>> -
>> -    r = kcalloc(count, sizeof(*r), GFP_KERNEL);
>> -    if (!r) {
>> -        ret = -ENOMEM;
>> -        goto dev_put;
>> -    }
>> -
>> -    ops->iommu_init_resources(r, node);
>> +    struct device *dev;
>> +    int ret;
>>   -    ret = platform_device_add_resources(pdev, r, count);
>>       /*
>> -     * Resources are duplicated in platform_device_add_resources,
>> -     * free their allocated memory
>> +     * Not enabling the parsing ops for now. The corresponding driver
>> +     * can parse this information as needed, so deleting relevant code as
>> +     * compared to base revision.
>>        */
>> -    kfree(r);
>>   -    if (ret)
>> -        goto dev_put;
>> +    dev = kzalloc(sizeof(struct device), GFP_KERNEL);
>> +    if (!dev)
>> +        return -ENOMEM;
>>         /*
>>        * Add a copy of IORT node pointer to platform_data to
>>        * be used to retrieve IORT data information.
>>        */
>> -    ret = platform_device_add_data(pdev, &node, sizeof(node));
>> -    if (ret)
>> -        goto dev_put;
>> -
>> -    /*
>> -     * We expect the dma masks to be equivalent for
>> -     * all SMMUs set-ups
>> -     */
>> -    pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
>> +    dev->type = DEV_ACPI;
>> +    dev->acpi_node = node;
>>         fwnode = iort_get_fwnode(node);
>>         if (!fwnode) {
>>           ret = -ENODEV;
>> -        goto dev_put;
>> +        goto error;
>>       }
>>   -    pdev->dev.fwnode = fwnode;
>> -
>> -    attr = ops->iommu_is_coherent(node) ?
>> -                 DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
>> -
>> -    /* Configure DMA for the page table walker */
>> -    acpi_dma_configure(&pdev->dev, attr);
>> +    dev->fwnode = fwnode;
>>   -    ret = platform_device_add(pdev);
>> -    if (ret)
>> -        goto dma_deconfigure;
>> +    /* Call the acpi init functions for IOMMU devices */
>> +    ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
>>         return 0;
>>   -dma_deconfigure:
>> -    acpi_dma_deconfigure(&pdev->dev);
>> -dev_put:
>> -    platform_device_put(pdev);
>> +error:
>> +    kfree(dev);
>>         return ret;
>>   }
>> @@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
>>         iort_init_platform_devices();
>>   -    acpi_probe_device_table(iort);
>> +    /* Xen; Do not need a device table probe */
>> +    /* acpi_probe_device_table(iort);*/
> 
> Please use either
> 
> #if 0
> 
> #endif
> 
> or introduce a dummy acpi_probe_device_table(...) at the start.
Will introduce a dummy acpi_probe.
> 
>>   }
>> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
>> index 362d578..ad956d5 100644
>> --- a/xen/drivers/passthrough/arm/smmu.c
>> +++ b/xen/drivers/passthrough/arm/smmu.c
>> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>>    * Xen: PCI functions
>>    * TODO: It should be implemented when PCI will be supported
>>    */
>> +#undef to_pci_dev
> 
> Why this change?
I had redefine the to_pci_dev to get the actual pci_dev struct. smmu driver does not use pci yet.
> 
>>   #define to_pci_dev(dev)    (NULL)
>>   static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
>>                        int (*fn) (struct pci_dev *pdev,
>> diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
>> index 77e0809..d4315a4 100644
>> --- a/xen/include/acpi/acpi_iort.h
>> +++ b/xen/include/acpi/acpi_iort.h
> 
> You probably want to re-sync this headers as it changed quite a bit and would avoid some specific #if 0 for Xen.
> 
>> @@ -19,27 +19,32 @@
>>   #ifndef __ACPI_IORT_H__
>>   #define __ACPI_IORT_H__
>>   -#include <linux/acpi.h>
>> -#include <linux/fwnode.h>
>> -#include <linux/irqdomain.h>
>> +#include <xen/acpi.h>
>> +#include <asm/device.h>
>>   +/* Xen: Not using IORT IRQ bindings */
>> +#if 0
>>   #define IORT_IRQ_MASK(irq)        (irq & 0xffffffffULL)
>>   #define IORT_IRQ_TRIGGER_MASK(irq)    ((irq >> 32) & 0xffffffffULL)
>>     int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
>>   void iort_deregister_domain_token(int trans_id);
>>   struct fwnode_handle *iort_find_domain_token(int trans_id);
>> -#ifdef CONFIG_ACPI_IORT
>> +#endif
>> +#ifdef CONFIG_ARM_64
> 
> As said in the first version, I see no point of replacing CONFIG_ACPI_IORT with CONFIG_ARM_64. You should instead take advantage of the Kconfig to add a new config ACPI_IORT and select on Arm64 with ACPI.

I agree. I saw your comments a bit late for this RFC. I will add this to the next set.
> 
>>   void acpi_iort_init(void);
>>   bool iort_node_match(u8 type);
>> +#if 0
>>   u32 iort_msi_map_rid(struct device *dev, u32 req_id);
>>   struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
>>   /* IOMMU interface */
>>   void iort_set_dma_mask(struct device *dev);
>> +#endif
>>   const struct iommu_ops *iort_iommu_configure(struct device *dev);
>>   #else
>>   static inline void acpi_iort_init(void) { }
>>   static inline bool iort_node_match(u8 type) { return false; }
>> +#if 0
>>   static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>>   { return req_id; }
>>   static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>> @@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>>   { return NULL; }
>>   /* IOMMU interface */
>>   static inline void iort_set_dma_mask(struct device *dev) { }
>> +#endif
>>   static inline
>>   const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>   { return NULL; }
>>   #endif
>>   -#define IORT_ACPI_DECLARE(name, table_id, fn)        \
>> -    ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
>> -
>>   #endif /* __ACPI_IORT_H__ */
>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>> index 5027c87..4eef9ce 100644
>> --- a/xen/include/asm-arm/device.h
>> +++ b/xen/include/asm-arm/device.h
>> @@ -7,6 +7,7 @@
>>   enum device_type
>>   {
>>       DEV_DT,
>> +    DEV_ACPI,
>>   };
>>     struct dev_archdata {
>> @@ -20,6 +21,7 @@ struct device
>>   #ifdef CONFIG_HAS_DEVICE_TREE
>>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>>   #endif
>> +    void *acpi_node; /*Current use case is acpi_iort_node */
> 
> Can you explain why you need that? After the creation of fwnode, I was expecting of_node to disappear. So I don't really fancy see acpi_node here more it does not exist in Linux.
of_node stays for backwards compatibility with smmu v2 driver. I will try to find a way to remove acpi_node.
> 
>>       struct fwnode_handle *fwnode; /*fw device node identifier */
>>       struct iommu_fwspec *iommu_fwspec;
>>       struct dev_archdata archdata;
>> diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
>> index 9409350..2f6aae1 100644
>> --- a/xen/include/xen/acpi.h
>> +++ b/xen/include/xen/acpi.h
>> @@ -32,6 +32,7 @@
>>     #include <acpi/acpi.h>
>>   #include <asm/acpi.h>
>> +#include <xen/fwnode.h>
> 
> I think this and ...
> 
>>     #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
>>       (ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
>> @@ -49,6 +50,26 @@
>>                   (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
>>                   (entry)->header.length < sizeof(*(entry)))
>>   +static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
>> +{
>> +    struct fwnode_handle *fwnode;
>> +
>> +    fwnode = xzalloc(struct fwnode_handle);
>> +    if (!fwnode)
>> +        return NULL;
>> +
>> +    fwnode->type = FWNODE_ACPI_STATIC;
>> +
>> +    return fwnode;
>> +}
>> +
>> +static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
>> +{
>> +    if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
>> +        return;
>> +
>> +    xfree(fwnode);
>> +}
> 
> ... those 2 helpers should go in asm/acpi.h.
Ok.
> 
>>   #ifdef CONFIG_ACPI
>>     enum acpi_interrupt_id {
>> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
>> index 43f2125..182b1a5 100644
>> --- a/xen/include/xen/pci.h
>> +++ b/xen/include/xen/pci.h
>> @@ -92,8 +92,16 @@ struct pci_dev {
>>   #define PT_FAULT_THRESHOLD 10
>>       } fault;
>>       u64 vf_rlen[6];
>> +#ifdef CONFIG_ARM
>> +    struct device dev;
>> +#endif
> 
> There are a part of PCI that is already per-arch. See arch_pci_dev in asm-arm/pci.h.
> 
> Please define the field dev in it rather than here.
Ok, I'll check if I can do this.
> 
>>   };
>>   +#ifdef CONFIG_ARM
>> +#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
>> +#define pci_domain_nr(dev) dev->seg
>> +#endif
> 
> Similarly, this should be moved in asm-arm/pci.h.
Ok.
> 
>> +
>>   #define for_each_pdev(domain, pdev) \
>>       list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
>>  
> 
> Cheers,
> 

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-10-19 15:00     ` Goel, Sameer
@ 2017-10-20  6:25       ` Manish Jaggi
  0 siblings, 0 replies; 34+ messages in thread
From: Manish Jaggi @ 2017-10-20  6:25 UTC (permalink / raw)
  To: Goel, Sameer, xen-devel, julien.grall
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 10/19/2017 8:30 PM, Goel, Sameer wrote:
> On 10/10/2017 6:36 AM, Manish Jaggi wrote:
>> Hi Sameer,
>> On 9/21/2017 6:07 AM, Sameer Goel wrote:
>>> Add support for parsing IORT table to initialize SMMU devices.
>>> * The code for creating an SMMU device has been modified, so that the SMMU
>>> device can be initialized.
>>> * The NAMED NODE code has been commented out as this will need DOM0 kernel
>>> support.
>>> * ITS code has been included but it has not been tested.
>> Could you please refactor this patch into another set of two patches.
>> I am planning to rebase my IORT for Dom0 Hiding patch rework on this patch.
> I will try to break this up. Lets discuss this a bit more next week.
Please have a look at the draft design. [1]
[1] https://www.mail-archive.com/xen-devel@lists.xen.org/msg125951.html
>> Thanks,
>> Manish
>>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>>> ---
>>>    xen/arch/arm/setup.c               |   3 +
>>>    xen/drivers/acpi/Makefile          |   1 +
>>>    xen/drivers/acpi/arm/Makefile      |   1 +
>>>    xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
>>>    xen/drivers/passthrough/arm/smmu.c |   1 +
>>>    xen/include/acpi/acpi_iort.h       |  17 ++--
>>>    xen/include/asm-arm/device.h       |   2 +
>>>    xen/include/xen/acpi.h             |  21 +++++
>>>    xen/include/xen/pci.h              |   8 ++
>>>    9 files changed, 146 insertions(+), 81 deletions(-)
>>>    create mode 100644 xen/drivers/acpi/arm/Makefile
>>>
>>> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
>>> index 92f173b..4ba09b2 100644
>>> --- a/xen/arch/arm/setup.c
>>> +++ b/xen/arch/arm/setup.c
>>> @@ -49,6 +49,7 @@
>>>    #include <asm/setup.h>
>>>    #include <xsm/xsm.h>
>>>    #include <asm/acpi.h>
>>> +#include <acpi/acpi_iort.h>
>>>      struct bootinfo __initdata bootinfo;
>>>    @@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
>>>          tasklet_subsys_init();
>>>    +    /* Parse the ACPI iort data */
>>> +    acpi_iort_init();
>>>          xsm_dt_init();
>>>    diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
>>> index 444b11d..e7ffd82 100644
>>> --- a/xen/drivers/acpi/Makefile
>>> +++ b/xen/drivers/acpi/Makefile
>>> @@ -1,5 +1,6 @@
>>>    subdir-y += tables
>>>    subdir-y += utilities
>>> +subdir-$(CONFIG_ARM) += arm
>>>    subdir-$(CONFIG_X86) += apei
>>>      obj-bin-y += tables.init.o
>>> diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
>>> new file mode 100644
>>> index 0000000..7c039bb
>>> --- /dev/null
>>> +++ b/xen/drivers/acpi/arm/Makefile
>>> @@ -0,0 +1 @@
>>> +obj-y += iort.o
>>> diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
>>> index 2e368a6..7f54062 100644
>>> --- a/xen/drivers/acpi/arm/iort.c
>>> +++ b/xen/drivers/acpi/arm/iort.c
>>> @@ -14,17 +14,47 @@
>>>     * This file implements early detection/parsing of I/O mapping
>>>     * reported to OS through firmware via I/O Remapping Table (IORT)
>>>     * IORT document number: ARM DEN 0049A
>>> + *
>>> + * Based on Linux drivers/acpi/arm64/iort.c
>>> + * => commit ca78d3173cff3503bcd15723b049757f75762d15
>>> + *
>>> + * Xen modification:
>>> + * Sameer Goel <sgoel@codeaurora.org>
>>> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
>>> + *
>>>     */
>>>    -#define pr_fmt(fmt)    "ACPI: IORT: " fmt
>>> -
>>> -#include <linux/acpi_iort.h>
>>> -#include <linux/iommu.h>
>>> -#include <linux/kernel.h>
>>> -#include <linux/list.h>
>>> -#include <linux/pci.h>
>>> -#include <linux/platform_device.h>
>>> -#include <linux/slab.h>
>>> +#include <xen/acpi.h>
>>> +#include <acpi/acpi_iort.h>
>>> +#include <xen/fwnode.h>
>>> +#include <xen/iommu.h>
>>> +#include <xen/lib.h>
>>> +#include <xen/list.h>
>>> +#include <xen/pci.h>
>>> +
>>> +#include <asm/device.h>
>>> +
>>> +/* Xen: Define compatibility functions */
>>> +#define FW_BUG        "[Firmware Bug]: "
>>> +#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
>>> +#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
>>> +
>>> +/* Alias to Xen allocation helpers */
>>> +#define kfree xfree
>>> +#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
>>> +#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))
>>> +
>>> +/* Redefine WARN macros */
>>> +#undef WARN
>>> +#undef WARN_ON
>>> +#define WARN(condition, format...) ({                    \
>>> +    int __ret_warn_on = !!(condition);                \
>>> +    if (unlikely(__ret_warn_on))                    \
>>> +        printk(format);                        \
>>> +    unlikely(__ret_warn_on);                    \
>>> +})
>>> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
>>> +#define WARN_ON(cond)                      (!!cond)
>>>      #define IORT_TYPE_MASK(type)    (1 << (type))
>>>    #define IORT_MSI_TYPE        (1 << ACPI_IORT_NODE_ITS_GROUP)
>>> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>>        acpi_status status;
>>>          if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
>>> +        status = AE_NOT_IMPLEMENTED;
>>> +/*
>>> + * We need the namespace object name from dsdt to match the iort node, this
>>> + * will need additions to the kernel xen bus notifiers.
>>> + * So, disabling the named node code till a proposal is approved.
>>> + */
>>> +#if 0
>>>            struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>>>            struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>>>            struct acpi_iort_named_component *ncomp;
>>> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>>            status = !strcmp(ncomp->device_name, buf.pointer) ?
>>>                                AE_OK : AE_NOT_FOUND;
>>>            acpi_os_free(buf.pointer);
>>> +#endif
>>>        } else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>>>            struct acpi_iort_root_complex *pci_rc;
>>> -        struct pci_bus *bus;
>>> +        struct pci_dev *pci_dev;
>>>    -        bus = to_pci_bus(dev);
>>> +        pci_dev = to_pci_dev(dev);
>>>            pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>>              /*
>>> @@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>>             * with root complexes. Each segment number can represent only
>>>             * one root complex.
>>>             */
>>> -        status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
>>> +        status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
>>>                                AE_OK : AE_NOT_FOUND;
>>>        } else {
>>>            status = AE_NOT_FOUND;
>>>        }
>>> -out:
>>>        return status;
>>>    }
>>>    @@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
>>>        return 0;
>>>    }
>>>    +/*
>>> + * Named components are not supported yet so we do not need the
>>> + * iort_node_get_id function
>>> + */
>>> +#if 0
>>>    static
>>>    struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>>                        u32 *id_out, u8 type_mask,
>>> @@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>>          return NULL;
>>>    }
>>> +#endif
>>>      static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
>>>                            u32 rid_in, u32 *rid_out,
>>> @@ -410,6 +453,10 @@ fail_map:
>>>        return NULL;
>>>    }
>>>    +/* Xen: Comment out the NamedComponent and ITS mapping code till the support
>>> + * is available.
>>> + */
>>> +#if 0
>>>    static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
>>>    {
>>>        struct pci_bus *pbus;
>>> @@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
>>>        return 0;
>>>    }
>>>    -/**
>>> +/*
>>>     * iort_get_device_domain() - Find MSI domain related to a device
>>>     * @dev: The device.
>>>     * @req_id: Requester ID for the device.
>>> @@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>>>        *rid = alias;
>>>        return 0;
>>>    }
>>> -
>>> +#endif
>>>    static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>>>                       struct fwnode_handle *fwnode,
>>>                       const struct iommu_ops *ops)
>>> @@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>>>        return ret ? NULL : ops;
>>>    }
>>>    +#if 0 /* Xen: We do not need this function for Xen */
>>>    /**
>>>     * iort_set_dma_mask - Set-up dma mask for a device.
>>>     *
>>> @@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
>>>        if (!dev->dma_mask)
>>>            dev->dma_mask = &dev->coherent_dma_mask;
>>>    }
>>> -
>>> +#endif
>>>    /**
>>>     * iort_iommu_configure - Set-up IOMMU configuration for a device.
>>>     *
>>> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>>        u32 streamid = 0;
>>>          if (dev_is_pci(dev)) {
>>> -        struct pci_bus *bus = to_pci_dev(dev)->bus;
>>> +        struct pci_dev *pci_device = to_pci_dev(dev);
>>>            u32 rid;
>>>    -        pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
>>> -                       &rid);
>>> +        rid = PCI_BDF2(pci_device->bus, pci_device->devfn);
>>>              node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
>>> -                      iort_match_node_callback, &bus->dev);
>>> +                      iort_match_node_callback, dev);
>>>            if (!node)
>>>                return NULL;
>>>    @@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>>            ops = iort_iommu_xlate(dev, parent, streamid);
>>>          } else {
>>> +        return NULL;
>>> +/*
>>> + * We need the namespace object name from dsdt to match the iort node, this
>>> + * will need additions to the kernel xen bus notifiers.
>>> + * So, disabling the named node code till a proposal is approved.
>>> + */
>>> +#if 0
>>>            int i = 0;
>>>              node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
>>> @@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>>                parent = iort_node_get_id(node, &streamid,
>>>                              IORT_IOMMU_TYPE, i++);
>>>            }
>>> +#endif
>>>        }
>>>          return ops;
>>>    }
>>>    +/*
>>> + * Xen: Not using the parsing ops for now. Need to check and see if it will
>>> + * be useful to use these in some form, or let the driver parse IORT node.
>>> + */
>>> +#if 0
>>>    static void __init acpi_iort_register_irq(int hwirq, const char *name,
>>>                          int trigger,
>>>                          struct resource *res)
>>> @@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>>            return NULL;
>>>        }
>>>    }
>>> -
>>> +#endif
>>>    /**
>>>     * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>>>     * @node: Pointer to SMMU ACPI IORT node
>>> @@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>>    static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
>>>    {
>>>        struct fwnode_handle *fwnode;
>>> -    struct platform_device *pdev;
>>> -    struct resource *r;
>>> -    enum dev_dma_attr attr;
>>> -    int ret, count;
>>> -    const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
>>> -
>>> -    if (!ops)
>>> -        return -ENODEV;
>>> -
>>> -    pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
>>> -    if (!pdev)
>>> -        return -ENOMEM;
>>> -
>>> -    count = ops->iommu_count_resources(node);
>>> -
>>> -    r = kcalloc(count, sizeof(*r), GFP_KERNEL);
>>> -    if (!r) {
>>> -        ret = -ENOMEM;
>>> -        goto dev_put;
>>> -    }
>>> -
>>> -    ops->iommu_init_resources(r, node);
>>> +    struct device *dev;
>>> +    int ret;
>>>    -    ret = platform_device_add_resources(pdev, r, count);
>>>        /*
>>> -     * Resources are duplicated in platform_device_add_resources,
>>> -     * free their allocated memory
>>> +     * Not enabling the parsing ops for now. The corresponding driver
>>> +     * can parse this information as needed, so deleting relevant code as
>>> +     * compared to base revision.
>>>         */
>>> -    kfree(r);
>>>    -    if (ret)
>>> -        goto dev_put;
>>> +    dev = kzalloc(sizeof(struct device), GFP_KERNEL);
>>> +    if (!dev)
>>> +        return -ENOMEM;
>>>          /*
>>>         * Add a copy of IORT node pointer to platform_data to
>>>         * be used to retrieve IORT data information.
>>>         */
>>> -    ret = platform_device_add_data(pdev, &node, sizeof(node));
>>> -    if (ret)
>>> -        goto dev_put;
>>> -
>>> -    /*
>>> -     * We expect the dma masks to be equivalent for
>>> -     * all SMMUs set-ups
>>> -     */
>>> -    pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
>>> +    dev->type = DEV_ACPI;
>>> +    dev->acpi_node = node;
>>>          fwnode = iort_get_fwnode(node);
>>>          if (!fwnode) {
>>>            ret = -ENODEV;
>>> -        goto dev_put;
>>> +        goto error;
>>>        }
>>>    -    pdev->dev.fwnode = fwnode;
>>> -
>>> -    attr = ops->iommu_is_coherent(node) ?
>>> -                 DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
>>> -
>>> -    /* Configure DMA for the page table walker */
>>> -    acpi_dma_configure(&pdev->dev, attr);
>>> +    dev->fwnode = fwnode;
>>>    -    ret = platform_device_add(pdev);
>>> -    if (ret)
>>> -        goto dma_deconfigure;
>>> +    /* Call the acpi init functions for IOMMU devices */
>>> +    ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
>>>          return 0;
>>>    -dma_deconfigure:
>>> -    acpi_dma_deconfigure(&pdev->dev);
>>> -dev_put:
>>> -    platform_device_put(pdev);
>>> +error:
>>> +    kfree(dev);
>>>          return ret;
>>>    }
>>> @@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
>>>          iort_init_platform_devices();
>>>    -    acpi_probe_device_table(iort);
>>> +    /* Xen; Do not need a device table probe */
>>> +    /* acpi_probe_device_table(iort);*/
>>>    }
>>> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
>>> index 362d578..ad956d5 100644
>>> --- a/xen/drivers/passthrough/arm/smmu.c
>>> +++ b/xen/drivers/passthrough/arm/smmu.c
>>> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>>>     * Xen: PCI functions
>>>     * TODO: It should be implemented when PCI will be supported
>>>     */
>>> +#undef to_pci_dev
>>>    #define to_pci_dev(dev)    (NULL)
>>>    static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
>>>                         int (*fn) (struct pci_dev *pdev,
>>> diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
>>> index 77e0809..d4315a4 100644
>>> --- a/xen/include/acpi/acpi_iort.h
>>> +++ b/xen/include/acpi/acpi_iort.h
>>> @@ -19,27 +19,32 @@
>>>    #ifndef __ACPI_IORT_H__
>>>    #define __ACPI_IORT_H__
>>>    -#include <linux/acpi.h>
>>> -#include <linux/fwnode.h>
>>> -#include <linux/irqdomain.h>
>>> +#include <xen/acpi.h>
>>> +#include <asm/device.h>
>>>    +/* Xen: Not using IORT IRQ bindings */
>>> +#if 0
>>>    #define IORT_IRQ_MASK(irq)        (irq & 0xffffffffULL)
>>>    #define IORT_IRQ_TRIGGER_MASK(irq)    ((irq >> 32) & 0xffffffffULL)
>>>      int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
>>>    void iort_deregister_domain_token(int trans_id);
>>>    struct fwnode_handle *iort_find_domain_token(int trans_id);
>>> -#ifdef CONFIG_ACPI_IORT
>>> +#endif
>>> +#ifdef CONFIG_ARM_64
>>>    void acpi_iort_init(void);
>>>    bool iort_node_match(u8 type);
>>> +#if 0
>>>    u32 iort_msi_map_rid(struct device *dev, u32 req_id);
>>>    struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
>>>    /* IOMMU interface */
>>>    void iort_set_dma_mask(struct device *dev);
>>> +#endif
>>>    const struct iommu_ops *iort_iommu_configure(struct device *dev);
>>>    #else
>>>    static inline void acpi_iort_init(void) { }
>>>    static inline bool iort_node_match(u8 type) { return false; }
>>> +#if 0
>>>    static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>>>    { return req_id; }
>>>    static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>>> @@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>>>    { return NULL; }
>>>    /* IOMMU interface */
>>>    static inline void iort_set_dma_mask(struct device *dev) { }
>>> +#endif
>>>    static inline
>>>    const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>>    { return NULL; }
>>>    #endif
>>>    -#define IORT_ACPI_DECLARE(name, table_id, fn)        \
>>> -    ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
>>> -
>>>    #endif /* __ACPI_IORT_H__ */
>>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>>> index 5027c87..4eef9ce 100644
>>> --- a/xen/include/asm-arm/device.h
>>> +++ b/xen/include/asm-arm/device.h
>>> @@ -7,6 +7,7 @@
>>>    enum device_type
>>>    {
>>>        DEV_DT,
>>> +    DEV_ACPI,
>>>    };
>>>      struct dev_archdata {
>>> @@ -20,6 +21,7 @@ struct device
>>>    #ifdef CONFIG_HAS_DEVICE_TREE
>>>        struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>>>    #endif
>>> +    void *acpi_node; /*Current use case is acpi_iort_node */
>>>        struct fwnode_handle *fwnode; /*fw device node identifier */
>>>        struct iommu_fwspec *iommu_fwspec;
>>>        struct dev_archdata archdata;
>>> diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
>>> index 9409350..2f6aae1 100644
>>> --- a/xen/include/xen/acpi.h
>>> +++ b/xen/include/xen/acpi.h
>>> @@ -32,6 +32,7 @@
>>>      #include <acpi/acpi.h>
>>>    #include <asm/acpi.h>
>>> +#include <xen/fwnode.h>
>>>      #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
>>>        (ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
>>> @@ -49,6 +50,26 @@
>>>                    (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
>>>                    (entry)->header.length < sizeof(*(entry)))
>>>    +static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
>>> +{
>>> +    struct fwnode_handle *fwnode;
>>> +
>>> +    fwnode = xzalloc(struct fwnode_handle);
>>> +    if (!fwnode)
>>> +        return NULL;
>>> +
>>> +    fwnode->type = FWNODE_ACPI_STATIC;
>>> +
>>> +    return fwnode;
>>> +}
>>> +
>>> +static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
>>> +{
>>> +    if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
>>> +        return;
>>> +
>>> +    xfree(fwnode);
>>> +}
>>>    #ifdef CONFIG_ACPI
>>>      enum acpi_interrupt_id {
>>> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
>>> index 43f2125..182b1a5 100644
>>> --- a/xen/include/xen/pci.h
>>> +++ b/xen/include/xen/pci.h
>>> @@ -92,8 +92,16 @@ struct pci_dev {
>>>    #define PT_FAULT_THRESHOLD 10
>>>        } fault;
>>>        u64 vf_rlen[6];
>>> +#ifdef CONFIG_ARM
>>> +    struct device dev;
>>> +#endif
>>>    };
>>>    +#ifdef CONFIG_ARM
>>> +#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
>>> +#define pci_domain_nr(dev) dev->seg
>>> +#endif
>>> +
>>>    #define for_each_pdev(domain, pdev) \
>>>        list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
>>>    
>>
>> _______________________________________________
>> Xen-devel mailing list
>> Xen-devel@lists.xen.org
>> https://lists.xen.org/xen-devel


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 2/7] arm64: Add definitions for fwnode_handle
  2017-10-19 14:53     ` Goel, Sameer
@ 2017-10-24 14:08       ` Julien Grall
  2017-11-09  0:56         ` Goel, Sameer
  0 siblings, 1 reply; 34+ messages in thread
From: Julien Grall @ 2017-10-24 14:08 UTC (permalink / raw)
  To: Goel, Sameer, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 19/10/17 15:53, Goel, Sameer wrote:
> On 10/12/2017 6:45 AM, Julien Grall wrote:
>> On 21/09/17 01:37, Sameer Goel wrote:
>>> This will be used as a device property to match the DMA capable devices
>>> with the associated SMMU. The header file is a port from linux. The code
>>> was changed to remove the types that were not needed for Xen.
>>
>> I think you probably want a bit more context in the commit message about implement fwnode.h in common code.
>>
>> Within this series, fwnode seems to only be used by Arm. So what would be the advantage to get that in xen/? Is it going to be used by x86 or taken advantage in common code?
>>
>>>
>>> Linux ChangeId:ce793486e23e: driver core / ACPI: Represent ACPI
>>> companions using fwnode_handle
>>>
>>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>>> ---
>>>    xen/include/asm-arm/device.h |  2 ++
>>>    xen/include/xen/fwnode.h     | 33 +++++++++++++++++++++++++++++++++
>>>    2 files changed, 35 insertions(+)
>>>    create mode 100644 xen/include/xen/fwnode.h
>>>
>>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>>> index 6734ae8..78c38fe 100644
>>> --- a/xen/include/asm-arm/device.h
>>> +++ b/xen/include/asm-arm/device.h
>>> @@ -2,6 +2,7 @@
>>>    #define __ASM_ARM_DEVICE_H
>>>      #include <xen/init.h>
>>> +#include <xen/fwnode.h>
>>>      enum device_type
>>>    {
>>> @@ -19,6 +20,7 @@ struct device
>>>    #ifdef CONFIG_HAS_DEVICE_TREE
>>>        struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>>
>> I was expecting a todo in the code after the discussion about leave of_node here.
>>
>>>    #endif
>>> +    struct fwnode_handle *fwnode; /*fw device node identifier */
> The fwnode handle was provide a match cookie for the SMMUs and not much else. Even with this around we will need the
> dt info in the device node. I agree that this rolls up into fw spec and I can look at the code cleanup for the next patch.

A clean-up patch would be great but not necessary. What I expect is a 
TODO mentioning the possible clean-up.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-10-19 15:21     ` Goel, Sameer
@ 2017-10-24 14:26       ` Julien Grall
  0 siblings, 0 replies; 34+ messages in thread
From: Julien Grall @ 2017-10-24 14:26 UTC (permalink / raw)
  To: Goel, Sameer, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 19/10/17 16:21, Goel, Sameer wrote:
> On 10/12/2017 8:06 AM, Julien Grall wrote:
>>> +
>>> +/* Redefine WARN macros */
>>> +#undef WARN
>>> +#undef WARN_ON
>>> +#define WARN(condition, format...) ({                    \
>>> +    int __ret_warn_on = !!(condition);                \
>>> +    if (unlikely(__ret_warn_on))                    \
>>> +        printk(format);                        \
>>> +    unlikely(__ret_warn_on);                    \
>>> +})
>>
>> Again, you should at least try to modify the common code version before deciding to redefine it here.
> The xen macro seems such that it explicitly tries to block a return by wrapping this macro in a loop. I had changed the common function in the last iteration and there seemed to be a pushback.

I don't think there was any pushback on changing the common code. Jan 
Beulich validly requested to move that change in a separate patch.

>>
>>> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
>>> +#define WARN_ON(cond)                      (!!cond)
>>>      #define IORT_TYPE_MASK(type)    (1 << (type))
>>>    #define IORT_MSI_TYPE        (1 << ACPI_IORT_NODE_ITS_GROUP)
>>> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>>        acpi_status status;
>>>          if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
>>> +        status = AE_NOT_IMPLEMENTED;
>>> +/*
>>> + * We need the namespace object name from dsdt to match the iort node, this
>>
>> Please add a "Xen: TODO:" in front.
> Ok.
>>
>>> + * will need additions to the kernel xen bus notifiers.
>>> + * So, disabling the named node code till a proposal is approved.
>>> + */
>>> +#if 0
>>>            struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>>>            struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>>>            struct acpi_iort_named_component *ncomp;
>>> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>>            status = !strcmp(ncomp->device_name, buf.pointer) ?
>>>                                AE_OK : AE_NOT_FOUND;
>>>            acpi_os_free(buf.pointer);
>>> +#endif
>>>        } else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>>>            struct acpi_iort_root_complex *pci_rc;
>>> -        struct pci_bus *bus;
>>> +        struct pci_dev *pci_dev;
>>
>> Do you really need to modify the code? Wouldn't it be possible to do
>>
>> #define pci_bus pci_dev
> The pci_dev is the container for the generic device. I wanted to call this out explicitly here. We can do the above if you insist :).

I agree this can be confusing to read. But that change is not justified 
for the goal you want to achieve. E.g importing the code from Linux and 
keep in sync in the future.

With a comment on top of the definitions, you could explain when pci_bus 
= pci_dev at the moment.

[...]

>>> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
>>> index 362d578..ad956d5 100644
>>> --- a/xen/drivers/passthrough/arm/smmu.c
>>> +++ b/xen/drivers/passthrough/arm/smmu.c
>>> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>>>     * Xen: PCI functions
>>>     * TODO: It should be implemented when PCI will be supported
>>>     */
>>> +#undef to_pci_dev
>>
>> Why this change?
> I had redefine the to_pci_dev to get the actual pci_dev struct. smmu driver does not use pci yet.

That should go in a separate commit in that case with probably all stub 
for PCI you added (see the pci.h).

The reason behind is those changes are not directly related to this 
patch. Patch should be kept simple and do one thing only. This makes 
easier to review.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-09-21  0:37 ` [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table Sameer Goel
                     ` (2 preceding siblings ...)
  2017-10-12 14:23   ` Julien Grall
@ 2017-11-08 14:41   ` Manish Jaggi
  2017-11-15  1:27     ` Goel, Sameer
  3 siblings, 1 reply; 34+ messages in thread
From: Manish Jaggi @ 2017-11-08 14:41 UTC (permalink / raw)
  To: Sameer Goel, xen-devel, julien.grall
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer

On 9/21/2017 6:07 AM, Sameer Goel wrote:
> Add support for parsing IORT table to initialize SMMU devices.
> * The code for creating an SMMU device has been modified, so that the SMMU
> device can be initialized.
> * The NAMED NODE code has been commented out as this will need DOM0 kernel
> support.
> * ITS code has been included but it has not been tested.
>
> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
Followup of the discussions we had on iort parsing and querying streamID 
and deviceId based on RID.
I have extended your patchset with a patch that provides an alternative
way of parsing iort into maps : {rid-streamid}, {rid-deviceID)
which can directly be looked up for searching streamId for a rid. This
will remove the need to traverse iort table again.

The test patch just describes the proposed flow and how the parsing and
query code might fit in. I have not tested it.
The code only compiles.

https://github.com/mjaggi-cavium/xen-wip/commit/df006d64bdbb5c8344de5a710da8bf64c9e8edd5
(This repo has all 7 of your patches + test code patch merged.

Note: The commit text of the patch describes the basic flow /assumptions 
/ usage of functions.
Please see the code along with the v2 design draft.
[RFC] [Draft Design v2] ACPI/IORT Support in Xen.
https://lists.xen.org/archives/html/xen-devel/2017-11/msg00512.html

I seek your advice on this. Please provide your feedback.

Thanks
Manish


> ---
>   xen/arch/arm/setup.c               |   3 +
>   xen/drivers/acpi/Makefile          |   1 +
>   xen/drivers/acpi/arm/Makefile      |   1 +
>   xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
>   xen/drivers/passthrough/arm/smmu.c |   1 +
>   xen/include/acpi/acpi_iort.h       |  17 ++--
>   xen/include/asm-arm/device.h       |   2 +
>   xen/include/xen/acpi.h             |  21 +++++
>   xen/include/xen/pci.h              |   8 ++
>   9 files changed, 146 insertions(+), 81 deletions(-)
>   create mode 100644 xen/drivers/acpi/arm/Makefile
>
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index 92f173b..4ba09b2 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -49,6 +49,7 @@
>   #include <asm/setup.h>
>   #include <xsm/xsm.h>
>   #include <asm/acpi.h>
> +#include <acpi/acpi_iort.h>
>   
>   struct bootinfo __initdata bootinfo;
>   
> @@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
>   
>       tasklet_subsys_init();
>   
> +    /* Parse the ACPI iort data */
> +    acpi_iort_init();
>   
>       xsm_dt_init();
>   
> diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
> index 444b11d..e7ffd82 100644
> --- a/xen/drivers/acpi/Makefile
> +++ b/xen/drivers/acpi/Makefile
> @@ -1,5 +1,6 @@
>   subdir-y += tables
>   subdir-y += utilities
> +subdir-$(CONFIG_ARM) += arm
>   subdir-$(CONFIG_X86) += apei
>   
>   obj-bin-y += tables.init.o
> diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
> new file mode 100644
> index 0000000..7c039bb
> --- /dev/null
> +++ b/xen/drivers/acpi/arm/Makefile
> @@ -0,0 +1 @@
> +obj-y += iort.o
> diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
> index 2e368a6..7f54062 100644
> --- a/xen/drivers/acpi/arm/iort.c
> +++ b/xen/drivers/acpi/arm/iort.c
> @@ -14,17 +14,47 @@
>    * This file implements early detection/parsing of I/O mapping
>    * reported to OS through firmware via I/O Remapping Table (IORT)
>    * IORT document number: ARM DEN 0049A
> + *
> + * Based on Linux drivers/acpi/arm64/iort.c
> + * => commit ca78d3173cff3503bcd15723b049757f75762d15
> + *
> + * Xen modification:
> + * Sameer Goel <sgoel@codeaurora.org>
> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
> + *
>    */
>   
> -#define pr_fmt(fmt)	"ACPI: IORT: " fmt
> -
> -#include <linux/acpi_iort.h>
> -#include <linux/iommu.h>
> -#include <linux/kernel.h>
> -#include <linux/list.h>
> -#include <linux/pci.h>
> -#include <linux/platform_device.h>
> -#include <linux/slab.h>
> +#include <xen/acpi.h>
> +#include <acpi/acpi_iort.h>
> +#include <xen/fwnode.h>
> +#include <xen/iommu.h>
> +#include <xen/lib.h>
> +#include <xen/list.h>
> +#include <xen/pci.h>
> +
> +#include <asm/device.h>
> +
> +/* Xen: Define compatibility functions */
> +#define FW_BUG		"[Firmware Bug]: "
> +#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
> +#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
> +
> +/* Alias to Xen allocation helpers */
> +#define kfree xfree
> +#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
> +#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))
> +
> +/* Redefine WARN macros */
> +#undef WARN
> +#undef WARN_ON
> +#define WARN(condition, format...) ({					\
> +	int __ret_warn_on = !!(condition);				\
> +	if (unlikely(__ret_warn_on))					\
> +		printk(format);						\
> +	unlikely(__ret_warn_on);					\
> +})
> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
> +#define WARN_ON(cond)                      (!!cond)
>   
>   #define IORT_TYPE_MASK(type)	(1 << (type))
>   #define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   	acpi_status status;
>   
>   	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
> +		status = AE_NOT_IMPLEMENTED;
> +/*
> + * We need the namespace object name from dsdt to match the iort node, this
> + * will need additions to the kernel xen bus notifiers.
> + * So, disabling the named node code till a proposal is approved.
> + */
> +#if 0
>   		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>   		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>   		struct acpi_iort_named_component *ncomp;
> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   		status = !strcmp(ncomp->device_name, buf.pointer) ?
>   							AE_OK : AE_NOT_FOUND;
>   		acpi_os_free(buf.pointer);
> +#endif
>   	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>   		struct acpi_iort_root_complex *pci_rc;
> -		struct pci_bus *bus;
> +		struct pci_dev *pci_dev;
>   
> -		bus = to_pci_bus(dev);
> +		pci_dev = to_pci_dev(dev);
>   		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>   
>   		/*
> @@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>   		 * with root complexes. Each segment number can represent only
>   		 * one root complex.
>   		 */
> -		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
> +		status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
>   							AE_OK : AE_NOT_FOUND;
>   	} else {
>   		status = AE_NOT_FOUND;
>   	}
> -out:
>   	return status;
>   }
>   
> @@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
>   	return 0;
>   }
>   
> +/*
> + * Named components are not supported yet so we do not need the
> + * iort_node_get_id function
> + */
> +#if 0
>   static
>   struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>   					u32 *id_out, u8 type_mask,
> @@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>   
>   	return NULL;
>   }
> +#endif
>   
>   static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
>   						u32 rid_in, u32 *rid_out,
> @@ -410,6 +453,10 @@ fail_map:
>   	return NULL;
>   }
>   
> +/* Xen: Comment out the NamedComponent and ITS mapping code till the support
> + * is available.
> + */
> +#if 0
>   static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
>   {
>   	struct pci_bus *pbus;
> @@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
>   	return 0;
>   }
>   
> -/**
> +/*
>    * iort_get_device_domain() - Find MSI domain related to a device
>    * @dev: The device.
>    * @req_id: Requester ID for the device.
> @@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>   	*rid = alias;
>   	return 0;
>   }
> -
> +#endif
>   static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>   			       struct fwnode_handle *fwnode,
>   			       const struct iommu_ops *ops)
> @@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>   	return ret ? NULL : ops;
>   }
>   
> +#if 0 /* Xen: We do not need this function for Xen */
>   /**
>    * iort_set_dma_mask - Set-up dma mask for a device.
>    *
> @@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
>   	if (!dev->dma_mask)
>   		dev->dma_mask = &dev->coherent_dma_mask;
>   }
> -
> +#endif
>   /**
>    * iort_iommu_configure - Set-up IOMMU configuration for a device.
>    *
> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   	u32 streamid = 0;
>   
>   	if (dev_is_pci(dev)) {
> -		struct pci_bus *bus = to_pci_dev(dev)->bus;
> +		struct pci_dev *pci_device = to_pci_dev(dev);
>   		u32 rid;
>   
> -		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
> -				       &rid);
> +		rid = PCI_BDF2(pci_device->bus, pci_device->devfn);
>   
>   		node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
> -				      iort_match_node_callback, &bus->dev);
> +				      iort_match_node_callback, dev);
>   		if (!node)
>   			return NULL;
>   
> @@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   		ops = iort_iommu_xlate(dev, parent, streamid);
>   
>   	} else {
> +		return NULL;
> +/*
> + * We need the namespace object name from dsdt to match the iort node, this
> + * will need additions to the kernel xen bus notifiers.
> + * So, disabling the named node code till a proposal is approved.
> + */
> +#if 0
>   		int i = 0;
>   
>   		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
> @@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   			parent = iort_node_get_id(node, &streamid,
>   						  IORT_IOMMU_TYPE, i++);
>   		}
> +#endif
>   	}
>   
>   	return ops;
>   }
>   
> +/*
> + * Xen: Not using the parsing ops for now. Need to check and see if it will
> + * be useful to use these in some form, or let the driver parse IORT node.
> + */
> +#if 0
>   static void __init acpi_iort_register_irq(int hwirq, const char *name,
>   					  int trigger,
>   					  struct resource *res)
> @@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>   		return NULL;
>   	}
>   }
> -
> +#endif
>   /**
>    * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>    * @node: Pointer to SMMU ACPI IORT node
> @@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>   static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
>   {
>   	struct fwnode_handle *fwnode;
> -	struct platform_device *pdev;
> -	struct resource *r;
> -	enum dev_dma_attr attr;
> -	int ret, count;
> -	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
> -
> -	if (!ops)
> -		return -ENODEV;
> -
> -	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
> -	if (!pdev)
> -		return -ENOMEM;
> -
> -	count = ops->iommu_count_resources(node);
> -
> -	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
> -	if (!r) {
> -		ret = -ENOMEM;
> -		goto dev_put;
> -	}
> -
> -	ops->iommu_init_resources(r, node);
> +	struct device *dev;
> +	int ret;
>   
> -	ret = platform_device_add_resources(pdev, r, count);
>   	/*
> -	 * Resources are duplicated in platform_device_add_resources,
> -	 * free their allocated memory
> +	 * Not enabling the parsing ops for now. The corresponding driver
> +	 * can parse this information as needed, so deleting relevant code as
> +	 * compared to base revision.
>   	 */
> -	kfree(r);
>   
> -	if (ret)
> -		goto dev_put;
> +	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
> +	if (!dev)
> +		return -ENOMEM;
>   
>   	/*
>   	 * Add a copy of IORT node pointer to platform_data to
>   	 * be used to retrieve IORT data information.
>   	 */
> -	ret = platform_device_add_data(pdev, &node, sizeof(node));
> -	if (ret)
> -		goto dev_put;
> -
> -	/*
> -	 * We expect the dma masks to be equivalent for
> -	 * all SMMUs set-ups
> -	 */
> -	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
> +	dev->type = DEV_ACPI;
> +	dev->acpi_node = node;
>   
>   	fwnode = iort_get_fwnode(node);
>   
>   	if (!fwnode) {
>   		ret = -ENODEV;
> -		goto dev_put;
> +		goto error;
>   	}
>   
> -	pdev->dev.fwnode = fwnode;
> -
> -	attr = ops->iommu_is_coherent(node) ?
> -			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
> -
> -	/* Configure DMA for the page table walker */
> -	acpi_dma_configure(&pdev->dev, attr);
> +	dev->fwnode = fwnode;
>   
> -	ret = platform_device_add(pdev);
> -	if (ret)
> -		goto dma_deconfigure;
> +	/* Call the acpi init functions for IOMMU devices */
> +	ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
>   
>   	return 0;
>   
> -dma_deconfigure:
> -	acpi_dma_deconfigure(&pdev->dev);
> -dev_put:
> -	platform_device_put(pdev);
> +error:
> +	kfree(dev);
>   
>   	return ret;
>   }
> @@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
>   
>   	iort_init_platform_devices();
>   
> -	acpi_probe_device_table(iort);
> +	/* Xen; Do not need a device table probe */
> +	/* acpi_probe_device_table(iort);*/
>   }
> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
> index 362d578..ad956d5 100644
> --- a/xen/drivers/passthrough/arm/smmu.c
> +++ b/xen/drivers/passthrough/arm/smmu.c
> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>    * Xen: PCI functions
>    * TODO: It should be implemented when PCI will be supported
>    */
> +#undef to_pci_dev
>   #define to_pci_dev(dev)	(NULL)
>   static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
>   					 int (*fn) (struct pci_dev *pdev,
> diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
> index 77e0809..d4315a4 100644
> --- a/xen/include/acpi/acpi_iort.h
> +++ b/xen/include/acpi/acpi_iort.h
> @@ -19,27 +19,32 @@
>   #ifndef __ACPI_IORT_H__
>   #define __ACPI_IORT_H__
>   
> -#include <linux/acpi.h>
> -#include <linux/fwnode.h>
> -#include <linux/irqdomain.h>
> +#include <xen/acpi.h>
> +#include <asm/device.h>
>   
> +/* Xen: Not using IORT IRQ bindings */
> +#if 0
>   #define IORT_IRQ_MASK(irq)		(irq & 0xffffffffULL)
>   #define IORT_IRQ_TRIGGER_MASK(irq)	((irq >> 32) & 0xffffffffULL)
>   
>   int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
>   void iort_deregister_domain_token(int trans_id);
>   struct fwnode_handle *iort_find_domain_token(int trans_id);
> -#ifdef CONFIG_ACPI_IORT
> +#endif
> +#ifdef CONFIG_ARM_64
>   void acpi_iort_init(void);
>   bool iort_node_match(u8 type);
> +#if 0
>   u32 iort_msi_map_rid(struct device *dev, u32 req_id);
>   struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
>   /* IOMMU interface */
>   void iort_set_dma_mask(struct device *dev);
> +#endif
>   const struct iommu_ops *iort_iommu_configure(struct device *dev);
>   #else
>   static inline void acpi_iort_init(void) { }
>   static inline bool iort_node_match(u8 type) { return false; }
> +#if 0
>   static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>   { return req_id; }
>   static inline struct irq_domain *iort_get_device_domain(struct device *dev,
> @@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>   { return NULL; }
>   /* IOMMU interface */
>   static inline void iort_set_dma_mask(struct device *dev) { }
> +#endif
>   static inline
>   const struct iommu_ops *iort_iommu_configure(struct device *dev)
>   { return NULL; }
>   #endif
>   
> -#define IORT_ACPI_DECLARE(name, table_id, fn)		\
> -	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
> -
>   #endif /* __ACPI_IORT_H__ */
> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
> index 5027c87..4eef9ce 100644
> --- a/xen/include/asm-arm/device.h
> +++ b/xen/include/asm-arm/device.h
> @@ -7,6 +7,7 @@
>   enum device_type
>   {
>       DEV_DT,
> +    DEV_ACPI,
>   };
>   
>   struct dev_archdata {
> @@ -20,6 +21,7 @@ struct device
>   #ifdef CONFIG_HAS_DEVICE_TREE
>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>   #endif
> +    void *acpi_node; /*Current use case is acpi_iort_node */
>       struct fwnode_handle *fwnode; /*fw device node identifier */
>       struct iommu_fwspec *iommu_fwspec;
>       struct dev_archdata archdata;
> diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
> index 9409350..2f6aae1 100644
> --- a/xen/include/xen/acpi.h
> +++ b/xen/include/xen/acpi.h
> @@ -32,6 +32,7 @@
>   
>   #include <acpi/acpi.h>
>   #include <asm/acpi.h>
> +#include <xen/fwnode.h>
>   
>   #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
>   	(ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
> @@ -49,6 +50,26 @@
>                   (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
>                   (entry)->header.length < sizeof(*(entry)))
>   
> +static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
> +{
> +	struct fwnode_handle *fwnode;
> +
> +	fwnode = xzalloc(struct fwnode_handle);
> +	if (!fwnode)
> +		return NULL;
> +
> +	fwnode->type = FWNODE_ACPI_STATIC;
> +
> +	return fwnode;
> +}
> +
> +static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
> +{
> +	if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
> +		return;
> +
> +	xfree(fwnode);
> +}
>   #ifdef CONFIG_ACPI
>   
>   enum acpi_interrupt_id {
> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
> index 43f2125..182b1a5 100644
> --- a/xen/include/xen/pci.h
> +++ b/xen/include/xen/pci.h
> @@ -92,8 +92,16 @@ struct pci_dev {
>   #define PT_FAULT_THRESHOLD 10
>       } fault;
>       u64 vf_rlen[6];
> +#ifdef CONFIG_ARM
> +    struct device dev;
> +#endif
>   };
>   
> +#ifdef CONFIG_ARM
> +#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
> +#define pci_domain_nr(dev) dev->seg
> +#endif
> +
>   #define for_each_pdev(domain, pdev) \
>       list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
>   


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 2/7] arm64: Add definitions for fwnode_handle
  2017-10-24 14:08       ` Julien Grall
@ 2017-11-09  0:56         ` Goel, Sameer
  0 siblings, 0 replies; 34+ messages in thread
From: Goel, Sameer @ 2017-11-09  0:56 UTC (permalink / raw)
  To: Julien Grall, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 10/24/2017 8:08 AM, Julien Grall wrote:
> Hi Sameer,
> 
> On 19/10/17 15:53, Goel, Sameer wrote:
>> On 10/12/2017 6:45 AM, Julien Grall wrote:
>>> On 21/09/17 01:37, Sameer Goel wrote:
>>>> This will be used as a device property to match the DMA capable devices
>>>> with the associated SMMU. The header file is a port from linux. The code
>>>> was changed to remove the types that were not needed for Xen.
>>>
>>> I think you probably want a bit more context in the commit message about implement fwnode.h in common code.
>>>
>>> Within this series, fwnode seems to only be used by Arm. So what would be the advantage to get that in xen/? Is it going to be used by x86 or taken advantage in common code?
>>>
>>>>
>>>> Linux ChangeId:ce793486e23e: driver core / ACPI: Represent ACPI
>>>> companions using fwnode_handle
>>>>
>>>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>>>> ---
>>>>    xen/include/asm-arm/device.h |  2 ++
>>>>    xen/include/xen/fwnode.h     | 33 +++++++++++++++++++++++++++++++++
>>>>    2 files changed, 35 insertions(+)
>>>>    create mode 100644 xen/include/xen/fwnode.h
>>>>
>>>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>>>> index 6734ae8..78c38fe 100644
>>>> --- a/xen/include/asm-arm/device.h
>>>> +++ b/xen/include/asm-arm/device.h
>>>> @@ -2,6 +2,7 @@
>>>>    #define __ASM_ARM_DEVICE_H
>>>>      #include <xen/init.h>
>>>> +#include <xen/fwnode.h>
>>>>      enum device_type
>>>>    {
>>>> @@ -19,6 +20,7 @@ struct device
>>>>    #ifdef CONFIG_HAS_DEVICE_TREE
>>>>        struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>>>
>>> I was expecting a todo in the code after the discussion about leave of_node here.
>>>
>>>>    #endif
>>>> +    struct fwnode_handle *fwnode; /*fw device node identifier */
>> The fwnode handle was provide a match cookie for the SMMUs and not much else. Even with this around we will need the
>> dt info in the device node. I agree that this rolls up into fw spec and I can look at the code cleanup for the next patch.
> 
> A clean-up patch would be great but not necessary. What I expect is a TODO mentioning the possible clean-up.
> 
I looked through the Linux code a bit more. The reason for pulling in the fwnode was to port the iort code as is. So, really I do not need this at all. All I need is a dummy struct for fwnode.

I will remove this header file and add a new definition in the linux compat header. What is a good location for this header?
> Cheers,
> 

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-11-08 14:41   ` Manish Jaggi
@ 2017-11-15  1:27     ` Goel, Sameer
  2017-11-15  8:58       ` Julien Grall
  0 siblings, 1 reply; 34+ messages in thread
From: Goel, Sameer @ 2017-11-15  1:27 UTC (permalink / raw)
  To: Manish Jaggi, xen-devel, julien.grall
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 11/8/2017 7:41 AM, Manish Jaggi wrote:
> Hi Sameer
> 
> On 9/21/2017 6:07 AM, Sameer Goel wrote:
>> Add support for parsing IORT table to initialize SMMU devices.
>> * The code for creating an SMMU device has been modified, so that the SMMU
>> device can be initialized.
>> * The NAMED NODE code has been commented out as this will need DOM0 kernel
>> support.
>> * ITS code has been included but it has not been tested.
>>
>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
> Followup of the discussions we had on iort parsing and querying streamID and deviceId based on RID.
> I have extended your patchset with a patch that provides an alternative
> way of parsing iort into maps : {rid-streamid}, {rid-deviceID)
> which can directly be looked up for searching streamId for a rid. This
> will remove the need to traverse iort table again.
> 
> The test patch just describes the proposed flow and how the parsing and
> query code might fit in. I have not tested it.
> The code only compiles.
> 
> https://github.com/mjaggi-cavium/xen-wip/commit/df006d64bdbb5c8344de5a710da8bf64c9e8edd5
> (This repo has all 7 of your patches + test code patch merged.
> 
> Note: The commit text of the patch describes the basic flow /assumptions / usage of functions.
> Please see the code along with the v2 design draft.
> [RFC] [Draft Design v2] ACPI/IORT Support in Xen.
> https://lists.xen.org/archives/html/xen-devel/2017-11/msg00512.html
> 
> I seek your advice on this. Please provide your feedback.
I responded back on the other thread. I think we are fixing something that is not broken. I will try to post a couple of new RFCs and let's discuss this with incremental changes on the mailing list.

Thanks,
Sameer
> 
> Thanks
> Manish
> 
> 
>> ---
>>   xen/arch/arm/setup.c               |   3 +
>>   xen/drivers/acpi/Makefile          |   1 +
>>   xen/drivers/acpi/arm/Makefile      |   1 +
>>   xen/drivers/acpi/arm/iort.c        | 173 +++++++++++++++++++++----------------
>>   xen/drivers/passthrough/arm/smmu.c |   1 +
>>   xen/include/acpi/acpi_iort.h       |  17 ++--
>>   xen/include/asm-arm/device.h       |   2 +
>>   xen/include/xen/acpi.h             |  21 +++++
>>   xen/include/xen/pci.h              |   8 ++
>>   9 files changed, 146 insertions(+), 81 deletions(-)
>>   create mode 100644 xen/drivers/acpi/arm/Makefile
>>
>> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
>> index 92f173b..4ba09b2 100644
>> --- a/xen/arch/arm/setup.c
>> +++ b/xen/arch/arm/setup.c
>> @@ -49,6 +49,7 @@
>>   #include <asm/setup.h>
>>   #include <xsm/xsm.h>
>>   #include <asm/acpi.h>
>> +#include <acpi/acpi_iort.h>
>>     struct bootinfo __initdata bootinfo;
>>   @@ -796,6 +797,8 @@ void __init start_xen(unsigned long boot_phys_offset,
>>         tasklet_subsys_init();
>>   +    /* Parse the ACPI iort data */
>> +    acpi_iort_init();
>>         xsm_dt_init();
>>   diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
>> index 444b11d..e7ffd82 100644
>> --- a/xen/drivers/acpi/Makefile
>> +++ b/xen/drivers/acpi/Makefile
>> @@ -1,5 +1,6 @@
>>   subdir-y += tables
>>   subdir-y += utilities
>> +subdir-$(CONFIG_ARM) += arm
>>   subdir-$(CONFIG_X86) += apei
>>     obj-bin-y += tables.init.o
>> diff --git a/xen/drivers/acpi/arm/Makefile b/xen/drivers/acpi/arm/Makefile
>> new file mode 100644
>> index 0000000..7c039bb
>> --- /dev/null
>> +++ b/xen/drivers/acpi/arm/Makefile
>> @@ -0,0 +1 @@
>> +obj-y += iort.o
>> diff --git a/xen/drivers/acpi/arm/iort.c b/xen/drivers/acpi/arm/iort.c
>> index 2e368a6..7f54062 100644
>> --- a/xen/drivers/acpi/arm/iort.c
>> +++ b/xen/drivers/acpi/arm/iort.c
>> @@ -14,17 +14,47 @@
>>    * This file implements early detection/parsing of I/O mapping
>>    * reported to OS through firmware via I/O Remapping Table (IORT)
>>    * IORT document number: ARM DEN 0049A
>> + *
>> + * Based on Linux drivers/acpi/arm64/iort.c
>> + * => commit ca78d3173cff3503bcd15723b049757f75762d15
>> + *
>> + * Xen modification:
>> + * Sameer Goel <sgoel@codeaurora.org>
>> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
>> + *
>>    */
>>   -#define pr_fmt(fmt)    "ACPI: IORT: " fmt
>> -
>> -#include <linux/acpi_iort.h>
>> -#include <linux/iommu.h>
>> -#include <linux/kernel.h>
>> -#include <linux/list.h>
>> -#include <linux/pci.h>
>> -#include <linux/platform_device.h>
>> -#include <linux/slab.h>
>> +#include <xen/acpi.h>
>> +#include <acpi/acpi_iort.h>
>> +#include <xen/fwnode.h>
>> +#include <xen/iommu.h>
>> +#include <xen/lib.h>
>> +#include <xen/list.h>
>> +#include <xen/pci.h>
>> +
>> +#include <asm/device.h>
>> +
>> +/* Xen: Define compatibility functions */
>> +#define FW_BUG        "[Firmware Bug]: "
>> +#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
>> +#define pr_warn(fmt, ...) printk(XENLOG_WARNING fmt, ## __VA_ARGS__)
>> +
>> +/* Alias to Xen allocation helpers */
>> +#define kfree xfree
>> +#define kmalloc(size, flags)            _xmalloc(size, sizeof(void *))
>> +#define kzalloc(size, flags)            _xzalloc(size, sizeof(void *))
>> +
>> +/* Redefine WARN macros */
>> +#undef WARN
>> +#undef WARN_ON
>> +#define WARN(condition, format...) ({                    \
>> +    int __ret_warn_on = !!(condition);                \
>> +    if (unlikely(__ret_warn_on))                    \
>> +        printk(format);                        \
>> +    unlikely(__ret_warn_on);                    \
>> +})
>> +#define WARN_TAINT(cond, taint, format...) WARN(cond, format)
>> +#define WARN_ON(cond)                      (!!cond)
>>     #define IORT_TYPE_MASK(type)    (1 << (type))
>>   #define IORT_MSI_TYPE        (1 << ACPI_IORT_NODE_ITS_GROUP)
>> @@ -256,6 +286,13 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>       acpi_status status;
>>         if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
>> +        status = AE_NOT_IMPLEMENTED;
>> +/*
>> + * We need the namespace object name from dsdt to match the iort node, this
>> + * will need additions to the kernel xen bus notifiers.
>> + * So, disabling the named node code till a proposal is approved.
>> + */
>> +#if 0
>>           struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
>>           struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
>>           struct acpi_iort_named_component *ncomp;
>> @@ -275,11 +312,12 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>           status = !strcmp(ncomp->device_name, buf.pointer) ?
>>                               AE_OK : AE_NOT_FOUND;
>>           acpi_os_free(buf.pointer);
>> +#endif
>>       } else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
>>           struct acpi_iort_root_complex *pci_rc;
>> -        struct pci_bus *bus;
>> +        struct pci_dev *pci_dev;
>>   -        bus = to_pci_bus(dev);
>> +        pci_dev = to_pci_dev(dev);
>>           pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>             /*
>> @@ -287,12 +325,11 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
>>            * with root complexes. Each segment number can represent only
>>            * one root complex.
>>            */
>> -        status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
>> +        status = pci_rc->pci_segment_number == pci_domain_nr(pci_dev) ?
>>                               AE_OK : AE_NOT_FOUND;
>>       } else {
>>           status = AE_NOT_FOUND;
>>       }
>> -out:
>>       return status;
>>   }
>>   @@ -320,6 +357,11 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
>>       return 0;
>>   }
>>   +/*
>> + * Named components are not supported yet so we do not need the
>> + * iort_node_get_id function
>> + */
>> +#if 0
>>   static
>>   struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>                       u32 *id_out, u8 type_mask,
>> @@ -358,6 +400,7 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
>>         return NULL;
>>   }
>> +#endif
>>     static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
>>                           u32 rid_in, u32 *rid_out,
>> @@ -410,6 +453,10 @@ fail_map:
>>       return NULL;
>>   }
>>   +/* Xen: Comment out the NamedComponent and ITS mapping code till the support
>> + * is available.
>> + */
>> +#if 0
>>   static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
>>   {
>>       struct pci_bus *pbus;
>> @@ -481,7 +528,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
>>       return 0;
>>   }
>>   -/**
>> +/*
>>    * iort_get_device_domain() - Find MSI domain related to a device
>>    * @dev: The device.
>>    * @req_id: Requester ID for the device.
>> @@ -510,7 +557,7 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>>       *rid = alias;
>>       return 0;
>>   }
>> -
>> +#endif
>>   static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>>                      struct fwnode_handle *fwnode,
>>                      const struct iommu_ops *ops)
>> @@ -546,6 +593,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>>       return ret ? NULL : ops;
>>   }
>>   +#if 0 /* Xen: We do not need this function for Xen */
>>   /**
>>    * iort_set_dma_mask - Set-up dma mask for a device.
>>    *
>> @@ -567,7 +615,7 @@ void iort_set_dma_mask(struct device *dev)
>>       if (!dev->dma_mask)
>>           dev->dma_mask = &dev->coherent_dma_mask;
>>   }
>> -
>> +#endif
>>   /**
>>    * iort_iommu_configure - Set-up IOMMU configuration for a device.
>>    *
>> @@ -583,14 +631,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>       u32 streamid = 0;
>>         if (dev_is_pci(dev)) {
>> -        struct pci_bus *bus = to_pci_dev(dev)->bus;
>> +        struct pci_dev *pci_device = to_pci_dev(dev);
>>           u32 rid;
>>   -        pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
>> -                       &rid);
>> +        rid = PCI_BDF2(pci_device->bus, pci_device->devfn);
>>             node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
>> -                      iort_match_node_callback, &bus->dev);
>> +                      iort_match_node_callback, dev);
>>           if (!node)
>>               return NULL;
>>   @@ -600,6 +647,13 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>           ops = iort_iommu_xlate(dev, parent, streamid);
>>         } else {
>> +        return NULL;
>> +/*
>> + * We need the namespace object name from dsdt to match the iort node, this
>> + * will need additions to the kernel xen bus notifiers.
>> + * So, disabling the named node code till a proposal is approved.
>> + */
>> +#if 0
>>           int i = 0;
>>             node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
>> @@ -616,11 +670,17 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>               parent = iort_node_get_id(node, &streamid,
>>                             IORT_IOMMU_TYPE, i++);
>>           }
>> +#endif
>>       }
>>         return ops;
>>   }
>>   +/*
>> + * Xen: Not using the parsing ops for now. Need to check and see if it will
>> + * be useful to use these in some form, or let the driver parse IORT node.
>> + */
>> +#if 0
>>   static void __init acpi_iort_register_irq(int hwirq, const char *name,
>>                         int trigger,
>>                         struct resource *res)
>> @@ -807,7 +867,7 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>           return NULL;
>>       }
>>   }
>> -
>> +#endif
>>   /**
>>    * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
>>    * @node: Pointer to SMMU ACPI IORT node
>> @@ -817,78 +877,42 @@ const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
>>   static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
>>   {
>>       struct fwnode_handle *fwnode;
>> -    struct platform_device *pdev;
>> -    struct resource *r;
>> -    enum dev_dma_attr attr;
>> -    int ret, count;
>> -    const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
>> -
>> -    if (!ops)
>> -        return -ENODEV;
>> -
>> -    pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
>> -    if (!pdev)
>> -        return -ENOMEM;
>> -
>> -    count = ops->iommu_count_resources(node);
>> -
>> -    r = kcalloc(count, sizeof(*r), GFP_KERNEL);
>> -    if (!r) {
>> -        ret = -ENOMEM;
>> -        goto dev_put;
>> -    }
>> -
>> -    ops->iommu_init_resources(r, node);
>> +    struct device *dev;
>> +    int ret;
>>   -    ret = platform_device_add_resources(pdev, r, count);
>>       /*
>> -     * Resources are duplicated in platform_device_add_resources,
>> -     * free their allocated memory
>> +     * Not enabling the parsing ops for now. The corresponding driver
>> +     * can parse this information as needed, so deleting relevant code as
>> +     * compared to base revision.
>>        */
>> -    kfree(r);
>>   -    if (ret)
>> -        goto dev_put;
>> +    dev = kzalloc(sizeof(struct device), GFP_KERNEL);
>> +    if (!dev)
>> +        return -ENOMEM;
>>         /*
>>        * Add a copy of IORT node pointer to platform_data to
>>        * be used to retrieve IORT data information.
>>        */
>> -    ret = platform_device_add_data(pdev, &node, sizeof(node));
>> -    if (ret)
>> -        goto dev_put;
>> -
>> -    /*
>> -     * We expect the dma masks to be equivalent for
>> -     * all SMMUs set-ups
>> -     */
>> -    pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
>> +    dev->type = DEV_ACPI;
>> +    dev->acpi_node = node;
>>         fwnode = iort_get_fwnode(node);
>>         if (!fwnode) {
>>           ret = -ENODEV;
>> -        goto dev_put;
>> +        goto error;
>>       }
>>   -    pdev->dev.fwnode = fwnode;
>> -
>> -    attr = ops->iommu_is_coherent(node) ?
>> -                 DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
>> -
>> -    /* Configure DMA for the page table walker */
>> -    acpi_dma_configure(&pdev->dev, attr);
>> +    dev->fwnode = fwnode;
>>   -    ret = platform_device_add(pdev);
>> -    if (ret)
>> -        goto dma_deconfigure;
>> +    /* Call the acpi init functions for IOMMU devices */
>> +    ret = acpi_device_init(DEVICE_IOMMU, (void *)dev, node->type);
>>         return 0;
>>   -dma_deconfigure:
>> -    acpi_dma_deconfigure(&pdev->dev);
>> -dev_put:
>> -    platform_device_put(pdev);
>> +error:
>> +    kfree(dev);
>>         return ret;
>>   }
>> @@ -957,5 +981,6 @@ void __init acpi_iort_init(void)
>>         iort_init_platform_devices();
>>   -    acpi_probe_device_table(iort);
>> +    /* Xen; Do not need a device table probe */
>> +    /* acpi_probe_device_table(iort);*/
>>   }
>> diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
>> index 362d578..ad956d5 100644
>> --- a/xen/drivers/passthrough/arm/smmu.c
>> +++ b/xen/drivers/passthrough/arm/smmu.c
>> @@ -181,6 +181,7 @@ static void __iomem *devm_ioremap_resource(struct device *dev,
>>    * Xen: PCI functions
>>    * TODO: It should be implemented when PCI will be supported
>>    */
>> +#undef to_pci_dev
>>   #define to_pci_dev(dev)    (NULL)
>>   static inline int pci_for_each_dma_alias(struct pci_dev *pdev,
>>                        int (*fn) (struct pci_dev *pdev,
>> diff --git a/xen/include/acpi/acpi_iort.h b/xen/include/acpi/acpi_iort.h
>> index 77e0809..d4315a4 100644
>> --- a/xen/include/acpi/acpi_iort.h
>> +++ b/xen/include/acpi/acpi_iort.h
>> @@ -19,27 +19,32 @@
>>   #ifndef __ACPI_IORT_H__
>>   #define __ACPI_IORT_H__
>>   -#include <linux/acpi.h>
>> -#include <linux/fwnode.h>
>> -#include <linux/irqdomain.h>
>> +#include <xen/acpi.h>
>> +#include <asm/device.h>
>>   +/* Xen: Not using IORT IRQ bindings */
>> +#if 0
>>   #define IORT_IRQ_MASK(irq)        (irq & 0xffffffffULL)
>>   #define IORT_IRQ_TRIGGER_MASK(irq)    ((irq >> 32) & 0xffffffffULL)
>>     int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
>>   void iort_deregister_domain_token(int trans_id);
>>   struct fwnode_handle *iort_find_domain_token(int trans_id);
>> -#ifdef CONFIG_ACPI_IORT
>> +#endif
>> +#ifdef CONFIG_ARM_64
>>   void acpi_iort_init(void);
>>   bool iort_node_match(u8 type);
>> +#if 0
>>   u32 iort_msi_map_rid(struct device *dev, u32 req_id);
>>   struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
>>   /* IOMMU interface */
>>   void iort_set_dma_mask(struct device *dev);
>> +#endif
>>   const struct iommu_ops *iort_iommu_configure(struct device *dev);
>>   #else
>>   static inline void acpi_iort_init(void) { }
>>   static inline bool iort_node_match(u8 type) { return false; }
>> +#if 0
>>   static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
>>   { return req_id; }
>>   static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>> @@ -47,12 +52,10 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
>>   { return NULL; }
>>   /* IOMMU interface */
>>   static inline void iort_set_dma_mask(struct device *dev) { }
>> +#endif
>>   static inline
>>   const struct iommu_ops *iort_iommu_configure(struct device *dev)
>>   { return NULL; }
>>   #endif
>>   -#define IORT_ACPI_DECLARE(name, table_id, fn)        \
>> -    ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
>> -
>>   #endif /* __ACPI_IORT_H__ */
>> diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
>> index 5027c87..4eef9ce 100644
>> --- a/xen/include/asm-arm/device.h
>> +++ b/xen/include/asm-arm/device.h
>> @@ -7,6 +7,7 @@
>>   enum device_type
>>   {
>>       DEV_DT,
>> +    DEV_ACPI,
>>   };
>>     struct dev_archdata {
>> @@ -20,6 +21,7 @@ struct device
>>   #ifdef CONFIG_HAS_DEVICE_TREE
>>       struct dt_device_node *of_node; /* Used by drivers imported from Linux */
>>   #endif
>> +    void *acpi_node; /*Current use case is acpi_iort_node */
>>       struct fwnode_handle *fwnode; /*fw device node identifier */
>>       struct iommu_fwspec *iommu_fwspec;
>>       struct dev_archdata archdata;
>> diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
>> index 9409350..2f6aae1 100644
>> --- a/xen/include/xen/acpi.h
>> +++ b/xen/include/xen/acpi.h
>> @@ -32,6 +32,7 @@
>>     #include <acpi/acpi.h>
>>   #include <asm/acpi.h>
>> +#include <xen/fwnode.h>
>>     #define ACPI_MADT_GET_(fld, x) (((x) & ACPI_MADT_##fld##_MASK) / \
>>       (ACPI_MADT_##fld##_MASK & -ACPI_MADT_##fld##_MASK))
>> @@ -49,6 +50,26 @@
>>                   (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
>>                   (entry)->header.length < sizeof(*(entry)))
>>   +static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
>> +{
>> +    struct fwnode_handle *fwnode;
>> +
>> +    fwnode = xzalloc(struct fwnode_handle);
>> +    if (!fwnode)
>> +        return NULL;
>> +
>> +    fwnode->type = FWNODE_ACPI_STATIC;
>> +
>> +    return fwnode;
>> +}
>> +
>> +static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
>> +{
>> +    if (!fwnode || fwnode->type != FWNODE_ACPI_STATIC)
>> +        return;
>> +
>> +    xfree(fwnode);
>> +}
>>   #ifdef CONFIG_ACPI
>>     enum acpi_interrupt_id {
>> diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
>> index 43f2125..182b1a5 100644
>> --- a/xen/include/xen/pci.h
>> +++ b/xen/include/xen/pci.h
>> @@ -92,8 +92,16 @@ struct pci_dev {
>>   #define PT_FAULT_THRESHOLD 10
>>       } fault;
>>       u64 vf_rlen[6];
>> +#ifdef CONFIG_ARM
>> +    struct device dev;
>> +#endif
>>   };
>>   +#ifdef CONFIG_ARM
>> +#define to_pci_dev(p) container_of(p, struct pci_dev,dev)
>> +#define pci_domain_nr(dev) dev->seg
>> +#endif
>> +
>>   #define for_each_pdev(domain, pdev) \
>>       list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
>>   
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table
  2017-11-15  1:27     ` Goel, Sameer
@ 2017-11-15  8:58       ` Julien Grall
  0 siblings, 0 replies; 34+ messages in thread
From: Julien Grall @ 2017-11-15  8:58 UTC (permalink / raw)
  To: Goel, Sameer, Manish Jaggi, xen-devel, julien.grall
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 11/15/2017 01:27 AM, Goel, Sameer wrote:
> 
> 
> On 11/8/2017 7:41 AM, Manish Jaggi wrote:
>> Hi Sameer
>>
>> On 9/21/2017 6:07 AM, Sameer Goel wrote:
>>> Add support for parsing IORT table to initialize SMMU devices.
>>> * The code for creating an SMMU device has been modified, so that the SMMU
>>> device can be initialized.
>>> * The NAMED NODE code has been commented out as this will need DOM0 kernel
>>> support.
>>> * ITS code has been included but it has not been tested.
>>>
>>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>> Followup of the discussions we had on iort parsing and querying streamID and deviceId based on RID.
>> I have extended your patchset with a patch that provides an alternative
>> way of parsing iort into maps : {rid-streamid}, {rid-deviceID)
>> which can directly be looked up for searching streamId for a rid. This
>> will remove the need to traverse iort table again.
>>
>> The test patch just describes the proposed flow and how the parsing and
>> query code might fit in. I have not tested it.
>> The code only compiles.
>>
>> https://github.com/mjaggi-cavium/xen-wip/commit/df006d64bdbb5c8344de5a710da8bf64c9e8edd5
>> (This repo has all 7 of your patches + test code patch merged.
>>
>> Note: The commit text of the patch describes the basic flow /assumptions / usage of functions.
>> Please see the code along with the v2 design draft.
>> [RFC] [Draft Design v2] ACPI/IORT Support in Xen.
>> https://lists.xen.org/archives/html/xen-devel/2017-11/msg00512.html
>>
>> I seek your advice on this. Please provide your feedback.
> I responded back on the other thread. I think we are fixing something that is not broken. I will try to post a couple of new RFCs and let's discuss this with incremental changes on the mailing list.

That other thread was a separate mailing list. For the benefits of the 
rest of the community it would be nice if you can post the summary here.

However, nobody said the code was broken. IORT will be used in various 
place in Xen and Manish is looking whether we can parse only once and 
for all the IORT. I think it is latest design is promising for that.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-10-12 16:36   ` Julien Grall
@ 2017-11-19  7:45     ` Goel, Sameer
  2017-11-20 14:25       ` Julien Grall
  0 siblings, 1 reply; 34+ messages in thread
From: Goel, Sameer @ 2017-11-19  7:45 UTC (permalink / raw)
  To: Julien Grall, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 10/12/2017 10:36 AM, Julien Grall wrote:
> Hi Sameer,
> 
> Given this is all Arm specific. I am not sure why people like Andrew, Jan have been added.
> 
> Please use scripts/get_maintainers to find the list of maintainers per patches and avoid to CC all of them on each patches.
Ok.

> 
> On 21/09/17 01:37, 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 */
>>
>> Signed-off-by: Sameer Goel <sgoel@codeaurora.org>
>> ---
>>   xen/drivers/passthrough/arm/Makefile  |   1 +
>>   xen/drivers/passthrough/arm/smmu-v3.c | 853 +++++++++++++++++++++++++++++-----
> 
> This is based on an old SMMUv3 version and I have been told there are some changes may benefits Xen (such as increasing the timeout for sync) and some optimisations also exist on the ML and will be queued soon.
> 
> So maybe you want to re-sync at least to master.
> 
>>   2 files changed, 738 insertions(+), 116 deletions(-)
>>
>> diff --git a/xen/drivers/passthrough/arm/Makefile b/xen/drivers/passthrough/arm/Makefile
>> index f4cd26e..57a6da6 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-y += smmu-v3.o
> 
> Do we want SMMUv3 to be built on Arm32? Maybe we should introduce a new Kconfig to let the user select.
Agreed. I will define a CONFIG_ARM_SMMU_V3.

> 
>> diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
>> index 380969a..8f3b43d 100644
>> --- a/xen/drivers/passthrough/arm/smmu-v3.c
>> +++ b/xen/drivers/passthrough/arm/smmu-v3.c
>> @@ -18,28 +18,266 @@
>>    * Author: Will Deacon <will.deacon@arm.com>
>>    *
>>    * This driver is powered by bad coffee and bombay mix.
>> + *
>> + *
>> + * Based on Linux drivers/iommu/arm-smmu-v3.c
>> + * => commit bdf95923086fb359ccb44c815724c3ace1611c90
>> + *
>> + * Xen modifications:
>> + * Sameer Goel <sgoel@codeaurora.org>
>> + * Copyright (C) 2017, The Linux Foundation, All rights reserved.
>> + *
>>    */
>>   -#include <linux/acpi.h>
>> -#include <linux/acpi_iort.h>
>> -#include <linux/delay.h>
>> -#include <linux/dma-iommu.h>
>> -#include <linux/err.h>
>> -#include <linux/interrupt.h>
>> -#include <linux/iommu.h>
>> -#include <linux/iopoll.h>
>> -#include <linux/module.h>
>> -#include <linux/msi.h>
>> -#include <linux/of.h>
>> -#include <linux/of_address.h>
>> -#include <linux/of_iommu.h>
>> -#include <linux/of_platform.h>
>> -#include <linux/pci.h>
>> -#include <linux/platform_device.h>
>> -
>> -#include <linux/amba/bus.h>
>> -
>> -#include "io-pgtable.h"
>> +#include <xen/config.h>
> 
> This is not necessary.
> 
>> +#include <xen/delay.h>
>> +#include <xen/errno.h>
>> +#include <xen/err.h>
>> +#include <xen/irq.h>
>> +#include <xen/lib.h>
>> +#include <xen/list.h>
>> +#include <xen/mm.h>
>> +#include <xen/vmap.h>
>> +#include <xen/rbtree.h>
>> +#include <xen/sched.h>
>> +#include <xen/sizes.h>
>> +#include <asm/atomic.h>
>> +#include <asm/device.h>
>> +#include <asm/io.h>
>> +#include <asm/platform.h>
>> +#include <xen/acpi.h>
> 
> Please order the includes alphabetically with xen/* first then asm/*

Done.
> 
>> +
>> +typedef paddr_t phys_addr_t;
>> +typedef paddr_t dma_addr_t;
>> +
>> +/* Alias to Xen device tree helpers */
>> +#define device_node dt_device_node
>> +#define of_phandle_args dt_phandle_args
>> +#define of_device_id dt_device_match
>> +#define of_match_node dt_match_node
>> +#define of_property_read_u32(np, pname, out) (!dt_property_read_u32(np, pname, out))
>> +#define of_property_read_bool dt_property_read_bool
>> +#define of_parse_phandle_with_args dt_parse_phandle_with_args
>> +#define mutex spinlock_t
>> +#define mutex_init spin_lock_init
>> +#define mutex_lock spin_lock
>> +#define mutex_unlock spin_unlock
> 
> mutex and spinlock are not the same. The former is sleeping whilst the later is not.
> 
> Can you please explain why this is fine and possibly add that in a comment?
> 
Mutex is used to protect the access to smmu device internal data structure when setting up the s2 config and installing stes for a given device in Linux. The ste programming  operation can be competitively long but in the current testing, I did not see this blocking for too long. I will put in a comment. 

>> +
>> +/* Xen: Helpers to get device MMIO and IRQs */
>> +struct resource {
>> +    u64 addr;
>> +    u64 size;
>> +    unsigned int type;
>> +};
> 
> Likely we want a compat header for defining Linux helpers. This would avoid replicating it everywhere.
Agreed.

> 
>> +
>> +#define resource_size(res) ((res)->size)
>> +
>> +#define platform_device device
>> +
>> +#define IORESOURCE_MEM 0
>> +#define IORESOURCE_IRQ 1
>> +
>> +static struct resource *platform_get_resource(struct platform_device *pdev,
>> +                          unsigned int type,
>> +                          unsigned int num)
>> +{
>> +    /*
>> +     * The resource is only used between 2 calls of platform_get_resource.
>> +     * It's quite ugly but it's avoid to add too much code in the part
>> +     * imported from Linux
>> +     */
>> +    static struct resource res;
>> +    struct acpi_iort_node *iort_node;
>> +    struct acpi_iort_smmu_v3 *node_smmu_data;
>> +    int ret = 0;
>> +
>> +    res.type = type;
>> +
>> +    switch (type) {
>> +    case IORESOURCE_MEM:
>> +        if (pdev->type == DEV_ACPI) {
>> +            ret = 1;
>> +            iort_node = pdev->acpi_node;
>> +            node_smmu_data =
>> +                (struct acpi_iort_smmu_v3 *)iort_node->node_data;
>> +
>> +            if (node_smmu_data != NULL) {
>> +                res.addr = node_smmu_data->base_address;
>> +                res.size = SZ_128K;
>> +                ret = 0;
>> +            }
>> +        } else {
>> +            ret = dt_device_get_address(dev_to_dt(pdev), num,
>> +                            &res.addr, &res.size);
>> +        }
>> +
>> +        return ((ret) ? NULL : &res);
>> +
>> +    case IORESOURCE_IRQ:
>> +        ret = platform_get_irq(dev_to_dt(pdev), num);
> 
> No IRQ for ACPI?
For IRQs the code calls platform_get_irq_byname. So, the IORESOURCE_IRQ implementation is not needed at all. (DT or ACPI)
> 
>> +
>> +        if (ret < 0)
>> +            return NULL;
>> +
>> +        res.addr = ret;
>> +        res.size = 1;
>> +
>> +        return &res;
>> +
>> +    default:
>> +        return NULL;
>> +    }
>> +}
>> +
>> +static int platform_get_irq_byname(struct platform_device *pdev, const char *name)
>> +{
>> +    const struct dt_property *dtprop;
>> +    struct acpi_iort_node *iort_node;
>> +    struct acpi_iort_smmu_v3 *node_smmu_data;
>> +    int ret = 0;
>> +
>> +    if (pdev->type == DEV_ACPI) {
>> +        iort_node = pdev->acpi_node;
>> +        node_smmu_data = (struct acpi_iort_smmu_v3 *)iort_node->node_data;
>> +
>> +        if (node_smmu_data != NULL) {
>> +            if (!strcmp(name, "eventq"))
>> +                ret = node_smmu_data->event_gsiv;
>> +            else if (!strcmp(name, "priq"))
>> +                ret = node_smmu_data->pri_gsiv;
>> +            else if (!strcmp(name, "cmdq-sync"))
>> +                ret = node_smmu_data->sync_gsiv;
>> +            else if (!strcmp(name, "gerror"))
>> +                ret = node_smmu_data->gerr_gsiv;
>> +            else
>> +                ret = -EINVAL;
>> +        }
>> +    } else {
>> +        dtprop = dt_find_property(dev_to_dt(pdev), "interrupt-names", NULL);
>> +        if (!dtprop)
>> +            return -EINVAL;
>> +
>> +        if (!dtprop->value)
>> +            return -ENODATA;
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \
>> +({ \
>> +    s_time_t deadline = NOW() + MICROSECS(timeout_us); \
>> +    for (;;) { \
>> +        (val) = op(addr); \
>> +        if (cond) \
>> +            break; \
>> +        if (NOW() > deadline) { \
>> +            (val) = op(addr); \
>> +            break; \
>> +        } \
>> +        cpu_relax(); \
> 
> I don't think calling cpu_relax() is correct here.
I will remove cpu_relax() from here. It should not be needed.
> 
>> +        udelay(sleep_us); \
>> +    } \
>> +    (cond) ? 0 : -ETIMEDOUT; \
>> +})
>> +
>> +#define readl_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
>> +    readx_poll_timeout(readl_relaxed, addr, val, cond, delay_us, timeout_us)
>> +
>> +/* Xen: Helpers for IRQ functions */
>> +#define request_irq(irq, func, flags, name, dev) request_irq(irq, flags, func, name, dev)
>> +#define free_irq release_irq
>> +
>> +enum irqreturn {
>> +    IRQ_NONE    = (0 << 0),
>> +    IRQ_HANDLED    = (1 << 0),
>> +};
>> +
>> +typedef enum irqreturn irqreturn_t;
>> +
>> +/* Device logger functions */
>> +#define dev_print(dev, lvl, fmt, ...)                        \
>> +     printk(lvl "smmu: " fmt, ## __VA_ARGS__)
>> +
>> +#define dev_dbg(dev, fmt, ...) dev_print(dev, XENLOG_DEBUG, fmt, ## __VA_ARGS__)
>> +#define dev_notice(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
>> +#define dev_warn(dev, fmt, ...) dev_print(dev, XENLOG_WARNING, fmt, ## __VA_ARGS__)
>> +#define dev_err(dev, fmt, ...) dev_print(dev, XENLOG_ERR, fmt, ## __VA_ARGS__)
>> +#define dev_info(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
>> +
>> +#define dev_err_ratelimited(dev, fmt, ...)                    \
>> +     dev_print(dev, 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)        _xmalloc(size, sizeof(void *))
>> +#define kzalloc(size, flags)        _xzalloc(size, sizeof(void *))
>> +#define devm_kzalloc(dev, size, flags)    _xzalloc(size, sizeof(void *))
>> +#define kmalloc_array(size, n, flags)    _xmalloc_array(size, sizeof(void *), n)
>> +
>> +/* Compatibility defines */
>> +#undef WARN_ON
>> +#define WARN_ON(cond) (!!cond)
> 
> Why do you redefine WARN_ON?Need it to be a scalar value. The Xen implementation is a do..while. Did not want a large impact hence the local define. I can try proposing a new common define.
> 
>> +#define WARN_ON_ONCE(cond) WARN_ON(cond)
>> Hmmm, can't we implement a common WARN_ON_ONCE?
Will not really be executed. Defining it to maintain compatibility. I think this file is the right place for this define. We can send it to a generic file if so needed.
> 
>> +
>> +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: Dummy iommu_domain */
>> +struct iommu_domain {
>> +    /* Runtime SMMU configuration for this iommu_domain */
>> +    struct arm_smmu_domain        *priv;
>> +    unsigned int            type;
>> +
>> +    atomic_t ref;
>> +    /* Used to link iommu_domain contexts for a same domain.
>> +     * There is at least one per-SMMU to used by the domain.
>> +     */
>> +    struct list_head        list;
>> +};
> 
> This is very similar to the SMMU version. Could we share some bits?
I will propose a common header for arm-smmu files.
> 
>> +/* Xen: Domain type definitions. Not really needed for Xen, defining to port
>> + * Linux code as-is
>> + */
>> +#define IOMMU_DOMAIN_UNMANAGED 0
>> +#define IOMMU_DOMAIN_DMA 1
>> +#define IOMMU_DOMAIN_IDENTITY 2
>> +
>> +/* Xen: Describes information required for a Xen domain */
>> +struct arm_smmu_xen_domain {
>> +    spinlock_t            lock;
>> +    /* List of iommu domains associated to this domain */
>> +    struct list_head        iommu_domains;
>> +};
> 
> Ditoo.
> 
>> +
>> +/*
>> + * Xen: Information about each device stored in dev->archdata.iommu
>> + *
>> + * The dev->archdata.iommu stores the iommu_domain (runtime configuration of
>> + * the SMMU).
>> + */
>> +struct arm_smmu_xen_device {
>> +    struct iommu_domain *domain;
>> +};
> 
> Ditto.
> 
>>     /* MMIO registers */
>>   #define ARM_SMMU_IDR0            0x0
>> @@ -412,10 +650,12 @@
>>   #define MSI_IOVA_BASE            0x8000000
>>   #define MSI_IOVA_LENGTH            0x100000
>>   +#if 0 /* Not applicable for Xen */
> 
> While the module_param_name() is not applicable in Xen, I don't see any reason to remove the variable.

Agreed.
> 
>>   static bool disable_bypass; >   module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO);
>>   MODULE_PARM_DESC(disable_bypass,
>>       "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
>> +#endif
>>     enum pri_resp {
>>       PRI_RESP_DENY,
>> @@ -423,6 +663,7 @@ enum pri_resp {
>>       PRI_RESP_SUCC,
>>   };
>>   +#if 0 /* Xen: No MSI support in this iteration */
>>   enum arm_smmu_msi_index {
>>       EVTQ_MSI_INDEX,
>>       GERROR_MSI_INDEX,
>> @@ -447,6 +688,7 @@ static phys_addr_t arm_smmu_msi_cfg[ARM_SMMU_MAX_MSIS][3] = {
>>           ARM_SMMU_PRIQ_IRQ_CFG2,
>>       },
>>   };
>> +#endif
>>     struct arm_smmu_cmdq_ent {
>>       /* Common fields */
>> @@ -551,6 +793,8 @@ struct arm_smmu_s2_cfg {
>>       u16                vmid;
>>       u64                vttbr;
>>       u64                vtcr;
>> +    /* Xen: Domain associated to this configuration */
>> +    struct domain            *domain;
>>   };
>>     struct arm_smmu_strtab_ent {
>> @@ -623,9 +867,20 @@ struct arm_smmu_device {
>>       struct arm_smmu_strtab_cfg    strtab_cfg;
>>         /* IOMMU core code handle */
>> -    struct iommu_device        iommu;
>> +    //struct iommu_device        iommu;
> 
> #if 0 but no // please.
Done.

> 
>> +
>> +    /* Xen: Need to keep a list of SMMU devices */
>> +    struct list_head                devices;
>>   };
>>   +/* Xen: Keep a list of devices associated with this driver */
>> +static DEFINE_SPINLOCK(arm_smmu_devices_lock);
>> +static LIST_HEAD(arm_smmu_devices);
>> +/* Xen: Helper for finding a device using fwnode */
>> +static
>> +struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode);
>> +
>> +
>>   /* SMMU private data for each master */
>>   struct arm_smmu_master_data {
>>       struct arm_smmu_device        *smmu;
>> @@ -642,7 +897,7 @@ enum arm_smmu_domain_stage {
>>     struct arm_smmu_domain {
>>       struct arm_smmu_device        *smmu;
>> -    struct mutex            init_mutex; /* Protects smmu pointer */
>> +    mutex            init_mutex; /* Protects smmu pointer */
>>         struct io_pgtable_ops        *pgtbl_ops;
>>       spinlock_t            pgtbl_lock;
>> @@ -737,15 +992,16 @@ static void queue_inc_prod(struct arm_smmu_queue *q)
>>    */
>>   static int queue_poll_cons(struct arm_smmu_queue *q, bool drain, bool wfe)
>>   {
>> -    ktime_t timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US);
>> +    s_time_t deadline = NOW() + MICROSECS(ARM_SMMU_POLL_TIMEOUT_US);
> 
> Please introduce proper wrappers to avoid the modification of the code.
Done.

> 
>>         while (queue_sync_cons(q), (drain ? !queue_empty(q) : queue_full(q))) {
>> -        if (ktime_compare(ktime_get(), timeout) > 0)
>> +
>> +        if (NOW() > deadline)
> 
> Ditto.
Done.

> 
>>               return -ETIMEDOUT;
>>   -        if (wfe) {
>> +        if (wfe)
> 
> Please avoid to drop {
> 
>>               wfe();
>> -        } else {
> 
> Ditto.
Done.

> 
>> +        else {
>>               cpu_relax();
> 
> Hmmm I now see why you added cpu_relax() at the top. Well, on Xen cpu_relax is just a barrier. On Linux it is used to yield.
> 
> And that bit is worrying me. The Linux code will allow context switching to another tasks if the code is taking too much time.
> 
> Xen is not preemptible, so is it fine?
This is used when consuming the command queue and could be a potential performance issue if the queue is large. (This is never the case).
I am wondering if we should define a yeild in long run? 

> 
>>               udelay(1);
>>           }
>> @@ -931,7 +1187,7 @@ static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
>>           dev_err_ratelimited(smmu->dev, "CMD_SYNC timeout\n");
>>       spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
>>   }
>> -
>> +#if 0
> 
> Please avoid dropping newline and explain why the #if 0.
Done.

> 
>>   /* Context descriptor manipulation functions */
>>   static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr)
>>   {
>> @@ -974,7 +1230,7 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
>>         cfg->cdptr[3] = cpu_to_le64(cfg->cd.mair << CTXDESC_CD_3_MAIR_SHIFT);
>>   }
>> -
>> +#endif
> 
> Ditto for the newline.
Done.

> 
>>   /* Stream table manipulation functions */
>>   static void
>>   arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
>> @@ -1044,7 +1300,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
>>               ste_live = true;
>>               break;
>>           case STRTAB_STE_0_CFG_ABORT:
>> -            if (disable_bypass)
>> +            //No bypass override for Xen
> 
> Why no leaving the variable on top with a comment. This would avoid such change.
Done.

> 
>>                   break;
>>           default:
>>               BUG(); /* STE corruption */
>> @@ -1056,7 +1312,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
>>         /* Bypass/fault */
>>       if (!ste->assigned || !(ste->s1_cfg || ste->s2_cfg)) {
>> -        if (!ste->assigned && disable_bypass)
>> +        if (!ste->assigned)
> 
> Ditto.
Done.

> 
>>               val |= STRTAB_STE_0_CFG_ABORT;
>>           else
>>               val |= STRTAB_STE_0_CFG_BYPASS;
>> @@ -1135,16 +1391,20 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>>       void *strtab;
>>       struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>>       struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
>> +    u32 alignment = 0;
>>         if (desc->l2ptr)
>>           return 0;
>>   -    size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>> +    size = 1 << (STRTAB_SPLIT + LOG_2(STRTAB_STE_DWORDS) + 3);
> 
> I would prefer if you introduce ilog2.
Done.

> 
>>       strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>>         desc->span = STRTAB_SPLIT + 1;
>> -    desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
>> -                      GFP_KERNEL | __GFP_ZERO);
>> +
>> +    alignment = 1 << ((5 + (desc->span - 1)));
> 
> Do you mind explaining the 5? Also, does the shift will always be < 32?
Its from the "Level 1 Stream Table Descriptor" from SMMU spec. I can add the ref to the spec. Yes the span is hard coded in the driver and with any spec valid span values this cannot exceed 32.
I have added a comment tot he code
> 
>> +    desc->l2ptr = _xzalloc(size, alignment);
>> +    desc->l2ptr_dma = virt_to_maddr(desc->l2ptr);
> 
> _xzalloc can fail and virt_to_maddr will result to a panic.
> 
I will move the check.
>> +
>>       if (!desc->l2ptr) {
>>           dev_err(smmu->dev,
>>               "failed to allocate l2 stream table for SID %u\n",
>> @@ -1158,7 +1418,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>>   }
>>     /* IRQ and event handlers */
>> -static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>> +static void arm_smmu_evtq_thread(int irq, void *dev, struct cpu_user_regs *regs)
> 
> Could you please introduce a wrapper instead as it was done in smmu.c?
> 
Done.

>>   {
>>       int i;
>>       struct arm_smmu_device *smmu = dev;
>> @@ -1186,7 +1446,6 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>         /* Sync our overflow flag, as we believe we're up to speed */
>>       q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
>> -    return IRQ_HANDLED;
>>   }
>>     static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
>> @@ -1203,7 +1462,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 0x%016lx\n",
> 
> Hmmm why?
The variable is defined as ungined long long in Linux. ( uses generic int-ll64.h) In Xen the definition changes to unsigned long for ARM_64 which actually makes sense. 
> 
>>            sid, ssid, grpid, last ? "L" : "",
>>            evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
>>            evt[0] & PRIQ_0_PERM_READ ? "R" : "",
>> @@ -1227,7 +1486,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
>>       }
>>   }
>>   -static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
>> +static void arm_smmu_priq_thread(int irq, void *dev, struct cpu_user_regs *regs)
> 
> Ditto about the prototype.
Done.
> 
>>   {
>>       struct arm_smmu_device *smmu = dev;
>>       struct arm_smmu_queue *q = &smmu->priq.q;
>> @@ -1243,18 +1502,16 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
>>         /* Sync our overflow flag, as we believe we're up to speed */
>>       q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
>> -    return IRQ_HANDLED;
>>   }
>>   -static irqreturn_t arm_smmu_cmdq_sync_handler(int irq, void *dev)
>> +static void arm_smmu_cmdq_sync_handler(int irq, void *dev, struct cpu_user_regs *regs)
> 
> Ditto.
Done.

> 
>>   {
>>       /* We don't actually use CMD_SYNC interrupts for anything */
>> -    return IRQ_HANDLED;
>>   }
>>     static int arm_smmu_device_disable(struct arm_smmu_device *smmu);
>>   -static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>> +static void arm_smmu_gerror_handler(int irq, void *dev, struct cpu_user_regs *regs)
> 
> Ditto
Done.

> 
>>   {
>>       u32 gerror, gerrorn, active;
>>       struct arm_smmu_device *smmu = dev;
>> @@ -1264,7 +1521,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>>         active = gerror ^ gerrorn;
>>       if (!(active & GERROR_ERR_MASK))
>> -        return IRQ_NONE; /* No errors pending */
>> +        return; /* No errors pending */
>>         dev_warn(smmu->dev,
>>            "unexpected global error reported (0x%08x), this could be serious\n",
>> @@ -1286,7 +1543,7 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>>         if (active & GERROR_MSI_CMDQ_ABT_ERR) {
>>           dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
>> -        arm_smmu_cmdq_sync_handler(irq, smmu->dev);
>> +        arm_smmu_cmdq_sync_handler(irq, smmu->dev, NULL);
>>       }
>>         if (active & GERROR_PRIQ_ABT_ERR)
>> @@ -1299,7 +1556,6 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
>>           arm_smmu_cmdq_skip_err(smmu);
>>         writel(gerror, smmu->base + ARM_SMMU_GERRORN);
>> -    return IRQ_HANDLED;
>>   }
>>     /* IO_PGTABLE API */
>> @@ -1311,11 +1567,13 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
>>       arm_smmu_cmdq_issue_cmd(smmu, &cmd);
>>   }
>>   +#if 0 /*Xen: Unused function */
>>   static void arm_smmu_tlb_sync(void *cookie)
>>   {
>>       struct arm_smmu_domain *smmu_domain = cookie;
>>       __arm_smmu_tlb_sync(smmu_domain->smmu);
>>   }
>> +#endif
>>     static void arm_smmu_tlb_inv_context(void *cookie)
>>   {
>> @@ -1336,6 +1594,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
>>       __arm_smmu_tlb_sync(smmu);
>>   }
>>   +#if 0 /*Xen: Unused functionality */
>>   static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
>>                         size_t granule, bool leaf, void *cookie)
>>   {
>> @@ -1362,7 +1621,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
>>       } while (size -= granule);
>>   }
>>   -static const struct iommu_gather_ops arm_smmu_gather_ops = {
>> +static struct iommu_gather_ops arm_smmu_gather_ops = {
>>       .tlb_flush_all    = arm_smmu_tlb_inv_context,
>>       .tlb_add_flush    = arm_smmu_tlb_inv_range_nosync,
>>       .tlb_sync    = arm_smmu_tlb_sync,
>> @@ -1380,6 +1639,11 @@ static bool arm_smmu_capable(enum iommu_cap cap)
>>           return false;
>>       }
>>   }
>> +#endif
>> +/* Xen: Stub out DMA domain related functions */
>> +#define iommu_get_dma_cookie(dom) 0
>> +#define iommu_put_dma_cookie(dom) 0
> 
> Please stub them at the top of the file.
Done.

> 
>> +
>>     static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>>   {
>> @@ -1410,6 +1674,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>>       return &smmu_domain->domain;
>>   }
>>   +#if 0
> 
> Please explain the #if 0
> 
Done.

>>   static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
>>   {
>>       int idx, size = 1 << span;
>> @@ -1427,36 +1692,20 @@ static void arm_smmu_bitmap_free(unsigned long *map, int idx)
>>   {
>>       clear_bit(idx, map);
>>   }
>> +#endif
>>     static void arm_smmu_domain_free(struct iommu_domain *domain)
>>   {
>>       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>> -    struct arm_smmu_device *smmu = smmu_domain->smmu;
>> -
>> -    iommu_put_dma_cookie(domain);
>> -    free_io_pgtable_ops(smmu_domain->pgtbl_ops);
>> -
>> -    /* Free the CD and ASID, if we allocated them */
>> -    if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>> -        struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>> -
>> -        if (cfg->cdptr) {
>> -            dmam_free_coherent(smmu_domain->smmu->dev,
>> -                       CTXDESC_CD_DWORDS << 3,
>> -                       cfg->cdptr,
>> -                       cfg->cdptr_dma);
>> -
>> -            arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
>> -        }
>> -    } else {
>> -        struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>> -        if (cfg->vmid)
>> -            arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
>> -    }
>> +    /*
>> +     * Xen: Remove the free functions that are not used and code related
>> +     * to S1 translation. We just need to free the domain here.
>> +     */
> 
> Please use #if 0 rather than removing the code + comment on top. But I am not sure why you drop the S2 free code. Shouldn't we allocate VMID from the SMMU?
I am picking up the vmid from the domain I am sharing the page tables with. domain->arch.p2m.vmid. This seemed valid. Please let me know if we want to generate a different vmid?


> 
>>         kfree(smmu_domain);
>>   }
>>   +#if 0
>>   static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
>>                          struct io_pgtable_cfg *pgtbl_cfg)
>>   {
>> @@ -1488,33 +1737,30 @@ out_free_asid:
>>       arm_smmu_bitmap_free(smmu->asid_map, asid);
>>       return ret;
>>   }
>> +#endif
>>   -static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
>> -                       struct io_pgtable_cfg *pgtbl_cfg)
>> +static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain)
>>   {
>> -    int vmid;
>> -    struct arm_smmu_device *smmu = smmu_domain->smmu;
>>       struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>>   -    vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
>> -    if (vmid < 0)
>> -        return vmid;
>> +    /* Xen: Set the values as needed */
>>   -    cfg->vmid    = (u16)vmid;
>> -    cfg->vttbr    = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
>> -    cfg->vtcr    = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
>> +    cfg->vmid    = cfg->domain->arch.p2m.vmid;
> 
> See my comment above.
I am wondering why we are considering this value invalid? Since the page tables are shared we can use the vmid from the domain. Is the concern regarding the size?

Thanks,
Sameer
> 
>> +    cfg->vttbr    = page_to_maddr(cfg->domain->arch.p2m.root);
>> +    cfg->vtcr    = READ_SYSREG32(VTCR_EL2);
> 
> This looks a bit suspicious. Looking at the specs, the bits does not seem to correspond here.
> 
> I will look at the rest either tomorrow or Monday.
> 
> Cheers,
> 

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-11-19  7:45     ` Goel, Sameer
@ 2017-11-20 14:25       ` Julien Grall
  2017-11-20 15:19         ` Robin Murphy
  2017-11-22  2:17         ` Goel, Sameer
  0 siblings, 2 replies; 34+ messages in thread
From: Julien Grall @ 2017-11-20 14:25 UTC (permalink / raw)
  To: Goel, Sameer, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 19/11/17 07:45, Goel, Sameer wrote:
> On 10/12/2017 10:36 AM, Julien Grall wrote:
>>> +
>>> +typedef paddr_t phys_addr_t;
>>> +typedef paddr_t dma_addr_t;
>>> +
>>> +/* Alias to Xen device tree helpers */
>>> +#define device_node dt_device_node
>>> +#define of_phandle_args dt_phandle_args
>>> +#define of_device_id dt_device_match
>>> +#define of_match_node dt_match_node
>>> +#define of_property_read_u32(np, pname, out) (!dt_property_read_u32(np, pname, out))
>>> +#define of_property_read_bool dt_property_read_bool
>>> +#define of_parse_phandle_with_args dt_parse_phandle_with_args
>>> +#define mutex spinlock_t
>>> +#define mutex_init spin_lock_init
>>> +#define mutex_lock spin_lock
>>> +#define mutex_unlock spin_unlock
>>
>> mutex and spinlock are not the same. The former is sleeping whilst the later is not.
>>
>> Can you please explain why this is fine and possibly add that in a comment?
>>
> Mutex is used to protect the access to smmu device internal data structure when setting up the s2 config and installing stes for a given device in Linux. The ste programming  operation can be competitively long but in the current testing, I did not see this blocking for too long. I will put in a comment.

Well, I don't think that this is a justification. You tested on one 
platform and does not explain how you perform them.

If I understand correctly, that mutex is only used when assigning 
device. So it might be ok to switch to spinlock. But that's not because 
the operation is not too long, it just because it would be only perform 
by the toolstack (domctl) and will not be issued by guest.

> 
>>> +
>>> +/* Xen: Helpers to get device MMIO and IRQs */
>>> +struct resource {
>>> +    u64 addr;
>>> +    u64 size;
>>> +    unsigned int type;
>>> +};
>>
>> Likely we want a compat header for defining Linux helpers. This would avoid replicating it everywhere.
> Agreed.
> 
That should be
>>
>>> +
>>> +#define resource_size(res) ((res)->size)
>>> +
>>> +#define platform_device device
>>> +
>>> +#define IORESOURCE_MEM 0
>>> +#define IORESOURCE_IRQ 1
>>> +
>>> +static struct resource *platform_get_resource(struct platform_device *pdev,
>>> +                          unsigned int type,
>>> +                          unsigned int num)
>>> +{
>>> +    /*
>>> +     * The resource is only used between 2 calls of platform_get_resource.
>>> +     * It's quite ugly but it's avoid to add too much code in the part
>>> +     * imported from Linux
>>> +     */
>>> +    static struct resource res;
>>> +    struct acpi_iort_node *iort_node;
>>> +    struct acpi_iort_smmu_v3 *node_smmu_data;
>>> +    int ret = 0;
>>> +
>>> +    res.type = type;
>>> +
>>> +    switch (type) {
>>> +    case IORESOURCE_MEM:
>>> +        if (pdev->type == DEV_ACPI) {
>>> +            ret = 1;
>>> +            iort_node = pdev->acpi_node;
>>> +            node_smmu_data =
>>> +                (struct acpi_iort_smmu_v3 *)iort_node->node_data;
>>> +
>>> +            if (node_smmu_data != NULL) {
>>> +                res.addr = node_smmu_data->base_address;
>>> +                res.size = SZ_128K;
>>> +                ret = 0;
>>> +            }
>>> +        } else {
>>> +            ret = dt_device_get_address(dev_to_dt(pdev), num,
>>> +                            &res.addr, &res.size);
>>> +        }
>>> +
>>> +        return ((ret) ? NULL : &res);
>>> +
>>> +    case IORESOURCE_IRQ:
>>> +        ret = platform_get_irq(dev_to_dt(pdev), num);
>>
>> No IRQ for ACPI?
> For IRQs the code calls platform_get_irq_byname. So, the IORESOURCE_IRQ implementation is not needed at all. (DT or ACPI)

Please document it then.

[...]

>>
>>> +        udelay(sleep_us); \
>>> +    } \
>>> +    (cond) ? 0 : -ETIMEDOUT; \
>>> +})
>>> +
>>> +#define readl_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
>>> +    readx_poll_timeout(readl_relaxed, addr, val, cond, delay_us, timeout_us)
>>> +
>>> +/* Xen: Helpers for IRQ functions */
>>> +#define request_irq(irq, func, flags, name, dev) request_irq(irq, flags, func, name, dev)
>>> +#define free_irq release_irq
>>> +
>>> +enum irqreturn {
>>> +    IRQ_NONE    = (0 << 0),
>>> +    IRQ_HANDLED    = (1 << 0),
>>> +};
>>> +
>>> +typedef enum irqreturn irqreturn_t;
>>> +
>>> +/* Device logger functions */
>>> +#define dev_print(dev, lvl, fmt, ...)                        \
>>> +     printk(lvl "smmu: " fmt, ## __VA_ARGS__)
>>> +
>>> +#define dev_dbg(dev, fmt, ...) dev_print(dev, XENLOG_DEBUG, fmt, ## __VA_ARGS__)
>>> +#define dev_notice(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
>>> +#define dev_warn(dev, fmt, ...) dev_print(dev, XENLOG_WARNING, fmt, ## __VA_ARGS__)
>>> +#define dev_err(dev, fmt, ...) dev_print(dev, XENLOG_ERR, fmt, ## __VA_ARGS__)
>>> +#define dev_info(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
>>> +
>>> +#define dev_err_ratelimited(dev, fmt, ...)                    \
>>> +     dev_print(dev, 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)        _xmalloc(size, sizeof(void *))
>>> +#define kzalloc(size, flags)        _xzalloc(size, sizeof(void *))
>>> +#define devm_kzalloc(dev, size, flags)    _xzalloc(size, sizeof(void *))
>>> +#define kmalloc_array(size, n, flags)    _xmalloc_array(size, sizeof(void *), n)
>>> +
>>> +/* Compatibility defines */
>>> +#undef WARN_ON
>>> +#define WARN_ON(cond) (!!cond)
>>
>> Why do you redefine WARN_ON?Need it to be a scalar value. The Xen implementation is a do..while. Did not want a large impact hence the local define. I can try proposing a new common define.

Well, I don't think it is acceptable to redefine WARN_ON. At least 
without trying to modify the common version.

>>
>>> +#define WARN_ON_ONCE(cond) WARN_ON(cond)
>>> Hmmm, can't we implement a common WARN_ON_ONCE?
> Will not really be executed. Defining it to maintain compatibility. I think this file is the right place for this define. We can send it to a generic file if so needed.

I can't see why we wouldn't want to have a WARN_ON_ONCE in the common 
code. If you disagree, please explain.

[...]

>>
>>> +        else {
>>>                cpu_relax();
>>
>> Hmmm I now see why you added cpu_relax() at the top. Well, on Xen cpu_relax is just a barrier. On Linux it is used to yield.
>>
>> And that bit is worrying me. The Linux code will allow context switching to another tasks if the code is taking too much time.
>>
>> Xen is not preemptible, so is it fine?
> This is used when consuming the command queue and could be a potential performance issue if the queue is large. (This is never the case).
> I am wondering if we should define a yeild in long run?

As I said before, Xen is not preemptible. In this particular case, there 
are spinlock taken by the callers (e.g any function assigning device). 
So yield would just make it worst.

[...]

>>
>>>        strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>>>          desc->span = STRTAB_SPLIT + 1;
>>> -    desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
>>> -                      GFP_KERNEL | __GFP_ZERO);
>>> +
>>> +    alignment = 1 << ((5 + (desc->span - 1)));
>>
>> Do you mind explaining the 5? Also, does the shift will always be < 32?
> Its from the "Level 1 Stream Table Descriptor" from SMMU spec. I can add the ref to the spec. Yes the span is hard coded in the driver and with any spec valid span values this cannot exceed 32.
> I have added a comment tot he code
>>
>>> +    desc->l2ptr = _xzalloc(size, alignment);
>>> +    desc->l2ptr_dma = virt_to_maddr(desc->l2ptr);
>>
>> _xzalloc can fail and virt_to_maddr will result to a panic.
>>
> I will move the check.
>>> +
>>>        if (!desc->l2ptr) {
>>>            dev_err(smmu->dev,
>>>                "failed to allocate l2 stream table for SID %u\n",
>>> @@ -1158,7 +1418,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>>>    }
>>>      /* IRQ and event handlers */
>>> -static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>> +static void arm_smmu_evtq_thread(int irq, void *dev, struct cpu_user_regs *regs)
>>
>> Could you please introduce a wrapper instead as it was done in smmu.c?
>>
> Done.
> 
>>>    {
>>>        int i;
>>>        struct arm_smmu_device *smmu = dev;
>>> @@ -1186,7 +1446,6 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>>          /* Sync our overflow flag, as we believe we're up to speed */
>>>        q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
>>> -    return IRQ_HANDLED;
>>>    }
>>>      static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
>>> @@ -1203,7 +1462,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 0x%016lx\n",
>>
>> Hmmm why?
> The variable is defined as ungined long long in Linux. ( uses generic int-ll64.h) In Xen the definition changes to unsigned long for ARM_64 which actually makes sense.

u64 is a 64-bit variable. And therefore the format should be PRIx64 to 
accomodate 64-bit and 32-bit.

[...]

>>
>>> +
>>>      static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>>>    {
>>> @@ -1410,6 +1674,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>>>        return &smmu_domain->domain;
>>>    }
>>>    +#if 0
>>
>> Please explain the #if 0
>>
> Done.
> 
>>>    static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
>>>    {
>>>        int idx, size = 1 << span;
>>> @@ -1427,36 +1692,20 @@ static void arm_smmu_bitmap_free(unsigned long *map, int idx)
>>>    {
>>>        clear_bit(idx, map);
>>>    }
>>> +#endif
>>>      static void arm_smmu_domain_free(struct iommu_domain *domain)
>>>    {
>>>        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>>> -    struct arm_smmu_device *smmu = smmu_domain->smmu;
>>> -
>>> -    iommu_put_dma_cookie(domain);
>>> -    free_io_pgtable_ops(smmu_domain->pgtbl_ops);
>>> -
>>> -    /* Free the CD and ASID, if we allocated them */
>>> -    if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>>> -        struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>>> -
>>> -        if (cfg->cdptr) {
>>> -            dmam_free_coherent(smmu_domain->smmu->dev,
>>> -                       CTXDESC_CD_DWORDS << 3,
>>> -                       cfg->cdptr,
>>> -                       cfg->cdptr_dma);
>>> -
>>> -            arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
>>> -        }
>>> -    } else {
>>> -        struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>>> -        if (cfg->vmid)
>>> -            arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
>>> -    }
>>> +    /*
>>> +     * Xen: Remove the free functions that are not used and code related
>>> +     * to S1 translation. We just need to free the domain here.
>>> +     */
>>
>> Please use #if 0 rather than removing the code + comment on top. But I am not sure why you drop the S2 free code. Shouldn't we allocate VMID from the SMMU?
> I am picking up the vmid from the domain I am sharing the page tables with. domain->arch.p2m.vmid. This seemed valid. Please let me know if we want to generate a different vmid?

The processor and the SMMU may support either 8 or 16bits VMID but I 
don't think any thing in the spec says that both processor and SMMU must 
support the same value.

So it would be possible to have a processor supporting 16-bits VMID and 
the SMMU only 8-bits VMID.

Adding a check at the SMMU initialization might be a solution. But as 
the code for allocating the VMID is already present, then I would prefer 
to we stick with different the VMID.

> 
> 
>>
>>>          kfree(smmu_domain);
>>>    }
>>>    +#if 0
>>>    static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
>>>                           struct io_pgtable_cfg *pgtbl_cfg)
>>>    {
>>> @@ -1488,33 +1737,30 @@ out_free_asid:
>>>        arm_smmu_bitmap_free(smmu->asid_map, asid);
>>>        return ret;
>>>    }
>>> +#endif
>>>    -static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
>>> -                       struct io_pgtable_cfg *pgtbl_cfg)
>>> +static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain)
>>>    {
>>> -    int vmid;
>>> -    struct arm_smmu_device *smmu = smmu_domain->smmu;
>>>        struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>>>    -    vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
>>> -    if (vmid < 0)
>>> -        return vmid;
>>> +    /* Xen: Set the values as needed */
>>>    -    cfg->vmid    = (u16)vmid;
>>> -    cfg->vttbr    = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
>>> -    cfg->vtcr    = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
>>> +    cfg->vmid    = cfg->domain->arch.p2m.vmid;
>>
>> See my comment above.
> I am wondering why we are considering this value invalid? Since the page tables are shared we can use the vmid from the domain. Is the concern regarding the size?

See above.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-11-20 14:25       ` Julien Grall
@ 2017-11-20 15:19         ` Robin Murphy
  2017-11-20 15:24           ` Julien Grall
  2017-11-22  2:17         ` Goel, Sameer
  1 sibling, 1 reply; 34+ messages in thread
From: Robin Murphy @ 2017-11-20 15:19 UTC (permalink / raw)
  To: Julien Grall, Goel, Sameer, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, shankerd

On 20/11/17 14:25, Julien Grall wrote:
[...]
>>>
>>>> +        else {
>>>>                cpu_relax();
>>>
>>> Hmmm I now see why you added cpu_relax() at the top. Well, on Xen 
>>> cpu_relax is just a barrier. On Linux it is used to yield.
>>>
>>> And that bit is worrying me. The Linux code will allow context 
>>> switching to another tasks if the code is taking too much time.
>>>
>>> Xen is not preemptible, so is it fine?
>> This is used when consuming the command queue and could be a potential 
>> performance issue if the queue is large. (This is never the case).
>> I am wondering if we should define a yeild in long run?
> 
> As I said before, Xen is not preemptible. In this particular case, there 
> are spinlock taken by the callers (e.g any function assigning device). 
> So yield would just make it worst.

The arguments here don't make much sense - the "yield" instruction has 
nothing to do with software-level concepts of preemption. It is a hint 
to SMT *hardware* that this logical processor is doing nothing useful in 
the short term, so it might be a good idea to let other logical 
processor(s) have priority over shared execution resources if applicable.

Until SMT CPUs become commonly available, though, it's somewhat of a 
moot point and mostly just a future-proofing consideration.

Robin.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-11-20 15:19         ` Robin Murphy
@ 2017-11-20 15:24           ` Julien Grall
  0 siblings, 0 replies; 34+ messages in thread
From: Julien Grall @ 2017-11-20 15:24 UTC (permalink / raw)
  To: Robin Murphy, Goel, Sameer, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, shankerd

Hi,

On 20/11/17 15:19, Robin Murphy wrote:
> On 20/11/17 14:25, Julien Grall wrote:
> [...]
>>>>
>>>>> +        else {
>>>>>                cpu_relax();
>>>>
>>>> Hmmm I now see why you added cpu_relax() at the top. Well, on Xen 
>>>> cpu_relax is just a barrier. On Linux it is used to yield.
>>>>
>>>> And that bit is worrying me. The Linux code will allow context 
>>>> switching to another tasks if the code is taking too much time.
>>>>
>>>> Xen is not preemptible, so is it fine?
>>> This is used when consuming the command queue and could be a 
>>> potential performance issue if the queue is large. (This is never the 
>>> case).
>>> I am wondering if we should define a yeild in long run?
>>
>> As I said before, Xen is not preemptible. In this particular case, 
>> there are spinlock taken by the callers (e.g any function assigning 
>> device). So yield would just make it worst.
> 
> The arguments here don't make much sense - the "yield" instruction has 
> nothing to do with software-level concepts of preemption. It is a hint 
> to SMT *hardware* that this logical processor is doing nothing useful in 
> the short term, so it might be a good idea to let other logical 
> processor(s) have priority over shared execution resources if applicable.

Oh, sorry I thought this could also be used by the software to switch 
between thread. Please disregard my comment then.

> 
> Until SMT CPUs become commonly available, though, it's somewhat of a 
> moot point and mostly just a future-proofing consideration.
> 
> Robin.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-11-20 14:25       ` Julien Grall
  2017-11-20 15:19         ` Robin Murphy
@ 2017-11-22  2:17         ` Goel, Sameer
  2017-11-27 12:28           ` Julien Grall
  1 sibling, 1 reply; 34+ messages in thread
From: Goel, Sameer @ 2017-11-22  2:17 UTC (permalink / raw)
  To: Julien Grall, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd



On 11/20/2017 7:25 AM, Julien Grall wrote:
> Hi Sameer,
> 
> On 19/11/17 07:45, Goel, Sameer wrote:
>> On 10/12/2017 10:36 AM, Julien Grall wrote:
>>>> +
>>>> +typedef paddr_t phys_addr_t;
>>>> +typedef paddr_t dma_addr_t;
>>>> +
>>>> +/* Alias to Xen device tree helpers */
>>>> +#define device_node dt_device_node
>>>> +#define of_phandle_args dt_phandle_args
>>>> +#define of_device_id dt_device_match
>>>> +#define of_match_node dt_match_node
>>>> +#define of_property_read_u32(np, pname, out) (!dt_property_read_u32(np, pname, out))
>>>> +#define of_property_read_bool dt_property_read_bool
>>>> +#define of_parse_phandle_with_args dt_parse_phandle_with_args
>>>> +#define mutex spinlock_t
>>>> +#define mutex_init spin_lock_init
>>>> +#define mutex_lock spin_lock
>>>> +#define mutex_unlock spin_unlock
>>>
>>> mutex and spinlock are not the same. The former is sleeping whilst the later is not.
>>>
>>> Can you please explain why this is fine and possibly add that in a comment?
>>>
>> Mutex is used to protect the access to smmu device internal data structure when setting up the s2 config and installing stes for a given device in Linux. The ste programming  operation can be competitively long but in the current testing, I did not see this blocking for too long. I will put in a comment.
> 
> Well, I don't think that this is a justification. You tested on one platform and does not explain how you perform them.
> 
> If I understand correctly, that mutex is only used when assigning device. So it might be ok to switch to spinlock. But that's not because the operation is not too long, it just because it would be only perform by the toolstack (domctl) and will not be issued by guest.
Ok. I agree ans will update the comment. 
> 
>>
>>>> +
>>>> +/* Xen: Helpers to get device MMIO and IRQs */
>>>> +struct resource {
>>>> +    u64 addr;
>>>> +    u64 size;
>>>> +    unsigned int type;
>>>> +};
>>>
>>> Likely we want a compat header for defining Linux helpers. This would avoid replicating it everywhere.
>> Agreed.
>>
> That should be
>>>
>>>> +
>>>> +#define resource_size(res) ((res)->size)
>>>> +
>>>> +#define platform_device device
>>>> +
>>>> +#define IORESOURCE_MEM 0
>>>> +#define IORESOURCE_IRQ 1
>>>> +
>>>> +static struct resource *platform_get_resource(struct platform_device *pdev,
>>>> +                          unsigned int type,
>>>> +                          unsigned int num)
>>>> +{
>>>> +    /*
>>>> +     * The resource is only used between 2 calls of platform_get_resource.
>>>> +     * It's quite ugly but it's avoid to add too much code in the part
>>>> +     * imported from Linux
>>>> +     */
>>>> +    static struct resource res;
>>>> +    struct acpi_iort_node *iort_node;
>>>> +    struct acpi_iort_smmu_v3 *node_smmu_data;
>>>> +    int ret = 0;
>>>> +
>>>> +    res.type = type;
>>>> +
>>>> +    switch (type) {
>>>> +    case IORESOURCE_MEM:
>>>> +        if (pdev->type == DEV_ACPI) {
>>>> +            ret = 1;
>>>> +            iort_node = pdev->acpi_node;
>>>> +            node_smmu_data =
>>>> +                (struct acpi_iort_smmu_v3 *)iort_node->node_data;
>>>> +
>>>> +            if (node_smmu_data != NULL) {
>>>> +                res.addr = node_smmu_data->base_address;
>>>> +                res.size = SZ_128K;
>>>> +                ret = 0;
>>>> +            }
>>>> +        } else {
>>>> +            ret = dt_device_get_address(dev_to_dt(pdev), num,
>>>> +                            &res.addr, &res.size);
>>>> +        }
>>>> +
>>>> +        return ((ret) ? NULL : &res);
>>>> +
>>>> +    case IORESOURCE_IRQ:
>>>> +        ret = platform_get_irq(dev_to_dt(pdev), num);
>>>
>>> No IRQ for ACPI?
>> For IRQs the code calls platform_get_irq_byname. So, the IORESOURCE_IRQ implementation is not needed at all. (DT or ACPI)
> 
> Please document it then.
Ok.
> 
> [...]
> 
>>>
>>>> +        udelay(sleep_us); \
>>>> +    } \
>>>> +    (cond) ? 0 : -ETIMEDOUT; \
>>>> +})
>>>> +
>>>> +#define readl_relaxed_poll_timeout(addr, val, cond, delay_us, timeout_us) \
>>>> +    readx_poll_timeout(readl_relaxed, addr, val, cond, delay_us, timeout_us)
>>>> +
>>>> +/* Xen: Helpers for IRQ functions */
>>>> +#define request_irq(irq, func, flags, name, dev) request_irq(irq, flags, func, name, dev)
>>>> +#define free_irq release_irq
>>>> +
>>>> +enum irqreturn {
>>>> +    IRQ_NONE    = (0 << 0),
>>>> +    IRQ_HANDLED    = (1 << 0),
>>>> +};
>>>> +
>>>> +typedef enum irqreturn irqreturn_t;
>>>> +
>>>> +/* Device logger functions */
>>>> +#define dev_print(dev, lvl, fmt, ...)                        \
>>>> +     printk(lvl "smmu: " fmt, ## __VA_ARGS__)
>>>> +
>>>> +#define dev_dbg(dev, fmt, ...) dev_print(dev, XENLOG_DEBUG, fmt, ## __VA_ARGS__)
>>>> +#define dev_notice(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
>>>> +#define dev_warn(dev, fmt, ...) dev_print(dev, XENLOG_WARNING, fmt, ## __VA_ARGS__)
>>>> +#define dev_err(dev, fmt, ...) dev_print(dev, XENLOG_ERR, fmt, ## __VA_ARGS__)
>>>> +#define dev_info(dev, fmt, ...) dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
>>>> +
>>>> +#define dev_err_ratelimited(dev, fmt, ...)                    \
>>>> +     dev_print(dev, 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)        _xmalloc(size, sizeof(void *))
>>>> +#define kzalloc(size, flags)        _xzalloc(size, sizeof(void *))
>>>> +#define devm_kzalloc(dev, size, flags)    _xzalloc(size, sizeof(void *))
>>>> +#define kmalloc_array(size, n, flags)    _xmalloc_array(size, sizeof(void *), n)
>>>> +
>>>> +/* Compatibility defines */
>>>> +#undef WARN_ON
>>>> +#define WARN_ON(cond) (!!cond)
>>>
>>> Why do you redefine WARN_ON?Need it to be a scalar value. The Xen implementation is a do..while. Did not want a large impact hence the local define. I can try proposing a new common define.
> 
> Well, I don't think it is acceptable to redefine WARN_ON. At least without trying to modify the common version.

I will put this in the common folder.
> 
>>>
>>>> +#define WARN_ON_ONCE(cond) WARN_ON(cond)
>>>> Hmmm, can't we implement a common WARN_ON_ONCE?
>> Will not really be executed. Defining it to maintain compatibility. I think this file is the right place for this define. We can send it to a generic file if so needed.
> 
> I can't see why we wouldn't want to have a WARN_ON_ONCE in the common code. If you disagree, please explain.
> 
> [...]
> 
>>>
>>>> +        else {
>>>>                cpu_relax();
>>>
>>> Hmmm I now see why you added cpu_relax() at the top. Well, on Xen cpu_relax is just a barrier. On Linux it is used to yield.
>>>
>>> And that bit is worrying me. The Linux code will allow context switching to another tasks if the code is taking too much time.
>>>
>>> Xen is not preemptible, so is it fine?
>> This is used when consuming the command queue and could be a potential performance issue if the queue is large. (This is never the case).
>> I am wondering if we should define a yeild in long run?
> 
> As I said before, Xen is not preemptible. In this particular case, there are spinlock taken by the callers (e.g any function assigning device). So yield would just make it worst.
> 
> [...]
I can keep the memory barrier as is. This should not impact much. This should not be a concern.
> 
>>>
>>>>        strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>>>>          desc->span = STRTAB_SPLIT + 1;
>>>> -    desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
>>>> -                      GFP_KERNEL | __GFP_ZERO);
>>>> +
>>>> +    alignment = 1 << ((5 + (desc->span - 1)));
>>>
>>> Do you mind explaining the 5? Also, does the shift will always be < 32?
>> Its from the "Level 1 Stream Table Descriptor" from SMMU spec. I can add the ref to the spec. Yes the span is hard coded in the driver and with any spec valid span values this cannot exceed 32.
>> I have added a comment tot he code
>>>
>>>> +    desc->l2ptr = _xzalloc(size, alignment);
>>>> +    desc->l2ptr_dma = virt_to_maddr(desc->l2ptr);
>>>
>>> _xzalloc can fail and virt_to_maddr will result to a panic.
>>>
>> I will move the check.
>>>> +
>>>>        if (!desc->l2ptr) {
>>>>            dev_err(smmu->dev,
>>>>                "failed to allocate l2 stream table for SID %u\n",
>>>> @@ -1158,7 +1418,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>>>>    }
>>>>      /* IRQ and event handlers */
>>>> -static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>>> +static void arm_smmu_evtq_thread(int irq, void *dev, struct cpu_user_regs *regs)
>>>
>>> Could you please introduce a wrapper instead as it was done in smmu.c?
>>>
>> Done.
>>
>>>>    {
>>>>        int i;
>>>>        struct arm_smmu_device *smmu = dev;
>>>> @@ -1186,7 +1446,6 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>>>          /* Sync our overflow flag, as we believe we're up to speed */
>>>>        q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
>>>> -    return IRQ_HANDLED;
>>>>    }
>>>>      static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
>>>> @@ -1203,7 +1462,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 0x%016lx\n",
>>>
>>> Hmmm why?
>> The variable is defined as ungined long long in Linux. ( uses generic int-ll64.h) In Xen the definition changes to unsigned long for ARM_64 which actually makes sense.
> 
> u64 is a 64-bit variable. And therefore the format should be PRIx64 to accomodate 64-bit and 32-bit.
Sure. I can change the format specifier. 
> 
> [...]
> 
>>>
>>>> +
>>>>      static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>>>>    {
>>>> @@ -1410,6 +1674,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>>>>        return &smmu_domain->domain;
>>>>    }
>>>>    +#if 0
>>>
>>> Please explain the #if 0
>>>
>> Done.
>>
>>>>    static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
>>>>    {
>>>>        int idx, size = 1 << span;
>>>> @@ -1427,36 +1692,20 @@ static void arm_smmu_bitmap_free(unsigned long *map, int idx)
>>>>    {
>>>>        clear_bit(idx, map);
>>>>    }
>>>> +#endif
>>>>      static void arm_smmu_domain_free(struct iommu_domain *domain)
>>>>    {
>>>>        struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>>>> -    struct arm_smmu_device *smmu = smmu_domain->smmu;
>>>> -
>>>> -    iommu_put_dma_cookie(domain);
>>>> -    free_io_pgtable_ops(smmu_domain->pgtbl_ops);
>>>> -
>>>> -    /* Free the CD and ASID, if we allocated them */
>>>> -    if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
>>>> -        struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg;
>>>> -
>>>> -        if (cfg->cdptr) {
>>>> -            dmam_free_coherent(smmu_domain->smmu->dev,
>>>> -                       CTXDESC_CD_DWORDS << 3,
>>>> -                       cfg->cdptr,
>>>> -                       cfg->cdptr_dma);
>>>> -
>>>> -            arm_smmu_bitmap_free(smmu->asid_map, cfg->cd.asid);
>>>> -        }
>>>> -    } else {
>>>> -        struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>>>> -        if (cfg->vmid)
>>>> -            arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
>>>> -    }
>>>> +    /*
>>>> +     * Xen: Remove the free functions that are not used and code related
>>>> +     * to S1 translation. We just need to free the domain here.
>>>> +     */
>>>
>>> Please use #if 0 rather than removing the code + comment on top. But I am not sure why you drop the S2 free code. Shouldn't we allocate VMID from the SMMU?
>> I am picking up the vmid from the domain I am sharing the page tables with. domain->arch.p2m.vmid. This seemed valid. Please let me know if we want to generate a different vmid?
> 
> The processor and the SMMU may support either 8 or 16bits VMID but I don't think any thing in the spec says that both processor and SMMU must support the same value.
> 
> So it would be possible to have a processor supporting 16-bits VMID and the SMMU only 8-bits VMID.
> 
> Adding a check at the SMMU initialization might be a solution. But as the code for allocating the VMID is already present, then I would prefer to we stick with different the VMID.
Sure. For this iteration I will generate an SMMU specific VMID. Do you think it would be an optimization to reuse the CPU VMID if SMMU supports 16bit VMID?

Thanks,
Sameer
> 
>>
>>
>>>
>>>>          kfree(smmu_domain);
>>>>    }
>>>>    +#if 0
>>>>    static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
>>>>                           struct io_pgtable_cfg *pgtbl_cfg)
>>>>    {
>>>> @@ -1488,33 +1737,30 @@ out_free_asid:
>>>>        arm_smmu_bitmap_free(smmu->asid_map, asid);
>>>>        return ret;
>>>>    }
>>>> +#endif
>>>>    -static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
>>>> -                       struct io_pgtable_cfg *pgtbl_cfg)
>>>> +static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain)
>>>>    {
>>>> -    int vmid;
>>>> -    struct arm_smmu_device *smmu = smmu_domain->smmu;
>>>>        struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
>>>>    -    vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
>>>> -    if (vmid < 0)
>>>> -        return vmid;
>>>> +    /* Xen: Set the values as needed */
>>>>    -    cfg->vmid    = (u16)vmid;
>>>> -    cfg->vttbr    = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
>>>> -    cfg->vtcr    = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
>>>> +    cfg->vmid    = cfg->domain->arch.p2m.vmid;
>>>
>>> See my comment above.
>> I am wondering why we are considering this value invalid? Since the page tables are shared we can use the vmid from the domain. Is the concern regarding the size?
> 
> See above.
> 
> Cheers,
> 

-- 
 Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver
  2017-11-22  2:17         ` Goel, Sameer
@ 2017-11-27 12:28           ` Julien Grall
  0 siblings, 0 replies; 34+ messages in thread
From: Julien Grall @ 2017-11-27 12:28 UTC (permalink / raw)
  To: Goel, Sameer, xen-devel, julien.grall, mjaggi
  Cc: sstabellini, wei.liu2, george.dunlap, Andrew.Cooper3, jbeulich,
	Ian.Jackson, nd, robin.murphy, shankerd

Hi Sameer,

On 22/11/17 02:17, Goel, Sameer wrote:
> On 11/20/2017 7:25 AM, Julien Grall wrote:
>> On 19/11/17 07:45, Goel, Sameer wrote:
>>> On 10/12/2017 10:36 AM, Julien Grall wrote:
>>>> Please use #if 0 rather than removing the code + comment on top. But I am not sure why you drop the S2 free code. Shouldn't we allocate VMID from the SMMU?
>>> I am picking up the vmid from the domain I am sharing the page tables with. domain->arch.p2m.vmid. This seemed valid. Please let me know if we want to generate a different vmid?
>>
>> The processor and the SMMU may support either 8 or 16bits VMID but I don't think any thing in the spec says that both processor and SMMU must support the same value.
>>
>> So it would be possible to have a processor supporting 16-bits VMID and the SMMU only 8-bits VMID.
>>
>> Adding a check at the SMMU initialization might be a solution. But as the code for allocating the VMID is already present, then I would prefer to we stick with different the VMID.
> Sure. For this iteration I will generate an SMMU specific VMID. Do you think it would be an optimization to reuse the CPU VMID if SMMU supports 16bit VMID?

The only benefit I can see is if the SMMU support broadcast TLB 
maintenance. AFAICT, the driver would need to configure the SMMU for that.

However, I think we should first focus on getting a basic SMMUv3 driver 
in Xen. Once this is done, we can look at optimizing the driver.

Cheers,

-- 
Julien Grall

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

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2017-11-27 12:28 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-21  0:37 [RFC v2 0/7] SMMUv3 driver and the supporting framework Sameer Goel
2017-09-21  0:37 ` [RFC v2 1/7] passthrough/arm: Modify SMMU driver to use generic device definition Sameer Goel
2017-09-21  0:37 ` [RFC v2 2/7] arm64: Add definitions for fwnode_handle Sameer Goel
2017-10-12 12:45   ` Julien Grall
2017-10-19 14:53     ` Goel, Sameer
2017-10-24 14:08       ` Julien Grall
2017-11-09  0:56         ` Goel, Sameer
2017-09-21  0:37 ` [RFC v2 3/7] xen/passthrough/arm: Introduce iommu_fwspec Sameer Goel
2017-10-12 13:05   ` Julien Grall
2017-10-12 13:36     ` Julien Grall
2017-10-19 14:58     ` Goel, Sameer
2017-09-21  0:37 ` [RFC v2 4/7] ACPI: arm: Support for IORT Sameer Goel
2017-09-21  0:37 ` [RFC v2 5/7] acpi:arm64: Add support for parsing IORT table Sameer Goel
2017-10-10 12:36   ` Manish Jaggi
2017-10-19 15:00     ` Goel, Sameer
2017-10-20  6:25       ` Manish Jaggi
2017-10-12 14:06   ` Julien Grall
2017-10-19 15:21     ` Goel, Sameer
2017-10-24 14:26       ` Julien Grall
2017-10-12 14:23   ` Julien Grall
2017-11-08 14:41   ` Manish Jaggi
2017-11-15  1:27     ` Goel, Sameer
2017-11-15  8:58       ` Julien Grall
2017-09-21  0:37 ` [RFC v2 6/7] Add verbatim copy of arm-smmu-v3.c from Linux Sameer Goel
2017-09-21  0:37 ` [RFC v2 7/7] xen/iommu: smmu-v3: Add Xen specific code to enable the ported driver Sameer Goel
2017-09-26  0:03   ` Goel, Sameer
2017-10-12 16:36   ` Julien Grall
2017-11-19  7:45     ` Goel, Sameer
2017-11-20 14:25       ` Julien Grall
2017-11-20 15:19         ` Robin Murphy
2017-11-20 15:24           ` Julien Grall
2017-11-22  2:17         ` Goel, Sameer
2017-11-27 12:28           ` Julien Grall
2017-09-21  5:43 ` [RFC v2 0/7] SMMUv3 driver and the supporting framework Manish Jaggi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.