pci: added pcie mechanism for config space access.
* pci-acpi.cpp is based on the bootloader bios_ia32/acpi.cpp. The ACPI module has already a dependency on the PCI module. Using pci-acpi.cpp eases the simple task of finding the PCIe base address to map the config space. * pci_read_config and pci_write_config in pci_controller.h were using an uint8 for offsets in the config space. Switched to uint16 to enable access to the extended config space (0x100 and upper). Added a check for these offsets in pci_mech[1|2]_[read|write]_config() for x86 and other platforms as these mechanisms don't support a priori the extended config space.
This commit is contained in:
parent
bc7a518375
commit
ce353e5d6e
@ -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);
|
uint8 bus, uint8 slot, uint8 function, uint8 offset);
|
||||||
|
|
||||||
static status_t m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device,
|
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,
|
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);
|
uint32 value);
|
||||||
static status_t m68k_atari_get_max_bus_devices(void *cookie, int32 *count);
|
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,
|
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
|
static status_t
|
||||||
m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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 *devices = (struct fake_pci_device *)cookie;
|
||||||
struct fake_pci_device *dev;
|
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
|
static status_t
|
||||||
m68k_atari_write_pci_config(void *cookie, uint8 bus, uint8 device,
|
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 0
|
||||||
if (m68k_atari_enable_config(bridge, bus, device, function, offset)) {
|
if (m68k_atari_enable_config(bridge, bus, device, function, offset)) {
|
||||||
|
@ -80,13 +80,16 @@ struct grackle_host_bridge {
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
grackle_host_bridge *bridge = (grackle_host_bridge*)cookie;
|
||||||
TRACE("grackle_read_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
|
TRACE("grackle_read_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
|
||||||
"size=%u)\n", (int)bus, (int)device, (int)function, (int)offset,
|
"size=%u)\n", (int)bus, (int)device, (int)function, (int)offset,
|
||||||
(int)size);
|
(int)size);
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
out32rb(bridge->address_registers, (1 << 31)
|
out32rb(bridge->address_registers, (1 << 31)
|
||||||
| (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8)
|
| (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8)
|
||||||
| (offset & 0xfc));
|
| (offset & 0xfc));
|
||||||
@ -115,13 +118,16 @@ grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
grackle_write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
grackle_host_bridge *bridge = (grackle_host_bridge*)cookie;
|
||||||
TRACE("grackle_write_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
|
TRACE("grackle_write_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
|
||||||
"size=%u, value=%lu)\n", (int)bus, (int)device, (int)function,
|
"size=%u, value=%lu)\n", (int)bus, (int)device, (int)function,
|
||||||
(int)offset, (int)size, value);
|
(int)offset, (int)size, value);
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
out32rb(bridge->address_registers, (1 << 31)
|
out32rb(bridge->address_registers, (1 << 31)
|
||||||
| (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8)
|
| (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8)
|
||||||
| (offset & 0xfc));
|
| (offset & 0xfc));
|
||||||
|
@ -74,9 +74,9 @@ static int uninorth_enable_config(struct uninorth_host_bridge *bridge,
|
|||||||
uint8 bus, uint8 slot, uint8 function, uint8 offset);
|
uint8 bus, uint8 slot, uint8 function, uint8 offset);
|
||||||
|
|
||||||
static status_t uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device,
|
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,
|
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);
|
uint32 value);
|
||||||
static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count);
|
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,
|
static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device,
|
||||||
@ -95,10 +95,13 @@ static pci_controller sUniNorthPCIController = {
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
addr_t caoff = bridge->data_registers + (offset & 0x07);
|
addr_t caoff = bridge->data_registers + (offset & 0x07);
|
||||||
|
|
||||||
if (uninorth_enable_config(bridge, bus, device, function, offset) != 0) {
|
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,
|
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;
|
uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
addr_t caoff = bridge->data_registers + (offset & 0x07);
|
addr_t caoff = bridge->data_registers + (offset & 0x07);
|
||||||
|
|
||||||
if (uninorth_enable_config(bridge, bus, device, function, offset)) {
|
if (uninorth_enable_config(bridge, bus, device, function, offset)) {
|
||||||
|
@ -4,7 +4,12 @@ SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
|||||||
|
|
||||||
UsePrivateHeaders kernel [ FDirName kernel arch x86 ] [ FDirName kernel util ] ;
|
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 :
|
KernelStaticLibrary pci_arch_bus_manager :
|
||||||
|
pci_acpi.cpp
|
||||||
pci_arch_info.cpp
|
pci_arch_info.cpp
|
||||||
pci_arch_module.cpp
|
pci_arch_module.cpp
|
||||||
pci_bios.cpp
|
pci_bios.cpp
|
||||||
|
270
src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp
Normal file
270
src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp
Normal file
@ -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 <string.h>
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
#include <arch/x86/arch_acpi.h>
|
||||||
|
|
||||||
|
|
||||||
|
//#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<typename PointerType>
|
||||||
|
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<uint32>(signature, sAcpiRsdt);
|
||||||
|
else if (sAcpiXsdt != NULL)
|
||||||
|
return acpi_find_table_generic<uint64>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h
Normal file
27
src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h
Normal file
@ -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 <SupportDefs.h>
|
||||||
|
|
||||||
|
#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 */
|
@ -17,7 +17,7 @@ pci_bios_init(void)
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
pci_bios_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ status_t pci_bios_init(void);
|
|||||||
|
|
||||||
status_t pci_bios_read_config(void *cookie,
|
status_t pci_bios_read_config(void *cookie,
|
||||||
uint8 bus, uint8 device, uint8 function,
|
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,
|
status_t pci_bios_write_config(void *cookie,
|
||||||
uint8 bus, uint8 device, uint8 function,
|
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);
|
status_t pci_bios_get_max_bus_devices(void *cookie, int32 *count);
|
||||||
|
|
||||||
|
@ -3,14 +3,20 @@
|
|||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <driver_settings.h>
|
#include <driver_settings.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "pci_irq.h"
|
|
||||||
#include "pci_bios.h"
|
#include "pci_acpi.h"
|
||||||
#include "pci_private.h"
|
|
||||||
#include "pci_controller.h"
|
|
||||||
#include "arch_cpu.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_REQ_PORT 0xCF8
|
||||||
#define PCI_MECH1_DATA_PORT 0xCFC
|
#define PCI_MECH1_DATA_PORT 0xCFC
|
||||||
@ -38,11 +44,14 @@ spinlock sConfigLock = B_SPINLOCK_INITIALIZER;
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
cpu_status cpu;
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
PCI_LOCK_CONFIG(cpu);
|
PCI_LOCK_CONFIG(cpu);
|
||||||
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
|
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@ -67,11 +76,14 @@ pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
cpu_status cpu;
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
PCI_LOCK_CONFIG(cpu);
|
PCI_LOCK_CONFIG(cpu);
|
||||||
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
|
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@ -104,11 +116,14 @@ pci_mech1_get_max_bus_devices(void *cookie, int32 *count)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
cpu_status cpu;
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
PCI_LOCK_CONFIG(cpu);
|
PCI_LOCK_CONFIG(cpu);
|
||||||
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
|
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
|
||||||
out8(bus, PCI_MECH2_FORWARD_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
|
static status_t
|
||||||
pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
|
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;
|
cpu_status cpu;
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
if (offset > 0xff)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
PCI_LOCK_CONFIG(cpu);
|
PCI_LOCK_CONFIG(cpu);
|
||||||
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
|
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
|
||||||
out8(bus, PCI_MECH2_FORWARD_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 *
|
void *
|
||||||
pci_ram_address(const void *physical_address_in_system_memory)
|
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_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_controller pci_controller_x86_bios =
|
||||||
{
|
{
|
||||||
pci_bios_read_config,
|
pci_bios_read_config,
|
||||||
@ -212,6 +304,7 @@ pci_controller_init(void)
|
|||||||
{
|
{
|
||||||
bool search_mech1 = true;
|
bool search_mech1 = true;
|
||||||
bool search_mech2 = true;
|
bool search_mech2 = true;
|
||||||
|
bool search_mechpcie = true;
|
||||||
bool search_bios = true;
|
bool search_bios = true;
|
||||||
void *config = NULL;
|
void *config = NULL;
|
||||||
status_t status;
|
status_t status;
|
||||||
@ -225,11 +318,13 @@ pci_controller_init(void)
|
|||||||
const char *mech = get_driver_parameter(config, "mechanism",
|
const char *mech = get_driver_parameter(config, "mechanism",
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
if (mech) {
|
if (mech) {
|
||||||
search_mech1 = search_mech2 = search_bios = false;
|
search_mech1 = search_mech2 = search_mechpcie = search_bios = false;
|
||||||
if (strcmp(mech, "1") == 0)
|
if (strcmp(mech, "1") == 0)
|
||||||
search_mech1 = true;
|
search_mech1 = true;
|
||||||
else if (strcmp(mech, "2") == 0)
|
else if (strcmp(mech, "2") == 0)
|
||||||
search_mech2 = true;
|
search_mech2 = true;
|
||||||
|
else if (strcmp(mech, "pcie") == 0)
|
||||||
|
search_mechpcie = true;
|
||||||
else if (strcmp(mech, "bios") == 0)
|
else if (strcmp(mech, "bios") == 0)
|
||||||
search_bios = true;
|
search_bios = true;
|
||||||
else
|
else
|
||||||
@ -240,10 +335,39 @@ pci_controller_init(void)
|
|||||||
|
|
||||||
// TODO: check safemode "don't call the BIOS" setting and unset search_bios!
|
// 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.
|
// If it doesn't work, try mechanism 2.
|
||||||
// Finally, try to fallback to PCI BIOS
|
// 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) {
|
if (search_mech1) {
|
||||||
// check for mechanism 1
|
// check for mechanism 1
|
||||||
out32(0x80000000, PCI_MECH1_REQ_PORT);
|
out32(0x80000000, PCI_MECH1_REQ_PORT);
|
||||||
|
@ -13,12 +13,12 @@ typedef struct pci_controller
|
|||||||
// read PCI config space
|
// read PCI config space
|
||||||
status_t (*read_pci_config)(void *cookie,
|
status_t (*read_pci_config)(void *cookie,
|
||||||
uint8 bus, uint8 device, uint8 function,
|
uint8 bus, uint8 device, uint8 function,
|
||||||
uint8 offset, uint8 size, uint32 *value);
|
uint16 offset, uint8 size, uint32 *value);
|
||||||
|
|
||||||
// write PCI config space
|
// write PCI config space
|
||||||
status_t (*write_pci_config)(void *cookie,
|
status_t (*write_pci_config)(void *cookie,
|
||||||
uint8 bus, uint8 device, uint8 function,
|
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);
|
status_t (*get_max_bus_devices)(void *cookie, int32 *count);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user