Added support for multiple PCI host controllers and allow multiple PCI domains (needed for PPC).

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16086 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2006-01-25 17:51:35 +00:00
parent 1571b4c958
commit 8d366c9e00
15 changed files with 654 additions and 408 deletions
@@ -1,27 +1,13 @@
#include "pci_priv.h" #include "pci_controller.h"
int gMaxBusDevices;
status_t status_t
pci_config_init() pci_controller_init(void)
{ {
return B_OK; return B_OK;
} }
uint32
pci_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size)
{
return 0;
}
void
pci_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value)
{
}
void * void *
pci_ram_address(const void *physical_address_in_system_memory) pci_ram_address(const void *physical_address_in_system_memory)
{ {
@@ -1,20 +0,0 @@
#include "pci_priv.h"
status_t
pci_irq_init(void)
{
return B_ERROR;
}
uint8
pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin)
{
return 0;
}
void
pci_write_irq(uint8 bus, uint8 device, uint8 function, uint8 pin, uint8 irq)
{
}
@@ -3,7 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch x86 ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
KernelStaticLibrary pci_arch_bus_manager : KernelStaticLibrary pci_arch_bus_manager :
bios.c pci_bios.c
pci_controller.c pci_controller.c
pci_io.c pci_io.c
pci_irq.c pci_irq.c
@@ -1,27 +0,0 @@
#include "pci_priv.h"
#include "bios.h"
void
pci_bios_init(void)
{
}
bool
pci_bios_available(void)
{
return false;
}
uint32
pci_bios_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size)
{
return 0;
}
void
pci_bios_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value)
{
}
@@ -1,7 +0,0 @@
void pci_bios_init(void);
bool pci_bios_available(void);
uint32 pci_bios_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
void pci_bios_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
@@ -0,0 +1,32 @@
#include "pci_priv.h"
#include "pci_bios.h"
status_t
pci_bios_init(void)
{
return B_ERROR;
}
status_t
pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 *value)
{
return B_ERROR;
}
status_t
pci_bios_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{
return B_ERROR;
}
status_t
pci_bios_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
@@ -0,0 +1,18 @@
#ifndef __PCI_X86_BIOS_H
#define __PCI_X86_BIOS_H
#include <SupportDefs.h>
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);
status_t pci_bios_write_config(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value);
status_t pci_bios_get_max_bus_devices(void *cookie, int32 *count);
#endif
@@ -1,21 +1,16 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h> #include <KernelExport.h>
#include "pci_irq.h"
#include "pci_bios.h"
#include "pci_priv.h" #include "pci_priv.h"
#include "bios.h" #include "pci_controller.h"
#include "arch_cpu.h" #include "arch_cpu.h"
static uint32 (*gReadConfigFunc)(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
static void (*gWriteConfigFunc)(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
int gMaxBusDevices;
status_t detect_config_mechanism(void);
bool pci_config_access_ok(void);
uint32 pci_mech1_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
void pci_mech1_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
uint32 pci_mech2_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
void pci_mech2_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
#define PCI_MECH1_REQ_PORT 0xCF8 #define PCI_MECH1_REQ_PORT 0xCF8
#define PCI_MECH1_DATA_PORT 0xCFC #define PCI_MECH1_DATA_PORT 0xCFC
#define PCI_MECH1_REQ_DATA(bus, device, func, offset) \ #define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
@@ -26,203 +21,125 @@ void pci_mech2_write_config(uint8 bus, uint8 device, uint8 function, uint8 offse
#define PCI_MECH2_CONFIG_PORT(dev, offset) \ #define PCI_MECH2_CONFIG_PORT(dev, offset) \
(uint16)(0xC00 | (dev << 8) | offset) (uint16)(0xC00 | (dev << 8) | offset)
#define PCI_LOCK_CONFIG(cpu_status) \
{ \
cpu_status = disable_interrupts(); \
acquire_spinlock(&sConfigLock); \
}
status_t #define PCI_UNLOCK_CONFIG(cpu_status) \
pci_config_init(void) { \
release_spinlock(&sConfigLock); \
restore_interrupts(cpu_status); \
}
spinlock sConfigLock = 0;
static status_t
pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 *value)
{ {
pci_bios_init(); cpu_status cpu;
status_t status = B_OK;
if (B_OK != detect_config_mechanism()) { PCI_LOCK_CONFIG(cpu);
dprintf("PCI: failed to detect configuration mechanism\n");
return B_ERROR;
}
return B_OK;
}
status_t
detect_config_mechanism(void)
{
// PCI configuration mechanism 1 is the preferred one.
// If it doesn't work, try mechanism 2.
// Finally, try to fallback to PCI BIOS
if (1) {
// check for mechanism 1
out32(0x80000000, PCI_MECH1_REQ_PORT);
if (0x80000000 == in32(PCI_MECH1_REQ_PORT)) {
dprintf("PCI: mechanism 1 found\n");
gMaxBusDevices = 32;
gReadConfigFunc = pci_mech1_read_config;
gWriteConfigFunc = pci_mech1_write_config;
if (pci_config_access_ok()) {
dprintf("PCI: using mechanism 1\n");
return B_OK;
}
}
}
if (1) {
// check for mechanism 2
out8(0x00, 0xCFB);
out8(0x00, 0xCF8);
out8(0x00, 0xCFA);
if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) {
dprintf("PCI: mechanism 2 found\n");
gMaxBusDevices = 16;
gReadConfigFunc = pci_mech2_read_config;
gWriteConfigFunc = pci_mech2_write_config;
if (pci_config_access_ok()) {
dprintf("PCI: using mechanism 2\n");
return B_OK;
}
}
}
if (1) {
// check for PCI BIOS
if (pci_bios_available()) {
gReadConfigFunc = pci_bios_read_config;
gWriteConfigFunc = pci_bios_write_config;
gMaxBusDevices = 32;
if (pci_config_access_ok()) {
dprintf("PCI: using PCI BIOS\n");
return B_OK;
}
}
}
dprintf("PCI: no configuration mechanism found\n");
return B_ERROR;
}
bool
pci_config_access_ok(void)
{
return true;
}
uint32
pci_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size)
{
return gReadConfigFunc(bus, device, function, offset, size);
}
void
pci_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value)
{
gWriteConfigFunc(bus, device, function, offset, size, value);
}
uint32
pci_mech1_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size)
{
uint32 result;
cpu_status status;
if (device > 31 || function > 7 || (size != 1 && size != 2 && size != 4)
|| (size == 2 && (offset & 3) == 3) || (size == 4 && (offset & 3) != 0)) {
dprintf("PCI: mech1 can't read config for bus %u, device %u, function %u, offset %u, size %u\n",
bus, device, function, offset, size);
return 0xffffffff;
}
PCI_LOCK_CONFIG(status);
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) {
case 1: case 1:
result = in8(PCI_MECH1_DATA_PORT + (offset & 3)); *value = in8(PCI_MECH1_DATA_PORT + (offset & 3));
break; break;
case 2: case 2:
result = in16(PCI_MECH1_DATA_PORT + (offset & 3)); *value = in16(PCI_MECH1_DATA_PORT + (offset & 3));
break; break;
case 4: case 4:
result = in32(PCI_MECH1_DATA_PORT); *value = in32(PCI_MECH1_DATA_PORT);
break; break;
default: default:
result = 0xffffffff; status = B_ERROR;
break;
} }
PCI_UNLOCK_CONFIG(status); PCI_UNLOCK_CONFIG(cpu);
return result;
return status;
} }
void static status_t
pci_mech1_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value) pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{ {
cpu_status status; cpu_status cpu;
if (device > 31 || function > 7 || (size != 1 && size != 2 && size != 4) status_t status = B_OK;
|| (size == 2 && (offset & 3) == 3) || (size == 4 && (offset & 3) != 0)) {
dprintf("PCI: mech1 can't write config for bus %u, device %u, function %u, offset %u, size %u\n",
bus, device, function, offset, size);
return;
}
PCI_LOCK_CONFIG(status); 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) {
case 1: case 1:
out8(value, PCI_MECH1_DATA_PORT + (offset & 3)); out8(value, PCI_MECH1_DATA_PORT + (offset & 3));
break; break;
case 2: case 2:
out16(value, PCI_MECH1_DATA_PORT + (offset & 3)); out16(value, PCI_MECH1_DATA_PORT + (offset & 3));
break; break;
case 4: case 4:
out32(value, PCI_MECH1_DATA_PORT); out32(value, PCI_MECH1_DATA_PORT);
break; break;
default:
status = B_ERROR;
break;
} }
PCI_UNLOCK_CONFIG(status); PCI_UNLOCK_CONFIG(cpu);
return status;
} }
uint32 static status_t
pci_mech2_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size) pci_mech1_get_max_bus_devices(void *cookie, int32 *count)
{ {
uint32 result; *count = 32;
cpu_status status; return B_OK;
if (device > 15 || function > 7 || (size != 1 && size != 2 && size != 4)) { }
dprintf("PCI: mech2 can't read config for bus %u, device %u, function %u, offset %u, size %u\n",
bus, device, function, offset, size);
return 0xffffffff; static status_t
} pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 *value)
{
cpu_status cpu;
status_t status = B_OK;
PCI_LOCK_CONFIG(status); 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);
switch (size) { switch (size) {
case 1: case 1:
result = in8(PCI_MECH2_CONFIG_PORT(device, offset)); *value = in8(PCI_MECH2_CONFIG_PORT(device, offset));
break; break;
case 2: case 2:
result = in16(PCI_MECH2_CONFIG_PORT(device, offset)); *value = in16(PCI_MECH2_CONFIG_PORT(device, offset));
break; break;
case 4: case 4:
result = in32(PCI_MECH2_CONFIG_PORT(device, offset)); *value = in32(PCI_MECH2_CONFIG_PORT(device, offset));
break; break;
default: default:
result = 0xffffffff; status = B_ERROR;
break;
} }
out8(0, PCI_MECH2_ENABLE_PORT); out8(0, PCI_MECH2_ENABLE_PORT);
PCI_UNLOCK_CONFIG(status); PCI_UNLOCK_CONFIG(cpu);
return result;
return status;
} }
void static status_t
pci_mech2_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value) pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{ {
cpu_status status; cpu_status cpu;
if (device > 15 || function > 7 || (size != 1 && size != 2 && size != 4)) { status_t status = B_OK;
dprintf("PCI: mech2 can't write config for bus %u, device %u, function %u, offset %u, size %u\n",
bus, device, function, offset, size);
return;
}
PCI_LOCK_CONFIG(status); 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);
switch (size) { switch (size) {
@@ -235,9 +152,22 @@ pci_mech2_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, ui
case 4: case 4:
out32(value, PCI_MECH2_CONFIG_PORT(device, offset)); out32(value, PCI_MECH2_CONFIG_PORT(device, offset));
break; break;
default:
status = B_ERROR;
break;
} }
out8(0, PCI_MECH2_ENABLE_PORT); out8(0, PCI_MECH2_ENABLE_PORT);
PCI_UNLOCK_CONFIG(status); PCI_UNLOCK_CONFIG(cpu);
return status;
}
static status_t
pci_mech2_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 16;
return B_OK;
} }
@@ -246,3 +176,82 @@ pci_ram_address(const void *physical_address_in_system_memory)
{ {
return (void *)physical_address_in_system_memory; return (void *)physical_address_in_system_memory;
} }
pci_controller pci_controller_x86_mech1 =
{
.read_pci_config = pci_mech1_read_config,
.write_pci_config = pci_mech1_write_config,
.get_max_bus_devices = pci_mech1_get_max_bus_devices,
.read_pci_irq = pci_x86_irq_read,
.write_pci_irq = pci_x86_irq_write,
};
pci_controller pci_controller_x86_mech2 =
{
.read_pci_config = pci_mech2_read_config,
.write_pci_config = pci_mech2_write_config,
.get_max_bus_devices = pci_mech2_get_max_bus_devices,
.read_pci_irq = pci_x86_irq_read,
.write_pci_irq = pci_x86_irq_write,
};
pci_controller pci_controller_x86_bios =
{
.read_pci_config = pci_bios_read_config,
.write_pci_config = pci_bios_write_config,
.get_max_bus_devices = pci_bios_get_max_bus_devices,
.read_pci_irq = pci_x86_irq_read,
.write_pci_irq = pci_x86_irq_write,
};
status_t
pci_controller_init(void)
{
bool search_mech1 = true;
bool search_mech2 = true;
bool search_bios = true;
status_t status;
status = pci_x86_irq_init();
if (status != B_OK)
return status;
// PCI configuration mechanism 1 is the preferred one.
// If it doesn't work, try mechanism 2.
// Finally, try to fallback to PCI BIOS
if (search_mech1) {
// check for mechanism 1
out32(0x80000000, PCI_MECH1_REQ_PORT);
if (0x80000000 == in32(PCI_MECH1_REQ_PORT)) {
dprintf("PCI: mechanism 1 controller found\n");
return pci_controller_add(&pci_controller_x86_mech1, NULL);
}
}
if (search_mech2) {
// check for mechanism 2
out8(0x00, 0xCFB);
out8(0x00, 0xCF8);
out8(0x00, 0xCFA);
if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) {
dprintf("PCI: mechanism 2 controller found\n");
return pci_controller_add(&pci_controller_x86_mech2, NULL);
}
}
if (search_bios) {
// check for PCI BIOS
if (pci_bios_init() == B_OK) {
dprintf("PCI: BIOS support found\n");
return pci_controller_add(&pci_controller_x86_bios, NULL);
}
}
dprintf("PCI: no configuration mechanism found\n");
return B_ERROR;
}
@@ -1,20 +1,32 @@
#include "pci_priv.h" /*
* Copyright 2006, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include "pci_irq.h"
status_t
pci_irq_init(void) status_t
pci_x86_irq_init(void)
{
return B_OK;
}
status_t
pci_x86_irq_read(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 *irq)
{ {
return B_ERROR; return B_ERROR;
} }
uint8 status_t
pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin) pci_x86_irq_write(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq)
{ {
return 0; return B_ERROR;
} }
void
pci_write_irq(uint8 bus, uint8 device, uint8 function, uint8 pin, uint8 irq)
{
}
@@ -0,0 +1,22 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#ifndef __PCI_X86_IRQ_H
#define __PCI_X86_IRQ_H
#include <SupportDefs.h>
status_t pci_x86_irq_init(void);
status_t pci_x86_irq_read(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 *irq);
status_t pci_x86_irq_write(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq);
#endif
+319 -104
View File
@@ -1,4 +1,5 @@
/* /*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved. * Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2003, Marcus Overhagen. All rights reserved. * Copyright 2003, Marcus Overhagen. All rights reserved.
* *
@@ -14,32 +15,76 @@
#include "pci_priv.h" #include "pci_priv.h"
#include "pci.h" #include "pci.h"
bool gIrqRouterAvailable = false;
spinlock gConfigLock = 0; spinlock gConfigLock = 0;
static PCI *sPCI; static PCI *sPCI;
// #pragma mark bus manager exports
status_t
pci_controller_add(pci_controller *controller, void *cookie)
{
return sPCI->AddController(controller, cookie);
}
long
pci_get_nth_pci_info(long index, pci_info *outInfo)
{
return sPCI->GetNthPciInfo(index, outInfo);
}
uint32
pci_read_config(uint8 virt_bus, uint8 device, uint8 function, uint8 offset, uint8 size)
{
uint8 bus;
int domain;
uint32 value;
if (sPCI->GetVirtBus(virt_bus, &domain, &bus) != B_OK)
return 0xffffffff;
if (sPCI->ReadPciConfig(domain, bus, device, function, offset, size, &value) != B_OK)
return 0xffffffff;
return value;
}
void
pci_write_config(uint8 virt_bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value)
{
uint8 bus;
int domain;
if (sPCI->GetVirtBus(virt_bus, &domain, &bus) != B_OK)
return;
sPCI->WritePciConfig(domain, bus, device, function, offset, size, value);
}
// #pragma mark bus manager init/uninit
status_t status_t
pci_init(void) pci_init(void)
{ {
sPCI = new PCI;
if (pci_io_init() != B_OK) { if (pci_io_init() != B_OK) {
TRACE(("PCI: pci_io_init failed\n")); TRACE(("PCI: pci_io_init failed\n"));
return B_ERROR; return B_ERROR;
} }
if (pci_config_init() != B_OK) { if (pci_controller_init() != B_OK) {
TRACE(("PCI: pci_config_init failed\n")); TRACE(("PCI: pci_controller_init failed\n"));
return B_ERROR; return B_ERROR;
} }
if (pci_irq_init() != B_OK) sPCI->InitDomainData();
TRACE(("PCI: IRQ router not available\n")); sPCI->InitBus();
else
gIrqRouterAvailable = true;
sPCI = new PCI;
return B_OK; return B_OK;
} }
@@ -52,22 +97,35 @@ pci_uninit(void)
} }
long // #pragma mark PCI class
pci_get_nth_pci_info(long index, pci_info *outInfo)
PCI::PCI()
: fRootBus(0)
, fDomainCount(0)
{ {
return sPCI->GetNthPciInfo(index, outInfo);
} }
PCI::PCI() void
PCI::InitBus()
{ {
fRootBus.parent = 0; PCIBus **ppnext = &fRootBus;
fRootBus.bus = 0;
fRootBus.child = 0;
DiscoverBus(&fRootBus); for (int i = 0; i < fDomainCount; i++) {
PCIBus *bus = new PCIBus;
RefreshDeviceInfo(&fRootBus); bus->next = NULL;
bus->parent = NULL;
bus->child = NULL;
bus->domain = i;
bus->bus = 0;
*ppnext = bus;
ppnext = &bus->next;
}
if (fRootBus) {
DiscoverBus(fRootBus);
RefreshDeviceInfo(fRootBus);
}
} }
@@ -76,11 +134,78 @@ PCI::~PCI()
} }
status_t
PCI::AddVirtBus(int domain, uint8 bus, uint8 *virt_bus)
{
if (MAX_PCI_DOMAINS != 8)
panic("PCI::AddVirtBus only 8 controllers supported");
if (domain > 7)
panic("PCI::AddVirtBus domain %d too large");
if (bus > 31)
panic("PCI::AddVirtBus bus %d too large");
*virt_bus = (domain << 5) | bus;
return B_OK;
}
status_t
PCI::GetVirtBus(uint8 virt_bus, int *domain, uint8 *bus)
{
// XXX if you modify this, also change pci_info.cpp print_info_basic() !!
*domain = virt_bus >> 5;
*bus = virt_bus & 0x1f;
return B_OK;
}
status_t
PCI::AddController(pci_controller *controller, void *controller_cookie)
{
if (fDomainCount == MAX_PCI_DOMAINS)
return B_ERROR;
fDomainData[fDomainCount].controller = controller;
fDomainData[fDomainCount].controller_cookie = controller_cookie;
// initialized later to avoid call back into controller at this point
fDomainData[fDomainCount].max_bus_devices = -1;
fDomainCount++;
return B_OK;
}
void
PCI::InitDomainData()
{
for (int i = 0; i < fDomainCount; i++) {
int32 count;
status_t status;
status = (*fDomainData[i].controller->get_max_bus_devices)(fDomainData[i].controller_cookie, &count);
fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0;
}
}
domain_data *
PCI::GetDomainData(int domain)
{
if (domain < 0 || domain >= fDomainCount)
return NULL;
return &fDomainData[domain];
}
status_t status_t
PCI::GetNthPciInfo(long index, pci_info *outInfo) PCI::GetNthPciInfo(long index, pci_info *outInfo)
{ {
long curindex = 0; long curindex = 0;
return GetNthPciInfo(&fRootBus, &curindex, index, outInfo); if (!fRootBus)
return B_ERROR;
return GetNthPciInfo(fRootBus, &curindex, index, outInfo);
} }
@@ -99,6 +224,10 @@ PCI::GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInf
return B_OK; return B_OK;
dev = dev->next; dev = dev->next;
} }
if (bus->next)
return GetNthPciInfo(bus->next, curindex, wantindex, outInfo);
return B_ERROR; return B_ERROR;
} }
@@ -106,49 +235,56 @@ PCI::GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInf
void void
PCI::DiscoverBus(PCIBus *bus) PCI::DiscoverBus(PCIBus *bus)
{ {
TRACE(("PCI: DiscoverBus, bus %u\n", bus->bus)); TRACE(("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus));
int max_bus_devices = GetDomainData(bus->domain)->max_bus_devices;
for (int dev = 0; dev < gMaxBusDevices; dev++) { for (int dev = 0; dev < max_bus_devices; dev++) {
uint16 vendor_id = pci_read_config(bus->bus, dev, 0, PCI_vendor_id, 2); uint16 vendor_id = ReadPciConfig(bus->domain, bus->bus, dev, 0, PCI_vendor_id, 2);
if (vendor_id == 0xffff) if (vendor_id == 0xffff)
continue; continue;
uint8 type = pci_read_config(bus->bus, dev, 0, PCI_header_type, 1); uint8 type = ReadPciConfig(bus->domain, bus->bus, dev, 0, PCI_header_type, 1);
int nfunc = (type & PCI_multifunction) ? 8 : 1; int nfunc = (type & PCI_multifunction) ? 8 : 1;
for (int func = 0; func < nfunc; func++) for (int func = 0; func < nfunc; func++)
DiscoverDevice(bus, dev, func); DiscoverDevice(bus, dev, func);
} }
if (bus->next)
DiscoverBus(bus->next);
} }
void void
PCI::DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func) PCI::DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func)
{ {
TRACE(("PCI: DiscoverDevice, bus %u, dev %u, func %u\n", bus->bus, dev, func)); TRACE(("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, func));
uint16 device_id = pci_read_config(bus->bus, dev, func, PCI_device_id, 2); uint16 device_id = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_device_id, 2);
if (device_id == 0xffff) if (device_id == 0xffff)
return; return;
PCIDev *newdev = CreateDevice(bus, dev, func); PCIDev *newdev = CreateDevice(bus, dev, func);
uint8 base_class = pci_read_config(bus->bus, dev, func, PCI_class_base, 1); uint8 base_class = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_class_base, 1);
uint8 sub_class = pci_read_config(bus->bus, dev, func, PCI_class_sub, 1); uint8 sub_class = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_class_sub, 1);
if (base_class == PCI_bridge && sub_class == PCI_pci) { if (base_class == PCI_bridge && sub_class == PCI_pci) {
uint8 secondary_bus = pci_read_config(bus->bus, dev, func, PCI_secondary_bus, 1); uint8 secondary_bus = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_secondary_bus, 1);
PCIBus *newbus = CreateBus(newdev, secondary_bus); PCIBus *newbus = CreateBus(newdev, bus->domain, secondary_bus);
DiscoverBus(newbus); DiscoverBus(newbus);
} }
} }
PCIBus * PCIBus *
PCI::CreateBus(PCIDev *parent, uint8 bus) PCI::CreateBus(PCIDev *parent, int domain, uint8 bus)
{ {
PCIBus *newbus = new PCIBus; PCIBus *newbus = new PCIBus;
newbus->next = NULL;
newbus->parent = parent; newbus->parent = parent;
newbus->child = NULL;
newbus->domain = domain;
newbus->bus = bus; newbus->bus = bus;
newbus->child = 0;
// append // append
parent->child = newbus; parent->child = newbus;
@@ -160,12 +296,13 @@ PCI::CreateBus(PCIDev *parent, uint8 bus)
PCIDev * PCIDev *
PCI::CreateDevice(PCIBus *parent, uint8 dev, uint8 func) PCI::CreateDevice(PCIBus *parent, uint8 dev, uint8 func)
{ {
TRACE(("PCI: CreateDevice, bus %u, dev %u, func %u:\n", parent->bus, dev, func)); TRACE(("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain, parent->bus, dev, func));
PCIDev *newdev = new PCIDev; PCIDev *newdev = new PCIDev;
newdev->next = 0; newdev->next = NULL;
newdev->parent = parent; newdev->parent = parent;
newdev->child = 0; newdev->child = NULL;
newdev->domain = parent->domain;
newdev->bus = parent->bus; newdev->bus = parent->bus;
newdev->dev = dev; newdev->dev = dev;
newdev->func = func; newdev->func = func;
@@ -205,10 +342,10 @@ PCI::BarSize(uint32 bits, uint32 mask)
void void
PCI::GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags) PCI::GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags)
{ {
uint32 oldvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); uint32 oldvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, 0xffffffff); WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, 0xffffffff);
uint32 newvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); uint32 newvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue); WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
*address = oldvalue & PCI_address_memory_32_mask; *address = oldvalue & PCI_address_memory_32_mask;
if (size) if (size)
@@ -221,10 +358,10 @@ PCI::GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8
void void
PCI::GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags) PCI::GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8 *flags)
{ {
uint32 oldvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); uint32 oldvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, 0xfffffffe); // LSB must be 0 WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, 0xfffffffe); // LSB must be 0
uint32 newvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4); uint32 newvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue); WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
*address = oldvalue & PCI_rom_address_mask; *address = oldvalue & PCI_rom_address_mask;
if (size) if (size)
@@ -237,20 +374,27 @@ PCI::GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uin
void void
PCI::ReadPciBasicInfo(PCIDev *dev) PCI::ReadPciBasicInfo(PCIDev *dev)
{ {
dev->info.vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_vendor_id, 2); uint8 virt_bus;
dev->info.device_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_device_id, 2);
dev->info.bus = dev->bus; if (AddVirtBus(dev->domain, dev->bus, &virt_bus) != B_OK) {
dprintf("PCI: AddVirtBus failed, domain %u, bus %u\n", dev->domain, dev->bus);
return;
}
dev->info.vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_vendor_id, 2);
dev->info.device_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_device_id, 2);
dev->info.bus = virt_bus;
dev->info.device = dev->dev; dev->info.device = dev->dev;
dev->info.function = dev->func; dev->info.function = dev->func;
dev->info.revision = pci_read_config(dev->bus, dev->dev, dev->func, PCI_revision, 1); dev->info.revision = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_revision, 1);
dev->info.class_api = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_api, 1); dev->info.class_api = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_api, 1);
dev->info.class_sub = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_sub, 1); dev->info.class_sub = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_sub, 1);
dev->info.class_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_base, 1); dev->info.class_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_base, 1);
dev->info.line_size = pci_read_config(dev->bus, dev->dev, dev->func, PCI_line_size, 1); dev->info.line_size = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_line_size, 1);
dev->info.latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_latency, 1); dev->info.latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_latency, 1);
// BeOS does not mask off the multifunction bit, developer must use (header_type & PCI_header_type_mask) // BeOS does not mask off the multifunction bit, developer must use (header_type & PCI_header_type_mask)
dev->info.header_type = pci_read_config(dev->bus, dev->dev, dev->func, PCI_header_type, 1); dev->info.header_type = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_header_type, 1);
dev->info.bist = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bist, 1); dev->info.bist = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bist, 1);
dev->info.reserved = 0; dev->info.reserved = 0;
} }
@@ -262,8 +406,8 @@ PCI::ReadPciHeaderInfo(PCIDev *dev)
case PCI_header_type_generic: case PCI_header_type_generic:
{ {
// disable PCI device address decoding (io and memory) while BARs are modified // disable PCI device address decoding (io and memory) while BARs are modified
uint16 pcicmd = pci_read_config(dev->bus, dev->dev, dev->func, PCI_command, 2); uint16 pcicmd = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2);
pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory)); WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
// get BAR size infos // get BAR size infos
GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci, &dev->info.u.h0.rom_size); GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci, &dev->info.u.h0.rom_size);
@@ -275,28 +419,28 @@ PCI::ReadPciHeaderInfo(PCIDev *dev)
} }
// restore PCI device address decoding // restore PCI device address decoding
pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd); WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd);
dev->info.u.h0.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h0.rom_base_pci); dev->info.u.h0.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h0.rom_base_pci);
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
dev->info.u.h0.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h0.base_registers_pci[i]); dev->info.u.h0.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h0.base_registers_pci[i]);
} }
dev->info.u.h0.cardbus_cis = pci_read_config(dev->bus, dev->dev, dev->func, PCI_cardbus_cis, 4); dev->info.u.h0.cardbus_cis = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_cardbus_cis, 4);
dev->info.u.h0.subsystem_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subsystem_id, 2); dev->info.u.h0.subsystem_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subsystem_id, 2);
dev->info.u.h0.subsystem_vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subsystem_vendor_id, 2); dev->info.u.h0.subsystem_vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subsystem_vendor_id, 2);
dev->info.u.h0.interrupt_line = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1); dev->info.u.h0.interrupt_line = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1);
dev->info.u.h0.interrupt_pin = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1); dev->info.u.h0.interrupt_pin = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1);
dev->info.u.h0.min_grant = pci_read_config(dev->bus, dev->dev, dev->func, PCI_min_grant, 1); dev->info.u.h0.min_grant = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_min_grant, 1);
dev->info.u.h0.max_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_max_latency, 1); dev->info.u.h0.max_latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_max_latency, 1);
break; break;
} }
case PCI_header_type_PCI_to_PCI_bridge: case PCI_header_type_PCI_to_PCI_bridge:
{ {
// disable PCI device address decoding (io and memory) while BARs are modified // disable PCI device address decoding (io and memory) while BARs are modified
uint16 pcicmd = pci_read_config(dev->bus, dev->dev, dev->func, PCI_command, 2); uint16 pcicmd = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2);
pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory)); WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
GetRomBarInfo(dev, PCI_bridge_rom_base, &dev->info.u.h1.rom_base_pci); GetRomBarInfo(dev, PCI_bridge_rom_base, &dev->info.u.h1.rom_base_pci);
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
@@ -307,56 +451,56 @@ PCI::ReadPciHeaderInfo(PCIDev *dev)
} }
// restore PCI device address decoding // restore PCI device address decoding
pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd); WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd);
dev->info.u.h1.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h1.rom_base_pci); dev->info.u.h1.rom_base = (ulong)pci_ram_address((void *)dev->info.u.h1.rom_base_pci);
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
dev->info.u.h1.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h1.base_registers_pci[i]); dev->info.u.h1.base_registers[i] = (ulong)pci_ram_address((void *)dev->info.u.h1.base_registers_pci[i]);
} }
dev->info.u.h1.primary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_primary_bus, 1); dev->info.u.h1.primary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_primary_bus, 1);
dev->info.u.h1.secondary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_bus, 1); dev->info.u.h1.secondary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_bus, 1);
dev->info.u.h1.subordinate_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subordinate_bus, 1); dev->info.u.h1.subordinate_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subordinate_bus, 1);
dev->info.u.h1.secondary_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_latency, 1); dev->info.u.h1.secondary_latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_latency, 1);
dev->info.u.h1.io_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base, 1); dev->info.u.h1.io_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base, 1);
dev->info.u.h1.io_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit, 1); dev->info.u.h1.io_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit, 1);
dev->info.u.h1.secondary_status = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_status, 2); dev->info.u.h1.secondary_status = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_status, 2);
dev->info.u.h1.memory_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_base, 2); dev->info.u.h1.memory_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_base, 2);
dev->info.u.h1.memory_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_limit, 2); dev->info.u.h1.memory_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit, 2);
dev->info.u.h1.prefetchable_memory_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base, 2); dev->info.u.h1.prefetchable_memory_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base, 2);
dev->info.u.h1.prefetchable_memory_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit, 2); dev->info.u.h1.prefetchable_memory_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit, 2);
dev->info.u.h1.prefetchable_memory_base_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base_upper32, 4); dev->info.u.h1.prefetchable_memory_base_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_base_upper32, 4);
dev->info.u.h1.prefetchable_memory_limit_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit_upper32, 4); dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit_upper32, 4);
dev->info.u.h1.io_base_upper16 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base_upper16, 2); dev->info.u.h1.io_base_upper16 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base_upper16, 2);
dev->info.u.h1.io_limit_upper16 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit_upper16, 2); dev->info.u.h1.io_limit_upper16 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit_upper16, 2);
dev->info.u.h1.interrupt_line = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1); dev->info.u.h1.interrupt_line = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_line, 1);
dev->info.u.h1.interrupt_pin = pci_read_config(dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1); dev->info.u.h1.interrupt_pin = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1);
dev->info.u.h1.bridge_control = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bridge_control, 2); dev->info.u.h1.bridge_control = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bridge_control, 2);
dev->info.u.h1.subsystem_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_sub_device_id_1, 2); dev->info.u.h1.subsystem_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_device_id_1, 2);
dev->info.u.h1.subsystem_vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_sub_vendor_id_1, 2); dev->info.u.h1.subsystem_vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_vendor_id_1, 2);
break; break;
} }
case PCI_header_type_cardbus: case PCI_header_type_cardbus:
{ {
// for testing only, not final: // for testing only, not final:
dev->info.u.h2.subsystem_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_sub_device_id_2, 2); dev->info.u.h2.subsystem_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_device_id_2, 2);
dev->info.u.h2.subsystem_vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_sub_vendor_id_2, 2); dev->info.u.h2.subsystem_vendor_id = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_vendor_id_2, 2);
dev->info.u.h2.primary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_primary_bus_2, 1); dev->info.u.h2.primary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_primary_bus_2, 1);
dev->info.u.h2.secondary_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_bus_2, 1); dev->info.u.h2.secondary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_bus_2, 1);
dev->info.u.h2.subordinate_bus = pci_read_config(dev->bus, dev->dev, dev->func, PCI_subordinate_bus_2, 1); dev->info.u.h2.subordinate_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subordinate_bus_2, 1);
dev->info.u.h2.secondary_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_latency_2, 1); dev->info.u.h2.secondary_latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_latency_2, 1);
dev->info.u.h2.reserved = 0; dev->info.u.h2.reserved = 0;
dev->info.u.h2.memory_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_base0_2, 4); dev->info.u.h2.memory_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_base0_2, 4);
dev->info.u.h2.memory_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_limit0_2, 4); dev->info.u.h2.memory_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit0_2, 4);
dev->info.u.h2.memory_base_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_base1_2, 4); dev->info.u.h2.memory_base_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_base1_2, 4);
dev->info.u.h2.memory_limit_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_memory_limit1_2, 4); dev->info.u.h2.memory_limit_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit1_2, 4);
dev->info.u.h2.io_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base0_2, 4); dev->info.u.h2.io_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base0_2, 4);
dev->info.u.h2.io_limit = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit0_2, 4); dev->info.u.h2.io_limit = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit0_2, 4);
dev->info.u.h2.io_base_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_base1_2, 4); dev->info.u.h2.io_base_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base1_2, 4);
dev->info.u.h2.io_limit_upper32 = pci_read_config(dev->bus, dev->dev, dev->func, PCI_io_limit1_2, 4); dev->info.u.h2.io_limit_upper32 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit1_2, 4);
dev->info.u.h2.secondary_status = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_status_2, 2); dev->info.u.h2.secondary_status = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_status_2, 2);
dev->info.u.h2.bridge_control = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bridge_control_2, 1); dev->info.u.h2.bridge_control = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bridge_control_2, 1);
break; break;
} }
@@ -376,4 +520,75 @@ PCI::RefreshDeviceInfo(PCIBus *bus)
if (dev->child) if (dev->child)
RefreshDeviceInfo(dev->child); RefreshDeviceInfo(dev->child);
} }
if (bus->next)
RefreshDeviceInfo(bus->next);
} }
status_t
PCI::ReadPciConfig(int domain, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 *value)
{
domain_data *info;
info = GetDomainData(domain);
if (!info)
return B_ERROR;
if (device > (info->max_bus_devices - 1)
|| function > 7
|| (size != 1 && size != 2 && size != 4)
|| (size == 2 && (offset & 3) == 3)
|| (size == 4 && (offset & 3) != 0)) {
dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
domain, bus, device, function, offset, size);
return B_ERROR;
}
status_t status;
status = (*info->controller->read_pci_config)(info->controller_cookie,
bus, device, function,
offset, size, value);
return status;
}
uint32
PCI::ReadPciConfig(int domain, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size)
{
uint32 value;
if (ReadPciConfig(domain, bus, device, function, offset, size, &value) != B_OK)
return 0xffffffff;
return value;
}
status_t
PCI::WritePciConfig(int domain, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{
domain_data *info;
info = GetDomainData(domain);
if (!info)
return B_ERROR;
if (device > (info->max_bus_devices - 1)
|| function > 7
|| (size != 1 && size != 2 && size != 4)
|| (size == 2 && (offset & 3) == 3)
|| (size == 4 && (offset & 3) != 0)) {
dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
domain, bus, device, function, offset, size);
return B_ERROR;
}
status_t status;
status = (*info->controller->write_pci_config)(info->controller_cookie,
bus, device, function,
offset, size, value);
return status;
}
+56 -12
View File
@@ -1,4 +1,5 @@
/* /*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved. * Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2003, Marcus Overhagen. All rights reserved. * Copyright 2003, Marcus Overhagen. All rights reserved.
* *
@@ -7,8 +8,7 @@
#ifndef __PCI_H__ #ifndef __PCI_H__
#define __PCI_H__ #define __PCI_H__
#include "pci_controller.h"
#include <SupportDefs.h>
#define TRACE_PCI #define TRACE_PCI
@@ -21,38 +21,69 @@
#ifdef __cplusplus #ifdef __cplusplus
struct PCIBus;
struct PCIDev; struct PCIDev;
struct PCIBus { struct PCIBus {
PCIBus *next;
PCIDev *parent; PCIDev *parent;
uint8 bus;
PCIDev *child; PCIDev *child;
int domain;
uint8 bus;
}; };
struct PCIDev { struct PCIDev {
PCIDev *next; PCIDev *next;
PCIBus *parent; PCIBus *parent;
PCIBus *child; PCIBus *child;
int domain;
uint8 bus; uint8 bus;
uint8 dev; uint8 dev;
uint8 func; uint8 func;
pci_info info; pci_info info;
}; };
struct domain_data
{
// These two are set in PCI::AddController:
pci_controller * controller;
void * controller_cookie;
// All the rest is set in PCI::InitDomainData
int max_bus_devices;
};
class PCI { class PCI {
public: public:
PCI(); PCI();
~PCI(); ~PCI();
void InitDomainData();
void InitBus();
status_t GetNthPciInfo(long index, pci_info *outInfo); status_t AddController(pci_controller *controller, void *controller_cookie);
status_t GetNthPciInfo(long index, pci_info *outInfo);
status_t ReadPciConfig(int domain, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 *value);
uint32 ReadPciConfig(int domain, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size);
status_t WritePciConfig(int domain, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value);
status_t GetVirtBus(uint8 virt_bus, int *domain, uint8 *bus);
private: private:
void DiscoverBus(PCIBus *bus); void DiscoverBus(PCIBus *bus);
void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func); void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func);
PCIDev *CreateDevice(PCIBus *parent, uint8 dev, uint8 func); PCIDev *CreateDevice(PCIBus *parent, uint8 dev, uint8 func);
PCIBus *CreateBus(PCIDev *parent, uint8 bus); PCIBus *CreateBus(PCIDev *parent, int domain, uint8 bus);
status_t GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo); status_t GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo);
void ReadPciBasicInfo(PCIDev *dev); void ReadPciBasicInfo(PCIDev *dev);
@@ -63,9 +94,19 @@ class PCI {
uint32 BarSize(uint32 bits, uint32 mask); uint32 BarSize(uint32 bits, uint32 mask);
void GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0); void GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
void GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0); void GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
domain_data * GetDomainData(int domain);
status_t AddVirtBus(int domain, uint8 bus, uint8 *virt_bus);
private: private:
PCIBus fRootBus; PCIBus * fRootBus;
enum { MAX_PCI_DOMAINS = 8 };
domain_data fDomainData[MAX_PCI_DOMAINS];
int fDomainCount;
}; };
#endif // __cplusplus #endif // __cplusplus
@@ -75,10 +116,13 @@ class PCI {
extern "C" { extern "C" {
#endif #endif
status_t pci_init(void); status_t pci_init(void);
void pci_uninit(void); void pci_uninit(void);
long pci_get_nth_pci_info(long index, pci_info *outInfo); long pci_get_nth_pci_info(long index, pci_info *outInfo);
uint32 pci_read_config(uint8 virt_bus, uint8 device, uint8 function, uint8 offset, uint8 size);
void pci_write_config(uint8 virt_bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -1,5 +1,5 @@
/* /*
** Copyright 2003-2005, Marcus Overhagen. All rights reserved. ** Copyright 2003-2006, Marcus Overhagen. All rights reserved.
** Distributed under the terms of the MIT License. ** Distributed under the terms of the MIT License.
*/ */
@@ -151,7 +151,9 @@ print_capabilities(const pci_info *info)
static void static void
print_info_basic(const pci_info *info, bool verbose) print_info_basic(const pci_info *info, bool verbose)
{ {
TRACE(("PCI: bus %2d, device %2d, function %2d: vendor %04x, device %04x, revision %02x\n", TRACE(("PCI: [dom %d, bus %2d] bus %3d, device %2d, function %2d: vendor %04x, device %04x, revision %02x\n",
// XXX this works only as long as PCI manager virtual bus mapping isn't changed:
(info->bus >> 5) /* domain */, (info->bus & 0x1f) /* bus */,
info->bus, info->device, info->function, info->vendor_id, info->device_id, info->revision)); info->bus, info->device, info->function, info->vendor_id, info->device_id, info->revision));
TRACE(("PCI: class_base %02x, class_function %02x, class_api %02x\n", TRACE(("PCI: class_base %02x, class_function %02x, class_api %02x\n",
info->class_base, info->class_sub, info->class_api)); info->class_base, info->class_sub, info->class_api));
@@ -48,6 +48,11 @@ pci_module_supports_device(device_node_handle parent, bool *_noConnection)
static status_t static status_t
pci_module_register_device(device_node_handle parent) pci_module_register_device(device_node_handle parent)
{ {
// XXX how do we handle this for PPC?
// I/O port for PCI config space address
#define PCI_CONFIG_ADDRESS 0xcf8
io_resource resources[2] = { io_resource resources[2] = {
{ IO_PORT, PCI_CONFIG_ADDRESS, 8 }, { IO_PORT, PCI_CONFIG_ADDRESS, 8 },
{} {}
@@ -140,22 +145,6 @@ pci_module_get_paths(const char ***_bus, const char ***_device)
} }
static uint32
pci_module_read_config(uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size)
{
return pci_read_config(bus, device, function, offset, size);
}
static void
pci_module_write_config(uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{
pci_write_config(bus, device, function, offset, size, value);
}
static status_t static status_t
pci_module_init(device_node_handle node, void *user_cookie, void **_cookie) pci_module_init(device_node_handle node, void *user_cookie, void **_cookie)
{ {
@@ -255,8 +244,8 @@ static struct pci_root_info sPCIModule = {
NULL, // rescan bus NULL, // rescan bus
}, },
pci_module_read_config, &pci_read_config,
pci_module_write_config &pci_write_config
}; };
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
@@ -16,11 +16,6 @@
// name of PCI device modules // name of PCI device modules
#define PCI_DEVICE_MODULE_NAME "bus_managers/pci/device_v1" #define PCI_DEVICE_MODULE_NAME "bus_managers/pci/device_v1"
// I/O port for PCI config space address
#define PCI_CONFIG_ADDRESS 0xcf8
// I/O port for PCI config space data
#define PCI_CONFIG_DATA 0xcfc
extern device_manager_info *gDeviceManager; extern device_manager_info *gDeviceManager;
@@ -42,30 +37,10 @@ typedef struct pci_root_info {
extern pci_device_module_info gPCIDeviceModule; extern pci_device_module_info gPCIDeviceModule;
extern spinlock gConfigLock;
extern int gMaxBusDevices;
extern bool gIrqRouterAvailable;
#define PCI_LOCK_CONFIG(cpu_status) \
{ \
cpu_status = disable_interrupts(); \
acquire_spinlock(&gConfigLock); \
}
#define PCI_UNLOCK_CONFIG(cpu_status) \
{ \
release_spinlock(&gConfigLock); \
restore_interrupts(cpu_status); \
}
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
status_t pci_config_init(void);
uint32 pci_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
void pci_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
void *pci_ram_address(const void *physical_address_in_system_memory); void *pci_ram_address(const void *physical_address_in_system_memory);
status_t pci_io_init(void); status_t pci_io_init(void);
@@ -76,10 +51,6 @@ void pci_write_io_16(int mapped_io_addr, uint16 value);
uint32 pci_read_io_32(int mapped_io_addr); uint32 pci_read_io_32(int mapped_io_addr);
void pci_write_io_32(int mapped_io_addr, uint32 value); void pci_write_io_32(int mapped_io_addr, uint32 value);
status_t pci_irq_init(void);
uint8 pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin);
void pci_write_irq(uint8 bus, uint8 device, uint8 function, uint8 pin, uint8 irq);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif