platsmp.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * linux/arch/arm/plat-versatile/platsmp.c
  3. *
  4. * Copyright (C) 2002 ARM Ltd.
  5. * All Rights Reserved
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/init.h>
  12. #include <linux/errno.h>
  13. #include <linux/delay.h>
  14. #include <linux/device.h>
  15. #include <linux/jiffies.h>
  16. #include <linux/smp.h>
  17. #include <asm/cacheflush.h>
  18. #include <asm/smp_plat.h>
  19. /*
  20. * control for which core is the next to come out of the secondary
  21. * boot "holding pen"
  22. */
  23. volatile int __cpuinitdata pen_release = -1;
  24. /*
  25. * Write pen_release in a way that is guaranteed to be visible to all
  26. * observers, irrespective of whether they're taking part in coherency
  27. * or not. This is necessary for the hotplug code to work reliably.
  28. */
  29. static void __cpuinit write_pen_release(int val)
  30. {
  31. pen_release = val;
  32. smp_wmb();
  33. __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
  34. outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
  35. }
  36. static DEFINE_SPINLOCK(boot_lock);
  37. void __cpuinit platform_secondary_init(unsigned int cpu)
  38. {
  39. /*
  40. * let the primary processor know we're out of the
  41. * pen, then head off into the C entry point
  42. */
  43. write_pen_release(-1);
  44. /*
  45. * Synchronise with the boot thread.
  46. */
  47. spin_lock(&boot_lock);
  48. spin_unlock(&boot_lock);
  49. }
  50. int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
  51. {
  52. unsigned long timeout;
  53. /*
  54. * Set synchronisation state between this boot processor
  55. * and the secondary one
  56. */
  57. spin_lock(&boot_lock);
  58. /*
  59. * This is really belt and braces; we hold unintended secondary
  60. * CPUs in the holding pen until we're ready for them. However,
  61. * since we haven't sent them a soft interrupt, they shouldn't
  62. * be there.
  63. */
  64. write_pen_release(cpu_logical_map(cpu));
  65. /*
  66. * Send the secondary CPU a soft interrupt, thereby causing
  67. * the boot monitor to read the system wide flags register,
  68. * and branch to the address found there.
  69. */
  70. gic_raise_softirq(cpumask_of(cpu), 1);
  71. timeout = jiffies + (1 * HZ);
  72. while (time_before(jiffies, timeout)) {
  73. smp_rmb();
  74. if (pen_release == -1)
  75. break;
  76. udelay(10);
  77. }
  78. /*
  79. * now the secondary core is starting up let it run its
  80. * calibrations, then wait for it to finish
  81. */
  82. spin_unlock(&boot_lock);
  83. return pen_release != -1 ? -ENOSYS : 0;
  84. }