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);
|
||||
|
||||
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)) {
|
||||
|
@ -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));
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
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
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -3,14 +3,20 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <driver_settings.h>
|
||||
#include <string.h>
|
||||
#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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user