pcienumeratorsupport.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,385 行 · 第 1/3 页

C
1,385
字号
}

PCI_IO_DEVICE *
GatherPPBInfo (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,
  IN PCI_TYPE00                       *Pci,
  UINT8                               Bus,
  UINT8                               Device,
  UINT8                               Func
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
{
  PCI_IO_DEVICE                   *PciIoDevice;
  EFI_STATUS                      Status;
  UINT32                          Value;
  EFI_PCI_IO_PROTOCOL             *PciIo;
  UINT8                           Temp;

  PciIoDevice = CreatePciIoDevice (
                  PciRootBridgeIo,
                  Pci,
                  Bus,
                  Device,
                  Func
                  );

  if (!PciIoDevice) {
    return NULL;
  }
  
  if (gFullEnumeration) {
    PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);

    //
    // Initalize the bridge control register
    //
    PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
  }

  PciIo = &PciIoDevice->PciIo;

  //
  // Test whether it support 32 decode or not
  //
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);

  if (Value) {
    if (Value & 0x01) {
      PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
    } else {
      PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
    }
  }

  Status = BarExisted (
            PciIoDevice,
            0x24,
            NULL,
            NULL
            );

  //
  // test if it supports 64 memory or not
  //
  if (!EFI_ERROR (Status)) {

    Status = BarExisted (
              PciIoDevice,
              0x28,
              NULL,
              NULL
              );

    if (!EFI_ERROR (Status)) {
      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
    } else {
      PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
    }
  }

  //
  // Memory 32 code is required for ppb
  //
  PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;

  return PciIoDevice;
}

PCI_IO_DEVICE *
GatherP2CInfo (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,
  IN PCI_TYPE00                       *Pci,
  UINT8                               Bus,
  UINT8                               Device,
  UINT8                               Func
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
{
  PCI_IO_DEVICE         *PciIoDevice;
  
  PciIoDevice = CreatePciIoDevice (
                  PciRootBridgeIo,
                  Pci,
                  Bus,
                  Device,
                  Func
                  );

  if (!PciIoDevice) {
    return NULL;
  }

  if (gFullEnumeration) {
    PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);

    //
    // Initalize the bridge control register
    //
    PciDisableBridgeControlRegister (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);

  }
  //
  // P2C only has one bar that is in 0x10
  //
  PciParseBar(PciIoDevice, 0x10, 0);
  
  PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED  |
                         EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
                         EFI_BRIDGE_IO32_DECODE_SUPPORTED;

  return PciIoDevice;
}

EFI_DEVICE_PATH_PROTOCOL *
CreatePciDevicePath (
  IN  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
  IN  PCI_IO_DEVICE            *PciIoDevice
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
{

  PCI_DEVICE_PATH PciNode;

  //
  // Create PCI device path
  //
  PciNode.Header.Type     = HARDWARE_DEVICE_PATH;
  PciNode.Header.SubType  = HW_PCI_DP;
  SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));

  PciNode.Device          = PciIoDevice->DeviceNumber;
  PciNode.Function        = PciIoDevice->FunctionNumber;
  PciIoDevice->DevicePath = EfiAppendDevicePathNode (ParentDevicePath, &PciNode.Header);

  return PciIoDevice->DevicePath;
}

EFI_STATUS
BarExisted (
  IN PCI_IO_DEVICE *PciIoDevice,
  IN UINTN         Offset,
  OUT UINT32       *BarLengthValue,
  OUT UINT32       *OriginalBarValue
  )
/*++

Routine Description:

  Check the bar is existed or not.

Arguments:

  PciIoDevice       - A pointer to the PCI_IO_DEVICE.
  Offset            - The offset.
  BarLengthValue    - The bar length value.
  OriginalBarValue  - The original bar value.

Returns:

  EFI_NOT_FOUND     - The bar don't exist.
  EFI_SUCCESS       - The bar exist.

--*/
{
  EFI_PCI_IO_PROTOCOL *PciIo;
  UINT32              OriginalValue;
  UINT32              Value;
  EFI_TPL             OldTpl;

  PciIo = &PciIoDevice->PciIo;

  //
  // Preserve the original value
  //

  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);

  //
  // Raise TPL to high level to disable timer interrupt while the BAR is probed
  //
  OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);

  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);

  //
  // Write back the original value
  //
  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);

  //
  // Restore TPL to its original level
  //
  gBS->RestoreTPL (OldTpl);

  if (BarLengthValue != NULL) {
    *BarLengthValue = Value;
  }

  if (OriginalBarValue != NULL) {
    *OriginalBarValue = OriginalValue;
  }

  if (Value == 0) {
    return EFI_NOT_FOUND;
  } else {
    return EFI_SUCCESS;
  }
}


