Thread (47 messages) 47 messages, 7 authors, 2014-07-01
STALE4382d

[PATCH v7 06/15] ARM: hisi: enable MCPM implementation

From: haojian.zhuang@linaro.org (Haojian Zhuang)
Date: 2014-05-15 06:23:43

On 14 May 2014 03:43, Nicolas Pitre [off-list ref] wrote:
On Tue, 13 May 2014, Haojian Zhuang wrote:
quoted
Multiple CPU clusters are used in Hisilicon HiP04 SoC. Now use MCPM
framework to manage power on HiP04 SoC.

Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
Some more comments...

[...]
quoted
+static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
+{
+     unsigned long data;
+
+     if (!fabric)
+             return;
How could this validly be NULL?
OK. I'll make it report BUG.
quoted
+     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;
+     }
+}
The above could be easily coded in assembly for the power_up_setup
callback thusly:

hip04_power_up_setup:

        cmp     r0, #0                  @ check affinity level
        bxeq    lr                      @ nothing to do at CPU level

        mrc     p15, 0, r0, c0, c0, 5   @ get MPIDR
        ubfx    r0, r0, #8, #8          @ extract cluster number

        adr     r1, .LC0
        ldmia   r1, {r2, r3}
        sub     r2, r2, r1              @ virt_addr - phys_addr
        ldr     r1, [r2, r3]            @ get fabric_phys_addr
        mov     r2, #1
        ldr     r3, [r1, #FAB_SF_MODE]  @ read "data"
        orr     r3, r3, r2, lsl r0      @ set cluster bit
        str     r3, [r1, #FAB_SF_MODE]  @ write it back

1:      ldr     r2, [r1, #FAB_SF_MODE]  @ read register content
        cmp     r2, r3                  @ make sure it matches
        bne     1b                      @ otherwise retry

        bx      lr

:LC0:   .word   .
        .word   fabric_phys_addr - .LC0

That should be it.
No. These code should be executed before new CPU on. If I transfer
them to assembler code, it means that code will be executed after
new CPU on.

Then it results me failing to make new CPU online.
quoted
+static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
+{
+     unsigned long data, mask;
+
+     if (!relocation || !sysctrl)
+             return -ENODEV;
+     if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER)
+             return -EINVAL;
+
+     spin_lock_irq(&boot_lock);
+     writel_relaxed(hip04_boot.bootwrapper_phys, relocation);
+     writel_relaxed(hip04_boot.bootwrapper_magic, relocation + 4);
+     writel_relaxed(virt_to_phys(mcpm_entry_point), relocation + 8);
+     writel_relaxed(0, relocation + 12);
Shouldn't you do the above writes only when
hip04_cpu_table[cluster][cpu] is zero?  Please see the comment in
mcpm_cpu_power_down() about unordered calls.
OK. I can add the check.
quoted
+     if (hip04_cluster_down(cluster)) {
+             data = CLUSTER_DEBUG_RESET_BIT;
+             writel_relaxed(data, sysctrl + SC_CPU_RESET_DREQ(cluster));
+             do {
+                     mask = CLUSTER_DEBUG_RESET_STATUS;
+                     data = readl_relaxed(sysctrl + \
+                                          SC_CPU_RESET_STATUS(cluster));
+             } while (data & mask);
+             hip04_set_snoop_filter(cluster, 1);
+     }
+
+     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));
+     spin_unlock_irq(&boot_lock);
+     msleep(POLL_MSEC);
+
+     return 0;
+}
+
+static void hip04_mcpm_power_down(void)
+{
+     unsigned int mpidr, cpu, cluster, data = 0;
+     bool skip_reset = false;
+
+     mpidr = read_cpuid_mpidr();
+     cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+     cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+     __mcpm_cpu_going_down(cpu, cluster);
+
+     spin_lock(&boot_lock);
+     BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+     hip04_cpu_table[cluster][cpu]--;
+     if (hip04_cpu_table[cluster][cpu] == 1) {
+             /* A power_up request went ahead of us. */
+             skip_reset = true;
+     } else if (hip04_cpu_table[cluster][cpu] > 1) {
+             pr_err("Cluster %d CPU%d is still running\n", cluster, cpu);
This message is misleading.  If execution gets here, that means
mcpm_cpu_power_up() was called more than twice in a row for the same CPU
which should never happen.
OK. I'll replace the comments.
quoted
+             BUG();
+     }
+
+     spin_unlock(&boot_lock);
+
+     v7_exit_coherency_flush(louis);
+
+     __mcpm_cpu_down(cpu, cluster);
+
+     if (!skip_reset) {
+             data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
+                    CORE_DEBUG_RESET_BIT(cpu);
+             writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
You should not perform this outside the lock protected region as this
could race with hip04_mcpm_power_up().  Instead, this should be done
above when hip04_cpu_table[cluster][cpu] == 0 after being decremented.
No. power_down() is executed on the specified CPU. If spin_unlock() is
placed after reset operation, it means that there's no chance to
execute
the spin_unlock(). Because CPU is already in reset mode at this time.

Regards
Haojian
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help