123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- msi.c
- Abstract:
- This module implements support for PCI message signaled interrupts.
- Author:
- Chris Stevens 9-Jul-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "pci.h"
- #include <minoca/kernel/acpi.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define offset values for PCI MSI configuration space.
- //
- #define PCI_MSI_CONTROL_OFFSET 0x0
- #define PCI_MSI_CONTROL_MASK 0xFFFF0000
- #define PCI_MSI_CONTROL_SHIFT 16
- #define PCI_MSI_LOWER_ADDRESS_OFFSET 0x04
- #define PCI_MSI_MASK_OFFSET 0x0C
- #define PCI_MSI_64_BIT_MASK_OFFSET 0x10
- #define PCI_MSI_PENDING_OFFSET 0x10
- #define PCI_MSI_64_BIT_PENDING_OFFSET 0x14
- //
- // Define the PCI MSI message control register bits.
- //
- #define PCI_MSI_CONTROL_ENABLE 0x0001
- #define PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK 0x000E
- #define PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT 1
- #define PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_MASK 0x0070
- #define PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_SHIFT 4
- #define PCI_MSI_CONTROL_64_BIT_CAPABLE 0x0080
- #define PCI_MSI_CONTROL_VECTOR_MASKING 0x0100
- #define PCI_MSI_MAXIMUM_VECTOR_ENCODING 5
- //
- // Define offset values for PCI MSI-X configuration space.
- //
- #define PCI_MSI_X_CONTROL_OFFSET 0x0
- #define PCI_MSI_X_CONTROL_MASK 0xFFFF0000
- #define PCI_MSI_X_CONTROL_SHIFT 16
- #define PCI_MSI_X_TABLE_DATA_OFFSET 0x4
- #define PCI_MSI_X_PENDING_ARRAY_DATA_OFFSET 0x8
- //
- // Define the PCI MSI-X message control register bits.
- //
- #define PCI_MSI_X_CONTROL_TABLE_SIZE_MASK 0x7FF
- #define PCI_MSI_X_CONTROL_TABLE_SIZE_SHIFT 0
- #define PCI_MSI_X_CONTROL_GLOBAL_MASK 0x4000
- #define PCI_MSI_X_CONTROL_ENABLE 0x8000
- //
- // Define the PCI MSI-X table data register bits.
- //
- #define PCI_MSI_X_TABLE_BAR_INDEX_MASK 0x00000007
- #define PCI_MSI_X_TABLE_OFFSET_MASK 0xFFFFFFF8
- //
- // Define the PCI MSI-X pending array data register bits.
- //
- #define PCI_MSI_X_PENDING_ARRAY_BAR_INDEX_MASK 0x00000007
- #define PCI_MSI_X_PENDING_ARRAY_OFFSET_MASK 0xFFFFFFF8
- //
- // Define the PCI MSI-X vector control bits.
- //
- #define PCI_MSI_X_VECTOR_CONTROL_MASKED 0x00000001
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef struct _PCI_MSI_X_TABLE_ENTRY {
- ULONGLONG Address;
- ULONG Data;
- ULONG Control;
- } PACKED PCI_MSI_X_TABLE_ENTRY, *PPCI_MSI_X_TABLE_ENTRY;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- PcipMsiGetSetInformation (
- PVOID DeviceToken,
- PPCI_MSI_INFORMATION Information,
- BOOL Set
- );
- KSTATUS
- PcipMsiSetVectors (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG Vector,
- ULONGLONG VectorIndex,
- ULONGLONG VectorCount,
- PPROCESSOR_SET Processors
- );
- KSTATUS
- PcipMsiMaskVectors (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG VectorIndex,
- ULONGLONG VectorCount,
- BOOL MaskVectors
- );
- KSTATUS
- PcipMsiIsVectorMasked (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG VectorIndex,
- PBOOL Masked
- );
- KSTATUS
- PcipMsiIsVectorPending (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG VectorIndex,
- PBOOL Pending
- );
- KSTATUS
- PcipMapMsiXTable (
- PPCI_MSI_CONTEXT MsiContext
- );
- KSTATUS
- PcipMapMsiXPendingArray (
- PPCI_MSI_CONTEXT MsiContext
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- PcipMsiCreateContextAndInterface (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- )
- /*++
- Routine Description:
- This routine initializes the MSI/MSI-X context and interface for the given
- PCI device.
- Arguments:
- Device - Supplies a pointer to the device in need of an MSI/MSI-X context
- and interface.
- PciDevice - Supplies a pointer to the PCI device context.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- UCHAR CapabilitiesListOffset;
- ULONG CapabilitiesPointerOffset;
- UCHAR Capability;
- ULONG Control;
- PFADT Fadt;
- ULONG HeaderType;
- USHORT ListEntry;
- PPCI_MSI_CONTEXT MsiContext;
- ULONG MsiFlags;
- PINTERFACE_PCI_MSI MsiInterface;
- ULONGLONG MsiMaxVectorCount;
- UCHAR MsiOffset;
- ULONGLONG MsiXMaxVectorCount;
- UCHAR MsiXOffset;
- UCHAR NextOffset;
- ULONG Offset;
- ULONG PciStatus;
- KSTATUS Status;
- MsiContext = NULL;
- //
- // If there is no capabilities list then there is definitely no MSI or
- // MSI-X interface.
- //
- PciStatus = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- PCI_STATUS_OFFSET,
- sizeof(ULONG));
- PciStatus = (PciStatus & PCI_STATUS_MASK) >> PCI_STATUS_SHIFT;
- if ((PciStatus & PCI_STATUS_CAPABILITIES_LIST) == 0) {
- Status = STATUS_SUCCESS;
- goto MsiCreateInterfaceEnd;
- }
- //
- // Get the header type to determine the offset of the capabilities pointer.
- //
- HeaderType = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- PCI_HEADER_TYPE_OFFSET,
- sizeof(ULONG));
- HeaderType = (HeaderType & PCI_HEADER_TYPE_MASK) >> PCI_HEADER_TYPE_SHIFT;
- HeaderType &= PCI_HEADER_TYPE_VALUE_MASK;
- if (HeaderType == PCI_HEADER_TYPE_CARDBUS_BRIDGE) {
- CapabilitiesPointerOffset = PCI_ALTERNATE_CAPABILITIES_POINTER_OFFSET;
- } else {
- CapabilitiesPointerOffset = PCI_DEFAULT_CAPABILITIES_POINTER_OFFSET;
- }
- //
- // Read the capabilities pointer offset to get the start of the
- // capabilities list.
- //
- CapabilitiesListOffset = (UCHAR)PciDevice->ReadConfig(
- PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- CapabilitiesPointerOffset,
- sizeof(UCHAR));
- ASSERT((CapabilitiesListOffset == 0) ||
- (CapabilitiesListOffset > PCI_INTERRUPT_LINE_OFFSET));
- //
- // Loop through the capabilities list searching for the MSI and MSI-X
- // capabilities. They should only ever appear once in the list.
- //
- MsiOffset = 0;
- MsiXOffset = 0;
- NextOffset = CapabilitiesListOffset & PCI_CAPABILITY_POINTER_MASK;
- while (NextOffset != 0) {
- ListEntry = (USHORT)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- NextOffset,
- sizeof(USHORT));
- //
- // If this list entry is for either of the desired MSI/MSI-X
- // capabilities then record the offset.
- //
- Capability = (ListEntry & PCI_CAPABILITY_LIST_ID_MASK) >>
- PCI_CAPABILITY_LIST_ID_SHIFT;
- if (Capability == PCI_CAPABILITY_MSI) {
- ASSERT(MsiOffset == 0);
- MsiOffset = NextOffset;
- //
- // Stop if both have now been found.
- //
- if (MsiXOffset != 0) {
- break;
- }
- } else if (Capability == PCI_CAPABILITY_MSI_X) {
- ASSERT(MsiXOffset == 0);
- MsiXOffset = NextOffset;
- //
- // Stop if both have now been found.
- //
- if (MsiOffset != 0) {
- break;
- }
- }
- //
- // Get the offset of the next capability.
- //
- NextOffset = (ListEntry & PCI_CAPABILITY_LIST_NEXT_POINTER_MASK) >>
- PCI_CAPABILITY_LIST_NEXT_POINTER_SHIFT;
- NextOffset &= PCI_CAPABILITY_POINTER_MASK;
- }
- //
- // If neither of the capabilities exist, then bail out.
- //
- if ((MsiOffset == 0) && (MsiXOffset == 0)) {
- Status = STATUS_SUCCESS;
- goto MsiCreateInterfaceEnd;
- }
- //
- // TODO: Test to see if the device tree has MSI/MSI-X support.
- //
- Fadt = AcpiFindTable(FADT_SIGNATURE, NULL);
- if ((Fadt == NULL) ||
- ((Fadt->IaBootFlags & FADT_IA_FLAG_MSI_NOT_SUPPORTED) != 0)) {
- Status = STATUS_SUCCESS;
- goto MsiCreateInterfaceEnd;
- }
- //
- // Save the read-only information from the MSI configuration space.
- //
- MsiFlags = 0;
- MsiMaxVectorCount = 0;
- if (MsiOffset != 0) {
- Offset = MsiOffset + PCI_MSI_CONTROL_OFFSET;
- Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- Control = (Control & PCI_MSI_CONTROL_MASK) >> PCI_MSI_CONTROL_SHIFT;
- if ((Control & PCI_MSI_CONTROL_64_BIT_CAPABLE) != 0) {
- MsiFlags |= PCI_MSI_FLAG_64_BIT_CAPABLE;
- }
- if ((Control & PCI_MSI_CONTROL_VECTOR_MASKING) != 0) {
- MsiFlags |= PCI_MSI_FLAG_MASKABLE;
- }
- MsiMaxVectorCount = (Control &
- PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK) >>
- PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT;
- MsiMaxVectorCount = 1 << MsiMaxVectorCount;
- }
- //
- // Save the read-only information from the MSI-X configuration space.
- //
- MsiXMaxVectorCount = 0;
- if (MsiXOffset != 0) {
- Offset = MsiXOffset + PCI_MSI_X_CONTROL_OFFSET;
- Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- Control = (Control & PCI_MSI_X_CONTROL_MASK) >> PCI_MSI_X_CONTROL_SHIFT;
- MsiXMaxVectorCount = (Control & PCI_MSI_X_CONTROL_TABLE_SIZE_MASK) >>
- PCI_MSI_X_CONTROL_TABLE_SIZE_SHIFT;
- MsiXMaxVectorCount = MsiXMaxVectorCount + 1;
- }
- //
- // One or both of the MSI and/or MSI-X capabilities exists. Create the
- // context and interface, recording the config space offsets.
- //
- AllocationSize = sizeof(PCI_MSI_CONTEXT) + sizeof(INTERFACE_PCI_MSI);
- MsiContext = MmAllocateNonPagedPool(AllocationSize, PCI_ALLOCATION_TAG);
- if (MsiContext == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto MsiCreateInterfaceEnd;
- }
- RtlZeroMemory(MsiContext, AllocationSize);
- MsiInterface = (PINTERFACE_PCI_MSI)(MsiContext + 1);
- MsiInterface->GetSetInformation = PcipMsiGetSetInformation;
- MsiInterface->SetVectors = PcipMsiSetVectors;
- MsiInterface->MaskVectors = PcipMsiMaskVectors;
- MsiInterface->IsVectorMasked = PcipMsiIsVectorMasked;
- MsiInterface->IsVectorPending = PcipMsiIsVectorPending;
- MsiInterface->DeviceToken = PciDevice;
- MsiContext->MsiOffset = MsiOffset;
- MsiContext->MsiXOffset = MsiXOffset;
- MsiContext->MsiFlags = MsiFlags;
- MsiContext->MsiMaxVectorCount = MsiMaxVectorCount;
- MsiContext->MsiXMaxVectorCount = MsiXMaxVectorCount;
- MsiContext->Interface = MsiInterface;
- PciDevice->MsiContext = MsiContext;
- Status = IoCreateInterface(&PciMessageSignaledInterruptsUuid,
- Device,
- MsiInterface,
- sizeof(INTERFACE_PCI_MSI));
- if (!KSUCCESS(Status)) {
- goto MsiCreateInterfaceEnd;
- }
- MsiCreateInterfaceEnd:
- if (!KSUCCESS(Status)) {
- if (MsiContext != NULL) {
- MmFreeNonPagedPool(MsiContext);
- }
- PciDevice->MsiContext = NULL;
- }
- return Status;
- }
- VOID
- PcipMsiDestroyContextAndInterface (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- )
- /*++
- Routine Description:
- This routine destroys the given PCI device's MSI context and interface if
- they exist.
- Arguments:
- Device - Supplies a pointer to the device whose MSI/MSI-x context and
- interface is to be destroyed.
- PciDevice - Supplies a pointer to the PCI device context.
- Return Value:
- None.
- --*/
- {
- if (PciDevice->MsiContext == NULL) {
- return;
- }
- IoDestroyInterface(&PciMessageSignaledInterruptsUuid,
- Device,
- PciDevice->MsiContext->Interface);
- MmFreeNonPagedPool(PciDevice->MsiContext);
- PciDevice->MsiContext = NULL;
- return;
- }
- VOID
- PcipGetMsiXBarInformation (
- PPCI_DEVICE PciDevice,
- PULONG TableBarIndex,
- PULONG TableOffset,
- PULONG PendingArrayBarIndex,
- PULONG PendingArrayOffset
- )
- /*++
- Routine Description:
- This routine gets the BAR information for the MSI-X table and pending bit
- array out of PCI configuration space.
- Arguments:
- PciDevice - Supplies a pointer to the PCI device context.
- TableBarIndex - Supplies a pointer that receives the index of the BAR
- within which the MSI-X table resides.
- TableOffset - Supplies a pointer that receives the offset within the BAR
- of the MSI-X table.
- PendingArrayBarIndex - Supplies a pointer that receives the index of the
- BAR within which the MSI-X pending bit array resides.
- PendingArrayOffset - Supplies a pointer that receives the offset within the
- BAR of the MSI-X pending bit array.
- Return Value:
- None.
- --*/
- {
- PPCI_MSI_CONTEXT MsiContext;
- ULONG Offset;
- ULONG PendingArrayData;
- ULONG TableData;
- ASSERT(PciDevice->MsiContext != NULL);
- ASSERT(PciDevice->MsiContext->MsiXOffset != 0);
- //
- // Get the BAR index and offset for the MSI-X vector table.
- //
- MsiContext = PciDevice->MsiContext;
- Offset = MsiContext->MsiXOffset + PCI_MSI_X_TABLE_DATA_OFFSET;
- TableData = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- *TableBarIndex = TableData & PCI_MSI_X_TABLE_BAR_INDEX_MASK;
- *TableOffset = TableData & PCI_MSI_X_TABLE_OFFSET_MASK;
- //
- // Get the BAR index and offset for the MSI-X pending bit array.
- //
- Offset = MsiContext->MsiXOffset + PCI_MSI_X_PENDING_ARRAY_DATA_OFFSET;
- PendingArrayData = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- *PendingArrayBarIndex = PendingArrayData &
- PCI_MSI_X_PENDING_ARRAY_BAR_INDEX_MASK;
- *PendingArrayOffset = PendingArrayData &
- PCI_MSI_X_PENDING_ARRAY_OFFSET_MASK;
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- PcipMsiGetSetInformation (
- PVOID DeviceToken,
- PPCI_MSI_INFORMATION Information,
- BOOL Set
- )
- /*++
- Routine Description:
- This routine gets or sets MSI/MSI-X information for the given PCI device.
- Returned information includes whether or not MSI/MSI-X is enabled, uses
- 64-bit addresses, is maskable, etc. Information to set includes enabling
- and disabling MSI/MSI-X, the MSI vector count, and the MSI-X global mask.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- Information - Supplies a pointer to a structure that either receives the
- requested information or contains the information to set. In both
- cases, the caller should specify the structure version and the MSI
- type - basic (MSI) or extended (MSI-X) - before passing it to the
- routine.
- Set - Supplies a boolean indicating whether to get or set the MSI/MSI-X
- information.
- Return Value:
- Status code.
- --*/
- {
- ULONG Control;
- ULONG Flags;
- ULONGLONG MaxVectorCount;
- PPCI_MSI_CONTEXT MsiContext;
- ULONG Offset;
- PPCI_DEVICE PciDevice;
- KSTATUS Status;
- ULONGLONG VectorCount;
- if (Information->Version != PCI_MSI_INTERFACE_INFORMATION_VERSION) {
- return STATUS_INVALID_PARAMETER;
- }
- PciDevice = (PPCI_DEVICE)DeviceToken;
- if (PciDevice->MsiContext == NULL) {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // Get the information for the requested MSI/MSI-X type.
- //
- Status = STATUS_SUCCESS;
- MsiContext = PciDevice->MsiContext;
- if (Set == FALSE) {
- switch (Information->MsiType) {
- case PciMsiTypeBasic:
- if (MsiContext->MsiOffset == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto MsiGetSetInformationEnd;
- }
- Offset = MsiContext->MsiOffset + PCI_MSI_CONTROL_OFFSET;
- Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI);
- Control = (Control & PCI_MSI_CONTROL_MASK) >>
- PCI_MSI_CONTROL_SHIFT;
- Information->Flags = 0;
- if ((Control & PCI_MSI_CONTROL_ENABLE) != 0) {
- Information->Flags |= PCI_MSI_INTERFACE_FLAG_ENABLED;
- }
- if ((Control & PCI_MSI_CONTROL_64_BIT_CAPABLE) != 0) {
- Information->Flags |= PCI_MSI_INTERFACE_FLAG_64_BIT_CAPABLE;
- }
- if ((Control & PCI_MSI_CONTROL_VECTOR_MASKING) != 0) {
- Information->Flags |= PCI_MSI_INTERFACE_FLAG_MASKABLE;
- }
- MaxVectorCount = (Control &
- PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK) >>
- PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT;
- Information->MaxVectorCount = 1 << MaxVectorCount;
- ASSERT(MsiContext->MsiMaxVectorCount ==
- Information->MaxVectorCount);
- VectorCount = (Control &
- PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_MASK) >>
- PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_SHIFT;
- Information->VectorCount = 1 << VectorCount;
- break;
- case PciMsiTypeExtended:
- if (MsiContext->MsiXOffset == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto MsiGetSetInformationEnd;
- }
- Offset = MsiContext->MsiXOffset + PCI_MSI_X_CONTROL_OFFSET;
- Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI_X);
- Control = (Control & PCI_MSI_X_CONTROL_MASK) >>
- PCI_MSI_X_CONTROL_SHIFT;
- Information->Flags = PCI_MSI_INTERFACE_FLAG_64_BIT_CAPABLE |
- PCI_MSI_INTERFACE_FLAG_MASKABLE;
- if ((Control & PCI_MSI_X_CONTROL_ENABLE) != 0) {
- Information->Flags |= PCI_MSI_INTERFACE_FLAG_ENABLED;
- }
- if ((Control & PCI_MSI_X_CONTROL_GLOBAL_MASK) != 0) {
- Information->Flags |= PCI_MSI_INTERFACE_FLAG_GLOBAL_MASK;
- }
- MaxVectorCount = (Control &
- PCI_MSI_X_CONTROL_TABLE_SIZE_MASK) >>
- PCI_MSI_X_CONTROL_TABLE_SIZE_SHIFT;
- Information->MaxVectorCount = MaxVectorCount + 1;
- ASSERT(MsiContext->MsiXMaxVectorCount ==
- Information->MaxVectorCount);
- Information->VectorCount = MsiContext->MsiXVectorCount;
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiGetSetInformationEnd;
- }
- //
- // Set the MSI/MSI-X state based on the supplied information.
- //
- } else {
- switch (Information->MsiType) {
- case PciMsiTypeBasic:
- if (MsiContext->MsiOffset == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto MsiGetSetInformationEnd;
- }
- //
- // Validate that the supplied vector count is less than the maximum
- // allowed vectors and that it is a power of two.
- //
- if ((Information->VectorCount == 0) ||
- (Information->VectorCount > MsiContext->MsiMaxVectorCount) ||
- (POWER_OF_2(Information->VectorCount) == FALSE)) {
- Status = STATUS_INVALID_PARAMETER;
- goto MsiGetSetInformationEnd;
- }
- //
- // The configuration space encodes the value x where the vector
- // count is 2^x. Make sure that the exponent isn't too large.
- //
- VectorCount = RtlCountTrailingZeros64(Information->VectorCount);
- if (VectorCount > PCI_MSI_MAXIMUM_VECTOR_ENCODING) {
- Status = STATUS_INVALID_PARAMETER;
- goto MsiGetSetInformationEnd;
- }
- //
- // Read the current control information.
- //
- Offset = MsiContext->MsiOffset + PCI_MSI_CONTROL_OFFSET;
- Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI);
- Control = (Control & PCI_MSI_CONTROL_MASK) >> PCI_MSI_CONTROL_SHIFT;
- //
- // Update the control status based on the supplied information.
- //
- if ((Information->Flags & PCI_MSI_INTERFACE_FLAG_ENABLED) != 0) {
- Control |= PCI_MSI_CONTROL_ENABLE;
- } else {
- Control &= ~PCI_MSI_CONTROL_ENABLE;
- }
- MaxVectorCount = (Control &
- PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_MASK) >>
- PCI_MSI_CONTROL_MULTI_VECTOR_CAPABLE_SHIFT;
- MaxVectorCount = 1 << MaxVectorCount;
- ASSERT(MsiContext->MsiMaxVectorCount == MaxVectorCount);
- Control |= (VectorCount <<
- PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_SHIFT) &
- PCI_MSI_CONTROL_MULTI_VECTOR_ENABLE_MASK;
- //
- // Write out the updated control information. There shouldn't be
- // a need to preserve the read-only capability ID and next pointer
- // offset, so just shift the control data and write it out.
- //
- Control <<= PCI_MSI_CONTROL_SHIFT;
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG),
- Control);
- break;
- case PciMsiTypeExtended:
- if (MsiContext->MsiXOffset == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto MsiGetSetInformationEnd;
- }
- //
- // Read the current control information.
- //
- Offset = MsiContext->MsiXOffset + PCI_MSI_X_CONTROL_OFFSET;
- Control = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- ASSERT((UCHAR)Control == PCI_CAPABILITY_MSI_X);
- Control = (Control & PCI_MSI_X_CONTROL_MASK) >>
- PCI_MSI_X_CONTROL_SHIFT;
- //
- // Update the control status based on the supplied information.
- //
- Flags = Information->Flags;
- if ((Flags & PCI_MSI_INTERFACE_FLAG_ENABLED) != 0) {
- Control |= PCI_MSI_X_CONTROL_ENABLE;
- } else {
- Control &= ~PCI_MSI_X_CONTROL_ENABLE;
- }
- if ((Flags & PCI_MSI_INTERFACE_FLAG_GLOBAL_MASK) != 0) {
- Control |= PCI_MSI_X_CONTROL_GLOBAL_MASK;
- } else {
- Control &= ~PCI_MSI_X_CONTROL_GLOBAL_MASK;
- }
- //
- // Write out the updated control information. There shouldn't be
- // a need to preserve the read-only capability ID and next pointer
- // offset, so just shift the control data and write it out.
- //
- Control <<= PCI_MSI_X_CONTROL_SHIFT;
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG),
- Control);
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiGetSetInformationEnd;
- }
- //
- // If the above set enabled MSI/MSI-X, then disable legacy interrupts.
- //
- if ((Information->Flags & PCI_MSI_INTERFACE_FLAG_ENABLED) != 0) {
- Control = (USHORT)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT));
- Control |= PCI_CONTROL_INTERRUPT_DISABLE;
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- Control);
- }
- }
- MsiGetSetInformationEnd:
- return Status;
- }
- KSTATUS
- PcipMsiSetVectors (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG Vector,
- ULONGLONG VectorIndex,
- ULONGLONG VectorCount,
- PPROCESSOR_SET Processors
- )
- /*++
- Routine Description:
- This routine sets the address and data for the given contiguous MSI/MSI-X
- vectors.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- MsiType - Supplies the type of the MSI vector.
- Vector - Supplies the starting vector to be set at the given vector index.
- VectorIndex - Supplies the index into the vector table where this vector
- information should be written. This is only valid for MSI-X.
- VectorCount - Supplies the number of contiguous vectors to set starting at
- the given vector and index.
- Processors - Supplies the set of processors that the MSIs should utilize.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- ULONGLONG Index;
- PMSI_INFORMATION Information;
- MSI_INFORMATION InformationBuffer;
- ULONGLONG MessageData;
- PPCI_MSI_CONTEXT MsiContext;
- ULONG Offset;
- PPCI_DEVICE PciDevice;
- PHYSICAL_ADDRESS PhysicalAddress;
- KSTATUS Status;
- PPCI_MSI_X_TABLE_ENTRY TableEntry;
- Information = NULL;
- PciDevice = (PPCI_DEVICE)DeviceToken;
- MsiContext = PciDevice->MsiContext;
- //
- // Bail out immediately if an unsupported MSI type was requested.
- //
- if ((MsiContext == NULL) ||
- ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
- ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
- ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // If no vector count was supplied, then it was likely by mistake.
- //
- if (VectorCount == 0) {
- return STATUS_INVALID_PARAMETER;
- }
- //
- // Validate the index and count based on the cached maximum vector count.
- //
- switch (MsiType) {
- case PciMsiTypeBasic:
- if ((VectorIndex + VectorCount) > MsiContext->MsiMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiSetVectorsEnd;
- }
- //
- // Truncate the vector count to 1 as MSI only has one physical address
- // and message register pair. Multiple vectors must be contiguous.
- //
- VectorCount = 1;
- break;
- case PciMsiTypeExtended:
- if ((VectorIndex + VectorCount) > MsiContext->MsiXMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiSetVectorsEnd;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiSetVectorsEnd;
- }
- //
- // Get an appropriate array for physical addresses and data pairs.
- //
- if (VectorCount == 1) {
- Information = &InformationBuffer;
- } else {
- AllocationSize = VectorCount * sizeof(MSI_INFORMATION);
- Information = MmAllocatePagedPool(AllocationSize,
- PCI_ALLOCATION_TAG);
- if (Information == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto MsiSetVectorsEnd;
- }
- }
- Status = HlGetMsiInformation(Vector,
- VectorCount,
- Processors,
- Information);
- if (!KSUCCESS(Status)) {
- goto MsiSetVectorsEnd;
- }
- //
- // Set the addresses and data in the MSI vector.
- //
- Status = STATUS_SUCCESS;
- switch (MsiType) {
- case PciMsiTypeBasic:
- ASSERT(MsiContext->MsiOffset != 0);
- ASSERT(VectorIndex == 0);
- //
- // Even if more than one vector is being programmed, there is only one
- // address and data field. Take the information from the first vector.
- //
- PhysicalAddress = Information[0].Address;
- MessageData = Information[0].Data;
- Offset = MsiContext->MsiOffset + PCI_MSI_LOWER_ADDRESS_OFFSET;
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG),
- (ULONG)PhysicalAddress);
- if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
- Offset += sizeof(ULONG);
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG),
- (ULONG)(PhysicalAddress >> 32));
- }
- Offset += sizeof(ULONG);
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(USHORT),
- (USHORT)MessageData);
- break;
- case PciMsiTypeExtended:
- ASSERT(MsiContext->MsiXOffset != 0);
- if (MsiContext->MsiXTable == NULL) {
- Status = PcipMapMsiXTable(MsiContext);
- if (!KSUCCESS(Status)) {
- goto MsiSetVectorsEnd;
- }
- }
- ASSERT(MsiContext->MsiXTable != NULL);
- TableEntry = (PPCI_MSI_X_TABLE_ENTRY)(MsiContext->MsiXTable +
- (VectorIndex *
- sizeof(PCI_MSI_X_TABLE_ENTRY)));
- for (Index = 0; Index < VectorCount; Index += 1) {
- if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) == 0) {
- TableEntry->Control |= PCI_MSI_X_VECTOR_CONTROL_MASKED;
- RtlMemoryBarrier();
- } else {
- MsiContext->MsiXVectorCount += 1;
- }
- TableEntry->Address = Information[Index].Address;
- TableEntry->Data = (ULONG)Information[Index].Data;
- RtlMemoryBarrier();
- TableEntry->Control &= ~PCI_MSI_X_VECTOR_CONTROL_MASKED;
- TableEntry += 1;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
- MsiSetVectorsEnd:
- if ((VectorCount != 1) && (Information != NULL)) {
- MmFreePagedPool(Information);
- }
- return Status;
- }
- KSTATUS
- PcipMsiMaskVectors (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG VectorIndex,
- ULONGLONG VectorCount,
- BOOL MaskVectors
- )
- /*++
- Routine Description:
- This routine masks or unmasks a set of contiguous MSI/MSI-X vectors for the
- given PCI device.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- MsiType - Supplies the type of the MSI vector.
- VectorIndex - Supplies the starting index of the vectors that are to be
- masked or unmasked.
- VectorCount - Supplies the number fo contiguous vectors to mask or unmask
- starting at the given index.
- MaskVectors - Supplies a boolean indicating whether the vector should be
- masked (TRUE) or unmasked (FALSE).
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG Index;
- ULONG Mask;
- PPCI_MSI_CONTEXT MsiContext;
- ULONG Offset;
- PPCI_DEVICE PciDevice;
- KSTATUS Status;
- PPCI_MSI_X_TABLE_ENTRY TableEntry;
- ULONG VectorMask;
- PciDevice = (PPCI_DEVICE)DeviceToken;
- MsiContext = PciDevice->MsiContext;
- //
- // Bail out immediately if an unsupported MSI type was requested.
- //
- if ((MsiContext == NULL) ||
- ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
- ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
- ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // Consider it a success if no vectors were asked to be masked or unmaksed.
- //
- if (VectorCount == 0) {
- return STATUS_SUCCESS;
- }
- //
- // Validate the index and count based on the cached maximum vector count.
- //
- switch (MsiType) {
- case PciMsiTypeBasic:
- if ((VectorIndex + VectorCount) > MsiContext->MsiMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiMaskVectorsEnd;
- }
- //
- // Bail now if masking is not supported.
- //
- if ((MsiContext->MsiFlags & PCI_MSI_FLAG_MASKABLE) == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto MsiMaskVectorsEnd;
- }
- break;
- case PciMsiTypeExtended:
- if ((VectorIndex + VectorCount) > MsiContext->MsiXMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiMaskVectorsEnd;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiMaskVectorsEnd;
- }
- //
- // Mask or unmask the vectors based on the type.
- //
- Status = STATUS_SUCCESS;
- switch (MsiType) {
- case PciMsiTypeBasic:
- ASSERT(MsiContext->MsiOffset != 0);
- if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
- Offset = MsiContext->MsiOffset + PCI_MSI_64_BIT_MASK_OFFSET;
- } else {
- Offset = MsiContext->MsiOffset + PCI_MSI_MASK_OFFSET;
- }
- //
- // Build out the mask of the vectors that are to be modified.
- //
- Mask = 0;
- for (Index = VectorIndex;
- Index < (VectorIndex + VectorCount);
- Index += 1) {
- Mask |= (1 << Index);
- }
- //
- // Read, modify, and write the configuration space to update the masks.
- //
- VectorMask = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- if (MaskVectors != FALSE) {
- VectorMask |= Mask;
- } else {
- VectorMask &= ~Mask;
- }
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG),
- VectorMask);
- break;
- case PciMsiTypeExtended:
- ASSERT(MsiContext->MsiXOffset != 0);
- if (MsiContext->MsiXTable == NULL) {
- Status = PcipMapMsiXTable(MsiContext);
- if (!KSUCCESS(Status)) {
- goto MsiMaskVectorsEnd;
- }
- }
- ASSERT(MsiContext->MsiXTable != NULL);
- TableEntry = (PPCI_MSI_X_TABLE_ENTRY)(MsiContext->MsiXTable +
- (VectorIndex *
- sizeof(PCI_MSI_X_TABLE_ENTRY)));
- if (MaskVectors != FALSE) {
- for (Index = 0; Index < VectorCount; Index += 1) {
- if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) ==
- 0) {
- TableEntry->Control |= PCI_MSI_X_VECTOR_CONTROL_MASKED;
- MsiContext->MsiXVectorCount -= 1;
- }
- TableEntry += 1;
- }
- } else {
- for (Index = 0; Index < VectorCount; Index += 1) {
- if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) !=
- 0) {
- TableEntry->Control &= ~PCI_MSI_X_VECTOR_CONTROL_MASKED;
- MsiContext->MsiXVectorCount += 1;
- }
- TableEntry += 1;
- }
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiMaskVectorsEnd;
- }
- MsiMaskVectorsEnd:
- return Status;
- }
- KSTATUS
- PcipMsiIsVectorMasked (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG VectorIndex,
- PBOOL Masked
- )
- /*++
- Routine Description:
- This routine determines whether or not an MSI/MSI-X vector for the given
- PCI device is masked.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- MsiType - Supplies the type of the MSI vector.
- VectorIndex - Supplies the index of the vector whose masked state is to be
- returned.
- Masked - Supplies a pointer to a boolean that receives whether or not the
- vector is masked.
- Return Value:
- Status code.
- --*/
- {
- ULONG Mask;
- PPCI_MSI_CONTEXT MsiContext;
- ULONG Offset;
- PPCI_DEVICE PciDevice;
- KSTATUS Status;
- PPCI_MSI_X_TABLE_ENTRY TableEntry;
- ULONG VectorMask;
- PciDevice = (PPCI_DEVICE)DeviceToken;
- MsiContext = PciDevice->MsiContext;
- //
- // Bail out immediately if an unsupported MSI type was requested.
- //
- if ((MsiContext == NULL) ||
- ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
- ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
- ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // Validate the index based on the cached maximum vector count.
- //
- switch (MsiType) {
- case PciMsiTypeBasic:
- if (VectorIndex >= MsiContext->MsiMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiIsVectorMaskedEnd;
- }
- //
- // Bail now if masking is not supported.
- //
- if ((MsiContext->MsiFlags & PCI_MSI_FLAG_MASKABLE) == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto MsiIsVectorMaskedEnd;
- }
- break;
- case PciMsiTypeExtended:
- if (VectorIndex >= MsiContext->MsiXMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiIsVectorMaskedEnd;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiIsVectorMaskedEnd;
- }
- //
- // Determine whether or not the vector is masked or unmasked.
- //
- Status = STATUS_SUCCESS;
- switch (MsiType) {
- case PciMsiTypeBasic:
- ASSERT(MsiContext->MsiOffset != 0);
- if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
- Offset = MsiContext->MsiOffset + PCI_MSI_64_BIT_MASK_OFFSET;
- } else {
- Offset = MsiContext->MsiOffset + PCI_MSI_MASK_OFFSET;
- }
- //
- // Read the vector mask data and check to see if the given vector's bit
- // is set.
- //
- VectorMask = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- Mask = 1 << VectorIndex;
- if ((VectorMask & Mask) != 0) {
- *Masked = TRUE;
- } else {
- *Masked = FALSE;
- }
- break;
- case PciMsiTypeExtended:
- ASSERT(MsiContext->MsiXOffset != 0);
- if (MsiContext->MsiXTable == NULL) {
- Status = PcipMapMsiXTable(MsiContext);
- if (!KSUCCESS(Status)) {
- goto MsiIsVectorMaskedEnd;
- }
- }
- ASSERT(MsiContext->MsiXTable != NULL);
- TableEntry = (PPCI_MSI_X_TABLE_ENTRY)(MsiContext->MsiXTable +
- (VectorIndex *
- sizeof(PCI_MSI_X_TABLE_ENTRY)));
- if ((TableEntry->Control & PCI_MSI_X_VECTOR_CONTROL_MASKED) != 0) {
- *Masked = TRUE;
- } else {
- *Masked = FALSE;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiIsVectorMaskedEnd;
- }
- MsiIsVectorMaskedEnd:
- return Status;
- }
- KSTATUS
- PcipMsiIsVectorPending (
- PVOID DeviceToken,
- PCI_MSI_TYPE MsiType,
- ULONGLONG VectorIndex,
- PBOOL Pending
- )
- /*++
- Routine Description:
- This routine determines whether or not an MSI/MSI-X vector for the given
- PCI device is pending.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- MsiType - Supplies the type of the MSI vector.
- VectorIndex - Supplies the index of the vector whose pending state is to be
- returned.
- Pending - Supplies a pointer to a boolean that receives whether or not the
- vector has a pending interrupt.
- Return Value:
- Status code.
- --*/
- {
- PULONG Address;
- ULONG Mask;
- PPCI_MSI_CONTEXT MsiContext;
- ULONG Offset;
- PPCI_DEVICE PciDevice;
- ULONG PendingMask;
- KSTATUS Status;
- PciDevice = (PPCI_DEVICE)DeviceToken;
- MsiContext = PciDevice->MsiContext;
- //
- // Bail out immediately if an unsupported MSI type was requested.
- //
- if ((MsiContext == NULL) ||
- ((MsiType == PciMsiTypeBasic) && (MsiContext->MsiOffset == 0)) ||
- ((MsiType == PciMsiTypeExtended) && (MsiContext->MsiXOffset == 0)) ||
- ((MsiType != PciMsiTypeBasic) && (MsiType != PciMsiTypeExtended))) {
- return STATUS_NOT_SUPPORTED;
- }
- //
- // Validate the index based on the cached maximum vector count.
- //
- switch (MsiType) {
- case PciMsiTypeBasic:
- if (VectorIndex >= MsiContext->MsiMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiIsVectorPendingEnd;
- }
- //
- // Bail now if masking/pending is not supported.
- //
- if ((MsiContext->MsiFlags & PCI_MSI_FLAG_MASKABLE) == 0) {
- Status = STATUS_NOT_SUPPORTED;
- goto MsiIsVectorPendingEnd;
- }
- break;
- case PciMsiTypeExtended:
- if (VectorIndex >= MsiContext->MsiXMaxVectorCount) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto MsiIsVectorPendingEnd;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiIsVectorPendingEnd;
- }
- //
- // Determine whether or not the vector is pending or not.
- //
- Status = STATUS_SUCCESS;
- switch (MsiType) {
- case PciMsiTypeBasic:
- ASSERT(MsiContext->MsiOffset != 0);
- if ((MsiContext->MsiFlags & PCI_MSI_FLAG_64_BIT_CAPABLE) != 0) {
- Offset = MsiContext->MsiOffset + PCI_MSI_64_BIT_PENDING_OFFSET;
- } else {
- Offset = MsiContext->MsiOffset + PCI_MSI_PENDING_OFFSET;
- }
- //
- // Read the vector pending data and check to see if the given vector's
- // bit is set.
- //
- PendingMask = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- sizeof(ULONG));
- Mask = 1 << VectorIndex;
- if ((PendingMask & Mask) != 0) {
- *Pending = TRUE;
- } else {
- *Pending = FALSE;
- }
- break;
- case PciMsiTypeExtended:
- ASSERT(MsiContext->MsiXOffset != 0);
- if (MsiContext->MsiXPendingArray == NULL) {
- Status = PcipMapMsiXPendingArray(MsiContext);
- if (!KSUCCESS(Status)) {
- goto MsiIsVectorPendingEnd;
- }
- }
- ASSERT(MsiContext->MsiXPendingArray != NULL);
- Address = MsiContext->MsiXPendingArray +
- ((VectorIndex / 32) * sizeof(ULONG));
- Mask = 1 << (VectorIndex % 32);
- if ((*Address & Mask) != 0) {
- *Pending = TRUE;
- } else {
- *Pending = FALSE;
- }
- break;
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto MsiIsVectorPendingEnd;
- }
- MsiIsVectorPendingEnd:
- return Status;
- }
- KSTATUS
- PcipMapMsiXTable (
- PPCI_MSI_CONTEXT MsiContext
- )
- /*++
- Routine Description:
- This routine synchronously maps the MSI-X table.
- Arguments:
- MsiContext - Supplies a pointer to the MSI context whose MSI-X table is to
- be mapped.
- Return Value:
- Status code.
- --*/
- {
- PVOID OriginalTable;
- PVOID Table;
- ULONG TableSize;
- ASSERT(MsiContext->MsiXOffset != 0);
- //
- // Exit immediately if the table is already mapped.
- //
- if (MsiContext->MsiXTable != NULL) {
- return STATUS_SUCCESS;
- }
- //
- // Fail if there is no physical address to map. This indicates that the
- // MSI-X interface is being invoked a bit early.
- //
- if (MsiContext->MsiXTablePhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
- return STATUS_TOO_EARLY;
- }
- //
- // Map the vector table. The vector count was cached when the context was
- // initialized.
- //
- TableSize = MsiContext->MsiXMaxVectorCount * sizeof(PCI_MSI_X_TABLE_ENTRY);
- Table = MmMapPhysicalAddress(MsiContext->MsiXTablePhysicalAddress,
- TableSize,
- TRUE,
- FALSE,
- TRUE);
- if (Table == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- //
- // Synchronously try to set this as the virtual address of the table.
- //
- OriginalTable = (PVOID)RtlAtomicCompareExchange(
- (volatile UINTN *)&(MsiContext->MsiXTable),
- (UINTN)Table,
- (UINTN)NULL);
- if (OriginalTable != NULL) {
- MmUnmapAddress(Table, TableSize);
- }
- ASSERT(MsiContext->MsiXTable != NULL);
- return STATUS_SUCCESS;
- }
- KSTATUS
- PcipMapMsiXPendingArray (
- PPCI_MSI_CONTEXT MsiContext
- )
- /*++
- Routine Description:
- This routine synchronously maps the MSI-X pending bit array.
- Arguments:
- MsiContext - Supplies a pointer to the MSI context whose MSI-X pending bit
- array is to be mapped.
- Return Value:
- Status code.
- --*/
- {
- PVOID Array;
- ULONG ArraySize;
- PVOID OriginalArray;
- ASSERT(MsiContext->MsiXOffset != 0);
- //
- // Exit immediately if the pending array is already mapped.
- //
- if (MsiContext->MsiXPendingArray != NULL) {
- return STATUS_SUCCESS;
- }
- //
- // Fail if there is no physical address to map. This indicates that the
- // MSI-X interface is being invoked a bit early.
- //
- if (MsiContext->MsiXPendingArrayPhysicalAddress ==
- INVALID_PHYSICAL_ADDRESS) {
- return STATUS_TOO_EARLY;
- }
- //
- // Determine the size of the array in bytes based on the cached vector
- // count.
- //
- ArraySize = MsiContext->MsiXMaxVectorCount / 64;
- if ((MsiContext->MsiXMaxVectorCount % 64) != 0) {
- ArraySize += 1;
- }
- ArraySize *= sizeof(ULONGLONG);
- Array = MmMapPhysicalAddress(MsiContext->MsiXPendingArrayPhysicalAddress,
- ArraySize,
- TRUE,
- FALSE,
- TRUE);
- if (Array == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- //
- // Synchronously try to set this as the virtual address of the table.
- //
- OriginalArray = (PVOID)RtlAtomicCompareExchange(
- (volatile UINTN *)&(MsiContext->MsiXPendingArray),
- (UINTN)Array,
- (UINTN)NULL);
- if (OriginalArray != NULL) {
- MmUnmapAddress(Array, ArraySize);
- }
- ASSERT(MsiContext->MsiXPendingArray != NULL);
- return STATUS_SUCCESS;
- }
|