msi.c 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. msi.c
  5. Abstract:
  6. This module implements support for PCI message signaled interrupts.
  7. Author:
  8. Chris Stevens 9-Jul-2014
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "pci.h"
  16. #include <minoca/kernel/acpi.h>
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // Define offset values for PCI MSI configuration space.
  22. //
  23. #define PCI_MSI_CONTROL_OFFSET 0x0
  24. #define PCI_MSI_CONTROL_MASK 0xFFFF0000
  25. #define PCI_MSI_CONTROL_SHIFT 16
  26. #define PCI_MSI_LOWER_ADDRESS_OFFSET 0x04
  27. #define PCI_MSI_MASK_OFFSET 0x0C
  28. #define PCI_MSI_64_BIT_MASK_OFFSET 0x10
  29. #define PCI_MSI_PENDING_OFFSET 0x10
  30. #define PCI_MSI_64_BIT_PENDING_OFFSET 0x14
  31. //
  32. // Define the PCI MSI message control register bits.
  33. //
  34. #define PCI_MSI_CONTROL_ENABLE 0x0001
  35. #define PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK 0x000E
  36. #define PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT 1
  37. #define PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_MASK 0x0070
  38. #define PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_SHIFT 4
  39. #define PCI_MSI_CONTROL_64_BIT_CAPABLE 0x0080
  40. #define PCI_MSI_CONTROL_VECTOR_MASKING 0x0100
  41. #define PCI_MSI_MAXIMUM_VECTOR_ENCODING 5
  42. //
  43. // Define offset values for PCI MSI-X configuration space.
  44. //
  45. #define PCI_MSI_X_CONTROL_OFFSET 0x0
  46. #define PCI_MSI_X_CONTROL_MASK 0xFFFF0000
  47. #define PCI_MSI_X_CONTROL_SHIFT 16
  48. #define PCI_MSI_X_TABLE_DATA_OFFSET 0x4
  49. #define PCI_MSI_X_PENDING_ARRAY_DATA_OFFSET 0x8
  50. //
  51. // Define the PCI MSI-X message control register bits.
  52. //
  53. #define PCI_MSI_X_CONTROL_TABLE_SIZE_MASK 0x7FF
  54. #define PCI_MSI_X_CONTROL_TABLE_SIZE_SHIFT 0
  55. #define PCI_MSI_X_CONTROL_GLOBAL_MASK 0x4000
  56. #define PCI_MSI_X_CONTROL_ENABLE 0x8000
  57. //
  58. // Define the PCI MSI-X table data register bits.
  59. //
  60. #define PCI_MSI_X_TABLE_BAR_INDEX_MASK 0x00000007
  61. #define PCI_MSI_X_TABLE_OFFSET_MASK 0xFFFFFFF8
  62. //
  63. // Define the PCI MSI-X pending array data register bits.
  64. //
  65. #define PCI_MSI_X_PENDING_ARRAY_BAR_INDEX_MASK 0x00000007
  66. #define PCI_MSI_X_PENDING_ARRAY_OFFSET_MASK 0xFFFFFFF8
  67. //
  68. // Define the PCI MSI-X vector control bits.
  69. //
  70. #define PCI_MSI_X_VECTOR_CONTROL_MASKED 0x00000001
  71. //
  72. // ------------------------------------------------------ Data Type Definitions
  73. //
  74. typedef struct _PCI_MSI_X_TABLE_ENTRY {
  75. ULONGLONG Address;
  76. ULONG Data;
  77. ULONG Control;
  78. } PACKED PCI_MSI_X_TABLE_ENTRY, *PPCI_MSI_X_TABLE_ENTRY;
  79. //
  80. // ----------------------------------------------- Internal Function Prototypes
  81. //
  82. KSTATUS
  83. PcipMsiGetSetInformation (
  84. PVOID DeviceToken,
  85. PPCI_MSI_INFORMATION Information,
  86. BOOL Set
  87. );
  88. KSTATUS
  89. PcipMsiSetVectors (
  90. PVOID DeviceToken,
  91. PCI_MSI_TYPE MsiType,
  92. ULONGLONG Vector,
  93. ULONGLONG VectorIndex,
  94. ULONGLONG VectorCount,
  95. PPROCESSOR_SET Processors
  96. );
  97. KSTATUS
  98. PcipMsiMaskVectors (
  99. PVOID DeviceToken,
  100. PCI_MSI_TYPE MsiType,
  101. ULONGLONG VectorIndex,
  102. ULONGLONG VectorCount,
  103. BOOL MaskVectors
  104. );
  105. KSTATUS
  106. PcipMsiIsVectorMasked (
  107. PVOID DeviceToken,
  108. PCI_MSI_TYPE MsiType,
  109. ULONGLONG VectorIndex,
  110. PBOOL Masked
  111. );
  112. KSTATUS
  113. PcipMsiIsVectorPending (
  114. PVOID DeviceToken,
  115. PCI_MSI_TYPE MsiType,
  116. ULONGLONG VectorIndex,
  117. PBOOL Pending
  118. );
  119. KSTATUS
  120. PcipMapMsiXTable (
  121. PPCI_MSI_CONTEXT MsiContext
  122. );
  123. KSTATUS
  124. PcipMapMsiXPendingArray (
  125. PPCI_MSI_CONTEXT MsiContext
  126. );
  127. //
  128. // -------------------------------------------------------------------- Globals
  129. //
  130. //
  131. // ------------------------------------------------------------------ Functions
  132. //
  133. KSTATUS
  134. PcipMsiCreateContextAndInterface (
  135. PDEVICE Device,
  136. PPCI_DEVICE PciDevice
  137. )
  138. /*++
  139. Routine Description:
  140. This routine initializes the MSI/MSI-X context and interface for the given
  141. PCI device.
  142. Arguments:
  143. Device - Supplies a pointer to the device in need of an MSI/MSI-X context
  144. and interface.
  145. PciDevice - Supplies a pointer to the PCI device context.
  146. Return Value:
  147. Status code.
  148. --*/
  149. {
  150. ULONG AllocationSize;
  151. UCHAR CapabilitiesListOffset;
  152. ULONG CapabilitiesPointerOffset;
  153. UCHAR Capability;
  154. ULONG Control;
  155. PFADT Fadt;
  156. ULONG HeaderType;
  157. USHORT ListEntry;
  158. PPCI_MSI_CONTEXT MsiContext;
  159. ULONG MsiFlags;
  160. PINTERFACE_PCI_MSI MsiInterface;
  161. ULONGLONG MsiMaxVectorCount;
  162. UCHAR MsiOffset;
  163. ULONGLONG MsiXMaxVectorCount;
  164. UCHAR MsiXOffset;
  165. UCHAR NextOffset;
  166. ULONG Offset;
  167. ULONG PciStatus;
  168. KSTATUS Status;
  169. MsiContext = NULL;
  170. //
  171. // If there is no capabilities list then there is definitely no MSI or
  172. // MSI-X interface.
  173. //
  174. PciStatus = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  175. PciDevice->DeviceNumber,
  176. PciDevice->FunctionNumber,
  177. PCI_STATUS_OFFSET,
  178. sizeof(ULONG));
  179. PciStatus = (PciStatus & PCI_STATUS_MASK) >> PCI_STATUS_SHIFT;
  180. if ((PciStatus & PCI_STATUS_CAPABILITIES_LIST) == 0) {
  181. Status = STATUS_SUCCESS;
  182. goto MsiCreateInterfaceEnd;
  183. }
  184. //
  185. // Get the header type to determine the offset of the capabilities pointer.
  186. //
  187. HeaderType = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  188. PciDevice->DeviceNumber,
  189. PciDevice->FunctionNumber,
  190. PCI_HEADER_TYPE_OFFSET,
  191. sizeof(ULONG));
  192. HeaderType = (HeaderType & PCI_HEADER_TYPE_MASK) >> PCI_HEADER_TYPE_SHIFT;
  193. HeaderType &= PCI_HEADER_TYPE_VALUE_MASK;
  194. if (HeaderType == PCI_HEADER_TYPE_CARDBUS_BRIDGE) {
  195. CapabilitiesPointerOffset = PCI_ALTERNATE_CAPABILITIES_POINTER_OFFSET;
  196. } else {
  197. CapabilitiesPointerOffset = PCI_DEFAULT_CAPABILITIES_POINTER_OFFSET;
  198. }
  199. //
  200. // Read the capabilities pointer offset to get the start of the
  201. // capabilities list.
  202. //
  203. CapabilitiesListOffset = (UCHAR)PciDevice->ReadConfig(
  204. PciDevice->BusNumber,
  205. PciDevice->DeviceNumber,
  206. PciDevice->FunctionNumber,
  207. CapabilitiesPointerOffset,
  208. sizeof(UCHAR));
  209. ASSERT((CapabilitiesListOffset == 0) ||
  210. (CapabilitiesListOffset > PCI_INTERRUPT_LINE_OFFSET));
  211. //
  212. // Loop through the capabilities list searching for the MSI and MSI-X
  213. // capabilities. They should only ever appear once in the list.
  214. //
  215. MsiOffset = 0;
  216. MsiXOffset = 0;
  217. NextOffset = CapabilitiesListOffset & PCI_CAPABILITY_POINTER_MASK;
  218. while (NextOffset != 0) {
  219. ListEntry = (USHORT)PciDevice->ReadConfig(PciDevice->BusNumber,
  220. PciDevice->DeviceNumber,
  221. PciDevice->FunctionNumber,
  222. NextOffset,
  223. sizeof(USHORT));
  224. //
  225. // If this list entry is for either of the desired MSI/MSI-X
  226. // capabilities then record the offset.
  227. //
  228. Capability = (ListEntry & PCI_CAPABILITY_LIST_ID_MASK) >>
  229. PCI_CAPABILITY_LIST_ID_SHIFT;
  230. if (Capability == PCI_CAPABILITY_MSI) {
  231. ASSERT(MsiOffset == 0);
  232. MsiOffset = NextOffset;
  233. //
  234. // Stop if both have now been found.
  235. //
  236. if (MsiXOffset != 0) {
  237. break;
  238. }
  239. } else if (Capability == PCI_CAPABILITY_MSI_X) {
  240. ASSERT(MsiXOffset == 0);
  241. MsiXOffset = NextOffset;
  242. //
  243. // Stop if both have now been found.
  244. //
  245. if (MsiOffset != 0) {
  246. break;
  247. }
  248. }
  249. //
  250. // Get the offset of the next capability.
  251. //
  252. NextOffset = (ListEntry & PCI_CAPABILITY_LIST_NEXT_POINTER_MASK) >>
  253. PCI_CAPABILITY_LIST_NEXT_POINTER_SHIFT;
  254. NextOffset &= PCI_CAPABILITY_POINTER_MASK;
  255. }
  256. //
  257. // If neither of the capabilities exist, then bail out.
  258. //
  259. if ((MsiOffset == 0) && (MsiXOffset == 0)) {
  260. Status = STATUS_SUCCESS;
  261. goto MsiCreateInterfaceEnd;
  262. }
  263. //
  264. // TODO: Test to see if the device tree has MSI/MSI-X support.
  265. //
  266. Fadt = AcpiFindTable(FADT_SIGNATURE, NULL);
  267. if ((Fadt == NULL) ||
  268. ((Fadt->IaBootFlags & FADT_IA_FLAG_MSI_NOT_SUPPORTED) != 0)) {
  269. Status = STATUS_SUCCESS;
  270. goto MsiCreateInterfaceEnd;
  271. }
  272. //
  273. // Save the read-only information from the MSI configuration space.
  274. //
  275. MsiFlags = 0;
  276. MsiMaxVectorCount = 0;
  277. if (MsiOffset != 0) {
  278. Offset = MsiOffset + PCI_MSI_CONTROL_OFFSET;
  279. Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  280. PciDevice->DeviceNumber,
  281. PciDevice->FunctionNumber,
  282. Offset,
  283. sizeof(ULONG));
  284. Control = (Control & PCI_MSI_CONTROL_MASK) >> PCI_MSI_CONTROL_SHIFT;
  285. if ((Control & PCI_MSI_CONTROL_64_BIT_CAPABLE) != 0) {
  286. MsiFlags |= PCI_MSI_FLAG_64_BIT_CAPABLE;
  287. }
  288. if ((Control & PCI_MSI_CONTROL_VECTOR_MASKING) != 0) {
  289. MsiFlags |= PCI_MSI_FLAG_MASKABLE;
  290. }
  291. MsiMaxVectorCount = (Control &
  292. PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK) >>
  293. PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT;
  294. MsiMaxVectorCount = 1 << MsiMaxVectorCount;
  295. }
  296. //
  297. // Save the read-only information from the MSI-X configuration space.
  298. //
  299. MsiXMaxVectorCount = 0;
  300. if (MsiXOffset != 0) {
  301. Offset = MsiXOffset + PCI_MSI_X_CONTROL_OFFSET;
  302. Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  303. PciDevice->DeviceNumber,
  304. PciDevice->FunctionNumber,
  305. Offset,
  306. sizeof(ULONG));
  307. Control = (Control & PCI_MSI_X_CONTROL_MASK) >> PCI_MSI_X_CONTROL_SHIFT;
  308. MsiXMaxVectorCount = (Control & PCI_MSI_X_CONTROL_TABLE_SIZE_MASK) >>
  309. PCI_MSI_X_CONTROL_TABLE_SIZE_SHIFT;
  310. MsiXMaxVectorCount = MsiXMaxVectorCount + 1;
  311. }
  312. //
  313. // One or both of the MSI and/or MSI-X capabilities exists. Create the
  314. // context and interface, recording the config space offsets.
  315. //
  316. AllocationSize = sizeof(PCI_MSI_CONTEXT) + sizeof(INTERFACE_PCI_MSI);
  317. MsiContext = MmAllocateNonPagedPool(AllocationSize, PCI_ALLOCATION_TAG);
  318. if (MsiContext == NULL) {
  319. Status = STATUS_INSUFFICIENT_RESOURCES;
  320. goto MsiCreateInterfaceEnd;
  321. }
  322. RtlZeroMemory(MsiContext, AllocationSize);
  323. MsiInterface = (PINTERFACE_PCI_MSI)(MsiContext + 1);
  324. MsiInterface->GetSetInformation = PcipMsiGetSetInformation;
  325. MsiInterface->SetVectors = PcipMsiSetVectors;
  326. MsiInterface->MaskVectors = PcipMsiMaskVectors;
  327. MsiInterface->IsVectorMasked = PcipMsiIsVectorMasked;
  328. MsiInterface->IsVectorPending = PcipMsiIsVectorPending;
  329. MsiInterface->DeviceToken = PciDevice;
  330. MsiContext->MsiOffset = MsiOffset;
  331. MsiContext->MsiXOffset = MsiXOffset;
  332. MsiContext->MsiFlags = MsiFlags;
  333. MsiContext->MsiMaxVectorCount = MsiMaxVectorCount;
  334. MsiContext->MsiXMaxVectorCount = MsiXMaxVectorCount;
  335. MsiContext->Interface = MsiInterface;
  336. PciDevice->MsiContext = MsiContext;
  337. Status = IoCreateInterface(&PciMessageSignaledInterruptsUuid,
  338. Device,
  339. MsiInterface,
  340. sizeof(INTERFACE_PCI_MSI));
  341. if (!KSUCCESS(Status)) {
  342. goto MsiCreateInterfaceEnd;
  343. }
  344. MsiCreateInterfaceEnd:
  345. if (!KSUCCESS(Status)) {
  346. if (MsiContext != NULL) {
  347. MmFreeNonPagedPool(MsiContext);
  348. }
  349. PciDevice->MsiContext = NULL;
  350. }
  351. return Status;
  352. }
  353. VOID
  354. PcipMsiDestroyContextAndInterface (
  355. PDEVICE Device,
  356. PPCI_DEVICE PciDevice
  357. )
  358. /*++
  359. Routine Description:
  360. This routine destroys the given PCI device's MSI context and interface if
  361. they exist.
  362. Arguments:
  363. Device - Supplies a pointer to the device whose MSI/MSI-x context and
  364. interface is to be destroyed.
  365. PciDevice - Supplies a pointer to the PCI device context.
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. if (PciDevice->MsiContext == NULL) {
  371. return;
  372. }
  373. IoDestroyInterface(&PciMessageSignaledInterruptsUuid,
  374. Device,
  375. PciDevice->MsiContext->Interface);
  376. MmFreeNonPagedPool(PciDevice->MsiContext);
  377. PciDevice->MsiContext = NULL;
  378. return;
  379. }
  380. VOID
  381. PcipGetMsiXBarInformation (
  382. PPCI_DEVICE PciDevice,
  383. PULONG TableBarIndex,
  384. PULONG TableOffset,
  385. PULONG PendingArrayBarIndex,
  386. PULONG PendingArrayOffset
  387. )
  388. /*++
  389. Routine Description:
  390. This routine gets the BAR information for the MSI-X table and pending bit
  391. array out of PCI configuration space.
  392. Arguments:
  393. PciDevice - Supplies a pointer to the PCI device context.
  394. TableBarIndex - Supplies a pointer that receives the index of the BAR
  395. within which the MSI-X table resides.
  396. TableOffset - Supplies a pointer that receives the offset within the BAR
  397. of the MSI-X table.
  398. PendingArrayBarIndex - Supplies a pointer that receives the index of the
  399. BAR within which the MSI-X pending bit array resides.
  400. PendingArrayOffset - Supplies a pointer that receives the offset within the
  401. BAR of the MSI-X pending bit array.
  402. Return Value:
  403. None.
  404. --*/
  405. {
  406. PPCI_MSI_CONTEXT MsiContext;
  407. ULONG Offset;
  408. ULONG PendingArrayData;
  409. ULONG TableData;
  410. ASSERT(PciDevice->MsiContext != NULL);
  411. ASSERT(PciDevice->MsiContext->MsiXOffset != 0);
  412. //
  413. // Get the BAR index and offset for the MSI-X vector table.
  414. //
  415. MsiContext = PciDevice->MsiContext;
  416. Offset = MsiContext->MsiXOffset + PCI_MSI_X_TABLE_DATA_OFFSET;
  417. TableData = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  418. PciDevice->DeviceNumber,
  419. PciDevice->FunctionNumber,
  420. Offset,
  421. sizeof(ULONG));
  422. *TableBarIndex = TableData & PCI_MSI_X_TABLE_BAR_INDEX_MASK;
  423. *TableOffset = TableData & PCI_MSI_X_TABLE_OFFSET_MASK;
  424. //
  425. // Get the BAR index and offset for the MSI-X pending bit array.
  426. //
  427. Offset = MsiContext->MsiXOffset + PCI_MSI_X_PENDING_ARRAY_DATA_OFFSET;
  428. PendingArrayData = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  429. PciDevice->DeviceNumber,
  430. PciDevice->FunctionNumber,
  431. Offset,
  432. sizeof(ULONG));
  433. *PendingArrayBarIndex = PendingArrayData &
  434. PCI_MSI_X_PENDING_ARRAY_BAR_INDEX_MASK;
  435. *PendingArrayOffset = PendingArrayData &
  436. PCI_MSI_X_PENDING_ARRAY_OFFSET_MASK;
  437. return;
  438. }
  439. //
  440. // --------------------------------------------------------- Internal Functions
  441. //
  442. KSTATUS
  443. PcipMsiGetSetInformation (
  444. PVOID DeviceToken,
  445. PPCI_MSI_INFORMATION Information,
  446. BOOL Set
  447. )
  448. /*++
  449. Routine Description:
  450. This routine gets or sets MSI/MSI-X information for the given PCI device.
  451. Returned information includes whether or not MSI/MSI-X is enabled, uses
  452. 64-bit addresses, is maskable, etc. Information to set includes enabling
  453. and disabling MSI/MSI-X, the MSI vector count, and the MSI-X global mask.
  454. Arguments:
  455. DeviceToken - Supplies the device token supplied when the interface was
  456. acquired.
  457. Information - Supplies a pointer to a structure that either receives the
  458. requested information or contains the information to set. In both
  459. cases, the caller should specify the structure version and the MSI
  460. type - basic (MSI) or extended (MSI-X) - before passing it to the
  461. routine.
  462. Set - Supplies a boolean indicating whether to get or set the MSI/MSI-X
  463. information.
  464. Return Value:
  465. Status code.
  466. --*/
  467. {
  468. ULONG Control;
  469. ULONG Flags;
  470. ULONGLONG MaxVectorCount;
  471. PPCI_MSI_CONTEXT MsiContext;
  472. ULONG Offset;
  473. PPCI_DEVICE PciDevice;
  474. KSTATUS Status;
  475. ULONGLONG VectorCount;
  476. if (Information->Version != PCI_MSI_INTERFACE_INFORMATION_VERSION) {
  477. return STATUS_INVALID_PARAMETER;
  478. }
  479. PciDevice = (PPCI_DEVICE)DeviceToken;
  480. if (PciDevice->MsiContext == NULL) {
  481. return STATUS_NOT_SUPPORTED;
  482. }
  483. //
  484. // Get the information for the requested MSI/MSI-X type.
  485. //
  486. Status = STATUS_SUCCESS;
  487. MsiContext = PciDevice->MsiContext;
  488. if (Set == FALSE) {
  489. switch (Information->MsiType) {
  490. case PciMsiTypeBasic:
  491. if (MsiContext->MsiOffset == 0) {
  492. Status = STATUS_NOT_SUPPORTED;
  493. goto MsiGetSetInformationEnd;
  494. }
  495. Offset = MsiContext->MsiOffset + PCI_MSI_CONTROL_OFFSET;
  496. Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  497. PciDevice->DeviceNumber,
  498. PciDevice->FunctionNumber,
  499. Offset,
  500. sizeof(ULONG));
  501. ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI);
  502. Control = (Control & PCI_MSI_CONTROL_MASK) >>
  503. PCI_MSI_CONTROL_SHIFT;
  504. Information->Flags = 0;
  505. if ((Control & PCI_MSI_CONTROL_ENABLE) != 0) {
  506. Information->Flags |= PCI_MSI_INTERFACE_FLAG_ENABLED;
  507. }
  508. if ((Control & PCI_MSI_CONTROL_64_BIT_CAPABLE) != 0) {
  509. Information->Flags |= PCI_MSI_INTERFACE_FLAG_64_BIT_CAPABLE;
  510. }
  511. if ((Control & PCI_MSI_CONTROL_VECTOR_MASKING) != 0) {
  512. Information->Flags |= PCI_MSI_INTERFACE_FLAG_MASKABLE;
  513. }
  514. MaxVectorCount = (Control &
  515. PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK) >>
  516. PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT;
  517. Information->MaxVectorCount = 1 << MaxVectorCount;
  518. ASSERT(MsiContext->MsiMaxVectorCount ==
  519. Information->MaxVectorCount);
  520. VectorCount = (Control &
  521. PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_MASK) >>
  522. PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_SHIFT;
  523. Information->VectorCount = 1 << VectorCount;
  524. break;
  525. case PciMsiTypeExtended:
  526. if (MsiContext->MsiXOffset == 0) {
  527. Status = STATUS_NOT_SUPPORTED;
  528. goto MsiGetSetInformationEnd;
  529. }
  530. Offset = MsiContext->MsiXOffset + PCI_MSI_X_CONTROL_OFFSET;
  531. Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  532. PciDevice->DeviceNumber,
  533. PciDevice->FunctionNumber,
  534. Offset,
  535. sizeof(ULONG));
  536. ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI_X);
  537. Control = (Control & PCI_MSI_X_CONTROL_MASK) >>
  538. PCI_MSI_X_CONTROL_SHIFT;
  539. Information->Flags = PCI_MSI_INTERFACE_FLAG_64_BIT_CAPABLE |
  540. PCI_MSI_INTERFACE_FLAG_MASKABLE;
  541. if ((Control & PCI_MSI_X_CONTROL_ENABLE) != 0) {
  542. Information->Flags |= PCI_MSI_INTERFACE_FLAG_ENABLED;
  543. }
  544. if ((Control & PCI_MSI_X_CONTROL_GLOBAL_MASK) != 0) {
  545. Information->Flags |= PCI_MSI_INTERFACE_FLAG_GLOBAL_MASK;
  546. }
  547. MaxVectorCount = (Control &
  548. PCI_MSI_X_CONTROL_TABLE_SIZE_MASK) >>
  549. PCI_MSI_X_CONTROL_TABLE_SIZE_SHIFT;
  550. Information->MaxVectorCount = MaxVectorCount + 1;
  551. ASSERT(MsiContext->MsiXMaxVectorCount ==
  552. Information->MaxVectorCount);
  553. Information->VectorCount = MsiContext->MsiXVectorCount;
  554. break;
  555. default:
  556. Status = STATUS_INVALID_PARAMETER;
  557. goto MsiGetSetInformationEnd;
  558. }
  559. //
  560. // Set the MSI/MSI-X state based on the supplied information.
  561. //
  562. } else {
  563. switch (Information->MsiType) {
  564. case PciMsiTypeBasic:
  565. if (MsiContext->MsiOffset == 0) {
  566. Status = STATUS_NOT_SUPPORTED;
  567. goto MsiGetSetInformationEnd;
  568. }
  569. //
  570. // Validate that the supplied vector count is less than the maximum
  571. // allowed vectors and that it is a power of two.
  572. //
  573. if ((Information->VectorCount == 0) ||
  574. (Information->VectorCount > MsiContext->MsiMaxVectorCount) ||
  575. (POWER_OF_2(Information->VectorCount) == FALSE)) {
  576. Status = STATUS_INVALID_PARAMETER;
  577. goto MsiGetSetInformationEnd;
  578. }
  579. //
  580. // The configuration space encodes the value x where the vector
  581. // count is 2^x. Make sure that the exponent isn't too large.
  582. //
  583. VectorCount = RtlCountTrailingZeros64(Information->VectorCount);
  584. if (VectorCount > PCI_MSI_MAXIMUM_VECTOR_ENCODING) {
  585. Status = STATUS_INVALID_PARAMETER;
  586. goto MsiGetSetInformationEnd;
  587. }
  588. //
  589. // Read the current control information.
  590. //
  591. Offset = MsiContext->MsiOffset + PCI_MSI_CONTROL_OFFSET;
  592. Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  593. PciDevice->DeviceNumber,
  594. PciDevice->FunctionNumber,
  595. Offset,
  596. sizeof(ULONG));
  597. ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI);
  598. Control = (Control & PCI_MSI_CONTROL_MASK) >> PCI_MSI_CONTROL_SHIFT;
  599. //
  600. // Update the control status based on the supplied information.
  601. //
  602. if ((Information->Flags & PCI_MSI_INTERFACE_FLAG_ENABLED) != 0) {
  603. Control |= PCI_MSI_CONTROL_ENABLE;
  604. } else {
  605. Control &= ~PCI_MSI_CONTROL_ENABLE;
  606. }
  607. MaxVectorCount = (Control &
  608. PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK) >>
  609. PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT;
  610. MaxVectorCount = 1 << MaxVectorCount;
  611. ASSERT(MsiContext->MsiMaxVectorCount == MaxVectorCount);
  612. Control |= (VectorCount <<
  613. PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_SHIFT) &
  614. PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_MASK;
  615. //
  616. // Write out the updated control information. There shouldn't be
  617. // a need to preserve the read-only capability ID and next pointer
  618. // offset, so just shift the control data and write it out.
  619. //
  620. Control <<= PCI_MSI_CONTROL_SHIFT;
  621. PciDevice->WriteConfig(PciDevice->BusNumber,
  622. PciDevice->DeviceNumber,
  623. PciDevice->FunctionNumber,
  624. Offset,
  625. sizeof(ULONG),
  626. Control);
  627. break;
  628. case PciMsiTypeExtended:
  629. if (MsiContext->MsiXOffset == 0) {
  630. Status = STATUS_NOT_SUPPORTED;
  631. goto MsiGetSetInformationEnd;
  632. }
  633. //
  634. // Read the current control information.
  635. //
  636. Offset = MsiContext->MsiXOffset + PCI_MSI_X_CONTROL_OFFSET;
  637. Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  638. PciDevice->DeviceNumber,
  639. PciDevice->FunctionNumber,
  640. Offset,
  641. sizeof(ULONG));
  642. ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI_X);
  643. Control = (Control & PCI_MSI_X_CONTROL_MASK) >>
  644. PCI_MSI_X_CONTROL_SHIFT;
  645. //
  646. // Update the control status based on the supplied information.
  647. //
  648. Flags = Information->Flags;
  649. if ((Flags & PCI_MSI_INTERFACE_FLAG_ENABLED) != 0) {
  650. Control |= PCI_MSI_X_CONTROL_ENABLE;
  651. } else {
  652. Control &= ~PCI_MSI_X_CONTROL_ENABLE;
  653. }
  654. if ((Flags & PCI_MSI_INTERFACE_FLAG_GLOBAL_MASK) != 0) {
  655. Control |= PCI_MSI_X_CONTROL_GLOBAL_MASK;
  656. } else {
  657. Control &= ~PCI_MSI_X_CONTROL_GLOBAL_MASK;
  658. }
  659. //
  660. // Write out the updated control information. There shouldn't be
  661. // a need to preserve the read-only capability ID and next pointer
  662. // offset, so just shift the control data and write it out.
  663. //
  664. Control <<= PCI_MSI_X_CONTROL_SHIFT;
  665. PciDevice->WriteConfig(PciDevice->BusNumber,
  666. PciDevice->DeviceNumber,
  667. PciDevice->FunctionNumber,
  668. Offset,
  669. sizeof(ULONG),
  670. Control);
  671. break;
  672. default:
  673. Status = STATUS_INVALID_PARAMETER;
  674. goto MsiGetSetInformationEnd;
  675. }
  676. //
  677. // If the above set enabled MSI/MSI-X, then disable legacy interrupts.
  678. //
  679. if ((Information->Flags & PCI_MSI_INTERFACE_FLAG_ENABLED) != 0) {
  680. Control = (USHORT)PciDevice->ReadConfig(PciDevice->BusNumber,
  681. PciDevice->DeviceNumber,
  682. PciDevice->FunctionNumber,
  683. PCI_CONTROL_OFFSET,
  684. sizeof(USHORT));
  685. Control |= PCI_CONTROL_INTERRUPT_DISABLE;
  686. PciDevice->WriteConfig(PciDevice->BusNumber,
  687. PciDevice->DeviceNumber,
  688. PciDevice->FunctionNumber,
  689. PCI_CONTROL_OFFSET,
  690. sizeof(USHORT),
  691. Control);
  692. }
  693. }
  694. MsiGetSetInformationEnd:
  695. return Status;
  696. }
  697. KSTATUS
  698. PcipMsiSetVectors (
  699. PVOID DeviceToken,
  700. PCI_MSI_TYPE MsiType,
  701. ULONGLONG Vector,
  702. ULONGLONG VectorIndex,
  703. ULONGLONG VectorCount,
  704. PPROCESSOR_SET Processors
  705. )
  706. /*++
  707. Routine Description:
  708. This routine sets the address and data for the given contiguous MSI/MSI-X
  709. vectors.
  710. Arguments:
  711. DeviceToken - Supplies the device token supplied when the interface was
  712. acquired.
  713. MsiType - Supplies the type of the MSI vector.
  714. Vector - Supplies the starting vector to be set at the given vector index.
  715. VectorIndex - Supplies the index into the vector table where this vector
  716. information should be written. This is only valid for MSI-X.
  717. VectorCount - Supplies the number of contiguous vectors to set starting at
  718. the given vector and index.
  719. Processors - Supplies the set of processors that the MSIs should utilize.
  720. Return Value:
  721. Status code.
  722. --*/
  723. {
  724. ULONG AllocationSize;
  725. ULONGLONG Index;
  726. PMSI_INFORMATION Information;
  727. MSI_INFORMATION InformationBuffer;
  728. ULONGLONG MessageData;
  729. PPCI_MSI_CONTEXT MsiContext;
  730. ULONG Offset;
  731. PPCI_DEVICE PciDevice;
  732. PHYSICAL_ADDRESS PhysicalAddress;
  733. KSTATUS Status;
  734. PPCI_MSI_X_TABLE_ENTRY TableEntry;
  735. Information = NULL;
  736. PciDevice = (PPCI_DEVICE)DeviceToken;
  737. MsiContext = PciDevice->MsiContext;
  738. //
  739. // Bail out immediately if an unsupported MSI type was requested.
  740. //
  741. if ((MsiContext == NULL) ||
  742. ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
  743. ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
  744. ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
  745. return STATUS_NOT_SUPPORTED;
  746. }
  747. //
  748. // If no vector count was supplied, then it was likely by mistake.
  749. //
  750. if (VectorCount == 0) {
  751. return STATUS_INVALID_PARAMETER;
  752. }
  753. //
  754. // Validate the index and count based on the cached maximum vector count.
  755. //
  756. switch (MsiType) {
  757. case PciMsiTypeBasic:
  758. if ((VectorIndex + VectorCount) > MsiContext->MsiMaxVectorCount) {
  759. Status = STATUS_OUT_OF_BOUNDS;
  760. goto MsiSetVectorsEnd;
  761. }
  762. //
  763. // Truncate the vector count to 1 as MSI only has one physical address
  764. // and message register pair. Multiple vectors must be contiguous.
  765. //
  766. VectorCount = 1;
  767. break;
  768. case PciMsiTypeExtended:
  769. if ((VectorIndex + VectorCount) > MsiContext->MsiXMaxVectorCount) {
  770. Status = STATUS_OUT_OF_BOUNDS;
  771. goto MsiSetVectorsEnd;
  772. }
  773. break;
  774. default:
  775. Status = STATUS_INVALID_PARAMETER;
  776. goto MsiSetVectorsEnd;
  777. }
  778. //
  779. // Get an appropriate array for physical addresses and data pairs.
  780. //
  781. if (VectorCount == 1) {
  782. Information = &InformationBuffer;
  783. } else {
  784. AllocationSize = VectorCount * sizeof(MSI_INFORMATION);
  785. Information = MmAllocatePagedPool(AllocationSize,
  786. PCI_ALLOCATION_TAG);
  787. if (Information == NULL) {
  788. Status = STATUS_INSUFFICIENT_RESOURCES;
  789. goto MsiSetVectorsEnd;
  790. }
  791. }
  792. Status = HlGetMsiInformation(Vector,
  793. VectorCount,
  794. Processors,
  795. Information);
  796. if (!KSUCCESS(Status)) {
  797. goto MsiSetVectorsEnd;
  798. }
  799. //
  800. // Set the addresses and data in the MSI vector.
  801. //
  802. Status = STATUS_SUCCESS;
  803. switch (MsiType) {
  804. case PciMsiTypeBasic:
  805. ASSERT(MsiContext->MsiOffset != 0);
  806. ASSERT(VectorIndex == 0);
  807. //
  808. // Even if more than one vector is being programmed, there is only one
  809. // address and data field. Take the information from the first vector.
  810. //
  811. PhysicalAddress = Information[0].Address;
  812. MessageData = Information[0].Data;
  813. Offset = MsiContext->MsiOffset + PCI_MSI_LOWER_ADDRESS_OFFSET;
  814. PciDevice->WriteConfig(PciDevice->BusNumber,
  815. PciDevice->DeviceNumber,
  816. PciDevice->FunctionNumber,
  817. Offset,
  818. sizeof(ULONG),
  819. (ULONG)PhysicalAddress);
  820. if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
  821. Offset += sizeof(ULONG);
  822. PciDevice->WriteConfig(PciDevice->BusNumber,
  823. PciDevice->DeviceNumber,
  824. PciDevice->FunctionNumber,
  825. Offset,
  826. sizeof(ULONG),
  827. (ULONG)(PhysicalAddress >> 32));
  828. }
  829. Offset += sizeof(ULONG);
  830. PciDevice->WriteConfig(PciDevice->BusNumber,
  831. PciDevice->DeviceNumber,
  832. PciDevice->FunctionNumber,
  833. Offset,
  834. sizeof(USHORT),
  835. (USHORT)MessageData);
  836. break;
  837. case PciMsiTypeExtended:
  838. ASSERT(MsiContext->MsiXOffset != 0);
  839. if (MsiContext->MsiXTable == NULL) {
  840. Status = PcipMapMsiXTable(MsiContext);
  841. if (!KSUCCESS(Status)) {
  842. goto MsiSetVectorsEnd;
  843. }
  844. }
  845. ASSERT(MsiContext->MsiXTable != NULL);
  846. TableEntry = (PPCI_MSI_X_TABLE_ENTRY)(MsiContext->MsiXTable +
  847. (VectorIndex *
  848. sizeof(PCI_MSI_X_TABLE_ENTRY)));
  849. for (Index = 0; Index < VectorCount; Index += 1) {
  850. if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) == 0) {
  851. TableEntry->Control |= PCI_MSI_X_VECTOR_CONTROL_MASKED;
  852. RtlMemoryBarrier();
  853. } else {
  854. MsiContext->MsiXVectorCount += 1;
  855. }
  856. TableEntry->Address = Information[Index].Address;
  857. TableEntry->Data = (ULONG)Information[Index].Data;
  858. RtlMemoryBarrier();
  859. TableEntry->Control &= ~PCI_MSI_X_VECTOR_CONTROL_MASKED;
  860. TableEntry += 1;
  861. }
  862. break;
  863. default:
  864. Status = STATUS_INVALID_PARAMETER;
  865. break;
  866. }
  867. MsiSetVectorsEnd:
  868. if ((VectorCount != 1) && (Information != NULL)) {
  869. MmFreePagedPool(Information);
  870. }
  871. return Status;
  872. }
  873. KSTATUS
  874. PcipMsiMaskVectors (
  875. PVOID DeviceToken,
  876. PCI_MSI_TYPE MsiType,
  877. ULONGLONG VectorIndex,
  878. ULONGLONG VectorCount,
  879. BOOL MaskVectors
  880. )
  881. /*++
  882. Routine Description:
  883. This routine masks or unmasks a set of contiguous MSI/MSI-X vectors for the
  884. given PCI device.
  885. Arguments:
  886. DeviceToken - Supplies the device token supplied when the interface was
  887. acquired.
  888. MsiType - Supplies the type of the MSI vector.
  889. VectorIndex - Supplies the starting index of the vectors that are to be
  890. masked or unmasked.
  891. VectorCount - Supplies the number fo contiguous vectors to mask or unmask
  892. starting at the given index.
  893. MaskVectors - Supplies a boolean indicating whether the vector should be
  894. masked (TRUE) or unmasked (FALSE).
  895. Return Value:
  896. Status code.
  897. --*/
  898. {
  899. ULONGLONG Index;
  900. ULONG Mask;
  901. PPCI_MSI_CONTEXT MsiContext;
  902. ULONG Offset;
  903. PPCI_DEVICE PciDevice;
  904. KSTATUS Status;
  905. PPCI_MSI_X_TABLE_ENTRY TableEntry;
  906. ULONG VectorMask;
  907. PciDevice = (PPCI_DEVICE)DeviceToken;
  908. MsiContext = PciDevice->MsiContext;
  909. //
  910. // Bail out immediately if an unsupported MSI type was requested.
  911. //
  912. if ((MsiContext == NULL) ||
  913. ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
  914. ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
  915. ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
  916. return STATUS_NOT_SUPPORTED;
  917. }
  918. //
  919. // Consider it a success if no vectors were asked to be masked or unmaksed.
  920. //
  921. if (VectorCount == 0) {
  922. return STATUS_SUCCESS;
  923. }
  924. //
  925. // Validate the index and count based on the cached maximum vector count.
  926. //
  927. switch (MsiType) {
  928. case PciMsiTypeBasic:
  929. if ((VectorIndex + VectorCount) > MsiContext->MsiMaxVectorCount) {
  930. Status = STATUS_OUT_OF_BOUNDS;
  931. goto MsiMaskVectorsEnd;
  932. }
  933. //
  934. // Bail now if masking is not supported.
  935. //
  936. if ((MsiContext->MsiFlags & PCI_MSI_FLAG_MASKABLE) == 0) {
  937. Status = STATUS_NOT_SUPPORTED;
  938. goto MsiMaskVectorsEnd;
  939. }
  940. break;
  941. case PciMsiTypeExtended:
  942. if ((VectorIndex + VectorCount) > MsiContext->MsiXMaxVectorCount) {
  943. Status = STATUS_OUT_OF_BOUNDS;
  944. goto MsiMaskVectorsEnd;
  945. }
  946. break;
  947. default:
  948. Status = STATUS_INVALID_PARAMETER;
  949. goto MsiMaskVectorsEnd;
  950. }
  951. //
  952. // Mask or unmask the vectors based on the type.
  953. //
  954. Status = STATUS_SUCCESS;
  955. switch (MsiType) {
  956. case PciMsiTypeBasic:
  957. ASSERT(MsiContext->MsiOffset != 0);
  958. if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
  959. Offset = MsiContext->MsiOffset + PCI_MSI_64_BIT_MASK_OFFSET;
  960. } else {
  961. Offset = MsiContext->MsiOffset + PCI_MSI_MASK_OFFSET;
  962. }
  963. //
  964. // Build out the mask of the vectors that are to be modified.
  965. //
  966. Mask = 0;
  967. for (Index = VectorIndex;
  968. Index < (VectorIndex + VectorCount);
  969. Index += 1) {
  970. Mask |= (1 << Index);
  971. }
  972. //
  973. // Read, modify, and write the configuration space to update the masks.
  974. //
  975. VectorMask = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  976. PciDevice->DeviceNumber,
  977. PciDevice->FunctionNumber,
  978. Offset,
  979. sizeof(ULONG));
  980. if (MaskVectors != FALSE) {
  981. VectorMask |= Mask;
  982. } else {
  983. VectorMask &= ~Mask;
  984. }
  985. PciDevice->WriteConfig(PciDevice->BusNumber,
  986. PciDevice->DeviceNumber,
  987. PciDevice->FunctionNumber,
  988. Offset,
  989. sizeof(ULONG),
  990. VectorMask);
  991. break;
  992. case PciMsiTypeExtended:
  993. ASSERT(MsiContext->MsiXOffset != 0);
  994. if (MsiContext->MsiXTable == NULL) {
  995. Status = PcipMapMsiXTable(MsiContext);
  996. if (!KSUCCESS(Status)) {
  997. goto MsiMaskVectorsEnd;
  998. }
  999. }
  1000. ASSERT(MsiContext->MsiXTable != NULL);
  1001. TableEntry = (PPCI_MSI_X_TABLE_ENTRY)(MsiContext->MsiXTable +
  1002. (VectorIndex *
  1003. sizeof(PCI_MSI_X_TABLE_ENTRY)));
  1004. if (MaskVectors != FALSE) {
  1005. for (Index = 0; Index < VectorCount; Index += 1) {
  1006. if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) ==
  1007. 0) {
  1008. TableEntry->Control |= PCI_MSI_X_VECTOR_CONTROL_MASKED;
  1009. MsiContext->MsiXVectorCount -= 1;
  1010. }
  1011. TableEntry += 1;
  1012. }
  1013. } else {
  1014. for (Index = 0; Index < VectorCount; Index += 1) {
  1015. if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) !=
  1016. 0) {
  1017. TableEntry->Control &= ~PCI_MSI_X_VECTOR_CONTROL_MASKED;
  1018. MsiContext->MsiXVectorCount += 1;
  1019. }
  1020. TableEntry += 1;
  1021. }
  1022. }
  1023. break;
  1024. default:
  1025. Status = STATUS_INVALID_PARAMETER;
  1026. goto MsiMaskVectorsEnd;
  1027. }
  1028. MsiMaskVectorsEnd:
  1029. return Status;
  1030. }
  1031. KSTATUS
  1032. PcipMsiIsVectorMasked (
  1033. PVOID DeviceToken,
  1034. PCI_MSI_TYPE MsiType,
  1035. ULONGLONG VectorIndex,
  1036. PBOOL Masked
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine determines whether or not an MSI/MSI-X vector for the given
  1041. PCI device is masked.
  1042. Arguments:
  1043. DeviceToken - Supplies the device token supplied when the interface was
  1044. acquired.
  1045. MsiType - Supplies the type of the MSI vector.
  1046. VectorIndex - Supplies the index of the vector whose masked state is to be
  1047. returned.
  1048. Masked - Supplies a pointer to a boolean that receives whether or not the
  1049. vector is masked.
  1050. Return Value:
  1051. Status code.
  1052. --*/
  1053. {
  1054. ULONG Mask;
  1055. PPCI_MSI_CONTEXT MsiContext;
  1056. ULONG Offset;
  1057. PPCI_DEVICE PciDevice;
  1058. KSTATUS Status;
  1059. PPCI_MSI_X_TABLE_ENTRY TableEntry;
  1060. ULONG VectorMask;
  1061. PciDevice = (PPCI_DEVICE)DeviceToken;
  1062. MsiContext = PciDevice->MsiContext;
  1063. //
  1064. // Bail out immediately if an unsupported MSI type was requested.
  1065. //
  1066. if ((MsiContext == NULL) ||
  1067. ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
  1068. ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
  1069. ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
  1070. return STATUS_NOT_SUPPORTED;
  1071. }
  1072. //
  1073. // Validate the index based on the cached maximum vector count.
  1074. //
  1075. switch (MsiType) {
  1076. case PciMsiTypeBasic:
  1077. if (VectorIndex >= MsiContext->MsiMaxVectorCount) {
  1078. Status = STATUS_OUT_OF_BOUNDS;
  1079. goto MsiIsVectorMaskedEnd;
  1080. }
  1081. //
  1082. // Bail now if masking is not supported.
  1083. //
  1084. if ((MsiContext->MsiFlags & PCI_MSI_FLAG_MASKABLE) == 0) {
  1085. Status = STATUS_NOT_SUPPORTED;
  1086. goto MsiIsVectorMaskedEnd;
  1087. }
  1088. break;
  1089. case PciMsiTypeExtended:
  1090. if (VectorIndex >= MsiContext->MsiXMaxVectorCount) {
  1091. Status = STATUS_OUT_OF_BOUNDS;
  1092. goto MsiIsVectorMaskedEnd;
  1093. }
  1094. break;
  1095. default:
  1096. Status = STATUS_INVALID_PARAMETER;
  1097. goto MsiIsVectorMaskedEnd;
  1098. }
  1099. //
  1100. // Determine whether or not the vector is masked or unmasked.
  1101. //
  1102. Status = STATUS_SUCCESS;
  1103. switch (MsiType) {
  1104. case PciMsiTypeBasic:
  1105. ASSERT(MsiContext->MsiOffset != 0);
  1106. if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
  1107. Offset = MsiContext->MsiOffset + PCI_MSI_64_BIT_MASK_OFFSET;
  1108. } else {
  1109. Offset = MsiContext->MsiOffset + PCI_MSI_MASK_OFFSET;
  1110. }
  1111. //
  1112. // Read the vector mask data and check to see if the given vector's bit
  1113. // is set.
  1114. //
  1115. VectorMask = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  1116. PciDevice->DeviceNumber,
  1117. PciDevice->FunctionNumber,
  1118. Offset,
  1119. sizeof(ULONG));
  1120. Mask = 1 << VectorIndex;
  1121. if ((VectorMask & Mask) != 0) {
  1122. *Masked = TRUE;
  1123. } else {
  1124. *Masked = FALSE;
  1125. }
  1126. break;
  1127. case PciMsiTypeExtended:
  1128. ASSERT(MsiContext->MsiXOffset != 0);
  1129. if (MsiContext->MsiXTable == NULL) {
  1130. Status = PcipMapMsiXTable(MsiContext);
  1131. if (!KSUCCESS(Status)) {
  1132. goto MsiIsVectorMaskedEnd;
  1133. }
  1134. }
  1135. ASSERT(MsiContext->MsiXTable != NULL);
  1136. TableEntry = (PPCI_MSI_X_TABLE_ENTRY)(MsiContext->MsiXTable +
  1137. (VectorIndex *
  1138. sizeof(PCI_MSI_X_TABLE_ENTRY)));
  1139. if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) != 0) {
  1140. *Masked = TRUE;
  1141. } else {
  1142. *Masked = FALSE;
  1143. }
  1144. break;
  1145. default:
  1146. Status = STATUS_INVALID_PARAMETER;
  1147. goto MsiIsVectorMaskedEnd;
  1148. }
  1149. MsiIsVectorMaskedEnd:
  1150. return Status;
  1151. }
  1152. KSTATUS
  1153. PcipMsiIsVectorPending (
  1154. PVOID DeviceToken,
  1155. PCI_MSI_TYPE MsiType,
  1156. ULONGLONG VectorIndex,
  1157. PBOOL Pending
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. This routine determines whether or not an MSI/MSI-X vector for the given
  1162. PCI device is pending.
  1163. Arguments:
  1164. DeviceToken - Supplies the device token supplied when the interface was
  1165. acquired.
  1166. MsiType - Supplies the type of the MSI vector.
  1167. VectorIndex - Supplies the index of the vector whose pending state is to be
  1168. returned.
  1169. Pending - Supplies a pointer to a boolean that receives whether or not the
  1170. vector has a pending interrupt.
  1171. Return Value:
  1172. Status code.
  1173. --*/
  1174. {
  1175. PULONG Address;
  1176. ULONG Mask;
  1177. PPCI_MSI_CONTEXT MsiContext;
  1178. ULONG Offset;
  1179. PPCI_DEVICE PciDevice;
  1180. ULONG PendingMask;
  1181. KSTATUS Status;
  1182. PciDevice = (PPCI_DEVICE)DeviceToken;
  1183. MsiContext = PciDevice->MsiContext;
  1184. //
  1185. // Bail out immediately if an unsupported MSI type was requested.
  1186. //
  1187. if ((MsiContext == NULL) ||
  1188. ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
  1189. ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
  1190. ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
  1191. return STATUS_NOT_SUPPORTED;
  1192. }
  1193. //
  1194. // Validate the index based on the cached maximum vector count.
  1195. //
  1196. switch (MsiType) {
  1197. case PciMsiTypeBasic:
  1198. if (VectorIndex >= MsiContext->MsiMaxVectorCount) {
  1199. Status = STATUS_OUT_OF_BOUNDS;
  1200. goto MsiIsVectorPendingEnd;
  1201. }
  1202. //
  1203. // Bail now if masking/pending is not supported.
  1204. //
  1205. if ((MsiContext->MsiFlags & PCI_MSI_FLAG_MASKABLE) == 0) {
  1206. Status = STATUS_NOT_SUPPORTED;
  1207. goto MsiIsVectorPendingEnd;
  1208. }
  1209. break;
  1210. case PciMsiTypeExtended:
  1211. if (VectorIndex >= MsiContext->MsiXMaxVectorCount) {
  1212. Status = STATUS_OUT_OF_BOUNDS;
  1213. goto MsiIsVectorPendingEnd;
  1214. }
  1215. break;
  1216. default:
  1217. Status = STATUS_INVALID_PARAMETER;
  1218. goto MsiIsVectorPendingEnd;
  1219. }
  1220. //
  1221. // Determine whether or not the vector is pending or not.
  1222. //
  1223. Status = STATUS_SUCCESS;
  1224. switch (MsiType) {
  1225. case PciMsiTypeBasic:
  1226. ASSERT(MsiContext->MsiOffset != 0);
  1227. if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
  1228. Offset = MsiContext->MsiOffset + PCI_MSI_64_BIT_PENDING_OFFSET;
  1229. } else {
  1230. Offset = MsiContext->MsiOffset + PCI_MSI_PENDING_OFFSET;
  1231. }
  1232. //
  1233. // Read the vector pending data and check to see if the given vector's
  1234. // bit is set.
  1235. //
  1236. PendingMask = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
  1237. PciDevice->DeviceNumber,
  1238. PciDevice->FunctionNumber,
  1239. Offset,
  1240. sizeof(ULONG));
  1241. Mask = 1 << VectorIndex;
  1242. if ((PendingMask & Mask) != 0) {
  1243. *Pending = TRUE;
  1244. } else {
  1245. *Pending = FALSE;
  1246. }
  1247. break;
  1248. case PciMsiTypeExtended:
  1249. ASSERT(MsiContext->MsiXOffset != 0);
  1250. if (MsiContext->MsiXPendingArray == NULL) {
  1251. Status = PcipMapMsiXPendingArray(MsiContext);
  1252. if (!KSUCCESS(Status)) {
  1253. goto MsiIsVectorPendingEnd;
  1254. }
  1255. }
  1256. ASSERT(MsiContext->MsiXPendingArray != NULL);
  1257. Address = MsiContext->MsiXPendingArray +
  1258. ((VectorIndex / 32) * sizeof(ULONG));
  1259. Mask = 1 << (VectorIndex % 32);
  1260. if ((*Address & Mask) != 0) {
  1261. *Pending = TRUE;
  1262. } else {
  1263. *Pending = FALSE;
  1264. }
  1265. break;
  1266. default:
  1267. Status = STATUS_INVALID_PARAMETER;
  1268. goto MsiIsVectorPendingEnd;
  1269. }
  1270. MsiIsVectorPendingEnd:
  1271. return Status;
  1272. }
  1273. KSTATUS
  1274. PcipMapMsiXTable (
  1275. PPCI_MSI_CONTEXT MsiContext
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. This routine synchronously maps the MSI-X table.
  1280. Arguments:
  1281. MsiContext - Supplies a pointer to the MSI context whose MSI-X table is to
  1282. be mapped.
  1283. Return Value:
  1284. Status code.
  1285. --*/
  1286. {
  1287. PVOID OriginalTable;
  1288. PVOID Table;
  1289. ULONG TableSize;
  1290. ASSERT(MsiContext->MsiXOffset != 0);
  1291. //
  1292. // Exit immediately if the table is already mapped.
  1293. //
  1294. if (MsiContext->MsiXTable != NULL) {
  1295. return STATUS_SUCCESS;
  1296. }
  1297. //
  1298. // Fail if there is no physical address to map. This indicates that the
  1299. // MSI-X interface is being invoked a bit early.
  1300. //
  1301. if (MsiContext->MsiXTablePhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
  1302. return STATUS_TOO_EARLY;
  1303. }
  1304. //
  1305. // Map the vector table. The vector count was cached when the context was
  1306. // initialized.
  1307. //
  1308. TableSize = MsiContext->MsiXMaxVectorCount * sizeof(PCI_MSI_X_TABLE_ENTRY);
  1309. Table = MmMapPhysicalAddress(MsiContext->MsiXTablePhysicalAddress,
  1310. TableSize,
  1311. TRUE,
  1312. FALSE,
  1313. TRUE);
  1314. if (Table == NULL) {
  1315. return STATUS_INSUFFICIENT_RESOURCES;
  1316. }
  1317. //
  1318. // Synchronously try to set this as the virtual address of the table.
  1319. //
  1320. OriginalTable = (PVOID)RtlAtomicCompareExchange(
  1321. (volatile UINTN *)&(MsiContext->MsiXTable),
  1322. (UINTN)Table,
  1323. (UINTN)NULL);
  1324. if (OriginalTable != NULL) {
  1325. MmUnmapAddress(Table, TableSize);
  1326. }
  1327. ASSERT(MsiContext->MsiXTable != NULL);
  1328. return STATUS_SUCCESS;
  1329. }
  1330. KSTATUS
  1331. PcipMapMsiXPendingArray (
  1332. PPCI_MSI_CONTEXT MsiContext
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. This routine synchronously maps the MSI-X pending bit array.
  1337. Arguments:
  1338. MsiContext - Supplies a pointer to the MSI context whose MSI-X pending bit
  1339. array is to be mapped.
  1340. Return Value:
  1341. Status code.
  1342. --*/
  1343. {
  1344. PVOID Array;
  1345. ULONG ArraySize;
  1346. PVOID OriginalArray;
  1347. ASSERT(MsiContext->MsiXOffset != 0);
  1348. //
  1349. // Exit immediately if the pending array is already mapped.
  1350. //
  1351. if (MsiContext->MsiXPendingArray != NULL) {
  1352. return STATUS_SUCCESS;
  1353. }
  1354. //
  1355. // Fail if there is no physical address to map. This indicates that the
  1356. // MSI-X interface is being invoked a bit early.
  1357. //
  1358. if (MsiContext->MsiXPendingArrayPhysicalAddress ==
  1359. INVALID_PHYSICAL_ADDRESS) {
  1360. return STATUS_TOO_EARLY;
  1361. }
  1362. //
  1363. // Determine the size of the array in bytes based on the cached vector
  1364. // count.
  1365. //
  1366. ArraySize = MsiContext->MsiXMaxVectorCount / 64;
  1367. if ((MsiContext->MsiXMaxVectorCount % 64) != 0) {
  1368. ArraySize += 1;
  1369. }
  1370. ArraySize *= sizeof(ULONGLONG);
  1371. Array = MmMapPhysicalAddress(MsiContext->MsiXPendingArrayPhysicalAddress,
  1372. ArraySize,
  1373. TRUE,
  1374. FALSE,
  1375. TRUE);
  1376. if (Array == NULL) {
  1377. return STATUS_INSUFFICIENT_RESOURCES;
  1378. }
  1379. //
  1380. // Synchronously try to set this as the virtual address of the table.
  1381. //
  1382. OriginalArray = (PVOID)RtlAtomicCompareExchange(
  1383. (volatile UINTN *)&(MsiContext->MsiXPendingArray),
  1384. (UINTN)Array,
  1385. (UINTN)NULL);
  1386. if (OriginalArray != NULL) {
  1387. MmUnmapAddress(Array, ArraySize);
  1388. }
  1389. ASSERT(MsiContext->MsiXPendingArray != NULL);
  1390. return STATUS_SUCCESS;
  1391. }