diff --git a/headers/private/kernel/acpi.h b/headers/private/kernel/acpi.h index 894866b498..3f55109c00 100644 --- a/headers/private/kernel/acpi.h +++ b/headers/private/kernel/acpi.h @@ -10,6 +10,7 @@ #define ACPI_RSDT_SIGNATURE "RSDT" #define ACPI_XSDT_SIGNATURE "XSDT" #define ACPI_MADT_SIGNATURE "APIC" +#define ACPI_MCFG_SIGNATURE "MCFG" #define ACPI_SPCR_SIGNATURE "SPCR" #define ACPI_LOCAL_APIC_ENABLED 0x01 @@ -248,6 +249,21 @@ typedef struct acpi_gas { uint64 address; } _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 { acpi_descriptor_header header; uint32 interface_type; @@ -293,6 +309,92 @@ typedef struct acpi_resource_fixed_memory32 { uint32 address_length; } _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 { uint8 producer_consumer; uint8 triggering; @@ -306,7 +408,12 @@ typedef struct acpi_resource_extended_irq { typedef union acpi_resource_data { 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_address address; } acpi_resource_data; typedef struct acpi_resource { @@ -317,6 +424,9 @@ typedef struct acpi_resource { enum { 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, }; diff --git a/src/add-ons/kernel/bus_managers/pci/arch/arm64/Jamfile b/src/add-ons/kernel/bus_managers/pci/arch/arm64/Jamfile index a09b7cbb37..56b0bd323a 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/arm64/Jamfile +++ b/src/add-ons/kernel/bus_managers/pci/arch/arm64/Jamfile @@ -1,10 +1,15 @@ SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch $(TARGET_ARCH) ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; + +UsePrivateKernelHeaders ; UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ] [ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ; + KernelStaticLibrary pci_arch_bus_manager : pci_controller.cpp - pci_io.c + pci_io.cpp + pci_ecam.cpp ; diff --git a/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_controller.cpp b/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_controller.cpp deleted file mode 100644 index c4e9917718..0000000000 --- a/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_controller.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2009, Haiku Inc. - * Distributed under the terms of the MIT License. - */ - - -#include "pci_controller.h" - -//#include - -#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; -} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_io.c b/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_io.c deleted file mode 100644 index f0b9a700d5..0000000000 --- a/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_io.c +++ /dev/null @@ -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 */ -} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_io.h b/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_io.h deleted file mode 100644 index a900b6c82c..0000000000 --- a/src/add-ons/kernel/bus_managers/pci/arch/arm64/pci_io.h +++ /dev/null @@ -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 - - -#endif // PCI_BUS_MANAGER_ARM_IO_H diff --git a/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_controller.cpp b/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_controller.cpp new file mode 100644 index 0000000000..8851af17ac --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_controller.cpp @@ -0,0 +1,208 @@ +/* + * Copyright 2009-2022, Haiku Inc. + * Distributed under the terms of the MIT License. + */ + + +#include "pci_controller.h" + +#include +#include + +#include + +#include "pci_private.h" + +#include // module +#include + + +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 *sRanges; + + +template +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 &ranges = *(Vector*)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(); + + acpi_status acpi_res = acpiDeviceModule->walk_resources(acpiDevice, + (char *)"_CRS", AcpiCrsScanCallback, sRanges); + + if (acpi_res != 0) + return B_ERROR; + + for (Vector::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::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; +} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_ecam.cpp b/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_ecam.cpp new file mode 100644 index 0000000000..1d6b194def --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_ecam.cpp @@ -0,0 +1,112 @@ +/* + * Copyright 2009-2022, Haiku Inc. + * Distributed under the terms of the MIT License. + */ + +#include "pci_controller.h" + +#include + + +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, +}; diff --git a/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_io.cpp b/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_io.cpp new file mode 100644 index 0000000000..6987f01b26 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/generic/pci_io.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2022, Haiku Inc. + * Distributed under the terms of the MIT License. + */ + + +#include + +#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; +} diff --git a/src/add-ons/kernel/bus_managers/pci/pci_root.cpp b/src/add-ons/kernel/bus_managers/pci/pci_root.cpp index 96bd855d20..50c5d2d8f1 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_root.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci_root.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -30,7 +31,7 @@ pci_root_supports_device(device_node* parent) if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK) return -1.0f; -#ifdef __riscv +#if defined(__riscv) const char* compatible; if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false) < B_OK) @@ -43,6 +44,17 @@ pci_root_supports_device(device_node* parent) && strcmp(compatible, "sifive,fu740-pcie") != 0) { 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 if (strcmp(bus, "root") != 0) return 0.0f;