[PATCH v18 2/8] ARM: hisi: enable MCPM implementation

Nicolas Pitre nicolas.pitre at linaro.org
Tue Aug 12 19:19:12 PDT 2014


On Wed, 13 Aug 2014, Haojian Zhuang wrote:

> On 12 August 2014 23:52, Nicolas Pitre <nicolas.pitre at linaro.org> wrote:
> > On Tue, 12 Aug 2014, Haojian Zhuang wrote:
> >
> >> +static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
> >> +{
> >> +     unsigned long data, mask;
> >> +     void __iomem *sys_dreq, *sys_status;
> >> +
> >> +     if (!sysctrl)
> >> +             return -ENODEV;
> >> +     if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER)
> >> +             return -EINVAL;
> >> +
> >> +     spin_lock_irq(&boot_lock);
> >> +
> >> +     if (hip04_cpu_table[cluster][cpu])
> >> +             goto out;
> >> +
> >> +     sys_dreq = sysctrl + SC_CPU_RESET_DREQ(cluster);
> >> +     sys_status = sysctrl + SC_CPU_RESET_STATUS(cluster);
> >> +     if (hip04_cluster_is_down(cluster)) {
> >> +             data = CLUSTER_DEBUG_RESET_BIT;
> >> +             writel_relaxed(data, sys_dreq);
> >> +             do {
> >> +                     cpu_relax();
> >> +                     mask = CLUSTER_DEBUG_RESET_STATUS;
> >> +                     data = readl_relaxed(sys_status);
> >> +             } while (data & mask);
> >> +     }
> >> +
> >> +     data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
> >> +            CORE_DEBUG_RESET_BIT(cpu);
> >> +     writel_relaxed(data, sys_dreq);
> >> +     do {
> >> +             cpu_relax();
> >> +     } while (data == readl_relaxed(sys_status));
> >> +     udelay(20);
> >
> > You really need this even if the snoops aren't disabled in
> > hip04_mcpm_power_down() ?
> >
> 
> I really need this. Otherwise, I failed to power up core again. And I
> can't get any clue from document. It's based on tests.

Please add this explanation as a comment in the code.

> >> +out:
> >> +     hip04_cpu_table[cluster][cpu]++;
> >> +     spin_unlock_irq(&boot_lock);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static void hip04_mcpm_power_down(void)
> >> +{
> >> +     unsigned int mpidr, cpu, cluster;
> >> +     bool skip_wfi = false, last_man = 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_irq(&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_wfi = true;
> >> +     } else if (hip04_cpu_table[cluster][cpu] > 1) {
> >> +             pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu);
> >> +             BUG();
> >> +     }
> >> +
> >> +     last_man = hip04_cluster_is_down(cluster);
> >> +     if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> >> +             spin_unlock(&boot_lock);
> >> +             v7_exit_coherency_flush(all);
> >> +             __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> >> +     } else {
> >> +             spin_unlock(&boot_lock);
> >> +             v7_exit_coherency_flush(louis);
> >> +     }
> >> +
> >> +     __mcpm_cpu_down(cpu, cluster);
> >> +
> >> +     if (!skip_wfi)
> >> +             wfi();
> >> +}
> >> +
> >> +static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
> >> +{
> >> +     unsigned int data, tries, count;
> >> +
> >> +     BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
> >> +            cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
> >> +
> >> +     count = TIMEOUT_MSEC / POLL_MSEC;
> >
> > This count value doesn't make much sense anymore, does it?  Nothing
> > relates to POLL_MSEC afterwards.
> >
> Yes, you're right. I'll fix.
> 
> >> +     spin_lock_irq(&boot_lock);
> >> +     /*
> >> +      * Target core should enter WFI first.
> >> +      * Then cluster could be disabled in snoop filter.
> >> +      * At last, target core could be reset.
> >> +      */
> >
> > You should verify that the CPU usage count is still 0 here as I
> > suggested.
> >
> I'll move the checking at here. And report error if the count is still 0.
> 
> >> +     for (tries = 0; tries < count; tries++) {
> >> +             cpu_relax();
> >
> > There is probably no point calling cpu_relax() if it is followed by
> > udelay().
> >
> This delay is required for power down the cluster. I should check if
> all cores in cluster should be down.

My point is: if you call udelay() then you don't need cpu_relax().

> If I removed the delay, I found that kernel panic reports. I guess
> that L2 is still in the process of clean.
> 
> With this delay, everything works well. I failed to find a command to
> clean L2 in coretex a15. It seems that I have to disable MMU & C bit
> in target cpu. It worth trying but I need more time. So as a
> workaround, I use udelay(50) at here.

Please add this explanation to a comment in the code.

> >> +             udelay(50);
> >> +             data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
> >> +             if (!hip04_cpu_table[cluster][cpu] || \
> >> +                 (data & CORE_WFI_STATUS(cpu))) {
> >> +                     break;
> >> +             }
> >> +     }
> >> +     if (tries >= count)
> >> +             goto err;
> >> +     if (hip04_cluster_is_down(cluster))
> >> +             hip04_set_snoop_filter(cluster, 0);
> >> +     data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
> >> +            CORE_DEBUG_RESET_BIT(cpu);
> >> +     writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
> >> +     for (tries = 0; tries < count; tries++) {
> >> +             cpu_relax();
> >> +             udelay(50);
> >> +             data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
> >> +             if (!hip04_cpu_table[cluster][cpu] || \
> >> +                 (data & CORE_RESET_STATUS(cpu))) {
> >> +                     break;
> >> +             }
> >> +     }
> >> +     if (tries >= count)
> >> +             goto err;
> >> +     spin_unlock_irq(&boot_lock);
> >> +     return 0;
> >> +err:
> >> +     spin_unlock_irq(&boot_lock);
> >> +     return -EBUSY;
> >> +}
> >
> > I don't really like the way things are done in general.  And we're
> > apparently going in circle over this. This is almost like if MCPM was of
> > no benefit to you given all the things which look "wrong".  But given
> > that no usable documentation is available, preventing me and others from
> > suggesting better ways, then this platform is going to be limited to
> > suboptimal CPU hotplug support.  So if you fix the minor issues I've
> > noted above then I'll provide my reluctant ACK for this patch if nothing
> > else can be helped.
> >
> OK. I'll fix them. But I can't delete these delay. Otherwise, I may
> meet failure on hotplug.

Those are hacks.  I want them to be commented as such please.


Nicolas



More information about the linux-arm-kernel mailing list