platsmp.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * arch/arm/mach-spear13xx/platsmp.c
  4. *
  5. * based upon linux/arch/arm/mach-realview/platsmp.c
  6. *
  7. * Copyright (C) 2012 ST Microelectronics Ltd.
  8. * Shiraz Hashim <[email protected]>
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/jiffies.h>
  12. #include <linux/io.h>
  13. #include <linux/smp.h>
  14. #include <asm/cacheflush.h>
  15. #include <asm/smp_scu.h>
  16. #include "spear.h"
  17. #include "generic.h"
  18. /* XXX spear_pen_release is cargo culted code - DO NOT COPY XXX */
  19. volatile int spear_pen_release = -1;
  20. /*
  21. * XXX CARGO CULTED CODE - DO NOT COPY XXX
  22. *
  23. * Write spear_pen_release in a way that is guaranteed to be visible to
  24. * all observers, irrespective of whether they're taking part in coherency
  25. * or not. This is necessary for the hotplug code to work reliably.
  26. */
  27. static void spear_write_pen_release(int val)
  28. {
  29. spear_pen_release = val;
  30. smp_wmb();
  31. sync_cache_w(&spear_pen_release);
  32. }
  33. static DEFINE_SPINLOCK(boot_lock);
  34. static void __iomem *scu_base = IOMEM(VA_SCU_BASE);
  35. static void spear13xx_secondary_init(unsigned int cpu)
  36. {
  37. /*
  38. * let the primary processor know we're out of the
  39. * pen, then head off into the C entry point
  40. */
  41. spear_write_pen_release(-1);
  42. /*
  43. * Synchronise with the boot thread.
  44. */
  45. spin_lock(&boot_lock);
  46. spin_unlock(&boot_lock);
  47. }
  48. static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
  49. {
  50. unsigned long timeout;
  51. /*
  52. * set synchronisation state between this boot processor
  53. * and the secondary one
  54. */
  55. spin_lock(&boot_lock);
  56. /*
  57. * The secondary processor is waiting to be released from
  58. * the holding pen - release it, then wait for it to flag
  59. * that it has been released by resetting spear_pen_release.
  60. *
  61. * Note that "spear_pen_release" is the hardware CPU ID, whereas
  62. * "cpu" is Linux's internal ID.
  63. */
  64. spear_write_pen_release(cpu);
  65. timeout = jiffies + (1 * HZ);
  66. while (time_before(jiffies, timeout)) {
  67. smp_rmb();
  68. if (spear_pen_release == -1)
  69. break;
  70. udelay(10);
  71. }
  72. /*
  73. * now the secondary core is starting up let it run its
  74. * calibrations, then wait for it to finish
  75. */
  76. spin_unlock(&boot_lock);
  77. return spear_pen_release != -1 ? -ENOSYS : 0;
  78. }
  79. /*
  80. * Initialise the CPU possible map early - this describes the CPUs
  81. * which may be present or become present in the system.
  82. */
  83. static void __init spear13xx_smp_init_cpus(void)
  84. {
  85. unsigned int i, ncores = scu_get_core_count(scu_base);
  86. if (ncores > nr_cpu_ids) {
  87. pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
  88. ncores, nr_cpu_ids);
  89. ncores = nr_cpu_ids;
  90. }
  91. for (i = 0; i < ncores; i++)
  92. set_cpu_possible(i, true);
  93. }
  94. static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus)
  95. {
  96. scu_enable(scu_base);
  97. /*
  98. * Write the address of secondary startup into the system-wide location
  99. * (presently it is in SRAM). The BootMonitor waits until it receives a
  100. * soft interrupt, and then the secondary CPU branches to this address.
  101. */
  102. __raw_writel(__pa_symbol(spear13xx_secondary_startup), SYS_LOCATION);
  103. }
  104. const struct smp_operations spear13xx_smp_ops __initconst = {
  105. .smp_init_cpus = spear13xx_smp_init_cpus,
  106. .smp_prepare_cpus = spear13xx_smp_prepare_cpus,
  107. .smp_secondary_init = spear13xx_secondary_init,
  108. .smp_boot_secondary = spear13xx_boot_secondary,
  109. #ifdef CONFIG_HOTPLUG_CPU
  110. .cpu_die = spear13xx_cpu_die,
  111. #endif
  112. };