Skip to content

Commit

Permalink
arm64: use both ZONE_DMA and ZONE_DMA32
Browse files Browse the repository at this point in the history
commit 1a8e1ce upstream.

So far all arm64 devices have supported 32 bit DMA masks for their
peripherals. This is not true anymore for the Raspberry Pi 4 as most of
it's peripherals can only address the first GB of memory on a total of
up to 4 GB.

This goes against ZONE_DMA32's intent, as it's expected for ZONE_DMA32
to be addressable with a 32 bit mask. So it was decided to re-introduce
ZONE_DMA in arm64.

ZONE_DMA will contain the lower 1G of memory, which is currently the
memory area addressable by any peripheral on an arm64 device.
ZONE_DMA32 will contain the rest of the 32 bit addressable memory.

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
  • Loading branch information
Nicolas Saenz Julienne authored and pelwell committed Mar 11, 2020
1 parent 82b2495 commit a0fbb84
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 15 deletions.
4 changes: 4 additions & 0 deletions arch/arm64/Kconfig
Expand Up @@ -267,6 +267,10 @@ config GENERIC_CSUM
config GENERIC_CALIBRATE_DELAY
def_bool y

config ZONE_DMA
bool "Support DMA zone" if EXPERT
default y

config ZONE_DMA32
bool "Support DMA32 zone" if EXPERT
default y
Expand Down
2 changes: 2 additions & 0 deletions arch/arm64/include/asm/page.h
Expand Up @@ -38,4 +38,6 @@ extern int pfn_valid(unsigned long);

#include <asm-generic/getorder.h>

#define ARCH_ZONE_DMA_BITS 30

#endif
54 changes: 39 additions & 15 deletions arch/arm64/mm/init.c
Expand Up @@ -56,6 +56,13 @@ EXPORT_SYMBOL(physvirt_offset);
struct page *vmemmap __ro_after_init;
EXPORT_SYMBOL(vmemmap);

/*
* We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of
* memory as some devices, namely the Raspberry Pi 4, have peripherals with
* this limited view of the memory. ZONE_DMA32 will cover the rest of the 32
* bit addressable memory area.
*/
phys_addr_t arm64_dma_phys_limit __ro_after_init;
phys_addr_t arm64_dma32_phys_limit __ro_after_init;

#ifdef CONFIG_KEXEC_CORE
Expand Down Expand Up @@ -169,15 +176,16 @@ static void __init reserve_elfcorehdr(void)
{
}
#endif /* CONFIG_CRASH_DUMP */

/*
* Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It
* currently assumes that for memory starting above 4G, 32-bit devices will
* use a DMA offset.
* Return the maximum physical address for a zone with a given address size
* limit. It currently assumes that for memory starting above 4G, 32-bit
* devices will use a DMA offset.
*/
static phys_addr_t __init max_zone_dma32_phys(void)
static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
{
phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
return min(offset + (1ULL << 30), memblock_end_of_DRAM());
phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits);
return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM());
}

#ifdef CONFIG_NUMA
Expand All @@ -186,6 +194,9 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};

#ifdef CONFIG_ZONE_DMA
max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit);
#endif
#ifdef CONFIG_ZONE_DMA32
max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
#endif
Expand All @@ -201,13 +212,18 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
struct memblock_region *reg;
unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
unsigned long max_dma32 = min;
unsigned long max_dma = min;

memset(zone_size, 0, sizeof(zone_size));

/* 4GB maximum for 32-bit only capable devices */
#ifdef CONFIG_ZONE_DMA
max_dma = PFN_DOWN(arm64_dma_phys_limit);
zone_size[ZONE_DMA] = max_dma - min;
max_dma32 = max_dma;
#endif
#ifdef CONFIG_ZONE_DMA32
max_dma32 = PFN_DOWN(arm64_dma32_phys_limit);
zone_size[ZONE_DMA32] = max_dma32 - min;
zone_size[ZONE_DMA32] = max_dma32 - max_dma;
#endif
zone_size[ZONE_NORMAL] = max - max_dma32;

Expand All @@ -219,11 +235,17 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)

if (start >= max)
continue;

#ifdef CONFIG_ZONE_DMA
if (start < max_dma) {
unsigned long dma_end = min_not_zero(end, max_dma);
zhole_size[ZONE_DMA] -= dma_end - start;
}
#endif
#ifdef CONFIG_ZONE_DMA32
if (start < max_dma32) {
unsigned long dma_end = min(end, max_dma32);
zhole_size[ZONE_DMA32] -= dma_end - start;
unsigned long dma32_end = min(end, max_dma32);
unsigned long dma32_start = max(start, max_dma);
zhole_size[ZONE_DMA32] -= dma32_end - dma32_start;
}
#endif
if (end > max_dma32) {
Expand Down Expand Up @@ -418,9 +440,11 @@ void __init arm64_memblock_init(void)

early_init_fdt_scan_reserved_mem();

/* 4GB maximum for 32-bit only capable devices */
if (IS_ENABLED(CONFIG_ZONE_DMA))
arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS);

if (IS_ENABLED(CONFIG_ZONE_DMA32))
arm64_dma32_phys_limit = max_zone_dma32_phys();
arm64_dma32_phys_limit = max_zone_phys(32);
else
arm64_dma32_phys_limit = PHYS_MASK + 1;

Expand All @@ -430,7 +454,7 @@ void __init arm64_memblock_init(void)

high_memory = __va(memblock_end_of_DRAM() - 1) + 1;

dma_contiguous_reserve(arm64_dma32_phys_limit);
dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit);
}

void __init bootmem_init(void)
Expand Down Expand Up @@ -534,7 +558,7 @@ static void __init free_unused_memmap(void)
void __init mem_init(void)
{
if (swiotlb_force == SWIOTLB_FORCE ||
max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT))
max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit))
swiotlb_init(1);
else
swiotlb_force = SWIOTLB_NO_FORCE;
Expand Down

0 comments on commit a0fbb84

Please sign in to comment.