diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.c b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.c index 03ab869683..6eb2e3bce2 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.c @@ -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) { diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_irq.c b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_irq.c deleted file mode 100644 index bbe552d9d7..0000000000 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_irq.c +++ /dev/null @@ -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) -{ -} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile b/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile index 02e364fbff..8e0cfd8790 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile @@ -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 diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/bios.c b/src/add-ons/kernel/bus_managers/pci/arch/x86/bios.c deleted file mode 100644 index f308c5e485..0000000000 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/bios.c +++ /dev/null @@ -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) -{ -} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/bios.h b/src/add-ons/kernel/bus_managers/pci/arch/x86/bios.h deleted file mode 100644 index e279611024..0000000000 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/bios.h +++ /dev/null @@ -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); diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.c b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.c new file mode 100644 index 0000000000..dfd6dc9e3d --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.c @@ -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; +} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h new file mode 100644 index 0000000000..89807f1fd8 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h @@ -0,0 +1,18 @@ +#ifndef __PCI_X86_BIOS_H +#define __PCI_X86_BIOS_H + +#include + +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 diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c index d872854bbb..914286be8b 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c @@ -1,21 +1,16 @@ +/* + * Copyright 2006, Marcus Overhagen. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ + #include +#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; +} + + diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_irq.c b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_irq.c index bbe552d9d7..8c2d8a7063 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_irq.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_irq.c @@ -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) -{ -} diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_irq.h b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_irq.h new file mode 100644 index 0000000000..8b038c2685 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_irq.h @@ -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 + +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 diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp b/src/add-ons/kernel/bus_managers/pci/pci.cpp index fa3a6bf102..538aa4f75c 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2006, Marcus Overhagen. All rights reserved. * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. 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; +} + diff --git a/src/add-ons/kernel/bus_managers/pci/pci.h b/src/add-ons/kernel/bus_managers/pci/pci.h index 42a5cab987..10e5c70b69 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.h +++ b/src/add-ons/kernel/bus_managers/pci/pci.h @@ -1,4 +1,5 @@ /* + * Copyright 2006, Marcus Overhagen. All rights reserved. * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Copyright 2003, Marcus Overhagen. All rights reserved. * @@ -7,8 +8,7 @@ #ifndef __PCI_H__ #define __PCI_H__ - -#include +#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 } diff --git a/src/add-ons/kernel/bus_managers/pci/pci_info.cpp b/src/add-ons/kernel/bus_managers/pci/pci_info.cpp index ffc5cbfed2..17c85c2051 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_info.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci_info.cpp @@ -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)); diff --git a/src/add-ons/kernel/bus_managers/pci/pci_module.c b/src/add-ons/kernel/bus_managers/pci/pci_module.c index 11b55228d6..4a21f0774a 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_module.c +++ b/src/add-ons/kernel/bus_managers/pci/pci_module.c @@ -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[] = { diff --git a/src/add-ons/kernel/bus_managers/pci/pci_priv.h b/src/add-ons/kernel/bus_managers/pci/pci_priv.h index 808702b063..25828af25d 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_priv.h +++ b/src/add-ons/kernel/bus_managers/pci/pci_priv.h @@ -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