Skip to content

Commit

Permalink
Merge tag 'arm-smmu-updates' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/will/linux into arm/smmu

Arm SMMU updates for 5.10

- Continued SVM enablement, where page-table is shared with CPU

- Groundwork to support integrated SMMU with Adreno GPU

- Allow disabling of MSI-based polling on the kernel command-line

- Minor driver fixes and cleanups (octal permissions, error messages, ...)
  • Loading branch information
Joerg Roedel committed Oct 1, 2020
2 parents f75aef3 + e2eae09 commit 0dd4ce6
Showing 18 changed files with 1,410 additions and 798 deletions.
3 changes: 1 addition & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
@@ -1506,8 +1506,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/iommu/arm,smmu*
F: drivers/iommu/arm/
F: drivers/iommu/io-pgtable-arm-v7s.c
F: drivers/iommu/io-pgtable-arm.c
F: drivers/iommu/io-pgtable-arm*

ARM SUB-ARCHITECTURES
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
1 change: 1 addition & 0 deletions arch/arm64/include/asm/barrier.h
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@
#define rmb() dsb(ld)
#define wmb() dsb(st)

#define dma_mb() dmb(osh)
#define dma_rmb() dmb(oshld)
#define dma_wmb() dmb(oshst)

1 change: 1 addition & 0 deletions arch/arm64/include/asm/io.h
Original file line number Diff line number Diff line change
@@ -110,6 +110,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)

#define __io_par(v) __iormb(v)
#define __iowmb() dma_wmb()
#define __iomb() dma_mb()

/*
* Relaxed I/O memory access primitives. These follow the Device memory
3 changes: 3 additions & 0 deletions arch/arm64/include/asm/mmu.h
Original file line number Diff line number Diff line change
@@ -17,11 +17,14 @@

#ifndef __ASSEMBLY__

#include <linux/refcount.h>

typedef struct {
atomic64_t id;
#ifdef CONFIG_COMPAT
void *sigpage;
#endif
refcount_t pinned;
void *vdso;
unsigned long flags;
} mm_context_t;
11 changes: 10 additions & 1 deletion arch/arm64/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
@@ -177,7 +177,13 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp)
#define destroy_context(mm) do { } while(0)
void check_and_switch_context(struct mm_struct *mm);

#define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; })
static inline int
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
atomic64_set(&mm->context.id, 0);
refcount_set(&mm->context.pinned, 0);
return 0;
}

#ifdef CONFIG_ARM64_SW_TTBR0_PAN
static inline void update_saved_ttbr0(struct task_struct *tsk,
@@ -248,6 +254,9 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
void verify_cpu_asid_bits(void);
void post_ttbr_update_workaround(void);

unsigned long arm64_mm_context_get(struct mm_struct *mm);
void arm64_mm_context_put(struct mm_struct *mm);

#endif /* !__ASSEMBLY__ */

#endif /* !__ASM_MMU_CONTEXT_H */
1 change: 1 addition & 0 deletions arch/arm64/kernel/cpufeature.c
Original file line number Diff line number Diff line change
@@ -1111,6 +1111,7 @@ u64 read_sanitised_ftr_reg(u32 id)
return 0;
return regp->sys_val;
}
EXPORT_SYMBOL_GPL(read_sanitised_ftr_reg);

#define read_sysreg_case(r) \
case r: return read_sysreg_s(r)
105 changes: 99 additions & 6 deletions arch/arm64/mm/context.c
Original file line number Diff line number Diff line change
@@ -27,6 +27,10 @@ static DEFINE_PER_CPU(atomic64_t, active_asids);
static DEFINE_PER_CPU(u64, reserved_asids);
static cpumask_t tlb_flush_pending;

static unsigned long max_pinned_asids;
static unsigned long nr_pinned_asids;
static unsigned long *pinned_asid_map;

#define ASID_MASK (~GENMASK(asid_bits - 1, 0))
#define ASID_FIRST_VERSION (1UL << asid_bits)

@@ -72,7 +76,7 @@ void verify_cpu_asid_bits(void)
}
}

static void set_kpti_asid_bits(void)
static void set_kpti_asid_bits(unsigned long *map)
{
unsigned int len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
/*
@@ -81,13 +85,15 @@ static void set_kpti_asid_bits(void)
* is set, then the ASID will map only userspace. Thus
* mark even as reserved for kernel.
*/
memset(asid_map, 0xaa, len);
memset(map, 0xaa, len);
}

static void set_reserved_asid_bits(void)
{
if (arm64_kernel_unmapped_at_el0())
set_kpti_asid_bits();
if (pinned_asid_map)
bitmap_copy(asid_map, pinned_asid_map, NUM_USER_ASIDS);
else if (arm64_kernel_unmapped_at_el0())
set_kpti_asid_bits(asid_map);
else
bitmap_clear(asid_map, 0, NUM_USER_ASIDS);
}
@@ -165,6 +171,14 @@ static u64 new_context(struct mm_struct *mm)
if (check_update_reserved_asid(asid, newasid))
return newasid;

