} hpet_sbdf;
extern unsigned int amd_iommu_acpi_info;
+extern unsigned int amd_iommu_max_paging_mode;
extern int amd_iommu_min_paging_mode;
extern void *shared_intremap_table;
while ( max_frames > PTE_PER_TABLE_SIZE )
{
max_frames = PTE_PER_TABLE_ALIGN(max_frames) >> PTE_PER_TABLE_SHIFT;
- if ( ++level > 6 )
+ if ( ++level > amd_iommu_max_paging_mode )
return -ENOMEM;
}
static int __init parse_ivmd_block(const struct acpi_ivrs_memory *ivmd_block)
{
unsigned long start_addr, mem_length, base, limit;
+ unsigned int addr_bits;
bool iw = true, ir = true, exclusion = false;
if ( ivmd_block->header.length < sizeof(*ivmd_block) )
AMD_IOMMU_DEBUG("IVMD Block: type %#x phys %#lx len %#lx\n",
ivmd_block->header.type, start_addr, mem_length);
+ addr_bits = min(MASK_EXTR(amd_iommu_acpi_info, ACPI_IVRS_PHYSICAL_SIZE),
+ MASK_EXTR(amd_iommu_acpi_info, ACPI_IVRS_VIRTUAL_SIZE));
+ if ( amd_iommu_get_paging_mode(PFN_UP(start_addr + mem_length)) < 0 ||
+ (addr_bits < BITS_PER_LONG &&
+ ((start_addr + mem_length - 1) >> addr_bits)) )
+ {
+ AMD_IOMMU_DEBUG("IVMD: [%lx,%lx) is not IOMMU addressable\n",
+ start_addr, start_addr + mem_length);
+ return 0;
+ }
+
if ( !e820_all_mapped(base, limit + PAGE_SIZE, E820_RESERVED) )
{
paddr_t addr;
iommu->features.raw =
readq(iommu->mmio_base + IOMMU_EXT_FEATURE_MMIO_OFFSET);
+
+ if ( 4 + iommu->features.flds.hats < amd_iommu_max_paging_mode )
+ amd_iommu_max_paging_mode = 4 + iommu->features.flds.hats;
}
/* Don't log the same set of features over and over. */
else if ( list_empty(&amd_iommu_head) )
AMD_IOMMU_DEBUG("EFRSup not set in ACPI table; will fall back to hardware\n");
+ if ( (amd_iommu_acpi_info & ACPI_IVRS_EFR_SUP) &&
+ 4 + iommu->features.flds.hats < amd_iommu_max_paging_mode )
+ amd_iommu_max_paging_mode = 4 + iommu->features.flds.hats;
+
/* override IOMMU HT flags */
iommu->ht_flags = ivhd_block->header.flags;
get_iommu_features(iommu);
+ /*
+ * Late extended feature determination may cause previously mappable
+ * IVMD ranges to become unmappable.
+ */
+ if ( amd_iommu_max_paging_mode < amd_iommu_min_paging_mode )
+ return -ERANGE;
+
return 0;
}