platsmp.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. * Write pen_release in a way that is guaranteed to be visible to all
  21. * observers, irrespective of whether they're taking part in coherency
  22. * or not. This is necessary for the hotplug code to work reliably.
  23. */
  24. static void write_pen_release(int val)
  25. {
  26. pen_release = val;
  27. smp_wmb();
  28. sync_cache_w(&pen_release);
  29. }
  30. static DEFINE_SPINLOCK(boot_lock);
  31. void versatile_secondary_init(unsigned int cpu)
  32. {
  33. /*
  34. * let the primary processor know we're out of the
  35. * pen, then head off into the C entry point
  36. */
  37. write_pen_release(-1);
  38. /*
  39. * Synchronise with the boot thread.
  40. */
  41. spin_lock(&boot_lock);
  42. spin_unlock(&boot_lock);
  43. }
  44. int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
  45. {
  46. unsigned long timeout;
  47. /*
  48. * Set synchronisation state between this boot processor
  49. * and the secondary one
  50. */
  51. spin_lock(&boot_lock);
  52. /*
  53. * This is really belt and braces; we hold unintended secondary
  54. * CPUs in the holding pen until we're ready for them. However,
  55. * since we haven't sent them a soft interrupt, they shouldn't
  56. * be there.
  57. */
  58. write_pen_release(cpu_logical_map(cpu));
  59. /*
  60. * Send the secondary CPU a soft interrupt, thereby causing
  61. * the boot monitor to read the system wide flags register,
  62. * and branch to the address found there.
  63. */
  64. arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  65. timeout = jiffies + (1 * HZ);
  66. while (time_before(jiffies, timeout)) {
  67. smp_rmb();
  68. if (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 pen_release != -1 ? -ENOSYS : 0;
  78. }