cpintr.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. cpintr.c
  5. Abstract:
  6. This module implements interrupt controller support for the Integrator/CP
  7. board.
  8. Author:
  9. Evan Green 22-Aug-2012
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. //
  17. // Include kernel.h, but be cautious about which APIs are used. Most of the
  18. // system depends on the hardware modules. Limit use to HL, RTL and AR routines.
  19. //
  20. #include <minoca/kernel/kernel.h>
  21. #include "integcp.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // Define the number of soft priority levels implemented in the interrupt
  27. // controller.
  28. //
  29. #define INTEGRATORCP_INTERRUPT_PRIORITY_COUNT 16
  30. //
  31. // --------------------------------------------------------------------- Macros
  32. //
  33. //
  34. // This macro reads from the Integrator/CP interrupt controller. The parameter
  35. // should be CP_INTERRUPT_REGISTER value.
  36. //
  37. #define READ_INTERRUPT_REGISTER(_Register) \
  38. HlReadRegister32((PULONG)HlCpInterruptController + (_Register))
  39. //
  40. // This macro writes to the Integrator/CP interrupt controller. _Register
  41. // should be CP_INTERRUPT_REGISTER value, and _Value should be a ULONG.
  42. //
  43. #define WRITE_INTERRUPT_REGISTER(_Register, _Value) \
  44. HlWriteRegister32((PULONG)HlCpInterruptController + (_Register), (_Value))
  45. //
  46. // ----------------------------------------------- Internal Function Prototypes
  47. //
  48. KSTATUS
  49. HlpCpInterruptInitializeIoUnit (
  50. PVOID Context
  51. );
  52. INTERRUPT_CAUSE
  53. HlpCpInterruptBegin (
  54. PVOID Context,
  55. PINTERRUPT_LINE FiringLine,
  56. PULONG MagicCandy
  57. );
  58. VOID
  59. HlpCpInterruptEndOfInterrupt (
  60. PVOID Context,
  61. ULONG MagicCandy
  62. );
  63. KSTATUS
  64. HlpCpInterruptRequestInterrupt (
  65. PVOID Context,
  66. PINTERRUPT_LINE Line,
  67. ULONG Vector,
  68. PINTERRUPT_HARDWARE_TARGET Target
  69. );
  70. KSTATUS
  71. HlpCpInterruptSetLineState (
  72. PVOID Context,
  73. PINTERRUPT_LINE Line,
  74. PINTERRUPT_LINE_STATE State,
  75. PVOID ResourceData,
  76. UINTN ResourceDataSize
  77. );
  78. VOID
  79. HlpCpInterruptMaskLine (
  80. PVOID Context,
  81. PINTERRUPT_LINE Line,
  82. BOOL Enable
  83. );
  84. KSTATUS
  85. HlpCpInterruptDescribeLines (
  86. VOID
  87. );
  88. //
  89. // ------------------------------------------------------ Data Type Definitions
  90. //
  91. //
  92. // Define the offsets to interrupt controller registers, in ULONGs.
  93. //
  94. typedef enum _CP_INTERRUPT_REGISTER {
  95. CpInterruptIrqStatus = 0x0,
  96. CpInterruptIrqRawStatus = 0x1,
  97. CpInterruptIrqEnable = 0x2,
  98. CpInterruptIrqDisable = 0x3,
  99. CpInterruptSoftwareInterruptSet = 0x4,
  100. CpInterruptSoftwareInterruptClear = 0x5,
  101. CpInterruptFiqStatus = 0x8,
  102. CpInterruptFiqRawStatus = 0x9,
  103. CpInterruptFiqEnable = 0xA,
  104. CpInterruptFiqDisable = 0xB,
  105. } CP_INTERRUPT_REGISTER, *PCP_INTERRUPT_REGISTER;
  106. /*++
  107. Structure Description:
  108. This structure describes the Integrator/CP private interrupt controller
  109. state.
  110. Members:
  111. PhysicalAddress - Stores the physical address of this controller.
  112. LinePriority - Stores the priority for each interrupt line.
  113. CurrentPriority - Stores the current priority of the interrupt controller.
  114. Masks - Stores the mask of interrupts to disable when an interrupt of each
  115. priority fires.
  116. EnabledMask - Stores the mask of interrupts enabled at any priority.
  117. --*/
  118. typedef struct _INTEGRATORCP_INTERRUPT_DATA {
  119. PHYSICAL_ADDRESS PhysicalAddress;
  120. UCHAR LinePriority[INTEGRATORCP_INTERRUPT_LINE_COUNT];
  121. UCHAR CurrentPriority;
  122. ULONG Masks[INTEGRATORCP_INTERRUPT_PRIORITY_COUNT];
  123. ULONG EnabledMask;
  124. } INTEGRATORCP_INTERRUPT_DATA, *PINTEGRATORCP_INTERRUPT_DATA;
  125. //
  126. // -------------------------------------------------------------------- Globals
  127. //
  128. //
  129. // Store the virtual address of the mapped interrupt controller.
  130. //
  131. PVOID HlCpInterruptController = NULL;
  132. //
  133. // Store a pointer to the Integrator/CP ACPI table, if found.
  134. //
  135. PINTEGRATORCP_TABLE HlCpIntegratorTable = NULL;
  136. //
  137. // Define the interrupt function table template.
  138. //
  139. INTERRUPT_FUNCTION_TABLE HlCpInterruptFunctionTable = {
  140. HlpCpInterruptInitializeIoUnit,
  141. HlpCpInterruptSetLineState,
  142. HlpCpInterruptMaskLine,
  143. HlpCpInterruptBegin,
  144. NULL,
  145. HlpCpInterruptEndOfInterrupt,
  146. HlpCpInterruptRequestInterrupt,
  147. NULL,
  148. NULL,
  149. NULL,
  150. NULL,
  151. NULL
  152. };
  153. //
  154. // ------------------------------------------------------------------ Functions
  155. //
  156. VOID
  157. HlpCpInterruptModuleEntry (
  158. VOID
  159. )
  160. /*++
  161. Routine Description:
  162. This routine is the entry point for the Integrator/CP Interrupt hardware
  163. module. Its role is to detect and report the prescense of an Integrator/CP
  164. interrupt controller.
  165. Arguments:
  166. None.
  167. Return Value:
  168. None.
  169. --*/
  170. {
  171. PINTEGRATORCP_TABLE IntegratorTable;
  172. PINTEGRATORCP_INTERRUPT_DATA InterruptData;
  173. INTERRUPT_CONTROLLER_DESCRIPTION NewController;
  174. KSTATUS Status;
  175. //
  176. // Attempt to find the Integrator/CP ACPI table.
  177. //
  178. IntegratorTable = HlGetAcpiTable(INTEGRATORCP_SIGNATURE, NULL);
  179. if (IntegratorTable == NULL) {
  180. goto IntegratorCpInterruptModuleEntryEnd;
  181. }
  182. HlCpIntegratorTable = IntegratorTable;
  183. //
  184. // Zero out the controller description.
  185. //
  186. RtlZeroMemory(&NewController, sizeof(INTERRUPT_CONTROLLER_DESCRIPTION));
  187. //
  188. // Allocate context needed for this Interrupt Controller.
  189. //
  190. InterruptData = HlAllocateMemory(sizeof(INTEGRATORCP_INTERRUPT_DATA),
  191. INTEGRATOR_ALLOCATION_TAG,
  192. FALSE,
  193. NULL);
  194. if (InterruptData == NULL) {
  195. goto IntegratorCpInterruptModuleEntryEnd;
  196. }
  197. RtlZeroMemory(InterruptData, sizeof(INTEGRATORCP_INTERRUPT_DATA));
  198. InterruptData->PhysicalAddress =
  199. IntegratorTable->InterruptControllerPhysicalAddress;
  200. //
  201. // Initialize the new controller structure.
  202. //
  203. NewController.TableVersion = INTERRUPT_CONTROLLER_DESCRIPTION_VERSION;
  204. RtlCopyMemory(&(NewController.FunctionTable),
  205. &HlCpInterruptFunctionTable,
  206. sizeof(INTERRUPT_FUNCTION_TABLE));
  207. NewController.Context = InterruptData;
  208. NewController.Identifier = 0;
  209. NewController.ProcessorCount = 0;
  210. NewController.PriorityCount = INTEGRATORCP_INTERRUPT_PRIORITY_COUNT;
  211. //
  212. // Register the controller with the system.
  213. //
  214. Status = HlRegisterHardware(HardwareModuleInterruptController,
  215. &NewController);
  216. if (!KSUCCESS(Status)) {
  217. goto IntegratorCpInterruptModuleEntryEnd;
  218. }
  219. IntegratorCpInterruptModuleEntryEnd:
  220. return;
  221. }
  222. //
  223. // --------------------------------------------------------- Internal Functions
  224. //
  225. KSTATUS
  226. HlpCpInterruptInitializeIoUnit (
  227. PVOID Context
  228. )
  229. /*++
  230. Routine Description:
  231. This routine initializes an interrupt controller. It's responsible for
  232. masking all interrupt lines on the controller and setting the current
  233. priority to the lowest (allow all interrupts). Once completed successfully,
  234. it is expected that interrupts can be enabled at the processor core with
  235. no interrupts occurring.
  236. Arguments:
  237. Context - Supplies the pointer to the controller's context, provided by the
  238. hardware module upon initialization.
  239. Return Value:
  240. STATUS_SUCCESS on success.
  241. Other status codes on failure.
  242. --*/
  243. {
  244. PINTEGRATORCP_INTERRUPT_DATA InterruptData;
  245. KSTATUS Status;
  246. InterruptData = (PINTEGRATORCP_INTERRUPT_DATA)Context;
  247. if (HlCpInterruptController == NULL) {
  248. HlCpInterruptController = HlMapPhysicalAddress(
  249. InterruptData->PhysicalAddress,
  250. INTEGRATORCP_INTERRUPT_CONTROLLER_SIZE,
  251. TRUE);
  252. if (HlCpInterruptController == NULL) {
  253. Status = STATUS_INSUFFICIENT_RESOURCES;
  254. goto CpInterruptInitializeIoUnitEnd;
  255. }
  256. //
  257. // Describe the interrupt lines on this controller.
  258. //
  259. Status = HlpCpInterruptDescribeLines();
  260. if (!KSUCCESS(Status)) {
  261. goto CpInterruptInitializeIoUnitEnd;
  262. }
  263. }
  264. //
  265. // Disable all FIQ and IRQ lines.
  266. //
  267. WRITE_INTERRUPT_REGISTER(CpInterruptIrqDisable, 0xFFFFFFFF);
  268. WRITE_INTERRUPT_REGISTER(CpInterruptFiqDisable, 0xFFFFFFFF);
  269. InterruptData->CurrentPriority = 0;
  270. InterruptData->EnabledMask = 0;
  271. Status = STATUS_SUCCESS;
  272. CpInterruptInitializeIoUnitEnd:
  273. return Status;
  274. }
  275. INTERRUPT_CAUSE
  276. HlpCpInterruptBegin (
  277. PVOID Context,
  278. PINTERRUPT_LINE FiringLine,
  279. PULONG MagicCandy
  280. )
  281. /*++
  282. Routine Description:
  283. This routine is called when an interrupt fires. Its role is to determine
  284. if an interrupt has fired on the given controller, accept it, and determine
  285. which line fired if any. This routine will always be called with interrupts
  286. disabled at the processor core.
  287. Arguments:
  288. Context - Supplies the pointer to the controller's context, provided by the
  289. hardware module upon initialization.
  290. FiringLine - Supplies a pointer where the interrupt hardware module will
  291. fill in which line fired, if applicable.
  292. MagicCandy - Supplies a pointer where the interrupt hardware module can
  293. store 32 bits of private information regarding this interrupt. This
  294. information will be returned to it when the End Of Interrupt routine
  295. is called.
  296. Return Value:
  297. Returns an interrupt cause indicating whether or not an interrupt line,
  298. spurious interrupt, or no interrupt fired on this controller.
  299. --*/
  300. {
  301. ULONG Index;
  302. PINTEGRATORCP_INTERRUPT_DATA InterruptData;
  303. ULONG Mask;
  304. UCHAR Priority;
  305. ULONG Status;
  306. InterruptData = (PINTEGRATORCP_INTERRUPT_DATA)Context;
  307. Status = READ_INTERRUPT_REGISTER(CpInterruptIrqStatus);
  308. if (Status == 0) {
  309. return InterruptCauseNoInterruptHere;
  310. }
  311. //
  312. // Find the first firing index.
  313. //
  314. Index = 0;
  315. while ((Status & 0x1) == 0) {
  316. Status = Status >> 1;
  317. Index += 1;
  318. }
  319. //
  320. // Disable all interrupts at or below this run level.
  321. //
  322. Priority = InterruptData->LinePriority[Index];
  323. Mask = InterruptData->Masks[Priority];
  324. WRITE_INTERRUPT_REGISTER(CpInterruptIrqDisable, Mask);
  325. //
  326. // Save the previous priority to know what to restore to when this
  327. // interrupt ends.
  328. //
  329. *MagicCandy = InterruptData->CurrentPriority;
  330. InterruptData->CurrentPriority = Priority;
  331. //
  332. // Return the interrupting line's information.
  333. //
  334. FiringLine->Type = InterruptLineControllerSpecified;
  335. FiringLine->U.Local.Controller = 0;
  336. FiringLine->U.Local.Line = Index;
  337. return InterruptCauseLineFired;
  338. }
  339. VOID
  340. HlpCpInterruptEndOfInterrupt (
  341. PVOID Context,
  342. ULONG MagicCandy
  343. )
  344. /*++
  345. Routine Description:
  346. This routine is called after an interrupt has fired and been serviced. Its
  347. role is to tell the interrupt controller that processing has completed.
  348. This routine will always be called with interrupts disabled at the
  349. processor core.
  350. Arguments:
  351. Context - Supplies the pointer to the controller's context, provided by the
  352. hardware module upon initialization.
  353. MagicCandy - Supplies the magic candy that that the interrupt hardware
  354. module stored when the interrupt began.
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. PINTEGRATORCP_INTERRUPT_DATA InterruptData;
  360. ULONG Mask;
  361. //
  362. // Re-enable interrupts at the previous priority level before this
  363. // interrupt fired. The enabled mask prevents enabling interrupts that
  364. // weren't enabled before.
  365. //
  366. InterruptData = (PINTEGRATORCP_INTERRUPT_DATA)Context;
  367. InterruptData->CurrentPriority = MagicCandy;
  368. Mask = ~InterruptData->Masks[MagicCandy] & InterruptData->EnabledMask;
  369. WRITE_INTERRUPT_REGISTER(CpInterruptIrqEnable, Mask);
  370. return;
  371. }
  372. KSTATUS
  373. HlpCpInterruptRequestInterrupt (
  374. PVOID Context,
  375. PINTERRUPT_LINE Line,
  376. ULONG Vector,
  377. PINTERRUPT_HARDWARE_TARGET Target
  378. )
  379. /*++
  380. Routine Description:
  381. This routine requests a hardware interrupt on the given line.
  382. Arguments:
  383. Context - Supplies the pointer to the controller's context, provided by the
  384. hardware module upon initialization.
  385. Line - Supplies a pointer to the interrupt line to spark.
  386. Vector - Supplies the vector to generate the interrupt on (for vectored
  387. architectures only).
  388. Target - Supplies a pointer to the set of processors to target.
  389. Return Value:
  390. STATUS_SUCCESS on success.
  391. Error code on failure.
  392. --*/
  393. {
  394. //
  395. // This feature will be implemented when it is required (probably by
  396. // power management).
  397. //
  398. return STATUS_NOT_IMPLEMENTED;
  399. }
  400. KSTATUS
  401. HlpCpInterruptSetLineState (
  402. PVOID Context,
  403. PINTERRUPT_LINE Line,
  404. PINTERRUPT_LINE_STATE State,
  405. PVOID ResourceData,
  406. UINTN ResourceDataSize
  407. )
  408. /*++
  409. Routine Description:
  410. This routine enables or disables and configures an interrupt line.
  411. Arguments:
  412. Context - Supplies the pointer to the controller's context, provided by the
  413. hardware module upon initialization.
  414. Line - Supplies a pointer to the line to set up. This will always be a
  415. controller specified line.
  416. State - Supplies a pointer to the new configuration of the line.
  417. ResourceData - Supplies an optional pointer to the device specific resource
  418. data for the interrupt line.
  419. ResourceDataSize - Supplies the size of the resource data, in bytes.
  420. Return Value:
  421. Status code.
  422. --*/
  423. {
  424. ULONG BitMask;
  425. ULONG Index;
  426. PINTEGRATORCP_INTERRUPT_DATA InterruptData;
  427. ULONG LocalLine;
  428. UCHAR Priority;
  429. KSTATUS Status;
  430. InterruptData = (PINTEGRATORCP_INTERRUPT_DATA)Context;
  431. LocalLine = Line->U.Local.Line;
  432. if ((Line->Type != InterruptLineControllerSpecified) ||
  433. (Line->U.Local.Controller != 0) ||
  434. (LocalLine >= INTEGRATORCP_INTERRUPT_LINE_COUNT)) {
  435. Status = STATUS_INVALID_PARAMETER;
  436. goto CpInterruptSetLineStateEnd;
  437. }
  438. if ((State->Output.Type != InterruptLineControllerSpecified) ||
  439. (State->Output.U.Local.Controller != INTERRUPT_CPU_IDENTIFIER) ||
  440. (State->Output.U.Local.Line != INTERRUPT_CPU_IRQ_PIN)) {
  441. Status = STATUS_INVALID_PARAMETER;
  442. goto CpInterruptSetLineStateEnd;
  443. }
  444. //
  445. // Calculate the bit to flip and flip it.
  446. //
  447. BitMask = 1 << LocalLine;
  448. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) != 0) {
  449. Priority = State->HardwarePriority;
  450. InterruptData->LinePriority[LocalLine] = Priority;
  451. InterruptData->EnabledMask |= BitMask;
  452. //
  453. // This interrupt gets masked at and above its priority level.
  454. //
  455. for (Index = Priority;
  456. Index < INTEGRATORCP_INTERRUPT_PRIORITY_COUNT;
  457. Index += 1) {
  458. InterruptData->Masks[Index] |= BitMask;
  459. }
  460. WRITE_INTERRUPT_REGISTER(CpInterruptIrqEnable, BitMask);
  461. } else {
  462. WRITE_INTERRUPT_REGISTER(CpInterruptIrqDisable, BitMask);
  463. InterruptData->EnabledMask &= ~BitMask;
  464. //
  465. // Remove this interrupt from the masks.
  466. //
  467. for (Index = 0;
  468. Index < INTEGRATORCP_INTERRUPT_PRIORITY_COUNT;
  469. Index += 1) {
  470. InterruptData->Masks[Index] &= ~BitMask;
  471. }
  472. }
  473. Status = STATUS_SUCCESS;
  474. CpInterruptSetLineStateEnd:
  475. return Status;
  476. }
  477. VOID
  478. HlpCpInterruptMaskLine (
  479. PVOID Context,
  480. PINTERRUPT_LINE Line,
  481. BOOL Enable
  482. )
  483. /*++
  484. Routine Description:
  485. This routine masks or unmasks an interrupt line, leaving the rest of the
  486. line state intact.
  487. Arguments:
  488. Context - Supplies the pointer to the controller's context, provided by the
  489. hardware module upon initialization.
  490. Line - Supplies a pointer to the line to maek or unmask. This will always
  491. be a controller specified line.
  492. Enable - Supplies a boolean indicating whether to mask the interrupt,
  493. preventing interrupts from coming through (FALSE), or enable the line
  494. and allow interrupts to come through (TRUE).
  495. Return Value:
  496. None.
  497. --*/
  498. {
  499. ULONG BitMask;
  500. //
  501. // Calculate the bit to flip and flip it.
  502. //
  503. BitMask = 1 << Line->U.Local.Line;
  504. if (Enable != FALSE) {
  505. WRITE_INTERRUPT_REGISTER(CpInterruptIrqEnable, BitMask);
  506. } else {
  507. WRITE_INTERRUPT_REGISTER(CpInterruptIrqDisable, BitMask);
  508. }
  509. return;
  510. }
  511. KSTATUS
  512. HlpCpInterruptDescribeLines (
  513. VOID
  514. )
  515. /*++
  516. Routine Description:
  517. This routine describes all interrupt lines to the system.
  518. Arguments:
  519. None.
  520. Return Value:
  521. Status code.
  522. --*/
  523. {
  524. INTERRUPT_LINES_DESCRIPTION Lines;
  525. KSTATUS Status;
  526. RtlZeroMemory(&Lines, sizeof(INTERRUPT_LINES_DESCRIPTION));
  527. Lines.Version = INTERRUPT_LINES_DESCRIPTION_VERSION;
  528. //
  529. // Describe the normal lines on the Integrator/CP.
  530. //
  531. Lines.Type = InterruptLinesStandardPin;
  532. Lines.Controller = 0;
  533. Lines.LineStart = 0;
  534. Lines.LineEnd = INTEGRATORCP_INTERRUPT_LINE_COUNT;
  535. Lines.Gsi = HlCpIntegratorTable->InterruptControllerGsiBase;
  536. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  537. if (!KSUCCESS(Status)) {
  538. goto CpInterruptDescribeLinesEnd;
  539. }
  540. //
  541. // Register the output lines.
  542. //
  543. Lines.Type = InterruptLinesOutput;
  544. Lines.OutputControllerIdentifier = INTERRUPT_CPU_IDENTIFIER;
  545. Lines.LineStart = INTERRUPT_ARM_MIN_CPU_LINE;
  546. Lines.LineEnd = INTERRUPT_ARM_MAX_CPU_LINE;
  547. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  548. if (!KSUCCESS(Status)) {
  549. goto CpInterruptDescribeLinesEnd;
  550. }
  551. CpInterruptDescribeLinesEnd:
  552. return Status;
  553. }