Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: sun9i: smp: Support cpu0 hotplug

The BROM has a branch that checks if the primary core is hotplugging.
If the magic flag is set, execution jumps to the address set in the
software entry register. (Secondary cores always branch to the that
address.)

This patch sets the flags that makes BROM jump execution on the
primary core (cpu0) to the SMP software entry code when the core is
powered back up. After it is re-integrated into the system, the flag
is cleared.

A custom .cpu_can_disable callback that returns true for all cpus,
so that cpu0 can really be brought down.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>

+56 -3
+56 -3
arch/arm/mach-sunxi/mc_smp.c
··· 65 65 #define PRCM_PWR_SWITCH_REG(c, cpu) (0x140 + 0x10 * (c) + 0x4 * (cpu)) 66 66 #define PRCM_CPU_SOFT_ENTRY_REG 0x164 67 67 68 + #define CPU0_SUPPORT_HOTPLUG_MAGIC0 0xFA50392F 69 + #define CPU0_SUPPORT_HOTPLUG_MAGIC1 0x790DCA3A 70 + 68 71 static void __iomem *cpucfg_base; 69 72 static void __iomem *prcm_base; 73 + static void __iomem *sram_b_smp_base; 70 74 71 75 static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster) 72 76 { ··· 129 125 return 0; 130 126 } 131 127 128 + static void sunxi_cpu0_hotplug_support_set(bool enable) 129 + { 130 + if (enable) { 131 + writel(CPU0_SUPPORT_HOTPLUG_MAGIC0, sram_b_smp_base); 132 + writel(CPU0_SUPPORT_HOTPLUG_MAGIC1, sram_b_smp_base + 0x4); 133 + } else { 134 + writel(0x0, sram_b_smp_base); 135 + writel(0x0, sram_b_smp_base + 0x4); 136 + } 137 + } 138 + 132 139 static int sunxi_cpu_powerup(unsigned int cpu, unsigned int cluster) 133 140 { 134 141 u32 reg; ··· 147 132 pr_debug("%s: cluster %u cpu %u\n", __func__, cluster, cpu); 148 133 if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS) 149 134 return -EINVAL; 135 + 136 + /* Set hotplug support magic flags for cpu0 */ 137 + if (cluster == 0 && cpu == 0) 138 + sunxi_cpu0_hotplug_support_set(true); 150 139 151 140 /* assert processor power-on reset */ 152 141 reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster)); ··· 381 362 return true; 382 363 } 383 364 365 + static void sunxi_mc_smp_secondary_init(unsigned int cpu) 366 + { 367 + /* Clear hotplug support magic flags for cpu0 */ 368 + if (cpu == 0) 369 + sunxi_cpu0_hotplug_support_set(false); 370 + } 371 + 384 372 static int sunxi_mc_smp_boot_secondary(unsigned int l_cpu, struct task_struct *idle) 385 373 { 386 374 unsigned int mpidr, cpu, cluster; ··· 598 572 return !ret; 599 573 } 600 574 575 + static bool sunxi_mc_smp_cpu_can_disable(unsigned int __unused) 576 + { 577 + return true; 578 + } 601 579 #endif 602 580 603 581 static const struct smp_operations sunxi_mc_smp_smp_ops __initconst = { 582 + .smp_secondary_init = sunxi_mc_smp_secondary_init, 604 583 .smp_boot_secondary = sunxi_mc_smp_boot_secondary, 605 584 #ifdef CONFIG_HOTPLUG_CPU 606 585 .cpu_die = sunxi_mc_smp_cpu_die, 607 586 .cpu_kill = sunxi_mc_smp_cpu_kill, 587 + .cpu_can_disable = sunxi_mc_smp_cpu_can_disable, 608 588 #endif 609 589 }; 610 590 ··· 686 654 687 655 static int __init sunxi_mc_smp_init(void) 688 656 { 689 - struct device_node *cpucfg_node, *node; 657 + struct device_node *cpucfg_node, *sram_node, *node; 690 658 struct resource res; 691 659 int ret; 692 660 ··· 734 702 goto err_put_cpucfg_node; 735 703 } 736 704 705 + sram_node = of_find_compatible_node(NULL, NULL, 706 + "allwinner,sun9i-a80-smp-sram"); 707 + if (!sram_node) { 708 + ret = -ENODEV; 709 + goto err_unmap_release_cpucfg; 710 + } 711 + 712 + sram_b_smp_base = of_io_request_and_map(sram_node, 0, "sunxi-mc-smp"); 713 + if (IS_ERR(sram_b_smp_base)) { 714 + ret = PTR_ERR(sram_b_smp_base); 715 + pr_err("%s: failed to map secure SRAM\n", __func__); 716 + goto err_put_sram_node; 717 + } 718 + 737 719 /* Configure CCI-400 for boot cluster */ 738 720 ret = sunxi_mc_smp_lookback(); 739 721 if (ret) { 740 722 pr_err("%s: failed to configure boot cluster: %d\n", 741 723 __func__, ret); 742 - goto err_unmap_release_cpucfg; 724 + goto err_unmap_release_secure_sram; 743 725 } 744 726 745 - /* We don't need the CPUCFG device node anymore */ 727 + /* We don't need the CPUCFG and SRAM device nodes anymore */ 746 728 of_node_put(cpucfg_node); 729 + of_node_put(sram_node); 747 730 748 731 /* Set the hardware entry point address */ 749 732 writel(__pa_symbol(sunxi_mc_smp_secondary_startup), ··· 771 724 772 725 return 0; 773 726 727 + err_unmap_release_secure_sram: 728 + iounmap(sram_b_smp_base); 729 + of_address_to_resource(sram_node, 0, &res); 730 + release_mem_region(res.start, resource_size(&res)); 731 + err_put_sram_node: 732 + of_node_put(sram_node); 774 733 err_unmap_release_cpucfg: 775 734 iounmap(cpucfg_base); 776 735 of_address_to_resource(cpucfg_node, 0, &res);