EFI_STATUS
DetermineDeviceAttribute (
  IN PCI_IO_DEVICE                      *PciIoDevice
  )
/*++

Routine Description:
 
  Determine the related attributes of all devices under a Root Bridge

Arguments:

Returns:

  None

--*/
{
  UINT16          Command;
  UINT16          BridgeControl;

  Command = 0;

  PciIoDevice->Supports |= EFI_PCI_DEVICE_ENABLE;
  PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;

  if (IS_PCI_VGA (&(PciIoDevice->Pci))){

    //
    // If the device is VGA, VGA related Attributes are supported
    //
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO ;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY   ;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_IO    ;
  }

  if(IS_ISA_BRIDGE(&(PciIoDevice->Pci)) || IS_INTEL_ISA_BRIDGE(&(PciIoDevice->Pci))) {
    //
    // If the devie is a ISA Bridge, set the two attributes
    //
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
  }

  if (IS_PCI_GFX (&(PciIoDevice->Pci))) {

    //
    // If the device is GFX, then only set the EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
    // attribute
    //
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO    ;
  }


  //
  // If the device is IDE, IDE related attributes are supported
  //
  if (IS_PCI_IDE (&(PciIoDevice->Pci))) {
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO  ;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO  ;
  }

  PciReadCommandRegister(PciIoDevice, &Command);

  
  if (Command & EFI_PCI_COMMAND_IO_SPACE) {
    PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
  }

  if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {
    PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
  }

  if (Command & EFI_PCI_COMMAND_BUS_MASTER) {
    PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
  }

  if (IS_PCI_BRIDGE (&(PciIoDevice->Pci)) || 
      IS_CARDBUS_BRIDGE (&(PciIoDevice->Pci))){

    //
    // If it is a PPB, read the Bridge Control Register to determine
    // the relevant attributes
    //
    BridgeControl = 0;
    PciReadBridgeControlRegister(PciIoDevice, &BridgeControl);

    //
    // Determine whether the ISA bit is set
    // If ISA Enable on Bridge is set, the PPB
    // will block forwarding 0x100-0x3ff for each 1KB in the 
    // first 64KB I/O range.
    //
    if (!BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) {
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
    } 

    //
    // Determine whether the VGA bit is set
    // If it is set, the bridge is set to decode VGA memory range
    // and palette register range
    //
    if (IS_PCI_VGA (&(PciIoDevice->Pci)) &&BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) {
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
    }

    //
    // if the palette snoop bit is set, then the brige is set to 
    // decode palette IO write
    //
    if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
    }
  } 

  return EFI_SUCCESS;
}

UINTN
PciParseBar (
  IN PCI_IO_DEVICE  *PciIoDevice,
  IN UINTN          Offset,
  IN UINTN          BarIndex
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
{
  UINT32      Value;
  UINT64      BarValue64;
  UINT32      OriginalValue;
  UINT32      Mask;
  UINT32      Data;
  UINT8       Index;
  EFI_STATUS  Status;

  OriginalValue = 0;
  Value         = 0;
  BarValue64    = 0;

  Status = BarExisted (
            PciIoDevice,
            Offset,
            &Value,
            &OriginalValue
            );

  if (EFI_ERROR (Status)) {
    PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
    PciIoDevice->PciBar[BarIndex].Length      = 0;
    PciIoDevice->PciBar[BarIndex].Alignment   = 0;

    //
    // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
    //
    PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
    return Offset + 4;
  }

  PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
  if (Value & 0x01) {
    //
    // Device I/Os
    //
    Mask = 0xfffffffc;

    if (Value & 0xFFFF0000) {
      //
      // It is a IO32 bar
      //
      PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo32;
      PciIoDevice->PciBar[BarIndex].Length    = ((~(Value & Mask)) + 1);
      PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;

    } else {
      //
      // It is a IO16 bar
      //
      PciIoDevice->PciBar[BarIndex].BarType   = PciBarTypeIo16;
      PciIoDevice->PciBar[BarIndex].Length    = 0x0000FFFF & ((~(Value & Mask)) + 1);
      PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;

    }
    //
    // Workaround. Some platforms inplement IO bar with 0 length
    // Need to treat it as no-bar
    //

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?