PCI: Support more than 6 PCI memory ranges.

Also use the standard kernel-wide constants for IO or memory space
rather than defining new ones, as well as the PCI constants for
address types.

Change-Id: Iad03f7666ad5121a5c9a398339aa1a191339a1d1
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7336
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2024-01-15 14:49:36 -05:00 committed by waddlesplash
parent 6533df4fe4
commit fabb71cc0e
9 changed files with 107 additions and 102 deletions

View File

@ -58,20 +58,11 @@ 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;
uint8 address_type;
phys_addr_t host_address;
phys_addr_t pci_address;
uint64 size;
} pci_resource_range;

View File

@ -81,8 +81,8 @@ pci_ram_address(phys_addr_t 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;
if (gPCI->LookupRange(B_IO_MEMORY, childAdr, domain, range) >= B_OK)
hostAdr = childAdr - range.pci_address + range.host_address;
#endif
//dprintf("pci_ram_address(%#" B_PRIx64 ") -> %#" B_PRIx64 "\n", childAdr, hostAdr);
return hostAdr;
@ -673,33 +673,27 @@ 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;
const auto &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) {
for (int32 i = 0; i < ranges.Count(); i++) {
const pci_resource_range curRange = ranges[i];
if (curRange.type != type)
continue;
if (pciAddr >= curRange.pci_address
&& pciAddr < (curRange.pci_address + curRange.size)) {
domain = curDomain;
range = curRange;
#if !(defined(__i386__) || defined(__x86_64__))
if (type == kPciRangeIoPort && mappedAdr != NULL)
if (type == B_IO_PORT && mappedAdr != NULL)
*mappedAdr = fDomainData[curDomain].io_port_adr;
#endif
return B_OK;
}
}
}
return B_ENTRY_NOT_FOUND;
}
@ -716,23 +710,27 @@ PCI::InitDomainData(domain_data &data)
status = ctrl->get_max_bus_devices(ctrlCookie, &count);
data.max_bus_devices = (status == B_OK) ? count : 0;
memset(data.ranges, 0, sizeof(data.ranges));
pci_resource_range range;
for (uint32 j = 0; ctrl->get_range(ctrlCookie, j, &range) >= B_OK; j++) {
if (range.type < kPciRangeEnd && range.size > 0)
data.ranges[range.type] = range;
}
for (uint32 j = 0; ctrl->get_range(ctrlCookie, j, &range) >= B_OK; j++)
data.ranges.Add(range);
#if !(defined(__i386__) || defined(__x86_64__))
// TODO: free resources when domain is detached
pci_resource_range &ioPortRange = data.ranges[kPciRangeIoPort];
if (ioPortRange.size > 0) {
data.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 **)&data.io_port_adr);
for (int32 i = 0; i < data.ranges.Count(); i++) {
pci_resource_range &ioPortRange = data.ranges[i];
if (ioPortRange.type != B_IO_PORT)
continue;
if (data.io_port_area < B_OK)
data.io_port_adr = NULL;
if (ioPortRange.size > 0) {
data.io_port_area = map_physical_memory("PCI IO Ports",
ioPortRange.host_address, ioPortRange.size, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&data.io_port_adr);
if (data.io_port_area < B_OK)
data.io_port_adr = NULL;
// TODO: Map other IO ports (if any.)
break;
}
}
#endif
}

View File

