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

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


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: "Goel, Sameer" <sgoel@xxxxxxxxxxxxxx>
  • Date: Thu, 31 May 2018 10:06:47 -0600
  • Authentication-results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org
  • Authentication-results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=sgoel@xxxxxxxxxxxxxx
  • Delivery-date: Thu, 31 May 2018 16:06:58 +0000
  • Dmarc-filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 6F209605A4
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>


On 5/30/2018 10:10 PM, Manish Jaggi wrote:
> 
> 
> On 05/31/2018 01:16 AM, Sameer Goel wrote:
>> Manish, I'll take another look at the variable names. I might not have 
>> enough time :).
>>>>
>>>> On 05/23/2018 10:48 PM, Manish Jaggi wrote:
>>>>> Hi Sameer,
>>>>>
>>>>> General Comment, please use appropriate variable names for XXX_domain 
>>>>> structures in code which is xen specific.
>>>> I thought that we had discussed this before on one of the RFCs.
>>> Yes and no one replied to my last comment that the var names have to be non 
>>> confusing in Xen specific code.
>> I'm sorry about that. I just assumed that since the policy on ported 
>> variable names was consistent we so not nee to change the names.
>>
>>>> At this point we are just using the format used for smmu-v2.
>>> smmu-v2 has a lot of confusing variable names with _domain.
>>> I believe that file needs to be fixed as well.
>>>> I don't think that the variable names are inappropriate. Unless there is a 
>>>> very specific issue with the variable names,
>>> The issue is in code readability and understanding the flow.
>>> It is confusing so many _domain variable names are used which are not 
>>> verbose.
>> These names are coming from the original Linux code. So, we do not change 
>> them as per the policy. That being said I can add a comment section to 
>> explain the confusing variables in the Xen specific code? Please let me know 
>> if this will help us resolve this issue?
>>   
> If it is in Xen specific functions, then it can be changed, this is what 
> julien also confirmed.

