Commit ee67c110 authored by Will Deacon's avatar Will Deacon
Browse files

arm64: acpi: Map EFI_MEMORY_WT memory as Normal-NC



The only user we have of Normal Write-Through memory is in the ACPI code
when mapping memory regions advertised as EFI_MEMORY_WT. Since most (all?)
CPUs treat write-through as non-cacheable under the hood, don't bother
with the extra memory type here and just treat EFI_MEMORY_WT the same way
as EFI_MEMORY_WC by mapping it to the Normal-NC memory type instead and
emitting a warning if we have failed to find an alternative EFI memory
type.

Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Christoph Hellwig <hch@lst.de>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Acked-by: default avatarArd Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20210527110319.22157-3-will@kernel.org


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 58cc6b72
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -239,6 +239,18 @@ void __init acpi_boot_table_init(void)
	}
}

static pgprot_t __acpi_get_writethrough_mem_attribute(void)
{
	/*
	 * Although UEFI specifies the use of Normal Write-through for
	 * EFI_MEMORY_WT, it is seldom used in practice and not implemented
	 * by most (all?) CPUs. Rather than allocate a MAIR just for this
	 * purpose, emit a warning and use Normal Non-cacheable instead.
	 */
	pr_warn_once("No MAIR allocation for EFI_MEMORY_WT; treating as Normal Non-cacheable\n");
	return __pgprot(PROT_NORMAL_NC);
}

pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
{
	/*
@@ -246,7 +258,7 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
	 * types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is
	 * mapped to a corresponding MAIR attribute encoding.
	 * The EFI memory attribute advises all possible capabilities
	 * of a memory region. We use the most efficient capability.
	 * of a memory region.
	 */

	u64 attr;
@@ -254,10 +266,10 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
	attr = efi_mem_attributes(addr);
	if (attr & EFI_MEMORY_WB)
		return PAGE_KERNEL;
	if (attr & EFI_MEMORY_WT)
		return __pgprot(PROT_NORMAL_WT);
	if (attr & EFI_MEMORY_WC)
		return __pgprot(PROT_NORMAL_NC);
	if (attr & EFI_MEMORY_WT)
		return __acpi_get_writethrough_mem_attribute();
	return __pgprot(PROT_DEVICE_nGnRnE);
}

@@ -340,10 +352,10 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
		default:
			if (region->attribute & EFI_MEMORY_WB)
				prot = PAGE_KERNEL;
			else if (region->attribute & EFI_MEMORY_WT)
				prot = __pgprot(PROT_NORMAL_WT);
			else if (region->attribute & EFI_MEMORY_WC)
				prot = __pgprot(PROT_NORMAL_NC);
			else if (region->attribute & EFI_MEMORY_WT)
				prot = __acpi_get_writethrough_mem_attribute();
		}
	}
	return __ioremap(phys, size, prot);