Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

951 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ixpciint.c
  5. Abstract:
  6. All PCI bus interrupt mapping is in this module, so that a real
  7. system which doesn't have all the limitations which PC PCI
  8. systems have can replaced this code easly.
  9. (bus memory & i/o address mappings can also be fix here)
  10. Author:
  11. Ken Reneris
  12. Environment:
  13. Kernel mode
  14. Revision History:
  15. --*/
  16. #include "halp.h"
  17. #include "pci.h"
  18. #include "pcip.h"
  19. #include "pcmp_nt.inc"
  20. volatile ULONG PCIType2Stall;
  21. extern struct HalpMpInfo HalpMpInfoTable;
  22. extern BOOLEAN HalpHackNoPciMotion;
  23. extern BOOLEAN HalpDoingCrashDump;
  24. VOID
  25. HalpPCIPin2MPSLine (
  26. IN PBUS_HANDLER BusHandler,
  27. IN PBUS_HANDLER RootHandler,
  28. IN PCI_SLOT_NUMBER SlotNumber,
  29. IN PPCI_COMMON_CONFIG PciData
  30. );
  31. VOID
  32. HalpPCIBridgedPin2Line (
  33. IN PBUS_HANDLER BusHandler,
  34. IN PBUS_HANDLER RootHandler,
  35. IN PCI_SLOT_NUMBER SlotNumber,
  36. IN PPCI_COMMON_CONFIG PciData
  37. );
  38. VOID
  39. HalpPCIMPSLine2Pin (
  40. IN PBUS_HANDLER BusHandler,
  41. IN PBUS_HANDLER RootHandler,
  42. IN PCI_SLOT_NUMBER SlotNumber,
  43. IN PPCI_COMMON_CONFIG PciNewData,
  44. IN PPCI_COMMON_CONFIG PciOldData
  45. );
  46. NTSTATUS
  47. HalpGetFixedPCIMPSLine (
  48. IN PBUS_HANDLER BusHandler,
  49. IN PBUS_HANDLER RootHandler,
  50. IN PCI_SLOT_NUMBER PciSlot,
  51. OUT PSUPPORTED_RANGE *Interrupt
  52. );
  53. BOOLEAN
  54. HalpMPSBusId2NtBusId (
  55. IN UCHAR ApicBusId,
  56. OUT PPCMPBUSTRANS *ppBusType,
  57. OUT PULONG BusNo
  58. );
  59. ULONG
  60. HalpGetPCIBridgedInterruptVector (
  61. IN PBUS_HANDLER BusHandler,
  62. IN PBUS_HANDLER RootHandler,
  63. IN ULONG InterruptLevel,
  64. IN ULONG InterruptVector,
  65. OUT PKIRQL Irql,
  66. OUT PKAFFINITY Affinity
  67. );
  68. #ifdef ALLOC_PRAGMA
  69. #pragma alloc_text(INIT, HalpSubclassPCISupport)
  70. #pragma alloc_text(INIT, HalpMPSPCIChildren)
  71. #pragma alloc_text(PAGE, HalpGetFixedPCIMPSLine)
  72. #pragma alloc_text(PAGE, HalpGetPCIBridgedInterruptVector)
  73. #pragma alloc_text(PAGE, HalpIrqTranslateRequirementsPci)
  74. #pragma alloc_text(PAGE, HalpIrqTranslateResourcesPci)
  75. #endif
  76. //
  77. // Turn PCI pin to inti via the MPS spec
  78. // (note: pin must be non-zero)
  79. //
  80. #define PCIPin2Int(Slot,Pin) \
  81. ((((Slot.u.bits.DeviceNumber << 2) | (Pin-1)) != 0) ? \
  82. (Slot.u.bits.DeviceNumber << 2) | (Pin-1) : 0x80);
  83. #define PCIInt2Pin(interrupt) \
  84. ((interrupt & 0x3) + 1)
  85. #define PCIInt2Slot(interrupt) \
  86. ((interrupt & 0x7f) >> 2)
  87. VOID
  88. HalpSubclassPCISupport (
  89. PBUS_HANDLER Handler,
  90. ULONG HwType
  91. )
  92. {
  93. ULONG d, pin, i, MaxDeviceFound;
  94. PPCIPBUSDATA BusData;
  95. PCI_SLOT_NUMBER SlotNumber;
  96. BOOLEAN DeviceFound;
  97. BusData = (PPCIPBUSDATA) Handler->BusData;
  98. SlotNumber.u.bits.Reserved = 0;
  99. MaxDeviceFound = 0;
  100. DeviceFound = FALSE;
  101. #ifdef P6_WORKAROUNDS
  102. BusData->MaxDevice = 0x10;
  103. #endif
  104. //
  105. // Find any PCI bus which has MPS inti information, and provide
  106. // MPS handlers for dealing with it.
  107. //
  108. // Note: we assume that any PCI bus with any MPS information
  109. // is totally defined. (Ie, it's not possible to connect some PCI
  110. // interrupts on a given PCI bus via the MPS table without connecting
  111. // them all).
  112. //
  113. // Note2: we assume that PCI buses are listed in the MPS table in
  114. // the same order the BUS declares them. (Ie, the first listed
  115. // PCI bus in the MPS table is assumed to match physical PCI bus 0, etc).
  116. //
  117. //
  118. for (d=0; d < PCI_MAX_DEVICES; d++) {
  119. SlotNumber.u.bits.DeviceNumber = d;
  120. SlotNumber.u.bits.FunctionNumber = 0;
  121. for (pin=1; pin <= 4; pin++) {
  122. i = PCIPin2Int (SlotNumber, pin);
  123. if (HalpGetApicInterruptDesc(PCIBus, Handler->BusNumber, i, (PUSHORT)&i)) {
  124. MaxDeviceFound = d;
  125. DeviceFound = TRUE;
  126. }
  127. }
  128. }
  129. if (DeviceFound) {
  130. //
  131. // There are Inti mapping for interrupts on this PCI bus
  132. // Change handlers for this bus to MPS versions
  133. //
  134. Handler->GetInterruptVector = HalpGetSystemInterruptVector;
  135. BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIPin2MPSLine;
  136. BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIMPSLine2Pin;
  137. BusData->GetIrqRange = HalpGetFixedPCIMPSLine;
  138. if (BusData->MaxDevice < MaxDeviceFound) {
  139. BusData->MaxDevice = MaxDeviceFound;
  140. }
  141. } else {
  142. //
  143. // Not all PCI machines are eisa machine, since the PCI interrupts
  144. // aren't coming into IoApics go check the Eisa ELCR for broken
  145. // behaviour.
  146. //
  147. HalpCheckELCR ();
  148. }
  149. }
  150. VOID
  151. HalpMPSPCIChildren (
  152. VOID
  153. )
  154. /*++
  155. Any PCI buses which don't have declared interrupt mappings and
  156. are children of parent buses that have MPS interrupt mappings
  157. need to inherit interrupts from parents via PCI barbar pole
  158. algorithm
  159. --*/
  160. {
  161. PBUS_HANDLER Handler, Parent;
  162. PPCIPBUSDATA BusData, ParentData;
  163. ULONG b, cnt, i, id;
  164. PCI_SLOT_NUMBER SlotNumber;
  165. struct {
  166. union {
  167. UCHAR map[4];
  168. ULONG all;
  169. } u;
  170. } Interrupt, Hold;
  171. //
  172. // Lookup each PCI bus in the system
  173. //
  174. for (b=0; Handler = HaliHandlerForBus(PCIBus, b); b++) {
  175. BusData = (PPCIPBUSDATA) Handler->BusData;
  176. if (BusData->CommonData.Pin2Line == (PciPin2Line) HalpPCIPin2MPSLine) {
  177. //
  178. // This bus already has mappings
  179. //
  180. continue;
  181. }
  182. //
  183. // Check if any parent has PCI MPS interrupt mappings
  184. //
  185. Interrupt.u.map[0] = 1;
  186. Interrupt.u.map[1] = 2;
  187. Interrupt.u.map[2] = 3;
  188. Interrupt.u.map[3] = 4;
  189. Parent = Handler;
  190. SlotNumber = BusData->CommonData.ParentSlot;
  191. while (Parent = Parent->ParentHandler) {
  192. if (Parent->InterfaceType != PCIBus) {
  193. break;
  194. }
  195. //
  196. // Check if parent has MPS interrupt mappings
  197. //
  198. ParentData = (PPCIPBUSDATA) Parent->BusData;
  199. if (ParentData->CommonData.Pin2Line == (PciPin2Line) HalpPCIPin2MPSLine) {
  200. //
  201. // This parent has MPS interrupt mappings. Set the device
  202. // to get its InterruptLine values from the buses SwizzleIn table
  203. //
  204. Handler->GetInterruptVector = HalpGetPCIBridgedInterruptVector;
  205. BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIBridgedPin2Line;
  206. BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIMPSLine2Pin;
  207. for (i=0; i < 4; i++) {
  208. id = PCIPin2Int (SlotNumber, Interrupt.u.map[i]);
  209. BusData->SwizzleIn[i] = (UCHAR) id;
  210. }
  211. break;
  212. }
  213. //
  214. // Apply interrupt mapping
  215. //
  216. i = SlotNumber.u.bits.DeviceNumber;
  217. Hold.u.map[0] = Interrupt.u.map[(i + 0) & 3];
  218. Hold.u.map[1] = Interrupt.u.map[(i + 1) & 3];
  219. Hold.u.map[2] = Interrupt.u.map[(i + 2) & 3];
  220. Hold.u.map[3] = Interrupt.u.map[(i + 3) & 3];
  221. Interrupt.u.all = Hold.u.all;
  222. SlotNumber = ParentData->CommonData.ParentSlot;
  223. }
  224. }
  225. }
  226. VOID
  227. HalpPCIPin2MPSLine (
  228. IN PBUS_HANDLER BusHandler,
  229. IN PBUS_HANDLER RootHandler,
  230. IN PCI_SLOT_NUMBER SlotNumber,
  231. IN PPCI_COMMON_CONFIG PciData
  232. )
  233. /*++
  234. --*/
  235. {
  236. if (!PciData->u.type0.InterruptPin) {
  237. return ;
  238. }
  239. PciData->u.type0.InterruptLine = (UCHAR)
  240. PCIPin2Int (SlotNumber, PciData->u.type0.InterruptPin);
  241. }
  242. VOID
  243. HalpPCIBridgedPin2Line (
  244. IN PBUS_HANDLER BusHandler,
  245. IN PBUS_HANDLER RootHandler,
  246. IN PCI_SLOT_NUMBER SlotNumber,
  247. IN PPCI_COMMON_CONFIG PciData
  248. )
  249. /*++
  250. This function maps the device's InterruptPin to an InterruptLine
  251. value.
  252. test function particular to dec pci-pci bridge card
  253. --*/
  254. {
  255. PPCIPBUSDATA BusData;
  256. ULONG i;
  257. if (!PciData->u.type0.InterruptPin) {
  258. return ;
  259. }
  260. //
  261. // Convert slot Pin into Bus INTA-D.
  262. //
  263. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  264. i = (PciData->u.type0.InterruptPin +
  265. SlotNumber.u.bits.DeviceNumber - 1) & 3;
  266. PciData->u.type0.InterruptLine = BusData->SwizzleIn[i];
  267. }
  268. VOID
  269. HalpPCIMPSLine2Pin (
  270. IN PBUS_HANDLER BusHandler,
  271. IN PBUS_HANDLER RootHandler,
  272. IN PCI_SLOT_NUMBER SlotNumber,
  273. IN PPCI_COMMON_CONFIG PciNewData,
  274. IN PPCI_COMMON_CONFIG PciOldData
  275. )
  276. /*++
  277. --*/
  278. {
  279. //
  280. // PCI interrupts described in the MPS table are directly
  281. // connected to APIC Inti pins.
  282. // Do nothing...
  283. //
  284. }
  285. ULONG
  286. HalpGetPCIBridgedInterruptVector (
  287. IN PBUS_HANDLER BusHandler,
  288. IN PBUS_HANDLER RootHandler,
  289. IN ULONG InterruptLevel,
  290. IN ULONG InterruptVector,
  291. OUT PKIRQL Irql,
  292. OUT PKAFFINITY Affinity
  293. )
  294. {
  295. //
  296. // Get parent's translation
  297. //
  298. return BusHandler->ParentHandler->GetInterruptVector (
  299. BusHandler->ParentHandler,
  300. BusHandler->ParentHandler,
  301. InterruptLevel,
  302. InterruptVector,
  303. Irql,
  304. Affinity
  305. );
  306. }
  307. NTSTATUS
  308. HalpGetFixedPCIMPSLine (
  309. IN PBUS_HANDLER BusHandler,
  310. IN PBUS_HANDLER RootHandler,
  311. IN PCI_SLOT_NUMBER PciSlot,
  312. OUT PSUPPORTED_RANGE *Interrupt
  313. )
  314. {
  315. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  316. PPCI_COMMON_CONFIG PciData;
  317. PciData = (PPCI_COMMON_CONFIG) buffer;
  318. HalGetBusData (
  319. PCIConfiguration,
  320. BusHandler->BusNumber,
  321. PciSlot.u.AsULONG,
  322. PciData,
  323. PCI_COMMON_HDR_LENGTH
  324. );
  325. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  326. return STATUS_UNSUCCESSFUL;
  327. }
  328. *Interrupt = ExAllocatePoolWithTag(PagedPool,
  329. sizeof(SUPPORTED_RANGE),
  330. HAL_POOL_TAG);
  331. if (!*Interrupt) {
  332. return STATUS_INSUFFICIENT_RESOURCES;
  333. }
  334. RtlZeroMemory (*Interrupt, sizeof (SUPPORTED_RANGE));
  335. (*Interrupt)->Base = 1; // base = 1, limit = 0
  336. if (!PciData->u.type0.InterruptPin) {
  337. return STATUS_SUCCESS;
  338. }
  339. (*Interrupt)->Base = PciData->u.type0.InterruptLine;
  340. (*Interrupt)->Limit = PciData->u.type0.InterruptLine;
  341. return STATUS_SUCCESS;
  342. }
  343. VOID
  344. HalpPCIType2TruelyBogus (
  345. ULONG Context
  346. )
  347. /*++
  348. This is a piece of work.
  349. Type 2 of the PCI configuration space is bad. Bad as in to
  350. access it one needs to block out 4K of I/O space.
  351. Video cards are bad. The only decode the bits in an I/O address
  352. they feel like. Which means one can't block out a 4K range
  353. or these video cards don't work.
  354. Combinding all these bad things onto an MP machine is even
  355. more (sic) bad. The I/O ports can't be mapped out unless
  356. all processors stop accessing I/O space.
  357. Allowing access to device specific PCI control space during
  358. an interrupt isn't bad, (although accessing it on every interrupt
  359. is ineficent) but this cause the added grief that all processors
  360. need to obtained at above all device interrupts.
  361. And... naturally we have an MP machine with a wired down
  362. bad video controller, stuck in the bad Type 2 configuration
  363. space (when we told everyone about type 1!). So the "fix"
  364. is to HALT ALL processors for the duration of reading/writing
  365. ANY part of PCI configuration space such that we can be sure
  366. no processor is touching the 4k I/O ports which get mapped out
  367. of existance when type2 accesses occur.
  368. ----
  369. While I'm flaming. Hooking PCI interrupts ontop of ISA interrupts
  370. in a machine which has the potential to have 240+ interrupts
  371. sources (read APIC) is bad.
  372. --*/
  373. {
  374. // oh - let's just wait here and not pay attention to that other processor
  375. // guy whom is punching holes into the I/O space
  376. while (PCIType2Stall == Context) {
  377. HalpPollForBroadcast ();
  378. }
  379. }
  380. VOID
  381. HalpPCIAcquireType2Lock (
  382. PKSPIN_LOCK SpinLock,
  383. PKIRQL OldIrql
  384. )
  385. {
  386. if (!HalpDoingCrashDump) {
  387. *OldIrql = KfRaiseIrql (CLOCK2_LEVEL-1);
  388. KiAcquireSpinLock (SpinLock);
  389. //
  390. // Interrupt all other processors and have them wait until the
  391. // barrier is cleared. (HalpGenericCall waits until the target
  392. // processors have been interrupted before returning)
  393. //
  394. HalpGenericCall (
  395. HalpPCIType2TruelyBogus,
  396. PCIType2Stall,
  397. HalpActiveProcessors & ~KeGetCurrentPrcb()->SetMember
  398. );
  399. } else {
  400. *OldIrql = HIGH_LEVEL;
  401. }
  402. }
  403. VOID
  404. HalpPCIReleaseType2Lock (
  405. PKSPIN_LOCK SpinLock,
  406. KIRQL Irql
  407. )
  408. {
  409. if (!HalpDoingCrashDump) {
  410. PCIType2Stall++; // clear barrier
  411. KiReleaseSpinLock (SpinLock);
  412. KfLowerIrql (Irql);
  413. }
  414. }
  415. NTSTATUS
  416. HalpIrqTranslateRequirementsPci(
  417. IN PVOID Context,
  418. IN PIO_RESOURCE_DESCRIPTOR Source,
  419. IN PDEVICE_OBJECT PhysicalDeviceObject,
  420. OUT PULONG TargetCount,
  421. OUT PIO_RESOURCE_DESCRIPTOR *Target
  422. )
  423. /*++
  424. Routine Description:
  425. This function translates IRQ resource requirements from
  426. a PCI bus that is described in the MPS table to the
  427. root.
  428. Arguments:
  429. Context - must hold the MPS bus number of this PCI bus
  430. Return Value:
  431. STATUS_SUCCESS, so long as we can allocate the necessary
  432. memory
  433. --*/
  434. #define USE_INT_LINE_REGISTER_TOKEN 0xffffffff
  435. {
  436. PIO_RESOURCE_DESCRIPTOR target;
  437. PPCMPBUSTRANS busType;
  438. PBUS_HANDLER busHandler;
  439. NTSTATUS status;
  440. UCHAR mpsBusNumber;
  441. ULONG devPciBus, bridgePciBus;
  442. PCI_SLOT_NUMBER pciSlot;
  443. UCHAR interruptLine, interruptPin;
  444. UCHAR dummy;
  445. PDEVICE_OBJECT parentPdo;
  446. ROUTING_TOKEN routingToken;
  447. KIRQL irql;
  448. KAFFINITY affinity;
  449. ULONG busVector;
  450. ULONG vector;
  451. BOOLEAN success;
  452. PAGED_CODE();
  453. ASSERT(Source->Type == CmResourceTypeInterrupt);
  454. ASSERT(PciIrqRoutingInterface.GetInterruptRouting);
  455. devPciBus = (ULONG)-1;
  456. pciSlot.u.AsULONG = (ULONG)-1;
  457. status = PciIrqRoutingInterface.GetInterruptRouting(
  458. PhysicalDeviceObject,
  459. &devPciBus,
  460. &pciSlot.u.AsULONG,
  461. &interruptLine,
  462. &interruptPin,
  463. &dummy,
  464. &dummy,
  465. &parentPdo,
  466. &routingToken,
  467. &dummy
  468. );
  469. if (!NT_SUCCESS(status)) {
  470. //
  471. // We should never get here. If we do, we have a bug.
  472. // It means that we're trying to arbitrate PCI IRQs for
  473. // a non-PCI device.
  474. //
  475. #if DBG
  476. DbgPrint("HAL: The PnP manager passed a non-PCI PDO to the PCI IRQ translator (%x)\n",
  477. PhysicalDeviceObject);
  478. #endif
  479. *TargetCount = 0;
  480. return STATUS_INVALID_PARAMETER_3;
  481. }
  482. target = ExAllocatePoolWithTag(PagedPool,
  483. sizeof(IO_RESOURCE_DESCRIPTOR),
  484. HAL_POOL_TAG);
  485. if (!target) {
  486. return STATUS_INSUFFICIENT_RESOURCES;
  487. }
  488. //
  489. // Copy the source to fill in all the relevant fields.
  490. //
  491. *target = *Source;
  492. if (Context == (PVOID)USE_INT_LINE_REGISTER_TOKEN) {
  493. //
  494. // This bus's vectors aren't described in
  495. // the MPS table. So just use the Int Line
  496. // register.
  497. //
  498. busVector = interruptLine;
  499. busHandler = HaliHandlerForBus(Isa, 0);
  500. } else {
  501. mpsBusNumber = (UCHAR)Context;
  502. success = HalpMPSBusId2NtBusId(mpsBusNumber,
  503. &busType,
  504. &bridgePciBus);
  505. if (!success) {
  506. ExFreePool(target);
  507. return STATUS_UNSUCCESSFUL;
  508. }
  509. //
  510. // Start with the assumption that the incoming
  511. // resources will contain the proper MPS-style
  512. // interrupt vector. This will be guaranteed
  513. // to be true if some previous translation has
  514. // been done on these resources. And it might
  515. // be true otherwise.
  516. //
  517. busVector = Source->u.Interrupt.MinimumVector;
  518. if (bridgePciBus == devPciBus) {
  519. //
  520. // If this device sits on the bus for which
  521. // this translator has been ejected, we can
  522. // do better than to assume the incoming
  523. // resources are clever.
  524. //
  525. busVector = PCIPin2Int(pciSlot, interruptPin);
  526. }
  527. //
  528. // Find the PCI bus that corresponds to this MPS bus.
  529. //
  530. ASSERT(busType->NtType == PCIBus);
  531. //
  532. // TEMPTEMP Use bus handlers for now.
  533. //
  534. busHandler = HaliHandlerForBus(PCIBus, devPciBus);
  535. }
  536. vector = busHandler->GetInterruptVector(busHandler,
  537. busHandler,
  538. busVector,
  539. busVector,
  540. &irql,
  541. &affinity);
  542. if (vector == 0) {
  543. #if DBG
  544. DbgPrint("\nHAL: PCI Device 0x%02x, Func. 0x%x on bus 0x%x is not in the MPS table.\n *** Note to WHQL: Fail this machine. ***\n\n",
  545. pciSlot.u.bits.DeviceNumber,
  546. pciSlot.u.bits.FunctionNumber,
  547. devPciBus);
  548. #endif
  549. ExFreePool(target);
  550. *TargetCount = 0;
  551. return STATUS_PNP_BAD_MPS_TABLE;
  552. } else {
  553. target->u.Interrupt.MinimumVector = vector;
  554. target->u.Interrupt.MaximumVector = vector;
  555. *TargetCount = 1;
  556. *Target = target;
  557. }
  558. return STATUS_TRANSLATION_COMPLETE;
  559. }
  560. NTSTATUS
  561. HalpIrqTranslateResourcesPci(
  562. IN PVOID Context,
  563. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  564. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  565. IN ULONG AlternativesCount, OPTIONAL
  566. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  567. IN PDEVICE_OBJECT PhysicalDeviceObject,
  568. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  569. )
  570. /*++
  571. Routine Description:
  572. This function translates IRQ resources between the
  573. IDT and PCI busses that are described in the MPS
  574. tables. The translation can go in either direction.
  575. Arguments:
  576. Context - Must hold the slot number of the bridge in
  577. the lower sixteen bits. Must hold the
  578. the bridge's primary bus number in the
  579. upper sixteen bits.
  580. Return Value:
  581. status
  582. --*/
  583. {
  584. PPCMPBUSTRANS busType;
  585. PBUS_HANDLER busHandler;
  586. UCHAR mpsBusNumber = (UCHAR)Context;
  587. ULONG devPciBus, bridgePciBus;
  588. KIRQL irql;
  589. KAFFINITY affinity;
  590. ULONG vector;
  591. ULONG busVector;
  592. NTSTATUS status;
  593. PCI_SLOT_NUMBER pciSlot;
  594. UCHAR interruptLine;
  595. UCHAR interruptPin;
  596. UCHAR dummy;
  597. PDEVICE_OBJECT parentPdo;
  598. ROUTING_TOKEN routingToken;
  599. BOOLEAN useAlternatives = FALSE;
  600. BOOLEAN foundBus = FALSE;
  601. ASSERT(Source->Type = CmResourceTypeInterrupt);
  602. ASSERT(PciIrqRoutingInterface.GetInterruptRouting);
  603. *Target = *Source;
  604. devPciBus = (ULONG)-1;
  605. pciSlot.u.AsULONG = (ULONG)-1;
  606. status = PciIrqRoutingInterface.GetInterruptRouting(
  607. PhysicalDeviceObject,
  608. &devPciBus,
  609. &pciSlot.u.AsULONG,
  610. &interruptLine,
  611. &interruptPin,
  612. &dummy,
  613. &dummy,
  614. &parentPdo,
  615. &routingToken,
  616. &dummy
  617. );
  618. ASSERT(NT_SUCCESS(status));
  619. switch (Direction) {
  620. case TranslateChildToParent:
  621. if (Context == (PVOID)USE_INT_LINE_REGISTER_TOKEN) {
  622. //
  623. // This bus's vectors aren't described in
  624. // the MPS table. So just use the Int Line
  625. // register.
  626. //
  627. interruptLine = (UCHAR)Source->u.Interrupt.Vector;
  628. busVector = interruptLine;
  629. busHandler = HaliHandlerForBus(Isa, 0);
  630. } else {
  631. //
  632. // Find the PCI bus that corresponds to this MPS bus.
  633. //
  634. mpsBusNumber = (UCHAR)Context;
  635. foundBus = HalpMPSBusId2NtBusId(mpsBusNumber,
  636. &busType,
  637. &bridgePciBus);
  638. if (!foundBus) {
  639. return STATUS_INVALID_PARAMETER_1;
  640. }
  641. ASSERT(busType->NtType == PCIBus);
  642. //
  643. // Start with the assumption that the incoming
  644. // resources will contain the proper MPS-style
  645. // interrupt vector. This will be guaranteed
  646. // to be true if some previous translation has
  647. // been done on these resources. And it might
  648. // be true otherwise.
  649. //
  650. busVector = Source->u.Interrupt.Vector;
  651. if (devPciBus == bridgePciBus) {
  652. //
  653. // If this device sits on the bus for which
  654. // this translator has been ejected, we can
  655. // do better than to assume the incoming
  656. // resources are clever.
  657. //
  658. busVector = PCIPin2Int(pciSlot, interruptPin);
  659. }
  660. //
  661. // TEMPTEMP Use bus handlers for now.
  662. //
  663. busHandler = HaliHandlerForBus(PCIBus, devPciBus);
  664. }
  665. vector = busHandler->GetInterruptVector(busHandler,
  666. busHandler,
  667. busVector,
  668. busVector,
  669. &irql,
  670. &affinity);
  671. ASSERT(vector != 0);
  672. Target->u.Interrupt.Vector = vector;
  673. Target->u.Interrupt.Level = irql;
  674. Target->u.Interrupt.Affinity = affinity;
  675. return STATUS_TRANSLATION_COMPLETE;
  676. case TranslateParentToChild:
  677. //
  678. // There is a problem here. We are translating from the
  679. // context of the IDT down to the context of a specific
  680. // PCI bus. (One decribed in the MPS tables.) This may
  681. // not, however, be the bus that PhysicalDeviceObject's
  682. // hardware lives on. There may be plug-in PCI to PCI
  683. // bridges between this bus and the device.
  684. //
  685. // But we are not being asked the question "What is the
  686. // bus-relative interrupt with respect to the bus that
  687. // the device lives on?" We are being asked "What is the
  688. // bus-relative interrupt once that interrupt passes through
  689. // all those briges and makes it up to this bus?" This
  690. // turns out to be a much harder question.
  691. //
  692. // There are really two cases:
  693. //
  694. // 1) There are no bridges between this bus and the device.
  695. //
  696. // This is easy. We answer the first question above and
  697. // we're done. (This information will actually get used.
  698. // it will appear in the start device IRP and the device
  699. // manager.)
  700. //
  701. // 2) There are bridges.
  702. //
  703. // This is the hard case. And the information, were we
  704. // actually going to bother to dig it up, would get thrown
  705. // away. Nobody actually cares what the answer is. The
  706. // only place it is going is the "Source" argument to
  707. // the next translator. And the translator for PCI to PCI
  708. // bridges won't end up using it.
  709. //
  710. // So we punt here and just answer the first question.
  711. //
  712. if (Context == (PVOID)USE_INT_LINE_REGISTER_TOKEN) {
  713. Target->u.Interrupt.Vector = interruptLine;
  714. } else {
  715. mpsBusNumber = (UCHAR)Context;
  716. if (HalpMPSBusId2NtBusId(mpsBusNumber,
  717. &busType,
  718. &bridgePciBus)) {
  719. if (devPciBus == bridgePciBus) {
  720. Target->u.Interrupt.Vector = PCIPin2Int(pciSlot, interruptPin);
  721. } else {
  722. useAlternatives = TRUE;
  723. }
  724. } else {
  725. useAlternatives = TRUE;
  726. }
  727. }
  728. if (useAlternatives) {
  729. //
  730. // Setup the default case. We assume that the I/O
  731. // res list had the right answer.
  732. //
  733. ASSERT(AlternativesCount == 1);
  734. ASSERT(Alternatives[0].Type == CmResourceTypeInterrupt);
  735. Target->u.Interrupt.Vector = Alternatives[0].u.Interrupt.MinimumVector;
  736. }
  737. Target->u.Interrupt.Level = Target->u.Interrupt.Vector;
  738. Target->u.Interrupt.Affinity = 0xffffffff;
  739. return STATUS_SUCCESS;
  740. }
  741. return STATUS_INVALID_PARAMETER_3;
  742. }