Agreed. Changing the var names.
> 
>>> Two functions different and confusing variable names
>>>>>> +    struct iommu_domain *domain;
>>>>>> +};
>>>>>> +
>>>>> As this is a xen specific code, can the variable names be used 
>>>>> appropriately.
>>>>> Repeating my comment  from earlier version.
>>>>> a domain is  usually a VM in Xen. So it is a bit confusing to use domain 
>>>>> for iommu_domain.
>> The struct is fine but you have an issue with the var name right?
> Yes.
>>
>>>>>> +/*
>>>>>> + * Xen: io_pgtable compatibility defines.
>>>>>> + * Most of these are to port in the S1 translation code as is.
>>>>>> + */
>>>>>> +struct io_pgtable_ops {
>>>>>> +};
>>>>>> +
>>>>>> +struct iommu_gather_ops {
>>>>>> +    void (*tlb_flush_all)(void *cookie);
>>>>>> +    void (*tlb_add_flush)(unsigned long iova, size_t size, size_t 
>>>>>> granule,
>>>>>> +                  bool leaf, void *cookie);
>>>>>> +    void (*tlb_sync)(void *cookie);
>>>>>> +};
>>>>>> +
>>>>>> +struct io_pgtable_cfg {
>>>>>> +    /*
>>>>>> +     * IO_PGTABLE_QUIRK_ARM_NS: (ARM formats) Set NS and NSTABLE bits in
>>>>>> +     *    stage 1 PTEs, for hardware which insists on validating them
>>>>>> +     *    even in    non-secure state where they should normally be 
>>>>>> ignored.
>>>>>> +     *
>>>>>> +     * IO_PGTABLE_QUIRK_NO_PERMS: Ignore the IOMMU_READ, IOMMU_WRITE and
>>>>>> +     *    IOMMU_NOEXEC flags and map everything with full access, for
>>>>>> +     *    hardware which does not implement the permissions of a given
>>>>>> +     *    format, and/or requires some format-specific default value.
>>>>>> +     *
>>>>>> +     * IO_PGTABLE_QUIRK_TLBI_ON_MAP: If the format forbids caching 
>>>>>> invalid
>>>>>> +     *    (unmapped) entries but the hardware might do so anyway, 
>>>>>> perform
>>>>>> +     *    TLB maintenance when mapping as well as when unmapping.
>>>>>> +     *
>>>>>> +     * IO_PGTABLE_QUIRK_ARM_MTK_4GB: (ARM v7s format) Set bit 9 in all
>>>>>> +     *    PTEs, for Mediatek IOMMUs which treat it as a 33rd address bit
>>>>>> +     *    when the SoC is in "4GB mode" and they can only access the 
>>>>>> high
>>>>>> +     *    remap of DRAM (0x1_00000000 to 0x1_ffffffff).
>>>>>> +     *
>>>>>> +     * IO_PGTABLE_QUIRK_NO_DMA: Guarantees that the tables will only 
>>>>>> ever
>>>>>> +     *    be accessed by a fully cache-coherent IOMMU or CPU (e.g. for a
>>>>>> +     *    software-emulated IOMMU), such that pagetable updates need not
>>>>>> +     *    be treated as explicit DMA data.
>>>>>> +     */
>>>>>> +    #define IO_PGTABLE_QUIRK_ARM_NS        BIT(0)
>>>>>> +    #define IO_PGTABLE_QUIRK_NO_PERMS    BIT(1)
>>>>>> +    #define IO_PGTABLE_QUIRK_TLBI_ON_MAP    BIT(2)
>>>>>> +    #define IO_PGTABLE_QUIRK_ARM_MTK_4GB    BIT(3)
>>>>>> +    #define IO_PGTABLE_QUIRK_NO_DMA        BIT(4)
>>>>>> +    unsigned long            quirks;
>>>>>> +    unsigned long            pgsize_bitmap;
>>>>>> +    unsigned int            ias;
>>>>>> +    unsigned int            oas;
>>>>>> +    const struct iommu_gather_ops    *tlb;
>>>>>> +    struct device            *iommu_dev;
>>>>>> +
>>>>>> +    /* Low-level data specific to the table format */
>>>>>> +    union {
>>>>>> +        struct {
>>>>>> +            u64    ttbr[2];
>>>>>> +            u64    tcr;
>>>>>> +            u64    mair[2];
>>>>>> +        } arm_lpae_s1_cfg;
>>>>>> +
>>>>>> +        struct {
>>>>>> +            u64    vttbr;
>>>>>> +            u64    vtcr;
>>>>>> +        } arm_lpae_s2_cfg;
>>>>>> +
>>>>>> +        struct {
>>>>>> +            u32    ttbr[2];
>>>>>> +            u32    tcr;
>>>>>> +            u32    nmrr;
>>>>>> +            u32    prrr;
>>>>>> +        } arm_v7s_cfg;
>>>>>> +    };
>>>>>> +};
>>>>>> +
>>>>>> +enum io_pgtable_fmt {
>>>>>> +    ARM_32_LPAE_S1,
>>>>>> +    ARM_32_LPAE_S2,
>>>>>> +    ARM_64_LPAE_S1,
>>>>>> +    ARM_64_LPAE_S2,
>>>>>> +    ARM_V7S,
>>>>>> +    IO_PGTABLE_NUM_FMTS,
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * Xen: The pgtable_ops are used by the S1 translations, so return the 
>>>>>> dummy
>>>>>> + * address.
>>>>>> + */
>>>>>> +#define alloc_io_pgtable_ops(f, c, o) ((struct io_pgtable_ops *)0x1)
>>>>>> +#define free_io_pgtable_ops(o)
>>>>>> +
>>>>>> +/* Xen: Define wrapper for requesting IRQs */
>>>>>> +#define IRQF_ONESHOT 0
>>>>>> +
>>>>>> +typedef void (*irq_handler_t)(int, void *, struct cpu_user_regs *);
>>>>>> +
>>>>>> +static inline int devm_request_irq(struct device *dev, unsigned int irq,
>>>>>> +                   irq_handler_t handler, unsigned long irqflags,
>>>>>> +                   const char *devname, void *dev_id)
>>>>>> +{
>>>>>> +    /*
>>>>>> +     * SMMUv3 implementation can support wired interrupt outputs that 
>>>>>> are
>>>>>> +     * edge-triggered. Set the irq type as per the spec.
>>>>>> +     */
>>>>>> +    irq_set_type(irq, IRQ_TYPE_EDGE_BOTH);
>>>>>> +    return request_irq(irq, irqflags, handler, devname, dev_id);
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * Xen does not have a concept of threaded irq, but we can use tasklets 
>>>>>> to
>>>>>> + * achieve the desired functionality as needed.
>>>>>> + */
>>>>>> +int devm_request_threaded_irq(struct device *dev, unsigned int irq, 
>>>>>> irq_handler_t handler,
>>>>>> +                  irq_handler_t thread_fn, unsigned long irqflags,
>>>>>> +                  const char *devname, void *dev_id)
>>>>>> +{
>>>>>> +    return devm_request_irq(dev, irq, thread_fn, irqflags, devname, 
>>>>>> dev_id);
>>>>>> +}
>>>>>> +
>>>>>> +/* Xen: The mutex is used only during initialization so the typecast is 
>>>>>> safe */
>>>>>> +#define mutex spinlock
>>>>>> +#define mutex_init spin_lock_init
>>>>>> +#define mutex_lock spin_lock
>>>>>> +#define mutex_unlock spin_unlock
>>>>>> +
>>>>>> +#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; \
>>>>>> +        } \
>>>>>> +    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)
>>>>>> +
>>>>>> +#define VA_BITS 0 /* Only needed for S1 translations */
>>>>>>      /* MMIO registers */
>>>>>>    #define ARM_SMMU_IDR0            0x0
>>>>>> @@ -433,6 +819,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,
>>>>>> @@ -457,6 +844,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 */
>>>>>> @@ -561,6 +949,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 {
>>>>>> @@ -635,9 +1025,25 @@ struct arm_smmu_device {
>>>>>>        struct arm_smmu_strtab_cfg    strtab_cfg;
>>>>>>          /* IOMMU core code handle */
>>>>>> +#if 0 /*Xen: Generic iommu_device ref not needed here */
>>>>>>        struct iommu_device        iommu;
>>>>>> +#endif
>>>>> Is it clean to put #if 0, can this line be deleted or used with a proper 
>>>>> macro
>> Manish this is a var name from original struct from Linux. I have just 
>> followed the prior standard of adding #if 0.
> It does not look clean, can we use something other than 0, say a macro 
> NA_CODE ...
That's true. Adding NA_CODE will probably make things clearer. I'll incorporate 
the change.

>>>>>> +    /* Xen: Need to keep a list of SMMU devices */
>>>>>> +    struct list_head                devices;
>>>>>> +    /* Xen: Tasklets for handling evts/faults and pci page request 
>>>>>> IRQs*/
>>>>>> +    struct tasklet            evtq_tasklet;
>>>>>> +    struct tasklet            priq_tasklet;
>>>>>> +    struct tasklet            combined_irq_tasklet;
.....
>>>>>> +                        struct device *dev)
>>>>> This is returning iommu_domain and not a domain.
>>>>> Please change the name of function.
>> Same as smmu-v2.c. I think with the complexity of the code we should try to 
>> get this in as the prior code. Once the set that has been pending for some 
>> time is in. We can start on the variable cleanup activity. I say this so 
>> that we can make the names consistent across the drivers and this will be a 
>> lot easier to do when the majority of the other code is in.
> smmu-v2.c had this issue and I had hard time understanding the code, the 
> confusing variable names break the understanding flow, especially when you 
> are debugging something and have lost touch of code.
> So let not do same mistake as in smmu-v2.c
Agreed. Will change the variable name.
>>>>>> +{
>>>>>> +    struct iommu_domain *domain;
>>>>>> +    struct arm_smmu_xen_domain *xen_domain;
>>>>> A suggestion
>>>>> 1. as you have used in above function smmu_domain variable for 
>>>>> arm_smmu_xen_domain
>>>>> Can similar logic be used for iommu_domain.
>> I am fine changing the var name.
>>>>> 2. When smmu_domain variable name is used in above function why 
>>>>> xen_domain is used in this function.
>>>>> It is quite confusing.
>>>>> logically xen_domain should mean a VM.
>> You lost me man. xen_domain is referring to the page tables of the the VM 
>> currently using the SMMU. What is the concern?
> in xen when you read basic documentation a domain is a VM, right?
> Now what would xen_domain variable should mean.
> How would you know it has something to do with SMMU.
> 
> So it is confusing to someone looking at the code.
I agree that you would think about the VMs when you see xen_domain. In this 
case the xen_domain variable has a 1:1 correspondence with the SMMU. If I call 
this smmu_xen_domain will it be easier to read?
>>>>>> +    struct arm_smmu_device *smmu;
>>>>>> +    struct arm_smmu_domain *smmu_domain;
>>>>> smmu_domain was used for arm_smmu_xen_domain.
>> Failed to see it. But, I'll have another look.
>>
>>>>> consistency of variable names is necessary for code clarity
>>>>>> +
>>>>>> +    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->contexts, 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)
>>>>> same
>> Ok
>>>>>> +{
>>>>>> +    list_del(&domain->list);
>>>>>> +    arm_smmu_domain_free(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;
>>>>> same
>> xen_domain is fine. You have an issue with the iommu_domioan here?
> domain has a variable name d, and iommu_domain has a variable name domain.
> Isnt it confusing.
> Why cant we use
> struct iommu_domain *io_domain ...
I agree. I am changing this all to iommu_domain. io_domain is fine too. What do 
you prefer?
> 
>>>>>> +    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->contexts);
>>>>>> +
>>>>>> +    }
>>>>>> +
>>>>>> +    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);
>>>>> same
>>>>>> +
>>>>>> +    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)
>>>>> Where is iommu_domain initialized?
>>>>> The function does not use a iommu_domain * variable
>>>>>> +{
>>>>>> +    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->contexts);
>>>>>> +
>>>>>> +    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->contexts));
>>>>>> +    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

>>> https://lists.xenproject.org/mailman/listinfo/xen-devel
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxxx
> https://lists.xenproject.org/mailman/listinfo/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@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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