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

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




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@xxxxxxxxxxxxxx>
> ---
>  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@xxxxxxx>
>   *
>   * 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@xxxxxxxxxxxxxx>
> + * 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@xxxxxxx>");
>  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@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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