Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

565 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. mpipic.c
  5. Abstract:
  6. This module provides the HAL support for interprocessor interrupts and
  7. processor initialization for MPS systems.
  8. Author:
  9. Forrest Foltz (forrestf) 27-Oct-2000
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #if defined(APIC_HAL)
  15. #if !defined(_MPIPIC_C_)
  16. #define _MPIPIC_C_
  17. #pragma optimize("Oxt2b2",on)
  18. #include "halp.h"
  19. #include "apic.inc"
  20. #include "pcmp_nt.inc"
  21. #if !defined(LOCAL_APIC)
  22. //
  23. // Temporary defines. These definitions are found in common header files in
  24. // the private hal branch.
  25. //
  26. #define LOCAL_APIC(x) (*((ULONG volatile *)&pLocalApic[(x)/sizeof(ULONG)]))
  27. /*++
  28. HalpStallWhileApicBusy (
  29. VOID
  30. )
  31. Routine Description:
  32. This routine waits until the local apic has completed sending
  33. an IPI.
  34. Parameters:
  35. None.
  36. Return Value:
  37. None.
  38. --*/
  39. #define HalpStallWhileApicBusy() \
  40. while (((LOCAL_APIC(LU_INT_CMD_LOW) & DELIVERY_PENDING) != 0)){}
  41. #endif // LOCAL_APIC
  42. //
  43. // HalpIpiTargetLookup[] and HalpIpiTargetMask[] are tables used by
  44. // HalpSendNodeIpi() and are initialized by HalpBuildIpiDestinationMap().
  45. //
  46. // They assist in performing the translation between a (32- or 64- bit)
  47. // KAFFINITY into a 64-bit Node Target Set.
  48. //
  49. // Each element of HalpIpiTargetLookup[] contains the logical sum of
  50. // the 8 (or 4) Node Target Sets for a particular byte value. Each
  51. // element of HalpIpiTargetMask[] contains the mask of all possible
  52. // APIC targets for a particular byte position with KAFFINITY.
  53. //
  54. // For example: Suppose one wished to determine the set of APIC targets
  55. // for affinity 0x00000000b7000000.
  56. //
  57. // First, find the value of HalpIpiTargetLookup[0xb7]. This represents the set
  58. // of APIC targets for the affinity 0xb7b7b7b7b7b7b7b7.
  59. //
  60. // Next, mask the value with HalpIpiTargetMask[3]. The 3 represents the byte
  61. // number within the KAFFINITY.
  62. //
  63. // The result of the operation will yield the set of APIC targets that
  64. // correspond to an affinity of 0x00000000b7000000.
  65. //
  66. ULONG64 HalpIpiTargetLookup[256];
  67. ULONG64 HalpIpiTargetMask[sizeof(KAFFINITY)];
  68. //
  69. // Local function prototypes and types. There are up to three versions of
  70. // the send IPI code, depending on whether the apic topology is flat, cluster
  71. // with 8 or fewer nodes, or cluster with more than 8 nodes.
  72. //
  73. VOID
  74. FASTCALL
  75. HalpSendFlatIpi (
  76. IN KAFFINITY Affinity,
  77. IN ULONG Command
  78. );
  79. VOID
  80. FASTCALL
  81. HalpSendNodeIpi32 (
  82. IN KAFFINITY Affinity,
  83. IN ULONG Command
  84. );
  85. VOID
  86. FASTCALL
  87. HalpSendNodeIpi64 (
  88. IN KAFFINITY Affinity,
  89. IN ULONG Command
  90. );
  91. VOID (FASTCALL *HalpIpiRoutine) (
  92. IN KAFFINITY Affinity,
  93. IN ULONG Command
  94. );
  95. //
  96. // External data
  97. //
  98. extern INTERRUPT_DEST HalpIntDestMap[MAX_PROCESSORS];
  99. //
  100. // Implementation
  101. //
  102. __forceinline
  103. VOID
  104. HalpSendIpiWorker (
  105. IN UCHAR TargetSet,
  106. IN ULONG Command
  107. )
  108. /*++
  109. Routine Description:
  110. This routine is called to send an IPI command to a set of processors
  111. on a single node.
  112. Parameters:
  113. TargetSet - Specifies the processor identifiers within the node.
  114. Command - Specifies the IPI command to send.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. ULONG destination;
  120. //
  121. // Only high byte of the destination is used. Wait until the Apic is
  122. // not busy before sending. Continue without waiting, there will be
  123. // another wait after all IPIs have been submitted.
  124. //
  125. destination = (ULONG)TargetSet << DESTINATION_SHIFT;
  126. HalpStallWhileApicBusy();
  127. LOCAL_APIC(LU_INT_CMD_HIGH) = destination;
  128. LOCAL_APIC(LU_INT_CMD_LOW) = Command;
  129. }
  130. VOID
  131. FASTCALL
  132. HalpSendFlatIpi (
  133. IN KAFFINITY Affinity,
  134. IN ULONG Command
  135. )
  136. /*++
  137. Routine Description:
  138. This routine is called to send an IPI command to a set of processors. This
  139. routine is invoked when we have a maximum of 8 processors and the APICs have
  140. been set up in "flat" mode.
  141. Parameters:
  142. TargetSet - Specifies the processor identifiers.
  143. Command - Specifies the IPI command to send.
  144. Return Value:
  145. None.
  146. --*/
  147. {
  148. HalpSendIpiWorker((UCHAR)Affinity,Command);
  149. HalpStallWhileApicBusy();
  150. }
  151. VOID
  152. FASTCALL
  153. HalpSendIpi (
  154. IN KAFFINITY Affinity,
  155. IN ULONG Command
  156. )
  157. /*++
  158. Routine Description:
  159. This routine disables interrupts, dispatches to the correct IPI send
  160. routine, and restores interrupts.
  161. Parameters:
  162. Affinity - Specifies the set of processors to receive the IPI.
  163. Command - Specifies the IPI command to send.
  164. Return Value:
  165. None.
  166. --*/
  167. {
  168. ULONG flags;
  169. //
  170. // Disable interrupts and call the appropriate routine.
  171. //
  172. // BUGBUG the compiler generates terrible code for this,
  173. // most likely because of the inline _asm{} block generated
  174. // by HalpDisableInterrupts().
  175. //
  176. // Ideally we could talk the x86 compiler team into giving
  177. // us an intrinsic like the AMD64 compiler's __getcallerseflags()
  178. //
  179. flags = HalpDisableInterrupts();
  180. HalpIpiRoutine(Affinity,Command);
  181. HalpRestoreInterrupts(flags);
  182. }
  183. #define APIC_IPI (DELIVER_FIXED | LOGICAL_DESTINATION | ICR_USE_DEST_FIELD | APIC_IPI_VECTOR)
  184. #define APIC_BROADCAST_EXCL \
  185. (DELIVER_FIXED | LOGICAL_DESTINATION | ICR_ALL_EXCL_SELF | APIC_IPI_VECTOR)
  186. #define APIC_BROADCAST_INCL \
  187. (DELIVER_FIXED | LOGICAL_DESTINATION | ICR_ALL_INCL_SELF | APIC_IPI_VECTOR)
  188. VOID
  189. HalRequestIpi (
  190. IN KAFFINITY Affinity
  191. )
  192. /*++
  193. Routine Description:
  194. Requests an interprocessor interrupt
  195. Arguments:
  196. Affinity - Supplies the set of processors to be interrupted
  197. Return Value:
  198. None.
  199. --*/
  200. {
  201. ULONG flags;
  202. KAFFINITY Self;
  203. //
  204. // If the target set of processors is the complete set of processors,
  205. // then use the broadcast capability of the APIC. Otherwise, send the
  206. // IPI to the individual processors.
  207. //
  208. Self = KeGetCurrentPrcb()->SetMember;
  209. if ((Affinity | Self) == HalpActiveProcessors) {
  210. flags = HalpDisableInterrupts();
  211. HalpStallWhileApicBusy();
  212. if ((Affinity & Self) != 0) {
  213. LOCAL_APIC(LU_INT_CMD_LOW) = APIC_BROADCAST_INCL;
  214. } else {
  215. LOCAL_APIC(LU_INT_CMD_LOW) = APIC_BROADCAST_EXCL;
  216. }
  217. HalpStallWhileApicBusy();
  218. HalpRestoreInterrupts(flags);
  219. } else {
  220. HalpSendIpi(Affinity, APIC_IPI);
  221. }
  222. return;
  223. }
  224. VOID
  225. HalpBuildIpiDestinationMap (
  226. VOID
  227. )
  228. /*++
  229. Routine Description
  230. This routine is called whenever a new processor comes on line, just
  231. after its APIC is initialized. It (re)builds the lookup tables that
  232. are used by HalpSendNodeIpi{32|64}.
  233. This code isn't particularly fast, and doesn't need to be - it is
  234. executed once per processor during boot.
  235. Arguments:
  236. None:
  237. Return Value:
  238. None
  239. --*/
  240. {
  241. ULONG byteNumber;
  242. ULONG index;
  243. ULONG mask;
  244. ULONG processor;
  245. ULONG64 targetMap;
  246. ULONG64 targetMapSum;
  247. if (HalpMaxProcsPerCluster == 0) {
  248. //
  249. // Running in flat mode. IPIs are sent by the flat mode routine.
  250. //
  251. HalpIpiRoutine = HalpSendFlatIpi;
  252. return;
  253. }
  254. //
  255. // Build HalpIpiTargetLookup[] and HalpIpiTargetMask[] according to
  256. // the contents of HalpIntDestMap[]. If an additional processor is
  257. // added, this routine can be safely called again assuming the topology
  258. // of the existing processors has not changed.
  259. //
  260. for (byteNumber = 0; byteNumber < sizeof(KAFFINITY); byteNumber++) {
  261. targetMapSum = 0;
  262. for (index = 0; index < 256; index++) {
  263. processor = byteNumber * 8;
  264. mask = index;
  265. while (mask != 0) {
  266. if ((mask & 0x1) != 0) {
  267. targetMap = HalpIntDestMap[processor].Cluster.Hw.DestId;
  268. targetMap <<=
  269. (HalpIntDestMap[processor].Cluster.Hw.ClusterId * 4);
  270. HalpIpiTargetLookup[index] |= targetMap;
  271. targetMapSum |= targetMap;
  272. }
  273. processor += 1;
  274. mask >>= 1;
  275. }
  276. }
  277. HalpIpiTargetMask[byteNumber] = targetMapSum;
  278. }
  279. #if defined(_AMD64_)
  280. HalpIpiRoutine = HalpSendNodeIpi64;
  281. #else
  282. //
  283. // Determine which of the two IPI cluster send routines to invoke
  284. // depending on the maximum node ID.
  285. //
  286. HalpIpiRoutine = HalpSendNodeIpi32;
  287. for (processor = 0; processor < MAX_PROCESSORS; processor += 1) {
  288. if (HalpIntDestMap[processor].Cluster.Hw.ClusterId > 7) {
  289. HalpIpiRoutine = HalpSendNodeIpi64;
  290. break;
  291. }
  292. }
  293. #endif
  294. }
  295. #if !defined(_AMD64_)
  296. //
  297. // Here, two versions of HalpSendNodeIpi are compiled. The first,
  298. // HalpSendNodeIpi32(), is used when we have a maximum of 8 APIC
  299. // nodes. On a 32-bit processor, it is significantly faster because
  300. // it uses 32-bit lookup, mask and shift operations.
  301. //
  302. #define HalpSendNodeIpi HalpSendNodeIpi32
  303. #define TARGET_MASK ULONG
  304. #include "mpipic.c"
  305. #undef HalpSendNodeIpi
  306. #undef TARGET_MASK
  307. #endif
  308. //
  309. // Here the 64-bit version of HalpSendNodeIpi64 is created. On a
  310. // 32-bit processor, this is used when we have more than 8 APIC
  311. // nodes. It is the only multi-node routine on a 64-bit platform.
  312. //
  313. #define HalpSendNodeIpi HalpSendNodeIpi64
  314. #define TARGET_MASK ULONG64
  315. #include "mpipic.c"
  316. #pragma optimize("",on)
  317. #else // _MPIPIC_C_
  318. //
  319. // This portion of the module is included at least once (see above) in
  320. // order to build HalpSendNodeIpi32() and/or HalpSendNodeIpi64().
  321. //
  322. VOID
  323. FASTCALL
  324. HalpSendNodeIpi (
  325. IN KAFFINITY Affinity,
  326. IN ULONG Command
  327. )
  328. /*++
  329. Routine Description:
  330. This routine sends one or more IPIs to APIC nodes. This code generates
  331. two forms of this routine - HalpSendNodeIpi32() and HalpSendNodeIpi64() -
  332. based on whether we have more than 8 APIC nodes or not.
  333. Parameters:
  334. Affinity - Specifies the set of processors to receive the IPI.
  335. Command - Specifies the IPI command to send.
  336. Return Value:
  337. None.
  338. --*/
  339. {
  340. KAFFINITY affinity;
  341. UCHAR clusterIndex;
  342. ULONG byteNumber;
  343. TARGET_MASK targetMap;
  344. TARGET_MASK targetMapSum;
  345. ULONG64 *targetMask;
  346. UCHAR logicalId;
  347. ULONG mapIndex;
  348. //
  349. // Affinity has some number of target processors indicated. Each
  350. // target processor is a member of a cluster of processors, or "node".
  351. //
  352. // Build targetMap by processing Affinity one byte at a time. This
  353. // loop executes a maximum of sizeof(KAFFINITY) times.
  354. //
  355. affinity = Affinity;
  356. targetMask = HalpIpiTargetMask;
  357. targetMapSum = 0;
  358. do {
  359. mapIndex = (UCHAR)affinity;
  360. if (mapIndex != 0) {
  361. targetMap = (TARGET_MASK)HalpIpiTargetLookup[mapIndex];
  362. targetMap &= (TARGET_MASK)*targetMask;
  363. targetMapSum |= targetMap;
  364. }
  365. targetMask += 1;
  366. affinity >>= 8;
  367. } while (affinity != 0);
  368. //
  369. // targetMap is an array of 4-bit node-relative target masks.
  370. // Process the array, sending an IPI to each non-zero element.
  371. //
  372. // This loop executes a maximum of sizeof(TARGET_MASK) times.
  373. //
  374. clusterIndex = 0;
  375. do {
  376. //
  377. // Determine whether any APICs in this node
  378. // are targeted, and send an IPI to the node
  379. // if so.
  380. //
  381. logicalId = (UCHAR)targetMapSum & 0x0F;
  382. if (logicalId != 0) {
  383. logicalId |= clusterIndex;
  384. HalpSendIpiWorker(logicalId,Command);
  385. }
  386. //
  387. // Shift the APIC targets for the next node into place, increment
  388. // the cluster ID, and continue processing if there are still
  389. // APIC targets remaining.
  390. //
  391. targetMapSum >>= 4;
  392. clusterIndex += 0x10;
  393. } while (targetMapSum != 0);
  394. //
  395. // Wait for the APIC to process the final IPI.
  396. //
  397. HalpStallWhileApicBusy();
  398. }
  399. #endif // _MPIPIC_C_
  400. #endif // APIC_HAL