/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: NvPciLpcBridge.cs // // Notes: // // Driver for Low-Pin Count devices. These are a mix of control // registers for legacy and current devices. We currently use it to // reroute integrated peripheral interrupts. using System; using System.Collections; using System.Diagnostics; using Microsoft.Singularity.Drivers.Pci; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Io; using Microsoft.Singularity.Configuration; namespace Microsoft.Singularity.Drivers { // create the resource object for CTR to fill in [DriverCategory] [Signature("pci/ven_10de&dev_0050&cc_0601")] // nForce4 [Signature("pci/ven_10de&dev_0030&cc_0601")] // nForce4 Intel Edition [EnumeratesDevice("/pnp/PNP0103")] internal class NvPciLpcResources : DriverCategoryDeclaration { // Provide to unify creation. public static IDevice! DeviceCreate(IoConfig! config, string! name) { return new NvPciLpcBridge((PciDeviceConfig) config); } } public sealed class NvPciLpcBridge : IBusDevice { private const ushort PCI_VENDOR_NVIDIA = 0x10de; private const ushort PCI_DEVICE_NVIDIA_AMD_SATA0 = 0x0054; private const ushort PCI_DEVICE_NVIDIA_AMD_SATA1 = 0x0055; private const ushort PCI_DEVICE_NVIDIA_AMD_MCP04 = 0x0056; private const ushort PCI_DEVICE_NVIDIA_INTEL_SATA0 = 0x0036; private const ushort PCI_DEVICE_NVIDIA_INTEL_SATA1 = 0x003e; private const ushort PCI_DEVICE_NVIDIA_INTEL_MCP04 = 0x0030; private const int PCI_HPET_POINTER = 0x44; // Generic PCI interrupt remapping private const int PCI_INTERRUPT_MAPPING = 0x7c; private const int SATA0_DEVICE_7_ROLL = 24; // Secondary SATA0 IRQ private const int SATA1_DEVICE_8_ROLL = 20; // Secondary SATA1 IRQ private const int PCI_INTR_Z_ROLL = 12; private const int PCI_INTR_Y_ROLL = 8; private const int PCI_INTR_X_ROLL = 4; private const int PCI_INTR_W_ROLL = 0; private const uint PINT_SEL_DISABLE_IRQ = 0x0; private const uint PINT_SEL_APIC_IRQ17 = 0x1; private const uint PINT_SEL_APIC_IRQ18 = 0x2; private const uint PINT_SEL_IRQ3 = 0x3; private const uint PINT_SEL_IRQ4 = 0x4; private const uint PINT_SEL_IRQ5 = 0x5; private const uint PINT_SEL_IRQ6 = 0x6; private const uint PINT_SEL_IRQ7 = 0x7; private const uint PINT_SEL_APIC_IRQ16 = 0x8; private const uint PINT_SEL_IRQ9 = 0x9; private const uint PINT_SEL_IRQ10 = 0xa; private const uint PINT_SEL_IRQ11 = 0xb; private const uint PINT_SEL_IRQ12 = 0xc; private const uint PINT_SEL_APIC_IRQ19 = 0xd; private const uint PINT_SEL_IRQ14 = 0xe; private const uint PINT_SEL_IRQ15 = 0xf; // Integrate peripheral mapping private const int INTERNAL_IRQ0 = 0x80; private const int INTERNAL_IRQ0_SATA0_ROLL = 28; // Primary SATA private const int INTERNAL_IRQ0_SATA1_ROLL = 24; private const int INTERNAL_IRQ0_P2P_ROLL = 16; private const int INTERNAL_IRQ0_USB2_ROLL = 12; private const int INTERNAL_IRQ0_SMBUS_ROLL = 8; private const int INTERNAL_IRQ0_TCO_ROLL = 4; private const int INTERNAL_IRQ0_SCI_ROLL = 0; private const int INTERNAL_IRQ1 = 0x84; private const int INTERNAL_IRQ1_IDE1_ROLL = 28; private const int INTERNAL_IRQ1_IDE0_ROLL = 24; private const int INTERNAL_IRQ1_MCI_ROLL = 20; private const int INTERNAL_IRQ1_ACI_ROLL = 16; private const int INTERNAL_IRQ1_MAC_ROLL = 8; private const int INTERNAL_IRQ1_USB0_ROLL = 0; private const uint INTERNAL_SEL_DISABLE_IRQ = 0x0; private const uint INTERNAL_SEL_APIC_IRQ23 = 0x1; private const uint INTERNAL_SEL_APIC_IRQ22 = 0x2; private const uint INTERNAL_SEL_IRQ3 = 0x3; private const uint INTERNAL_SEL_IRQ4 = 0x4; private const uint INTERNAL_SEL_IRQ5 = 0x5; private const uint INTERNAL_SEL_IRQ6 = 0x6; private const uint INTERNAL_SEL_IRQ7 = 0x7; private const uint INTERNAL_SEL_APIC_IRQ20 = 0x8; private const uint INTERNAL_SEL_IRQ9 = 0x9; private const uint INTERNAL_SEL_IRQ10 = 0xa; private const uint INTERNAL_SEL_IRQ11 = 0xb; private const uint INTERNAL_SEL_IRQ12 = 0xc; private const uint INTERNAL_SEL_APIC_IRQ21 = 0xd; private const uint INTERNAL_SEL_IRQ14 = 0xe; private const uint INTERNAL_SEL_IRQ15 = 0xf; /////////////////////////////////////////////////////////////////////// PciDeviceConfig! config; internal NvPciLpcBridge(PciDeviceConfig! pciDeviceConfig) { config = pciDeviceConfig; } void IDevice.Initialize() { DebugStub.Print("NvPciLpc.Initialize (maxirq={0})\n", __arglist(IoSystem.GetMaximumIrq())); // Reroute NVidia fixed device resources on APIC system if (IoSystem.GetMaximumIrq() > 15) { ReroutePciInterrupts(); } } void IDevice.Finalize() { } private void SetRouteEntry(int register, int roll, uint value) { DebugStub.Print("NvPciLpc.SetRouteEntry(reg={0},rol={1},val={2})\n", __arglist(register, roll, value)); uint r = config.Read32(register) & ~(0x0fu << roll); r |= value << roll; config.Write32(register, r); } private void ReroutePciInterrupts() { PciEnumerator enumerator = PciEnumerator.GetEnumerator(null); ICollection! pciConfigs = enumerator.Enumerate().Values; foreach (PciConfig! pc in pciConfigs) { if (pc.VendorId == PCI_VENDOR_NVIDIA) { // NB - if there are multiple devices on the bus with the // same ID, we still break. Also note that the parameter // "1" indicates that this method wants to renumber the 1st // Irq in the IoConfig.DynamicRanges list, not the 1st // object. if ((pc.DeviceId == PCI_DEVICE_NVIDIA_AMD_MCP04 || pc.DeviceId == PCI_DEVICE_NVIDIA_INTEL_MCP04) && IoSystem.RequestRerouteIrq((!)pc.Id, 1, 23)) { SetRouteEntry(INTERNAL_IRQ1, INTERNAL_IRQ1_MAC_ROLL, INTERNAL_SEL_APIC_IRQ23); pc.SetInterrupt(23); } else if ((pc.DeviceId == PCI_DEVICE_NVIDIA_AMD_SATA0 || pc.DeviceId == PCI_DEVICE_NVIDIA_INTEL_SATA0) && IoSystem.RequestRerouteIrq((!)pc.Id, 1, 14)) { SetRouteEntry(INTERNAL_IRQ0, INTERNAL_IRQ0_SATA0_ROLL, INTERNAL_SEL_IRQ14); pc.SetInterrupt(14); // Map secondary same as primary SetRouteEntry(PCI_INTERRUPT_MAPPING, SATA0_DEVICE_7_ROLL, PINT_SEL_IRQ14); } else if ((pc.DeviceId == PCI_DEVICE_NVIDIA_AMD_SATA1 || pc.DeviceId == PCI_DEVICE_NVIDIA_INTEL_SATA1) && IoSystem.RequestRerouteIrq((!)pc.Id, 1, 15)) { SetRouteEntry(INTERNAL_IRQ0, INTERNAL_IRQ0_SATA1_ROLL, INTERNAL_SEL_IRQ15); pc.SetInterrupt(15); // Map secondary same as primary SetRouteEntry(PCI_INTERRUPT_MAPPING, SATA1_DEVICE_8_ROLL, PINT_SEL_IRQ15); } } } } public SortedList Enumerate() { SortedList devs = new SortedList(); uint hpetPointer = config.Read32(PCI_HPET_POINTER); if (hpetPointer != 0) { IoMemoryRange hpetMemory = new IoMemoryRange(hpetPointer, 0x1000, Access.ReadWrite); devs.Add("/hpet", new PnpConfig(new string[] { "/pnp/PNP0103" }, new IoRange [1] { hpetMemory } ) ); } #if NO // // XXX sgc compiler does not accept the following preferred // means of instantiating a PnpConfig object. It complains: // // NvPciLpc.cs(189,31): error CS1501: // No overload for method 'PnpConfig' takes '2' arguments // // which is bogus - there are two constructors that take two // arguments. They are both public and differ only in their // second argument. This is visible in PnpConfig.cs and in // the kernel ilasm. // ArrayList hpetResources = new ArrayList(); hpetResources.Add(hpetMemory); devs.Add("/hpet", new PnpConfig("/PNP0103", hpResources)); #endif return devs; } } }