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
pci_config_init()
pci_controller_init(void)
{
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 *
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) ] ;
KernelStaticLibrary pci_arch_bus_manager :
bios.c
pci_bios.c
pci_controller.c
pci_io.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 "pci_irq.h"
#include "pci_bios.h"
#include "pci_priv.h"
#include "bios.h"
#include "pci_controller.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_DATA_PORT 0xCFC
#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) \
(uint16)(0xC00 | (dev << 8) | offset)
#define PCI_LOCK_CONFIG(cpu_status) \
{ \
cpu_status = disable_interrupts(); \
acquire_spinlock(&sConfigLock); \
}
status_t
pci_config_init(void)
#define PCI_UNLOCK_CONFIG(cpu_status) \
{ \
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()) {
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);
PCI_LOCK_CONFIG(cpu);
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
switch (size) {
case 1:
result = in8(PCI_MECH1_DATA_PORT + (offset & 3));
*value = in8(PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 2:
result = in16(PCI_MECH1_DATA_PORT + (offset & 3));
*value = in16(PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 4:
result = in32(PCI_MECH1_DATA_PORT);
*value = in32(PCI_MECH1_DATA_PORT);
break;
default:
result = 0xffffffff;
status = B_ERROR;
break;
}
PCI_UNLOCK_CONFIG(status);
return result;
PCI_UNLOCK_CONFIG(cpu);
return status;
}
void
pci_mech1_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value)
static status_t
pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{
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 write config for bus %u, device %u, function %u, offset %u, size %u\n",
bus, device, function, offset, size);
return;
}
cpu_status cpu;
status_t status = B_OK;
PCI_LOCK_CONFIG(status);
PCI_LOCK_CONFIG(cpu);
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
switch (size) {
case 1:
out8(value, PCI_MECH1_DATA_PORT + (offset & 3));
break;
break;
case 2:
out16(value, PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 4:
out32(value, PCI_MECH1_DATA_PORT);
break;
default:
status = B_ERROR;
break;
}
PCI_UNLOCK_CONFIG(status);
PCI_UNLOCK_CONFIG(cpu);
return status;
}
uint32
pci_mech2_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size)
static status_t
pci_mech1_get_max_bus_devices(void *cookie, int32 *count)
{
uint32 result;
cpu_status status;
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;
}
*count = 32;
return B_OK;
}
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(bus, PCI_MECH2_FORWARD_PORT);
switch (size) {
case 1:
result = in8(PCI_MECH2_CONFIG_PORT(device, offset));
*value = in8(PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 2:
result = in16(PCI_MECH2_CONFIG_PORT(device, offset));
*value = in16(PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 4:
result = in32(PCI_MECH2_CONFIG_PORT(device, offset));
*value = in32(PCI_MECH2_CONFIG_PORT(device, offset));
break;
default:
result = 0xffffffff;
status = B_ERROR;
break;
}
out8(0, PCI_MECH2_ENABLE_PORT);
PCI_UNLOCK_CONFIG(status);
return result;
PCI_UNLOCK_CONFIG(cpu);
return status;
}
void
pci_mech2_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value)
static status_t
pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{
cpu_status status;
if (device > 15 || function > 7 || (size != 1 && size != 2 && size != 4)) {
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;
}
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(bus, PCI_MECH2_FORWARD_PORT);
switch (size) {
@@ -235,9 +152,22 @@ pci_mech2_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, ui
case 4:
out32(value, PCI_MECH2_CONFIG_PORT(device, offset));
break;
default:
status = B_ERROR;
break;
}
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;
}
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;
}
uint8
pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin)
status_t
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 2003, Marcus Overhagen. All rights reserved.
*
@@ -14,32 +15,76 @@
#include "pci_priv.h"
#include "pci.h"
bool gIrqRouterAvailable = false;
spinlock gConfigLock = 0;
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
pci_init(void)
{
sPCI = new PCI;
if (pci_io_init() != B_OK) {
TRACE(("PCI: pci_io_init failed\n"));
return B_ERROR;
}
if (pci_config_init() != B_OK) {
TRACE(("PCI: pci_config_init failed\n"));
if (pci_controller_init() != B_OK) {
TRACE(("PCI: pci_controller_init failed\n"));
return B_ERROR;
}
if (pci_irq_init() != B_OK)
TRACE(("PCI: IRQ router not available\n"));
else
gIrqRouterAvailable = true;
sPCI = new PCI;
sPCI->InitDomainData();
sPCI->InitBus();
return B_OK;
}
@@ -52,22 +97,35 @@ pci_uninit(void)
}
long
pci_get_nth_pci_info(long index, pci_info *outInfo)
// #pragma mark PCI class
PCI::PCI()
: fRootBus(0)
, fDomainCount(0)
{
return sPCI->GetNthPciInfo(index, outInfo);
}
PCI::PCI()
void
PCI::InitBus()
{
fRootBus.parent = 0;
fRootBus.bus = 0;
fRootBus.child = 0;
PCIBus **ppnext = &fRootBus;
DiscoverBus(&fRootBus);
RefreshDeviceInfo(&fRootBus);
for (int i = 0; i < fDomainCount; i++) {
PCIBus *bus = new PCIBus;
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
PCI::GetNthPciInfo(long index, pci_info *outInfo)
{
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;
dev = dev->next;
}
if (bus->next)
return GetNthPciInfo(bus->next, curindex, wantindex, outInfo);
return B_ERROR;
}
@@ -106,49 +235,56 @@ PCI::GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInf
void
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++) {
uint16 vendor_id = pci_read_config(bus->bus, dev, 0, PCI_vendor_id, 2);
for (int dev = 0; dev < max_bus_devices; dev++) {
uint16 vendor_id = ReadPciConfig(bus->domain, bus->bus, dev, 0, PCI_vendor_id, 2);
if (vendor_id == 0xffff)
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;
for (int func = 0; func < nfunc; func++)
DiscoverDevice(bus, dev, func);
}
if (bus->next)
DiscoverBus(bus->next);
}
void
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)
return;
PCIDev *newdev = CreateDevice(bus, dev, func);
uint8 base_class = pci_read_config(bus->bus, dev, func, PCI_class_base, 1);
uint8 sub_class = pci_read_config(bus->bus, dev, func, PCI_class_sub, 1);
uint8 base_class = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_class_base, 1);
uint8 sub_class = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_class_sub, 1);
if (base_class == PCI_bridge && sub_class == PCI_pci) {
uint8 secondary_bus = pci_read_config(bus->bus, dev, func, PCI_secondary_bus, 1);
PCIBus *newbus = CreateBus(newdev, secondary_bus);
uint8 secondary_bus = ReadPciConfig(bus->domain, bus->bus, dev, func, PCI_secondary_bus, 1);
PCIBus *newbus = CreateBus(newdev, bus->domain, secondary_bus);
DiscoverBus(newbus);
}
}
PCIBus *
PCI::CreateBus(PCIDev *parent, uint8 bus)
PCI::CreateBus(PCIDev *parent, int domain, uint8 bus)
{
PCIBus *newbus = new PCIBus;
newbus->next = NULL;
newbus->parent = parent;
newbus->child = NULL;
newbus->domain = domain;
newbus->bus = bus;
newbus->child = 0;
// append
parent->child = newbus;
@@ -160,12 +296,13 @@ PCI::CreateBus(PCIDev *parent, uint8 bus)
PCIDev *
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;
newdev->next = 0;
newdev->next = NULL;
newdev->parent = parent;
newdev->child = 0;
newdev->child = NULL;
newdev->domain = parent->domain;
newdev->bus = parent->bus;
newdev->dev = dev;
newdev->func = func;
@@ -205,10 +342,10 @@ PCI::BarSize(uint32 bits, uint32 mask)
void
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);
pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, 0xffffffff);
uint32 newvalue = pci_read_config(dev->bus, dev->dev, dev->func, offset, 4);
pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
uint32 oldvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, 0xffffffff);
uint32 newvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
*address = oldvalue & PCI_address_memory_32_mask;
if (size)
@@ -221,10 +358,10 @@ PCI::GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uint8
void
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);
pci_write_config(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);
pci_write_config(dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
uint32 oldvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, 0xfffffffe); // LSB must be 0
uint32 newvalue = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4);
WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, offset, 4, oldvalue);
*address = oldvalue & PCI_rom_address_mask;
if (size)
@@ -237,20 +374,27 @@ PCI::GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size, uin
void
PCI::ReadPciBasicInfo(PCIDev *dev)
{
dev->info.vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_vendor_id, 2);
dev->info.device_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_device_id, 2);
dev->info.bus = dev->bus;
uint8 virt_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.function = dev->func;
dev->info.revision = pci_read_config(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_sub = pci_read_config(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.line_size = pci_read_config(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.revision = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_revision, 1);
dev->info.class_api = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_api, 1);
dev->info.class_sub = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_sub, 1);
dev->info.class_base = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_class_base, 1);
dev->info.line_size = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_line_size, 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)
dev->info.header_type = pci_read_config(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.header_type = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_header_type, 1);
dev->info.bist = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bist, 1);
dev->info.reserved = 0;
}
@@ -262,8 +406,8 @@ PCI::ReadPciHeaderInfo(PCIDev *dev)
case PCI_header_type_generic:
{
// 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);
pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
uint16 pcicmd = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2);
WritePciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
// get BAR size infos
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
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);
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.cardbus_cis = pci_read_config(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_vendor_id = pci_read_config(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_pin = pci_read_config(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.max_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_max_latency, 1);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subsystem_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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_line, 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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_min_grant, 1);
dev->info.u.h0.max_latency = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_max_latency, 1);
break;
}
case PCI_header_type_PCI_to_PCI_bridge:
{
// 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);
pci_write_config(dev->bus, dev->dev, dev->func, PCI_command, 2, pcicmd & ~(PCI_command_io | PCI_command_memory));
uint16 pcicmd = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_command, 2);
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);
for (int i = 0; i < 2; i++) {
@@ -307,56 +451,56 @@ PCI::ReadPciHeaderInfo(PCIDev *dev)
}
// 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);
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.primary_bus = pci_read_config(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.subordinate_bus = pci_read_config(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.io_base = pci_read_config(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.secondary_status = pci_read_config(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_limit = pci_read_config(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_limit = pci_read_config(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_limit_upper32 = pci_read_config(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_limit_upper16 = pci_read_config(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_pin = pci_read_config(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.subsystem_id = pci_read_config(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.primary_bus = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_primary_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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_subordinate_bus, 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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_base, 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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_status, 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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit, 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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit, 2);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_prefetchable_memory_limit_upper32, 4);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit_upper16, 2);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_interrupt_pin, 1);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_device_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;
}
case PCI_header_type_cardbus:
{
// 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_vendor_id = pci_read_config(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.secondary_bus = pci_read_config(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.secondary_latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_secondary_latency_2, 1);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_sub_vendor_id_2, 2);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_secondary_latency_2, 1);
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_limit = pci_read_config(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_limit_upper32 = pci_read_config(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_limit = pci_read_config(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_limit_upper32 = pci_read_config(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.bridge_control = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bridge_control_2, 1);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit0_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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_memory_limit1_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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit0_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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_io_limit1_2, 4);
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 = ReadPciConfig(dev->domain, dev->bus, dev->dev, dev->func, PCI_bridge_control_2, 1);
break;
}
@@ -376,4 +520,75 @@ PCI::RefreshDeviceInfo(PCIBus *bus)
if (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 2003, Marcus Overhagen. All rights reserved.
*
@@ -7,8 +8,7 @@
#ifndef __PCI_H__
#define __PCI_H__
#include <SupportDefs.h>
#include "pci_controller.h"
#define TRACE_PCI
@@ -21,38 +21,69 @@
#ifdef __cplusplus
struct PCIBus;
struct PCIDev;
struct PCIBus {
PCIBus *next;
PCIDev *parent;
uint8 bus;
PCIDev *child;
int domain;
uint8 bus;
};
struct PCIDev {
PCIDev *next;
PCIBus *parent;
PCIBus *child;
int domain;
uint8 bus;
uint8 dev;
uint8 func;
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 {
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:
void DiscoverBus(PCIBus *bus);
void DiscoverDevice(PCIBus *bus, 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);
void ReadPciBasicInfo(PCIDev *dev);
@@ -63,9 +94,19 @@ class PCI {
uint32 BarSize(uint32 bits, uint32 mask);
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);
domain_data * GetDomainData(int domain);
status_t AddVirtBus(int domain, uint8 bus, uint8 *virt_bus);
private:
PCIBus fRootBus;
PCIBus * fRootBus;
enum { MAX_PCI_DOMAINS = 8 };
domain_data fDomainData[MAX_PCI_DOMAINS];
int fDomainCount;
};
#endif // __cplusplus
@@ -75,10 +116,13 @@ class PCI {
extern "C" {
#endif
status_t pci_init(void);
void pci_uninit(void);
status_t pci_init(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
}
@@ -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.
*/
@@ -151,7 +151,9 @@ print_capabilities(const pci_info *info)
static void
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));
TRACE(("PCI: class_base %02x, class_function %02x, class_api %02x\n",
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
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_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
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
},
pci_module_read_config,
pci_module_write_config
&pci_read_config,
&pci_write_config
};
module_dependency module_dependencies[] = {
@@ -16,11 +16,6 @@
// name of PCI device modules
#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;
@@ -42,30 +37,10 @@ typedef struct pci_root_info {
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
extern "C" {
#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);
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);
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
}
#endif