diff mbox

[Xen-devel,v2,2/7] xen/arm: Implement hip04-d01 platform

Message ID 1415033196-30529-3-git-send-email-frediano.ziglio@huawei.com
State New
Headers show

Commit Message

Frediano Ziglio Nov. 3, 2014, 4:46 p.m. UTC
Add this new platform to Xen.
This platform requires specific code to initialize CPUs.

Signed-off-by: Frediano Ziglio <frediano.ziglio@huawei.com>
Signed-off-by: Zoltan Kiss <zoltan.kiss@huawei.com>
---
 xen/arch/arm/platforms/Makefile |   1 +
 xen/arch/arm/platforms/hip04.c  | 308 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 309 insertions(+)
 create mode 100644 xen/arch/arm/platforms/hip04.c

Comments

Julien Grall Nov. 4, 2014, 1:21 p.m. UTC | #1
Hi Frediano,

On 11/03/2014 04:46 PM, Frediano Ziglio wrote:
> Add this new platform to Xen.
> This platform requires specific code to initialize CPUs.

I guess your platform doesn't support PSCI?

> Signed-off-by: Frediano Ziglio <frediano.ziglio@huawei.com>
> Signed-off-by: Zoltan Kiss <zoltan.kiss@huawei.com>
> ---
> +static void hip04_reset(void)
> +{
> +    unsigned long data;
> +
> +    if ( !gb2 )
> +        return;

gb2 will never be NULL. Xen will panic if the initialization callback
failed.

> +
> +    data = readl_relaxed(gb2);
> +    writel_relaxed(data & ~0x4000000u, gb2);
> +
> +    mdelay(10);
> +}
> +
> +static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
> +{
> +    unsigned long data;
> +
> +    if ( !fabric )
> +        return;

Ditto.


[..]

> +static void __init hip04_iounmap(void __iomem **p)
> +{
> +    if ( *p )
> +    {
> +        iounmap(*p);
> +        *p = NULL;
> +    }
> +}

What is used for? Should not iounmap enough?

Regards,
Frediano Ziglio Nov. 4, 2014, 1:52 p.m. UTC | #2
> 
> Hi Frediano,
> 
> On 11/03/2014 04:46 PM, Frediano Ziglio wrote:
> > Add this new platform to Xen.
> > This platform requires specific code to initialize CPUs.
> 
> I guess your platform doesn't support PSCI?
> 

No, there is no PSCI support.

> > Signed-off-by: Frediano Ziglio <frediano.ziglio@huawei.com>
> > Signed-off-by: Zoltan Kiss <zoltan.kiss@huawei.com>
> > ---
> > +static void hip04_reset(void)
> > +{
> > +    unsigned long data;
> > +
> > +    if ( !gb2 )
> > +        return;
> 
> gb2 will never be NULL. Xen will panic if the initialization callback
> failed.
> 
> > +
> > +    data = readl_relaxed(gb2);
> > +    writel_relaxed(data & ~0x4000000u, gb2);
> > +
> > +    mdelay(10);
> > +}
> > +
> > +static void hip04_set_snoop_filter(unsigned int cluster, unsigned
> int
> > +on) {
> > +    unsigned long data;
> > +
> > +    if ( !fabric )
> > +        return;
> 
> Ditto.
> 

Done

> 
> [..]
> 
> > +static void __init hip04_iounmap(void __iomem **p) {
> > +    if ( *p )
> > +    {
> > +        iounmap(*p);
> > +        *p = NULL;
> > +    }
> > +}
> 
> What is used for? Should not iounmap enough?
> 

I just like to clear pointers after freeing them.

Frediano
Julien Grall Nov. 4, 2014, 2:03 p.m. UTC | #3
On 11/04/2014 01:52 PM, Frediano Ziglio wrote:
>>
>> [..]
>>
>>> +static void __init hip04_iounmap(void __iomem **p) {
>>> +    if ( *p )
>>> +    {
>>> +        iounmap(*p);
>>> +        *p = NULL;
>>> +    }
>>> +}
>>
>> What is used for? Should not iounmap enough?
>>
> 
> I just like to clear pointers after freeing them.

It's not really useful :).

If you really want to keep the *p = NULL. This could be simplify into:

hip04_iounmap(....)
{
   iounmap(*p);
   *p = NULL;
}

This is because iounmap takes care of NULL pointer.

Regards,
Frediano Ziglio Nov. 4, 2014, 2:17 p.m. UTC | #4
> On 11/04/2014 01:52 PM, Frediano Ziglio wrote:
> >>
> >> [..]
> >>
> >>> +static void __init hip04_iounmap(void __iomem **p) {
> >>> +    if ( *p )
> >>> +    {
> >>> +        iounmap(*p);
> >>> +        *p = NULL;
> >>> +    }
> >>> +}
> >>
> >> What is used for? Should not iounmap enough?
> >>
> >
> > I just like to clear pointers after freeing them.
> 
> It's not really useful :).
> 

Just paranoia :)
Never liked dandling pointers.

> If you really want to keep the *p = NULL. This could be simplify into:
> 
> hip04_iounmap(....)
> {
>    iounmap(*p);
>    *p = NULL;
> }
> 
> This is because iounmap takes care of NULL pointer.
> 

Are you sure? I looked at code and is not a simple vm_free call, it does some mapping even if address is NULL.

Regards,
  Frediano
Julien Grall Nov. 4, 2014, 2:23 p.m. UTC | #5
On 11/04/2014 02:17 PM, Frediano Ziglio wrote:
>> If you really want to keep the *p = NULL. This could be simplify into:
>>
>> hip04_iounmap(....)
>> {
>>    iounmap(*p);
>>    *p = NULL;
>> }
>>
>> This is because iounmap takes care of NULL pointer.
>>
> 
> Are you sure? I looked at code and is not a simple vm_free call, it does some mapping even if address is NULL.

Yes, vm_size(va) will return 0 and destroy_xen_mappings won't unmap
anything because start == end.

I agree that an explicit check in vunmap would be nice.

Regards,
diff mbox

Patch

diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile
index 8f47c16..d0b2d99 100644
--- a/xen/arch/arm/platforms/Makefile
+++ b/xen/arch/arm/platforms/Makefile
@@ -5,4 +5,5 @@  obj-$(CONFIG_ARM_32) += midway.o
 obj-$(CONFIG_ARM_32) += omap5.o
 obj-$(CONFIG_ARM_32) += sunxi.o
 obj-$(CONFIG_ARM_64) += seattle.o
+obj-$(CONFIG_ARM_32) += hip04.o
 obj-$(CONFIG_ARM_64) += xgene-storm.o
diff --git a/xen/arch/arm/platforms/hip04.c b/xen/arch/arm/platforms/hip04.c
new file mode 100644
index 0000000..799b5b3
--- /dev/null
+++ b/xen/arch/arm/platforms/hip04.c
@@ -0,0 +1,308 @@ 
+/*
+ * xen/arch/arm/platforms/hip04.c
+ *
+ * HiSilicon HIP-04 D01 board
+ *
+ * Copyright (c) 2012-2013 Hisilicon Ltd.
+ * Copyright (c) 2012-2013 Linaro Ltd.
+ * Copyright (c) 2014 Huawei Tech. Co., Ltd.
+ *
+ * Author: Frediano Ziglio <frediano.ziglio@huawei.com>
+ *
+ * Original code from Linux kernel arch/arm/mach-hisi/hisilicon.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/platform.h>
+#include <xen/mm.h>
+#include <xen/vmap.h>
+#include <asm/io.h>
+#include <asm/gic.h>
+#include <xen/delay.h>
+
+#define CORE_RESET_BIT(x)            (1 << x)
+#define NEON_RESET_BIT(x)            (1 << (x + 4))
+#define CORE_DEBUG_RESET_BIT(x)      (1 << (x + 9))
+#define CLUSTER_L2_RESET_BIT         (1 << 8)
+#define CLUSTER_DEBUG_RESET_BIT      (1 << 13)
+
+#define CLUSTER_L2_RESET_STATUS      (1 << 8)
+#define CLUSTER_DEBUG_RESET_STATUS   (1 << 13)
+
+#define SC_CPU_RESET_DREQ(x)         (0x524 + (x << 3))    /* unreset */
+#define SC_CPU_RESET_STATUS(x)       (0x1520 + (x << 3))
+
+#define FAB_SF_MODE                  0x0c
+
+#define HIP04_MAX_CLUSTERS           4
+#define HIP04_MAX_CPUS_PER_CLUSTER   4
+
+struct hip04_secondary_cpu_data
+{
+    u32 bootwrapper_phys;
+    u32 bootwrapper_size;
+    u32 bootwrapper_magic;
+    u32 relocation_entry;
+    u32 relocation_size;
+};
+
+static void __iomem *relocation, *sysctrl, *fabric, *gb2;
+static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER];
+static struct hip04_secondary_cpu_data hip04_boot;
+
+static void hip04_reset(void)
+{
+    unsigned long data;
+
+    if ( !gb2 )
+        return;
+
+    data = readl_relaxed(gb2);
+    writel_relaxed(data & ~0x4000000u, gb2);
+
+    mdelay(10);
+}
+
+static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
+{
+    unsigned long data;
+
+    if ( !fabric )
+        return;
+    data = readl_relaxed(fabric + FAB_SF_MODE);
+    if ( on )
+        data |= 1 << cluster;
+    else
+        data &= ~(1 << cluster);
+    writel_relaxed(data, fabric + FAB_SF_MODE);
+    while ( 1 )
+    {
+        if ( data == readl_relaxed(fabric + FAB_SF_MODE) )
+            break;
+    }
+}
+
+static bool __init hip04_cpu_table_init(void)
+{
+    unsigned int mpidr, cpu, cluster;
+
+    mpidr = cpu_logical_map(smp_processor_id());
+    cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+    cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+    if ( cluster >= HIP04_MAX_CLUSTERS ||
+        cpu >= HIP04_MAX_CPUS_PER_CLUSTER )
+    {
+        printk(XENLOG_ERR "%s: boot CPU is out of bound!\n", __func__);
+        return false;
+    }
+
+    hip04_set_snoop_filter(cluster, 1);
+    hip04_cpu_table[cluster][cpu] = 1;
+    return true;
+}
+
+static bool hip04_cluster_down(unsigned int cluster)
+{
+    int i;
+
+    for ( i = 0; i < HIP04_MAX_CPUS_PER_CLUSTER; i++ )
+        if ( hip04_cpu_table[cluster][i] )
+            return false;
+    return true;
+}
+
+static void hip04_cluster_up(unsigned int cluster)
+{
+    unsigned long data, mask;
+
+    if ( !hip04_cluster_down(cluster) )
+        return;
+
+    data = CLUSTER_L2_RESET_BIT | CLUSTER_DEBUG_RESET_BIT;
+    writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+    do {
+        mask = CLUSTER_L2_RESET_STATUS | \
+               CLUSTER_DEBUG_RESET_STATUS;
+        data = readl_relaxed(sysctrl + \
+                     SC_CPU_RESET_STATUS(cluster));
+    } while ( data & mask );
+    hip04_set_snoop_filter(cluster, 1);
+}
+
+static void __init hip04_iounmap(void __iomem **p)
+{
+    if ( *p )
+    {
+        iounmap(*p);
+        *p = NULL;
+    }
+}
+
+static int __init hip04_smp_init(void)
+{
+    const struct dt_device_node *np, *np_fab, *bw;
+    const char *msg;
+    u64 addr, size;
+
+    np = dt_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+    msg = "hisilicon,sysctrl missing in DT\n";
+    if ( !np )
+        goto err;
+
+    np_fab = dt_find_compatible_node(NULL, NULL, "hisilicon,hip04-fabric");
+    msg = "hisilicon,hip04-fabric missing in DT\n";
+    if ( !np_fab )
+        goto err;
+
+    if ( !dt_property_read_u32(np, "bootwrapper-phys",
+                               &hip04_boot.bootwrapper_phys) ) {
+        u32 boot_method[4];
+        bw = dt_find_compatible_node(NULL, NULL, "hisilicon,hip04-bootwrapper");
+        msg = "hisilicon,hip04-bootwrapper missing in DT\n";
+        if ( !bw )
+            goto err;
+
+        msg = "failed to get boot-method\n";
+        if ( !dt_property_read_u32_array(bw, "boot-method", boot_method, 4) )
+            goto err;
+        hip04_boot.bootwrapper_phys = boot_method[0];
+        hip04_boot.bootwrapper_size = boot_method[1];
+        hip04_boot.bootwrapper_magic = 0xa5a5a5a5;
+        hip04_boot.relocation_entry = boot_method[2];
+        hip04_boot.relocation_size = boot_method[3];
+    }
+    else
+    {
+        msg = "failed to get bootwrapper-size\n";
+        if ( !dt_property_read_u32(np, "bootwrapper-size",
+                                   &hip04_boot.bootwrapper_size) )
+            goto err;
+
+        msg = "failed to get bootwrapper-magic\n";
+        if ( !dt_property_read_u32(np, "bootwrapper-magic",
+                                   &hip04_boot.bootwrapper_magic) )
+            goto err;
+
+        msg = "failed to get relocation-entry\n";
+        if ( !dt_property_read_u32(np, "relocation-entry",
+                                   &hip04_boot.relocation_entry) )
+            goto err;
+
+        msg = "failed to get relocation-size\n";
+        if ( !dt_property_read_u32(np, "relocation-size",
+                                   &hip04_boot.relocation_size) )
+            goto err;
+    }
+
+    relocation = ioremap_nocache(hip04_boot.relocation_entry,
+                                 hip04_boot.relocation_size);
+    msg = "failed to map relocation space\n";
+    if ( !relocation )
+        goto err;
+
+    msg = "Error in \"hisilicon,sysctrl\"\n";
+    if ( dt_device_get_address(np, 0, &addr, &size) )
+        goto err;
+    sysctrl = ioremap_nocache(addr, size);
+    if ( !sysctrl )
+        goto err;
+
+    msg = "Error in \"hisilicon,hip04-fabric\"\n";
+    if ( dt_device_get_address(np_fab, 0, &addr, &size) )
+        goto err;
+    fabric = ioremap_nocache(addr, size);
+    if ( !fabric )
+        goto err;
+
+    msg = "Error mapping GB2\n";
+    gb2 = ioremap_nocache(0xe4002000, 0x1000);
+    if ( !gb2 )
+        goto err;
+
+    msg = "Error initializing SMP table\n";
+    if ( !hip04_cpu_table_init() )
+        goto err;
+
+    writel_relaxed(hip04_boot.bootwrapper_phys, relocation);
+    writel_relaxed(hip04_boot.bootwrapper_magic, relocation + 4);
+    writel_relaxed(__pa(init_secondary), relocation + 8);
+    writel_relaxed(0, relocation + 12);
+
+    return 0;
+
+err:
+    hip04_iounmap(&relocation);
+    hip04_iounmap(&sysctrl);
+    hip04_iounmap(&fabric);
+    hip04_iounmap(&gb2);
+
+    printk("%s", msg);
+    return -ENXIO;
+}
+
+static int hip04_cpu_up(int cpu)
+{
+    unsigned int cluster;
+    unsigned long data;
+
+    cluster = cpu / HIP04_MAX_CPUS_PER_CLUSTER;
+    cpu %= HIP04_MAX_CPUS_PER_CLUSTER;
+
+    writel_relaxed(hip04_boot.bootwrapper_phys, relocation);
+    writel_relaxed(hip04_boot.bootwrapper_magic, relocation + 4);
+    writel_relaxed(__pa(init_secondary), relocation + 8);
+    writel_relaxed(0, relocation + 12);
+
+    hip04_cluster_up(cluster);
+
+    hip04_cpu_table[cluster][cpu]++;
+
+    data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+           CORE_DEBUG_RESET_BIT(cpu);
+    writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+
+    return cpu_up_send_sgi(cpu);
+}
+
+
+static const char * const hip04_dt_compat[] __initconst =
+{
+    "hisilicon,hip04-d01",
+    NULL
+};
+
+static const struct dt_device_match hip04_blacklist_dev[] __initconst =
+{
+    /* Hardware power management */
+    DT_MATCH_COMPATIBLE("hisilicon,sysctrl"),
+    DT_MATCH_COMPATIBLE("hisilicon,hip04-fabric"),
+    { /* sentinel */ },
+};
+
+
+PLATFORM_START(hip04, "HISILICON HIP04")
+    .compatible = hip04_dt_compat,
+    .smp_init = hip04_smp_init,
+    .cpu_up = hip04_cpu_up,
+    .reset = hip04_reset,
+    .blacklist_dev = hip04_blacklist_dev,
+PLATFORM_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */