arm64: Discover PCI from ACPI.

Change-Id: I2e40c8a531f319cce25363ab83d4d0fe9f8702d2
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5274
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: David Karoly <[email protected]>
Reviewed-by: Fredrik Holmqvist <[email protected]>
This commit is contained in:
milek7
2022-08-17 19:23:51 +00:00
committed by David Karoly
parent 2226d2eef7
commit 6bef283b50
9 changed files with 529 additions and 102 deletions
+110
View File
@@ -10,6 +10,7 @@
#define ACPI_RSDT_SIGNATURE "RSDT" #define ACPI_RSDT_SIGNATURE "RSDT"
#define ACPI_XSDT_SIGNATURE "XSDT" #define ACPI_XSDT_SIGNATURE "XSDT"
#define ACPI_MADT_SIGNATURE "APIC" #define ACPI_MADT_SIGNATURE "APIC"
#define ACPI_MCFG_SIGNATURE "MCFG"
#define ACPI_SPCR_SIGNATURE "SPCR" #define ACPI_SPCR_SIGNATURE "SPCR"
#define ACPI_LOCAL_APIC_ENABLED 0x01 #define ACPI_LOCAL_APIC_ENABLED 0x01
@@ -248,6 +249,21 @@ typedef struct acpi_gas {
uint64 address; uint64 address;
} _PACKED acpi_gas; } _PACKED acpi_gas;
typedef struct acpi_mcfg
{
acpi_descriptor_header header;
uint8 reserved[8];
} _PACKED acpi_mcfg;
typedef struct acpi_mcfg_allocation
{
uint64 address;
uint16 pci_segment;
uint8 start_bus_number;
uint8 end_bus_number;
uint32 reserved;
} _PACKED acpi_mcfg_allocation;
typedef struct acpi_spcr { typedef struct acpi_spcr {
acpi_descriptor_header header; acpi_descriptor_header header;
uint32 interface_type; uint32 interface_type;
@@ -293,6 +309,92 @@ typedef struct acpi_resource_fixed_memory32 {
uint32 address_length; uint32 address_length;
} _PACKED acpi_resource_fixed_memory32; } _PACKED acpi_resource_fixed_memory32;
typedef struct acpi_memory_attribute {
uint8 write_protect;
uint8 caching;
uint8 range_type;
uint8 translation;
} _PACKED acpi_memory_attribute;
typedef struct acpi_io_attribute {
uint8 range_type;
uint8 translation;
uint8 translation_type;
uint8 reserved1;
} _PACKED acpi_io_attribute;
typedef union acpi_resource_attribute {
acpi_memory_attribute mem;
acpi_io_attribute io;
uint8 type_specific;
} acpi_resource_attribute;
typedef struct acpi_address16_attribute {
uint16 granularity;
uint16 minimum;
uint16 maximum;
uint16 translation_offset;
uint16 address_length;
} _PACKED acpi_address16_attribute;
typedef struct acpi_address32_attribute {
uint32 granularity;
uint32 minimum;
uint32 maximum;
uint32 translation_offset;
uint32 address_length;
} _PACKED acpi_address32_attribute;
typedef struct acpi_address64_attribute {
uint64 granularity;
uint64 minimum;
uint64 maximum;
uint64 translation_offset;
uint64 address_length;
} _PACKED acpi_address64_attribute;
typedef struct acpi_resource_address {
uint8 resource_type;
uint8 producer_consumer;
uint8 decode;
uint8 minAddress_fixed;
uint8 maxAddress_fixed;
acpi_resource_attribute info;
} _PACKED acpi_resource_address;
typedef struct acpi_resource_address16 {
uint8 resource_type;
uint8 producer_consumer;
uint8 decode;
uint8 minAddress_fixed;
uint8 maxAddress_fixed;
acpi_resource_attribute info;
acpi_address16_attribute address;
acpi_resource_source resource_source;
} _PACKED acpi_resource_address16;
typedef struct acpi_resource_address32 {
uint8 resource_type;
uint8 producer_consumer;
uint8 decode;
uint8 minAddress_fixed;
uint8 maxAddress_fixed;
acpi_resource_attribute info;
acpi_address32_attribute address;
acpi_resource_source resource_source;
} _PACKED acpi_resource_address32;
typedef struct acpi_resource_address64 {
uint8 resource_type;
uint8 producer_consumer;
uint8 decode;
uint8 minAddress_fixed;
uint8 maxAddress_fixed;
acpi_resource_attribute info;
acpi_address64_attribute address;
acpi_resource_source resource_source;
} _PACKED acpi_resource_address64;
typedef struct acpi_resource_extended_irq { typedef struct acpi_resource_extended_irq {
uint8 producer_consumer; uint8 producer_consumer;
uint8 triggering; uint8 triggering;
@@ -306,7 +408,12 @@ typedef struct acpi_resource_extended_irq {
typedef union acpi_resource_data { typedef union acpi_resource_data {
acpi_resource_fixed_memory32 fixed_memory32; acpi_resource_fixed_memory32 fixed_memory32;
acpi_resource_address16 address16;
acpi_resource_address32 address32;
acpi_resource_address64 address64;
acpi_resource_extended_irq extended_irq; acpi_resource_extended_irq extended_irq;
acpi_resource_address address;
} acpi_resource_data; } acpi_resource_data;
typedef struct acpi_resource { typedef struct acpi_resource {
@@ -317,6 +424,9 @@ typedef struct acpi_resource {
enum { enum {
ACPI_RESOURCE_TYPE_FIXED_MEMORY32 = 10, ACPI_RESOURCE_TYPE_FIXED_MEMORY32 = 10,
ACPI_RESOURCE_TYPE_ADDRESS16 = 11,
ACPI_RESOURCE_TYPE_ADDRESS32 = 12,
ACPI_RESOURCE_TYPE_ADDRESS64 = 13,
ACPI_RESOURCE_TYPE_EXTENDED_IRQ = 15, ACPI_RESOURCE_TYPE_EXTENDED_IRQ = 15,
}; };
@@ -1,10 +1,15 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch $(TARGET_ARCH) ; SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch $(TARGET_ARCH) ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateKernelHeaders ;
UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ] UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ]
[ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ; [ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
KernelStaticLibrary pci_arch_bus_manager : KernelStaticLibrary pci_arch_bus_manager :
pci_controller.cpp pci_controller.cpp
pci_io.c pci_io.cpp
pci_ecam.cpp
; ;
@@ -1,27 +0,0 @@
/*
* Copyright 2009, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
//#include <arch_platform.h>
#include "pci_private.h"
status_t
pci_controller_init(void)
{
/* no support yet */
#warning ARM:WRITEME
return B_OK;
}
phys_addr_t
pci_ram_address(phys_addr_t physical_address_in_system_memory)
{
return physical_address_in_system_memory;
}
@@ -1,61 +0,0 @@
/*
* Copyright 2009, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include "pci_io.h"
#include "pci_private.h"
#warning ARM:WRITEME
status_t
pci_io_init()
{
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
/* NOT IMPLEMENTED */
return 0;
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
/* NOT IMPLEMENTED */
}
uint16
pci_read_io_16(int mapped_io_addr)
{
/* NOT IMPLEMENTED */
return 0;
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
/* NOT IMPLEMENTED */
}
uint32
pci_read_io_32(int mapped_io_addr)
{
/* NOT IMPLEMENTED */
return 0;
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
/* NOT IMPLEMENTED */
}
@@ -1,12 +0,0 @@
/*
* Copyright 2009, Haiku Inc.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_ARM_IO_H
#define PCI_BUS_MANAGER_ARM_IO_H
#include <SupportDefs.h>
#endif // PCI_BUS_MANAGER_ARM_IO_H
@@ -0,0 +1,208 @@
/*
* Copyright 2009-2022, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <kernel/debug.h>
#include <util/Vector.h>
#include <AutoDeleterDrivers.h>
#include "pci_private.h"
#include <ACPI.h> // module
#include <acpi.h>
addr_t gPCIeBase;
uint8 gStartBusNumber;
uint8 gEndBusNumber;
addr_t gPCIioBase;
extern pci_controller pci_controller_ecam;
enum RangeType
{
RANGE_IO,
RANGE_MEM
};
struct PciRange
{
RangeType type;
phys_addr_t hostAddr;
phys_addr_t pciAddr;
size_t length;
};
static Vector<PciRange> *sRanges;
template<typename T>
acpi_address64_attribute AcpiCopyAddressAttr(const T &src)
{
acpi_address64_attribute dst;
dst.granularity = src.granularity;
dst.minimum = src.minimum;
dst.maximum = src.maximum;
dst.translation_offset = src.translation_offset;
dst.address_length = src.address_length;
return dst;
}
static acpi_status
AcpiCrsScanCallback(acpi_resource *res, void *context)
{
Vector<PciRange> &ranges = *(Vector<PciRange>*)context;
acpi_address64_attribute address;
if (res->type == ACPI_RESOURCE_TYPE_ADDRESS16)
address = AcpiCopyAddressAttr(res->data.address16.address);
else if (res->type == ACPI_RESOURCE_TYPE_ADDRESS32)
address = AcpiCopyAddressAttr(res->data.address32.address);
else if (res->type == ACPI_RESOURCE_TYPE_ADDRESS64)
address = AcpiCopyAddressAttr(res->data.address64.address);
else
return B_OK;
acpi_resource_address &common = res->data.address;
if (common.resource_type != 0 && common.resource_type != 1)
return B_OK;
ASSERT(address.minimum + address.address_length - 1 == address.maximum);
PciRange range;
range.type = (common.resource_type == 0 ? RANGE_MEM : RANGE_IO);
range.hostAddr = address.minimum + address.translation_offset;
range.pciAddr = address.minimum;
range.length = address.address_length;
ranges.PushBack(range);
return B_OK;
}
status_t
pci_controller_init(void)
{
if (gPCIRootNode == NULL)
return B_DEV_NOT_READY;
dprintf("PCI: pci_controller_init\n");
DeviceNodePutter<&gDeviceManager>
parent(gDeviceManager->get_parent_node(gPCIRootNode));
if (parent.Get() == NULL)
return B_ERROR;
const char *bus;
if (gDeviceManager->get_attr_string(parent.Get(), B_DEVICE_BUS, &bus, false) < B_OK)
return B_ERROR;
if (strcmp(bus, "acpi") == 0) {
dprintf("initialize PCI controller from ACPI\n");
status_t res;
acpi_module_info *acpiModule;
acpi_device_module_info *acpiDeviceModule;
acpi_device acpiDevice;
res = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
if (res != B_OK)
return B_ERROR;
acpi_mcfg *mcfg;
res = acpiModule->get_table(ACPI_MCFG_SIGNATURE, 0, (void**)&mcfg);
if (res != B_OK)
return B_ERROR;
res = gDeviceManager->get_driver(parent.Get(),
(driver_module_info**)&acpiDeviceModule, (void**)&acpiDevice);
if (res != B_OK)
return B_ERROR;
sRanges = new Vector<PciRange>();
acpi_status acpi_res = acpiDeviceModule->walk_resources(acpiDevice,
(char *)"_CRS", AcpiCrsScanCallback, sRanges);
if (acpi_res != 0)
return B_ERROR;
for (Vector<PciRange>::Iterator it = sRanges->Begin(); it != sRanges->End(); it++) {
if (it->type != RANGE_IO)
continue;
if (gPCIioBase != 0) {
dprintf("PCI: multiple io ranges not supported!");
continue;
}
area_id area = map_physical_memory("pci io",
it->hostAddr, it->length, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIioBase);
if (area < 0)
return B_ERROR;
}
acpi_mcfg_allocation *end = (acpi_mcfg_allocation *) ((char*)mcfg + mcfg->header.length);
acpi_mcfg_allocation *alloc = (acpi_mcfg_allocation *) (mcfg + 1);
if (alloc + 1 != end)
dprintf("PCI: multiple host bridges not supported!");
for (; alloc < end; alloc++) {
dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: %x, end: %x\n",
alloc->address, alloc->pci_segment, alloc->start_bus_number, alloc->end_bus_number);
if (alloc->pci_segment != 0) {
dprintf("PCI: multiple segments not supported!");
continue;
}
gStartBusNumber = alloc->start_bus_number;
gEndBusNumber = alloc->end_bus_number;
area_id area = map_physical_memory("pci config",
alloc->address, (gEndBusNumber - gStartBusNumber + 1) << 20, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIeBase);
if (area < 0)
break;
dprintf("PCI: ecam controller found\n");
return pci_controller_add(&pci_controller_ecam, NULL);
}
}
return B_ERROR;
}
phys_addr_t
pci_ram_address(phys_addr_t addr)
{
for (Vector<PciRange>::Iterator it = sRanges->Begin(); it != sRanges->End(); it++) {
if (addr >= it->pciAddr && addr < it->pciAddr + it->length) {
phys_addr_t result = addr - it->pciAddr;
if (it->type != RANGE_IO)
result += it->hostAddr;
return result;
}
}
dprintf("PCI: requested translation of invalid address %" B_PRIxPHYSADDR "\n", addr);
return 0;
}
@@ -0,0 +1,112 @@
/*
* Copyright 2009-2022, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <kernel/debug.h>
extern addr_t gPCIeBase;
extern uint8 gStartBusNumber;
extern uint8 gEndBusNumber;
#define PCIE_VADDR(base, bus, slot, func, reg) \
((base) + ((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) \
| (((func) & 0x7) << 12) | ((reg) & 0xfff)))
static status_t
read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
if (!(bus >= gStartBusNumber && bus <= gEndBusNumber))
return B_ERROR;
status_t status = B_OK;
addr_t address = PCIE_VADDR(gPCIeBase, bus - gStartBusNumber, device, function, offset);
switch (size) {
case 1:
*value = *(uint8*)address;
break;
case 2:
*value = *(uint16*)address;
break;
case 4:
*value = *(uint32*)address;
break;
default:
status = B_ERROR;
break;
}
return status;
}
static status_t
write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
if (!(bus >= gStartBusNumber && bus <= gEndBusNumber))
return B_ERROR;
status_t status = B_OK;
addr_t address = PCIE_VADDR(gPCIeBase, bus - gStartBusNumber, device, function, offset);
switch (size) {
case 1:
*(uint8*)address = value;
break;
case 2:
*(uint16*)address = value;
break;
case 4:
*(uint32*)address = value;
break;
default:
status = B_ERROR;
break;
}
return status;
}
static status_t
get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
static status_t
read_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, uint8 pin,
uint8 *irq)
{
dprintf("read_pci_irq\n");
return B_NOT_SUPPORTED;
}
static status_t
write_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, uint8 pin,
uint8 irq)
{
dprintf("write_pci_irq\n");
return B_NOT_SUPPORTED;
}
pci_controller pci_controller_ecam =
{
read_pci_config,
write_pci_config,
get_max_bus_devices,
read_pci_irq,
write_pci_irq,
};
@@ -0,0 +1,80 @@
/*
* Copyright 2022, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include <SupportDefs.h>
#include "pci_private.h"
//#define TRACE_PCI_IO
#ifdef TRACE_PCI_IO
# define TRACE(x...) dprintf("PCI_IO: " x)
#else
# define TRACE(x...) ;
#endif
extern addr_t gPCIioBase;
status_t
pci_io_init()
{
TRACE("pci_io_init()\n");
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
TRACE("pci_read_io_8(%d)\n", mapped_io_addr);
volatile uint8* ptr = (uint8*)(gPCIioBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
TRACE("pci_write_io_8(%d)\n", mapped_io_addr);
volatile uint8* ptr = (uint8*)(gPCIioBase + mapped_io_addr);
*ptr = value;
}
uint16
pci_read_io_16(int mapped_io_addr)
{
TRACE("pci_read_io_16(%d)\n", mapped_io_addr);
volatile uint16* ptr = (uint16*)(gPCIioBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
TRACE("pci_write_io_16(%d)\n", mapped_io_addr);
volatile uint16* ptr = (uint16*)(gPCIioBase + mapped_io_addr);
*ptr = value;
}
uint32
pci_read_io_32(int mapped_io_addr)
{
TRACE("pci_read_io_32(%d)\n", mapped_io_addr);
volatile uint32* ptr = (uint32*)(gPCIioBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
TRACE("pci_write_io_32(%d)\n", mapped_io_addr);
volatile uint32* ptr = (uint32*)(gPCIioBase + mapped_io_addr);
*ptr = value;
}
@@ -8,6 +8,7 @@
#include <device_manager.h> #include <device_manager.h>
#include <PCI.h> #include <PCI.h>
#include <drivers/ACPI.h>
#include <drivers/bus/FDT.h> #include <drivers/bus/FDT.h>
#include <string.h> #include <string.h>
@@ -30,7 +31,7 @@ pci_root_supports_device(device_node* parent)
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK) if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK)
return -1.0f; return -1.0f;
#ifdef __riscv #if defined(__riscv)
const char* compatible; const char* compatible;
if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible,
false) < B_OK) false) < B_OK)
@@ -43,6 +44,17 @@ pci_root_supports_device(device_node* parent)
&& strcmp(compatible, "sifive,fu740-pcie") != 0) { && strcmp(compatible, "sifive,fu740-pcie") != 0) {
return 0.0f; return 0.0f;
} }
#elif defined(__aarch64__)
if (strcmp(bus, "acpi") != 0)
return -1.0f;
const char* hid;
if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid,
false) < B_OK)
return -1.0f;
if (strcmp(hid, "PNP0A03") != 0 && strcmp(hid, "PNP0A08") != 0)
return -1.0f;
#else #else
if (strcmp(bus, "root") != 0) if (strcmp(bus, "root") != 0)
return 0.0f; return 0.0f;