genapic_flat.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright 2004 James Cleverdon, IBM.
  3. * Subject to the GNU Public License, v.2
  4. *
  5. * Flat APIC subarch code. Maximum 8 CPUs, logical delivery.
  6. *
  7. * Hacked for x86-64 by James Cleverdon from i386 architecture code by
  8. * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
  9. * James Cleverdon.
  10. * Ashok Raj <ashok.raj@intel.com>
  11. * Removed IPI broadcast shortcut to support CPU hotplug
  12. */
  13. #include <linux/config.h>
  14. #include <linux/threads.h>
  15. #include <linux/cpumask.h>
  16. #include <linux/string.h>
  17. #include <linux/kernel.h>
  18. #include <linux/ctype.h>
  19. #include <linux/init.h>
  20. #include <asm/smp.h>
  21. #include <asm/ipi.h>
  22. /*
  23. * The following permit choosing broadcast IPI shortcut v.s sending IPI only
  24. * to online cpus via the send_IPI_mask varient.
  25. * The mask version is my preferred option, since it eliminates a lot of
  26. * other extra code that would need to be written to cleanup intrs sent
  27. * to a CPU while offline.
  28. *
  29. * Sending broadcast introduces lots of trouble in CPU hotplug situations.
  30. * These IPI's are delivered to cpu's irrespective of their offline status
  31. * and could pickup stale intr data when these CPUS are turned online.
  32. *
  33. * Not using broadcast is a cleaner approach IMO, but Andi Kleen disagrees with
  34. * the idea of not using broadcast IPI's anymore. Hence the run time check
  35. * is introduced, on his request so we can choose an alternate mechanism.
  36. *
  37. * Initial wacky performance tests that collect cycle counts show
  38. * no increase in using mask v.s broadcast version. In fact they seem
  39. * identical in terms of cycle counts.
  40. *
  41. * if we need to use broadcast, we need to do the following.
  42. *
  43. * cli;
  44. * hold call_lock;
  45. * clear any pending IPI, just ack and clear all pending intr
  46. * set cpu_online_map;
  47. * release call_lock;
  48. * sti;
  49. *
  50. * The complicated dummy irq processing shown above is not required if
  51. * we didnt sent IPI's to wrong CPU's in the first place.
  52. *
  53. * - Ashok Raj <ashok.raj@intel.com>
  54. */
  55. #ifdef CONFIG_HOTPLUG_CPU
  56. #define DEFAULT_SEND_IPI (1)
  57. #else
  58. #define DEFAULT_SEND_IPI (0)
  59. #endif
  60. static int no_broadcast=DEFAULT_SEND_IPI;
  61. static cpumask_t flat_target_cpus(void)
  62. {
  63. return cpu_online_map;
  64. }
  65. /*
  66. * Set up the logical destination ID.
  67. *
  68. * Intel recommends to set DFR, LDR and TPR before enabling
  69. * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
  70. * document number 292116). So here it goes...
  71. */
  72. static void flat_init_apic_ldr(void)
  73. {
  74. unsigned long val;
  75. unsigned long num, id;
  76. num = smp_processor_id();
  77. id = 1UL << num;
  78. x86_cpu_to_log_apicid[num] = id;
  79. apic_write_around(APIC_DFR, APIC_DFR_FLAT);
  80. val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  81. val |= SET_APIC_LOGICAL_ID(id);
  82. apic_write_around(APIC_LDR, val);
  83. }
  84. static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
  85. {
  86. unsigned long mask = cpus_addr(cpumask)[0];
  87. unsigned long cfg;
  88. unsigned long flags;
  89. local_save_flags(flags);
  90. local_irq_disable();
  91. /*
  92. * Wait for idle.
  93. */
  94. apic_wait_icr_idle();
  95. /*
  96. * prepare target chip field
  97. */
  98. cfg = __prepare_ICR2(mask);
  99. apic_write_around(APIC_ICR2, cfg);
  100. /*
  101. * program the ICR
  102. */
  103. cfg = __prepare_ICR(0, vector, APIC_DEST_LOGICAL);
  104. /*
  105. * Send the IPI. The write to APIC_ICR fires this off.
  106. */
  107. apic_write_around(APIC_ICR, cfg);
  108. local_irq_restore(flags);
  109. }
  110. static inline void __local_flat_send_IPI_allbutself(int vector)
  111. {
  112. if (no_broadcast) {
  113. cpumask_t mask = cpu_online_map;
  114. int this_cpu = get_cpu();
  115. cpu_clear(this_cpu, mask);
  116. flat_send_IPI_mask(mask, vector);
  117. put_cpu();
  118. }
  119. else
  120. __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
  121. }
  122. static inline void __local_flat_send_IPI_all(int vector)
  123. {
  124. if (no_broadcast)
  125. flat_send_IPI_mask(cpu_online_map, vector);
  126. else
  127. __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
  128. }
  129. static void flat_send_IPI_allbutself(int vector)
  130. {
  131. if (((num_online_cpus()) - 1) >= 1)
  132. __local_flat_send_IPI_allbutself(vector);
  133. }
  134. static void flat_send_IPI_all(int vector)
  135. {
  136. __local_flat_send_IPI_all(vector);
  137. }
  138. static int flat_apic_id_registered(void)
  139. {
  140. return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
  141. }
  142. static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
  143. {
  144. return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
  145. }
  146. static unsigned int phys_pkg_id(int index_msb)
  147. {
  148. u32 ebx;
  149. ebx = cpuid_ebx(1);
  150. return ((ebx >> 24) & 0xFF) >> index_msb;
  151. }
  152. static __init int no_ipi_broadcast(char *str)
  153. {
  154. get_option(&str, &no_broadcast);
  155. printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" :
  156. "IPI Broadcast");
  157. return 1;
  158. }
  159. __setup("no_ipi_broadcast", no_ipi_broadcast);
  160. struct genapic apic_flat = {
  161. .name = "flat",
  162. .int_delivery_mode = dest_LowestPrio,
  163. .int_dest_mode = (APIC_DEST_LOGICAL != 0),
  164. .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
  165. .target_cpus = flat_target_cpus,
  166. .apic_id_registered = flat_apic_id_registered,
  167. .init_apic_ldr = flat_init_apic_ldr,
  168. .send_IPI_all = flat_send_IPI_all,
  169. .send_IPI_allbutself = flat_send_IPI_allbutself,
  170. .send_IPI_mask = flat_send_IPI_mask,
  171. .cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
  172. .phys_pkg_id = phys_pkg_id,
  173. };
  174. static int __init print_ipi_mode(void)
  175. {
  176. printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" :
  177. "Shortcut");
  178. return 0;
  179. }
  180. late_initcall(print_ipi_mode);