@ -47,6 +47,14 @@ struct PCIDev {
struct domain_data {
~domain_data()
{
#if !(defined(__i386__) || defined(__x86_64__))
if (io_port_area >= 0)
delete_area(io_port_area);
#endif
}
// These two are set in PCI::AddController:
pci_controller_module_info *controller;
void * controller_cookie;
@ -55,11 +63,11 @@ struct domain_data {
// All the rest is set in PCI::InitDomainData
int max_bus_devices;
pci_resource_range ranges[kPciRangeEnd];
Vector<pci_resource_range> ranges;
#if !(defined(__i386__) || defined(__x86_64__))
area_id io_port_area;
uint8 * io_port_adr;
area_id io_port_area = -1;
uint8 * io_port_adr = NULL;
#endif
};

View File

@ -201,28 +201,30 @@ DWPCIController::ReadResourceInfo()
uint64_t parentAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3));
uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5));
uint32 outType = kPciRangeInvalid;
pci_resource_range range = {};
range.host_address = parentAdr;
range.pci_address = childAdr;
range.size = len;
if ((type & fdtPciRangePrefechable) != 0)
range.address_type |= PCI_address_prefetchable;
switch (type & fdtPciRangeTypeMask) {
case fdtPciRangeIoPort:
outType = kPciRangeIoPort;
range.type = B_IO_PORT;
fResourceRanges.Add(range);
break;
case fdtPciRangeMmio32Bit:
outType = kPciRangeMmio;
range.type = B_IO_MEMORY;
range.address_type |= PCI_address_type_32;
fResourceRanges.Add(range);
break;
case fdtPciRangeMmio64Bit:
outType = kPciRangeMmio + kPciRangeMmio64Bit;
range.type = B_IO_MEMORY;
range.address_type |= PCI_address_type_64;
fResourceRanges.Add(range);
break;
}
if (outType >= kPciRangeMmio && outType < kPciRangeMmioEnd
&& (fdtPciRangePrefechable & type) != 0)
outType += kPciRangeMmioPrefetch;
if (outType != kPciRangeInvalid) {
fResourceRanges[outType].type = outType;
fResourceRanges[outType].host_addr = parentAdr;
fResourceRanges[outType].pci_addr = childAdr;
fResourceRanges[outType].size = len;
}
switch (type & fdtPciRangeTypeMask) {
case fdtPciRangeConfig: dprintf("CONFIG"); break;
@ -392,7 +394,7 @@ DWPCIController::WriteIrq(uint8 bus, uint8 device, uint8 function,
status_t
DWPCIController::GetRange(uint32 index, pci_resource_range* range)
{
if (index >= kPciRangeEnd)
if (index >= (uint32)fResourceRanges.Count())
return B_BAD_INDEX;
*range = fResourceRanges[index];

View File

@ -12,6 +12,7 @@
#include <AutoDeleterOS.h>
#include <lock.h>
#include <util/Vector.h>
#define CHECK_RET(err) {status_t _err = (err); if (_err < B_OK) return _err;}
@ -231,7 +232,7 @@ private:
addr_t fConfigBase {};
size_t fConfigSize {};
pci_resource_range fResourceRanges[kPciRangeEnd] {};
Vector<pci_resource_range> fResourceRanges;
InterruptMapMask fInterruptMapMask {};
uint32 fInterruptMapLen {};
ArrayDeleter<InterruptMap> fInterruptMap;

View File

@ -245,7 +245,7 @@ ECAMPCIController::WriteIrq(uint8 bus, uint8 device, uint8 function,
status_t
ECAMPCIController::GetRange(uint32 index, pci_resource_range* range)
{
if (index >= kPciRangeEnd)
if (index >= (uint32)fResourceRanges.Count())
return B_BAD_INDEX;
*range = fResourceRanges[index];

View File

@ -13,6 +13,7 @@
#include <AutoDeleterOS.h>
#include <lock.h>
#include <util/Vector.h>
#define CHECK_RET(err) {status_t _err = (err); if (_err < B_OK) return _err;}
@ -128,7 +129,7 @@ protected:
uint8 volatile* fRegs{};
uint64 fRegsLen{};
pci_resource_range fResourceRanges[kPciRangeEnd] {};
Vector<pci_resource_range> fResourceRanges;
};

View File

@ -106,8 +106,8 @@ DecodeAddress(const T& resource, pci_resource_range& range)
addressMaximum = acpiRange.minimum + addressLength - 1;
ASSERT((phys_addr_t)(acpiRange.minimum + addressLength - 1) == addressMaximum);
range.host_addr = acpiRange.minimum + acpiRange.translation_offset;
range.pci_addr = acpiRange.minimum;
range.host_address = acpiRange.minimum + acpiRange.translation_offset;
range.pci_address = acpiRange.minimum;
range.size = addressLength;
}
@ -115,44 +115,46 @@ DecodeAddress(const T& resource, pci_resource_range& range)
acpi_status
ECAMPCIControllerACPI::AcpiCrsScanCallbackInt(acpi_resource *res)
{
uint32 outType;
switch (res->data.address.resource_type) {
case 0: // ACPI_MEMORY_RANGE
outType = kPciRangeMmio;
if (res->type == ACPI_RESOURCE_TYPE_ADDRESS64)
outType += kPciRangeMmio64Bit;
if (res->data.address.info.mem.caching == 3 /*ACPI_PREFETCHABLE_MEMORY*/)
outType += kPciRangeMmioPrefetch;
break;
case 1: // ACPI_IO_RANGE
outType = kPciRangeIoPort;
break;
default:
return B_OK;
}
pci_resource_range& range = fResourceRanges[outType];
range.type = outType;
pci_resource_range range = {};
switch (res->type) {
case ACPI_RESOURCE_TYPE_ADDRESS16: {
const auto &address = res->data.address16;
const auto& address = res->data.address16;
DecodeAddress(address, range);
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS32: {
const auto &address = res->data.address32;
const auto& address = res->data.address32;
DecodeAddress(address, range);
range.address_type |= PCI_address_type_32;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS64: {
const auto &address = res->data.address64;
const auto& address = res->data.address64;
DecodeAddress(address, range);
range.address_type |= PCI_address_type_64;
break;
}
default:
return B_OK;
}
switch (res->data.address.resource_type) {
case 0: // ACPI_MEMORY_RANGE
range.type = B_IO_MEMORY;
if (res->data.address.info.mem.caching == 3 /*ACPI_PREFETCHABLE_MEMORY*/)
range.address_type |= PCI_address_prefetchable;
break;
case 1: // ACPI_IO_RANGE
range.type = B_IO_PORT;
break;
default:
return B_OK;
}
fResourceRanges.Add(range);
return B_OK;
}

View File

@ -44,28 +44,30 @@ ECAMPCIControllerFDT::ReadResourceInfo()
uint64_t parentAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3));
uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5));
uint32 outType = kPciRangeInvalid;
pci_resource_range range = {};
range.host_address = parentAdr;
range.pci_address = childAdr;
range.size = len;
if ((type & fdtPciRangePrefechable) != 0)
range.address_type |= PCI_address_prefetchable;
switch (type & fdtPciRangeTypeMask) {
case fdtPciRangeIoPort:
outType = kPciRangeIoPort;
range.type = B_IO_PORT;
fResourceRanges.Add(range);
break;
case fdtPciRangeMmio32Bit:
outType = kPciRangeMmio;
range.type = B_IO_MEMORY;
range.address_type |= PCI_address_type_32;
fResourceRanges.Add(range);
break;
case fdtPciRangeMmio64Bit:
outType = kPciRangeMmio + kPciRangeMmio64Bit;
range.type = B_IO_MEMORY;
range.address_type |= PCI_address_type_64;
fResourceRanges.Add(range);
break;
}
if (outType >= kPciRangeMmio && outType < kPciRangeMmioEnd
&& (fdtPciRangePrefechable & type) != 0)
outType += kPciRangeMmioPrefetch;
if (outType != kPciRangeInvalid) {
fResourceRanges[outType].type = outType;
fResourceRanges[outType].host_addr = parentAdr;
fResourceRanges[outType].pci_addr = childAdr;
fResourceRanges[outType].size = len;
}
switch (type & fdtPciRangeTypeMask) {
case fdtPciRangeConfig: dprintf("CONFIG"); break;