Commit 1c6d010a authored by Mao Minkai's avatar Mao Minkai Committed by guzitao
Browse files

sw64: add memory management

Sunway inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8Y8CY



--------------------------------

Add memory management support for SW64.

Signed-off-by: default avatarMao Minkai <maominkai@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent f4d37cfb
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * include/asm/cache.h
 */
#ifndef _ASM_SW64_CACHE_H
#define _ASM_SW64_CACHE_H

#define L1_CACHE_SHIFT		7
#define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)

#define SMP_CACHE_BYTES		L1_CACHE_BYTES

#endif /* _ASM_SW64_CACHE_H */
+13 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_CACHEFLUSH_H
#define _ASM_SW64_CACHEFLUSH_H

/*
 * DCache: PIPT
 * ICache:
 *	- C3B is VIVT with ICTAG, support coherence.
 *	- C4 is VIPT
 */
#include <asm-generic/cacheflush.h>

#endif /* _ASM_SW64_CACHEFLUSH_H */
+35 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_MEMORY_H
#define _ASM_SW64_MEMORY_H

#ifdef CONFIG_NUMA
#include <linux/numa.h>
#endif

#define MIN_MEMORY_BLOCK_SIZE_VM_MEMHP    (1UL << 30)
#define NODE0_START	(_TEXT_START - __START_KERNEL_map)

#define MAX_PHYSMEM_BITS	48

struct mem_desc_t {
	unsigned long phys_base;	/* start address of physical memory */
	unsigned long phys_size;	/* size of physical memory */
	phys_addr_t base;		/* start address of memory managed by kernel */
	phys_addr_t size;		/* size of memory managed by kernel */
};
extern struct mem_desc_t mem_desc;

struct numa_node_desc_t {
	phys_addr_t base;
	phys_addr_t size;
};
extern struct numa_node_desc_t numa_nodes_desc[];

void __init callback_init(void);
void __init mem_detect(void);
void __init sw64_memblock_init(void);
void __init zone_sizes_init(void);
void __init sw64_numa_init(void);
void __init sw64_memory_present(void);

#endif /* _ASM_SW64_MEMORY_H */
+10 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_MMU_H
#define _ASM_SW64_MMU_H

/* The sw64 MMU context is one "unsigned long" bitmap per CPU*/
typedef struct {
	unsigned long asid[NR_CPUS];
	void *vdso;
} mm_context_t;
#endif /* _ASM_SW64_MMU_H */
+136 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_MMU_CONTEXT_H
#define _ASM_SW64_MMU_CONTEXT_H

#include <linux/mm_types.h>

#include <asm/compiler.h>
#include <asm/io.h>

/*
 * The maximum ASID's the processor supports.
 */

#if defined(CONFIG_SUBARCH_C3B) || defined(CONFIG_SUBARCH_C4)
#define ASID_BITS	10
#endif

#include <asm/hw_init.h>
#define last_asid(cpu)		(cpu_data[cpu].last_asid)

#define ASID_FIRST_VERSION	(1UL << ASID_BITS)
#define ASID_MASK		((1UL << ASID_BITS) - 1)

#define cpu_asid(cpu, mm)	((mm)->context.asid[cpu] & ASID_MASK)

static inline bool asid_valid(struct mm_struct *mm, unsigned int cpu)
{
	return !((mm->context.asid[cpu] ^ last_asid(cpu)) & ~ASID_MASK);
}

/*
 * NOTE! The way this is set up, the high bits of the "last_asid" (and
 * the "mm->context.asid[cpu]") are the ASID _version_ code. A version
 * of 0 is always considered invalid, so to invalidate another process
 * you only need to do "p->mm->context.asid[cpu] = 0".
 *
 * If we need more ASID's than the processor has, we invalidate the old
 * user TLB's (tbivp()) and start a new ASID version. That will force a
 * new asid for any other processes the next time they want to run.
 */

static inline void __get_new_mm_context(struct mm_struct *mm, long cpu)
{
	unsigned long asid = last_asid(cpu);

	if (!(++asid & ASID_MASK))
		tbivp();
	mm->context.asid[cpu] = last_asid(cpu) = asid;

}

static inline void
switch_mm_irqs_off(struct mm_struct *prev_mm, struct mm_struct *next_mm,
		   struct task_struct *next)
{
	/* Check if our ASID is of an older version, and thus invalid. */
	unsigned long asid, ptbr;
	long cpu = smp_processor_id();

	if (!asid_valid(next_mm, cpu))
		__get_new_mm_context(next_mm, cpu);

	/* Update CSR:UPN and CSR:PTBR. Another thread may have allocated
	 * a new mm->context[asid] (via flush_tlb_mm) without the ASID serial
	 * number wrapping.  We have no way to detect when this is needed.
	 */
	asid = cpu_asid(cpu, next_mm);
	ptbr = virt_to_pfn(next_mm->pgd);
	load_mm(asid, ptbr);
	cpumask_set_cpu(cpu, mm_cpumask(next_mm));
}

#define switch_mm_irqs_off switch_mm_irqs_off

static inline void
switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
	  struct task_struct *tsk)
{
	unsigned long flags;

	local_irq_save(flags);
	switch_mm_irqs_off(prev_mm, next_mm, tsk);
	local_irq_restore(flags);
}

#define activate_mm(prev, next) switch_mm(prev, next, current)
#define deactivate_mm(tsk, mm)	do { } while (0)

static inline int init_new_context(struct task_struct *tsk,
				   struct mm_struct *mm)
{
	int i;

	for_each_possible_cpu(i)
		mm->context.asid[i] = 0;
	return 0;
}

static inline void destroy_context(struct mm_struct *mm)
{
	/* Nothing to do.  */
}

static inline void enter_lazy_tlb(struct mm_struct *mm,
				  struct task_struct *tsk)
{
}

static inline int arch_dup_mmap(struct mm_struct *oldmm,
				struct mm_struct *mm)
{
	return 0;
}

static inline void arch_exit_mmap(struct mm_struct *mm)
{
}

static inline void arch_unmap(struct mm_struct *mm, unsigned long start,
				unsigned long end)
{
}

static inline void arch_bprm_mm_init(struct mm_struct *mm,
				     struct vm_area_struct *vma)
{
}

static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
					     bool write, bool execute,
					     bool foreign)
{
	/* by default, allow everything */
	return true;
}
#endif /* _ASM_SW64_MMU_CONTEXT_H */
Loading