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:
@@ -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 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 scsi : ahci virtio_scsi ;
|
||||
AddFilesToPackage add-ons kernel busses usb : <usb>uhci <usb>ohci <usb>ehci
|
||||
@@ -197,6 +198,7 @@ AddBootModuleSymlinksToPackage
|
||||
nvme_disk
|
||||
openpic@ppc
|
||||
packagefs pci
|
||||
<pci>x86@x86,x86_64
|
||||
fdt@riscv64,arm,arm64
|
||||
scsi scsi_cd scsi_disk scsi_periph silicon_image_3112 highpoint_ide_pci
|
||||
sdhci_pci
|
||||
|
||||
@@ -58,6 +58,54 @@ typedef struct 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 */
|
||||
#define B_PCI_DEVICE_DOMAIN "pci/domain" /* uint32 */
|
||||
#define B_PCI_DEVICE_BUS "pci/bus" /* uint8 */
|
||||
|
||||
@@ -3,16 +3,16 @@ SubDir HAIKU_TOP src add-ons kernel bus_managers pci ;
|
||||
UsePrivateKernelHeaders ;
|
||||
UsePrivateHeaders shared ;
|
||||
UsePrivateHeaders [ FDirName kernel util ] ;
|
||||
UseHeaders [ FDirName $(SUBDIR) arch $(TARGET_KERNEL_ARCH_DIR) ] ;
|
||||
|
||||
KernelAddon pci :
|
||||
pci.cpp
|
||||
pci_fixup.cpp
|
||||
pci_info.cpp
|
||||
pci_io.cpp
|
||||
pci_module.cpp
|
||||
pci_root.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
|
||||
@@ -20,6 +20,3 @@ ObjectHdrs [ FGristFiles pci_info$(SUFOBJ) ]
|
||||
: [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR_$(TARGET_PACKAGING_ARCH)) apps
|
||||
devices ] ;
|
||||
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, ®s, ®sLen);
|
||||
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, ®s, ®sLen);
|
||||
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
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "pci_private.h"
|
||||
#include "pci.h"
|
||||
|
||||
|
||||
#define TRACE_CAP(x...) dprintf(x)
|
||||
#define FLOW(x...)
|
||||
//#define FLOW(x...) dprintf(x)
|
||||
@@ -32,13 +33,6 @@ PCI *gPCI;
|
||||
// #pragma mark bus manager exports
|
||||
|
||||
|
||||
status_t
|
||||
pci_controller_add(pci_controller *controller, void *cookie)
|
||||
{
|
||||
return gPCI->AddController(controller, cookie);
|
||||
}
|
||||
|
||||
|
||||
long
|
||||
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
|
||||
pci_find_capability(uint8 virtualBus, uint8 device, uint8 function,
|
||||
uint8 capID, uint8 *offset)
|
||||
@@ -155,11 +166,10 @@ pci_reserve_device(uchar virtualBus, uchar device, uchar function,
|
||||
device_node *node, *legacy;
|
||||
|
||||
status = B_DEVICE_NOT_FOUND;
|
||||
if (gPCIRootNode == NULL)
|
||||
goto err1;
|
||||
device_node *root_pci_node = gPCI->_GetDomainData(domain)->root_node;
|
||||
|
||||
node = NULL;
|
||||
if (gDeviceManager->get_next_child_node(gPCIRootNode,
|
||||
if (gDeviceManager->get_next_child_node(root_pci_node,
|
||||
matchThis, &node) < B_OK) {
|
||||
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,
|
||||
// domain, bus, device, function, driverName, nodeCookie));
|
||||
|
||||
device_attr matchPCIRoot[] = {
|
||||
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "PCI"}},
|
||||
{NULL}
|
||||
};
|
||||
device_attr matchThis[] = {
|
||||
// info about device
|
||||
{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}},
|
||||
{NULL}
|
||||
};
|
||||
device_node *root, *pci, *node, *legacy, *drv;
|
||||
device_node *pci, *node, *legacy, *drv;
|
||||
|
||||
status = B_DEVICE_NOT_FOUND;
|
||||
root = gDeviceManager->get_root_node();
|
||||
if (!root)
|
||||
return status;
|
||||
|
||||
pci = NULL;
|
||||
if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
|
||||
goto err0;
|
||||
pci = gPCI->_GetDomainData(domain)->root_node;
|
||||
|
||||
node = NULL;
|
||||
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...
|
||||
|
||||
gDeviceManager->put_node(node);
|
||||
gDeviceManager->put_node(pci);
|
||||
gDeviceManager->put_node(root);
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
@@ -281,9 +280,6 @@ err3:
|
||||
err2:
|
||||
gDeviceManager->put_node(node);
|
||||
err1:
|
||||
gDeviceManager->put_node(pci);
|
||||
err0:
|
||||
gDeviceManager->put_node(root);
|
||||
TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
|
||||
strerror(status)));
|
||||
return status;
|
||||
@@ -480,29 +476,14 @@ pcirefresh(int argc, char **argv)
|
||||
static bool sInitDone;
|
||||
|
||||
|
||||
status_t __attribute__((weak)) pci_controller_finalize() { return B_OK; }
|
||||
|
||||
|
||||
status_t
|
||||
pci_init_deferred(void)
|
||||
{
|
||||
dprintf("pci_init_deferred()\n");
|
||||
|
||||
if (sInitDone)
|
||||
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("in32", &display_io, "dump io words (32-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("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"));
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -539,14 +520,7 @@ status_t
|
||||
pci_init(void)
|
||||
{
|
||||
gPCI = new PCI;
|
||||
|
||||
status_t ret = pci_init_deferred();
|
||||
if (ret == B_DEV_NOT_READY) {
|
||||
TRACE(("PCI: init deferred\n"));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
@@ -701,13 +694,15 @@ PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus)
|
||||
|
||||
|
||||
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)
|
||||
return B_ERROR;
|
||||
|
||||
fDomainData[fDomainCount].controller = controller;
|
||||
fDomainData[fDomainCount].controller_cookie = controller_cookie;
|
||||
fDomainData[fDomainCount].root_node = root_node;
|
||||
|
||||
// initialized later to avoid call back into controller at this point
|
||||
fDomainData[fDomainCount].max_bus_devices = -1;
|
||||
@@ -716,6 +711,42 @@ PCI::AddController(pci_controller *controller, void *controller_cookie)
|
||||
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
|
||||
PCI::InitDomainData()
|
||||
{
|
||||
@@ -723,9 +754,31 @@ PCI::InitDomainData()
|
||||
int32 count;
|
||||
status_t status;
|
||||
|
||||
status = (*fDomainData[i].controller->get_max_bus_devices)(
|
||||
fDomainData[i].controller_cookie, &count);
|
||||
pci_controller_module_info *ctrlModule = fDomainData[i].controller;
|
||||
void *ctrl = fDomainData[i].controller_cookie;
|
||||
|
||||
status = ctrlModule->get_max_bus_devices(ctrl, &count);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
#include <PCI.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <VectorMap.h>
|
||||
#endif
|
||||
#include <VectorMap.h>
|
||||
|
||||
#include "pci_controller.h"
|
||||
#include "pci_msi.h"
|
||||
@@ -24,8 +22,6 @@
|
||||
# define TRACE(x) dprintf x
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct PCIDev;
|
||||
|
||||
struct PCIBus {
|
||||
@@ -54,11 +50,18 @@ struct PCIDev {
|
||||
|
||||
struct domain_data {
|
||||
// These two are set in PCI::AddController:
|
||||
pci_controller * controller;
|
||||
pci_controller_module_info *controller;
|
||||
void * controller_cookie;
|
||||
device_node * root_node;
|
||||
|
||||
// All the rest is set in PCI::InitDomainData
|
||||
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 InitBus();
|
||||
status_t Finalize();
|
||||
|
||||
status_t AddController(pci_controller *controller,
|
||||
void *controller_cookie);
|
||||
status_t AddController(pci_controller_module_info *controller,
|
||||
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);
|
||||
|
||||
@@ -169,8 +176,10 @@ private:
|
||||
uint32 &address, uint32 *size = NULL,
|
||||
uint8 *flags = NULL);
|
||||
|
||||
public:
|
||||
domain_data * _GetDomainData(uint8 domain);
|
||||
|
||||
private:
|
||||
status_t _CreateVirtualBus(uint8 domain, uint8 bus,
|
||||
uint8 *virtualBus);
|
||||
|
||||
@@ -203,12 +212,8 @@ private:
|
||||
|
||||
extern PCI *gPCI;
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
status_t pci_init(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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PCI_H__ */
|
||||
|
||||
@@ -6,31 +6,7 @@
|
||||
#ifndef __PCI_CONTROLLER_H
|
||||
#define __PCI_CONTROLLER_H
|
||||
|
||||
#include <SupportDefs.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;
|
||||
#include <bus/PCI.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -39,7 +15,7 @@ extern "C" {
|
||||
|
||||
status_t pci_controller_init(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
|
||||
}
|
||||
|
||||
@@ -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_device_module_info gPCIDeviceModule;
|
||||
|
||||
extern device_node* gPCIRootNode;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -50,7 +48,7 @@ phys_addr_t pci_ram_address(phys_addr_t physical_address_in_system_memory);
|
||||
|
||||
status_t pci_find_capability(uint8 bus, uint8 device, uint8 function,
|
||||
uint8 cap_id, uint8 *offset);
|
||||
status_t pci_find_extended_capability(uint8 bus, uint8 device, uint8 function,
|
||||
status_t pci_find_extended_capability(uint8 bus, uint8 device, uint8 function,
|
||||
uint16 cap_id, uint16 *offset);
|
||||
|
||||
status_t pci_reserve_device(uchar virtualBus, uchar device, uchar function,
|
||||
@@ -65,7 +63,6 @@ status_t pci_get_powerstate(uchar virtualBus, uint8 device,
|
||||
status_t pci_set_powerstate(uchar virtualBus, uint8 device,
|
||||
uint8 function, uint8 newState);
|
||||
|
||||
status_t pci_io_init(void);
|
||||
uint8 pci_read_io_8(int mapped_io_addr);
|
||||
void pci_write_io_8(int mapped_io_addr, uint8 value);
|
||||
uint16 pci_read_io_16(int mapped_io_addr);
|
||||
|
||||
@@ -13,62 +13,18 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <AutoDeleterDrivers.h>
|
||||
|
||||
#include "pci_private.h"
|
||||
#include "pci.h"
|
||||
|
||||
#define CHECK_RET(err) {status_t _err = (err); if (_err < B_OK) return _err;}
|
||||
|
||||
|
||||
// name of PCI root module
|
||||
#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
|
||||
pci_root_register_device(device_node* parent)
|
||||
{
|
||||
@@ -140,14 +96,21 @@ pci_root_init(device_node* node, void** _cookie)
|
||||
{
|
||||
*_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;
|
||||
status_t res = get_module(B_PCI_MODULE_NAME, &module);
|
||||
if (res < B_OK)
|
||||
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_supports_device,
|
||||
NULL,
|
||||
pci_root_register_device,
|
||||
pci_root_init,
|
||||
NULL, // uninit
|
||||
|
||||
@@ -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 i2c ;
|
||||
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 scsi ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses usb ;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel busses pci ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses pci x86 ;
|
||||
@@ -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
|
||||
};
|
||||
Reference in New Issue
Block a user