diff --git a/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp b/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp index d29f51c53e..c81474a82d 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp @@ -82,9 +82,9 @@ static int m68k_atari_enable_config(struct m68k_atari_fake_host_bridge *bridge, uint8 bus, uint8 slot, uint8 function, uint8 offset); static status_t m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device, - uint8 function, uint8 offset, uint8 size, uint32 *value); + uint8 function, uint16 offset, uint8 size, uint32 *value); static status_t m68k_atari_write_pci_config(void *cookie, uint8 bus, - uint8 device, uint8 function, uint8 offset, uint8 size, + uint8 device, uint8 function, uint16 offset, uint8 size, uint32 value); static status_t m68k_atari_get_max_bus_devices(void *cookie, int32 *count); static status_t m68k_atari_read_pci_irq(void *cookie, uint8 bus, uint8 device, @@ -103,7 +103,7 @@ static pci_controller sM68kAtariPCIController = { static status_t m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value) + uint16 offset, uint8 size, uint32 *value) { struct fake_pci_device *devices = (struct fake_pci_device *)cookie; struct fake_pci_device *dev; @@ -183,7 +183,7 @@ m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function static status_t m68k_atari_write_pci_config(void *cookie, uint8 bus, uint8 device, - uint8 function, uint8 offset, uint8 size, uint32 value) + uint8 function, uint16 offset, uint8 size, uint32 value) { #if 0 if (m68k_atari_enable_config(bridge, bus, device, function, offset)) { diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp index 7a67ca02c4..b0a98f16d8 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp @@ -80,13 +80,16 @@ struct grackle_host_bridge { static status_t grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value) + uint16 offset, uint8 size, uint32 *value) { grackle_host_bridge *bridge = (grackle_host_bridge*)cookie; TRACE("grackle_read_pci_config(bus=%u, dev=%u, func=%u, offset=%u, " "size=%u)\n", (int)bus, (int)device, (int)function, (int)offset, (int)size); + if (offset > 0xff) + return B_BAD_VALUE; + out32rb(bridge->address_registers, (1 << 31) | (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8) | (offset & 0xfc)); @@ -115,13 +118,16 @@ grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, static status_t grackle_write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 value) + uint16 offset, uint8 size, uint32 value) { grackle_host_bridge *bridge = (grackle_host_bridge*)cookie; TRACE("grackle_write_pci_config(bus=%u, dev=%u, func=%u, offset=%u, " "size=%u, value=%lu)\n", (int)bus, (int)device, (int)function, (int)offset, (int)size, value); + if (offset > 0xff) + return B_BAD_VALUE; + out32rb(bridge->address_registers, (1 << 31) | (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8) | (offset & 0xfc)); diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp index d7a1f4c0ea..7997129f79 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp @@ -74,9 +74,9 @@ static int uninorth_enable_config(struct uninorth_host_bridge *bridge, uint8 bus, uint8 slot, uint8 function, uint8 offset); static status_t uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, - uint8 function, uint8 offset, uint8 size, uint32 *value); + uint8 function, uint16 offset, uint8 size, uint32 *value); static status_t uninorth_write_pci_config(void *cookie, uint8 bus, - uint8 device, uint8 function, uint8 offset, uint8 size, + uint8 device, uint8 function, uint16 offset, uint8 size, uint32 value); static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count); static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device, @@ -95,10 +95,13 @@ static pci_controller sUniNorthPCIController = { static status_t uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value) + uint16 offset, uint8 size, uint32 *value) { uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie; + if (offset > 0xff) + return B_BAD_VALUE; + addr_t caoff = bridge->data_registers + (offset & 0x07); if (uninorth_enable_config(bridge, bus, device, function, offset) != 0) { @@ -124,10 +127,13 @@ uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, static status_t uninorth_write_pci_config(void *cookie, uint8 bus, uint8 device, - uint8 function, uint8 offset, uint8 size, uint32 value) + uint8 function, uint16 offset, uint8 size, uint32 value) { uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie; + if (offset > 0xff) + return B_BAD_VALUE; + addr_t caoff = bridge->data_registers + (offset & 0x07); if (uninorth_enable_config(bridge, bus, device, function, offset)) { diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile b/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile index f03f6c7048..980b4504f3 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile @@ -4,7 +4,12 @@ SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; UsePrivateHeaders kernel [ FDirName kernel arch x86 ] [ FDirName kernel util ] ; +SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include ; +SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include + platform ; + KernelStaticLibrary pci_arch_bus_manager : + pci_acpi.cpp pci_arch_info.cpp pci_arch_module.cpp pci_bios.cpp diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp new file mode 100644 index 0000000000..f1fb0fad65 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp @@ -0,0 +1,270 @@ +/* + * Copyright 2011, Rene Gollent, rene@gollent.com. + * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. + * Copyright 2007, Michael Lotz, mmlr@mlotz.ch + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. +*/ + + +#include "pci_acpi.h" + +#include + +#include + +#include + + +//#define TRACE_ACPI +#ifdef TRACE_ACPI +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + +static struct scan_spots_struct acpi_scan_spots[] = { + { 0x0, 0x1000, 0x1000 }, + { 0x9f000, 0x10000, 0x1000 }, + { 0xe0000, 0x110000, 0x20000 }, + { 0xfd000, 0xfe000, 0x1000}, + { 0, 0, 0 } +}; + +static acpi_descriptor_header* sAcpiRsdt; // System Description Table +static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table +static int32 sNumEntries = -1; + + +static status_t +acpi_validate_rsdp(acpi_rsdp* rsdp) +{ + const char* data = (const char*)rsdp; + unsigned char checksum = 0; + for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++) + checksum += data[i]; + + if ((checksum & 0xff) != 0) { + TRACE(("acpi: rsdp failed basic checksum\n")); + return B_BAD_DATA; + } + + // for ACPI 2.0+ we need to also validate the extended checksum + if (rsdp->revision > 0) { + for (uint32 i = sizeof(acpi_rsdp_legacy); + i < sizeof(acpi_rsdp_extended); i++) { + checksum += data[i]; + } + + if ((checksum & 0xff) != 0) { + TRACE(("acpi: rsdp failed extended checksum\n")); + return B_BAD_DATA; + } + } + + return B_OK; +} + + +static status_t +acpi_validate_rsdt(acpi_descriptor_header* rsdt) +{ + const char* data = (const char*)rsdt; + unsigned char checksum = 0; + for (uint32 i = 0; i < rsdt->length; i++) + checksum += data[i]; + + return checksum == 0 ? B_OK : B_BAD_DATA; +} + + +static status_t +acpi_check_rsdt(acpi_rsdp* rsdp) +{ + if (acpi_validate_rsdp(rsdp) != B_OK) + return B_BAD_DATA; + + bool usingXsdt = false; + + TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n", + rsdp, rsdp->oem_id, rsdp->revision)); + TRACE(("acpi: rsdp points to rsdt at 0x%lx\n", rsdp->rsdt_address)); + + uint32 length = 0; + acpi_descriptor_header* rsdt = NULL; + area_id rsdtArea = -1; + if (rsdp->revision > 0) { + length = rsdp->xsdt_length; + rsdtArea = map_physical_memory("rsdt acpi", + (uint32)rsdp->xsdt_address, rsdp->xsdt_length, B_ANY_KERNEL_ADDRESS, + B_KERNEL_READ_AREA, (void **)&rsdt); + if (rsdt != NULL + && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) { + delete_area(rsdtArea); + rsdt = NULL; + TRACE(("acpi: invalid extended system description table\n")); + } else + usingXsdt = true; + } + + // if we're ACPI v1 or we fail to map the XSDT for some reason, + // attempt to use the RSDT instead. + if (rsdt == NULL) { + // map and validate the root system description table + rsdtArea = map_physical_memory("rsdt acpi", + rsdp->rsdt_address, sizeof(acpi_descriptor_header), + B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&rsdt); + if (rsdt != NULL + && strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) { + delete_area(rsdtArea); + rsdt = NULL; + TRACE(("acpi: invalid root system description table\n")); + return B_ERROR; + } + + length = rsdt->length; + // Map the whole table, not just the header + TRACE(("acpi: rsdt length: %lu\n", length)); + delete_area(rsdtArea); + rsdtArea = map_physical_memory("rsdt acpi", + rsdp->rsdt_address, length, B_ANY_KERNEL_ADDRESS, + B_KERNEL_READ_AREA, (void **)&rsdt); + } + + if (rsdt != NULL) { + if (acpi_validate_rsdt(rsdt) != B_OK) { + TRACE(("acpi: rsdt failed checksum validation\n")); + delete_area(rsdtArea); + return B_ERROR; + } else { + if (usingXsdt) + sAcpiXsdt = rsdt; + else + sAcpiRsdt = rsdt; + TRACE(("acpi: found valid %s at %p\n", + usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE, + rsdt)); + } + } else + return B_ERROR; + + return B_OK; +} + + +template +acpi_descriptor_header* +acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt) +{ + if (acpiSdt == NULL) + return NULL; + + if (sNumEntries == -1) { + // if using the xsdt, our entries are 64 bits wide. + sNumEntries = (acpiSdt->length + - sizeof(acpi_descriptor_header)) + / sizeof(PointerType); + } + + if (sNumEntries <= 0) { + TRACE(("acpi: root system description table is empty\n")); + return NULL; + } + + TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries, + signature)); + + PointerType* pointer = (PointerType*)((uint8*)acpiSdt + + sizeof(acpi_descriptor_header)); + + acpi_descriptor_header* header = NULL; + area_id headerArea = -1; + for (int32 j = 0; j < sNumEntries; j++, pointer++) { + headerArea = map_physical_memory("acpi header", (uint32)*pointer, + sizeof(acpi_descriptor_header), B_ANY_KERNEL_ADDRESS, + B_KERNEL_READ_AREA, (void **)&header); + + if (header == NULL + || strncmp(header->signature, signature, 4) != 0) { + // not interesting for us + TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n", + signature, header != NULL ? header->signature : "null")); + + if (header != NULL) { + delete_area(headerArea); + header = NULL; + } + + continue; + } + + TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer)); + break; + } + + + if (header == NULL) + return NULL; + + // Map the whole table, not just the header + uint32 length = header->length; + delete_area(headerArea); + + headerArea = map_physical_memory("acpi table", + (uint32)*pointer, length, B_ANY_KERNEL_ADDRESS, + B_KERNEL_READ_AREA, (void **)&header); + return header; +} + + +void* +acpi_find_table(const char* signature) +{ + if (sAcpiRsdt != NULL) + return acpi_find_table_generic(signature, sAcpiRsdt); + else if (sAcpiXsdt != NULL) + return acpi_find_table_generic(signature, sAcpiXsdt); + + return NULL; +} + + +void +acpi_init() +{ + // Try to find the ACPI RSDP. + for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) { + acpi_rsdp* rsdp = NULL; + + TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n", + acpi_scan_spots[i].start, acpi_scan_spots[i].stop)); + + char* start = NULL; + area_id rsdpArea = map_physical_memory("acpi rsdp", + acpi_scan_spots[i].start, acpi_scan_spots[i].length, + B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&start); + if (rsdpArea < B_OK) { + TRACE(("acpi_init: couldn't map %s\n", strerror(rsdpArea))); + break; + } + for (char *pointer = start; + (addr_t)pointer < (addr_t)start + acpi_scan_spots[i].length; + pointer += 16) { + if (strncmp(pointer, ACPI_RSDP_SIGNATURE, 8) == 0) { + TRACE(("acpi_init: found ACPI RSDP signature at %p\n", + pointer)); + rsdp = (acpi_rsdp*)pointer; + } + } + + if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) { + delete_area(rsdpArea); + break; + } + delete_area(rsdpArea); + } + +} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h new file mode 100644 index 0000000000..8be385616d --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h @@ -0,0 +1,27 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef PCI_ACPI_H +#define PCI_ACPI_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct scan_spots_struct { + uint32 start; + uint32 stop; + uint32 length; +}; + +void *acpi_find_table(const char *signature); +void acpi_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PCI_ACPI_H */ diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp index 1852f70f3b..ef34b2be11 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp @@ -17,7 +17,7 @@ pci_bios_init(void) status_t pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value) + uint16 offset, uint8 size, uint32 *value) { return B_ERROR; } @@ -25,7 +25,7 @@ pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, status_t pci_bios_write_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 value) + uint16 offset, uint8 size, uint32 value) { return B_ERROR; } diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h index 89807f1fd8..64d05b67be 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h @@ -7,11 +7,11 @@ status_t pci_bios_init(void); status_t pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value); + uint16 offset, uint8 size, uint32 *value); status_t pci_bios_write_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 value); + uint16 offset, uint8 size, uint32 value); status_t pci_bios_get_max_bus_devices(void *cookie, int32 *count); diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp index 4a0fd7fc5a..e702ca78c2 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp @@ -3,14 +3,20 @@ * Distributed under the terms of the MIT License. */ + #include #include #include -#include "pci_irq.h" -#include "pci_bios.h" -#include "pci_private.h" -#include "pci_controller.h" + +#include "pci_acpi.h" #include "arch_cpu.h" +#include "pci_bios.h" +#include "pci_controller.h" +#include "pci_irq.h" +#include "pci_private.h" + +#include "acpi.h" + #define PCI_MECH1_REQ_PORT 0xCF8 #define PCI_MECH1_DATA_PORT 0xCFC @@ -38,11 +44,14 @@ spinlock sConfigLock = B_SPINLOCK_INITIALIZER; static status_t pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value) + uint16 offset, uint8 size, uint32 *value) { cpu_status cpu; status_t status = B_OK; + if (offset > 0xff) + return B_BAD_VALUE; + PCI_LOCK_CONFIG(cpu); out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT); switch (size) { @@ -67,11 +76,14 @@ pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, static status_t pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 value) + uint16 offset, uint8 size, uint32 value) { cpu_status cpu; status_t status = B_OK; + if (offset > 0xff) + return B_BAD_VALUE; + PCI_LOCK_CONFIG(cpu); out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT); switch (size) { @@ -104,11 +116,14 @@ pci_mech1_get_max_bus_devices(void *cookie, int32 *count) static status_t pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value) + uint16 offset, uint8 size, uint32 *value) { cpu_status cpu; status_t status = B_OK; + if (offset > 0xff) + return B_BAD_VALUE; + PCI_LOCK_CONFIG(cpu); out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT); out8(bus, PCI_MECH2_FORWARD_PORT); @@ -135,11 +150,14 @@ pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, static status_t pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 value) + uint16 offset, uint8 size, uint32 value) { cpu_status cpu; status_t status = B_OK; + if (offset > 0xff) + return B_BAD_VALUE; + PCI_LOCK_CONFIG(cpu); out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT); out8(bus, PCI_MECH2_FORWARD_PORT); @@ -172,6 +190,71 @@ pci_mech2_get_max_bus_devices(void *cookie, int32 *count) } +addr_t sPCIeBase = 0; +#define PCIE_VADDR(base, bus, slot, func, reg) ((base) + \ + ((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) | \ + (((func) & 0x7) << 12) | ((reg) & 0xfff))) + +static status_t +pci_mechpcie_read_config(void *cookie, uint8 bus, uint8 device, uint8 function, + uint16 offset, uint8 size, uint32 *value) +{ + status_t status = B_OK; + + addr_t address = PCIE_VADDR(sPCIeBase, bus, 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 +pci_mechpcie_write_config(void *cookie, uint8 bus, uint8 device, uint8 function, + uint16 offset, uint8 size, uint32 value) +{ + status_t status = B_OK; + + addr_t address = PCIE_VADDR(sPCIeBase, bus, 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 +pci_mechpcie_get_max_bus_devices(void *cookie, int32 *count) +{ + *count = 32; + return B_OK; +} + + void * pci_ram_address(const void *physical_address_in_system_memory) { @@ -197,6 +280,15 @@ pci_controller pci_controller_x86_mech2 = pci_x86_irq_write, }; +pci_controller pci_controller_x86_mechpcie = +{ + pci_mechpcie_read_config, + pci_mechpcie_write_config, + pci_mechpcie_get_max_bus_devices, + pci_x86_irq_read, + pci_x86_irq_write, +}; + pci_controller pci_controller_x86_bios = { pci_bios_read_config, @@ -212,6 +304,7 @@ pci_controller_init(void) { bool search_mech1 = true; bool search_mech2 = true; + bool search_mechpcie = true; bool search_bios = true; void *config = NULL; status_t status; @@ -225,11 +318,13 @@ pci_controller_init(void) const char *mech = get_driver_parameter(config, "mechanism", NULL, NULL); if (mech) { - search_mech1 = search_mech2 = search_bios = false; + search_mech1 = search_mech2 = search_mechpcie = search_bios = false; if (strcmp(mech, "1") == 0) search_mech1 = true; else if (strcmp(mech, "2") == 0) search_mech2 = true; + else if (strcmp(mech, "pcie") == 0) + search_mechpcie = true; else if (strcmp(mech, "bios") == 0) search_bios = true; else @@ -240,10 +335,39 @@ pci_controller_init(void) // TODO: check safemode "don't call the BIOS" setting and unset search_bios! - // PCI configuration mechanism 1 is the preferred one. + // PCI configuration mechanism PCIe is the preferred one. + // If it doesn't work, try mechanism 1. // If it doesn't work, try mechanism 2. // Finally, try to fallback to PCI BIOS + if (search_mechpcie) { + acpi_init(); + struct acpi_table_mcfg* mcfg = + (struct acpi_table_mcfg*)acpi_find_table("MCFG"); + if (mcfg != NULL) { + struct acpi_mcfg_allocation* end = (struct acpi_mcfg_allocation*) + ((char*)mcfg + mcfg->Header.Length); + struct acpi_mcfg_allocation* alloc = (struct acpi_mcfg_allocation*) + (mcfg + 1); + for (; alloc < end; alloc++) { + dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: " + "%x, end: %x\n", alloc->Address, alloc->PciSegment, + alloc->StartBusNumber, alloc->EndBusNumber); + if (alloc->PciSegment == 0) { + area_id mcfgArea = map_physical_memory("acpi mcfg", + alloc->Address, (alloc->EndBusNumber + 1) << 20, + B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA + | B_KERNEL_WRITE_AREA, (void **)&sPCIeBase); + if (mcfgArea < 0) + break; + dprintf("PCI: mechanism pcie controller found\n"); + return pci_controller_add(&pci_controller_x86_mechpcie, + NULL); + } + } + } + } + if (search_mech1) { // check for mechanism 1 out32(0x80000000, PCI_MECH1_REQ_PORT); diff --git a/src/add-ons/kernel/bus_managers/pci/pci_controller.h b/src/add-ons/kernel/bus_managers/pci/pci_controller.h index 0c39c35106..3a37e80ccd 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_controller.h +++ b/src/add-ons/kernel/bus_managers/pci/pci_controller.h @@ -13,12 +13,12 @@ typedef struct pci_controller // read PCI config space status_t (*read_pci_config)(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 *value); + uint16 offset, uint8 size, uint32 *value); // write PCI config space status_t (*write_pci_config)(void *cookie, uint8 bus, uint8 device, uint8 function, - uint8 offset, uint8 size, uint32 value); + uint16 offset, uint8 size, uint32 value); status_t (*get_max_bus_devices)(void *cookie, int32 *count);