/*
* If it is pinned, we can keep using it. Note that reserved
* takes priority, because even if it is also pinned, we need to
* update the generation into the reserved_asids.
*/
if (refcount_read(&mm->context.pinned))
return newasid;

/*
* We had a valid ASID in a previous life, so try to re-use
* it if possible.
@@ -256,6 +270,71 @@ void check_and_switch_context(struct mm_struct *mm)
cpu_switch_mm(mm->pgd, mm);
}

unsigned long arm64_mm_context_get(struct mm_struct *mm)
{
unsigned long flags;
u64 asid;

if (!pinned_asid_map)
return 0;

raw_spin_lock_irqsave(&cpu_asid_lock, flags);

asid = atomic64_read(&mm->context.id);

if (refcount_inc_not_zero(&mm->context.pinned))
goto out_unlock;

if (nr_pinned_asids >= max_pinned_asids) {
asid = 0;
goto out_unlock;
}

if (!asid_gen_match(asid)) {
/*
* We went through one or more rollover since that ASID was
* used. Ensure that it is still valid, or generate a new one.
*/
asid = new_context(mm);
atomic64_set(&mm->context.id, asid);
}

nr_pinned_asids++;
__set_bit(asid2idx(asid), pinned_asid_map);
refcount_set(&mm->context.pinned, 1);

out_unlock:
raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);

asid &= ~ASID_MASK;

/* Set the equivalent of USER_ASID_BIT */
if (asid && arm64_kernel_unmapped_at_el0())
asid |= 1;

return asid;
}
EXPORT_SYMBOL_GPL(arm64_mm_context_get);

void arm64_mm_context_put(struct mm_struct *mm)
{
unsigned long flags;
u64 asid = atomic64_read(&mm->context.id);

if (!pinned_asid_map)
return;

raw_spin_lock_irqsave(&cpu_asid_lock, flags);

if (refcount_dec_and_test(&mm->context.pinned)) {
__clear_bit(asid2idx(asid), pinned_asid_map);
nr_pinned_asids--;
}

raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
}
EXPORT_SYMBOL_GPL(arm64_mm_context_put);

/* Errata workaround post TTBRx_EL1 update. */
asmlinkage void post_ttbr_update_workaround(void)
{
@@ -296,15 +375,25 @@ static int asids_update_limit(void)
{
unsigned long num_available_asids = NUM_USER_ASIDS;

if (arm64_kernel_unmapped_at_el0())
if (arm64_kernel_unmapped_at_el0()) {
num_available_asids /= 2;
if (pinned_asid_map)
set_kpti_asid_bits(pinned_asid_map);
}
/*
* Expect allocation after rollover to fail if we don't have at least
* one more ASID than CPUs. ASID #0 is reserved for init_mm.
*/
WARN_ON(num_available_asids - 1 <= num_possible_cpus());
pr_info("ASID allocator initialised with %lu entries\n",
num_available_asids);

/*
* There must always be an ASID available after rollover. Ensure that,
* even if all CPUs have a reserved ASID and the maximum number of ASIDs
* are pinned, there still is at least one empty slot in the ASID map.
*/
max_pinned_asids = num_available_asids - num_possible_cpus() - 2;
return 0;
}
arch_initcall(asids_update_limit);
@@ -319,13 +408,17 @@ static int asids_init(void)
panic("Failed to allocate bitmap for %lu ASIDs\n",
NUM_USER_ASIDS);

pinned_asid_map = kcalloc(BITS_TO_LONGS(NUM_USER_ASIDS),
sizeof(*pinned_asid_map), GFP_KERNEL);
nr_pinned_asids = 0;

/*
* We cannot call set_reserved_asid_bits() here because CPU
* caps are not finalized yet, so it is safer to assume KPTI
* and reserve kernel ASID's from beginning.
*/
if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
set_kpti_asid_bits();
set_kpti_asid_bits(asid_map);
return 0;
}
early_initcall(asids_init);
10 changes: 10 additions & 0 deletions drivers/iommu/Kconfig
Original file line number Diff line number Diff line change
@@ -308,6 +308,16 @@ config ARM_SMMU_V3
Say Y here if your system includes an IOMMU device implementing
the ARM SMMUv3 architecture.

config ARM_SMMU_V3_SVA
bool "Shared Virtual Addressing support for the ARM SMMUv3"
depends on ARM_SMMU_V3
help
Support for sharing process address spaces with devices using the
SMMUv3.

Say Y here if your system supports SVA extensions such as PCIe PASID
and PRI.

config S390_IOMMU
def_bool y if S390 && PCI
depends on S390 && PCI
5 changes: 4 additions & 1 deletion drivers/iommu/arm/arm-smmu-v3/Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o
obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o
arm_smmu_v3-objs-y += arm-smmu-v3.o
arm_smmu_v3-objs-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o
arm_smmu_v3-objs := $(arm_smmu_v3-objs-y)
Loading

0 comments on commit 0dd4ce6

Please sign in to comment.