PCI: try harder to fixup broken resource ranges in ACPI tables

Try to handle two cases mentionned here: https://github.com/xCuri0/ReBarUEFI/wiki/DSDT-Patching

- Min/Max/Length/Gran are all zero, but no resource tag (ignore the range)
- Length is larger than Min/Max window (recompute the length)

Should fix #18454

Change-Id: I536dc06fcfbfc9aacf5eb6b9563cf03f9d09178a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7581
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
PulkoMandy 2024-03-31 22:01:11 +02:00 committed by waddlesplash
parent dae087ed53
commit 5c6e17e773

View File

@ -87,7 +87,7 @@ ECAMPCIControllerACPI::AcpiCrsScanCallback(acpi_resource *res, void *context)
*
* This is a template because ACPI resources can be encoded using 8, 16, 32 or 64 bit values.
*/
template<typename T> void
template<typename T> bool
DecodeAddress(const T& resource, pci_resource_range& range)
{
const auto& acpiRange = resource.address;
@ -100,15 +100,29 @@ DecodeAddress(const T& resource, pci_resource_range& range)
// If maximum isn't set, compute it from minimum and length
auto addressLength = acpiRange.address_length;
phys_addr_t addressMaximum = acpiRange.maximum;
if (addressLength == 0)
addressLength = acpiRange.maximum - acpiRange.minimum + 1;
else if (!resource.maxAddress_fixed)
if (addressLength == 0 && addressMaximum <= acpiRange.minimum) {
// There's nothing we can do with that...
dprintf("PCI: Ignore empty ACPI range\n");
return false;
} else if (!resource.maxAddress_fixed) {
if (addressLength == 0) {
dprintf("PCI: maxAddress and addressLength are not set, ignore range\n");
return false;
}
dprintf("PCI: maxAddress is not set, compute it\n");
addressMaximum = acpiRange.minimum + addressLength - 1;
ASSERT((phys_addr_t)(acpiRange.minimum + addressLength - 1) == addressMaximum);
} else if (addressLength != addressMaximum - acpiRange.minimum + 1) {
dprintf("PCI: Fixup invalid length from ACPI!\n");
addressLength = addressMaximum - acpiRange.minimum + 1;
}
range.host_address = acpiRange.minimum + acpiRange.translation_offset;
range.pci_address = acpiRange.minimum;
range.size = addressLength;
return true;
}
@ -120,18 +134,21 @@ ECAMPCIControllerACPI::AcpiCrsScanCallbackInt(acpi_resource *res)
switch (res->type) {
case ACPI_RESOURCE_TYPE_ADDRESS16: {
const auto& address = res->data.address16;
DecodeAddress(address, range);
if (!DecodeAddress(address, range))
return B_OK;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS32: {
const auto& address = res->data.address32;
DecodeAddress(address, range);
if (!DecodeAddress(address, range))
return B_OK;
range.address_type |= PCI_address_type_32;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS64: {
const auto& address = res->data.address64;
DecodeAddress(address, range);
if (!DecodeAddress(address, range))
return B_OK;
range.address_type |= PCI_address_type_64;
break;
}