1
0

b2709int.c 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. b2709int.c
  5. Abstract:
  6. This module implements support for the BCM2709 interrupt controller.
  7. Author:
  8. Chris Stevens 24-Mar-2014
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. //
  16. // Include kernel.h, but be cautious about which APIs are used. Most of the
  17. // system depends on the hardware modules. Limit use to HL, RTL and AR routines.
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. #include <minoca/kernel/arm.h>
  21. #include "bcm2709.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // Define the flags for the basic interrupts.
  27. //
  28. #define BCM2709_INTERRUPT_IRQ_BASIC_TIMER 0x00000001
  29. #define BCM2709_INTERRUPT_IRQ_BASIC_MAILBOX 0x00000002
  30. #define BCM2709_INTERRUPT_IRQ_BASIC_DOORBELL0 0x00000004
  31. #define BCM2709_INTERRUPT_IRQ_BASIC_DOORBELL1 0x00000008
  32. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU0_HALTED 0x00000010
  33. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU1_HALTED 0x00000020
  34. #define BCM2709_INTERRUPT_IRQ_BASIC_ILLEGAL_ACCESS_1 0x00000040
  35. #define BCM2709_INTERRUPT_IRQ_BASIC_ILLEGAL_ACCESS_0 0x00000080
  36. #define BCM2709_INTERRUPT_IRQ_BASIC_MASK 0x000000FF
  37. //
  38. // Define the flags for the GPU interrupts included in the basic pending status
  39. // register.
  40. //
  41. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_7 0x00000400
  42. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_9 0x00000800
  43. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_10 0x00001000
  44. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_18 0x00002000
  45. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_19 0x00004000
  46. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_53 0x00008000
  47. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_54 0x00010000
  48. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_55 0x00020000
  49. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_56 0x00040000
  50. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_57 0x00080000
  51. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_62 0x00100000
  52. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_MASK 0x001FFC00
  53. //
  54. // Define the number of bits to shift in order to get to the GPU bits in the
  55. // basic pending register.
  56. //
  57. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_SHIFT 10
  58. //
  59. // Define the number of GPU registers whose pending status is expressed in the
  60. // basic pending status register.
  61. //
  62. #define BCM2709_INTERRUPT_IRQ_BASIC_GPU_COUNT 11
  63. //
  64. // Define the flags that signify that one of the normal pending status
  65. // registers has a pending interrupt.
  66. //
  67. #define BCM2709_INTERRUPT_IRQ_BASIC_PENDING_1 0x00000100
  68. #define BCM2709_INTERRUPT_IRQ_BASIC_PENDING_2 0x00000200
  69. #define BCM2709_INTERRUPT_IRQ_BASIC_PENDING_MASK 0x00000300
  70. //
  71. // Define the masks for GPU interrupt bits that are served by the basic
  72. // interrupt register.
  73. //
  74. #define BCM2709_INTERRUPT_IRQ1_BASIC_MASK 0x000C0680
  75. #define BCM2709_INTERRUPT_IRQ2_BASIC_MASK 0x43E00000
  76. //
  77. // Define the number of GPU interrupt lines on the BCM2709.
  78. //
  79. #define BCM2709_INTERRUPT_GPU_LINE_COUNT 64
  80. //
  81. // Define the bits for the CPU local mailbox interrupt control registers.
  82. //
  83. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_FIQ_3_ENABLE 0x00000080
  84. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_FIQ_2_ENABLE 0x00000040
  85. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_FIQ_1_ENABLE 0x00000020
  86. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_FIQ_0_ENABLE 0x00000010
  87. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_IRQ_3_ENABLE 0x00000008
  88. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_IRQ_2_ENABLE 0x00000004
  89. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_IRQ_1_ENABLE 0x00000002
  90. #define BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_IRQ_0_ENABLE 0x00000001
  91. //
  92. // Define the status bitmask for the pending IRQ local register.
  93. //
  94. #define BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_SECURE 0x00000001
  95. #define BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_NON_SECURE 0x00000002
  96. #define BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_HYPERVISOR 0x00000004
  97. #define BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_VIRTUAL 0x00000008
  98. #define BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_IPI 0x00000010
  99. #define BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_GPU 0x00000100
  100. #define BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CORE_TIMER_MASK \
  101. (BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_SECURE | \
  102. BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_NON_SECURE | \
  103. BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_HYPERVISOR | \
  104. BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CT_VIRTUAL)
  105. //
  106. // Define the number of software lines.
  107. //
  108. #define BCM2709_INTERRUPT_SOFTWARE_LINE_COUNT 32
  109. //
  110. // Define the base for the software lines.
  111. //
  112. #define BCM2709_INTERRUPT_SOFTWARE_LINE_BASE \
  113. (Bcm2709InterruptHardwareLineCount + \
  114. BCM2709_INTERRUPT_PER_PROCESSOR_LINE_COUNT)
  115. //
  116. // Define the number of per-processor interrupt lines.
  117. //
  118. #define BCM2709_INTERRUPT_PER_PROCESSOR_LINE_COUNT 32
  119. //
  120. // Define the base for the per-processor interrupt lines.
  121. //
  122. #define BCM2709_INTERRUPT_PER_PROCESSOR_LINE_BASE \
  123. Bcm2709InterruptHardwareLineCount
  124. //
  125. // Define the total number of interrupt lines.
  126. //
  127. #define BCM2709_INTERRUPT_MAX_LINE_COUNT \
  128. (Bcm2709InterruptHardwareLineCount + \
  129. BCM2709_INTERRUPT_SOFTWARE_LINE_COUNT + \
  130. BCM2709_INTERRUPT_PER_PROCESSOR_LINE_COUNT)
  131. //
  132. // Define the number of soft priorities implemented in the interrrupt
  133. // controller.
  134. //
  135. #define BCM2709_INTERRUPT_PRIORITY_COUNT 16
  136. //
  137. // Define which bits of the MPIDR are valid processor ID bits for the local
  138. // BCM2709 interrupt controller.
  139. //
  140. #define BCM2709_INTERRUPT_PROCESSOR_ID_MASK 0x000000FF
  141. //
  142. // --------------------------------------------------------------------- Macros
  143. //
  144. //
  145. // This macro translates a register and a processor ID into a local register
  146. // address. The processors' local registers are 4 bytes apart.
  147. //
  148. #define GET_LOCAL_ADDRESS(_Register, _ProcessorId) \
  149. (HlBcm2709LocalBase + ((_Register) + (0x4 * (_ProcessorId))))
  150. //
  151. // This macro translates a register and a processor ID into an IPI register
  152. // address. The processors' IPI registers are 16 bytes apart.
  153. //
  154. #define GET_IPI_ADDRESS(_Register, _ProcessorId) \
  155. (HlBcm2709LocalBase + ((_Register) + (0x10 * (_ProcessorId))))
  156. //
  157. // This macro reads from the BCM2709 interrupt controller. The parameter should
  158. // be a BCM2709_INTERRUPT_REGISTER value.
  159. //
  160. #define READ_INTERRUPT_REGISTER(_Register) \
  161. HlReadRegister32(HlBcm2709InterruptController + (_Register))
  162. //
  163. // This macro writes to the BCM2709 interrupt controller. _Register should be a
  164. // BCM2709_INTERRUPT_REGISTER value and _Value should be a ULONG. This Broadcom
  165. // interrupt controller appears to make posted writes. Perform a read of the
  166. // same register to make sure the write sticks.
  167. //
  168. #define WRITE_INTERRUPT_REGISTER(_Register, _Value) \
  169. HlWriteRegister32(HlBcm2709InterruptController + (_Register), _Value); \
  170. HlReadRegister32(HlBcm2709InterruptController + (_Register));
  171. //
  172. // This macro reads from the BCM2709 local registers. _Register should be a
  173. // BCM2709_LOCAL_REGISTER value and _ProcessorId should be the index of the
  174. // processor whose register information is being requested.
  175. //
  176. #define READ_LOCAL_REGISTER(_Register, _ProcessorId) \
  177. HlReadRegister32(GET_LOCAL_ADDRESS(_Register, _ProcessorId))
  178. //
  179. // This macro writes to the BCM2709 interrupt controller. _Register should be a
  180. // BCM2709_LOCAL_REGISTER value, _ProcessorId should be the index of the
  181. // processor whose register is being written and _Value should be a ULONG. This
  182. // Broadcom interrupt controller appears to make posted writes. Perform a read
  183. // of the same register to make sure the write sticks.
  184. //
  185. #define WRITE_LOCAL_REGISTER(_Register, _ProcessorId, _Value) \
  186. HlWriteRegister32(GET_LOCAL_ADDRESS(_Register, _ProcessorId), _Value); \
  187. HlReadRegister32(GET_LOCAL_ADDRESS(_Register, _ProcessorId));
  188. //
  189. // This macro reads from the BCM2709 local interrupt registers. _Register
  190. // should be a BCM2836_LOCAL_REGISTER value and _ProcessorId should be the
  191. // index of the processor whose register information is being requested.
  192. //
  193. #define READ_LOCAL_IPI_REGISTER(_Register, _ProcessorId) \
  194. HlReadRegister32(GET_IPI_ADDRESS(_Register, _ProcessorId))
  195. //
  196. // This macro writes to the BCM2709 local interrupt controller. _Register
  197. // should be a BCM2709_LOCAL_REGISTER value, _ProcessorId should be the index
  198. // of the processor whose register is being written, and _Value should be a
  199. // ULONG. This Broadcom interrupt controller appears to make posted writes.
  200. // Perform a read of the same register to make sure the write sticks.
  201. //
  202. #define WRITE_LOCAL_IPI_REGISTER(_Register, _ProcessorId, _Value) \
  203. HlWriteRegister32(GET_IPI_ADDRESS(_Register, _ProcessorId), _Value); \
  204. HlReadRegister32(GET_IPI_ADDRESS(_Register, _ProcessorId));
  205. //
  206. // ------------------------------------------------------ Data Type Definitions
  207. //
  208. //
  209. // Define the offsets to interrupt controller registers, in bytes.
  210. //
  211. typedef enum _BCM2709_INTERRUPT_REGISTER {
  212. Bcm2709InterruptIrqPendingBasic = 0x00,
  213. Bcm2709InterruptIrqPending1 = 0x04,
  214. Bcm2709InterruptIrqPending2 = 0x08,
  215. Bcm2709InterruptFiqControl = 0x0C,
  216. Bcm2709InterruptIrqEnable1 = 0x10,
  217. Bcm2709InterruptIrqEnable2 = 0x14,
  218. Bcm2709InterruptIrqEnableBasic = 0x18,
  219. Bcm2709InterruptIrqDisable1 = 0x1C,
  220. Bcm2709InterruptIrqDisable2 = 0x20,
  221. Bcm2709InterruptIrqDisableBasic = 0x24,
  222. Bcm2709InterruptSize = 0x28
  223. } BCM2709_INTERRUPT_REGISTER, *PBCM2709_INTERRUPT_REGISTER;
  224. //
  225. // Define the offsets to the BCM2709 local registers, in bytes.
  226. //
  227. typedef enum _BCM2836_LOCAL_REGISTER {
  228. Bcm2709LocalCoreTimerInterruptControl = 0x40,
  229. Bcm2709LocalCoreTimerInterruptControlCpu0 = 0x40,
  230. Bcm2709LocalCoreTimerInterruptControlCpu1 = 0x44,
  231. Bcm2709LocalCoreTimerInterruptControlCpu2 = 0x48,
  232. Bcm2709LocalCoreTimerInterruptControlCpu4 = 0x4C,
  233. Bcm2709LocalMailboxInterruptControl = 0x50,
  234. Bcm2709LocalMailboxInterruptControlCpu0 = 0x50,
  235. Bcm2709LocalMailboxInterruptControlCpu1 = 0x54,
  236. Bcm2709LocalMailboxInterruptControlCpu2 = 0x58,
  237. Bcm2709LocalMailboxInterruptControlCpu3 = 0x5C,
  238. Bcm2709LocalIrqPending = 0x60,
  239. Bcm2709LocalIrqPendingCpu0 = 0x60,
  240. Bcm2709LocalIrqPendingCpu1 = 0x64,
  241. Bcm2709LocalIrqPendingCpu2 = 0x68,
  242. Bcm2709LocalIrqPendingCpu3 = 0x6C,
  243. Bcm2709LocalFiqPending = 0x70,
  244. Bcm2709LocalFiqPendingCpu0 = 0x70,
  245. Bcm2709LocalFiqPendingCpu1 = 0x74,
  246. Bcm2709LocalFiqPendingCpu2 = 0x78,
  247. Bcm2709LocalFiqPendingCpu3 = 0x7C,
  248. Bcm2709LocalRequestIpi = 0x80,
  249. Bcm2709LocalRequestIpiCpu0 = 0x80,
  250. Bcm2709LocalRequestIpiCpu1 = 0x90,
  251. Bcm2709LocalRequestIpiCpu2 = 0xA0,
  252. Bcm2709LocalRequestIpiCpu3 = 0xB0,
  253. Bcm2709LocalIpiPending = 0xC0,
  254. Bcm2709LocalIpiPendingCpu0 = 0xC0,
  255. Bcm2709LocalIpiPendingCpu1 = 0xD0,
  256. Bcm2709LocalIpiPendingCpu2 = 0xE0,
  257. Bcm2709LocalIpiPendingCpu3 = 0xF0,
  258. Bcm2709LocalInterruptSize = 0x100
  259. } BCM2709_LOCAL_REGISTER, *PBCM2709_LOCAL_REGISTER;
  260. //
  261. // Define the interrupt lines for the non GPU interrupts.
  262. //
  263. typedef enum _BCM2709_CPU_INTERRUPT_LINE {
  264. Bcm2709InterruptArmTimer = 64,
  265. Bcm2709InterruptArmMailbox = 65,
  266. Bcm2709InterruptArmDoorbell0 = 66,
  267. Bcm2709InterruptArmDoorbell1 = 67,
  268. Bcm2709InterruptGpu0Halted = 68,
  269. Bcm2709InterruptGpu1Halted = 69,
  270. Bcm2709InterruptIllegalAccess1 = 70,
  271. Bcm2709InterruptIllegalAccess0 = 71,
  272. Bcm2709InterruptHardwareLineCount = 96
  273. } BCM2709_CPU_INTERRUPT_LINE, *PBCM2709_CPU_INTERRUPT_LINE;
  274. //
  275. // Define the interrupt lines for the per-processor interrupts.
  276. //
  277. typedef enum _BCM2709_PPI_INTERRUPT_LINE {
  278. Bcm2709PpiCoreTimerSecure = 96,
  279. Bcm2709PpiCoreTimerNonSecure = 97,
  280. Bcm2709PpiCoreTimerHypervisor = 98,
  281. Bcm2709PpiCoreTimerVirtual = 99,
  282. } BCM2709_PPI_INTERRUPT_LINE, *PBCM2709_PPI_INTERRUPT_LINE;
  283. /*++
  284. Structure Description:
  285. This structure defines an interrupt priority level.
  286. Members:
  287. IrqMaskBasic - Stores the mask for all basic interrupts that operate at the
  288. priority level.
  289. IrqMask1 - Stores the mask for all register 1 interrupts that operate at
  290. the priority level.
  291. IrqMask2 - Stores the mask for all register 2 interrupts that operate at
  292. the priority level.
  293. IrqMaskPpi - Stores the mask for all PPIs that operate at the priority
  294. level.
  295. IrqMaskSgi - Stores the mask for all SGIs that operate at the priority
  296. level.
  297. --*/
  298. typedef struct _BCM2709_INTERRUPT_MASK {
  299. ULONG IrqMaskBasic;
  300. ULONG IrqMask1;
  301. ULONG IrqMask2;
  302. ULONG IrqMaskPpi;
  303. ULONG IrqMaskSgi;
  304. } BCM2709_INTERRUPT_MASK, *PBCM2709_INTERRUPT_MASK;
  305. /*++
  306. Structure Description:
  307. This structure defines the processor state for the BCM2709 interrupt
  308. controller.
  309. Members:
  310. CurrentPriority - Stores the current priority level of the interrupt that
  311. is being handled.
  312. PendingIpis - Stores a mask of processor local interrupts that arrived
  313. while the processor was dispatching another IPI of the same priority or
  314. greater.
  315. --*/
  316. typedef struct _BCM2709_INTERRUPT_PROCESSOR {
  317. UCHAR CurrentPriority;
  318. ULONG PendingIpis;
  319. } BCM2709_INTERRUPT_PROCESSOR, *PBCM2709_INTERRUPT_PROCESSOR;
  320. /*++
  321. Structure Description:
  322. This structure defines the internal data for an BCM2709 interrupt
  323. controller.
  324. Members:
  325. LinePriority - Stores the priority level for each interrupt line.
  326. Masks - Stores an array of interrupt masks for each priority level.
  327. EnabledMask - Stores the mask of interrupts enabled at any priority
  328. level.
  329. ProcessorCount - Stores the total number of processors goverened by this
  330. interrupt controller.
  331. Processor - Stores an array of interrupt data for each processor, including
  332. its current priority and pending IPIs.
  333. --*/
  334. typedef struct _BCM2709_INTERRUPT_CONTROLLER {
  335. UCHAR LinePriority[BCM2709_INTERRUPT_MAX_LINE_COUNT];
  336. BCM2709_INTERRUPT_MASK Masks[BCM2709_INTERRUPT_PRIORITY_COUNT];
  337. BCM2709_INTERRUPT_MASK EnabledMask;
  338. ULONG ProcessorCount;
  339. BCM2709_INTERRUPT_PROCESSOR Processor[ANYSIZE_ARRAY];
  340. } BCM2709_INTERRUPT_CONTROLLER, *PBCM2709_INTERRUPT_CONTROLLER;
  341. //
  342. // ----------------------------------------------- Internal Function Prototypes
  343. //
  344. KSTATUS
  345. HlpBcm2709InterruptEnumerateProcessors (
  346. PVOID Context,
  347. PPROCESSOR_DESCRIPTION Descriptions,
  348. ULONG DescriptionsBufferSize
  349. );
  350. KSTATUS
  351. HlpBcm2709InterruptInitializeLocalUnit (
  352. PVOID Context,
  353. PULONG Identifier
  354. );
  355. KSTATUS
  356. HlpBcm2709InterruptInitializeIoUnit (
  357. PVOID Context
  358. );
  359. KSTATUS
  360. HlpBcm2709InterruptSetLocalUnitAddressing (
  361. PVOID Context,
  362. PINTERRUPT_HARDWARE_TARGET Target
  363. );
  364. INTERRUPT_CAUSE
  365. HlpBcm2709InterruptBegin (
  366. PVOID Context,
  367. PINTERRUPT_LINE FiringLine,
  368. PULONG MagicCandy
  369. );
  370. VOID
  371. HlpBcm2709InterruptEndOfInterrupt (
  372. PVOID Context,
  373. ULONG MagicCandy
  374. );
  375. KSTATUS
  376. HlpBcm2709InterruptRequestInterrupt (
  377. PVOID Context,
  378. PINTERRUPT_LINE Line,
  379. ULONG Vector,
  380. PINTERRUPT_HARDWARE_TARGET Target
  381. );
  382. KSTATUS
  383. HlpBcm2709InterruptStartProcessor (
  384. PVOID Context,
  385. ULONG Identifier,
  386. PHYSICAL_ADDRESS JumpAddressPhysical
  387. );
  388. KSTATUS
  389. HlpBcm2709InterruptSetLineState (
  390. PVOID Context,
  391. PINTERRUPT_LINE Line,
  392. PINTERRUPT_LINE_STATE State,
  393. PVOID ResourceData,
  394. UINTN ResourceDataSize
  395. );
  396. VOID
  397. HlpBcm2709InterruptMaskLine (
  398. PVOID Context,
  399. PINTERRUPT_LINE Line,
  400. BOOL Enable
  401. );
  402. KSTATUS
  403. HlpBcm2709InitializeController (
  404. PBCM2709_INTERRUPT_CONTROLLER Controller
  405. );
  406. KSTATUS
  407. HlpBcm2709InterruptDescribeLines (
  408. PBCM2709_INTERRUPT_CONTROLLER Controller
  409. );
  410. //
  411. // -------------------------------------------------------------------- Globals
  412. //
  413. //
  414. // Store the virtual address of the mapped interrupt controller.
  415. //
  416. PVOID HlBcm2709InterruptController = NULL;
  417. PVOID HlBcm2709LocalBase = NULL;
  418. //
  419. // Store a pointer to the BCM2709 ACPI Table.
  420. //
  421. PBCM2709_TABLE HlBcm2709Table = NULL;
  422. //
  423. // Store a table that tracks which GPU IRQs are in the basic pending status
  424. // register.
  425. //
  426. ULONG
  427. HlBcm2709InterruptIrqBasicGpuTable[BCM2709_INTERRUPT_IRQ_BASIC_GPU_COUNT] = {
  428. 7,
  429. 9,
  430. 10,
  431. 18,
  432. 19,
  433. 53,
  434. 54,
  435. 55,
  436. 56,
  437. 57,
  438. 62
  439. };
  440. //
  441. // Define the interrupt function table template.
  442. //
  443. INTERRUPT_FUNCTION_TABLE HlBcm2709InterruptFunctionTable = {
  444. HlpBcm2709InterruptInitializeIoUnit,
  445. HlpBcm2709InterruptSetLineState,
  446. HlpBcm2709InterruptMaskLine,
  447. HlpBcm2709InterruptBegin,
  448. NULL,
  449. HlpBcm2709InterruptEndOfInterrupt,
  450. HlpBcm2709InterruptRequestInterrupt,
  451. HlpBcm2709InterruptEnumerateProcessors,
  452. HlpBcm2709InterruptInitializeLocalUnit,
  453. HlpBcm2709InterruptSetLocalUnitAddressing,
  454. HlpBcm2709InterruptStartProcessor,
  455. NULL,
  456. NULL,
  457. NULL
  458. };
  459. //
  460. // ------------------------------------------------------------------ Functions
  461. //
  462. VOID
  463. HlpBcm2709InterruptModuleEntry (
  464. VOID
  465. )
  466. /*++
  467. Routine Description:
  468. This routine is the entry point for the APIC hardware module. Its role is to
  469. detect and report the prescense of an APIC.
  470. Arguments:
  471. None.
  472. Return Value:
  473. None.
  474. --*/
  475. {
  476. ULONG AllocationSize;
  477. PBCM2709_INTERRUPT_CONTROLLER Context;
  478. PBCM2709_GENERIC_ENTRY CurrentEntry;
  479. ULONG Index;
  480. INTERRUPT_CONTROLLER_DESCRIPTION NewController;
  481. ULONG ProcessorCount;
  482. KSTATUS Status;
  483. HlBcm2709Table = HlGetAcpiTable(BCM2709_SIGNATURE, NULL);
  484. if (HlBcm2709Table == NULL) {
  485. goto Bcm2709InterruptModuleEntryEnd;
  486. }
  487. //
  488. // Loop through every entry in the BCM2709 table once to determine the
  489. // number of processors in the system. If no CPU entries are found, then
  490. // there is actually just one processor.
  491. //
  492. ProcessorCount = 0;
  493. CurrentEntry = (PBCM2709_GENERIC_ENTRY)(HlBcm2709Table + 1);
  494. while ((UINTN)CurrentEntry <
  495. ((UINTN)HlBcm2709Table + HlBcm2709Table->Header.Length)) {
  496. if ((CurrentEntry->Type == Bcm2709EntryTypeCpu) &&
  497. (CurrentEntry->Length == sizeof(BCM2709_CPU_ENTRY))) {
  498. ProcessorCount += 1;
  499. }
  500. CurrentEntry = (PBCM2709_GENERIC_ENTRY)((PUCHAR)CurrentEntry +
  501. CurrentEntry->Length);
  502. }
  503. //
  504. // Allocate the interrupt controller context.
  505. //
  506. AllocationSize = sizeof(BCM2709_INTERRUPT_CONTROLLER);
  507. if (ProcessorCount > 1) {
  508. AllocationSize += sizeof(BCM2709_INTERRUPT_PROCESSOR) *
  509. (ProcessorCount - 1);
  510. }
  511. Context = HlAllocateMemory(AllocationSize,
  512. BCM2709_ALLOCATION_TAG,
  513. FALSE,
  514. NULL);
  515. if (Context == NULL) {
  516. Status = STATUS_INSUFFICIENT_RESOURCES;
  517. goto Bcm2709InterruptModuleEntryEnd;
  518. }
  519. RtlZeroMemory(Context, sizeof(BCM2709_INTERRUPT_CONTROLLER));
  520. for (Index = 0; Index < BCM2709_INTERRUPT_MAX_LINE_COUNT; Index += 1) {
  521. Context->LinePriority[Index] = BCM2709_INTERRUPT_PRIORITY_COUNT;
  522. }
  523. //
  524. // If there is only 1 processor, then the controller needs to be reported
  525. // with a processor count of 0, but recall locally that there is at least
  526. // one processor.
  527. //
  528. if (ProcessorCount == 0) {
  529. Context->ProcessorCount = 1;
  530. } else {
  531. Context->ProcessorCount = ProcessorCount;
  532. }
  533. //
  534. // Zero out the controller description.
  535. //
  536. RtlZeroMemory(&NewController, sizeof(INTERRUPT_CONTROLLER_DESCRIPTION));
  537. NewController.TableVersion = INTERRUPT_CONTROLLER_DESCRIPTION_VERSION;
  538. RtlCopyMemory(&(NewController.FunctionTable),
  539. &HlBcm2709InterruptFunctionTable,
  540. sizeof(INTERRUPT_FUNCTION_TABLE));
  541. //
  542. // If there is only one processor, do not report the multi-processor
  543. // functions.
  544. //
  545. if (ProcessorCount == 0) {
  546. NewController.FunctionTable.EnumerateProcessors = NULL;
  547. NewController.FunctionTable.InitializeLocalUnit = NULL;
  548. NewController.FunctionTable.SetLocalUnitAddressing = NULL;
  549. NewController.FunctionTable.StartProcessor = NULL;
  550. }
  551. NewController.Context = Context;
  552. NewController.Identifier = 0;
  553. NewController.ProcessorCount = ProcessorCount;
  554. NewController.PriorityCount = BCM2709_INTERRUPT_PRIORITY_COUNT;
  555. //
  556. // Register the controller with the system.
  557. //
  558. Status = HlRegisterHardware(HardwareModuleInterruptController,
  559. &NewController);
  560. if (!KSUCCESS(Status)) {
  561. goto Bcm2709InterruptModuleEntryEnd;
  562. }
  563. Bcm2709InterruptModuleEntryEnd:
  564. return;
  565. }
  566. //
  567. // --------------------------------------------------------- Internal Functions
  568. //
  569. KSTATUS
  570. HlpBcm2709InterruptEnumerateProcessors (
  571. PVOID Context,
  572. PPROCESSOR_DESCRIPTION Descriptions,
  573. ULONG DescriptionsBufferSize
  574. )
  575. /*++
  576. Routine Description:
  577. This routine describes all processors.
  578. Arguments:
  579. Context - Supplies the pointer to the controller's context, provided by the
  580. hardware module upon initialization.
  581. Descriptions - Supplies a pointer to a buffer of an array of processor
  582. descriptions that the hardware module is expected to fill out on
  583. success. The number of entries in the array is the number of processors
  584. reported during the interrupt controller registration.
  585. DescriptionsBufferSize - Supplies the size of the buffer passed. The
  586. hardware module should fail the routine if the buffer size is smaller
  587. than expected, but should not fail if the buffer size is larger than
  588. expected.
  589. Return Value:
  590. STATUS_SUCCESS on success. The Descriptions buffer will contain
  591. descriptions of all processors under the jurisdiction of the given
  592. interrupt controller.
  593. Other status codes on failure. The contents of the Descriptions buffer is
  594. undefined.
  595. --*/
  596. {
  597. PBCM2709_CPU_ENTRY CpuEntry;
  598. PBCM2709_GENERIC_ENTRY CurrentEntry;
  599. PPROCESSOR_DESCRIPTION CurrentProcessor;
  600. ULONG ProcessorCount;
  601. ULONG ProcessorId;
  602. KSTATUS Status;
  603. if (HlBcm2709Table == NULL) {
  604. Status = STATUS_NOT_INITIALIZED;
  605. goto Bcm2709InterruptEnumerateProcessorsEnd;
  606. }
  607. //
  608. // Loop through every entry in the BCM2709 table looking for CPU interfaces.
  609. //
  610. ProcessorCount = 0;
  611. CurrentProcessor = Descriptions;
  612. CurrentEntry = (PBCM2709_GENERIC_ENTRY)(HlBcm2709Table + 1);
  613. while ((UINTN)CurrentEntry <
  614. ((UINTN)HlBcm2709Table + HlBcm2709Table->Header.Length)) {
  615. if ((CurrentEntry->Type == Bcm2709EntryTypeCpu) &&
  616. (CurrentEntry->Length == sizeof(BCM2709_CPU_ENTRY))) {
  617. CpuEntry = (PBCM2709_CPU_ENTRY)CurrentEntry;
  618. ProcessorCount += 1;
  619. //
  620. // Fail if the buffer is not big enough for this processor.
  621. //
  622. if (sizeof(PROCESSOR_DESCRIPTION) * ProcessorCount >
  623. DescriptionsBufferSize) {
  624. Status = STATUS_BUFFER_TOO_SMALL;
  625. goto Bcm2709InterruptEnumerateProcessorsEnd;
  626. }
  627. CurrentProcessor->Version = PROCESSOR_DESCRIPTION_VERSION;
  628. ProcessorId = CpuEntry->ProcessorId;
  629. CurrentProcessor->PhysicalId = ProcessorId;
  630. CurrentProcessor->LogicalFlatId =
  631. 1 << (ProcessorId & BCM2709_INTERRUPT_PROCESSOR_ID_MASK);
  632. CurrentProcessor->FirmwareIdentifier = CpuEntry->ProcessorId;
  633. CurrentProcessor->Flags = 0;
  634. if ((CpuEntry->Flags & BCM2709_CPU_FLAG_ENABLED) != 0) {
  635. CurrentProcessor->Flags |= PROCESSOR_DESCRIPTION_FLAG_PRESENT;
  636. }
  637. CurrentProcessor->ParkedPhysicalAddress = CpuEntry->ParkedAddress;
  638. CurrentProcessor += 1;
  639. }
  640. CurrentEntry = (PBCM2709_GENERIC_ENTRY)((PUCHAR)CurrentEntry +
  641. CurrentEntry->Length);
  642. }
  643. Status = STATUS_SUCCESS;
  644. Bcm2709InterruptEnumerateProcessorsEnd:
  645. return Status;
  646. }
  647. KSTATUS
  648. HlpBcm2709InterruptInitializeLocalUnit (
  649. PVOID Context,
  650. PULONG Identifier
  651. )
  652. /*++
  653. Routine Description:
  654. This routine initializes the local unit of an interrupt controller. It is
  655. always called on the processor of the local unit to initialize.
  656. Arguments:
  657. Context - Supplies the pointer to the context of the I/O unit that owns
  658. this processor, provided by the hardware module upon initialization.
  659. Identifier - Supplies a pointer where this function will return the
  660. identifier of the processor being initialized.
  661. Return Value:
  662. STATUS_SUCCESS on success.
  663. Other status codes on failure.
  664. --*/
  665. {
  666. PBCM2709_INTERRUPT_CONTROLLER Controller;
  667. ULONG ProcessorId;
  668. KSTATUS Status;
  669. Controller = (PBCM2709_INTERRUPT_CONTROLLER)Context;
  670. if (HlBcm2709InterruptController == NULL) {
  671. Status = HlpBcm2709InitializeController(Controller);
  672. if (!KSUCCESS(Status)) {
  673. goto Bcm2709InterruptInitializeLocalUnitEnd;
  674. }
  675. }
  676. *Identifier = 0;
  677. if (Controller->ProcessorCount > 1) {
  678. ProcessorId = ArGetMultiprocessorIdRegister() & ARM_PROCESSOR_ID_MASK;
  679. *Identifier = ProcessorId;
  680. ProcessorId &= BCM2709_INTERRUPT_PROCESSOR_ID_MASK;
  681. WRITE_LOCAL_IPI_REGISTER(Bcm2709LocalIpiPending,
  682. ProcessorId,
  683. 0xFFFFFFFF);
  684. //
  685. // Make sure the mailbox 0 interrupt is enabled for the core. It will
  686. // be used by the IPIs.
  687. //
  688. WRITE_LOCAL_REGISTER(
  689. Bcm2709LocalMailboxInterruptControl,
  690. ProcessorId,
  691. BCM2709_INTERRUPT_LOCAL_MAILBOX_CONTROL_IRQ_0_ENABLE);
  692. }
  693. Status = STATUS_SUCCESS;
  694. Bcm2709InterruptInitializeLocalUnitEnd:
  695. return Status;
  696. }
  697. KSTATUS
  698. HlpBcm2709InterruptInitializeIoUnit (
  699. PVOID Context
  700. )
  701. /*++
  702. Routine Description:
  703. This routine initializes an interrupt controller. It's responsible for
  704. masking all interrupt lines on the controller and setting the current
  705. priority to the lowest (allow all interrupts). Once completed successfully,
  706. it is expected that interrupts can be enabled at the processor core with
  707. no interrupts occurring.
  708. Arguments:
  709. Context - Supplies the pointer to the controller's context, provided by the
  710. hardware module upon initialization.
  711. Return Value:
  712. STATUS_SUCCESS on success.
  713. Other status codes on failure.
  714. --*/
  715. {
  716. PBCM2709_INTERRUPT_CONTROLLER Controller;
  717. ULONG Index;
  718. KSTATUS Status;
  719. Controller = Context;
  720. if (HlBcm2709InterruptController == NULL) {
  721. Controller = (PBCM2709_INTERRUPT_CONTROLLER)Context;
  722. Status = HlpBcm2709InitializeController(Controller);
  723. if (!KSUCCESS(Status)) {
  724. return Status;
  725. }
  726. }
  727. //
  728. // Disable all FIQ and IRQ lines.
  729. //
  730. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisable1, 0xFFFFFFFF);
  731. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisable2, 0xFFFFFFFF);
  732. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisableBasic, 0xFFFFFFFF);
  733. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptFiqControl, 0);
  734. Controller->EnabledMask.IrqMaskBasic = 0;
  735. Controller->EnabledMask.IrqMask1 = 0;
  736. Controller->EnabledMask.IrqMask2 = 0;
  737. Controller->EnabledMask.IrqMaskPpi = 0;
  738. Controller->EnabledMask.IrqMaskSgi = 0;
  739. for (Index = 0; Index < Controller->ProcessorCount; Index += 1) {
  740. Controller->Processor[Index].CurrentPriority = 0;
  741. Controller->Processor[Index].PendingIpis = 0;
  742. }
  743. Status = STATUS_SUCCESS;
  744. return Status;
  745. }
  746. KSTATUS
  747. HlpBcm2709InterruptSetLocalUnitAddressing (
  748. PVOID Context,
  749. PINTERRUPT_HARDWARE_TARGET Target
  750. )
  751. /*++
  752. Routine Description:
  753. This routine attempts to set the current processor's addressing mode.
  754. Arguments:
  755. Context - Supplies the pointer to the controller's context, provided by the
  756. hardware module upon initialization.
  757. Target - Supplies a pointer to the targeting configuration to set for this
  758. processor.
  759. Return Value:
  760. STATUS_SUCCESS on success.
  761. STATUS_UNSUCCESSFUL if the operation failed.
  762. STATUS_NOT_SUPPORTED if this configuration is never supported on this
  763. hardware.
  764. --*/
  765. {
  766. KSTATUS Status;
  767. UCHAR ThisProcessorTarget;
  768. ThisProcessorTarget = ArGetMultiprocessorIdRegister() &
  769. ARM_PROCESSOR_ID_MASK;
  770. switch (Target->Addressing) {
  771. case InterruptAddressingLogicalClustered:
  772. Status = STATUS_NOT_SUPPORTED;
  773. break;
  774. case InterruptAddressingPhysical:
  775. if (Target->U.PhysicalId != ThisProcessorTarget) {
  776. Status = STATUS_UNSUCCESSFUL;
  777. goto SetLocalUnitAddressingEnd;
  778. }
  779. Status = STATUS_SUCCESS;
  780. break;
  781. case InterruptAddressingLogicalFlat:
  782. ThisProcessorTarget &= BCM2709_INTERRUPT_PROCESSOR_ID_MASK;
  783. if (Target->U.LogicalFlatId != (1 << ThisProcessorTarget)) {
  784. Status = STATUS_UNSUCCESSFUL;
  785. goto SetLocalUnitAddressingEnd;
  786. }
  787. Status = STATUS_SUCCESS;
  788. break;
  789. default:
  790. Status = STATUS_INVALID_PARAMETER;
  791. goto SetLocalUnitAddressingEnd;
  792. }
  793. SetLocalUnitAddressingEnd:
  794. return Status;
  795. }
  796. INTERRUPT_CAUSE
  797. HlpBcm2709InterruptBegin (
  798. PVOID Context,
  799. PINTERRUPT_LINE FiringLine,
  800. PULONG MagicCandy
  801. )
  802. /*++
  803. Routine Description:
  804. This routine is called when an interrupt fires. Its role is to determine
  805. if an interrupt has fired on the given controller, accept it, and determine
  806. which line fired if any. This routine will always be called with interrupts
  807. disabled at the processor core.
  808. Arguments:
  809. Context - Supplies the pointer to the controller's context, provided by the
  810. hardware module upon initialization.
  811. FiringLine - Supplies a pointer where the interrupt hardware module will
  812. fill in which line fired, if applicable.
  813. MagicCandy - Supplies a pointer where the interrupt hardware module can
  814. store 32 bits of private information regarding this interrupt. This
  815. information will be returned to it when the End Of Interrupt routine
  816. is called.
  817. Return Value:
  818. Returns an interrupt cause indicating whether or not an interrupt line,
  819. spurious interrupt, or no interrupt fired on this controller.
  820. --*/
  821. {
  822. ULONG Base;
  823. ULONG BasicMask;
  824. BOOL CheckGpu;
  825. PBCM2709_INTERRUPT_CONTROLLER Controller;
  826. BOOL Disabled;
  827. ULONG DisableMask;
  828. BOOL HandleInterrupt;
  829. ULONG Line;
  830. PBCM2709_INTERRUPT_MASK Mask;
  831. ULONG PendingIpi;
  832. ULONG PendingIrq;
  833. UCHAR Priority;
  834. PBCM2709_INTERRUPT_PROCESSOR Processor;
  835. ULONG ProcessorId;
  836. BCM2709_INTERRUPT_REGISTER Register;
  837. CheckGpu = TRUE;
  838. HandleInterrupt = FALSE;
  839. //
  840. // Determine which processor the interrupt arrived on.
  841. //
  842. Controller = (PBCM2709_INTERRUPT_CONTROLLER)Context;
  843. ProcessorId = 0;
  844. if (Controller->ProcessorCount > 1) {
  845. ProcessorId = ArGetMultiprocessorIdRegister() &
  846. BCM2709_INTERRUPT_PROCESSOR_ID_MASK;
  847. }
  848. Processor = &(Controller->Processor[ProcessorId]);
  849. //
  850. // If there are multiple processors available, then check for an IPI first.
  851. //
  852. if (Controller->ProcessorCount > 1) {
  853. //
  854. // If the IPI flag is set in the pending IRQ mask, attempt to handle
  855. // the IPI.
  856. //
  857. PendingIrq = READ_LOCAL_REGISTER(Bcm2709LocalIrqPending, ProcessorId);
  858. if ((PendingIrq & BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_IPI) != 0) {
  859. PendingIpi = READ_LOCAL_IPI_REGISTER(Bcm2709LocalIpiPending,
  860. ProcessorId);
  861. if (PendingIpi != 0) {
  862. Line = RtlCountTrailingZeros32(PendingIpi);
  863. PendingIpi = 1 << Line;
  864. WRITE_LOCAL_IPI_REGISTER(Bcm2709LocalIpiPending,
  865. ProcessorId,
  866. PendingIpi);
  867. //
  868. // If this IPI is disabled at the current priority, keep it
  869. // pended. Otherwise handle the IPI.
  870. //
  871. Mask = &(Controller->Masks[Processor->CurrentPriority]);
  872. if ((PendingIpi & Mask->IrqMaskSgi) != 0) {
  873. Processor->PendingIpis |= PendingIpi;
  874. return InterruptCauseSpuriousInterrupt;
  875. }
  876. //
  877. // If an IPI was present and acknowledged, never do further
  878. // checks for GPU interrupts.
  879. //
  880. CheckGpu = FALSE;
  881. HandleInterrupt = TRUE;
  882. Line += BCM2709_INTERRUPT_SOFTWARE_LINE_BASE;
  883. }
  884. } else if ((PendingIrq &
  885. BCM2709_INTERRUPT_LOCAL_IRQ_PENDING_CORE_TIMER_MASK) != 0) {
  886. PendingIrq = READ_LOCAL_REGISTER(
  887. Bcm2709LocalCoreTimerInterruptControl,
  888. ProcessorId);
  889. if (PendingIrq != 0) {
  890. Line = RtlCountTrailingZeros32(PendingIrq);
  891. Line += BCM2709_INTERRUPT_PER_PROCESSOR_LINE_BASE;
  892. CheckGpu = FALSE;
  893. HandleInterrupt = TRUE;
  894. }
  895. }
  896. }
  897. //
  898. // Determine which interrupt fired based on the pending status. Only handle
  899. // GPU interrupts on processor zero as there is no interrupt stearing.
  900. //
  901. if ((ProcessorId == 0) && (CheckGpu != FALSE)) {
  902. PendingIrq = READ_INTERRUPT_REGISTER(Bcm2709InterruptIrqPendingBasic);
  903. if (PendingIrq == 0) {
  904. return InterruptCauseNoInterruptHere;
  905. }
  906. //
  907. // If this is a basic interrupt, then determine which line fired based
  908. // on the bit set.
  909. //
  910. if ((PendingIrq & BCM2709_INTERRUPT_IRQ_BASIC_MASK) != 0) {
  911. PendingIrq &= BCM2709_INTERRUPT_IRQ_BASIC_MASK;
  912. Line = RtlCountTrailingZeros32(PendingIrq);
  913. Line += Bcm2709InterruptArmTimer;
  914. //
  915. // If this is a GPU interrupt that gets set in the basic pending status
  916. // register, then check which bit is set. The pending 1 and 2 bits do
  917. // not get set for these interrupts.
  918. //
  919. } else if ((PendingIrq & BCM2709_INTERRUPT_IRQ_BASIC_GPU_MASK) != 0) {
  920. PendingIrq = PendingIrq >> BCM2709_INTERRUPT_IRQ_BASIC_GPU_SHIFT;
  921. Line = RtlCountTrailingZeros32(PendingIrq);
  922. Line = HlBcm2709InterruptIrqBasicGpuTable[Line];
  923. } else {
  924. if ((PendingIrq & BCM2709_INTERRUPT_IRQ_BASIC_PENDING_1) != 0) {
  925. Register = Bcm2709InterruptIrqPending1;
  926. BasicMask = BCM2709_INTERRUPT_IRQ1_BASIC_MASK;
  927. Base = 0;
  928. } else {
  929. Register = Bcm2709InterruptIrqPending2;
  930. BasicMask = BCM2709_INTERRUPT_IRQ2_BASIC_MASK;
  931. Base = 32;
  932. }
  933. //
  934. // Remove the GPU interrupts that appear in the basic register in
  935. // order to count the trailing zeros.
  936. //
  937. PendingIrq = READ_INTERRUPT_REGISTER(Register);
  938. PendingIrq &= ~BasicMask;
  939. Line = RtlCountTrailingZeros32(PendingIrq);
  940. Line += Base;
  941. }
  942. HandleInterrupt = TRUE;
  943. }
  944. if (HandleInterrupt == FALSE) {
  945. return InterruptCauseNoInterruptHere;
  946. }
  947. //
  948. // Processor zero is the only core that receives interrupts that are not
  949. // IPIs and PPIs. So, if this is processor 0, mask all of the interrupts
  950. // at or below the firing line's priority level.
  951. //
  952. Disabled = FALSE;
  953. Priority = Controller->LinePriority[Line];
  954. if (ProcessorId == 0) {
  955. Mask = &(Controller->Masks[Priority]);
  956. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisableBasic,
  957. Mask->IrqMaskBasic);
  958. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisable1, Mask->IrqMask1);
  959. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqDisable2, Mask->IrqMask2);
  960. Disabled = TRUE;
  961. }
  962. //
  963. // If there is more than one core, then PPIs may be enabled. Disable all of
  964. // the PPIs enabled at or below the firing line's priority level. IPIs
  965. // cannot be disabled in the hardware, so even those are per-processor,
  966. // they are treated separately.
  967. //
  968. if (Controller->ProcessorCount > 1) {
  969. Mask = &(Controller->Masks[Priority]);
  970. DisableMask = ~Mask->IrqMaskPpi & Controller->EnabledMask.IrqMaskPpi;
  971. WRITE_LOCAL_REGISTER(Bcm2709LocalCoreTimerInterruptControl,
  972. ProcessorId,
  973. DisableMask);
  974. Disabled = TRUE;
  975. }
  976. //
  977. // Now that the interrupt is disabled, if the firing interrupt's priority
  978. // is less than the current priority, treat it as spurious. This can happen
  979. // if another core enables an interrupt line while core zero is running at
  980. // a higher priority. This spurious interrupt will be re-enabled when core
  981. // zero lowers its priority. It should fire again at that point.
  982. //
  983. if ((Disabled != FALSE) && (Priority < Processor->CurrentPriority)) {
  984. return InterruptCauseSpuriousInterrupt;
  985. }
  986. //
  987. // Save the previous priority to know where to get back to when this
  988. // interrupt completes.
  989. //
  990. *MagicCandy = Processor->CurrentPriority;
  991. Processor->CurrentPriority = Priority;
  992. //
  993. // Return the interrupt line information.
  994. //
  995. FiringLine->Type = InterruptLineControllerSpecified;
  996. FiringLine->U.Local.Controller = 0;
  997. FiringLine->U.Local.Line = Line;
  998. return InterruptCauseLineFired;
  999. }
  1000. VOID
  1001. HlpBcm2709InterruptEndOfInterrupt (
  1002. PVOID Context,
  1003. ULONG MagicCandy
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This routine is called after an interrupt has fired and been serviced. Its
  1008. role is to tell the interrupt controller that processing has completed.
  1009. This routine will always be called with interrupts disabled at the
  1010. processor core.
  1011. Arguments:
  1012. Context - Supplies the pointer to the controller's context, provided by the
  1013. hardware module upon initialization.
  1014. MagicCandy - Supplies the magic candy that that the interrupt hardware
  1015. module stored when the interrupt began.
  1016. Return Value:
  1017. None.
  1018. --*/
  1019. {
  1020. PBCM2709_INTERRUPT_CONTROLLER Controller;
  1021. ULONG EnableMask;
  1022. PBCM2709_INTERRUPT_MASK Mask;
  1023. ULONG PendingIpis;
  1024. UCHAR PreviousPriority;
  1025. PBCM2709_INTERRUPT_PROCESSOR Processor;
  1026. ULONG ProcessorId;
  1027. Controller = (PBCM2709_INTERRUPT_CONTROLLER)Context;
  1028. ProcessorId = 0;
  1029. if (Controller->ProcessorCount > 1) {
  1030. ProcessorId = ArGetMultiprocessorIdRegister() &
  1031. BCM2709_INTERRUPT_PROCESSOR_ID_MASK;
  1032. }
  1033. //
  1034. // Set the interrupt masks to correspond to what they were before this
  1035. // interrupt began and raised the priority. Use the enable mask to avoid
  1036. // simply enabling every interrupt ever. Only modify the GPU and CPU
  1037. // interrupt lines on processor 0.
  1038. //
  1039. PreviousPriority = MagicCandy;
  1040. Mask = &(Controller->Masks[PreviousPriority]);
  1041. Controller->Processor[ProcessorId].CurrentPriority = PreviousPriority;
  1042. if (ProcessorId == 0) {
  1043. EnableMask = ~Mask->IrqMaskBasic & Controller->EnabledMask.IrqMaskBasic;
  1044. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqEnableBasic, EnableMask);
  1045. EnableMask = ~Mask->IrqMask1 & Controller->EnabledMask.IrqMask1;
  1046. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqEnable1, EnableMask);
  1047. EnableMask = ~Mask->IrqMask2 & Controller->EnabledMask.IrqMask2;
  1048. WRITE_INTERRUPT_REGISTER(Bcm2709InterruptIrqEnable2, EnableMask);
  1049. }
  1050. //
  1051. // Check the PPI and IPI masks on all cores to see if the lowering of the
  1052. // priority re-enables some per-processor interrupts. If there were any
  1053. // pending IPIs in the re-enabled set, replay those interrupts.
  1054. //
  1055. if (Controller->ProcessorCount > 1) {
  1056. EnableMask = ~Mask->IrqMaskPpi & Controller->EnabledMask.IrqMaskPpi;
  1057. if (EnableMask != 0) {
  1058. WRITE_LOCAL_REGISTER(Bcm2709LocalCoreTimerInterruptControl,
  1059. ProcessorId,
  1060. EnableMask);
  1061. }
  1062. EnableMask = ~Mask->IrqMaskSgi & Controller->EnabledMask.IrqMaskSgi;
  1063. if (EnableMask != 0) {
  1064. Processor = &(Controller->Processor[ProcessorId]);
  1065. PendingIpis = EnableMask & Processor->PendingIpis;
  1066. if (PendingIpis != 0) {
  1067. Processor->PendingIpis &= ~PendingIpis;
  1068. WRITE_LOCAL_IPI_REGISTER(Bcm2709LocalRequestIpi,
  1069. ProcessorId,
  1070. PendingIpis);
  1071. }
  1072. }
  1073. }
  1074. return;
  1075. }
  1076. KSTATUS
  1077. HlpBcm2709InterruptRequestInterrupt (
  1078. PVOID Context,
  1079. PINTERRUPT_LINE Line,
  1080. ULONG Vector,
  1081. PINTERRUPT_HARDWARE_TARGET Target
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. This routine requests a hardware interrupt on the given line.
  1086. Arguments:
  1087. Context - Supplies the pointer to the controller's context, provided by the
  1088. hardware module upon initialization.
  1089. Line - Supplies a pointer to the interrupt line to spark.
  1090. Vector - Supplies the vector to generate the interrupt on (for vectored
  1091. architectures only).
  1092. Target - Supplies a pointer to the set of processors to target.
  1093. Return Value:
  1094. STATUS_SUCCESS on success.
  1095. Error code on failure.
  1096. --*/
  1097. {
  1098. PBCM2709_INTERRUPT_CONTROLLER Controller;
  1099. ULONG InterruptValue;
  1100. ULONG ProcessorId;
  1101. ULONG ProcessorMask;
  1102. KSTATUS Status;
  1103. Controller = (PBCM2709_INTERRUPT_CONTROLLER)Context;
  1104. //
  1105. // Currently requesting device interrupts is not supported. This support
  1106. // will probably have to be added when deep power management comes online.
  1107. //
  1108. if (Line->U.Local.Line < BCM2709_INTERRUPT_SOFTWARE_LINE_BASE) {
  1109. Status = STATUS_NOT_IMPLEMENTED;
  1110. goto Bcm2709InterruptRequestInterruptEnd;
  1111. }
  1112. Status = STATUS_SUCCESS;
  1113. ProcessorMask = 0;
  1114. switch (Target->Addressing) {
  1115. case InterruptAddressingLogicalClustered:
  1116. Status = STATUS_NOT_SUPPORTED;
  1117. break;
  1118. case InterruptAddressingSelf:
  1119. ProcessorId = ArGetMultiprocessorIdRegister();
  1120. ProcessorId &= BCM2709_INTERRUPT_PROCESSOR_ID_MASK;
  1121. ProcessorMask = 1 << ProcessorId;
  1122. break;
  1123. case InterruptAddressingAll:
  1124. ProcessorMask = (1 << Controller->ProcessorCount) - 1;
  1125. break;
  1126. case InterruptAddressingAllExcludingSelf:
  1127. ProcessorId = ArGetMultiprocessorIdRegister();
  1128. ProcessorId &= BCM2709_INTERRUPT_PROCESSOR_ID_MASK;
  1129. ProcessorMask = (1 << Controller->ProcessorCount) - 1;
  1130. ProcessorMask &= ~(1 << ProcessorId);
  1131. break;
  1132. case InterruptAddressingLogicalFlat:
  1133. ProcessorMask = Target->U.LogicalFlatId;
  1134. break;
  1135. case InterruptAddressingPhysical:
  1136. ProcessorMask =
  1137. 1 << (Target->U.PhysicalId & BCM2709_INTERRUPT_PROCESSOR_ID_MASK);
  1138. break;
  1139. default:
  1140. Status = STATUS_INVALID_PARAMETER;
  1141. break;
  1142. }
  1143. if (!KSUCCESS(Status)) {
  1144. goto Bcm2709InterruptRequestInterruptEnd;
  1145. }
  1146. InterruptValue =
  1147. 1 << (Line->U.Local.Line - BCM2709_INTERRUPT_SOFTWARE_LINE_BASE);
  1148. //
  1149. // Write the command out to the software interrupt register for each
  1150. // processor targeted by the interrupt.
  1151. //
  1152. ProcessorId = 0;
  1153. while (ProcessorMask != 0) {
  1154. if ((ProcessorMask & 0x1) == 0) {
  1155. ProcessorMask >>= 1;
  1156. ProcessorId += 1;
  1157. continue;
  1158. }
  1159. WRITE_LOCAL_IPI_REGISTER(Bcm2709LocalRequestIpi,
  1160. ProcessorId,
  1161. InterruptValue);
  1162. ProcessorMask >>= 1;
  1163. ProcessorId += 1;
  1164. }
  1165. Bcm2709InterruptRequestInterruptEnd:
  1166. return Status;
  1167. }
  1168. KSTATUS
  1169. HlpBcm2709InterruptStartProcessor (
  1170. PVOID Context,
  1171. ULONG Identifier,
  1172. PHYSICAL_ADDRESS JumpAddressPhysical
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. This routine attempts to start the given processor.
  1177. Arguments:
  1178. Context - Supplies the pointer to the controller's context, provided by the
  1179. hardware module upon initialization.
  1180. Identifier - Supplies the identifier of the processor to start.
  1181. JumpAddressPhysical - Supplies the physical address of the location that
  1182. new processor should jump to.
  1183. Return Value:
  1184. STATUS_SUCCESS if the start command was successfully sent.
  1185. Error code on failure.
  1186. --*/
  1187. {
  1188. INTERRUPT_LINE Line;
  1189. KSTATUS Status;
  1190. INTERRUPT_HARDWARE_TARGET Target;
  1191. Line.Type = InterruptLineControllerSpecified;
  1192. Line.U.Local.Controller = 0;
  1193. Line.U.Local.Line = BCM2709_INTERRUPT_SOFTWARE_LINE_BASE;
  1194. Target.Addressing = InterruptAddressingPhysical;
  1195. Target.U.PhysicalId = Identifier;
  1196. Status = HlpBcm2709InterruptRequestInterrupt(Context, &Line, 0, &Target);
  1197. return Status;
  1198. }
  1199. KSTATUS
  1200. HlpBcm2709InterruptSetLineState (
  1201. PVOID Context,
  1202. PINTERRUPT_LINE Line,
  1203. PINTERRUPT_LINE_STATE State,
  1204. PVOID ResourceData,
  1205. UINTN ResourceDataSize
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This routine enables or disables and configures an interrupt line.
  1210. Arguments:
  1211. Context - Supplies the pointer to the controller's context, provided by the
  1212. hardware module upon initialization.
  1213. Line - Supplies a pointer to the line to set up. This will always be a
  1214. controller specified line.
  1215. State - Supplies a pointer to the new configuration of the line.
  1216. ResourceData - Supplies an optional pointer to the device specific resource
  1217. data for the interrupt line.
  1218. ResourceDataSize - Supplies the size of the resource data, in bytes.
  1219. Return Value:
  1220. Status code.
  1221. --*/
  1222. {
  1223. PBCM2709_INTERRUPT_CONTROLLER Controller;
  1224. ULONG Index;
  1225. ULONG LineNumber;
  1226. BOOL LocalInterrupt;
  1227. BCM2709_INTERRUPT_MASK Mask;
  1228. BOOL PpiInterrupt;
  1229. UCHAR Priority;
  1230. BCM2709_INTERRUPT_REGISTER Register;
  1231. ULONG RegisterValue;
  1232. ULONG Shift;
  1233. KSTATUS Status;
  1234. Controller = (PBCM2709_INTERRUPT_CONTROLLER)Context;
  1235. LineNumber = Line->U.Local.Line;
  1236. if ((Line->Type != InterruptLineControllerSpecified) ||
  1237. (Line->U.Local.Controller != 0) ||
  1238. (LineNumber >= BCM2709_INTERRUPT_MAX_LINE_COUNT)) {
  1239. Status = STATUS_INVALID_PARAMETER;
  1240. goto Bcm2709SetLineStateEnd;
  1241. }
  1242. if ((State->Output.Type != InterruptLineControllerSpecified) ||
  1243. (State->Output.U.Local.Controller != INTERRUPT_CPU_IDENTIFIER) ||
  1244. (State->Output.U.Local.Line != INTERRUPT_CPU_IRQ_PIN)) {
  1245. Status = STATUS_INVALID_PARAMETER;
  1246. goto Bcm2709SetLineStateEnd;
  1247. }
  1248. RtlZeroMemory(&Mask, sizeof(BCM2709_INTERRUPT_MASK));
  1249. LocalInterrupt = FALSE;
  1250. PpiInterrupt = FALSE;
  1251. //
  1252. // If the line is a GPU line, then determine which of the two
  1253. // disable/enable registers it belongs to.
  1254. //
  1255. if (LineNumber < BCM2709_INTERRUPT_GPU_LINE_COUNT) {
  1256. Shift = LineNumber;
  1257. if (LineNumber >= 32) {
  1258. Shift -= 32;
  1259. }
  1260. RegisterValue = 1 << Shift;
  1261. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) == 0) {
  1262. if (LineNumber < 32) {
  1263. Register = Bcm2709InterruptIrqDisable1;
  1264. } else {
  1265. Register = Bcm2709InterruptIrqDisable2;
  1266. }
  1267. } else {
  1268. if (LineNumber < 32) {
  1269. Register = Bcm2709InterruptIrqEnable1;
  1270. } else {
  1271. Register = Bcm2709InterruptIrqEnable2;
  1272. }
  1273. }
  1274. //
  1275. // Set the mask in the priority level.
  1276. //
  1277. if (LineNumber < 32) {
  1278. Mask.IrqMask1 |= RegisterValue;
  1279. } else {
  1280. Mask.IrqMask2 |= RegisterValue;
  1281. }
  1282. //
  1283. // If this is an ARM line, then get the correct register and mask.
  1284. //
  1285. } else if (LineNumber < Bcm2709InterruptHardwareLineCount) {
  1286. Shift = LineNumber - BCM2709_INTERRUPT_GPU_LINE_COUNT;
  1287. RegisterValue = 1 << Shift;
  1288. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) == 0) {
  1289. Register = Bcm2709InterruptIrqDisableBasic;
  1290. } else {
  1291. Register = Bcm2709InterruptIrqEnableBasic;
  1292. }
  1293. //
  1294. // Set the mask in the priority level.
  1295. //
  1296. Mask.IrqMaskBasic |= RegisterValue;
  1297. //
  1298. // If this is a per-processor interrupt, prepare to enable/disable on each
  1299. // core.
  1300. //
  1301. } else if (LineNumber < BCM2709_INTERRUPT_SOFTWARE_LINE_BASE) {
  1302. PpiInterrupt = TRUE;
  1303. Register = Bcm2709LocalCoreTimerInterruptControl;
  1304. Shift = LineNumber - BCM2709_INTERRUPT_PER_PROCESSOR_LINE_BASE;
  1305. Mask.IrqMaskPpi |= 1 << Shift;
  1306. //
  1307. // Otherwise this is a software interrupt.
  1308. //
  1309. } else {
  1310. LocalInterrupt = TRUE;
  1311. Shift = LineNumber - BCM2709_INTERRUPT_SOFTWARE_LINE_BASE;
  1312. Mask.IrqMaskSgi |= 1 << Shift;
  1313. }
  1314. //
  1315. // If the interrupt is about to be enabled, make sure the priority mask is
  1316. // updated first.
  1317. //
  1318. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) != 0) {
  1319. Controller->EnabledMask.IrqMaskBasic |= Mask.IrqMaskBasic;
  1320. Controller->EnabledMask.IrqMask1 |= Mask.IrqMask1;
  1321. Controller->EnabledMask.IrqMask2 |= Mask.IrqMask2;
  1322. Controller->EnabledMask.IrqMaskPpi |= Mask.IrqMaskPpi;
  1323. Controller->EnabledMask.IrqMaskSgi |= Mask.IrqMaskSgi;
  1324. Priority = State->HardwarePriority;
  1325. Controller->LinePriority[LineNumber] = Priority;
  1326. //
  1327. // This interrupt should be masked for any priority at or above it.
  1328. //
  1329. for (Index = Priority;
  1330. Index < BCM2709_INTERRUPT_PRIORITY_COUNT;
  1331. Index += 1) {
  1332. Controller->Masks[Index].IrqMaskBasic |= Mask.IrqMaskBasic;
  1333. Controller->Masks[Index].IrqMask1 |= Mask.IrqMask1;
  1334. Controller->Masks[Index].IrqMask2 |= Mask.IrqMask2;
  1335. Controller->Masks[Index].IrqMaskPpi |= Mask.IrqMaskPpi;
  1336. Controller->Masks[Index].IrqMaskSgi |= Mask.IrqMaskSgi;
  1337. }
  1338. }
  1339. //
  1340. // Change the state of the interrupt based on the register and the value
  1341. // determined above. There is nothing to do for IPIs, but for regular PPIs
  1342. // the interrupt must be enabled/disabled on each core.
  1343. //
  1344. if (LocalInterrupt == FALSE) {
  1345. if (PpiInterrupt == FALSE) {
  1346. WRITE_INTERRUPT_REGISTER(Register, RegisterValue);
  1347. } else {
  1348. for (Index = 0; Index < Controller->ProcessorCount; Index += 1) {
  1349. RegisterValue = READ_LOCAL_REGISTER(
  1350. Bcm2709LocalCoreTimerInterruptControl,
  1351. Index);
  1352. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) == 0) {
  1353. RegisterValue &= ~Mask.IrqMaskPpi;
  1354. } else {
  1355. RegisterValue |= Mask.IrqMaskPpi;
  1356. }
  1357. WRITE_LOCAL_REGISTER(Bcm2709LocalCoreTimerInterruptControl,
  1358. Index,
  1359. RegisterValue);
  1360. }
  1361. }
  1362. }
  1363. //
  1364. // If the interrupt was just disabled, make sure the priority mask is
  1365. // updated after.
  1366. //
  1367. if ((State->Flags & INTERRUPT_LINE_STATE_FLAG_ENABLED) == 0) {
  1368. Controller->EnabledMask.IrqMaskBasic &= ~Mask.IrqMaskBasic;
  1369. Controller->EnabledMask.IrqMask1 &= ~Mask.IrqMask1;
  1370. Controller->EnabledMask.IrqMask2 &= ~Mask.IrqMask2;
  1371. Controller->EnabledMask.IrqMaskPpi &= ~Mask.IrqMaskPpi;
  1372. Controller->EnabledMask.IrqMaskSgi &= ~Mask.IrqMaskSgi;
  1373. //
  1374. // Remove the mask for this interrupt at any priority.
  1375. //
  1376. for (Index = 0;
  1377. Index < BCM2709_INTERRUPT_PRIORITY_COUNT;
  1378. Index += 1) {
  1379. Controller->Masks[Index].IrqMaskBasic &= ~Mask.IrqMaskBasic;
  1380. Controller->Masks[Index].IrqMask1 &= ~Mask.IrqMask1;
  1381. Controller->Masks[Index].IrqMask2 &= ~Mask.IrqMask2;
  1382. Controller->Masks[Index].IrqMaskPpi &= ~Mask.IrqMaskPpi;
  1383. Controller->Masks[Index].IrqMaskSgi &= ~Mask.IrqMaskSgi;
  1384. }
  1385. }
  1386. Status = STATUS_SUCCESS;
  1387. Bcm2709SetLineStateEnd:
  1388. return Status;
  1389. }
  1390. VOID
  1391. HlpBcm2709InterruptMaskLine (
  1392. PVOID Context,
  1393. PINTERRUPT_LINE Line,
  1394. BOOL Enable
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. This routine masks or unmasks an interrupt line, leaving the rest of the
  1399. line state intact.
  1400. Arguments:
  1401. Context - Supplies the pointer to the controller's context, provided by the
  1402. hardware module upon initialization.
  1403. Line - Supplies a pointer to the line to maek or unmask. This will always
  1404. be a controller specified line.
  1405. Enable - Supplies a boolean indicating whether to mask the interrupt,
  1406. preventing interrupts from coming through (FALSE), or enable the line
  1407. and allow interrupts to come through (TRUE).
  1408. Return Value:
  1409. None.
  1410. --*/
  1411. {
  1412. PBCM2709_INTERRUPT_CONTROLLER Controller;
  1413. ULONG Index;
  1414. ULONG LineNumber;
  1415. ULONG Mask;
  1416. BCM2709_INTERRUPT_REGISTER Register;
  1417. ULONG RegisterValue;
  1418. ULONG Shift;
  1419. Controller = (PBCM2709_INTERRUPT_CONTROLLER)Context;
  1420. LineNumber = Line->U.Local.Line;
  1421. //
  1422. // Handle GPU interrupts.
  1423. //
  1424. if (LineNumber < Bcm2709InterruptHardwareLineCount) {
  1425. //
  1426. // If the line is a GPU line, then determine which of the two
  1427. // disable/enable registers it belongs to.
  1428. //
  1429. if (LineNumber < BCM2709_INTERRUPT_GPU_LINE_COUNT) {
  1430. Shift = LineNumber;
  1431. if (LineNumber >= 32) {
  1432. Shift -= 32;
  1433. }
  1434. RegisterValue = 1 << Shift;
  1435. if (Enable == FALSE) {
  1436. if (LineNumber < 32) {
  1437. Register = Bcm2709InterruptIrqDisable1;
  1438. } else {
  1439. Register = Bcm2709InterruptIrqDisable2;
  1440. }
  1441. } else {
  1442. if (LineNumber < 32) {
  1443. Register = Bcm2709InterruptIrqEnable1;
  1444. } else {
  1445. Register = Bcm2709InterruptIrqEnable2;
  1446. }
  1447. }
  1448. //
  1449. // Otherwise the interrupt belongs to the basic enable and disable
  1450. // registers.
  1451. //
  1452. } else {
  1453. Shift = LineNumber - BCM2709_INTERRUPT_GPU_LINE_COUNT;
  1454. RegisterValue = 1 << Shift;
  1455. if (Enable == FALSE) {
  1456. Register = Bcm2709InterruptIrqDisableBasic;
  1457. } else {
  1458. Register = Bcm2709InterruptIrqEnableBasic;
  1459. }
  1460. }
  1461. WRITE_INTERRUPT_REGISTER(Register, RegisterValue);
  1462. //
  1463. // Handle per-processor interrupts.
  1464. //
  1465. } else if (LineNumber < BCM2709_INTERRUPT_SOFTWARE_LINE_BASE) {
  1466. LineNumber -= BCM2709_INTERRUPT_PER_PROCESSOR_LINE_BASE;
  1467. Mask = 1 << LineNumber;
  1468. for (Index = 0; Index < Controller->ProcessorCount; Index += 1) {
  1469. RegisterValue = READ_LOCAL_REGISTER(
  1470. Bcm2709LocalCoreTimerInterruptControl,
  1471. Index);
  1472. if (Enable == FALSE) {
  1473. RegisterValue &= ~Mask;
  1474. } else {
  1475. RegisterValue |= Mask;
  1476. }
  1477. WRITE_LOCAL_REGISTER(Bcm2709LocalCoreTimerInterruptControl,
  1478. Index,
  1479. RegisterValue);
  1480. }
  1481. }
  1482. return;
  1483. }
  1484. KSTATUS
  1485. HlpBcm2709InitializeController (
  1486. PBCM2709_INTERRUPT_CONTROLLER Controller
  1487. )
  1488. /*++
  1489. Routine Description:
  1490. This routine initialized the interrupt controller state for the BCM2709
  1491. interrupt controller.
  1492. Arguments:
  1493. Controller - Supplies a pointer to the BCM2709 interrupt controller being
  1494. initialized.
  1495. Return Value:
  1496. Status code.
  1497. --*/
  1498. {
  1499. PVOID InterruptController;
  1500. PVOID LocalBase;
  1501. PHYSICAL_ADDRESS PhysicalAddress;
  1502. KSTATUS Status;
  1503. Status = STATUS_SUCCESS;
  1504. if (HlBcm2709InterruptController == NULL) {
  1505. PhysicalAddress = HlBcm2709Table->InterruptControllerPhysicalAddress;
  1506. InterruptController = HlMapPhysicalAddress(PhysicalAddress,
  1507. Bcm2709InterruptSize,
  1508. TRUE);
  1509. if (InterruptController == NULL) {
  1510. Status = STATUS_INSUFFICIENT_RESOURCES;
  1511. goto Bcm2709InitializeControllerEnd;
  1512. }
  1513. HlBcm2709InterruptController = InterruptController;
  1514. PhysicalAddress = HlBcm2709Table->CpuLocalPhysicalAddress;
  1515. if ((HlBcm2709LocalBase == NULL) && (PhysicalAddress != 0)) {
  1516. LocalBase = HlMapPhysicalAddress(PhysicalAddress,
  1517. Bcm2709LocalInterruptSize,
  1518. TRUE);
  1519. if (LocalBase == NULL) {
  1520. Status = STATUS_INSUFFICIENT_RESOURCES;
  1521. goto Bcm2709InitializeControllerEnd;
  1522. }
  1523. HlBcm2709LocalBase = LocalBase;
  1524. }
  1525. Status = HlpBcm2709InterruptDescribeLines(Controller);
  1526. if (!KSUCCESS(Status)) {
  1527. goto Bcm2709InitializeControllerEnd;
  1528. }
  1529. }
  1530. Bcm2709InitializeControllerEnd:
  1531. return Status;
  1532. }
  1533. KSTATUS
  1534. HlpBcm2709InterruptDescribeLines (
  1535. PBCM2709_INTERRUPT_CONTROLLER Controller
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. This routine describes all interrupt lines to the system.
  1540. Arguments:
  1541. Controller - Supplies a pointer to the BCM2709 interrupt controller whose
  1542. lines are being described.
  1543. Return Value:
  1544. Status code.
  1545. --*/
  1546. {
  1547. INTERRUPT_LINES_DESCRIPTION Lines;
  1548. KSTATUS Status;
  1549. RtlZeroMemory(&Lines, sizeof(INTERRUPT_LINES_DESCRIPTION));
  1550. Lines.Version = INTERRUPT_LINES_DESCRIPTION_VERSION;
  1551. //
  1552. // Describe the normal lines on the BCM2709.
  1553. //
  1554. Lines.Type = InterruptLinesStandardPin;
  1555. Lines.LineStart = 0;
  1556. Lines.LineEnd = Lines.LineStart + Bcm2709InterruptHardwareLineCount;
  1557. Lines.Gsi = HlBcm2709Table->InterruptControllerGsiBase;
  1558. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  1559. if (!KSUCCESS(Status)) {
  1560. goto Bcm2709InterruptDescribeLinesEnd;
  1561. }
  1562. //
  1563. // Describe the per-processor interrupt lines.
  1564. //
  1565. ASSERT(Lines.LineEnd == BCM2709_INTERRUPT_PER_PROCESSOR_LINE_BASE);
  1566. Lines.Type = InterruptLinesProcessorLocal;
  1567. Lines.LineStart = Lines.LineEnd;
  1568. Lines.LineEnd = Lines.LineStart +
  1569. BCM2709_INTERRUPT_PER_PROCESSOR_LINE_COUNT;
  1570. Lines.Gsi = Lines.Gsi + Bcm2709InterruptHardwareLineCount;
  1571. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  1572. if (!KSUCCESS(Status)) {
  1573. goto Bcm2709InterruptDescribeLinesEnd;
  1574. }
  1575. //
  1576. // Describe the SGIs. These are fake and actually tied up to GSI 100 for
  1577. // the ARM local mailbox 0, but that particular mailbox can express 32 bits.
  1578. //
  1579. ASSERT(Lines.LineEnd == BCM2709_INTERRUPT_SOFTWARE_LINE_BASE);
  1580. Lines.Type = InterruptLinesSoftwareOnly;
  1581. Lines.LineStart = Lines.LineEnd;
  1582. Lines.LineEnd = Lines.LineStart + BCM2709_INTERRUPT_SOFTWARE_LINE_COUNT;
  1583. Lines.Gsi = INTERRUPT_LINES_GSI_NONE;
  1584. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  1585. if (!KSUCCESS(Status)) {
  1586. goto Bcm2709InterruptDescribeLinesEnd;
  1587. }
  1588. //
  1589. // Register the output lines.
  1590. //
  1591. Lines.Type = InterruptLinesOutput;
  1592. Lines.OutputControllerIdentifier = INTERRUPT_CPU_IDENTIFIER;
  1593. Lines.LineStart = INTERRUPT_ARM_MIN_CPU_LINE;
  1594. Lines.LineEnd = INTERRUPT_ARM_MAX_CPU_LINE;
  1595. Status = HlRegisterHardware(HardwareModuleInterruptLines, &Lines);
  1596. if (!KSUCCESS(Status)) {
  1597. goto Bcm2709InterruptDescribeLinesEnd;
  1598. }
  1599. Bcm2709InterruptDescribeLinesEnd:
  1600. return Status;
  1601. }