singrdk/base/Kernel/Singularity.Drivers/NvPciLpc.cs

239 lines
10 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// 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;
}
}
}