bus_managers/pci: split PCI controller to separate add-on

busses/pci/x86: add
Other add-ons are in following commits.

Change-Id: I7a77bfaef0e8995917b4b54c8369d7075533ec26
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6220
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
X512
2023-04-25 15:54:32 +00:00
committed by waddlesplash
parent 97b7c7719d
commit a23ac85fa9
67 changed files with 989 additions and 4974 deletions
+2
View File
@@ -30,6 +30,7 @@ AddFilesToPackage add-ons kernel busses ata
AddFilesToPackage add-ons kernel busses i2c : pch_i2c@x86,x86_64 ; AddFilesToPackage add-ons kernel busses i2c : pch_i2c@x86,x86_64 ;
AddFilesToPackage add-ons kernel busses mmc : sdhci_pci ; AddFilesToPackage add-ons kernel busses mmc : sdhci_pci ;
AddFilesToPackage add-ons kernel busses pci : <pci>x86@x86,x86_64 ;
AddFilesToPackage add-ons kernel busses random : ccp_rng@x86,x86_64 virtio_rng ; AddFilesToPackage add-ons kernel busses random : ccp_rng@x86,x86_64 virtio_rng ;
AddFilesToPackage add-ons kernel busses scsi : ahci virtio_scsi ; AddFilesToPackage add-ons kernel busses scsi : ahci virtio_scsi ;
AddFilesToPackage add-ons kernel busses usb : <usb>uhci <usb>ohci <usb>ehci AddFilesToPackage add-ons kernel busses usb : <usb>uhci <usb>ohci <usb>ehci
@@ -197,6 +198,7 @@ AddBootModuleSymlinksToPackage
nvme_disk nvme_disk
openpic@ppc openpic@ppc
packagefs pci packagefs pci
<pci>x86@x86,x86_64
fdt@riscv64,arm,arm64 fdt@riscv64,arm,arm64
scsi scsi_cd scsi_disk scsi_periph silicon_image_3112 highpoint_ide_pci scsi scsi_cd scsi_disk scsi_periph silicon_image_3112 highpoint_ide_pci
sdhci_pci sdhci_pci
+48
View File
@@ -58,6 +58,54 @@ typedef struct pci_device_module_info {
} pci_device_module_info; } pci_device_module_info;
enum {
kPciRangeInvalid = 0,
kPciRangeIoPort = 1,
kPciRangeMmio = 2,
kPciRangeMmio64Bit = 1 << 0,
kPciRangeMmioPrefetch = 1 << 1,
kPciRangeMmioEnd = 6,
kPciRangeEnd = 6,
};
typedef struct pci_resource_range {
uint32 type;
phys_addr_t host_addr;
phys_addr_t pci_addr;
uint64 size;
} pci_resource_range;
typedef struct pci_controller_module_info {
driver_module_info info;
// read PCI config space
status_t (*read_pci_config)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value);
// write PCI config space
status_t (*write_pci_config)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value);
status_t (*get_max_bus_devices)(void *cookie, int32 *count);
status_t (*read_pci_irq)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 *irq);
status_t (*write_pci_irq)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq);
status_t (*get_range)(void *cookie, uint32 index, pci_resource_range *range);
status_t (*finalize)(void *cookie);
} pci_controller_module_info;
/* Attributes of PCI device nodes */ /* Attributes of PCI device nodes */
#define B_PCI_DEVICE_DOMAIN "pci/domain" /* uint32 */ #define B_PCI_DEVICE_DOMAIN "pci/domain" /* uint32 */
#define B_PCI_DEVICE_BUS "pci/bus" /* uint8 */ #define B_PCI_DEVICE_BUS "pci/bus" /* uint8 */
+2 -5
View File
@@ -3,16 +3,16 @@ SubDir HAIKU_TOP src add-ons kernel bus_managers pci ;
UsePrivateKernelHeaders ; UsePrivateKernelHeaders ;
UsePrivateHeaders shared ; UsePrivateHeaders shared ;
UsePrivateHeaders [ FDirName kernel util ] ; UsePrivateHeaders [ FDirName kernel util ] ;
UseHeaders [ FDirName $(SUBDIR) arch $(TARGET_KERNEL_ARCH_DIR) ] ;
KernelAddon pci : KernelAddon pci :
pci.cpp pci.cpp
pci_fixup.cpp pci_fixup.cpp
pci_info.cpp pci_info.cpp
pci_io.cpp
pci_module.cpp pci_module.cpp
pci_root.cpp pci_root.cpp
pci_device.cpp pci_device.cpp
: pci_arch_bus_manager.a :
; ;
# pci_info.cpp currently needs pcihdr.h so we make its path available and adds dependency # pci_info.cpp currently needs pcihdr.h so we make its path available and adds dependency
@@ -20,6 +20,3 @@ ObjectHdrs [ FGristFiles pci_info$(SUFOBJ) ]
: [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) apps : [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) apps
devices ] ; devices ] ;
Includes [ FGristFiles pci_info.cpp ] : <src!apps!devices>pcihdr.h ; Includes [ FGristFiles pci_info.cpp ] : <src!apps!devices>pcihdr.h ;
SubInclude HAIKU_TOP src add-ons kernel bus_managers pci arch
$(TARGET_KERNEL_ARCH_DIR) ;
@@ -1,18 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch $(TARGET_ARCH) ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateKernelHeaders ;
UsePrivateHeaders [ FDirName kernel util ] ;
UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ]
[ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ;
SubDirHdrs $(HAIKU_TOP) src system kernel arch generic ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
KernelStaticLibrary pci_arch_bus_manager :
pci_controller.cpp
pci_ecam.cpp
pci_io.cpp
;
@@ -1,18 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch $(TARGET_ARCH) ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateKernelHeaders ;
UsePrivateHeaders [ FDirName kernel util ] ;
UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ]
[ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ;
SubDirHdrs $(HAIKU_TOP) src system kernel arch generic ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
KernelStaticLibrary pci_arch_bus_manager :
pci_controller.cpp
pci_io.cpp
pci_ecam.cpp
;
@@ -1,398 +0,0 @@
/*
* Copyright 2009-2022, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <kernel/debug.h>
#include <kernel/int.h>
#include <util/Vector.h>
#include <AutoDeleterDrivers.h>
#include "pci_private.h"
#include "pci.h"
#include <ACPI.h> // module
#include <acpi.h>
#include <drivers/bus/FDT.h>
#include "acpi_irq_routing_table.h"
addr_t gPCIeBase;
uint8 gStartBusNumber;
uint8 gEndBusNumber;
addr_t gPCIioBase;
extern pci_controller pci_controller_ecam;
enum RangeType
{
RANGE_IO,
RANGE_MEM
};
struct PciRange
{
RangeType type;
phys_addr_t hostAddr;
phys_addr_t pciAddr;
size_t length;
};
static Vector<PciRange> *sRanges;
template<typename T>
acpi_address64_attribute AcpiCopyAddressAttr(const T &src)
{
acpi_address64_attribute dst;
dst.granularity = src.granularity;
dst.minimum = src.minimum;
dst.maximum = src.maximum;
dst.translation_offset = src.translation_offset;
dst.address_length = src.address_length;
return dst;
}
static acpi_status
AcpiCrsScanCallback(acpi_resource *res, void *context)
{
Vector<PciRange> &ranges = *(Vector<PciRange>*)context;
acpi_address64_attribute address;
if (res->type == ACPI_RESOURCE_TYPE_ADDRESS16)
address = AcpiCopyAddressAttr(res->data.address16.address);
else if (res->type == ACPI_RESOURCE_TYPE_ADDRESS32)
address = AcpiCopyAddressAttr(res->data.address32.address);
else if (res->type == ACPI_RESOURCE_TYPE_ADDRESS64)
address = AcpiCopyAddressAttr(res->data.address64.address);
else
return B_OK;
acpi_resource_address &common = res->data.address;
if (common.resource_type != 0 && common.resource_type != 1)
return B_OK;
ASSERT(address.minimum + address.address_length - 1 == address.maximum);
PciRange range;
range.type = (common.resource_type == 0 ? RANGE_MEM : RANGE_IO);
range.hostAddr = address.minimum + address.translation_offset;
range.pciAddr = address.minimum;
range.length = address.address_length;
ranges.PushBack(range);
return B_OK;
}
static bool
is_interrupt_available(int32 gsi)
{
return true;
}
status_t
pci_controller_init(void)
{
if (gPCIRootNode == NULL)
return B_DEV_NOT_READY;
dprintf("PCI: pci_controller_init\n");
DeviceNodePutter<&gDeviceManager>
parent(gDeviceManager->get_parent_node(gPCIRootNode));
if (parent.Get() == NULL)
return B_ERROR;
const char *bus;
if (gDeviceManager->get_attr_string(parent.Get(), B_DEVICE_BUS, &bus, false) < B_OK)
return B_ERROR;
if (strcmp(bus, "fdt") == 0) {
dprintf("initialize PCI controller from FDT\n");
status_t res;
fdt_device_module_info* parentModule;
fdt_device* parentDev;
res = gDeviceManager->get_driver(parent.Get(),
(driver_module_info**)&parentModule, (void**)&parentDev);
if (res != B_OK) {
dprintf("can't get parent node driver\n");
return B_ERROR;
}
uint64 configRegs = 0;
uint64 configRegsLen = 0;
parentModule->get_reg(parentDev, 0, &configRegs, &configRegsLen);
dprintf(" configRegs: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n",
configRegs, configRegsLen);
area_id area = map_physical_memory("pci config",
configRegs, configRegsLen, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIeBase);
if (area < 0)
return B_ERROR;
sRanges = new Vector<PciRange>();
int rangesLen;
const void* rangesAddr = parentModule->get_prop(parentDev, "ranges",
&rangesLen);
if (rangesAddr == NULL) {
dprintf(" ranges property not found\n");
return B_ERROR;
}
for (uint32_t *it = (uint32_t*)rangesAddr;
(uint8_t*)it - (uint8_t*)rangesAddr < rangesLen; it += 7) {
uint32_t kind = B_BENDIAN_TO_HOST_INT32(*(it + 0));
uint64_t childAddr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 1));
uint64_t parentAddr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3));
uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5));
PciRange range;
range.type = ((kind & 0x03000000) == 0x01000000) ? RANGE_IO : RANGE_MEM;
range.hostAddr = parentAddr;
range.pciAddr = childAddr;
range.length = len;
sRanges->PushBack(range);
if ((kind & 0x03000000) != 0x01000000)
continue;
dprintf(" (0x%08" B_PRIx32 "): ", kind);
dprintf("child: %08" B_PRIx64, childAddr);
dprintf(", parent: %08" B_PRIx64, parentAddr);
dprintf(", len: %" B_PRIx64 "\n", len);
area_id area = map_physical_memory("pci io",
parentAddr, len, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIioBase);
if (area < 0)
return B_ERROR;
}
gStartBusNumber = 0;
gEndBusNumber = 0xff;
return pci_controller_add(&pci_controller_ecam, NULL);
}
if (strcmp(bus, "acpi") == 0) {
dprintf("initialize PCI controller from ACPI\n");
status_t res;
acpi_module_info *acpiModule;
acpi_device_module_info *acpiDeviceModule;
acpi_device acpiDevice;
res = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
if (res != B_OK)
return B_ERROR;
acpi_mcfg *mcfg;
res = acpiModule->get_table(ACPI_MCFG_SIGNATURE, 0, (void**)&mcfg);
if (res != B_OK)
return B_ERROR;
res = gDeviceManager->get_driver(parent.Get(),
(driver_module_info**)&acpiDeviceModule, (void**)&acpiDevice);
if (res != B_OK)
return B_ERROR;
sRanges = new Vector<PciRange>();
acpi_status acpi_res = acpiDeviceModule->walk_resources(acpiDevice,
(char *)"_CRS", AcpiCrsScanCallback, sRanges);
if (acpi_res != 0)
return B_ERROR;
for (Vector<PciRange>::Iterator it = sRanges->Begin(); it != sRanges->End(); it++) {
if (it->type != RANGE_IO)
continue;
if (gPCIioBase != 0) {
dprintf("PCI: multiple io ranges not supported!");
continue;
}
area_id area = map_physical_memory("pci io",
it->hostAddr, it->length, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIioBase);
if (area < 0)
return B_ERROR;
}
acpi_mcfg_allocation *end = (acpi_mcfg_allocation *) ((char*)mcfg + mcfg->header.length);
acpi_mcfg_allocation *alloc = (acpi_mcfg_allocation *) (mcfg + 1);
if (alloc + 1 != end)
dprintf("PCI: multiple host bridges not supported!");
for (; alloc < end; alloc++) {
dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: %x, end: %x\n",
alloc->address, alloc->pci_segment, alloc->start_bus_number, alloc->end_bus_number);
if (alloc->pci_segment != 0) {
dprintf("PCI: multiple segments not supported!");
continue;
}
gStartBusNumber = alloc->start_bus_number;
gEndBusNumber = alloc->end_bus_number;
area_id area = map_physical_memory("pci config",
alloc->address, (gEndBusNumber - gStartBusNumber + 1) << 20, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gPCIeBase);
if (area < 0)
break;
dprintf("PCI: ecam controller found\n");
return pci_controller_add(&pci_controller_ecam, NULL);
}
}
return B_ERROR;
}
static void
pci_controller_finalize_interrupts(fdt_device_module_info* fdtModule, struct fdt_interrupt_map* interruptMap,
int bus, int device, int function)
{
uint32 childAddr = ((bus & 0xff) << 16) | ((device & 0x1f) << 11) | ((function & 0x07) << 8);
uint32 interruptPin = pci_read_config(bus, device, function, PCI_interrupt_pin, 1);
if (interruptPin == 0xffffffff) {
dprintf("Error: Unable to read interrupt pin!\n");
return;
}
uint32 irq = fdtModule->lookup_interrupt_map(interruptMap, childAddr, interruptPin);
if (irq == 0xffffffff) {
dprintf("no interrupt mapping for childAddr: (%d:%d:%d), childIrq: %d)\n",
bus, device, function, interruptPin);
} else {
dprintf("configure interrupt (%d,%d,%d) --> %d\n",
bus, device, function, irq);
pci_update_interrupt_line(bus, device, function, irq);
}
}
status_t
pci_controller_finalize(void)
{
DeviceNodePutter<&gDeviceManager>
parent(gDeviceManager->get_parent_node(gPCIRootNode));
if (parent.Get() == NULL)
return B_ERROR;
const char* bus;
if (gDeviceManager->get_attr_string(parent.Get(), B_DEVICE_BUS, &bus, false) < B_OK)
return B_ERROR;
if (strcmp(bus, "fdt") == 0) {
dprintf("finalize PCI controller from FDT\n");
status_t res;
fdt_device_module_info* parentModule;
fdt_device* parentDev;
res = gDeviceManager->get_driver(parent.Get(),
(driver_module_info**)&parentModule, (void**)&parentDev);
if (res != B_OK) {
dprintf("can't get parent node driver\n");
return B_ERROR;
}
struct fdt_interrupt_map* interruptMap = parentModule->get_interrupt_map(parentDev);
parentModule->print_interrupt_map(interruptMap);
for (int bus = 0; bus < 8; bus++) {
for (int device = 0; device < 32; device++) {
uint32 vendorID = pci_read_config(bus, device, 0, PCI_vendor_id, 2);
if ((vendorID != 0xffffffff) && (vendorID != 0xffff)) {
uint32 headerType = pci_read_config(bus, device, 0, PCI_header_type, 1);
if ((headerType & 0x80) != 0) {
for (int function = 0; function < 8; function++) {
pci_controller_finalize_interrupts(parentModule, interruptMap, bus, device, function);
}
} else {
pci_controller_finalize_interrupts(parentModule, interruptMap, bus, device, 0);
}
}
}
}
return B_OK;
}
if (strcmp(bus, "acpi") == 0) {
dprintf("finalize PCI controller from ACPI\n");
status_t res;
acpi_module_info *acpiModule;
res = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
if (res != B_OK)
return B_ERROR;
IRQRoutingTable table;
res = prepare_irq_routing(acpiModule, table, &is_interrupt_available);
if (res != B_OK) {
dprintf("PCI: irq routing preparation failed\n");
return B_ERROR;
}
res = enable_irq_routing(acpiModule, table);
if (res != B_OK) {
dprintf("PCI: irq routing failed\n");
return B_ERROR;
}
print_irq_routing_table(table);
return B_OK;
}
return B_ERROR;
}
phys_addr_t
pci_ram_address(phys_addr_t addr)
{
for (Vector<PciRange>::Iterator it = sRanges->Begin(); it != sRanges->End(); it++) {
if (addr >= it->pciAddr && addr < it->pciAddr + it->length) {
phys_addr_t result = addr - it->pciAddr;
if (it->type != RANGE_IO)
result += it->hostAddr;
return result;
}
}
dprintf("PCI: requested translation of invalid address %" B_PRIxPHYSADDR "\n", addr);
return 0;
}
@@ -1,112 +0,0 @@
/*
* Copyright 2009-2022, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <kernel/debug.h>
extern addr_t gPCIeBase;
extern uint8 gStartBusNumber;
extern uint8 gEndBusNumber;
#define PCIE_VADDR(base, bus, slot, func, reg) \
((base) + ((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) \
| (((func) & 0x7) << 12) | ((reg) & 0xfff)))
static status_t
read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
if (!(bus >= gStartBusNumber && bus <= gEndBusNumber))
return B_ERROR;
status_t status = B_OK;
addr_t address = PCIE_VADDR(gPCIeBase, bus - gStartBusNumber, device, function, offset);
switch (size) {
case 1:
*value = *(uint8*)address;
break;
case 2:
*value = *(uint16*)address;
break;
case 4:
*value = *(uint32*)address;
break;
default:
status = B_ERROR;
break;
}
return status;
}
static status_t
write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
if (!(bus >= gStartBusNumber && bus <= gEndBusNumber))
return B_ERROR;
status_t status = B_OK;
addr_t address = PCIE_VADDR(gPCIeBase, bus - gStartBusNumber, device, function, offset);
switch (size) {
case 1:
*(uint8*)address = value;
break;
case 2:
*(uint16*)address = value;
break;
case 4:
*(uint32*)address = value;
break;
default:
status = B_ERROR;
break;
}
return status;
}
static status_t
get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
static status_t
read_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, uint8 pin,
uint8 *irq)
{
dprintf("read_pci_irq\n");
return B_NOT_SUPPORTED;
}
static status_t
write_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, uint8 pin,
uint8 irq)
{
dprintf("write_pci_irq\n");
return B_NOT_SUPPORTED;
}
pci_controller pci_controller_ecam =
{
read_pci_config,
write_pci_config,
get_max_bus_devices,
read_pci_irq,
write_pci_irq,
};
@@ -1,80 +0,0 @@
/*
* Copyright 2022, Haiku Inc.
* Distributed under the terms of the MIT License.
*/
#include <SupportDefs.h>
#include "pci_private.h"
//#define TRACE_PCI_IO
#ifdef TRACE_PCI_IO
# define TRACE(x...) dprintf("PCI_IO: " x)
#else
# define TRACE(x...) ;
#endif
extern addr_t gPCIioBase;
status_t
pci_io_init()
{
TRACE("pci_io_init()\n");
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
TRACE("pci_read_io_8(%d)\n", mapped_io_addr);
volatile uint8* ptr = (uint8*)(gPCIioBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
TRACE("pci_write_io_8(%d)\n", mapped_io_addr);
volatile uint8* ptr = (uint8*)(gPCIioBase + mapped_io_addr);
*ptr = value;
}
uint16
pci_read_io_16(int mapped_io_addr)
{
TRACE("pci_read_io_16(%d)\n", mapped_io_addr);
volatile uint16* ptr = (uint16*)(gPCIioBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
TRACE("pci_write_io_16(%d)\n", mapped_io_addr);
volatile uint16* ptr = (uint16*)(gPCIioBase + mapped_io_addr);
*ptr = value;
}
uint32
pci_read_io_32(int mapped_io_addr)
{
TRACE("pci_read_io_32(%d)\n", mapped_io_addr);
volatile uint32* ptr = (uint32*)(gPCIioBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
TRACE("pci_write_io_32(%d)\n", mapped_io_addr);
volatile uint32* ptr = (uint32*)(gPCIioBase + mapped_io_addr);
*ptr = value;
}
@@ -1,19 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch m68k ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ]
[ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) amiga ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) apple ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) atari ] ;
KernelStaticLibrary pci_arch_bus_manager :
pci_controller.cpp
pci_io.c
# platforms
pci_amiga.cpp
pci_apple.cpp
pci_atari.cpp
;
@@ -1,23 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "pci_amiga.h"
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
status_t
m68k_amiga_pci_controller_init(void)
{
return B_OK;
}
// #pragma mark - support functions
@@ -1,13 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_M68K_AMIGA_H
#define PCI_BUS_MANAGER_M68K_AMIGA_H
#include <SupportDefs.h>
status_t m68k_amiga_pci_controller_init(void);
#endif // PCI_BUS_MANAGER_M68K_AMIGA_H
@@ -1,23 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "pci_apple.h"
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
status_t
m68k_apple_pci_controller_init(void)
{
return B_OK;
}
// #pragma mark - support functions
@@ -1,13 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_M68K_APPLE_H
#define PCI_BUS_MANAGER_M68K_APPLE_H
#include <SupportDefs.h>
status_t m68k_apple_pci_controller_init(void);
#endif // PCI_BUS_MANAGER_M68K_APPLE_H
@@ -1,281 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "pci_atari.h"
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include <PCI.h>
#include "pci_controller.h"
/*
* Here we fake a PCI bus that maps the physical memory
* (which is also I/O on 68k), and fake some system devices.
* Some other devices are faked as ISA because they need DMA
* notification.
*
* TODO: anything to be done to support VME cards ?
* I don't think they are PnP at all anyway.
*
* TODO: On Hades/Milan clones a real PCI bus is accessible
* through PAE-like extra bits in page descriptors. This one
* should be handled in a separate file.
*/
//XXX:find one and put in shared priv header!
// 0x68xx is free according to pci.ids
// 68fx (f=fake) x = 0:amiga, 1:apple, 2:atari
#define FAKEV 0x68f2
// bus number
#define BN 0
// default line size
#define DLL 1
// default latency
#define DL 0
// default header_type
#define DH PCI_header_type_generic
// default bist
#define DB 0
#define PEI 0
#define INVV 0xffff //0x0000 ??
#define INVD 0xffff
struct fake_pci_device {
pci_info info;
};
static struct fake_pci_device gFakePCIDevices[] = {
{ {FAKEV, 0x0000, BN, 0, 0, 0, 0xff, PCI_host, PCI_bridge, DLL, DL, DH, DB, 0, PEI }}, /* cpu */
{ {FAKEV, 0x0001, BN, 1, 0, 0, 0xff, 0x68/*fake*/, PCI_processor, DLL, DL, DH, DB, 0, PEI }}, /* cpu */
{ {FAKEV, 0x0002, BN, 2, 0, 0, 0xff, PCI_display_other, PCI_display, DLL, DL, DH, DB, 0, /*0xFFFF8200,*/ PEI }}, /* gfx */
{ {FAKEV, 0x0003, BN, 3, 0, 0, 0xff, PCI_ide, PCI_mass_storage, DLL, DL, DH, DB, 0, /*0xFFF00000,*/ PEI }}, /* ide */
{ {FAKEV, 0x0004, BN, 4, 0, 0, 0xff, PCI_scsi, PCI_mass_storage, DLL, DL, DH, DB, 0, PEI }}, /* scsi */
{ {FAKEV, 0x0005, BN, 5, 0, 0, 0xff, 0x0/*CHANGEME*/, PCI_multimedia, DLL, DL, DH, DB, /*0x00,*/ 0, /*0xFFFF8900,*/ PEI }}, /* snd */
//UART ?
//centronics?
{ {INVV, INVD} }
};
#define FAKE_DEVICES_COUNT (sizeof(gFakePCIDevices)/sizeof(struct fake_pci_device)-1)
struct m68k_atari_fake_host_bridge {
uint32 bus;
};
#define out8rb(address, value) m68k_out8((vuint8*)(address), value)
#define out16rb(address, value) m68k_out16_reverse((vuint16*)(address), value)
#define out32rb(address, value) m68k_out32_reverse((vuint32*)(address), value)
#define in8rb(address) m68k_in8((const vuint8*)(address))
#define in16rb(address) m68k_in16_reverse((const vuint16*)(address))
#define in32rb(address) m68k_in32_reverse((const vuint32*)(address))
static int m68k_atari_enable_config(struct m68k_atari_fake_host_bridge *bridge,
uint8 bus, uint8 slot, uint8 function, uint8 offset);
static status_t m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device,
uint8 function, uint16 offset, uint8 size, uint32 *value);
static status_t m68k_atari_write_pci_config(void *cookie, uint8 bus,
uint8 device, uint8 function, uint16 offset, uint8 size,
uint32 value);
static status_t m68k_atari_get_max_bus_devices(void *cookie, int32 *count);
static status_t m68k_atari_read_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 *irq);
static status_t m68k_atari_write_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 irq);
static pci_controller sM68kAtariPCIController = {
m68k_atari_read_pci_config,
m68k_atari_write_pci_config,
m68k_atari_get_max_bus_devices,
m68k_atari_read_pci_irq,
m68k_atari_write_pci_irq,
};
static status_t
m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
struct fake_pci_device *devices = (struct fake_pci_device *)cookie;
struct fake_pci_device *dev;
if (bus != 0)
return EINVAL;
if (device >= FAKE_DEVICES_COUNT)
return EINVAL;
if (function != 0)
return EINVAL;
dev = &devices[device];
#define O(pn,n,s) \
case pn: \
if (size != s) { \
panic("invalid pci config size %d for offset %d", size, offset); \
return EINVAL; \
} \
*value = dev->info.n; \
return B_OK
if (1) {
switch (offset) {
O(PCI_vendor_id, vendor_id, 2);
O(PCI_device_id, device_id, 2);
O(PCI_revision, revision, 1);
O(PCI_class_api, class_api, 1);
O(PCI_class_sub, class_sub, 1);
O(PCI_class_base, class_base, 1);
O(PCI_line_size, line_size, 1);
O(PCI_latency, latency, 1);
O(PCI_header_type, header_type, 1);
O(PCI_bist, bist, 1);
}
}
//#undef O
#if 0
#define PCI_command 0x04 /* (2 byte) command */
#define PCI_status 0x06 /* (2 byte) status */
#endif
if (dev->info.header_type == 0x00 || dev->info.header_type == 0x01) {
switch (offset) {
case PCI_base_registers:
return EINVAL;
O(PCI_interrupt_line, u.h0.interrupt_line, 1);
O(PCI_interrupt_pin, u.h0.interrupt_pin, 1);
default:
break;
}
}
if (dev->info.header_type == 0x00) {
switch (offset) {
default:
break;
}
}
if (dev->info.header_type == 0x01) {
switch (offset) {
O(PCI_primary_bus, u.h1.primary_bus, 1);
O(PCI_secondary_bus, u.h1.secondary_bus, 1);
O(PCI_subordinate_bus, u.h1.subordinate_bus, 1);
O(PCI_secondary_latency, u.h1.secondary_latency, 1);
default:
break;
}
}
*value = 0xffffffff;
panic("invalid pci config offset %d", offset);
return EINVAL;
//return B_OK;
}
static status_t
m68k_atari_write_pci_config(void *cookie, uint8 bus, uint8 device,
uint8 function, uint16 offset, uint8 size, uint32 value)
{
#if 0
if (m68k_atari_enable_config(bridge, bus, device, function, offset)) {
switch (size) {
case 1:
out8rb(caoff, (uint8)value);
(void)in8rb(caoff);
break;
case 2:
out16rb(caoff, (uint16)value);
(void)in16rb(caoff);
break;
case 4:
out32rb(caoff, value);
(void)in32rb(caoff);
break;
}
}
#endif
panic("write pci config dev %d offset %d", device, offset);
return B_ERROR;
return B_OK;
}
static status_t
m68k_atari_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
static status_t
m68k_atari_read_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 *irq)
{
#warning M68K: WRITEME
return B_ERROR;
}
static status_t
m68k_atari_write_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 irq)
{
#warning M68K: WRITEME
return B_ERROR;
}
// #pragma mark -
static int
m68k_atari_enable_config(struct m68k_atari_fake_host_bridge *bridge, uint8 bus,
uint8 slot, uint8 function, uint8 offset)
{
#warning M68K: WRITEME
return 0;
}
// #pragma mark -
status_t
m68k_atari_pci_controller_init(void)
{
struct m68k_atari_fake_host_bridge *bridge;
bridge = (struct m68k_atari_fake_host_bridge *)
malloc(sizeof(struct m68k_atari_fake_host_bridge));
if (!bridge)
return B_NO_MEMORY;
bridge->bus = 0;
status_t error = pci_controller_add(&sM68kAtariPCIController, bridge);
if (error != B_OK)
free(bridge);
// TODO: probe Hades & Milan bridges
return error;
}
// #pragma mark - support functions
@@ -1,13 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_M68K_ATARI_H
#define PCI_BUS_MANAGER_M68K_ATARI_H
#include <SupportDefs.h>
status_t m68k_atari_pci_controller_init(void);
#endif // PCI_BUS_MANAGER_M68K_ATARI_H
@@ -1,51 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <arch_platform.h>
#include "pci_private.h"
/*
* As we don't have any real PCI bus in any of the supported m68k platforms,
* we fake one, with hardcoded devices.
* TODO: this doesn't make any sense, as we can't share any drivers, anyway.
* We should better export dedicated bus managers for Zorro etc. busses on
* these systems.
* TODO: actually, there are several PCI boards for the Amiga.
*/
#include "amiga/pci_amiga.h"
#include "apple/pci_apple.h"
#include "atari/pci_atari.h"
status_t
pci_controller_init(void)
{
switch (M68KPlatform::Default()->PlatformType()) {
/* case M68K_PLATFORM_AMIGA:
return m68k_amiga_pci_controller_init();
break;
case M68K_PLATFORM_APPLE:
return m68k_apple_pci_controller_init();
break;*/
case M68K_PLATFORM_ATARI:
return m68k_atari_pci_controller_init();
break;
default:
return EINVAL;
}
return B_OK;
}
phys_addr_t
pci_ram_address(phys_addr_t physical_address_in_system_memory)
{
return physical_address_in_system_memory;
}
@@ -1,57 +0,0 @@
/*
* Copyright 2007, François Revol <[email protected]>.
* Distributed under the terms of the MIT License.
*/
#include "pci_io.h"
#include "pci_private.h"
status_t
pci_io_init()
{
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
return m68k_in8((vuint8*)mapped_io_addr);
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
m68k_out8((vuint8*)mapped_io_addr, value);
}
uint16
pci_read_io_16(int mapped_io_addr)
{
return m68k_in16((vuint16*)mapped_io_addr);
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
m68k_out16((vuint16*)mapped_io_addr, value);
}
uint32
pci_read_io_32(int mapped_io_addr)
{
return m68k_in32((vuint32*)mapped_io_addr);
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
m68k_out32((vuint32*)mapped_io_addr, value);
}
@@ -1,106 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_M68K_IO_H
#define PCI_BUS_MANAGER_M68K_IO_H
#include <SupportDefs.h>
#define IOBARRIER() asm volatile("nop") /* nop flushes the instruction pipeline */
/*XXX: sync cache/pmmu?*/
static inline void
m68k_out8(vuint8 *address, uint8 value)
{
*address = value;
IOBARRIER();
}
static inline void
m68k_out16(vuint16 *address, uint16 value)
{
*address = value;
IOBARRIER();
}
#if _XXX_HAS_REVERSE_IO
static inline void
m68k_out16_reverse(vuint16 *address, uint16 value)
{
asm volatile("sthbrx %1, 0, %0" : : "r"(address), "r"(value));
IOBARRIER();
}
#endif
static inline void
m68k_out32(vuint32 *address, uint32 value)
{
*address = value;
IOBARRIER();
}
#if _XXX_HAS_REVERSE_IO
static inline void
m68k_out32_reverse(vuint32 *address, uint32 value)
{
asm volatile("stwbrx %1, 0, %0" : : "r"(address), "r"(value));
IOBARRIER();
}
#endif
static inline uint8
m68k_in8(const vuint8 *address)
{
uint8 value = *address;
IOBARRIER();
return value;
}
static inline uint16
m68k_in16(const vuint16 *address)
{
uint16 value = *address;
IOBARRIER();
return value;
}
#if _XXX_HAS_REVERSE_IO
static inline uint16
m68k_in16_reverse(const vuint16 *address)
{
uint16 value;
asm volatile("lhbrx %0, 0, %1" : "=r"(value) : "r"(address));
IOBARRIER();
return value;
}
#endif
static inline uint32
m68k_in32(const vuint32 *address)
{
uint32 value = *address;
IOBARRIER();
return value;
}
#if _XXX_HAS_REVERSE_IO
static inline uint32
m68k_in32_reverse(const vuint32 *address)
{
uint32 value;
asm volatile("lwbrx %0, 0, %1" : "=r"(value) : "r"(address));
IOBARRIER();
return value;
}
#endif
#endif // PCI_BUS_MANAGER_M68K_IO_H
@@ -1,21 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch ppc ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ]
[ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) openfirmware ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) u-boot ] ;
KernelStaticLibrary pci_arch_bus_manager :
pci_controller.cpp
pci_io.c
# openfirmware
pci_openfirmware.cpp
uninorth.cpp
grackle.cpp
# U-Boot
pci_u-boot.cpp
;
@@ -1,254 +0,0 @@
/*
* Copyright 2010 Andreas Färber <[email protected]>
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
/*-
* Copyright (c) 2000 Tsubai Masanari. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <KernelExport.h>
#include <platform/openfirmware/devices.h>
#include <platform/openfirmware/openfirmware.h>
#include <platform/openfirmware/pci.h>
#include "pci_controller.h"
#include "pci_io.h"
#include "pci_openfirmware_priv.h"
//#define TRACE_GRACKLE
#ifdef TRACE_GRACKLE
#define TRACE(fmt...) dprintf(fmt)
#else
#define TRACE(fmt...) ;
#endif
struct grackle_range {
uint32_t pci_hi;
uint32_t pci_mid;
uint32_t pci_lo;
uint32_t host;
uint32_t size_hi;
uint32_t size_lo;
};
struct grackle_host_bridge {
int device_node;
addr_t address_registers;
addr_t data_registers;
uint32 bus;
struct grackle_range ranges[6];
int range_count;
};
#define out8rb(address, value) ppc_out8((vuint8*)(address), value)
#define out16rb(address, value) ppc_out16_reverse((vuint16*)(address), value)
#define out32rb(address, value) ppc_out32_reverse((vuint32*)(address), value)
#define in8rb(address) ppc_in8((const vuint8*)(address))
#define in16rb(address) ppc_in16_reverse((const vuint16*)(address))
#define in32rb(address) ppc_in32_reverse((const vuint32*)(address))
static status_t
grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
grackle_host_bridge *bridge = (grackle_host_bridge*)cookie;
TRACE("grackle_read_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
"size=%u)\n", (int)bus, (int)device, (int)function, (int)offset,
(int)size);
if (offset > 0xff)
return B_BAD_VALUE;
out32rb(bridge->address_registers, (1 << 31)
| (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8)
| (offset & 0xfc));
addr_t dataAddress = bridge->data_registers + (offset & 0x3);
switch (size) {
case 1:
*value = in8rb(dataAddress);
break;
case 2:
*value = in16rb(dataAddress);
break;
case 4:
*value = in32rb(dataAddress);
break;
default:
*value = 0xffffffff;
break;
}
out32rb(bridge->address_registers, 0);
return B_OK;
}
static status_t
grackle_write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
grackle_host_bridge *bridge = (grackle_host_bridge*)cookie;
TRACE("grackle_write_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
"size=%u, value=%lu)\n", (int)bus, (int)device, (int)function,
(int)offset, (int)size, value);
if (offset > 0xff)
return B_BAD_VALUE;
out32rb(bridge->address_registers, (1 << 31)
| (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8)
| (offset & 0xfc));
addr_t dataAddress = bridge->data_registers + (offset & 0x3);
switch (size) {
case 1:
out8rb(dataAddress, (uint8)value);
break;
case 2:
out16rb(dataAddress, (uint16)value);
break;
case 4:
out32rb(dataAddress, value);
break;
}
out32rb(bridge->address_registers, 0);
return B_OK;
}
static status_t
grackle_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
static status_t
grackle_read_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 *irq)
{
return B_ERROR;
}
static status_t
grackle_write_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq)
{
return B_ERROR;
}
static pci_controller sGracklePCIController = {
grackle_read_pci_config,
grackle_write_pci_config,
grackle_get_max_bus_devices,
grackle_read_pci_irq,
grackle_write_pci_irq,
};
status_t
ppc_openfirmware_probe_grackle(int deviceNode,
const StringArrayPropertyValue &compatibleValue)
{
if (!compatibleValue.ContainsElement("grackle"))
return B_ERROR;
uint32_t busrange[2];
if (of_getprop(deviceNode, "bus-range", busrange, sizeof(busrange)) != 8)
return B_ERROR;
grackle_host_bridge *bridge =
(grackle_host_bridge*)malloc(sizeof(grackle_host_bridge));
if (bridge == NULL)
return B_NO_MEMORY;
bridge->device_node = deviceNode;
bridge->address_registers = 0xfec00000;
bridge->data_registers = 0xfee00000;
bridge->bus = busrange[0];
memset(bridge->ranges, 0, sizeof(bridge->ranges));
int bytesRead = of_getprop(deviceNode, "ranges", bridge->ranges,
sizeof(bridge->ranges));
if (bytesRead < 0) {
dprintf("ppc_openfirmware_probe_grackle: Could not get ranges.\n");
free(bridge);
return B_ERROR;
}
bridge->range_count = bytesRead / sizeof(grackle_range);
grackle_range *ioRange = NULL;
grackle_range *memoryRanges[2];
int memoryRangeCount = 0;
for (int i = 0; i < bridge->range_count; i++) {
grackle_range *range = bridge->ranges + i;
switch (range->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
case OFW_PCI_PHYS_HI_SPACE_CONFIG:
break;
case OFW_PCI_PHYS_HI_SPACE_IO:
ioRange = range;
break;
case OFW_PCI_PHYS_HI_SPACE_MEM32:
memoryRanges[memoryRangeCount++] = range;
break;
case OFW_PCI_PHYS_HI_SPACE_MEM64:
break;
}
}
if (ioRange == NULL) {
dprintf("ppc_openfirmware_probe_grackle: Can't find io range.\n");
free(bridge);
return B_ERROR;
}
if (memoryRangeCount == 0) {
dprintf("ppc_openfirmware_probe_grackle: Can't find mem ranges.\n");
free(bridge);
return B_ERROR;
}
status_t error = pci_controller_add(&sGracklePCIController, bridge);
if (error != B_OK)
free(bridge);
return error;
}
@@ -1,107 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "pci_openfirmware.h"
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include <platform/openfirmware/devices.h>
#include <platform/openfirmware/openfirmware.h>
#include <platform/openfirmware/pci.h>
#include "pci_openfirmware_priv.h"
typedef status_t (*probeFunction)(int, const StringArrayPropertyValue&);
static const probeFunction sProbeFunctions[] = {
ppc_openfirmware_probe_uninorth,
ppc_openfirmware_probe_grackle,
NULL,
};
status_t
ppc_openfirmware_pci_controller_init(void)
{
char path[256];
intptr_t cookie = 0;
while (of_get_next_device(&cookie, 0, "pci", path, sizeof(path))
== B_OK) {
dprintf("ppc_openfirmware_pci_controller_init(): pci device node: %s\n", path);
// get the device node and the "compatible" property
int deviceNode = of_finddevice(path);
StringArrayPropertyValue compatible;
status_t error = openfirmware_get_property(deviceNode, "compatible",
compatible);
if (error != B_OK) {
dprintf("ppc_openfirmware_pci_controller_init: Failed to get "
"\"compatible\" property for pci device: %s\n", path);
continue;
}
// probe
for (int i = 0; sProbeFunctions[i]; i++) {
error = sProbeFunctions[i](deviceNode, compatible);
if (error == B_OK)
break;
}
}
return B_OK;
}
// #pragma mark - support functions
char *
StringArrayPropertyValue::NextElement(int &cookie) const
{
if (cookie >= length)
return NULL;
char *result = value + cookie;
cookie += strnlen(result, length - cookie) + 1;
return result;
}
bool
StringArrayPropertyValue::ContainsElement(const char *value) const
{
int cookie = 0;
while (char *checkValue = NextElement(cookie)) {
if (strcmp(checkValue, value) == 0)
return true;
}
return false;
}
status_t
openfirmware_get_property(int package, const char *propertyName,
PropertyValue &value)
{
value.length = of_getproplen(package, propertyName);
if (value.length < 0)
return B_ENTRY_NOT_FOUND;
value.value = (char*)malloc(value.length);
if (!value.value)
return B_NO_MEMORY;
if (of_getprop(package, propertyName, value.value, value.length)
== OF_FAILED) {
return B_ERROR;
}
return B_OK;
}
@@ -1,13 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_H
#define PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_H
#include <SupportDefs.h>
status_t ppc_openfirmware_pci_controller_init(void);
#endif // PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_H
@@ -1,52 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_PRIV_H
#define PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_PRIV_H
#include <stdlib.h>
#include <string.h>
#include <SupportDefs.h>
struct StringArrayPropertyValue;
// implementations
status_t ppc_openfirmware_probe_uninorth(int deviceNode,
const StringArrayPropertyValue &compatibleValue);
status_t ppc_openfirmware_probe_grackle(int deviceNode,
const StringArrayPropertyValue &compatibleValue);
// property support
struct PropertyValue {
PropertyValue()
: value(NULL)
{
}
~PropertyValue()
{
free(value);
}
char *value;
int length;
};
struct StringArrayPropertyValue : PropertyValue {
char *NextElement(int &cookie) const;
bool ContainsElement(const char *value) const;
};
status_t openfirmware_get_property(int package, const char *propertyName,
PropertyValue &value);
#endif // PCI_BUS_MANAGER_PPC_OPEN_FIRMWARE_PRIV_H
@@ -1,293 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
/*-
* Copyright (C) 2002 Benno Rice.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include <platform/openfirmware/devices.h>
#include <platform/openfirmware/openfirmware.h>
#include <platform/openfirmware/pci.h>
#include "pci_controller.h"
#include "pci_io.h"
#include "pci_openfirmware_priv.h"
struct uninorth_range {
uint32 pci_hi;
uint32 pci_mid;
uint32 pci_lo;
uint32 host;
uint32 size_hi;
uint32 size_lo;
};
struct uninorth_host_bridge {
int device_node;
addr_t address_registers;
addr_t data_registers;
uint32 bus;
struct uninorth_range ranges[6];
int range_count;
};
#define out8rb(address, value) ppc_out8((vuint8*)(address), value)
#define out16rb(address, value) ppc_out16_reverse((vuint16*)(address), value)
#define out32rb(address, value) ppc_out32_reverse((vuint32*)(address), value)
#define in8rb(address) ppc_in8((const vuint8*)(address))
#define in16rb(address) ppc_in16_reverse((const vuint16*)(address))
#define in32rb(address) ppc_in32_reverse((const vuint32*)(address))
static int uninorth_enable_config(struct uninorth_host_bridge *bridge,
uint8 bus, uint8 slot, uint8 function, uint8 offset);
static status_t uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device,
uint8 function, uint16 offset, uint8 size, uint32 *value);
static status_t uninorth_write_pci_config(void *cookie, uint8 bus,
uint8 device, uint8 function, uint16 offset, uint8 size,
uint32 value);
static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count);
static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 *irq);
static status_t uninorth_write_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 irq);
static pci_controller sUniNorthPCIController = {
uninorth_read_pci_config,
uninorth_write_pci_config,
uninorth_get_max_bus_devices,
uninorth_read_pci_irq,
uninorth_write_pci_irq,
};
static status_t
uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
if (offset > 0xff)
return B_BAD_VALUE;
addr_t caoff = bridge->data_registers + (offset & 0x07);
if (uninorth_enable_config(bridge, bus, device, function, offset) != 0) {
switch (size) {
case 1:
*value = in8rb(caoff);
break;
case 2:
*value = in16rb(caoff);
break;
case 4:
*value = in32rb(caoff);
break;
default:
*value = 0xffffffff;
break;
}
} else
*value = 0xffffffff;
return B_OK;
}
static status_t uninorth_write_pci_config(void *cookie, uint8 bus, uint8 device,
uint8 function, uint16 offset, uint8 size, uint32 value)
{
uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
if (offset > 0xff)
return B_BAD_VALUE;
addr_t caoff = bridge->data_registers + (offset & 0x07);
if (uninorth_enable_config(bridge, bus, device, function, offset)) {
switch (size) {
case 1:
out8rb(caoff, (uint8)value);
(void)in8rb(caoff);
break;
case 2:
out16rb(caoff, (uint16)value);
(void)in16rb(caoff);
break;
case 4:
out32rb(caoff, value);
(void)in32rb(caoff);
break;
}
}
return B_OK;
}
static status_t uninorth_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
static status_t uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 *irq)
{
return B_ERROR;
}
static status_t uninorth_write_pci_irq(void *cookie, uint8 bus, uint8 device,
uint8 function, uint8 pin, uint8 irq)
{
return B_ERROR;
}
// #pragma mark -
static int
uninorth_enable_config(struct uninorth_host_bridge *bridge, uint8 bus,
uint8 slot, uint8 function, uint8 offset)
{
// uint32 pass;
// if (resource_int_value(device_get_name(sc->sc_dev),
// device_get_unit(sc->sc_dev), "skipslot", &pass) == 0) {
// if (pass == slot)
// return (0);
// }
uint32 cfgval;
if (bridge->bus == bus) {
/*
* No slots less than 11 on the primary bus
*/
if (slot < 11)
return (0);
cfgval = (1 << slot) | (function << 8) | (offset & 0xfc);
} else {
cfgval = (bus << 16) | (slot << 11) | (function << 8) |
(offset & 0xfc) | 1;
}
do {
out32rb(bridge->address_registers, cfgval);
} while (in32rb(bridge->address_registers) != cfgval);
return (1);
}
// #pragma mark -
status_t
ppc_openfirmware_probe_uninorth(int deviceNode,
const StringArrayPropertyValue &compatibleValue)
{
if (!compatibleValue.ContainsElement("uni-north"))
return B_ERROR;
uint32 reg[2];
if (of_getprop(deviceNode, "reg", reg, sizeof(reg)) < 8)
return B_ERROR;
uint32 busrange[2];
if (of_getprop(deviceNode, "bus-range", busrange, sizeof(busrange)) != 8)
return B_ERROR;
uninorth_host_bridge *bridge
= (uninorth_host_bridge*)malloc(sizeof(uninorth_host_bridge));
if (!bridge)
return B_NO_MEMORY;
bridge->device_node = deviceNode;
bridge->address_registers = reg[0] + 0x800000;
bridge->data_registers = reg[0] + 0xc00000;
bridge->bus = busrange[0];
// TODO: Check whether address and data registers have already been mapped by
// the Open Firmware. If not, map them ourselves.
memset(bridge->ranges, 0, sizeof(bridge->ranges));
int bytesRead = of_getprop(deviceNode, "ranges", bridge->ranges,
sizeof(bridge->ranges));
if (bytesRead < 0) {
dprintf("ppc_openfirmware_probe_uninorth: Could not get ranges.\n");
free(bridge);
return B_ERROR;
}
bridge->range_count = bytesRead / sizeof(uninorth_range);
uninorth_range *ioRange = NULL;
uninorth_range *memoryRanges[2];
int memoryRangeCount = 0;
for (int i = 0; i < bridge->range_count; i++) {
uninorth_range *range = bridge->ranges + i;
switch (range->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
case OFW_PCI_PHYS_HI_SPACE_CONFIG:
break;
case OFW_PCI_PHYS_HI_SPACE_IO:
ioRange = range;
break;
case OFW_PCI_PHYS_HI_SPACE_MEM32:
memoryRanges[memoryRangeCount++] = range;
break;
case OFW_PCI_PHYS_HI_SPACE_MEM64:
break;
}
}
if (ioRange == NULL) {
dprintf("ppc_openfirmware_probe_uninorth: Can't find io range.\n");
free(bridge);
return B_ERROR;
}
if (memoryRangeCount == 0) {
dprintf("ppc_openfirmware_probe_uninorth: Can't find mem ranges.\n");
free(bridge);
return B_ERROR;
}
status_t error = pci_controller_add(&sUniNorthPCIController, bridge);
if (error != B_OK)
free(bridge);
return error;
}
@@ -1,36 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <arch_platform.h>
#include "pci_private.h"
#include "openfirmware/pci_openfirmware.h"
#include "u-boot/pci_u-boot.h"
status_t
pci_controller_init(void)
{
switch (PPCPlatform::Default()->PlatformType()) {
case PPC_PLATFORM_OPEN_FIRMWARE:
return ppc_openfirmware_pci_controller_init();
case PPC_PLATFORM_U_BOOT:
return ppc_uboot_pci_controller_init();
default:
panic("pci: unknown platform");
}
return B_ERROR;
}
phys_addr_t
pci_ram_address(phys_addr_t physical_address_in_system_memory)
{
return physical_address_in_system_memory;
}
@@ -1,57 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_io.h"
#include "pci_private.h"
status_t
pci_io_init()
{
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
return ppc_in8((vuint8*)mapped_io_addr);
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
ppc_out8((vuint8*)mapped_io_addr, value);
}
uint16
pci_read_io_16(int mapped_io_addr)
{
return ppc_in16((vuint16*)mapped_io_addr);
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
ppc_out16((vuint16*)mapped_io_addr, value);
}
uint32
pci_read_io_32(int mapped_io_addr)
{
return ppc_in32((vuint32*)mapped_io_addr);
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
ppc_out32((vuint32*)mapped_io_addr, value);
}
@@ -1,97 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_PPC_IO_H
#define PCI_BUS_MANAGER_PPC_IO_H
#include <SupportDefs.h>
static inline void
ppc_out8(vuint8 *address, uint8 value)
{
*address = value;
asm volatile("eieio; sync");
}
static inline void
ppc_out16(vuint16 *address, uint16 value)
{
*address = value;
asm volatile("eieio; sync");
}
static inline void
ppc_out16_reverse(vuint16 *address, uint16 value)
{
asm volatile("sthbrx %1, 0, %0" : : "r"(address), "r"(value));
asm volatile("eieio; sync");
}
static inline void
ppc_out32(vuint32 *address, uint32 value)
{
*address = value;
asm volatile("eieio; sync");
}
static inline void
ppc_out32_reverse(vuint32 *address, uint32 value)
{
asm volatile("stwbrx %1, 0, %0" : : "r"(address), "r"(value));
asm volatile("eieio; sync");
}
static inline uint8
ppc_in8(const vuint8 *address)
{
uint8 value = *address;
asm volatile("eieio; sync");
return value;
}
static inline uint16
ppc_in16(const vuint16 *address)
{
uint16 value = *address;
asm volatile("eieio; sync");
return value;
}
static inline uint16
ppc_in16_reverse(const vuint16 *address)
{
uint16 value;
asm volatile("lhbrx %0, 0, %1" : "=r"(value) : "r"(address));
asm volatile("eieio; sync");
return value;
}
static inline uint32
ppc_in32(const vuint32 *address)
{
uint32 value = *address;
asm volatile("eieio; sync");
return value;
}
static inline uint32
ppc_in32_reverse(const vuint32 *address)
{
uint32 value;
asm volatile("lwbrx %0, 0, %1" : "=r"(value) : "r"(address));
asm volatile("eieio; sync");
return value;
}
#endif // PCI_BUS_MANAGER_PPC_IO_H
@@ -1,24 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "pci_u-boot.h"
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
//#include <platform/openfirmware/devices.h>
//#include <platform/openfirmware/openfirmware.h>
//#include <platform/openfirmware/pci.h>
status_t
ppc_uboot_pci_controller_init(void)
{
return B_ERROR;
}
@@ -1,13 +0,0 @@
/*
* Copyright 2012, François Revol <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_PPC_U_BOOT_H
#define PCI_BUS_MANAGER_PPC_U_BOOT_H
#include <SupportDefs.h>
status_t ppc_uboot_pci_controller_init(void);
#endif // PCI_BUS_MANAGER_PPC_U_BOOT_H
@@ -1,20 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch $(TARGET_ARCH) ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateKernelHeaders ;
UsePrivateHeaders shared ;
UsePrivateHeaders [ FDirName kernel util ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) fu740 ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) ecam ] ;
KernelStaticLibrary pci_arch_bus_manager :
arch_pci_controller.cpp
pci_io.cpp
# SiFive fu740
pci_fu740.cpp
# ECAM
pci_ecam.cpp
;
@@ -1,572 +0,0 @@
/*
* Copyright 2021, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* x512 <[email protected]>
* Alexander von Gluck IV <[email protected]>
*/
#include "arch_pci_controller.h"
#include "fu740/pci_fu740.h"
#include "ecam/pci_ecam.h"
extern PCI* gPCI;
ArchPCIController* gArchPCI = NULL;
ArchPCIController::ArchPCIController()
:
fMsiPhysAddr(0),
fMsiStartIrq(0),
fMsiData(0),
fHostCtrlType(0),
fConfigPhysBase(0),
fConfigBase(0),
fConfigSize(0),
fDbiPhysBase(0),
fDbiBase(0),
fDbiSize(0),
fIoBase(0),
fInterruptMapLen(0)
{
fAllocatedMsiIrqs[0] = 0;
}
ArchPCIController::~ArchPCIController()
{
}
uint32_t
ArchPCIController::EncodePciAddress(uint8 bus, uint8 device, uint8 function)
{
return bus % (1 << 8) * (1 << 16)
+ device % (1 << 5) * (1 << 11)
+ function % (1 << 3) * (1 << 8);
}
void
ArchPCIController::DecodePciAddress(uint32_t adr, uint8& bus, uint8& device, uint8& function)
{
bus = adr / (1 << 16) % (1 << 8);
device = adr / (1 << 11) % (1 << 5);
function = adr / (1 << 8) % (1 << 3);
}
volatile PciDbiRegs*
ArchPCIController::GetDbuRegs()
{
if (fDbiBase == 0) {
return NULL;
}
return (PciDbiRegs*)fDbiBase;
}
RegisterRange*
ArchPCIController::GetRegisterRange(int kind)
{
if (kind > 3)
return NULL;
return &fRegisterRanges[kind];
}
void
ArchPCIController::SetRegisterRange(int kind, phys_addr_t parentBase, phys_addr_t childBase,
size_t size)
{
auto& range = fRegisterRanges[kind];
range.parentBase = parentBase;
range.childBase = childBase;
range.size = size;
// Avoid allocating zero address.
range.free = (childBase != 0) ? childBase : 1;
}
phys_addr_t
ArchPCIController::AllocRegister(int kind, size_t size)
{
auto& range = fRegisterRanges[kind];
phys_addr_t adr = ROUNDUP(range.free, size);
if (adr - range.childBase + size > range.size)
return 0;
range.free = adr + size;
return adr;
}
InterruptMap*
ArchPCIController::LookupInterruptMap(uint32_t childAdr, uint32_t childIrq)
{
childAdr &= fInterruptMapMask.childAdr;
childIrq &= fInterruptMapMask.childIrq;
for (uint32 i = 0; i < fInterruptMapLen; i++) {
if ((fInterruptMap[i].childAdr) == childAdr
&& (fInterruptMap[i].childIrq) == childIrq)
return &fInterruptMap[i];
}
return NULL;
}
void
ArchPCIController::AllocRegs()
{
dprintf("AllocRegs()\n");
// TODO: improve enumeration
for (int j = 0; j < 8; j++) {
for (int i = 0; i < 32; i++) {
uint32 vendorID;
status_t res = ReadConfig(NULL, j, i, 0, PCI_vendor_id, 2, &vendorID);
if (res >= B_OK && vendorID != 0xffff) {
uint32 headerType = 0;
ReadConfig(NULL, j, i, 0,
PCI_header_type, 1, &headerType);
if ((headerType & 0x80) != 0) {
for (int k = 0; k < 8; k++)
AllocRegsForDevice(j, i, k);
} else
AllocRegsForDevice(j, i, 0);
}
}
}
}
status_t
ArchPCIController::ReadConfig(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
addr_t address = ConfigAddress(bus, device, function, offset);
if (address == 0)
return B_ERROR;
switch (size) {
case 1:
*value = *(uint8*)address;
break;
case 2:
*value = *(uint16*)address;
break;
case 4:
*value = *(uint32*)address;
break;
default:
return B_ERROR;
}
return B_OK;
}
status_t
ArchPCIController::WriteConfig(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
addr_t address = ConfigAddress(bus, device, function, offset);
if (address == 0)
return B_ERROR;
switch (size) {
case 1:
*(uint8*)address = value;
break;
case 2:
*(uint16*)address = value;
break;
case 4:
*(uint32*)address = value;
break;
default:
return B_ERROR;
}
return B_OK;
}
void
ArchPCIController::AllocRegsForDevice(uint8 bus, uint8 device, uint8 function)
{
dprintf("AllocRegsForDevice(bus: %d, device: %d, function: %d)\n", bus,
device, function);
bool allocBars = AllocateBar();
status_t result = B_OK;
// TODO: Better error checking on all ReadConfig / WriteConfig calls
uint32 vendorID = 0;
uint32 deviceID = 0;
result = ReadConfig(NULL, bus, device, function, PCI_vendor_id, 2, &vendorID);
if (result != B_OK)
dprintf("Error: unable to read vendorID!\n");
else
dprintf(" vendorID: %#04" B_PRIx32 "\n", vendorID);
result = ReadConfig(NULL, bus, device, function, PCI_device_id, 2, &deviceID);
if (result != B_OK)
dprintf("Error: unable to read deviceID!\n");
else
dprintf(" deviceID: %#04" B_PRIx32 "\n", deviceID);
uint32 headerType = 0;
result = ReadConfig(NULL, bus, device, function, PCI_header_type, 1, &headerType);
if (result != B_OK)
dprintf("Error: unable to read header type!\n");
else {
headerType = headerType % 0x80;
dprintf(" headerType: ");
switch (headerType) {
case PCI_header_type_generic:
dprintf("generic");
break;
case PCI_header_type_PCI_to_PCI_bridge:
dprintf("bridge");
break;
case PCI_header_type_cardbus:
dprintf("cardbus");
break;
default:
dprintf("?(%u)", headerType);
}
dprintf("\n");
}
if (headerType == PCI_header_type_PCI_to_PCI_bridge) {
uint32 primaryBus;
uint32 secondaryBus;
uint32 subordinateBus;
result = ReadConfig(NULL, bus, device, function, PCI_primary_bus, 1, &primaryBus);
if (result != B_OK)
dprintf("Error: Unable to read primaryBus!\n");
else
dprintf(" primaryBus: %u\n", primaryBus);
result = ReadConfig(NULL, bus, device, function, PCI_secondary_bus, 1, &secondaryBus);
if (result != B_OK)
dprintf("Error: Unable to read secondaryBus!\n");
else
dprintf(" secondaryBus: %u\n", secondaryBus);
result = ReadConfig(NULL, bus, device, function, PCI_subordinate_bus, 1, &subordinateBus);
if (result != B_OK)
dprintf("Error: Unable to read subordinateBus!\n");
else
dprintf(" subordinateBus: %u\n", subordinateBus);
}
uint32 oldValLo = 0;
uint32 oldValHi = 0;
uint32 sizeLo = 0;
uint32 sizeHi = 0;
uint64 val;
uint64 size;
for (int i = 0; i < ((headerType == PCI_header_type_PCI_to_PCI_bridge) ? 2 : 6); i++) {
dprintf(" bar[%d]: ", i);
ReadConfig(NULL, bus, device, function, PCI_base_registers + i*4, 4, &oldValLo);
int regKind;
if (oldValLo % 2 == 1) {
regKind = kRegIo;
dprintf("IOPORT");
} else if (oldValLo / 2 % 4 == 0) {
regKind = kRegMmio32;
dprintf("MMIO32");
} else if (oldValLo / 2 % 4 == 2) {
regKind = kRegMmio64;
dprintf("MMIO64");
} else {
dprintf("?(%d)", oldValLo / 2 % 4);
dprintf("\n");
continue;
}
ReadConfig(NULL, bus, device, function, PCI_base_registers + i*4, 4, &oldValLo);
WriteConfig(NULL, bus, device, function, PCI_base_registers + i*4, 4, 0xffffffff);
ReadConfig(NULL, bus, device, function, PCI_base_registers + i*4, 4, &sizeLo);
WriteConfig(NULL, bus, device, function, PCI_base_registers + i*4, 4, oldValLo);
val = oldValLo;
size = sizeLo;
if (regKind == kRegMmio64) {
ReadConfig(NULL, bus, device, function, PCI_base_registers + (i + 1)*4, 4,
&oldValHi);
WriteConfig(NULL, bus, device, function, PCI_base_registers + (i + 1)*4, 4,
0xffffffff);
ReadConfig(NULL, bus, device, function, PCI_base_registers + (i + 1)*4, 4,
&sizeHi);
WriteConfig(NULL, bus, device, function, PCI_base_registers + (i + 1)*4, 4,
oldValHi);
val += ((uint64)oldValHi) << 32;
size += ((uint64)sizeHi ) << 32;
} else {
if (sizeLo != 0)
size += ((uint64)0xffffffff) << 32;
}
val &= ~(uint64)0xf;
size = ~(size & ~(uint64)0xf) + 1;
/*
dprintf(", oldValLo: 0x%" B_PRIx32 ", sizeLo: 0x%" B_PRIx32, oldValLo,
sizeLo);
if (regKind == regMmio64) {
dprintf(", oldValHi: 0x%" B_PRIx32 ", sizeHi: 0x%" B_PRIx32,
oldValHi, sizeHi);
}
*/
dprintf(", adr: 0x%" B_PRIx64 ", size: 0x%" B_PRIx64, val, size);
if (allocBars && /*val == 0 &&*/ size != 0) {
if (regKind == kRegMmio64) {
val = AllocRegister(regKind, size);
WriteConfig(NULL, bus, device, function,
PCI_base_registers + (i + 0)*4, 4, (uint32)val);
WriteConfig(NULL, bus, device, function,
PCI_base_registers + (i + 1)*4, 4,
(uint32)(val >> 32));
dprintf(" -> 0x%" B_PRIx64, val);
} else {
val = AllocRegister(regKind, size);
WriteConfig(NULL, bus, device, function,
PCI_base_registers + i*4, 4, (uint32)val);
dprintf(" -> 0x%" B_PRIx64, val);
}
}
dprintf("\n");
if (regKind == kRegMmio64)
i++;
}
// ROM
dprintf(" rom_bar: ");
uint32 romBaseOfs = (headerType == PCI_header_type_PCI_to_PCI_bridge) ? PCI_bridge_rom_base : PCI_rom_base;
ReadConfig(NULL, bus, device, function, romBaseOfs, 4, &oldValLo);
WriteConfig(NULL, bus, device, function, romBaseOfs, 4, 0xfffffffe);
ReadConfig(NULL, bus, device, function, romBaseOfs, 4, &sizeLo);
WriteConfig(NULL, bus, device, function, romBaseOfs, 4, oldValLo);
val = oldValLo & PCI_rom_address_mask;
size = ~(sizeLo & ~(uint32)0xf) + 1;
dprintf("adr: 0x%" B_PRIx64 ", size: 0x%" B_PRIx64, val, size);
if (allocBars && /*val == 0 &&*/ size != 0) {
val = AllocRegister(kRegMmio32, size);
WriteConfig(NULL, bus, device, function,
PCI_rom_base, 4, (uint32)val);
dprintf(" -> 0x%" B_PRIx64, val);
}
dprintf("\n");
uint32 intPin = 0;
result = ReadConfig(NULL, bus, device, function, PCI_interrupt_pin, 1, &intPin);
if (result != B_OK)
dprintf("Error: Unable to read interrupt pin!\n");
InterruptMap* intMap = LookupInterruptMap(EncodePciAddress(bus, device, function), intPin);
if (intMap == NULL) {
dprintf("no interrupt mapping for childAdr: (%d:%d:%d), childIrq: %d)\n", bus,
device, function, intPin);
} else {
WriteConfig(NULL, bus, device, function, PCI_interrupt_line,
1, intMap->parentIrq);
}
InitDeviceMSI(bus, device, function);
uint32 intLine;
result = ReadConfig(NULL, bus, device, function, PCI_interrupt_line, 1, &intLine);
if (result != B_OK)
dprintf("Error: Unable to read PCI interrupt line!\n");
else {
dprintf(" intLine: %u\n", intLine);
dprintf(" intPin: ");
}
switch (intPin) {
case 0:
dprintf("-");
break;
case 1:
dprintf("INTA#");
break;
case 2:
dprintf("INTB#");
break;
case 3:
dprintf("INTC#");
break;
case 4:
dprintf("INTD#");
break;
default:
dprintf("?(%u)", intPin);
break;
}
dprintf("\n");
}
static status_t
read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
if (gArchPCI == NULL)
return B_ERROR;
// PciConfigAdr may use sliding window
// TODO: SMP
InterruptsLocker locker;
return gArchPCI->ReadConfig(cookie, bus, device, function, offset, size, value);
}
static status_t
write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
if (gArchPCI == NULL)
return B_ERROR;
// PciConfigAdr may use sliding window
// TODO: SMP
InterruptsLocker locker;
/*
dprintf("write_pci_config(%d:%d:%d, 0x%04x, %d, 0x%08x)\n", bus, device,
function, offset, size, value);
*/
return gArchPCI->WriteConfig(cookie, bus, device, function, offset, size, value);
}
static status_t
get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
status_t
read_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, uint8 pin,
uint8 *irq)
{
return B_NOT_SUPPORTED;
}
status_t
write_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, uint8 pin,
uint8 irq)
{
return B_NOT_SUPPORTED;
}
pci_controller pci_controller_riscv64 =
{
read_pci_config,
write_pci_config,
get_max_bus_devices,
read_pci_irq,
write_pci_irq,
};
//#pragma mark -
status_t
pci_controller_init()
{
dprintf("pci_controller_init()\n");
dprintf("sizeof(PciDbi): %#" B_PRIxSIZE "\n", sizeof(PciDbiRegs));
if (gPCIRootNode == NULL)
return B_OK;
DeviceNodePutter<&gDeviceManager> parent(
gDeviceManager->get_parent_node(gPCIRootNode));
const char* compatible;
if (gDeviceManager->get_attr_string(parent.Get(), "fdt/compatible", &compatible,
false) < B_OK)
return B_ERROR;
dprintf("hostCtrlType: ");
if (strcmp(compatible, "pci-host-ecam-generic") == 0) {
static char buffer[sizeof(PCIEcam)];
gArchPCI = new(buffer) PCIEcam();
dprintf("ecam\n");
} else if (strcmp(compatible, "sifive,fu740-pcie") == 0) {
static char buffer[sizeof(PCIFU740)];
gArchPCI = new(buffer) PCIFU740();
dprintf("sifive\n");
} else {
dprintf("unknown\n");
return B_ERROR;
}
if (gArchPCI == NULL)
return B_ERROR;
status_t result = B_ERROR;
// Init our detected PCI bus
result = gArchPCI->Init(gPCIRootNode);
if (result != B_OK)
return result;
return pci_controller_add(&pci_controller_riscv64, NULL);
}
phys_addr_t
pci_ram_address(phys_addr_t childAdr)
{
// dprintf("pci_ram_address(0x%" B_PRIxPHYSADDR "): ", childAdr);
phys_addr_t parentAdr = 0;
for (int kind = kRegIo; kind <= kRegMmio64; kind++) {
auto range = gArchPCI->GetRegisterRange(kind);
if (range == NULL) {
dprintf("%s: Invalid register range %d!\n", __func__, kind);
return 0;
}
if (childAdr >= range->childBase
&& childAdr < range->childBase + range->size) {
parentAdr = childAdr - range->childBase;
if (kind != kRegIo)
parentAdr += range->parentBase;
// dprintf("0x%" B_PRIxPHYSADDR "\n", parentAdr);
return parentAdr;
}
}
// dprintf("?\n");
return 0;
}
@@ -1,122 +0,0 @@
/*
* Copyright 2021, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* x512 <[email protected]>
* Alexander von Gluck IV <[email protected]>
*/
#ifndef _ARCH_PCI_CONTROLLER_H_
#define _ARCH_PCI_CONTROLLER_H_
#include "pci_controller_private.h"
#include "pci_controller.h"
#include "pci_private.h"
#include "pci.h"
#include <AutoDeleterOS.h>
#include <AutoDeleterDrivers.h>
#include <drivers/bus/FDT.h>
#include <util/AutoLock.h>
enum {
kRegIo,
kRegMmio32,
kRegMmio64,
};
struct RegisterRange {
phys_addr_t parentBase;
phys_addr_t childBase;
size_t size;
phys_addr_t free;
};
struct InterruptMapMask {
uint32_t childAdr;
uint32_t childIrq;
};
struct InterruptMap {
uint32_t childAdr;
uint32_t childIrq;
uint32_t parentIrqCtrl;
uint32_t parentIrq;
};
class ArchPCIController {
public:
ArchPCIController();
virtual ~ArchPCIController();
// Implementation Specific
virtual status_t Init(device_node* pciRootNode) = 0;
virtual status_t InitMSI(int32 irq) = 0;
virtual int32 AllocateMSIIrq() = 0;
virtual void FreeMSIIrq(int32 irq) = 0;
virtual void InitDeviceMSI(uint8 bus, uint8 device, uint8 function) = 0;
virtual int32 HandleMSIIrq(void* arg) = 0;
virtual addr_t ConfigAddress(uint8 bus, uint8 device, uint8 function,
uint16 offset) = 0;
virtual bool AllocateBar() = 0;
// Generic Helpers
uint32_t EncodePciAddress(uint8 bus, uint8 device, uint8 function);
void DecodePciAddress(uint32_t adr, uint8& bus, uint8& device,
uint8& function);
addr_t GetIoRegs() { return fIoBase; };
volatile PciDbiRegs* GetDbuRegs();
RegisterRange* GetRegisterRange(int range);
void SetRegisterRange(int kind, phys_addr_t parentBase,
phys_addr_t childBase, size_t size);
phys_addr_t AllocRegister(int kind, size_t size);
void AllocRegsForDevice(uint8 bus, uint8 device, uint8 function);
InterruptMap* LookupInterruptMap(uint32_t childAdr, uint32_t childIrq);
void AllocRegs();
status_t ReadConfig(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value);
status_t WriteConfig(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value);
protected:
uint32 fAllocatedMsiIrqs[1];
phys_addr_t fMsiPhysAddr;
long fMsiStartIrq;
uint64 fMsiData;
RegisterRange fRegisterRanges[3];
InterruptMapMask fInterruptMapMask;
uint32 fHostCtrlType;
AreaDeleter fConfigArea;
addr_t fConfigPhysBase;
addr_t fConfigBase;
size_t fConfigSize;
AreaDeleter fDbiArea;
addr_t fDbiPhysBase;
addr_t fDbiBase;
size_t fDbiSize;
AreaDeleter fIoArea;
addr_t fIoBase;
ArrayDeleter<InterruptMap> fInterruptMap;
uint32_t fInterruptMapLen;
};
#endif /* _ARCH_PCI_CONTROLLER_H_ */
@@ -1,222 +0,0 @@
/*
* Copyright 2021, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* x512 <[email protected]>
* Alexander von Gluck IV <[email protected]>
*/
#include "pci_ecam.h"
status_t
PCIEcam::InitMSI(int32 irq)
{
// No MSI on Ecam?
return B_ERROR;
}
int32
PCIEcam::AllocateMSIIrq()
{
return B_ERROR;
}
void
PCIEcam::FreeMSIIrq(int32 irq)
{
}
int32
PCIEcam::HandleMSIIrq(void* arg)
{
return B_UNHANDLED_INTERRUPT;
}
status_t
PCIEcam::Init(device_node* pciRootNode)
{
fdt_device_module_info* parentModule;
fdt_device* parentDev;
DeviceNodePutter<&gDeviceManager> parent(
gDeviceManager->get_parent_node(gPCIRootNode));
if (gDeviceManager->get_driver(parent.Get(),
(driver_module_info**)&parentModule, (void**)&parentDev))
panic("can't get parent node driver");
uint64 regs;
uint64 regsLen;
for (uint32 i = 0; parentModule->get_reg(parentDev, i, &regs, &regsLen);
i++) {
dprintf(" reg[%" B_PRIu32 "]: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n",
i, regs, regsLen);
}
uint64 configRegs = 0;
uint64 configRegsLen = 0;
if (!parentModule->get_reg(parentDev, 0, &configRegs, &configRegsLen)) {
dprintf(" no regs\n");
return B_ERROR;
}
dprintf(" configRegs: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n",
configRegs, configRegsLen);
int intMapLen;
const void* intMapAdr = parentModule->get_prop(parentDev, "interrupt-map",
&intMapLen);
if (intMapAdr == NULL) {
dprintf(" \"interrupt-map\" property not found");
return B_ERROR;
} else {
int intMapMaskLen;
const void* intMapMask = parentModule->get_prop(parentDev, "interrupt-map-mask",
&intMapMaskLen);
if (intMapMask == NULL || intMapMaskLen != 4 * 4) {
dprintf(" \"interrupt-map-mask\" property not found or invalid");
return B_ERROR;
}
fInterruptMapMask.childAdr = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 0));
fInterruptMapMask.childIrq = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 3));
fInterruptMapLen = (uint32)intMapLen / (6 * 4);
fInterruptMap.SetTo(new(std::nothrow) InterruptMap[fInterruptMapLen]);
if (!fInterruptMap.IsSet())
return B_NO_MEMORY;
for (uint32_t *it = (uint32_t*)intMapAdr;
(uint8_t*)it - (uint8_t*)intMapAdr < intMapLen; it += 6) {
size_t i = (it - (uint32_t*)intMapAdr) / 6;
fInterruptMap[i].childAdr = B_BENDIAN_TO_HOST_INT32(*(it + 0));
fInterruptMap[i].childIrq = B_BENDIAN_TO_HOST_INT32(*(it + 3));
fInterruptMap[i].parentIrqCtrl = B_BENDIAN_TO_HOST_INT32(*(it + 4));
fInterruptMap[i].parentIrq = B_BENDIAN_TO_HOST_INT32(*(it + 5));
}
dprintf(" interrupt-map:\n");
for (size_t i = 0; i < fInterruptMapLen; i++) {
dprintf(" ");
// child unit address
uint8 bus, device, function;
DecodePciAddress(fInterruptMap[i].childAdr, bus, device, function);
dprintf("bus: %" B_PRIu32, bus);
dprintf(", dev: %" B_PRIu32, device);
dprintf(", fn: %" B_PRIu32, function);
dprintf(", childIrq: %" B_PRIu32,
fInterruptMap[i].childIrq);
dprintf(", parentIrq: (%" B_PRIu32,
fInterruptMap[i].parentIrqCtrl);
dprintf(", %" B_PRIu32, fInterruptMap[i].parentIrq);
dprintf(")\n");
if (i % 4 == 3 && (i + 1 < fInterruptMapLen))
dprintf("\n");
}
}
memset(fRegisterRanges, 0, sizeof(fRegisterRanges));
int rangesLen;
const void* rangesAdr = parentModule->get_prop(parentDev, "ranges",
&rangesLen);
if (rangesAdr == NULL) {
dprintf(" \"ranges\" property not found");
} else {
dprintf(" ranges:\n");
for (uint32_t *it = (uint32_t*)rangesAdr;
(uint8_t*)it - (uint8_t*)rangesAdr < rangesLen; it += 7) {
dprintf(" ");
uint32_t kind = B_BENDIAN_TO_HOST_INT32(*(it + 0));
uint64_t childAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 1));
uint64_t parentAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3));
uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5));
switch (kind & 0x03000000) {
case 0x01000000:
SetRegisterRange(kRegIo, parentAdr, childAdr, len);
break;
case 0x02000000:
SetRegisterRange(kRegMmio32, parentAdr, childAdr, len);
break;
case 0x03000000:
SetRegisterRange(kRegMmio64, parentAdr, childAdr, len);
break;
}
switch (kind & 0x03000000) {
case 0x00000000: dprintf("CONFIG"); break;
case 0x01000000: dprintf("IOPORT"); break;
case 0x02000000: dprintf("MMIO32"); break;
case 0x03000000: dprintf("MMIO64"); break;
}
dprintf(" (0x%08" B_PRIx32 "): ", kind);
dprintf("child: %08" B_PRIx64, childAdr);
dprintf(", parent: %08" B_PRIx64, parentAdr);
dprintf(", len: %" B_PRIx64 "\n", len);
}
}
fConfigPhysBase = configRegs;
fConfigSize = configRegsLen;
fConfigArea.SetTo(map_physical_memory(
"PCI Config MMIO",
configRegs, fConfigSize, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
(void**)&fConfigBase
));
fIoArea.SetTo(map_physical_memory(
"PCI IO",
fRegisterRanges[kRegIo].parentBase,
fRegisterRanges[kRegIo].size,
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
(void**)&fIoBase
));
if (!fConfigArea.IsSet()) {
dprintf(" can't map Config MMIO\n");
return fConfigArea.Get();
}
if (!fIoArea.IsSet()) {
dprintf(" can't map IO\n");
return fIoArea.Get();
}
InitMSI(-1);
AllocRegs();
return B_OK;
}
addr_t
PCIEcam::ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset)
{
addr_t address = fConfigBase + EncodePciAddress(bus, device, function) * (1 << 4) + offset;
if (address < fConfigBase || address /*+ size*/ > fConfigBase + fConfigSize)
return 0;
return address;
}
void
PCIEcam::InitDeviceMSI(uint8 bus, uint8 device, uint8 function)
{
}
@@ -1,22 +0,0 @@
/*
* Copyright 2009-2020, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "arch_pci_controller.h"
class PCIEcam : public ArchPCIController {
status_t Init(device_node* pciRootNode);
status_t InitMSI(int32 irq);
int32 AllocateMSIIrq();
void FreeMSIIrq(int32 irq);
int32 HandleMSIIrq(void* arg);
addr_t ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset);
void InitDeviceMSI(uint8 bus, uint8 device, uint8 function);
bool AllocateBar() { return true; }
};
@@ -1,416 +0,0 @@
/*
* Copyright 2021, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* x512 <[email protected]>
* Alexander von Gluck IV <[email protected]>
*/
#include "pci_fu740.h"
extern ArchPCIController* gArchPCI;
static int32
msi_interrupt_handler(void* arg)
{
if (gArchPCI == NULL) {
dprintf(" irq on unconfigured PCI bus!\n");
return B_ERROR;
}
return gArchPCI->HandleMSIIrq(arg);
}
int32
PCIFU740::HandleMSIIrq(void* arg)
{
// dprintf("MsiInterruptHandler()\n");
uint32 status = GetDbuRegs()->msiIntr[0].status;
for (int i = 0; i < 32; i++) {
if (((1 << i) & status) != 0) {
// dprintf("MSI IRQ: %d (%ld)\n", i, gStartMsiIrq + i);
int_io_interrupt_handler(fMsiStartIrq + i, false);
GetDbuRegs()->msiIntr[0].status = (1 << i);
}
}
return B_HANDLED_INTERRUPT;
}
status_t
PCIFU740::InitMSI(int32 msiIrq)
{
dprintf("InitPciMsi()\n");
dprintf(" msiIrq: %" B_PRId32 "\n", msiIrq);
physical_entry pe;
status_t result = get_memory_map(&fMsiData, sizeof(fMsiData), &pe, 1);
if (result != B_OK) {
dprintf(" unable to get MSI Memory map!\n");
return result;
}
fMsiPhysAddr = pe.address;
dprintf(" fMsiPhysAddr: %#" B_PRIxADDR "\n", fMsiPhysAddr);
GetDbuRegs()->msiAddrLo = (uint32)fMsiPhysAddr;
GetDbuRegs()->msiAddrHi = (uint32)(fMsiPhysAddr >> 32);
GetDbuRegs()->msiIntr[0].enable = 0xffffffff;
GetDbuRegs()->msiIntr[0].mask = 0xffffffff;
result = install_io_interrupt_handler(msiIrq, msi_interrupt_handler, NULL, 0);
if (result != B_OK) {
dprintf(" unable to attach MSI irq handler!\n");
return result;
}
result = allocate_io_interrupt_vectors(32, &fMsiStartIrq, INTERRUPT_TYPE_IRQ);
if (result != B_OK) {
dprintf(" unable to attach MSI irq handler!\n");
return result;
}
msi_set_interface(static_cast<MSIInterface*>(this));
dprintf(" fMsiStartIrq: %ld\n", fMsiStartIrq);
return B_OK;
}
status_t
PCIFU740::AllocateVectors(uint8 count, uint8& startVector, uint64& address, uint16& data)
{
if (count != 1)
return B_ERROR;
for (int i = 0; i < 32; i++) {
if (((1 << i) & fAllocatedMsiIrqs[0]) == 0) {
fAllocatedMsiIrqs[0] |= (1 << i);
GetDbuRegs()->msiIntr[0].mask &= ~(1 << i);
startVector = fMsiStartIrq + i;
address = fMsiPhysAddr;
data = i;
return B_OK;
}
}
return B_ERROR;
}
void
PCIFU740::FreeVectors(uint8 count, uint8 startVector)
{
int32 irq = (int32)startVector - fMsiStartIrq;
while (count > 0) {
if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) {
GetDbuRegs()->msiIntr[0].mask |= (1 << (uint32)irq);
fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq);
}
irq++;
count--;
}
}
status_t
PCIFU740::AtuMap(uint32 index, uint32 direction, uint32 type, uint64 parentAdr, uint64 childAdr,
uint32 size)
{
/*
dprintf("AtuMap(%" B_PRIu32 ", %" B_PRIu32 ", %#" B_PRIx64 ", %#" B_PRIx64 ", "
"%#" B_PRIx32 ")\n", index, type, parentAdr, childAdr, size);
*/
volatile PciAtuRegs* atu = (PciAtuRegs*)(fDbiBase + kPciAtuOffset + (2*index + direction)*sizeof(PciAtuRegs));
atu->baseLo = (uint32)parentAdr;
atu->baseHi = (uint32)(parentAdr >> 32);
atu->limit = (uint32)(parentAdr + size - 1);
atu->targetLo = (uint32)childAdr;
atu->targetHi = (uint32)(childAdr >> 32);
atu->ctrl1 = type;
atu->ctrl2 = kPciAtuEnable;
for (;;) {
if ((atu->ctrl2 & kPciAtuEnable) != 0)
break;
}
return B_OK;
}
void
PCIFU740::AtuDump()
{
dprintf("ATU:\n");
for (uint32 direction = 0; direction < 2; direction++) {
switch (direction) {
case kPciAtuOutbound:
dprintf(" outbound:\n");
break;
case kPciAtuInbound:
dprintf(" inbound:\n");
break;
}
for (uint32 index = 0; index < 8; index++) {
volatile PciAtuRegs* atu = (PciAtuRegs*)(fDbiBase
+ kPciAtuOffset + (2 * index + direction) * sizeof(PciAtuRegs));
dprintf(" %" B_PRIu32 ": ", index);
dprintf("base: %#08" B_PRIx64, atu->baseLo + ((uint64)atu->baseHi << 32));
dprintf(", limit: %#08" B_PRIx32, atu->limit);
dprintf(", target: %#08" B_PRIx64, atu->targetLo
+ ((uint64)atu->targetHi << 32));
dprintf(", ctrl1: ");
uint32 ctrl1 = atu->ctrl1;
switch (ctrl1) {
case kPciAtuTypeMem:
dprintf("mem");
break;
case kPciAtuTypeIo:
dprintf("io");
break;
case kPciAtuTypeCfg0:
dprintf("cfg0");
break;
case kPciAtuTypeCfg1:
dprintf("cfg1");
break;
default:
dprintf("? (%#" B_PRIx32 ")", ctrl1);
}
dprintf(", ctrl2: {");
uint32 ctrl2 = atu->ctrl2;
bool first = true;
for (uint32 i = 0; i < 32; i++) {
if (((1 << i) & ctrl2) != 0) {
if (first)
first = false;
else
dprintf(", ");
switch (i) {
case 30:
dprintf("barModeEnable");
break;
case 31:
dprintf("enable");
break;
default:
dprintf("? (%" B_PRIu32 ")", i);
break;
}
}
}
dprintf("}\n");
}
}
}
status_t
PCIFU740::Init(device_node* pciRootNode)
{
fdt_device* parentDev;
fdt_device_module_info* parentModule;
DeviceNodePutter<&gDeviceManager> parent(
gDeviceManager->get_parent_node(gPCIRootNode));
if (gDeviceManager->get_driver(parent.Get(),
(driver_module_info**)&parentModule, (void**)&parentDev))
panic("can't get parent node driver");
uint64 regs;
uint64 regsLen;
for (uint32 i = 0; parentModule->get_reg(parentDev, i, &regs, &regsLen);
i++) {
dprintf(" reg[%" B_PRIu32 "]: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n",
i, regs, regsLen);
}
uint64 configRegs = 0;
uint64 configRegsLen = 0;
uint64 dbiRegs = 0;
uint64 dbiRegsLen = 0;
if (!parentModule->get_reg(parentDev, 0, &dbiRegs, &dbiRegsLen)
|| !parentModule->get_reg(parentDev, 1, &configRegs, &configRegsLen)) {
dprintf(" no regs\n");
return B_ERROR;
}
/*
// !!!
configRegs = 0x60070000;
configRegsLen = 0x10000;
*/
dprintf(" configRegs: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n",
configRegs, configRegsLen);
dprintf(" dbiRegs: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n",
dbiRegs, dbiRegsLen);
int intMapLen;
const void* intMapAdr = parentModule->get_prop(parentDev, "interrupt-map",
&intMapLen);
if (intMapAdr == NULL) {
dprintf(" \"interrupt-map\" property not found");
return B_ERROR;
} else {
int intMapMaskLen;
const void* intMapMask = parentModule->get_prop(parentDev, "interrupt-map-mask",
&intMapMaskLen);
if (intMapMask == NULL || intMapMaskLen != 4 * 4) {
dprintf(" \"interrupt-map-mask\" property not found or invalid");
return B_ERROR;
}
fInterruptMapMask.childAdr = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 0));
fInterruptMapMask.childIrq = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 3));
fInterruptMapLen = (uint32)intMapLen / (6 * 4);
fInterruptMap.SetTo(new(std::nothrow) InterruptMap[fInterruptMapLen]);
if (!fInterruptMap.IsSet())
return B_NO_MEMORY;
for (uint32_t *it = (uint32_t*)intMapAdr;
(uint8_t*)it - (uint8_t*)intMapAdr < intMapLen; it += 6) {
size_t i = (it - (uint32_t*)intMapAdr) / 6;
fInterruptMap[i].childAdr = B_BENDIAN_TO_HOST_INT32(*(it + 0));
fInterruptMap[i].childIrq = B_BENDIAN_TO_HOST_INT32(*(it + 3));
fInterruptMap[i].parentIrqCtrl = B_BENDIAN_TO_HOST_INT32(*(it + 4));
fInterruptMap[i].parentIrq = B_BENDIAN_TO_HOST_INT32(*(it + 5));
}
dprintf(" interrupt-map:\n");
for (size_t i = 0; i < fInterruptMapLen; i++) {
dprintf(" ");
// child unit address
uint8 bus, device, function;
DecodePciAddress(fInterruptMap[i].childAdr, bus, device, function);
dprintf("bus: %" B_PRIu32, bus);
dprintf(", dev: %" B_PRIu32, device);
dprintf(", fn: %" B_PRIu32, function);
dprintf(", childIrq: %" B_PRIu32,
fInterruptMap[i].childIrq);
dprintf(", parentIrq: (%" B_PRIu32,
fInterruptMap[i].parentIrqCtrl);
dprintf(", %" B_PRIu32, fInterruptMap[i].parentIrq);
dprintf(")\n");
if (i % 4 == 3 && (i + 1 < fInterruptMapLen))
dprintf("\n");
}
}
memset(fRegisterRanges, 0, sizeof(fRegisterRanges));
int rangesLen;
const void* rangesAdr = parentModule->get_prop(parentDev, "ranges",
&rangesLen);
if (rangesAdr == NULL) {
dprintf(" \"ranges\" property not found");
} else {
dprintf(" ranges:\n");
for (uint32_t *it = (uint32_t*)rangesAdr;
(uint8_t*)it - (uint8_t*)rangesAdr < rangesLen; it += 7) {
dprintf(" ");
uint32_t kind = B_BENDIAN_TO_HOST_INT32(*(it + 0));
uint64_t childAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 1));
uint64_t parentAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3));
uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5));
switch (kind & 0x03000000) {
case 0x01000000:
SetRegisterRange(kRegIo, parentAdr, childAdr, len);
break;
case 0x02000000:
SetRegisterRange(kRegMmio32, parentAdr, childAdr, len);
break;
case 0x03000000:
SetRegisterRange(kRegMmio64, parentAdr, childAdr, len);
break;
}
switch (kind & 0x03000000) {
case 0x00000000: dprintf("CONFIG"); break;
case 0x01000000: dprintf("IOPORT"); break;
case 0x02000000: dprintf("MMIO32"); break;
case 0x03000000: dprintf("MMIO64"); break;
}
dprintf(" (0x%08" B_PRIx32 "): ", kind);
dprintf("child: %08" B_PRIx64, childAdr);
dprintf(", parent: %08" B_PRIx64, parentAdr);
dprintf(", len: %" B_PRIx64 "\n", len);
}
}
fConfigPhysBase = configRegs;
fConfigSize = configRegsLen;
fConfigArea.SetTo(map_physical_memory("PCI Config MMIO", configRegs,
fConfigSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
(void**)&fConfigBase));
if (dbiRegs != 0) {
fDbiPhysBase = dbiRegs;
fDbiSize = dbiRegsLen;
fDbiArea.SetTo(map_physical_memory("PCI DBI MMIO", dbiRegs, fDbiSize,
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
(void**)&fDbiBase));
}
fIoArea.SetTo(map_physical_memory("PCI IO", fRegisterRanges[kRegIo].parentBase,
fRegisterRanges[kRegIo].size, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fIoBase));
if (!fConfigArea.IsSet()) {
dprintf(" can't map Config MMIO\n");
return fConfigArea.Get();
}
if (!fIoArea.IsSet()) {
dprintf(" can't map IO\n");
return fIoArea.Get();
}
AtuDump();
// TODO: Get from MSI!
InitMSI(0x38);
AllocRegs();
AtuDump();
return B_OK;
}
addr_t
PCIFU740::ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset)
{
uint32 atuType;
if (bus == 0) {
if (device != 0 || function != 0)
return 0;
return fDbiBase + offset;
} else if (bus == 1)
atuType = kPciAtuTypeCfg0;
else
atuType = kPciAtuTypeCfg1;
status_t res = AtuMap(1, kPciAtuOutbound, atuType, fConfigPhysBase, EncodePciAddress(bus, device, function) << 8, fConfigSize);
if (res < B_OK)
return 0;
return fConfigBase + offset;
}
@@ -1,121 +0,0 @@
/*
* Copyright 2009-2020, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "arch_pci_controller.h"
#include <arch/generic/msi.h>
enum {
kPciAtuOffset = 0x300000,
};
enum {
kPciAtuOutbound = 0,
kPciAtuInbound = 1,
};
enum {
// ctrl1
kPciAtuTypeMem = 0,
kPciAtuTypeIo = 2,
kPciAtuTypeCfg0 = 4,
kPciAtuTypeCfg1 = 5,
// ctrl2
kPciAtuBarModeEnable = 1 << 30,
kPciAtuEnable = 1 << 31,
};
struct PciAtuRegs {
uint32 ctrl1;
uint32 ctrl2;
uint32 baseLo;
uint32 baseHi;
uint32 limit;
uint32 targetLo;
uint32 targetHi;
uint32 unused[57];
};
struct PciDbiRegs {
uint8 unknown0[0x700];
uint32 unknown1[3];
uint32 portAfr;
uint32 linkControl;
uint32 unknown2[5];
uint32 portDebug0;
uint32 portDebug1;
uint32 unknown3[55];
uint32 linkWidthSpeedControl;
uint32 unknown4[4];
uint32 msiAddrLo;
uint32 msiAddrHi;
struct {
uint32 enable;
uint32 mask;
uint32 status;
} msiIntr[8];
uint32 unknown5[13];
uint32 miscControl1Off;
uint32 miscPortMultiLaneCtrl;
uint32 unknown6[15];
uint32 atuViewport;
uint32 atuCr1;
uint32 atuCr2;
uint32 atuBaseLo;
uint32 atuBaseHi;
uint32 atuLimit;
uint32 atuTargetLo;
uint32 atuTargetHi;
uint32 unknown7;
uint32 atuLimitHi;
uint32 unknown8[8];
uint32 msixDoorbell;
uint32 unknown9[117];
uint32 plChkRegControlStatus;
uint32 unknown10;
uint32 plChkRegErrAddr;
uint32 unknown11[309];
};
class PCIFU740 : public ArchPCIController, public MSIInterface {
status_t Init(device_node* pciRootNode);
PciDbiRegs volatile* GetDbuRegs() {return (PciDbiRegs volatile*)fDbiBase;}
status_t InitMSI(int32 irq);
status_t AllocateVectors(uint8 count, uint8& startVector, uint64& address,
uint16& data) final;
void FreeVectors(uint8 count, uint8 startVector) final;
static int32 HandleMSIIrq(void* arg);
inline int32 HandleMSIIrqInt();
void EnableIoInterrupt(int irq) final;
void DisableIoInterrupt(int irq) final;
void ConfigureIoInterrupt(int irq, uint32 config) final;
int32 AssignToCpu(int32 irq, int32 cpu) final;
addr_t ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset);
bool AllocateBar() { return false; }
private:
status_t AtuMap(uint32 index, uint32 direction, uint32 type,
uint64 parentAdr, uint64 childAdr, uint32 size);
void AtuDump();
private:
AreaDeleter fDbiArea;
addr_t fDbiPhysBase{};
addr_t fDbiBase{};
size_t fDbiSize{};
};
@@ -1,58 +0,0 @@
/*
* Copyright 2021, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _PCI_CONTROLLER_PRIVATE_H_
#define _PCI_CONTROLLER_PRIVATE_H_
#include <SupportDefs.h>
struct PciDbiRegs {
uint8 unknown0[0x700];
uint32 unknown1[3];
uint32 portAfr;
uint32 linkControl;
uint32 unknown2[5];
uint32 portDebug0;
uint32 portDebug1;
uint32 unknown3[55];
uint32 linkWidthSpeedControl;
uint32 unknown4[4];
uint32 msiAddrLo;
uint32 msiAddrHi;
struct {
uint32 enable;
uint32 mask;
uint32 status;
} msiIntr[8];
uint32 unknown5[13];
uint32 miscControl1Off;
uint32 miscPortMultiLaneCtrl;
uint32 unknown6[15];
uint32 atuViewport;
uint32 atuCr1;
uint32 atuCr2;
uint32 atuBaseLo;
uint32 atuBaseHi;
uint32 atuLimit;
uint32 atuTargetLo;
uint32 atuTargetHi;
uint32 unknown7;
uint32 atuLimitHi;
uint32 unknown8[8];
uint32 msixDoorbell;
uint32 unknown9[117];
uint32 plChkRegControlStatus;
uint32 unknown10;
uint32 plChkRegErrAddr;
uint32 unknown11[309];
};
#endif // _PCI_CONTROLLER_PRIVATE_H_
@@ -1,91 +0,0 @@
/*
* Copyright 2009-2020, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "arch_pci_controller.h"
#include "pci_io.h"
#include "pci_private.h"
#include <AutoDeleterOS.h>
#undef TRACE
//#define TRACE_PCI_IO
#ifdef TRACE_PCI_IO
# define TRACE(x...) fprintf("PCI_IO: " x)
#else
# define TRACE(x...) ;
#endif
extern ArchPCIController* gArchPCI;
addr_t gPCIeIoBase;
status_t
pci_io_init()
{
TRACE("pci_io_init()\n");
if (gArchPCI == NULL)
return B_ERROR;
gPCIeIoBase = gArchPCI->GetIoRegs();
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
TRACE("pci_read_io_8(%d)\n", mapped_io_addr);
volatile uint8* ptr = (uint8*)(gPCIeIoBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
TRACE("pci_write_io_8(%d)\n", mapped_io_addr);
volatile uint8* ptr = (uint8*)(gPCIeIoBase + mapped_io_addr);
*ptr = value;
}
uint16
pci_read_io_16(int mapped_io_addr)
{
TRACE("pci_read_io_16(%d)\n", mapped_io_addr);
volatile uint16* ptr = (uint16*)(gPCIeIoBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
TRACE("pci_write_io_16(%d)\n", mapped_io_addr);
volatile uint16* ptr = (uint16*)(gPCIeIoBase + mapped_io_addr);
*ptr = value;
}
uint32
pci_read_io_32(int mapped_io_addr)
{
TRACE("pci_read_io_32(%d)\n", mapped_io_addr);
volatile uint32* ptr = (uint32*)(gPCIeIoBase + mapped_io_addr);
return *ptr;
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
TRACE("pci_write_io_32(%d)\n", mapped_io_addr);
volatile uint32* ptr = (uint32*)(gPCIeIoBase + mapped_io_addr);
*ptr = value;
}
@@ -1,11 +0,0 @@
/*
* Copyright 2009-2020, Haiku Inc., All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_RISCV64_IO_H
#define PCI_BUS_MANAGER_RISCV64_IO_H
#include <SupportDefs.h>
#endif // PCI_BUS_MANAGER_RISCV64_IO_H
@@ -1,16 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch sparc ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateHeaders kernel [ FDirName kernel arch $(TARGET_ARCH) ]
[ FDirName kernel boot platform $(HAIKU_BOOT_PLATFORM) ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) openfirmware ] ;
KernelStaticLibrary pci_arch_bus_manager :
pci_controller.cpp
pci_io.c
# openfirmware
pci_openfirmware.cpp
;
@@ -1,105 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "pci_openfirmware.h"
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include <platform/openfirmware/devices.h>
#include <platform/openfirmware/openfirmware.h>
#include <platform/openfirmware/pci.h>
#include "pci_openfirmware_priv.h"
typedef status_t (*probeFunction)(int, const StringArrayPropertyValue&);
static const probeFunction sProbeFunctions[] = {
NULL,
};
status_t
sparc_openfirmware_pci_controller_init(void)
{
char path[256];
intptr_t cookie = 0;
while (of_get_next_device(&cookie, 0, "pci", path, sizeof(path))
== B_OK) {
dprintf("sparc_openfirmware_pci_controller_init(): pci device node: %s\n", path);
// get the device node and the "compatible" property
int deviceNode = of_finddevice(path);
StringArrayPropertyValue compatible;
status_t error = openfirmware_get_property(deviceNode, "compatible",
compatible);
if (error != B_OK) {
dprintf("sparc_openfirmware_pci_controller_init: Failed to get "
"\"compatible\" property for pci device: %s\n", path);
continue;
}
// probe
for (int i = 0; sProbeFunctions[i]; i++) {
error = sProbeFunctions[i](deviceNode, compatible);
if (error == B_OK)
break;
}
}
return B_OK;
}
// #pragma mark - support functions
char *
StringArrayPropertyValue::NextElement(int &cookie) const
{
if (cookie >= length)
return NULL;
char *result = value + cookie;
cookie += strnlen(result, length - cookie) + 1;
return result;
}
bool
StringArrayPropertyValue::ContainsElement(const char *value) const
{
int cookie = 0;
while (char *checkValue = NextElement(cookie)) {
if (strcmp(checkValue, value) == 0)
return true;
}
return false;
}
status_t
openfirmware_get_property(int package, const char *propertyName,
PropertyValue &value)
{
value.length = of_getproplen(package, propertyName);
if (value.length < 0)
return B_ENTRY_NOT_FOUND;
value.value = (char*)malloc(value.length);
if (!value.value)
return B_NO_MEMORY;
if (of_getprop(package, propertyName, value.value, value.length)
== OF_FAILED) {
return B_ERROR;
}
return B_OK;
}
@@ -1,13 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_SPARC_OPEN_FIRMWARE_H
#define PCI_BUS_MANAGER_SPARC_OPEN_FIRMWARE_H
#include <SupportDefs.h>
status_t sparc_openfirmware_pci_controller_init(void);
#endif // PCI_BUS_MANAGER_SPARC_OPEN_FIRMWARE_H
@@ -1,49 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_SPARC_OPEN_FIRMWARE_PRIV_H
#define PCI_BUS_MANAGER_SPARC_OPEN_FIRMWARE_PRIV_H
#include <stdlib.h>
#include <string.h>
#include <SupportDefs.h>
struct StringArrayPropertyValue;
// implementations
// TODO
// property support
struct PropertyValue {
PropertyValue()
: value(NULL)
{
}
~PropertyValue()
{
free(value);
}
char *value;
int length;
};
struct StringArrayPropertyValue : PropertyValue {
char *NextElement(int &cookie) const;
bool ContainsElement(const char *value) const;
};
status_t openfirmware_get_property(int package, const char *propertyName,
PropertyValue &value);
#endif // PCI_BUS_MANAGER_SPARC_OPEN_FIRMWARE_PRIV_H
@@ -1,27 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <arch_platform.h>
#include "pci_private.h"
#include "openfirmware/pci_openfirmware.h"
status_t
pci_controller_init(void)
{
return sparc_openfirmware_pci_controller_init();
}
phys_addr_t
pci_ram_address(phys_addr_t physical_address_in_system_memory)
{
return physical_address_in_system_memory;
}
@@ -1,61 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_io.h"
#include "pci_private.h"
static const uint8_t* gPCIBase;
status_t
pci_io_init()
{
// TODO set gPCIBase
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
return sparc_in8((vuint8*)(gPCIBase + mapped_io_addr));
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
sparc_out8((vuint8*)(gPCIBase + mapped_io_addr), value);
}
uint16
pci_read_io_16(int mapped_io_addr)
{
return sparc_in16((vuint16*)(gPCIBase + mapped_io_addr));
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
sparc_out16((vuint16*)(gPCIBase + mapped_io_addr), value);
}
uint32
pci_read_io_32(int mapped_io_addr)
{
return sparc_in32((vuint32*)(gPCIBase + mapped_io_addr));
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
sparc_out32((vuint32*)(gPCIBase + mapped_io_addr), value);
}
@@ -1,97 +0,0 @@
/*
* Copyright 2006, Ingo Weinhold <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PCI_BUS_MANAGER_SPARC_IO_H
#define PCI_BUS_MANAGER_SPARC_IO_H
#include <SupportDefs.h>
static inline void
sparc_out8(vuint8 *address, uint8 value)
{
*address = value;
asm volatile("MEMBAR #MemIssue");
}
static inline void
sparc_out16(vuint16 *address, uint16 value)
{
*address = value;
asm volatile("MEMBAR #MemIssue");
}
static inline void
sparc_out16_reverse(vuint16 *address, uint16 value)
{
asm volatile("stha %1, [%0] 0x88" : : "r"(address), "r"(value));
asm volatile("MEMBAR #MemIssue");
}
static inline void
sparc_out32(vuint32 *address, uint32 value)
{
*address = value;
asm volatile("MEMBAR #MemIssue");
}
static inline void
sparc_out32_reverse(vuint32 *address, uint32 value)
{
asm volatile("stwa %1, [%0] 0x88" : : "r"(address), "r"(value));
asm volatile("MEMBAR #MemIssue");
}
static inline uint8
sparc_in8(const vuint8 *address)
{
uint8 value = *address;
asm volatile("MEMBAR #MemIssue");
return value;
}
static inline uint16
sparc_in16(const vuint16 *address)
{
uint16 value = *address;
asm volatile("MEMBAR #MemIssue");
return value;
}
static inline uint16
sparc_in16_reverse(const vuint16 *address)
{
uint16 value;
asm volatile("lha [%1] 0x88, %0" : "=r"(value) : "r"(address));
asm volatile("MEMBAR #MemIssue");
return value;
}
static inline uint32
sparc_in32(const vuint32 *address)
{
uint32 value = *address;
asm volatile("MEMBAR #MemIssue");
return value;
}
static inline uint32
sparc_in32_reverse(const vuint32 *address)
{
uint32 value;
asm volatile("ldwa [%1] 0x88, %0" : "=r"(value) : "r"(address));
asm volatile("MEMBAR #MemIssue");
return value;
}
#endif // PCI_BUS_MANAGER_SPARC_IO_H
@@ -1,18 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch x86 ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateHeaders kernel [ FDirName kernel arch x86 ] [ FDirName kernel util ] ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include
platform ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi arch $(TARGET_KERNEL_ARCH_DIR) ;
KernelStaticLibrary pci_arch_bus_manager :
pci_acpi.cpp
pci_bios.cpp
pci_controller.cpp
pci_io.cpp
pci_irq.cpp
;
@@ -1,39 +0,0 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_private.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,
uint16 offset, uint8 size, uint32 *value)
{
return B_ERROR;
}
status_t
pci_bios_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 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;
}
@@ -1,18 +0,0 @@
#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,
uint16 offset, uint8 size, uint32 *value);
status_t pci_bios_write_config(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value);
status_t pci_bios_get_max_bus_devices(void *cookie, int32 *count);
#endif
@@ -1,417 +0,0 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
#include <driver_settings.h>
#include <string.h>
#include "pci_acpi.h"
#include "arch_cpu.h"
#include "pci_bios.h"
#include "pci_controller.h"
#include "pci_irq.h"
#include "pci_private.h"
#include "acpi.h"
#define PCI_MECH1_REQ_PORT 0xCF8
#define PCI_MECH1_DATA_PORT 0xCFC
#define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
(0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3))
#define PCI_MECH2_ENABLE_PORT 0x0cf8
#define PCI_MECH2_FORWARD_PORT 0x0cfa
#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); \
}
#define PCI_UNLOCK_CONFIG(cpu_status) \
{ \
release_spinlock(&sConfigLock); \
restore_interrupts(cpu_status); \
}
spinlock sConfigLock = B_SPINLOCK_INITIALIZER;
static status_t
pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
cpu_status cpu;
status_t status = B_OK;
if (offset > 0xff)
return B_BAD_VALUE;
PCI_LOCK_CONFIG(cpu);
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
switch (size) {
case 1:
*value = in8(PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 2:
*value = in16(PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 4:
*value = in32(PCI_MECH1_DATA_PORT);
break;
default:
status = B_ERROR;
break;
}
PCI_UNLOCK_CONFIG(cpu);
return status;
}
static status_t
pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
cpu_status cpu;
status_t status = B_OK;
if (offset > 0xff)
return B_BAD_VALUE;
PCI_LOCK_CONFIG(cpu);
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
switch (size) {
case 1:
out8(value, PCI_MECH1_DATA_PORT + (offset & 3));
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(cpu);
return status;
}
static status_t
pci_mech1_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
static status_t
pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
cpu_status cpu;
status_t status = B_OK;
if (offset > 0xff)
return B_BAD_VALUE;
PCI_LOCK_CONFIG(cpu);
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
out8(bus, PCI_MECH2_FORWARD_PORT);
switch (size) {
case 1:
*value = in8(PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 2:
*value = in16(PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 4:
*value = in32(PCI_MECH2_CONFIG_PORT(device, offset));
break;
default:
status = B_ERROR;
break;
}
out8(0, PCI_MECH2_ENABLE_PORT);
PCI_UNLOCK_CONFIG(cpu);
return status;
}
static status_t
pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
cpu_status cpu;
status_t status = B_OK;
if (offset > 0xff)
return B_BAD_VALUE;
PCI_LOCK_CONFIG(cpu);
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
out8(bus, PCI_MECH2_FORWARD_PORT);
switch (size) {
case 1:
out8(value, PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 2:
out16(value, PCI_MECH2_CONFIG_PORT(device, offset));
break;
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(cpu);
return status;
}
static status_t
pci_mech2_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 16;
return B_OK;
}
addr_t sPCIeBase = 0;
uint8 sStartBusNumber;
uint8 sEndBusNumber;
#define PCIE_VADDR(base, bus, slot, func, reg) ((base) + \
((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) | \
(((func) & 0x7) << 12) | ((reg) & 0xfff)))
static status_t
pci_mechpcie_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value)
{
// fallback to mechanism 1 for out of range busses
if (bus < sStartBusNumber || bus > sEndBusNumber) {
return pci_mech1_read_config(cookie, bus, device, function, offset,
size, value);
}
status_t status = B_OK;
addr_t address = PCIE_VADDR(sPCIeBase, bus, device, function, offset);
switch (size) {
case 1:
*value = *(uint8*)address;
break;
case 2:
*value = *(uint16*)address;
break;
case 4:
*value = *(uint32*)address;
break;
default:
status = B_ERROR;
break;
}
return status;
}
static status_t
pci_mechpcie_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
// fallback to mechanism 1 for out of range busses
if (bus < sStartBusNumber || bus > sEndBusNumber) {
return pci_mech1_write_config(cookie, bus, device, function, offset,
size, value);
}
status_t status = B_OK;
addr_t address = PCIE_VADDR(sPCIeBase, bus, device, function, offset);
switch (size) {
case 1:
*(uint8*)address = value;
break;
case 2:
*(uint16*)address = value;
break;
case 4:
*(uint32*)address = value;
break;
default:
status = B_ERROR;
break;
}
return status;
}
static status_t
pci_mechpcie_get_max_bus_devices(void *cookie, int32 *count)
{
*count = 32;
return B_OK;
}
phys_addr_t
pci_ram_address(phys_addr_t physical_address_in_system_memory)
{
return physical_address_in_system_memory;
}
pci_controller pci_controller_x86_mech1 =
{
pci_mech1_read_config,
pci_mech1_write_config,
pci_mech1_get_max_bus_devices,
pci_x86_irq_read,
pci_x86_irq_write,
};
pci_controller pci_controller_x86_mech2 =
{
pci_mech2_read_config,
pci_mech2_write_config,
pci_mech2_get_max_bus_devices,
pci_x86_irq_read,
pci_x86_irq_write,
};
pci_controller pci_controller_x86_mechpcie =
{
pci_mechpcie_read_config,
pci_mechpcie_write_config,
pci_mechpcie_get_max_bus_devices,
pci_x86_irq_read,
pci_x86_irq_write,
};
pci_controller pci_controller_x86_bios =
{
pci_bios_read_config,
pci_bios_write_config,
pci_bios_get_max_bus_devices,
pci_x86_irq_read,
pci_x86_irq_write,
};
status_t
pci_controller_init(void)
{
bool search_mech1 = true;
bool search_mech2 = true;
bool search_mechpcie = true;
bool search_bios = true;
void *config = NULL;
status_t status;
status = pci_x86_irq_init();
if (status != B_OK)
return status;
config = load_driver_settings("pci");
if (config) {
const char *mech = get_driver_parameter(config, "mechanism",
NULL, NULL);
if (mech) {
search_mech1 = search_mech2 = search_mechpcie = search_bios = false;
if (strcmp(mech, "1") == 0)
search_mech1 = true;
else if (strcmp(mech, "2") == 0)
search_mech2 = true;
else if (strcmp(mech, "pcie") == 0)
search_mechpcie = true;
else if (strcmp(mech, "bios") == 0)
search_bios = true;
else
panic("Unknown pci config mechanism setting %s\n", mech);
}
unload_driver_settings(config);
}
// TODO: check safemode "don't call the BIOS" setting and unset search_bios!
// PCI configuration mechanism PCIe is the preferred one.
// If it doesn't work, try mechanism 1.
// If it doesn't work, try mechanism 2.
// Finally, try to fallback to PCI BIOS
if (search_mechpcie) {
acpi_init();
struct acpi_table_mcfg* mcfg =
(struct acpi_table_mcfg*)acpi_find_table("MCFG");
if (mcfg != NULL) {
struct acpi_mcfg_allocation* end = (struct acpi_mcfg_allocation*)
((char*)mcfg + mcfg->Header.Length);
struct acpi_mcfg_allocation* alloc = (struct acpi_mcfg_allocation*)
(mcfg + 1);
for (; alloc < end; alloc++) {
dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: "
"%x, end: %x\n", alloc->Address, alloc->PciSegment,
alloc->StartBusNumber, alloc->EndBusNumber);
if (alloc->PciSegment == 0) {
area_id mcfgArea = map_physical_memory("acpi mcfg",
alloc->Address, (alloc->EndBusNumber + 1) << 20,
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA
| B_KERNEL_WRITE_AREA, (void **)&sPCIeBase);
if (mcfgArea < 0)
break;
sStartBusNumber = alloc->StartBusNumber;
sEndBusNumber = alloc->EndBusNumber;
dprintf("PCI: mechanism pcie controller found\n");
return pci_controller_add(&pci_controller_x86_mechpcie,
NULL);
}
}
}
}
if (search_mech1) {
// check for mechanism 1
out32(0x80000000, PCI_MECH1_REQ_PORT);
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,58 +0,0 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_private.h"
#include "arch_cpu.h"
status_t
pci_io_init()
{
// nothing to do on x86 hardware
return B_OK;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
return in8(mapped_io_addr);
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
out8(value, mapped_io_addr);
}
uint16
pci_read_io_16(int mapped_io_addr)
{
return in16(mapped_io_addr);
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
out16(value, mapped_io_addr);
}
uint32
pci_read_io_32(int mapped_io_addr)
{
return in32(mapped_io_addr);
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
out32(value, mapped_io_addr);
}
@@ -1,32 +0,0 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include "pci_irq.h"
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;
}
status_t
pci_x86_irq_write(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq)
{
return B_ERROR;
}
@@ -1,22 +0,0 @@
/*
* 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
+107 -54
View File
@@ -21,6 +21,7 @@
#include "pci_private.h" #include "pci_private.h"
#include "pci.h" #include "pci.h"
#define TRACE_CAP(x...) dprintf(x) #define TRACE_CAP(x...) dprintf(x)
#define FLOW(x...) #define FLOW(x...)
//#define FLOW(x...) dprintf(x) //#define FLOW(x...) dprintf(x)
@@ -32,13 +33,6 @@ PCI *gPCI;
// #pragma mark bus manager exports // #pragma mark bus manager exports
status_t
pci_controller_add(pci_controller *controller, void *cookie)
{
return gPCI->AddController(controller, cookie);
}
long long
pci_get_nth_pci_info(long index, pci_info *outInfo) pci_get_nth_pci_info(long index, pci_info *outInfo)
{ {
@@ -78,6 +72,23 @@ pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
} }
phys_addr_t
pci_ram_address(phys_addr_t childAdr)
{
phys_addr_t hostAdr = 0;
#if defined(__i386__) || defined(__x86_64__)
hostAdr = childAdr;
#else
uint8 domain;
pci_resource_range range;
if (gPCI->LookupRange(kPciRangeMmio, childAdr, domain, range) >= B_OK)
hostAdr = childAdr - range.pci_addr + range.host_addr;
#endif
//dprintf("pci_ram_address(%#" B_PRIx64 ") -> %#" B_PRIx64 "\n", childAdr, hostAdr);
return hostAdr;
}
status_t status_t
pci_find_capability(uint8 virtualBus, uint8 device, uint8 function, pci_find_capability(uint8 virtualBus, uint8 device, uint8 function,
uint8 capID, uint8 *offset) uint8 capID, uint8 *offset)
@@ -155,11 +166,10 @@ pci_reserve_device(uchar virtualBus, uchar device, uchar function,
device_node *node, *legacy; device_node *node, *legacy;
status = B_DEVICE_NOT_FOUND; status = B_DEVICE_NOT_FOUND;
if (gPCIRootNode == NULL) device_node *root_pci_node = gPCI->_GetDomainData(domain)->root_node;
goto err1;
node = NULL; node = NULL;
if (gDeviceManager->get_next_child_node(gPCIRootNode, if (gDeviceManager->get_next_child_node(root_pci_node,
matchThis, &node) < B_OK) { matchThis, &node) < B_OK) {
goto err1; goto err1;
} }
@@ -208,10 +218,6 @@ pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus, //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
// domain, bus, device, function, driverName, nodeCookie)); // domain, bus, device, function, driverName, nodeCookie));
device_attr matchPCIRoot[] = {
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "PCI"}},
{NULL}
};
device_attr matchThis[] = { device_attr matchThis[] = {
// info about device // info about device
{B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}}, {B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}},
@@ -236,16 +242,11 @@ pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
{"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}}, {"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}},
{NULL} {NULL}
}; };
device_node *root, *pci, *node, *legacy, *drv; device_node *pci, *node, *legacy, *drv;
status = B_DEVICE_NOT_FOUND; status = B_DEVICE_NOT_FOUND;
root = gDeviceManager->get_root_node();
if (!root)
return status;
pci = NULL; pci = gPCI->_GetDomainData(domain)->root_node;
if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
goto err0;
node = NULL; node = NULL;
if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK) if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
@@ -272,8 +273,6 @@ pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
// we'll get EBUSY here anyway... // we'll get EBUSY here anyway...
gDeviceManager->put_node(node); gDeviceManager->put_node(node);
gDeviceManager->put_node(pci);
gDeviceManager->put_node(root);
return B_OK; return B_OK;
err3: err3:
@@ -281,9 +280,6 @@ err3:
err2: err2:
gDeviceManager->put_node(node); gDeviceManager->put_node(node);
err1: err1:
gDeviceManager->put_node(pci);
err0:
gDeviceManager->put_node(root);
TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName, TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
strerror(status))); strerror(status)));
return status; return status;
@@ -480,29 +476,14 @@ pcirefresh(int argc, char **argv)
static bool sInitDone; static bool sInitDone;
status_t __attribute__((weak)) pci_controller_finalize() { return B_OK; }
status_t status_t
pci_init_deferred(void) pci_init_deferred(void)
{ {
dprintf("pci_init_deferred()\n");
if (sInitDone) if (sInitDone)
return B_OK; return B_OK;
status_t ret = pci_controller_init();
if (ret == B_DEV_NOT_READY)
return ret;
if (ret != B_OK) {
TRACE(("PCI: pci_controller_init failed\n"));
return B_ERROR;
}
if (pci_io_init() != B_OK) {
TRACE(("PCI: pci_io_init failed\n"));
return B_ERROR;
}
add_debugger_command("inw", &display_io, "dump io words (32-bit)"); add_debugger_command("inw", &display_io, "dump io words (32-bit)");
add_debugger_command("in32", &display_io, "dump io words (32-bit)"); add_debugger_command("in32", &display_io, "dump io words (32-bit)");
add_debugger_command("ins", &display_io, "dump io shorts (16-bit)"); add_debugger_command("ins", &display_io, "dump io shorts (16-bit)");
@@ -523,7 +504,7 @@ pci_init_deferred(void)
add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers"); add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers");
add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info"); add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info");
if (pci_controller_finalize() != B_OK) { if (gPCI->Finalize() != B_OK) {
TRACE(("PCI: pci_controller_finalize failed\n")); TRACE(("PCI: pci_controller_finalize failed\n"));
return B_ERROR; return B_ERROR;
} }
@@ -539,14 +520,7 @@ status_t
pci_init(void) pci_init(void)
{ {
gPCI = new PCI; gPCI = new PCI;
status_t ret = pci_init_deferred();
if (ret == B_DEV_NOT_READY) {
TRACE(("PCI: init deferred\n"));
return B_OK; return B_OK;
}
return ret;
} }
@@ -632,6 +606,25 @@ PCI::InitBus()
} }
status_t
PCI::Finalize()
{
// TODO: Properly handle multiple domains. Currently finalize fill be called twice for first
// domain is second domain is added, but should be called only once.
for (uint8 i = 0; i < fDomainCount; i++) {
pci_controller_module_info* controller = fDomainData[i].controller;
if (controller->finalize != NULL) {
status_t res = controller->finalize(fDomainData[i].controller_cookie);
if (res < B_OK)
return res;
}
}
return B_OK;
}
PCI::~PCI() PCI::~PCI()
{ {
} }
@@ -701,13 +694,15 @@ PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus)
status_t status_t
PCI::AddController(pci_controller *controller, void *controller_cookie) PCI::AddController(pci_controller_module_info *controller, void *controller_cookie,
device_node *root_node)
{ {
if (fDomainCount == MAX_PCI_DOMAINS) if (fDomainCount == MAX_PCI_DOMAINS)
return B_ERROR; return B_ERROR;
fDomainData[fDomainCount].controller = controller; fDomainData[fDomainCount].controller = controller;
fDomainData[fDomainCount].controller_cookie = controller_cookie; fDomainData[fDomainCount].controller_cookie = controller_cookie;
fDomainData[fDomainCount].root_node = root_node;
// initialized later to avoid call back into controller at this point // initialized later to avoid call back into controller at this point
fDomainData[fDomainCount].max_bus_devices = -1; fDomainData[fDomainCount].max_bus_devices = -1;
@@ -716,6 +711,42 @@ PCI::AddController(pci_controller *controller, void *controller_cookie)
return B_OK; return B_OK;
} }
status_t
PCI::LookupRange(uint32 type, phys_addr_t pciAddr,
uint8 &domain, pci_resource_range &range, uint8 **mappedAdr)
{
if (type >= kPciRangeEnd)
return B_BAD_VALUE;
for (uint8 curDomain = 0; curDomain < fDomainCount; curDomain++) {
pci_resource_range const *const &ranges = fDomainData[curDomain].ranges;
uint32 typeBeg, typeEnd;
if (type == kPciRangeMmio) {
typeBeg = kPciRangeMmio;
typeEnd = kPciRangeMmioEnd;
} else {
typeBeg = type;
typeEnd = type + 1;
}
for (uint32 curType = typeBeg; curType < typeEnd; curType++) {
const pci_resource_range curRange = ranges[curType];
if (pciAddr >= curRange.pci_addr && pciAddr < curRange.pci_addr + curRange.size) {
domain = curDomain;
range = curRange;
#if !(defined(__i386__) || defined(__x86_64__))
if (type == kPciRangeIoPort && mappedAdr != NULL)
*mappedAdr = fDomainData[curDomain].io_port_adr;
#endif
return B_OK;
}
}
}
return B_ENTRY_NOT_FOUND;
}
void void
PCI::InitDomainData() PCI::InitDomainData()
{ {
@@ -723,9 +754,31 @@ PCI::InitDomainData()
int32 count; int32 count;
status_t status; status_t status;
status = (*fDomainData[i].controller->get_max_bus_devices)( pci_controller_module_info *ctrlModule = fDomainData[i].controller;
fDomainData[i].controller_cookie, &count); void *ctrl = fDomainData[i].controller_cookie;
status = ctrlModule->get_max_bus_devices(ctrl, &count);
fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0; fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0;
memset(fDomainData[i].ranges, 0, sizeof(fDomainData[i].ranges));
pci_resource_range range;
for (uint32 j = 0; ctrlModule->get_range(ctrl, j, &range) >= B_OK; j++) {
if (range.type < kPciRangeEnd && range.size > 0)
fDomainData[i].ranges[range.type] = range;
}
#if !(defined(__i386__) || defined(__x86_64__))
// TODO: free resources when domain is detached
pci_resource_range &ioPortRange = fDomainData[i].ranges[kPciRangeIoPort];
if (ioPortRange.size > 0) {
fDomainData[i].io_port_area = map_physical_memory("PCI IO Ports",
ioPortRange.host_addr, ioPortRange.size, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&fDomainData[i].io_port_adr);
if (fDomainData[i].io_port_area < B_OK)
fDomainData[i].io_port_adr = NULL;
}
#endif
} }
} }
+17 -14
View File
@@ -9,9 +9,7 @@
#include <PCI.h> #include <PCI.h>
#ifdef __cplusplus #include <VectorMap.h>
#include <VectorMap.h>
#endif
#include "pci_controller.h" #include "pci_controller.h"
#include "pci_msi.h" #include "pci_msi.h"
@@ -24,8 +22,6 @@
# define TRACE(x) dprintf x # define TRACE(x) dprintf x
#endif #endif
#ifdef __cplusplus
struct PCIDev; struct PCIDev;
struct PCIBus { struct PCIBus {
@@ -54,11 +50,18 @@ struct PCIDev {
struct domain_data { struct domain_data {
// These two are set in PCI::AddController: // These two are set in PCI::AddController:
pci_controller * controller; pci_controller_module_info *controller;
void * controller_cookie; void * controller_cookie;
device_node * root_node;
// All the rest is set in PCI::InitDomainData // All the rest is set in PCI::InitDomainData
int max_bus_devices; int max_bus_devices;
pci_resource_range ranges[kPciRangeEnd];
#if !(defined(__i386__) || defined(__x86_64__))
area_id io_port_area;
uint8 * io_port_adr;
#endif
}; };
@@ -69,9 +72,13 @@ public:
void InitDomainData(); void InitDomainData();
void InitBus(); void InitBus();
status_t Finalize();
status_t AddController(pci_controller *controller, status_t AddController(pci_controller_module_info *controller,
void *controller_cookie); void *controller_cookie, device_node *root_node);
status_t LookupRange(uint32 type, phys_addr_t pciAddr,
uint8 &domain, pci_resource_range &range, uint8 **mappedAdr = NULL);
status_t GetNthInfo(long index, pci_info *outInfo); status_t GetNthInfo(long index, pci_info *outInfo);
@@ -169,8 +176,10 @@ private:
uint32 &address, uint32 *size = NULL, uint32 &address, uint32 *size = NULL,
uint8 *flags = NULL); uint8 *flags = NULL);
public:
domain_data * _GetDomainData(uint8 domain); domain_data * _GetDomainData(uint8 domain);
private:
status_t _CreateVirtualBus(uint8 domain, uint8 bus, status_t _CreateVirtualBus(uint8 domain, uint8 bus,
uint8 *virtualBus); uint8 *virtualBus);
@@ -203,12 +212,8 @@ private:
extern PCI *gPCI; extern PCI *gPCI;
#endif // __cplusplus
#ifdef __cplusplus
extern "C" { extern "C" {
#endif
status_t pci_init(void); status_t pci_init(void);
status_t pci_init_deferred(void); status_t pci_init_deferred(void);
@@ -223,8 +228,6 @@ void pci_write_config(uint8 virtualBus, uint8 device, uint8 function,
void __pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus); void __pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus);
#ifdef __cplusplus
} }
#endif
#endif /* __PCI_H__ */ #endif /* __PCI_H__ */
@@ -6,31 +6,7 @@
#ifndef __PCI_CONTROLLER_H #ifndef __PCI_CONTROLLER_H
#define __PCI_CONTROLLER_H #define __PCI_CONTROLLER_H
#include <SupportDefs.h> #include <bus/PCI.h>
typedef struct pci_controller
{
// read PCI config space
status_t (*read_pci_config)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 *value);
// write PCI config space
status_t (*write_pci_config)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value);
status_t (*get_max_bus_devices)(void *cookie, int32 *count);
status_t (*read_pci_irq)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 *irq);
status_t (*write_pci_irq)(void *cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq);
} pci_controller;
#ifdef __cplusplus #ifdef __cplusplus
@@ -39,7 +15,7 @@ extern "C" {
status_t pci_controller_init(void); status_t pci_controller_init(void);
status_t pci_controller_finalize(void); status_t pci_controller_finalize(void);
status_t pci_controller_add(pci_controller *controller, void *cookie); status_t pci_controller_add(pci_controller_module_info *controller, void *cookie);
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -0,0 +1,151 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci.h"
#include "pci_private.h"
#include "arch_cpu.h"
//#define TRACE_PCI_IO
#undef TRACE
#ifdef TRACE_PCI_IO
# define TRACE(x...) dprintf("PCI_IO: " x)
#else
# define TRACE(x...) ;
#endif
#if defined(__i386__) || defined(__x86_64__)
uint8
pci_read_io_8(int mapped_io_addr)
{
return in8(mapped_io_addr);
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
out8(value, mapped_io_addr);
}
uint16
pci_read_io_16(int mapped_io_addr)
{
return in16(mapped_io_addr);
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
out16(value, mapped_io_addr);
}
uint32
pci_read_io_32(int mapped_io_addr)
{
return in32(mapped_io_addr);
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
out32(value, mapped_io_addr);
}
#else
static uint8*
get_io_port_address(int ioPort)
{
uint8 domain;
pci_resource_range range;
uint8 *mappedAdr;
if (gPCI->LookupRange(kPciRangeIoPort, ioPort, domain, range, &mappedAdr) < B_OK)
return NULL;
return mappedAdr + ioPort;
}
uint8
pci_read_io_8(int mapped_io_addr)
{
TRACE("pci_read_io_8(%d)\n", mapped_io_addr);
vuint8* ptr = get_io_port_address(mapped_io_addr);
if (ptr == NULL)
return 0;
return *ptr;
}
void
pci_write_io_8(int mapped_io_addr, uint8 value)
{
TRACE("pci_write_io_8(%d)\n", mapped_io_addr);
vuint8* ptr = get_io_port_address(mapped_io_addr);
if (ptr == NULL)
return;
*ptr = value;
}
uint16
pci_read_io_16(int mapped_io_addr)
{
TRACE("pci_read_io_16(%d)\n", mapped_io_addr);
vuint16* ptr = (uint16*)get_io_port_address(mapped_io_addr);
if (ptr == NULL)
return 0;
return *ptr;
}
void
pci_write_io_16(int mapped_io_addr, uint16 value)
{
TRACE("pci_write_io_16(%d)\n", mapped_io_addr);
vuint16* ptr = (uint16*)get_io_port_address(mapped_io_addr);
if (ptr == NULL)
return;
*ptr = value;
}
uint32
pci_read_io_32(int mapped_io_addr)
{
TRACE("pci_read_io_32(%d)\n", mapped_io_addr);
vuint32* ptr = (uint32*)get_io_port_address(mapped_io_addr);
if (ptr == NULL)
return 0;
return *ptr;
}
void
pci_write_io_32(int mapped_io_addr, uint32 value)
{
TRACE("pci_write_io_32(%d)\n", mapped_io_addr);
vuint32* ptr = (vuint32*)get_io_port_address(mapped_io_addr);
if (ptr == NULL)
return;
*ptr = value;
}
#endif
@@ -39,8 +39,6 @@ typedef struct pci_root_module_info {
extern pci_root_module_info gPCIRootModule; extern pci_root_module_info gPCIRootModule;
extern pci_device_module_info gPCIDeviceModule; extern pci_device_module_info gPCIDeviceModule;
extern device_node* gPCIRootNode;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -65,7 +63,6 @@ status_t pci_get_powerstate(uchar virtualBus, uint8 device,
status_t pci_set_powerstate(uchar virtualBus, uint8 device, status_t pci_set_powerstate(uchar virtualBus, uint8 device,
uint8 function, uint8 newState); uint8 function, uint8 newState);
status_t pci_io_init(void);
uint8 pci_read_io_8(int mapped_io_addr); uint8 pci_read_io_8(int mapped_io_addr);
void pci_write_io_8(int mapped_io_addr, uint8 value); void pci_write_io_8(int mapped_io_addr, uint8 value);
uint16 pci_read_io_16(int mapped_io_addr); uint16 pci_read_io_16(int mapped_io_addr);
@@ -13,62 +13,18 @@
#include <string.h> #include <string.h>
#include <AutoDeleterDrivers.h>
#include "pci_private.h" #include "pci_private.h"
#include "pci.h" #include "pci.h"
#define CHECK_RET(err) {status_t _err = (err); if (_err < B_OK) return _err;}
// name of PCI root module // name of PCI root module
#define PCI_ROOT_MODULE_NAME "bus_managers/pci/root/driver_v1" #define PCI_ROOT_MODULE_NAME "bus_managers/pci/root/driver_v1"
device_node* gPCIRootNode = NULL;
static float
pci_root_supports_device(device_node* parent)
{
const char* bus;
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK)
return -1.0f;
#if defined(__riscv)
if (strcmp(bus, "fdt") == 0) {
const char* compatible;
if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false) < B_OK)
return -1.0f;
if (strcmp(compatible, "pci-host-ecam-generic") == 0
|| strcmp(compatible, "sifive,fu740-pcie") == 0) {
return 1.0f;
}
}
#elif defined(__arm__) || defined(__aarch64__)
if (strcmp(bus, "fdt") == 0) {
const char* compatible;
if (gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false) < B_OK)
return -1.0f;
if (strcmp(compatible, "pci-host-ecam-generic") == 0)
return 1.0f;
}
if (strcmp(bus, "acpi") == 0) {
const char* hid;
if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, false) < B_OK)
return -1.0f;
if (strcmp(hid, "PNP0A03") == 0 || strcmp(hid, "PNP0A08") == 0)
return 1.0f;
}
#else
if (strcmp(bus, "root") == 0)
return 1.0f;
#endif
return 0.0;
}
static status_t static status_t
pci_root_register_device(device_node* parent) pci_root_register_device(device_node* parent)
{ {
@@ -140,14 +96,21 @@ pci_root_init(device_node* node, void** _cookie)
{ {
*_cookie = node; *_cookie = node;
gPCIRootNode = node; DeviceNodePutter<&gDeviceManager> pciHostNode(gDeviceManager->get_parent_node(node));
pci_controller_module_info* pciHostModule;
void* pciHostDev;
CHECK_RET(gDeviceManager->get_driver(pciHostNode.Get(), (driver_module_info**)&pciHostModule, &pciHostDev));
module_info *module; module_info *module;
status_t res = get_module(B_PCI_MODULE_NAME, &module); status_t res = get_module(B_PCI_MODULE_NAME, &module);
if (res < B_OK) if (res < B_OK)
return res; return res;
return pci_init_deferred(); CHECK_RET(gPCI->AddController(pciHostModule, pciHostDev, node));
CHECK_RET(pci_init_deferred());
return B_OK;
} }
@@ -174,7 +137,7 @@ struct pci_root_module_info gPCIRootModule = {
pci_root_std_ops pci_root_std_ops
}, },
pci_root_supports_device, NULL,
pci_root_register_device, pci_root_register_device,
pci_root_init, pci_root_init,
NULL, // uninit NULL, // uninit
+1
View File
@@ -4,6 +4,7 @@ SubInclude HAIKU_TOP src add-ons kernel busses ata ;
SubInclude HAIKU_TOP src add-ons kernel busses agp_gart ; SubInclude HAIKU_TOP src add-ons kernel busses agp_gart ;
SubInclude HAIKU_TOP src add-ons kernel busses i2c ; SubInclude HAIKU_TOP src add-ons kernel busses i2c ;
SubInclude HAIKU_TOP src add-ons kernel busses mmc ; SubInclude HAIKU_TOP src add-ons kernel busses mmc ;
SubInclude HAIKU_TOP src add-ons kernel busses pci ;
SubInclude HAIKU_TOP src add-ons kernel busses random ; SubInclude HAIKU_TOP src add-ons kernel busses random ;
SubInclude HAIKU_TOP src add-ons kernel busses scsi ; SubInclude HAIKU_TOP src add-ons kernel busses scsi ;
SubInclude HAIKU_TOP src add-ons kernel busses usb ; SubInclude HAIKU_TOP src add-ons kernel busses usb ;
+3
View File
@@ -0,0 +1,3 @@
SubDir HAIKU_TOP src add-ons kernel busses pci ;
SubInclude HAIKU_TOP src add-ons kernel busses pci x86 ;
+15
View File
@@ -0,0 +1,15 @@
SubDir HAIKU_TOP src add-ons kernel busses pci x86 ;
SubDirC++Flags -fno-rtti ;
UsePrivateKernelHeaders ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include ;
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include
platform ;
KernelAddon <pci>x86 :
pci_acpi.cpp
X86PCIController.cpp
kernel_interface.cpp
;
@@ -0,0 +1,437 @@
/*
* Copyright 2022, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#include "X86PCIController.h"
#include "pci_acpi.h"
#include <AutoDeleterDrivers.h>
#include <util/AutoLock.h>
#include "acpi.h"
#include <string.h>
#include <new>
#define PCI_MECH1_REQ_PORT 0xCF8
#define PCI_MECH1_DATA_PORT 0xCFC
#define PCI_MECH1_REQ_DATA(bus, device, func, offset) \
(0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3))
#define PCI_MECH2_ENABLE_PORT 0x0cf8
#define PCI_MECH2_FORWARD_PORT 0x0cfa
#define PCI_MECH2_CONFIG_PORT(dev, offset) \
(uint16)(0xC00 | (dev << 8) | offset)
//#pragma mark - driver
float
X86PCIController::SupportsDevice(device_node* parent)
{
const char* bus;
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK)
return -1.0f;
if (strcmp(bus, "root") == 0)
return 1.0f;
return 0.0;
}
status_t
X86PCIController::RegisterDevice(device_node* parent)
{
device_attr attrs[] = {
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "X86 PCI Host Controller"} },
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = "bus_managers/pci/root/driver_v1"} },
{}
};
return gDeviceManager->register_node(parent, PCI_X86_DRIVER_MODULE_NAME, attrs, NULL, NULL);
}
status_t
X86PCIController::InitDriver(device_node* node, X86PCIController*& outDriver)
{
bool search_mech1 = true;
bool search_mech2 = true;
bool search_mechpcie = true;
void *config = NULL;
config = load_driver_settings("pci");
if (config) {
const char *mech = get_driver_parameter(config, "mechanism", NULL, NULL);
if (mech) {
search_mech1 = search_mech2 = search_mechpcie = false;
if (strcmp(mech, "1") == 0)
search_mech1 = true;
else if (strcmp(mech, "2") == 0)
search_mech2 = true;
else if (strcmp(mech, "pcie") == 0)
search_mechpcie = true;
else
panic("Unknown pci config mechanism setting %s\n", mech);
}
unload_driver_settings(config);
}
// PCI configuration mechanism PCIe is the preferred one.
// If it doesn't work, try mechanism 1.
// If it doesn't work, try mechanism 2.
if (search_mechpcie) {
if (CreateDriver(node, new(std::nothrow) X86PCIControllerMethPcie(), outDriver) >= B_OK)
return B_OK;
}
if (search_mech1) {
if (CreateDriver(node, new(std::nothrow) X86PCIControllerMeth1(), outDriver) >= B_OK)
return B_OK;
}
if (search_mech2) {
if (CreateDriver(node, new(std::nothrow) X86PCIControllerMeth2(), outDriver) >= B_OK)
return B_OK;
}
dprintf("PCI: no configuration mechanism found\n");
return B_ERROR;
}
status_t
X86PCIController::CreateDriver(device_node* node, X86PCIController* driverIn,
X86PCIController*& driverOut)
{
ObjectDeleter<X86PCIController> driver(driverIn);
if (!driver.IsSet())
return B_NO_MEMORY;
CHECK_RET(driver->InitDriverInt(node));
driverOut = driver.Detach();
return B_OK;
}
status_t
X86PCIController::InitDriverInt(device_node* node)
{
fNode = node;
return B_OK;
}
void
X86PCIController::UninitDriver()
{
delete this;
}
//#pragma mark - PCI controller
status_t
X86PCIController::ReadIrq(uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8& irq)
{
return B_UNSUPPORTED;
}
status_t
X86PCIController::WriteIrq(uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq)
{
return B_UNSUPPORTED;
}
status_t
X86PCIController::GetRange(uint32 index, pci_resource_range* range)
{
return B_BAD_INDEX;
}
//#pragma mark - X86PCIControllerMeth1
status_t
X86PCIControllerMeth1::InitDriverInt(device_node* node)
{
CHECK_RET(X86PCIController::InitDriverInt(node));
// 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 B_OK;
}
return B_ERROR;
}
status_t
X86PCIControllerMeth1::ReadConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 &value)
{
if (offset > 0xff)
return B_BAD_VALUE;
InterruptsSpinLocker lock(fLock);
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
switch (size) {
case 1:
value = in8(PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 2:
value = in16(PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 4:
value = in32(PCI_MECH1_DATA_PORT);
break;
default:
return B_ERROR;
}
return B_OK;
}
status_t
X86PCIControllerMeth1::WriteConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
if (offset > 0xff)
return B_BAD_VALUE;
InterruptsSpinLocker lock(fLock);
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;
case 2:
out16(value, PCI_MECH1_DATA_PORT + (offset & 3));
break;
case 4:
out32(value, PCI_MECH1_DATA_PORT);
break;
default:
return B_ERROR;
}
return B_OK;
}
status_t X86PCIControllerMeth1::GetMaxBusDevices(int32& count)
{
count = 32;
return B_OK;
}
//#pragma mark - X86PCIControllerMeth2
status_t
X86PCIControllerMeth2::InitDriverInt(device_node* node)
{
CHECK_RET(X86PCIController::InitDriverInt(node));
// 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 B_OK;
}
return B_ERROR;
}
status_t
X86PCIControllerMeth2::ReadConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 &value)
{
if (offset > 0xff)
return B_BAD_VALUE;
InterruptsSpinLocker lock(fLock);
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
out8(bus, PCI_MECH2_FORWARD_PORT);
switch (size) {
case 1:
value = in8(PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 2:
value = in16(PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 4:
value = in32(PCI_MECH2_CONFIG_PORT(device, offset));
break;
default:
return B_ERROR;
}
out8(0, PCI_MECH2_ENABLE_PORT);
return B_OK;
}
status_t
X86PCIControllerMeth2::WriteConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
if (offset > 0xff)
return B_BAD_VALUE;
InterruptsSpinLocker lock(fLock);
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
out8(bus, PCI_MECH2_FORWARD_PORT);
switch (size) {
case 1:
out8(value, PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 2:
out16(value, PCI_MECH2_CONFIG_PORT(device, offset));
break;
case 4:
out32(value, PCI_MECH2_CONFIG_PORT(device, offset));
break;
default:
return B_ERROR;
}
out8(0, PCI_MECH2_ENABLE_PORT);
return B_OK;
}
status_t X86PCIControllerMeth2::GetMaxBusDevices(int32& count)
{
count = 16;
return B_OK;
}
//#pragma mark - X86PCIControllerMethPcie
#define PCIE_VADDR(base, bus, slot, func, reg) ((base) + \
((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) | \
(((func) & 0x7) << 12) | ((reg) & 0xfff)))
status_t
X86PCIControllerMethPcie::InitDriverInt(device_node* node)
{
CHECK_RET(X86PCIController::InitDriverInt(node));
acpi_init();
struct acpi_table_mcfg* mcfg =
(struct acpi_table_mcfg*)acpi_find_table("MCFG");
if (mcfg != NULL) {
struct acpi_mcfg_allocation* end = (struct acpi_mcfg_allocation*)
((char*)mcfg + mcfg->Header.Length);
struct acpi_mcfg_allocation* alloc = (struct acpi_mcfg_allocation*)
(mcfg + 1);
for (; alloc < end; alloc++) {
dprintf("PCI: mechanism addr: %" B_PRIx64 ", seg: %x, start: "
"%x, end: %x\n", alloc->Address, alloc->PciSegment,
alloc->StartBusNumber, alloc->EndBusNumber);
if (alloc->PciSegment == 0) {
area_id mcfgArea = map_physical_memory("acpi mcfg",
alloc->Address, (alloc->EndBusNumber + 1) << 20,
B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA
| B_KERNEL_WRITE_AREA, (void **)&fPCIeBase);
if (mcfgArea < 0)
break;
fStartBusNumber = alloc->StartBusNumber;
fEndBusNumber = alloc->EndBusNumber;
dprintf("PCI: mechanism pcie controller found\n");
return B_OK;
}
}
}
return B_ERROR;
}
status_t
X86PCIControllerMethPcie::ReadConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 &value)
{
// fallback to mechanism 1 for out of range busses
if (bus < fStartBusNumber || bus > fEndBusNumber) {
return X86PCIControllerMeth1::ReadConfig(bus, device, function, offset,
size, value);
}
addr_t address = PCIE_VADDR(fPCIeBase, bus, device, function, offset);
switch (size) {
case 1:
value = *(uint8*)address;
break;
case 2:
value = *(uint16*)address;
break;
case 4:
value = *(uint32*)address;
break;
default:
return B_ERROR;
}
return B_OK;
}
status_t
X86PCIControllerMethPcie::WriteConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value)
{
// fallback to mechanism 1 for out of range busses
if (bus < fStartBusNumber || bus > fEndBusNumber) {
return X86PCIControllerMeth1::WriteConfig(bus, device, function, offset,
size, value);
}
addr_t address = PCIE_VADDR(fPCIeBase, bus, device, function, offset);
switch (size) {
case 1:
*(uint8*)address = value;
break;
case 2:
*(uint16*)address = value;
break;
case 4:
*(uint32*)address = value;
break;
default:
return B_ERROR;
}
return B_OK;
}
status_t X86PCIControllerMethPcie::GetMaxBusDevices(int32& count)
{
count = 32;
return B_OK;
}
@@ -0,0 +1,122 @@
/*
* Copyright 2022, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _X86PCICONTROLLER_H_
#define _X86PCICONTROLLER_H_
#include <bus/PCI.h>
#include <AutoDeleterOS.h>
#include <lock.h>
#define CHECK_RET(err) {status_t _err = (err); if (_err < B_OK) return _err;}
#define PCI_X86_DRIVER_MODULE_NAME "busses/pci/x86/driver_v1"
class X86PCIController {
public:
virtual ~X86PCIController() = default;
static float SupportsDevice(device_node* parent);
static status_t RegisterDevice(device_node* parent);
static status_t InitDriver(device_node* node, X86PCIController*& outDriver);
void UninitDriver();
virtual status_t ReadConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 &value) = 0;
virtual status_t WriteConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value) = 0;
virtual status_t GetMaxBusDevices(int32& count) = 0;
status_t ReadIrq(
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8& irq);
status_t WriteIrq(
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq);
status_t GetRange(uint32 index, pci_resource_range* range);
protected:
static status_t CreateDriver(device_node* node, X86PCIController* driver,
X86PCIController*& driverOut);
virtual status_t InitDriverInt(device_node* node);
protected:
spinlock fLock = B_SPINLOCK_INITIALIZER;
device_node* fNode{};
addr_t fPCIeBase{};
uint8 fStartBusNumber{};
uint8 fEndBusNumber{};
};
class X86PCIControllerMeth1: public X86PCIController {
public:
virtual ~X86PCIControllerMeth1() = default;
status_t InitDriverInt(device_node* node) override;
status_t ReadConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 &value) override;
status_t WriteConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value) override;
status_t GetMaxBusDevices(int32& count) override;
};
class X86PCIControllerMeth2: public X86PCIController {
public:
virtual ~X86PCIControllerMeth2() = default;
status_t InitDriverInt(device_node* node) final;
status_t ReadConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 &value) final;
status_t WriteConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value) final;
status_t GetMaxBusDevices(int32& count) final;
};
class X86PCIControllerMethPcie: public X86PCIControllerMeth1 {
public:
virtual ~X86PCIControllerMethPcie() = default;
status_t InitDriverInt(device_node* node) final;
status_t ReadConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 &value) final;
status_t WriteConfig(
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value) final;
status_t GetMaxBusDevices(int32& count) final;
};
extern device_manager_info* gDeviceManager;
#endif // _X86PCICONTROLLER_H_
@@ -0,0 +1,66 @@
/*
* Copyright 2022, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#include "X86PCIController.h"
device_manager_info* gDeviceManager;
pci_controller_module_info gPciControllerDriver = {
.info = {
.info = {
.name = PCI_X86_DRIVER_MODULE_NAME,
},
.supports_device = X86PCIController::SupportsDevice,
.register_device = X86PCIController::RegisterDevice,
.init_driver = [](device_node* node, void** driverCookie) {
return X86PCIController::InitDriver(node, *(X86PCIController**)driverCookie);
},
.uninit_driver = [](void* driverCookie) {
return static_cast<X86PCIController*>(driverCookie)->UninitDriver();
},
},
.read_pci_config = [](void* cookie,
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32* value) {
return static_cast<X86PCIController*>(cookie)
->ReadConfig(bus, device, function, offset, size, *value);
},
.write_pci_config = [](void* cookie,
uint8 bus, uint8 device, uint8 function,
uint16 offset, uint8 size, uint32 value) {
return static_cast<X86PCIController*>(cookie)
->WriteConfig(bus, device, function, offset, size, value);
},
.get_max_bus_devices = [](void* cookie, int32* count) {
return static_cast<X86PCIController*>(cookie)->GetMaxBusDevices(*count);
},
.read_pci_irq = [](void* cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 *irq) {
return static_cast<X86PCIController*>(cookie)->ReadIrq(bus, device, function, pin, *irq);
},
.write_pci_irq = [](void* cookie,
uint8 bus, uint8 device, uint8 function,
uint8 pin, uint8 irq) {
return static_cast<X86PCIController*>(cookie)->WriteIrq(bus, device, function, pin, irq);
},
.get_range = [](void *cookie, uint32 index, pci_resource_range* range) {
return static_cast<X86PCIController*>(cookie)->GetRange(index, range);
}
};
_EXPORT module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
{}
};
_EXPORT module_info *modules[] = {
(module_info *)&gPciControllerDriver,
NULL
};