[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 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@xxxxxxxxxxxxxx>
>> ---
>>   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@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>
> 
> 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@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®.