Hello Wei,

could you please send email replies in plain text (rather than html)?

Thanks,

Stefano

On Mon, 25 Apr 2016, Wei Chen wrote:
> Hi Julien,
> 
> On 23 April 2016 at 02:29, Julien Grall <julien.gr...@arm.com> wrote:
>       Hi Wei,
> 
>       On 21/04/16 09:24, Wei Chen wrote:
>             This patch adds v2m extension support in GIC-v2 driver. The GICv2 
> driver
>             detects the MSI frames from device tree and creates corresponding 
> device
>             tree nodes in Domain0's DTB. It also provides one hw_ops callback 
> to map
>             v2m MMIO regions to domain0 and route v2m SPIs to domain0.
> 
>             With this GICv2m extension support, the domain0 kernel can do 
> GICv2m
>             frame setup and initialization.
> 
>             This patch is based on the GICv2m patch of Suravee Suthikulpanit:
>             [PATCH 2/2] xen/arm: gicv2: Adding support for GICv2m in Dom0
>             http://lists.xen.org/archives/html/xen-devel/2015-04/msg02613.html
> 
>             Signed-off-by: Wei Chen <wei.c...@linaro.org>
>             ---
>               xen/arch/arm/domain_build.c |   5 +
>               xen/arch/arm/gic-v2.c       | 285 
> ++++++++++++++++++++++++++++++++++++++++++++
>               xen/arch/arm/gic.c          |   9 ++
>               xen/include/asm-arm/gic.h   |   3 +
>               4 files changed, 302 insertions(+)
> 
>             diff --git a/xen/arch/arm/domain_build.c 
> b/xen/arch/arm/domain_build.c
>             index aba714c..b5d82fc 100644
>             --- a/xen/arch/arm/domain_build.c
>             +++ b/xen/arch/arm/domain_build.c
>             @@ -2176,6 +2176,11 @@ int construct_dom0(struct domain *d)
>                   if ( rc < 0 )
>                       return rc;
> 
>             +    /* Map extra GIC MMIO, irqs and other hw stuffs to domain0. 
> */
> 
> 
> NIT: s/domain0/dom0/
> 
>       +    rc = gic_map_hwdom_extra_mappings(d);
>       +    if ( rc < 0 )
>       +        return rc;
>       +
>             rc = platform_specific_mapping(d);
>             if ( rc < 0 )
>                 return rc;
>       diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
>       index 450755f..4a7d65a 100644
>       --- a/xen/arch/arm/gic-v2.c
>       +++ b/xen/arch/arm/gic-v2.c
>       @@ -21,6 +21,7 @@
>         #include <xen/lib.h>
>         #include <xen/init.h>
>         #include <xen/mm.h>
>       +#include <xen/vmap.h>
> 
> 
> Why do you need to include this header?
> 
> This header is used for "iounmap" API. 
> 
>               #include <xen/irq.h>
>               #include <xen/iocap.h>
>               #include <xen/sched.h>
>             @@ -66,6 +67,41 @@
>               #define GICH_V2_VMCR_PRIORITY_MASK   0x1f
>               #define GICH_V2_VMCR_PRIORITY_SHIFT  27
> 
>             +/* GICv2m extension register definitions. */
>             +/*
>             +* MSI_TYPER:
>             +*     [31:26] Reserved
>             +*     [25:16] lowest SPI assigned to MSI
>             +*     [15:10] Reserved
>             +*     [9:0]   Number of SPIs assigned to MSI
>             +*/
>             +#define V2M_MSI_TYPER               0x008
>             +#define V2M_MSI_TYPER_BASE_SHIFT    16
>             +#define V2M_MSI_TYPER_BASE_MASK     0x3FF
>             +#define V2M_MSI_TYPER_NUM_MASK      0x3FF
>             +#define V2M_MSI_SETSPI_NS           0x040
>             +#define V2M_MIN_SPI                 32
>             +#define V2M_MAX_SPI                 1019
>             +#define V2M_MSI_IIDR                0xFCC
>             +
>             +#define V2M_MSI_TYPER_BASE_SPI(x)   \
>             +                (((x) >> V2M_MSI_TYPER_BASE_SHIFT) & 
> V2M_MSI_TYPER_BASE_MASK)
>             +
>             +#define V2M_MSI_TYPER_NUM_SPI(x)    ((x) & 
> V2M_MSI_TYPER_NUM_MASK)
>             +
>             +struct v2m_data {
>             +    struct list_head entry;
>             +    /* Pointer to the DT node representing the v2m frame */
>             +    const struct dt_device_node *dt_node;
>             +    paddr_t addr; /* Register frame base */
>             +    paddr_t size; /* Register frame size */
>             +    u32 spi_start; /* The SPI number that MSIs start */
>             +    u32 nr_spis; /* The number of SPIs for MSIs */
>             +};
>             +
>             +/* v2m extension register frame information list */
>             +static LIST_HEAD(gicv2m_info);
>             +
>               /* Global state */
>               static struct {
>                   void __iomem * map_dbase; /* IO mapped Address of 
> distributor registers */
>             @@ -551,6 +587,173 @@ static void gicv2_irq_set_affinity(struct 
> irq_desc *desc, const cpumask_t *cpu_m
>                   spin_unlock(&gicv2.lock);
>               }
> 
>             +static int gicv2_map_hwdown_extra_mappings(struct domain *d)
>             +{
>             +    const struct v2m_data *v2m_data;
>             +
>             +    /*
>             +     * For the moment, we'll assign all v2m frames to a single 
> domain
>             +     * (i.e Domain0).
> 
> 
> NIT: s/Domain0/hardware domain/
> 
> Also, I would drop the i.e and say "... frames to the hardware domain."
> 
>       +     */
>       +    list_for_each_entry( v2m_data, &gicv2m_info, entry )
>       +    {
>       +        int ret, spi;
> 
> 
> Please use "u32" for the variable spi.
> 
>       +
>       +        printk("GICv2: Mapping v2m frame to domain%d: addr=0x%lx 
> size=0x%lx spi_base=%u num_spis=%u\n",
> 
> 
> NIT: You can shorten domain%d to d%d
> 
>       +               d->domain_id, v2m_data->addr, v2m_data->size,
>       +               v2m_data->spi_start, v2m_data->nr_spis);
>       +
>       +        ret = map_mmio_regions(d, paddr_to_pfn(v2m_data->addr),
>       +                               DIV_ROUND_UP(v2m_data->size, PAGE_SIZE),
>       +                               paddr_to_pfn(v2m_data->addr));
>       +        if ( ret )
>       +        {
>       +            printk(XENLOG_ERR
>       +                  "GICv2: Map v2m frame to domain%d failed.\n",
> 
> 
> Ditto.
> 
> Also the indentation looks wrong.
> 
> It's very strange. This indentation looks well in the patch file, and all 
> indentations are space chars.
> I'll try to send a revised patch.
> 
> 
>             +                   d->domain_id);
>             +            return ret;
>             +        }
>             +
>             +        /*
>             +         * Map all SPIs that are allocated to MSIs in a single 
> frame to the
> 
> 
>       s/in a single frame/for the frame/
> 
>             +         * domain.
>             +         */
>             +        for ( spi = v2m_data->spi_start;
>             +              spi < (v2m_data->spi_start + v2m_data->nr_spis); 
> spi++ )
>             +        {
>             +            /*
>             +             * MSIs are always edge-triggered. Configure the 
> associated SPIs
>             +             * to be edge-rising.
>             +             */
>             +            ret = irq_set_spi_type(spi, IRQ_TYPE_EDGE_RISING);
>             +            if ( ret )
>             +            {
>             +                printk(XENLOG_ERR
>             +                       "GICv2: Failed to set v2m MSI SPI[%d] 
> type.\n", spi);
>             +                return ret;
>             +            }
>             +
>             +            /* Route a SPI that is allocated to MSI to the 
> domain. */
>             +            ret = route_irq_to_guest(d, spi, spi, "v2m");
>             +            if ( ret )
>             +            {
>             +                printk(XENLOG_ERR
>             +                       "GICv2: Failed to route v2m MSI SPI[%d] 
> to Dom%d.\n",
>             +                        spi, d->domain_id);
>             +                return ret;
>             +            }
>             +
>             +            /* Reserve a SPI that is allocated to MSI for the 
> domain. */
>             +            if ( !vgic_reserve_virq(d, spi) )
>             +            {
>             +                printk(XENLOG_ERR
>             +                       "GICv2: Failed to reserve v2m MSI SPI[%d] 
> for Dom%d.\n",
>             +                        spi, d->domain_id);
>             +                return -EINVAL;
>             +            }
>             +        }
>             +    }
>             +
>             +    return 0;
>             +}
>             +
>             +/*
>             + * Set up gic v2m DT sub-node.
>             + * Please refer to the binding document:
>             + * 
> https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
>             + */
>             +static int gicv2m_make_dt_node(const struct domain *d,
>             +                              const struct dt_device_node *gic,
>             +                              void *fdt)
> 
> 
> The indentation looks wrong to me. It should be:
> 
> foo(const struct ...,
>     const struct ...
>     void *...)
> 
> Ditto. 
>             +{
>             +    u32 len;
>             +    int res;
>             +    const void *prop = NULL;
>             +    const struct dt_device_node *v2m = NULL;
>             +    const struct v2m_data *v2m_data;
>             +
>             +    /* The sub-nodes require the ranges property */
>             +    prop = dt_get_property(gic, "ranges", &len);
>             +    if ( !prop )
>             +    {
>             +        printk(XENLOG_ERR "Can't find ranges property for the 
> gic node\n");
>             +        return -FDT_ERR_XEN(ENOENT);
>             +    }
>             +
>             +    res = fdt_property(fdt, "ranges", prop, len);
>             +    if ( res )
>             +        return res;
>             +
>             +    list_for_each_entry( v2m_data, &gicv2m_info, entry )
>             +    {
>             +        v2m = v2m_data->dt_node;
>             +
>             +        printk("GICv2: Creating v2m DT node for domain%d: 
> addr=0x%lx size=0x%lx spi_base=%u num_spis=%u\n",
> 
> 
>       NIT: s/domain%d/d%d/
> 
>             +               d->domain_id, v2m_data->addr, v2m_data->size,
>             +               v2m_data->spi_start, v2m_data->nr_spis);
>             +
>             +        res = fdt_begin_node(fdt, v2m->name);
>             +        if ( res )
>             +            return res;
>             +
>             +        res = fdt_property_string(fdt, "compatible", 
> "arm,gic-v2m-frame");
>             +        if ( res )
>             +            return res;
>             +
>             +        res = fdt_property(fdt, "msi-controller", NULL, 0);
>             +        if ( res )
>             +            return res;
>             +
>             +        if ( v2m->phandle )
>             +        {
>             +            res = fdt_property_cell(fdt, "phandle", 
> v2m->phandle);
>             +            if ( res )
>             +                return res;
>             +        }
>             +
>             +        /* Use the same reg regions as v2m node in DTB. */
> 
> 
>       s/DTB/host DTB/ to make clear we are speaking about the host one and 
> not the guest one.
> 
>             +        prop = dt_get_property(v2m, "reg", &len);
>             +        if ( !prop )
>             +        {
>             +            printk(XENLOG_ERR "GICv2: Can't find v2m reg 
> property.\n");
>             +            res = -FDT_ERR_XEN(ENOENT);
>             +            return res;
>             +        }
>             +
>             +        res = fdt_property(fdt, "reg", prop, len);
>             +        if ( res )
>             +            return res;
>             +
>             +        /*
>             +         * Create msi-base-spi and msi-num-spis properties in 
> Guest DT to
>             +         * override the hardware setting. From the binding 
> document, we can
>             +         * find that these two properties are optional. But if 
> these two
>             +         * properties are present in the v2m DT node, the guest 
> v2m driver
>             +         * should read the configuration from these two 
> properties instead
>             +         * of reading from hardware register.
> 
> 
>       This paragraph is not clear. I would reword;
> 
>       "The properties msi-base-spi and msi-num-spis are used to override the 
> hardware settings. Therefore it is fine to always write them in the
>       guest DT.".
> 
>             +         */
>             +        res = fdt_property_u32(fdt, "arm,msi-base-spi", 
> v2m_data->spi_start);
>             +        if ( res )
>             +        {
>             +            printk(XENLOG_ERR
>             +                   "GICv2: Failed to create v2m msi-base-spi in 
> Guest DT.\n");
>             +            return res;
>             +        }
>             +
>             +        res = fdt_property_u32(fdt, "arm,msi-num-spis", 
> v2m_data->nr_spis);
>             +        if ( res )
>             +        {
>             +            printk(XENLOG_ERR
>             +                   "GICv2: Failed to create v2m msi-num-spis in 
> Guest DT.\n");
>             +            return res;
>             +        }
>             +
>             +        fdt_end_node(fdt);
>             +    }
>             +
>             +    return res;
>             +}
>             +
>               static int gicv2_make_hwdom_dt_node(const struct domain *d,
>                                                   const struct dt_device_node 
> *gic,
>                                                   void *fdt)
>             @@ -587,6 +790,10 @@ static int gicv2_make_hwdom_dt_node(const 
> struct domain *d,
>                   len *= 2;
> 
>                   res = fdt_property(fdt, "reg", regs, len);
>             +    if ( res )
>             +        return res;
>             +
>             +    res = gicv2m_make_dt_node(d, gic, fdt);
> 
>                   return res;
>               }
>             @@ -632,6 +839,77 @@ static bool_t gicv2_is_aliased(paddr_t 
> cbase, paddr_t csize)
>                   return ((val_low & 0xfff0fff) == 0x0202043B && val_low == 
> val_high);
>               }
> 
>             +static void gicv2_extension_dt_init(const struct dt_device_node 
> *node)
>             +{
>             +    int res;
>             +    u32 spi_start, nr_spis;
>             +    paddr_t addr, size;
>             +    const struct dt_device_node *v2m = NULL;
>             +
>             +    /*
>             +     * Check whether this GIC implements the v2m extension. If 
> so,
>             +     * add v2m register frames to gicv2m_info.
>             +     */
>             +    dt_for_each_child_node(node, v2m)
>             +    {
>             +        struct v2m_data *v2m_data;
>             +
>             +        if ( !dt_device_is_compatible(v2m, "arm,gic-v2m-frame") )
>             +            continue;
>             +
>             +        v2m_data = xzalloc_bytes(sizeof(struct v2m_data));
>             +        if ( !v2m_data )
>             +            panic("GICv2: Cannot allocate memory for v2m frame");
>             +
>             +        /*
>             +         * Check whether DT uses msi-base-spi and msi-num-spis 
> properties to
>             +         * override the hardware setting.
>             +         */
>             +        if ( !dt_property_read_u32(v2m, "arm,msi-base-spi", 
> &spi_start) ||
>             +             !dt_property_read_u32(v2m, "arm,msi-num-spis", 
> &nr_spis) )
>             +        {
>             +            u32 msi_typer;
>             +            void __iomem *base;
>             +
>             +            /*
>             +            * DT does not override the hardware setting, so we 
> have to read
>             +            * base_spi and num_spis from hardware registers to 
> reserve irqs.
>             +            */
>             +            res = dt_device_get_address(v2m, 0, &addr, &size);
>             +            if ( res )
>             +                panic("GICv2: Cannot find a valid v2m frame 
> address");
>             +
>             +            base = ioremap_nocache(addr, size);
>             +            if ( !base )
>             +                panic("GICv2: Cannot remap v2m register frame");
>             +
>             +            msi_typer = readl_relaxed(base + V2M_MSI_TYPER);
>             +            spi_start = V2M_MSI_TYPER_BASE_SPI(msi_typer);
>             +            nr_spis = V2M_MSI_TYPER_NUM_SPI(msi_typer);
>             +
>             +            iounmap(base);
>             +        }
>             +
>             +        /* Initialize a new entry to record new frame 
> infomation. */
>             +        INIT_LIST_HEAD(&v2m_data->entry);
>             +        v2m_data->addr = addr;
>             +        v2m_data->size = size;
>             +        v2m_data->spi_start = spi_start;
>             +        v2m_data->nr_spis = nr_spis;
>             +        v2m_data->dt_node = v2m;
>             +
>             +        printk("GICv2m extension register frame:\n"
>             +               "        gic_v2m_addr=%"PRIpaddr"\n"
>             +               "        gic_v2m_size=%"PRIpaddr"\n"
>             +               "        gic_v2m_spi_base=%u\n"
>             +               "        gic_v2m_num_spis=%u\n",
>             +               v2m_data->addr, v2m_data->size,
>             +               v2m_data->spi_start, v2m_data->nr_spis);
>             +
>             +        list_add_tail(&v2m_data->entry, &gicv2m_info);
> 
> 
> I would pull non-DT code in a separate function, so we can re-use the code 
> later for the support of GICv2m with ACPI.
> 
>       +    }
>       +}
>       +
>         static paddr_t __initdata hbase, dbase, cbase, csize, vbase;
> 
>         static void __init gicv2_dt_init(void)
>       @@ -683,6 +961,12 @@ static void __init gicv2_dt_init(void)
>             if ( csize != vsize )
>                 panic("GICv2: Sizes of GICC (%#"PRIpaddr") and GICV 
> (%#"PRIpaddr") don't match\n",
>                        csize, vsize);
>       +
>       +    /*
>       +     * Check whether this GIC implements the v2m extension. If so,
>       +     * add v2m register frames to gicv2_extension_info.
>       +     */
>       +    gicv2_extension_dt_init(node);
>         }
> 
>         static int gicv2_iomem_deny_access(const struct domain *d)
>       @@ -936,6 +1220,7 @@ const static struct gic_hw_operations gicv2_ops = {
>             .read_apr            = gicv2_read_apr,
>             .make_hwdom_dt_node  = gicv2_make_hwdom_dt_node,
>             .make_hwdom_madt     = gicv2_make_hwdom_madt,
>       +    .map_hwdom_extra_mappings = gicv2_map_hwdown_extra_mappings,
>             .iomem_deny_access   = gicv2_iomem_deny_access,
>         };
> 
>       diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>       index 2bfe4de..12bb0ab 100644
>       --- a/xen/arch/arm/gic.c
>       +++ b/xen/arch/arm/gic.c
>       @@ -230,6 +230,15 @@ int gic_irq_xlate(const u32 *intspec, unsigned int 
> intsize,
>             return 0;
>         }
> 
>       +/* Map extra GIC MMIO, irqs and other hw stuffs to the hardware 
> domain. */
>       +int gic_map_hwdom_extra_mappings(struct domain *d)
>       +{
>       +    if ( gic_hw_ops->map_hwdom_extra_mappings )
>       +        return gic_hw_ops->map_hwdom_extra_mappings(d);
>       +
>       +    return 0;
>       +}
>       +
>         static void __init gic_dt_preinit(void)
>         {
>             int rc;
>       diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>       index cd97bb2..836f1ad 100644
>       --- a/xen/include/asm-arm/gic.h
>       +++ b/xen/include/asm-arm/gic.h
>       @@ -360,6 +360,8 @@ struct gic_hw_operations {
>                                       const struct dt_device_node *gic, void 
> *fdt);
>             /* Create MADT table for the hardware domain */
>             int (*make_hwdom_madt)(const struct domain *d, u32 offset);
>       +    /* Map extra GIC MMIO, irqs and other hw stuffs to the hardware 
> domain. */
>       +    int (*map_hwdom_extra_mappings)(struct domain *d);
>             /* Deny access to GIC regions */
>             int (*iomem_deny_access)(const struct domain *d);
>         };
>       @@ -369,6 +371,7 @@ int gic_make_hwdom_dt_node(const struct domain *d,
>                                    const struct dt_device_node *gic,
>                                    void *fdt);
>         int gic_make_hwdom_madt(const struct domain *d, u32 offset);
>       +int gic_map_hwdom_extra_mappings(struct domain *d);
>         int gic_iomem_deny_access(const struct domain *d);
> 
>         #endif /* __ASSEMBLY__ */
> 
> 
> Regards,
> 
> --
> Julien Grall
> 
> 
> 
> 
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

Reply via email to