LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] generic ELF support for kexec
From: Sven Schnelle @ 2019-06-25 18:54 UTC (permalink / raw)
  To: kexec; +Cc: linux-s390, deller, linuxppc-dev

Hi List,

i recently started working on kexec for PA-RISC. While doing so, i figured
that powerpc already has support for reading ELF images inside of the Kernel.
My first attempt was to steal the source code and modify it for PA-RISC, but
it turned out that i didn't had to change much. Only ARM specific stuff like
fdt blob fetching had to be removed.

So instead of duplicating the code, i thought about moving the ELF stuff to
the core kexec code, and exposing several function to use that code from the
arch specific code.

I'm attaching the patch to this Mail. What do you think about that change?
s390 also uses ELF files, and (maybe?) could also switch to this implementation.
But i don't know anything about S/390 and don't have one in my basement. So
i'll leave s390 to the IBM folks.

I haven't really tested PowerPC yet. Can anyone give me a helping hand what
would be a good target to test this code in QEMU? Or even better, test this
code on real Hardware?

If that change is acceptable i would finish the patch and submit it. I think
best would be to push this change through Helge's parisc tree, so we don't
have any dependencies to sort out.

Regards,
Sven

[PATCH] kexec: add generic support for elf kernel images

Signed-off-by: Sven Schnelle <svens@stackframe.org>
---
 arch/Kconfig                       |   3 +
 arch/powerpc/Kconfig               |   1 +
 arch/powerpc/kernel/kexec_elf_64.c | 547 +--------------------------
 include/linux/kexec.h              |  35 ++
 kernel/Makefile                    |   1 +
 kernel/kexec_file_elf.c            | 574 +++++++++++++++++++++++++++++
 6 files changed, 619 insertions(+), 542 deletions(-)
 create mode 100644 kernel/kexec_file_elf.c

diff --git a/arch/Kconfig b/arch/Kconfig
index c47b328eada0..de7520100136 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -18,6 +18,9 @@ config KEXEC_CORE
 	select CRASH_CORE
 	bool
 
+config KEXEC_FILE_ELF
+	bool
+
 config HAVE_IMA_KEXEC
 	bool
 
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8c1c636308c8..48241260b6ae 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -502,6 +502,7 @@ config KEXEC_FILE
 	select KEXEC_CORE
 	select HAVE_IMA_KEXEC
 	select BUILD_BIN2C
+	select KEXEC_FILE_ELF
 	depends on PPC64
 	depends on CRYPTO=y
 	depends on CRYPTO_SHA256=y
diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c
index ba4f18a43ee8..0059e36913e9 100644
--- a/arch/powerpc/kernel/kexec_elf_64.c
+++ b/arch/powerpc/kernel/kexec_elf_64.c
@@ -21,8 +21,6 @@
  * GNU General Public License for more details.
  */
 
-#define pr_fmt(fmt)	"kexec_elf: " fmt
-
 #include <linux/elf.h>
 #include <linux/kexec.h>
 #include <linux/libfdt.h>
@@ -31,540 +29,6 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 
-#define PURGATORY_STACK_SIZE	(16 * 1024)
-
-#define elf_addr_to_cpu	elf64_to_cpu
-
-#ifndef Elf_Rel
-#define Elf_Rel		Elf64_Rel
-#endif /* Elf_Rel */
-
-struct elf_info {
-	/*
-	 * Where the ELF binary contents are kept.
-	 * Memory managed by the user of the struct.
-	 */
-	const char *buffer;
-
-	const struct elfhdr *ehdr;
-	const struct elf_phdr *proghdrs;
-	struct elf_shdr *sechdrs;
-};
-
-static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
-{
-       return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0;
-}
-
-static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value)
-{
-	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
-		value = le64_to_cpu(value);
-	else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
-		value = be64_to_cpu(value);
-
-	return value;
-}
-
-static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value)
-{
-	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
-		value = le16_to_cpu(value);
-	else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
-		value = be16_to_cpu(value);
-
-	return value;
-}
-
-static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value)
-{
-	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
-		value = le32_to_cpu(value);
-	else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
-		value = be32_to_cpu(value);
-
-	return value;
-}
-
-/**
- * elf_is_ehdr_sane - check that it is safe to use the ELF header
- * @buf_len:	size of the buffer in which the ELF file is loaded.
- */
-static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len)
-{
-	if (ehdr->e_phnum > 0 && ehdr->e_phentsize != sizeof(struct elf_phdr)) {
-		pr_debug("Bad program header size.\n");
-		return false;
-	} else if (ehdr->e_shnum > 0 &&
-		   ehdr->e_shentsize != sizeof(struct elf_shdr)) {
-		pr_debug("Bad section header size.\n");
-		return false;
-	} else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
-		   ehdr->e_version != EV_CURRENT) {
-		pr_debug("Unknown ELF version.\n");
-		return false;
-	}
-
-	if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
-		size_t phdr_size;
-
-		/*
-		 * e_phnum is at most 65535 so calculating the size of the
-		 * program header cannot overflow.
-		 */
-		phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
-
-		/* Sanity check the program header table location. */
-		if (ehdr->e_phoff + phdr_size < ehdr->e_phoff) {
-			pr_debug("Program headers at invalid location.\n");
-			return false;
-		} else if (ehdr->e_phoff + phdr_size > buf_len) {
-			pr_debug("Program headers truncated.\n");
-			return false;
-		}
-	}
-
-	if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) {
-		size_t shdr_size;
-
-		/*
-		 * e_shnum is at most 65536 so calculating
-		 * the size of the section header cannot overflow.
-		 */
-		shdr_size = sizeof(struct elf_shdr) * ehdr->e_shnum;
-
-		/* Sanity check the section header table location. */
-		if (ehdr->e_shoff + shdr_size < ehdr->e_shoff) {
-			pr_debug("Section headers at invalid location.\n");
-			return false;
-		} else if (ehdr->e_shoff + shdr_size > buf_len) {
-			pr_debug("Section headers truncated.\n");
-			return false;
-		}
-	}
-
-	return true;
-}
-
-static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr)
-{
-	struct elfhdr *buf_ehdr;
-
-	if (len < sizeof(*buf_ehdr)) {
-		pr_debug("Buffer is too small to hold ELF header.\n");
-		return -ENOEXEC;
-	}
-
-	memset(ehdr, 0, sizeof(*ehdr));
-	memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident));
-	if (!elf_is_elf_file(ehdr)) {
-		pr_debug("No ELF header magic.\n");
-		return -ENOEXEC;
-	}
-
-	if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
-		pr_debug("Not a supported ELF class.\n");
-		return -ENOEXEC;
-	} else  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB &&
-		ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
-		pr_debug("Not a supported ELF data format.\n");
-		return -ENOEXEC;
-	}
-
-	buf_ehdr = (struct elfhdr *) buf;
-	if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) {
-		pr_debug("Bad ELF header size.\n");
-		return -ENOEXEC;
-	}
-
-	ehdr->e_type      = elf16_to_cpu(ehdr, buf_ehdr->e_type);
-	ehdr->e_machine   = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
-	ehdr->e_version   = elf32_to_cpu(ehdr, buf_ehdr->e_version);
-	ehdr->e_entry     = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry);
-	ehdr->e_phoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff);
-	ehdr->e_shoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff);
-	ehdr->e_flags     = elf32_to_cpu(ehdr, buf_ehdr->e_flags);
-	ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
-	ehdr->e_phnum     = elf16_to_cpu(ehdr, buf_ehdr->e_phnum);
-	ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize);
-	ehdr->e_shnum     = elf16_to_cpu(ehdr, buf_ehdr->e_shnum);
-	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx);
-
-	return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_is_phdr_sane - check that it is safe to use the program header
- * @buf_len:	size of the buffer in which the ELF file is loaded.
- */
-static bool elf_is_phdr_sane(const struct elf_phdr *phdr, size_t buf_len)
-{
-
-	if (phdr->p_offset + phdr->p_filesz < phdr->p_offset) {
-		pr_debug("ELF segment location wraps around.\n");
-		return false;
-	} else if (phdr->p_offset + phdr->p_filesz > buf_len) {
-		pr_debug("ELF segment not in file.\n");
-		return false;
-	} else if (phdr->p_paddr + phdr->p_memsz < phdr->p_paddr) {
-		pr_debug("ELF segment address wraps around.\n");
-		return false;
-	}
-
-	return true;
-}
-
-static int elf_read_phdr(const char *buf, size_t len, struct elf_info *elf_info,
-			 int idx)
-{
-	/* Override the const in proghdrs, we are the ones doing the loading. */
-	struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
-	const char *pbuf;
-	struct elf_phdr *buf_phdr;
-
-	pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr));
-	buf_phdr = (struct elf_phdr *) pbuf;
-
-	phdr->p_type   = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type);
-	phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset);
-	phdr->p_paddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr);
-	phdr->p_vaddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr);
-	phdr->p_flags  = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags);
-
-	/*
-	 * The following fields have a type equivalent to Elf_Addr
-	 * both in 32 bit and 64 bit ELF.
-	 */
-	phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz);
-	phdr->p_memsz  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz);
-	phdr->p_align  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align);
-
-	return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_read_phdrs - read the program headers from the buffer
- *
- * This function assumes that the program header table was checked for sanity.
- * Use elf_is_ehdr_sane() if it wasn't.
- */
-static int elf_read_phdrs(const char *buf, size_t len,
-			  struct elf_info *elf_info)
-{
-	size_t phdr_size, i;
-	const struct elfhdr *ehdr = elf_info->ehdr;
-
-	/*
-	 * e_phnum is at most 65535 so calculating the size of the
-	 * program header cannot overflow.
-	 */
-	phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
-
-	elf_info->proghdrs = kzalloc(phdr_size, GFP_KERNEL);
-	if (!elf_info->proghdrs)
-		return -ENOMEM;
-
-	for (i = 0; i < ehdr->e_phnum; i++) {
-		int ret;
-
-		ret = elf_read_phdr(buf, len, elf_info, i);
-		if (ret) {
-			kfree(elf_info->proghdrs);
-			elf_info->proghdrs = NULL;
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * elf_is_shdr_sane - check that it is safe to use the section header
- * @buf_len:	size of the buffer in which the ELF file is loaded.
- */
-static bool elf_is_shdr_sane(const struct elf_shdr *shdr, size_t buf_len)
-{
-	bool size_ok;
-
-	/* SHT_NULL headers have undefined values, so we can't check them. */
-	if (shdr->sh_type == SHT_NULL)
-		return true;
-
-	/* Now verify sh_entsize */
-	switch (shdr->sh_type) {
-	case SHT_SYMTAB:
-		size_ok = shdr->sh_entsize == sizeof(Elf_Sym);
-		break;
-	case SHT_RELA:
-		size_ok = shdr->sh_entsize == sizeof(Elf_Rela);
-		break;
-	case SHT_DYNAMIC:
-		size_ok = shdr->sh_entsize == sizeof(Elf_Dyn);
-		break;
-	case SHT_REL:
-		size_ok = shdr->sh_entsize == sizeof(Elf_Rel);
-		break;
-	case SHT_NOTE:
-	case SHT_PROGBITS:
-	case SHT_HASH:
-	case SHT_NOBITS:
-	default:
-		/*
-		 * This is a section whose entsize requirements
-		 * I don't care about.  If I don't know about
-		 * the section I can't care about it's entsize
-		 * requirements.
-		 */
-		size_ok = true;
-		break;
-	}
-
-	if (!size_ok) {
-		pr_debug("ELF section with wrong entry size.\n");
-		return false;
-	} else if (shdr->sh_addr + shdr->sh_size < shdr->sh_addr) {
-		pr_debug("ELF section address wraps around.\n");
-		return false;
-	}
-
-	if (shdr->sh_type != SHT_NOBITS) {
-		if (shdr->sh_offset + shdr->sh_size < shdr->sh_offset) {
-			pr_debug("ELF section location wraps around.\n");
-			return false;
-		} else if (shdr->sh_offset + shdr->sh_size > buf_len) {
-			pr_debug("ELF section not in file.\n");
-			return false;
-		}
-	}
-
-	return true;
-}
-
-static int elf_read_shdr(const char *buf, size_t len, struct elf_info *elf_info,
-			 int idx)
-{
-	struct elf_shdr *shdr = &elf_info->sechdrs[idx];
-	const struct elfhdr *ehdr = elf_info->ehdr;
-	const char *sbuf;
-	struct elf_shdr *buf_shdr;
-
-	sbuf = buf + ehdr->e_shoff + idx * sizeof(*buf_shdr);
-	buf_shdr = (struct elf_shdr *) sbuf;
-
-	shdr->sh_name      = elf32_to_cpu(ehdr, buf_shdr->sh_name);
-	shdr->sh_type      = elf32_to_cpu(ehdr, buf_shdr->sh_type);
-	shdr->sh_addr      = elf_addr_to_cpu(ehdr, buf_shdr->sh_addr);
-	shdr->sh_offset    = elf_addr_to_cpu(ehdr, buf_shdr->sh_offset);
-	shdr->sh_link      = elf32_to_cpu(ehdr, buf_shdr->sh_link);
-	shdr->sh_info      = elf32_to_cpu(ehdr, buf_shdr->sh_info);
-
-	/*
-	 * The following fields have a type equivalent to Elf_Addr
-	 * both in 32 bit and 64 bit ELF.
-	 */
-	shdr->sh_flags     = elf_addr_to_cpu(ehdr, buf_shdr->sh_flags);
-	shdr->sh_size      = elf_addr_to_cpu(ehdr, buf_shdr->sh_size);
-	shdr->sh_addralign = elf_addr_to_cpu(ehdr, buf_shdr->sh_addralign);
-	shdr->sh_entsize   = elf_addr_to_cpu(ehdr, buf_shdr->sh_entsize);
-
-	return elf_is_shdr_sane(shdr, len) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_read_shdrs - read the section headers from the buffer
- *
- * This function assumes that the section header table was checked for sanity.
- * Use elf_is_ehdr_sane() if it wasn't.
- */
-static int elf_read_shdrs(const char *buf, size_t len,
-			  struct elf_info *elf_info)
-{
-	size_t shdr_size, i;
-
-	/*
-	 * e_shnum is at most 65536 so calculating
-	 * the size of the section header cannot overflow.
-	 */
-	shdr_size = sizeof(struct elf_shdr) * elf_info->ehdr->e_shnum;
-
-	elf_info->sechdrs = kzalloc(shdr_size, GFP_KERNEL);
-	if (!elf_info->sechdrs)
-		return -ENOMEM;
-
-	for (i = 0; i < elf_info->ehdr->e_shnum; i++) {
-		int ret;
-
-		ret = elf_read_shdr(buf, len, elf_info, i);
-		if (ret) {
-			kfree(elf_info->sechdrs);
-			elf_info->sechdrs = NULL;
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * elf_read_from_buffer - read ELF file and sets up ELF header and ELF info
- * @buf:	Buffer to read ELF file from.
- * @len:	Size of @buf.
- * @ehdr:	Pointer to existing struct which will be populated.
- * @elf_info:	Pointer to existing struct which will be populated.
- *
- * This function allows reading ELF files with different byte order than
- * the kernel, byte-swapping the fields as needed.
- *
- * Return:
- * On success returns 0, and the caller should call elf_free_info(elf_info) to
- * free the memory allocated for the section and program headers.
- */
-int elf_read_from_buffer(const char *buf, size_t len, struct elfhdr *ehdr,
-			 struct elf_info *elf_info)
-{
-	int ret;
-
-	ret = elf_read_ehdr(buf, len, ehdr);
-	if (ret)
-		return ret;
-
-	elf_info->buffer = buf;
-	elf_info->ehdr = ehdr;
-	if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
-		ret = elf_read_phdrs(buf, len, elf_info);
-		if (ret)
-			return ret;
-	}
-	if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) {
-		ret = elf_read_shdrs(buf, len, elf_info);
-		if (ret) {
-			kfree(elf_info->proghdrs);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * elf_free_info - free memory allocated by elf_read_from_buffer
- */
-void elf_free_info(struct elf_info *elf_info)
-{
-	kfree(elf_info->proghdrs);
-	kfree(elf_info->sechdrs);
-	memset(elf_info, 0, sizeof(*elf_info));
-}
-/**
- * build_elf_exec_info - read ELF executable and check that we can use it
- */
-static int build_elf_exec_info(const char *buf, size_t len, struct elfhdr *ehdr,
-			       struct elf_info *elf_info)
-{
-	int i;
-	int ret;
-
-	ret = elf_read_from_buffer(buf, len, ehdr, elf_info);
-	if (ret)
-		return ret;
-
-	/* Big endian vmlinux has type ET_DYN. */
-	if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
-		pr_err("Not an ELF executable.\n");
-		goto error;
-	} else if (!elf_info->proghdrs) {
-		pr_err("No ELF program header.\n");
-		goto error;
-	}
-
-	for (i = 0; i < ehdr->e_phnum; i++) {
-		/*
-		 * Kexec does not support loading interpreters.
-		 * In addition this check keeps us from attempting
-		 * to kexec ordinay executables.
-		 */
-		if (elf_info->proghdrs[i].p_type == PT_INTERP) {
-			pr_err("Requires an ELF interpreter.\n");
-			goto error;
-		}
-	}
-
-	return 0;
-error:
-	elf_free_info(elf_info);
-	return -ENOEXEC;
-}
-
-static int elf64_probe(const char *buf, unsigned long len)
-{
-	struct elfhdr ehdr;
-	struct elf_info elf_info;
-	int ret;
-
-	ret = build_elf_exec_info(buf, len, &ehdr, &elf_info);
-	if (ret)
-		return ret;
-
-	elf_free_info(&elf_info);
-
-	return elf_check_arch(&ehdr) ? 0 : -ENOEXEC;
-}
-
-/**
- * elf_exec_load - load ELF executable image
- * @lowest_load_addr:	On return, will be the address where the first PT_LOAD
- *			section will be loaded in memory.
- *
- * Return:
- * 0 on success, negative value on failure.
- */
-static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr,
-			 struct elf_info *elf_info,
-			 unsigned long *lowest_load_addr)
-{
-	unsigned long base = 0, lowest_addr = UINT_MAX;
-	int ret;
-	size_t i;
-	struct kexec_buf kbuf = { .image = image, .buf_max = ppc64_rma_size,
-				  .top_down = false };
-
-	/* Read in the PT_LOAD segments. */
-	for (i = 0; i < ehdr->e_phnum; i++) {
-		unsigned long load_addr;
-		size_t size;
-		const struct elf_phdr *phdr;
-
-		phdr = &elf_info->proghdrs[i];
-		if (phdr->p_type != PT_LOAD)
-			continue;
-
-		size = phdr->p_filesz;
-		if (size > phdr->p_memsz)
-			size = phdr->p_memsz;
-
-		kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset;
-		kbuf.bufsz = size;
-		kbuf.memsz = phdr->p_memsz;
-		kbuf.buf_align = phdr->p_align;
-		kbuf.buf_min = phdr->p_paddr + base;
-		ret = kexec_add_buffer(&kbuf);
-		if (ret)
-			goto out;
-		load_addr = kbuf.mem;
-
-		if (load_addr < lowest_addr)
-			lowest_addr = load_addr;
-	}
-
-	/* Update entry point to reflect new load address. */
-	ehdr->e_entry += base;
-
-	*lowest_load_addr = lowest_addr;
-	ret = 0;
- out:
-	return ret;
-}
-
 static void *elf64_load(struct kimage *image, char *kernel_buf,
 			unsigned long kernel_len, char *initrd,
 			unsigned long initrd_len, char *cmdline,
@@ -577,17 +41,17 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
 	void *fdt;
 	const void *slave_code;
 	struct elfhdr ehdr;
-	struct elf_info elf_info;
+	struct kexec_elf_info elf_info;
 	struct kexec_buf kbuf = { .image = image, .buf_min = 0,
 				  .buf_max = ppc64_rma_size };
 	struct kexec_buf pbuf = { .image = image, .buf_min = 0,
 				  .buf_max = ppc64_rma_size, .top_down = true };
 
-	ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info);
+	ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info);
 	if (ret)
 		goto out;
 
-	ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr);
+	ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr);
 	if (ret)
 		goto out;
 
@@ -652,13 +116,12 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
 		pr_err("Error setting up the purgatory.\n");
 
 out:
-	elf_free_info(&elf_info);
-
+	kexec_free_elf_info(&elf_info);
 	/* Make kimage_file_post_load_cleanup free the fdt buffer for us. */
 	return ret ? ERR_PTR(ret) : fdt;
 }
 
 const struct kexec_file_ops kexec_elf64_ops = {
-	.probe = elf64_probe,
+	.probe = kexec_elf_probe,
 	.load = elf64_load,
 };
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index b9b1bc5f9669..49b23b425f84 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -216,6 +216,41 @@ extern int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_map,
 				       void **addr, unsigned long *sz);
 #endif /* CONFIG_KEXEC_FILE */
 
+#ifdef CONFIG_KEXEC_FILE_ELF
+
+struct kexec_elf_info {
+	/*
+	 * Where the ELF binary contents are kept.
+	 * Memory managed by the user of the struct.
+	 */
+	const char *buffer;
+
+	const struct elfhdr *ehdr;
+	const struct elf_phdr *proghdrs;
+	struct elf_shdr *sechdrs;
+};
+
+void kexec_free_elf_info(struct kexec_elf_info *elf_info);
+
+int kexec_build_elf_info(const char *buf, size_t len, struct elfhdr *ehdr,
+			  struct kexec_elf_info *elf_info);
+
+int kexec_elf_kernel_load(struct kimage *image, struct kexec_buf *kbuf,
+			  char *kernel_buf, unsigned long kernel_len,
+			  unsigned long *kernel_load_addr);
+
+int kexec_elf_probe(const char *buf, unsigned long len);
+
+int kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
+			 struct kexec_elf_info *elf_info,
+			 struct kexec_buf *kbuf,
+			 unsigned long *lowest_load_addr);
+
+int kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
+			 struct kexec_elf_info *elf_info,
+			 struct kexec_buf *kbuf,
+			 unsigned long *lowest_load_addr);
+#endif
 struct kimage {
 	kimage_entry_t head;
 	kimage_entry_t *entry;
diff --git a/kernel/Makefile b/kernel/Makefile
index 33824f0385b3..fdba91785977 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_CRASH_CORE) += crash_core.o
 obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
+obj-$(CONFIG_KEXEC_FILE_ELF) += kexec_file_elf.o
 obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_CGROUPS) += cgroup/
diff --git a/kernel/kexec_file_elf.c b/kernel/kexec_file_elf.c
new file mode 100644
index 000000000000..bb966c93492c
--- /dev/null
+++ b/kernel/kexec_file_elf.c
@@ -0,0 +1,574 @@
+/*
+ * Load ELF vmlinux file for the kexec_file_load syscall.
+ *
+ * Copyright (C) 2004  Adam Litke (agl@us.ibm.com)
+ * Copyright (C) 2004  IBM Corp.
+ * Copyright (C) 2005  R Sharada (sharada@in.ibm.com)
+ * Copyright (C) 2006  Mohan Kumar M (mohan@in.ibm.com)
+ * Copyright (C) 2016  IBM Corporation
+ *
+ * Based on kexec-tools' kexec-elf-exec.c and kexec-elf-ppc64.c.
+ * Heavily modified for the kernel by
+ * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"kexec_elf: " fmt
+
+#include <linux/elf.h>
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define elf_addr_to_cpu	elf64_to_cpu
+
+#ifndef Elf_Rel
+#define Elf_Rel		Elf64_Rel
+#endif /* Elf_Rel */
+
+static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
+{
+       return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0;
+}
+
+static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value)
+{
+	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+		value = le64_to_cpu(value);
+	else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+		value = be64_to_cpu(value);
+
+	return value;
+}
+
+static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value)
+{
+	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+		value = le16_to_cpu(value);
+	else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+		value = be16_to_cpu(value);
+
+	return value;
+}
+
+static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value)
+{
+	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+		value = le32_to_cpu(value);
+	else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+		value = be32_to_cpu(value);
+
+	return value;
+}
+
+/**
+ * elf_is_ehdr_sane - check that it is safe to use the ELF header
+ * @buf_len:	size of the buffer in which the ELF file is loaded.
+ */
+static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len)
+{
+	if (ehdr->e_phnum > 0 && ehdr->e_phentsize != sizeof(struct elf_phdr)) {
+		pr_debug("Bad program header size.\n");
+		return false;
+	} else if (ehdr->e_shnum > 0 &&
+		   ehdr->e_shentsize != sizeof(struct elf_shdr)) {
+		pr_debug("Bad section header size.\n");
+		return false;
+	} else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
+		   ehdr->e_version != EV_CURRENT) {
+		pr_debug("Unknown ELF version.\n");
+		return false;
+	}
+
+	if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
+		size_t phdr_size;
+
+		/*
+		 * e_phnum is at most 65535 so calculating the size of the
+		 * program header cannot overflow.
+		 */
+		phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
+
+		/* Sanity check the program header table location. */
+		if (ehdr->e_phoff + phdr_size < ehdr->e_phoff) {
+			pr_debug("Program headers at invalid location.\n");
+			return false;
+		} else if (ehdr->e_phoff + phdr_size > buf_len) {
+			pr_debug("Program headers truncated.\n");
+			return false;
+		}
+	}
+
+	if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) {
+		size_t shdr_size;
+
+		/*
+		 * e_shnum is at most 65536 so calculating
+		 * the size of the section header cannot overflow.
+		 */
+		shdr_size = sizeof(struct elf_shdr) * ehdr->e_shnum;
+
+		/* Sanity check the section header table location. */
+		if (ehdr->e_shoff + shdr_size < ehdr->e_shoff) {
+			pr_debug("Section headers at invalid location.\n");
+			return false;
+		} else if (ehdr->e_shoff + shdr_size > buf_len) {
+			pr_debug("Section headers truncated.\n");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr)
+{
+	struct elfhdr *buf_ehdr;
+
+	if (len < sizeof(*buf_ehdr)) {
+		pr_debug("Buffer is too small to hold ELF header.\n");
+		return -ENOEXEC;
+	}
+
+	memset(ehdr, 0, sizeof(*ehdr));
+	memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident));
+	if (!elf_is_elf_file(ehdr)) {
+		pr_debug("No ELF header magic.\n");
+		return -ENOEXEC;
+	}
+
+	if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
+		pr_debug("Not a supported ELF class.\n");
+		return -ENOEXEC;
+	} else  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB &&
+		ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+		pr_debug("Not a supported ELF data format.\n");
+		return -ENOEXEC;
+	}
+
+	buf_ehdr = (struct elfhdr *) buf;
+	if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) {
+		pr_debug("Bad ELF header size.\n");
+		return -ENOEXEC;
+	}
+
+	ehdr->e_type      = elf16_to_cpu(ehdr, buf_ehdr->e_type);
+	ehdr->e_machine   = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
+	ehdr->e_version   = elf32_to_cpu(ehdr, buf_ehdr->e_version);
+	ehdr->e_entry     = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry);
+	ehdr->e_phoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff);
+	ehdr->e_shoff     = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff);
+	ehdr->e_flags     = elf32_to_cpu(ehdr, buf_ehdr->e_flags);
+	ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
+	ehdr->e_phnum     = elf16_to_cpu(ehdr, buf_ehdr->e_phnum);
+	ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize);
+	ehdr->e_shnum     = elf16_to_cpu(ehdr, buf_ehdr->e_shnum);
+	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx);
+
+	return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC;
+}
+
+/**
+ * elf_is_phdr_sane - check that it is safe to use the program header
+ * @buf_len:	size of the buffer in which the ELF file is loaded.
+ */
+static bool elf_is_phdr_sane(const struct elf_phdr *phdr, size_t buf_len)
+{
+
+	if (phdr->p_offset + phdr->p_filesz < phdr->p_offset) {
+		pr_debug("ELF segment location wraps around.\n");
+		return false;
+	} else if (phdr->p_offset + phdr->p_filesz > buf_len) {
+		pr_debug("ELF segment not in file.\n");
+		return false;
+	} else if (phdr->p_paddr + phdr->p_memsz < phdr->p_paddr) {
+		pr_debug("ELF segment address wraps around.\n");
+		return false;
+	}
+
+	return true;
+}
+
+static int elf_read_phdr(const char *buf, size_t len, struct kexec_elf_info *elf_info,
+			 int idx)
+{
+	/* Override the const in proghdrs, we are the ones doing the loading. */
+	struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
+	const char *pbuf;
+	struct elf_phdr *buf_phdr;
+
+	pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr));
+	buf_phdr = (struct elf_phdr *) pbuf;
+
+	phdr->p_type   = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type);
+	phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset);
+	phdr->p_paddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr);
+	phdr->p_vaddr  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr);
+	phdr->p_flags  = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags);
+
+	/*
+	 * The following fields have a type equivalent to Elf_Addr
+	 * both in 32 bit and 64 bit ELF.
+	 */
+	phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz);
+	phdr->p_memsz  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz);
+	phdr->p_align  = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align);
+
+	return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC;
+}
+
+/**
+ * elf_read_phdrs - read the program headers from the buffer
+ *
+ * This function assumes that the program header table was checked for sanity.
+ * Use elf_is_ehdr_sane() if it wasn't.
+ */
+static int elf_read_phdrs(const char *buf, size_t len,
+			  struct kexec_elf_info *elf_info)
+{
+	size_t phdr_size, i;
+	const struct elfhdr *ehdr = elf_info->ehdr;
+
+	/*
+	 * e_phnum is at most 65535 so calculating the size of the
+	 * program header cannot overflow.
+	 */
+	phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum;
+
+	elf_info->proghdrs = kzalloc(phdr_size, GFP_KERNEL);
+	if (!elf_info->proghdrs)
+		return -ENOMEM;
+
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		int ret;
+
+		ret = elf_read_phdr(buf, len, elf_info, i);
+		if (ret) {
+			kfree(elf_info->proghdrs);
+			elf_info->proghdrs = NULL;
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * elf_is_shdr_sane - check that it is safe to use the section header
+ * @buf_len:	size of the buffer in which the ELF file is loaded.
+ */
+static bool elf_is_shdr_sane(const struct elf_shdr *shdr, size_t buf_len)
+{
+	bool size_ok;
+
+	/* SHT_NULL headers have undefined values, so we can't check them. */
+	if (shdr->sh_type == SHT_NULL)
+		return true;
+
+	/* Now verify sh_entsize */
+	switch (shdr->sh_type) {
+	case SHT_SYMTAB:
+		size_ok = shdr->sh_entsize == sizeof(Elf_Sym);
+		break;
+	case SHT_RELA:
+		size_ok = shdr->sh_entsize == sizeof(Elf_Rela);
+		break;
+	case SHT_DYNAMIC:
+		size_ok = shdr->sh_entsize == sizeof(Elf_Dyn);
+		break;
+	case SHT_REL:
+		size_ok = shdr->sh_entsize == sizeof(Elf_Rel);
+		break;
+	case SHT_NOTE:
+	case SHT_PROGBITS:
+	case SHT_HASH:
+	case SHT_NOBITS:
+	default:
+		/*
+		 * This is a section whose entsize requirements
+		 * I don't care about.  If I don't know about
+		 * the section I can't care about it's entsize
+		 * requirements.
+		 */
+		size_ok = true;
+		break;
+	}
+
+	if (!size_ok) {
+		pr_debug("ELF section with wrong entry size.\n");
+		return false;
+	} else if (shdr->sh_addr + shdr->sh_size < shdr->sh_addr) {
+		pr_debug("ELF section address wraps around.\n");
+		return false;
+	}
+
+	if (shdr->sh_type != SHT_NOBITS) {
+		if (shdr->sh_offset + shdr->sh_size < shdr->sh_offset) {
+			pr_debug("ELF section location wraps around.\n");
+			return false;
+		} else if (shdr->sh_offset + shdr->sh_size > buf_len) {
+			pr_debug("ELF section not in file.\n");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int elf_read_shdr(const char *buf, size_t len, struct kexec_elf_info *elf_info,
+			 int idx)
+{
+	struct elf_shdr *shdr = &elf_info->sechdrs[idx];
+	const struct elfhdr *ehdr = elf_info->ehdr;
+	const char *sbuf;
+	struct elf_shdr *buf_shdr;
+
+	sbuf = buf + ehdr->e_shoff + idx * sizeof(*buf_shdr);
+	buf_shdr = (struct elf_shdr *) sbuf;
+
+	shdr->sh_name      = elf32_to_cpu(ehdr, buf_shdr->sh_name);
+	shdr->sh_type      = elf32_to_cpu(ehdr, buf_shdr->sh_type);
+	shdr->sh_addr      = elf_addr_to_cpu(ehdr, buf_shdr->sh_addr);
+	shdr->sh_offset    = elf_addr_to_cpu(ehdr, buf_shdr->sh_offset);
+	shdr->sh_link      = elf32_to_cpu(ehdr, buf_shdr->sh_link);
+	shdr->sh_info      = elf32_to_cpu(ehdr, buf_shdr->sh_info);
+
+	/*
+	 * The following fields have a type equivalent to Elf_Addr
+	 * both in 32 bit and 64 bit ELF.
+	 */
+	shdr->sh_flags     = elf_addr_to_cpu(ehdr, buf_shdr->sh_flags);
+	shdr->sh_size      = elf_addr_to_cpu(ehdr, buf_shdr->sh_size);
+	shdr->sh_addralign = elf_addr_to_cpu(ehdr, buf_shdr->sh_addralign);
+	shdr->sh_entsize   = elf_addr_to_cpu(ehdr, buf_shdr->sh_entsize);
+
+	return elf_is_shdr_sane(shdr, len) ? 0 : -ENOEXEC;
+}
+
+/**
+ * elf_read_shdrs - read the section headers from the buffer
+ *
+ * This function assumes that the section header table was checked for sanity.
+ * Use elf_is_ehdr_sane() if it wasn't.
+ */
+static int elf_read_shdrs(const char *buf, size_t len,
+			  struct kexec_elf_info *elf_info)
+{
+	size_t shdr_size, i;
+
+	/*
+	 * e_shnum is at most 65536 so calculating
+	 * the size of the section header cannot overflow.
+	 */
+	shdr_size = sizeof(struct elf_shdr) * elf_info->ehdr->e_shnum;
+
+	elf_info->sechdrs = kzalloc(shdr_size, GFP_KERNEL);
+	if (!elf_info->sechdrs)
+		return -ENOMEM;
+
+	for (i = 0; i < elf_info->ehdr->e_shnum; i++) {
+		int ret;
+
+		ret = elf_read_shdr(buf, len, elf_info, i);
+		if (ret) {
+			kfree(elf_info->sechdrs);
+			elf_info->sechdrs = NULL;
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * elf_read_from_buffer - read ELF file and sets up ELF header and ELF info
+ * @buf:	Buffer to read ELF file from.
+ * @len:	Size of @buf.
+ * @ehdr:	Pointer to existing struct which will be populated.
+ * @elf_info:	Pointer to existing struct which will be populated.
+ *
+ * This function allows reading ELF files with different byte order than
+ * the kernel, byte-swapping the fields as needed.
+ *
+ * Return:
+ * On success returns 0, and the caller should call kexec_free_elf_info(elf_info) to
+ * free the memory allocated for the section and program headers.
+ */
+int elf_read_from_buffer(const char *buf, size_t len, struct elfhdr *ehdr,
+			 struct kexec_elf_info *elf_info)
+{
+	int ret;
+
+	ret = elf_read_ehdr(buf, len, ehdr);
+	if (ret)
+		return ret;
+
+	elf_info->buffer = buf;
+	elf_info->ehdr = ehdr;
+	if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) {
+		ret = elf_read_phdrs(buf, len, elf_info);
+		if (ret)
+			return ret;
+	}
+	if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) {
+		ret = elf_read_shdrs(buf, len, elf_info);
+		if (ret) {
+			kfree(elf_info->proghdrs);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * kexec_free_elf_info - free memory allocated by elf_read_from_buffer
+ */
+void kexec_free_elf_info(struct kexec_elf_info *elf_info)
+{
+	kfree(elf_info->proghdrs);
+	kfree(elf_info->sechdrs);
+	memset(elf_info, 0, sizeof(*elf_info));
+}
+EXPORT_SYMBOL(kexec_free_elf_info);
+
+/**
+ * kexec_build_elf_info - read ELF executable and check that we can use it
+ */
+int kexec_build_elf_info(const char *buf, size_t len, struct elfhdr *ehdr,
+			  struct kexec_elf_info *elf_info)
+{
+	int i;
+	int ret;
+
+	ret = elf_read_from_buffer(buf, len, ehdr, elf_info);
+	if (ret)
+		return ret;
+
+	/* Big endian vmlinux has type ET_DYN. */
+	if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
+		pr_err("Not an ELF executable.\n");
+		goto error;
+	} else if (!elf_info->proghdrs) {
+		pr_err("No ELF program header.\n");
+		goto error;
+	}
+
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		/*
+		 * Kexec does not support loading interpreters.
+		 * In addition this check keeps us from attempting
+		 * to kexec ordinay executables.
+		 */
+		if (elf_info->proghdrs[i].p_type == PT_INTERP) {
+			pr_err("Requires an ELF interpreter.\n");
+			goto error;
+		}
+	}
+
+	return 0;
+error:
+	kexec_free_elf_info(elf_info);
+	return -ENOEXEC;
+}
+EXPORT_SYMBOL(kexec_build_elf_info);
+
+/**
+ * elf_exec_load - load ELF executable image
+ * @lowest_load_addr:	On return, will be the address where the first PT_LOAD
+ *			section will be loaded in memory.
+ *
+ * Return:
+ * 0 on success, negative value on failure.
+ */
+int kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
+		   struct kexec_elf_info *elf_info,
+		   struct kexec_buf *kbuf,
+		   unsigned long *lowest_load_addr)
+{
+	unsigned long lowest_addr = UINT_MAX;
+	int ret;
+	size_t i;
+	/* Read in the PT_LOAD segments. */
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		unsigned long load_addr;
+		size_t size;
+		const struct elf_phdr *phdr;
+
+		phdr = &elf_info->proghdrs[i];
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		size = phdr->p_filesz;
+		if (size > phdr->p_memsz)
+			size = phdr->p_memsz;
+
+		kbuf->buffer = (void *) elf_info->buffer + phdr->p_offset;
+		kbuf->bufsz = size;
+		kbuf->memsz = phdr->p_memsz;
+		kbuf->buf_align = phdr->p_align;
+		kbuf->buf_min = phdr->p_paddr;
+		kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
+		ret = kexec_add_buffer(kbuf);
+		if (ret)
+			goto out;
+		load_addr = kbuf->mem;
+
+		if (load_addr < lowest_addr)
+			lowest_addr = load_addr;
+	}
+
+	image->start = ehdr->e_entry;
+	*lowest_load_addr = lowest_addr;
+	ret = 0;
+ out:
+	return ret;
+}
+EXPORT_SYMBOL(kexec_elf_load);
+
+int kexec_elf_kernel_load(struct kimage *image, struct kexec_buf *kbuf,
+			char *kernel_buf, unsigned long kernel_len,
+			unsigned long *kernel_load_addr)
+{
+	int ret;
+	struct elfhdr ehdr;
+	struct kexec_elf_info elf_info;
+
+	ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info);
+	if (ret)
+		goto out;
+
+	ret = kexec_elf_load(image, &ehdr, &elf_info, kbuf, kernel_load_addr);
+out:
+	kexec_free_elf_info(&elf_info);
+	return ret;
+
+}
+EXPORT_SYMBOL(kexec_elf_kernel_load);
+
+int kexec_elf_probe(const char *buf, unsigned long len)
+{
+	struct elfhdr ehdr;
+	struct kexec_elf_info elf_info;
+	int ret;
+
+	ret = kexec_build_elf_info(buf, len, &ehdr, &elf_info);
+	if (ret)
+		return ret;
+
+	kexec_free_elf_info(&elf_info);
+
+	return elf_check_arch(&ehdr) ? 0 : -ENOEXEC;
+}
+EXPORT_SYMBOL(kexec_elf_probe);
-- 
2.20.1


^ permalink raw reply related

* [PATCH 0/5] Enable CONFIG_NODES_SPAN_OTHER_NODES by default for NUMA
From: Hoan Tran OS @ 2019-06-25 22:30 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Andrew Morton, Michal Hocko,
	Vlastimil Babka, Oscar Salvador, Pavel Tatashin, Mike Rapoport,
	Alexander Duyck, Benjamin Herrenschmidt, Paul Mackerras,
	Michael Ellerman, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H . Peter Anvin, David S . Miller, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger
  Cc: linux-s390@vger.kernel.org, x86@kernel.org,
	linux-kernel@vger.kernel.org, open list:MEMORY MANAGEMENT,
	Hoan Tran OS, sparclinux@vger.kernel.org, Open Source Submission,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

This patch set enables CONFIG_NODES_SPAN_OTHER_NODES by default
for NUMA.

The original patch [1]
[1] arm64: Kconfig: Enable NODES_SPAN_OTHER_NODES config for NUMA
https://www.spinics.net/lists/arm-kernel/msg737306.html

Hoan Tran (5):
  mm: Enable CONFIG_NODES_SPAN_OTHER_NODES by default for NUMA
  powerpc: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES
  x86: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES
  sparc: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES
  s390: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES

 arch/powerpc/Kconfig | 9 ---------
 arch/s390/Kconfig    | 8 --------
 arch/sparc/Kconfig   | 9 ---------
 arch/x86/Kconfig     | 9 ---------
 mm/page_alloc.c      | 2 +-
 5 files changed, 1 insertion(+), 36 deletions(-)

-- 
2.7.4


^ permalink raw reply

* [PATCH 1/5] mm: Enable CONFIG_NODES_SPAN_OTHER_NODES by default for NUMA
From: Hoan Tran OS @ 2019-06-25 22:30 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Andrew Morton, Michal Hocko,
	Vlastimil Babka, Oscar Salvador, Pavel Tatashin, Mike Rapoport,
	Alexander Duyck, Benjamin Herrenschmidt, Paul Mackerras,
	Michael Ellerman, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H . Peter Anvin, David S . Miller, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger
  Cc: linux-s390@vger.kernel.org, x86@kernel.org,
	linux-kernel@vger.kernel.org, open list:MEMORY MANAGEMENT,
	Hoan Tran OS, sparclinux@vger.kernel.org, Open Source Submission,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1561501810-25163-1-git-send-email-Hoan@os.amperecomputing.com>

This patch enables CONFIG_NODES_SPAN_OTHER_NODES by default
for NUMA. As some NUMA nodes have memory ranges that span other
nodes. Even though a pfn is valid and between a node's start and
end pfns, it may not reside on that node.

Signed-off-by: Hoan Tran <Hoan@os.amperecomputing.com>
---
 mm/page_alloc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d66bc8a..6335505 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1413,7 +1413,7 @@ int __meminit early_pfn_to_nid(unsigned long pfn)
 }
 #endif
 
-#ifdef CONFIG_NODES_SPAN_OTHER_NODES
+#ifdef CONFIG_NUMA
 /* Only safe to use early in boot when initialisation is single-threaded */
 static inline bool __meminit early_pfn_in_nid(unsigned long pfn, int node)
 {
-- 
2.7.4


^ permalink raw reply related

* [PATCH 2/5] powerpc: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES
From: Hoan Tran OS @ 2019-06-25 22:30 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Andrew Morton, Michal Hocko,
	Vlastimil Babka, Oscar Salvador, Pavel Tatashin, Mike Rapoport,
	Alexander Duyck, Benjamin Herrenschmidt, Paul Mackerras,
	Michael Ellerman, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H . Peter Anvin, David S . Miller, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger
  Cc: linux-s390@vger.kernel.org, x86@kernel.org,
	linux-kernel@vger.kernel.org, open list:MEMORY MANAGEMENT,
	Hoan Tran OS, sparclinux@vger.kernel.org, Open Source Submission,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1561501810-25163-1-git-send-email-Hoan@os.amperecomputing.com>

This patch removes CONFIG_NODES_SPAN_OTHER_NODES as it's
enabled by default with NUMA.

Signed-off-by: Hoan Tran <Hoan@os.amperecomputing.com>
---
 arch/powerpc/Kconfig | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8c1c636..bdde8bc 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -629,15 +629,6 @@ config ARCH_MEMORY_PROBE
 	def_bool y
 	depends on MEMORY_HOTPLUG
 
-# Some NUMA nodes have memory ranges that span
-# other nodes.  Even though a pfn is valid and
-# between a node's start and end pfns, it may not
-# reside on that node.  See memmap_init_zone()
-# for details.
-config NODES_SPAN_OTHER_NODES
-	def_bool y
-	depends on NEED_MULTIPLE_NODES
-
 config STDBINUTILS
 	bool "Using standard binutils settings"
 	depends on 44x
-- 
2.7.4


^ permalink raw reply related

* [PATCH 3/5] x86: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES
From: Hoan Tran OS @ 2019-06-25 22:30 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Andrew Morton, Michal Hocko,
	Vlastimil Babka, Oscar Salvador, Pavel Tatashin, Mike Rapoport,
	Alexander Duyck, Benjamin Herrenschmidt, Paul Mackerras,
	Michael Ellerman, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H . Peter Anvin, David S . Miller, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger
  Cc: linux-s390@vger.kernel.org, x86@kernel.org,
	linux-kernel@vger.kernel.org, open list:MEMORY MANAGEMENT,
	Hoan Tran OS, sparclinux@vger.kernel.org, Open Source Submission,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1561501810-25163-1-git-send-email-Hoan@os.amperecomputing.com>

This patch removes CONFIG_NODES_SPAN_OTHER_NODES as it's
enabled by default with NUMA.

Signed-off-by: Hoan Tran <Hoan@os.amperecomputing.com>
---
 arch/x86/Kconfig | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 2bbbd4d..fa9318c 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1567,15 +1567,6 @@ config X86_64_ACPI_NUMA
 	---help---
 	  Enable ACPI SRAT based node topology detection.
 
-# Some NUMA nodes have memory ranges that span
-# other nodes.  Even though a pfn is valid and
-# between a node's start and end pfns, it may not
-# reside on that node.  See memmap_init_zone()
-# for details.
-config NODES_SPAN_OTHER_NODES
-	def_bool y
-	depends on X86_64_ACPI_NUMA
-
 config NUMA_EMU
 	bool "NUMA emulation"
 	depends on NUMA
-- 
2.7.4


^ permalink raw reply related

* [PATCH 4/5] sparc: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES
From: Hoan Tran OS @ 2019-06-25 22:30 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Andrew Morton, Michal Hocko,
	Vlastimil Babka, Oscar Salvador, Pavel Tatashin, Mike Rapoport,
	Alexander Duyck, Benjamin Herrenschmidt, Paul Mackerras,
	Michael Ellerman, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H . Peter Anvin, David S . Miller, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger
  Cc: linux-s390@vger.kernel.org, x86@kernel.org,
	linux-kernel@vger.kernel.org, open list:MEMORY MANAGEMENT,
	Hoan Tran OS, sparclinux@vger.kernel.org, Open Source Submission,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1561501810-25163-1-git-send-email-Hoan@os.amperecomputing.com>

This patch removes CONFIG_NODES_SPAN_OTHER_NODES as it's
enabled by default with NUMA.

Signed-off-by: Hoan Tran <Hoan@os.amperecomputing.com>
---
 arch/sparc/Kconfig | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 26ab6f5..13449ea 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -291,15 +291,6 @@ config NODES_SHIFT
 	  Specify the maximum number of NUMA Nodes available on the target
 	  system.  Increases memory reserved to accommodate various tables.
 
-# Some NUMA nodes have memory ranges that span
-# other nodes.  Even though a pfn is valid and
-# between a node's start and end pfns, it may not
-# reside on that node.  See memmap_init_zone()
-# for details.
-config NODES_SPAN_OTHER_NODES
-	def_bool y
-	depends on NEED_MULTIPLE_NODES
-
 config ARCH_SELECT_MEMORY_MODEL
 	def_bool y if SPARC64
 
-- 
2.7.4


^ permalink raw reply related

* [PATCH 5/5] s390: Kconfig: Remove CONFIG_NODES_SPAN_OTHER_NODES
From: Hoan Tran OS @ 2019-06-25 22:30 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Andrew Morton, Michal Hocko,
	Vlastimil Babka, Oscar Salvador, Pavel Tatashin, Mike Rapoport,
	Alexander Duyck, Benjamin Herrenschmidt, Paul Mackerras,
	Michael Ellerman, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H . Peter Anvin, David S . Miller, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger
  Cc: linux-s390@vger.kernel.org, x86@kernel.org,
	linux-kernel@vger.kernel.org, open list:MEMORY MANAGEMENT,
	Hoan Tran OS, sparclinux@vger.kernel.org, Open Source Submission,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1561501810-25163-1-git-send-email-Hoan@os.amperecomputing.com>

This patch removes CONFIG_NODES_SPAN_OTHER_NODES as it's
enabled by default with NUMA.

Signed-off-by: Hoan Tran <Hoan@os.amperecomputing.com>
---
 arch/s390/Kconfig | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 109243f..788a8e9 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -438,14 +438,6 @@ config HOTPLUG_CPU
 	  can be controlled through /sys/devices/system/cpu/cpu#.
 	  Say N if you want to disable CPU hotplug.
 
-# Some NUMA nodes have memory ranges that span
-# other nodes.	Even though a pfn is valid and
-# between a node's start and end pfns, it may not
-# reside on that node.	See memmap_init_zone()
-# for details. <- They meant memory holes!
-config NODES_SPAN_OTHER_NODES
-	def_bool NUMA
-
 config NUMA
 	bool "NUMA support"
 	depends on SMP && SCHED_TOPOLOGY
-- 
2.7.4


^ permalink raw reply related

* Re: [PATCH 0/5] Enable CONFIG_NODES_SPAN_OTHER_NODES by default for NUMA
From: Linus Torvalds @ 2019-06-26  0:28 UTC (permalink / raw)
  To: Hoan Tran OS
  Cc: Michal Hocko, Catalin Marinas, Heiko Carstens,
	open list:MEMORY MANAGEMENT, Paul Mackerras, H . Peter Anvin,
	sparclinux@vger.kernel.org, Alexander Duyck,
	linux-s390@vger.kernel.org, x86@kernel.org, Mike Rapoport,
	Christian Borntraeger, Ingo Molnar, Vlastimil Babka,
	Open Source Submission, Pavel Tatashin, Vasily Gorbik,
	Will Deacon, Borislav Petkov, Thomas Gleixner,
	linux-arm-kernel@lists.infradead.org, Oscar Salvador,
	linux-kernel@vger.kernel.org, Andrew Morton,
	linuxppc-dev@lists.ozlabs.org, David S . Miller
In-Reply-To: <1561501810-25163-1-git-send-email-Hoan@os.amperecomputing.com>

This is not a comment on the patch series itself, it is a comment on the emails.

Your email is mis-configured and ends up all being marked as spam for
me, because you go through the wrong smtp server (or maybe your smtp
server itself is miconfigured)

All your emails fail dmarc, because the "From" header is
os.amperecomputing.com, but the DKIM signature is for
amperemail.onmicrosoft.com.

End result: it wil all go into the spam box of anybody who checks DKIM.

                       Linus

On Wed, Jun 26, 2019 at 6:30 AM Hoan Tran OS
<hoan@os.amperecomputing.com> wrote:
>
> This patch set enables CONFIG_NODES_SPAN_OTHER_NODES by default
> for NUMA. [...]

^ permalink raw reply

* Re: [PATCH 3/4] powerpc/powernv: remove unused NPU DMA code
From: Alexey Kardashevskiy @ 2019-06-26  0:44 UTC (permalink / raw)
  To: Christoph Hellwig, Benjamin Herrenschmidt, Paul Mackerras,
	Michael Ellerman
  Cc: Frederic Barrat, linuxppc-dev, Oliver O'Halloran,
	linux-kernel
In-Reply-To: <20190625145239.2759-4-hch@lst.de>



On 26/06/2019 00:52, Christoph Hellwig wrote:
> None of these routines were ever used anywhere in the kernel tree
> since they were added to the kernel.


So none of my comments has been addressed. Nice.


> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  arch/powerpc/include/asm/book3s/64/mmu.h |   2 -
>  arch/powerpc/include/asm/powernv.h       |  22 -
>  arch/powerpc/mm/book3s64/mmu_context.c   |   1 -
>  arch/powerpc/platforms/powernv/npu-dma.c | 556 -----------------------
>  4 files changed, 581 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
> index 74d24201fc4f..23b83d3593e2 100644
> --- a/arch/powerpc/include/asm/book3s/64/mmu.h
> +++ b/arch/powerpc/include/asm/book3s/64/mmu.h
> @@ -116,8 +116,6 @@ typedef struct {
>  	/* Number of users of the external (Nest) MMU */
>  	atomic_t copros;
>  
> -	/* NPU NMMU context */
> -	struct npu_context *npu_context;
>  	struct hash_mm_context *hash_context;
>  
>  	unsigned long vdso_base;
> diff --git a/arch/powerpc/include/asm/powernv.h b/arch/powerpc/include/asm/powernv.h
> index 05b552418519..40f868c5e93c 100644
> --- a/arch/powerpc/include/asm/powernv.h
> +++ b/arch/powerpc/include/asm/powernv.h
> @@ -11,35 +11,13 @@
>  #define _ASM_POWERNV_H
>  
>  #ifdef CONFIG_PPC_POWERNV
> -#define NPU2_WRITE 1
>  extern void powernv_set_nmmu_ptcr(unsigned long ptcr);
> -extern struct npu_context *pnv_npu2_init_context(struct pci_dev *gpdev,
> -			unsigned long flags,
> -			void (*cb)(struct npu_context *, void *),
> -			void *priv);
> -extern void pnv_npu2_destroy_context(struct npu_context *context,
> -				struct pci_dev *gpdev);
> -extern int pnv_npu2_handle_fault(struct npu_context *context, uintptr_t *ea,
> -				unsigned long *flags, unsigned long *status,
> -				int count);
>  
>  void pnv_program_cpu_hotplug_lpcr(unsigned int cpu, u64 lpcr_val);
>  
>  void pnv_tm_init(void);
>  #else
>  static inline void powernv_set_nmmu_ptcr(unsigned long ptcr) { }
> -static inline struct npu_context *pnv_npu2_init_context(struct pci_dev *gpdev,
> -			unsigned long flags,
> -			struct npu_context *(*cb)(struct npu_context *, void *),
> -			void *priv) { return ERR_PTR(-ENODEV); }
> -static inline void pnv_npu2_destroy_context(struct npu_context *context,
> -					struct pci_dev *gpdev) { }
> -
> -static inline int pnv_npu2_handle_fault(struct npu_context *context,
> -					uintptr_t *ea, unsigned long *flags,
> -					unsigned long *status, int count) {
> -	return -ENODEV;
> -}
>  
>  static inline void pnv_tm_init(void) { }
>  #endif
> diff --git a/arch/powerpc/mm/book3s64/mmu_context.c b/arch/powerpc/mm/book3s64/mmu_context.c
> index cb2b08635508..0dd3e631cf3e 100644
> --- a/arch/powerpc/mm/book3s64/mmu_context.c
> +++ b/arch/powerpc/mm/book3s64/mmu_context.c
> @@ -140,7 +140,6 @@ static int radix__init_new_context(struct mm_struct *mm)
>  	 */
>  	asm volatile("ptesync;isync" : : : "memory");
>  
> -	mm->context.npu_context = NULL;
>  	mm->context.hash_context = NULL;
>  
>  	return index;
> diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
> index dc1058efc24f..72b7441029ca 100644
> --- a/arch/powerpc/platforms/powernv/npu-dma.c
> +++ b/arch/powerpc/platforms/powernv/npu-dma.c
> @@ -22,12 +22,6 @@
>  
>  #include "pci.h"
>  
> -/*
> - * spinlock to protect initialisation of an npu_context for a particular
> - * mm_struct.
> - */
> -static DEFINE_SPINLOCK(npu_context_lock);
> -
>  static struct pci_dev *get_pci_dev(struct device_node *dn)
>  {
>  	struct pci_dn *pdn = PCI_DN(dn);
> @@ -375,15 +369,6 @@ struct npu_comp {
>  /* An NPU descriptor, valid for POWER9 only */
>  struct npu {
>  	int index;
> -	__be64 *mmio_atsd_regs[NV_NMMU_ATSD_REGS];
> -	unsigned int mmio_atsd_count;
> -
> -	/* Bitmask for MMIO register usage */
> -	unsigned long mmio_atsd_usage;
> -
> -	/* Do we need to explicitly flush the nest mmu? */
> -	bool nmmu_flush;
> -
>  	struct npu_comp npucomp;
>  };
>  
> @@ -640,534 +625,8 @@ struct iommu_table_group *pnv_npu_compound_attach(struct pnv_ioda_pe *pe)
>  }
>  #endif /* CONFIG_IOMMU_API */
>  
> -/* Maximum number of nvlinks per npu */
> -#define NV_MAX_LINKS 6
> -
> -/* Maximum index of npu2 hosts in the system. Always < NV_MAX_NPUS */
> -static int max_npu2_index;
> -
> -struct npu_context {
> -	struct mm_struct *mm;
> -	struct pci_dev *npdev[NV_MAX_NPUS][NV_MAX_LINKS];
> -	struct mmu_notifier mn;
> -	struct kref kref;
> -	bool nmmu_flush;
> -
> -	/* Callback to stop translation requests on a given GPU */
> -	void (*release_cb)(struct npu_context *context, void *priv);
> -
> -	/*
> -	 * Private pointer passed to the above callback for usage by
> -	 * device drivers.
> -	 */
> -	void *priv;
> -};
> -
> -struct mmio_atsd_reg {
> -	struct npu *npu;
> -	int reg;
> -};
> -
> -/*
> - * Find a free MMIO ATSD register and mark it in use. Return -ENOSPC
> - * if none are available.
> - */
> -static int get_mmio_atsd_reg(struct npu *npu)
> -{
> -	int i;
> -
> -	for (i = 0; i < npu->mmio_atsd_count; i++) {
> -		if (!test_bit(i, &npu->mmio_atsd_usage))
> -			if (!test_and_set_bit_lock(i, &npu->mmio_atsd_usage))
> -				return i;
> -	}
> -
> -	return -ENOSPC;
> -}
> -
> -static void put_mmio_atsd_reg(struct npu *npu, int reg)
> -{
> -	clear_bit_unlock(reg, &npu->mmio_atsd_usage);
> -}
> -
> -/* MMIO ATSD register offsets */
> -#define XTS_ATSD_LAUNCH 0
> -#define XTS_ATSD_AVA    1
> -#define XTS_ATSD_STAT   2
> -
> -static unsigned long get_atsd_launch_val(unsigned long pid, unsigned long psize)
> -{
> -	unsigned long launch = 0;
> -
> -	if (psize == MMU_PAGE_COUNT) {
> -		/* IS set to invalidate entire matching PID */
> -		launch |= PPC_BIT(12);
> -	} else {
> -		/* AP set to invalidate region of psize */
> -		launch |= (u64)mmu_get_ap(psize) << PPC_BITLSHIFT(17);
> -	}
> -
> -	/* PRS set to process-scoped */
> -	launch |= PPC_BIT(13);
> -
> -	/* PID */
> -	launch |= pid << PPC_BITLSHIFT(38);
> -
> -	/* Leave "No flush" (bit 39) 0 so every ATSD performs a flush */
> -
> -	return launch;
> -}
> -
> -static void mmio_atsd_regs_write(struct mmio_atsd_reg
> -			mmio_atsd_reg[NV_MAX_NPUS], unsigned long offset,
> -			unsigned long val)
> -{
> -	struct npu *npu;
> -	int i, reg;
> -
> -	for (i = 0; i <= max_npu2_index; i++) {
> -		reg = mmio_atsd_reg[i].reg;
> -		if (reg < 0)
> -			continue;
> -
> -		npu = mmio_atsd_reg[i].npu;
> -		__raw_writeq_be(val, npu->mmio_atsd_regs[reg] + offset);
> -	}
> -}
> -
> -static void mmio_invalidate_pid(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS],
> -				unsigned long pid)
> -{
> -	unsigned long launch = get_atsd_launch_val(pid, MMU_PAGE_COUNT);
> -
> -	/* Invalidating the entire process doesn't use a va */
> -	mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_LAUNCH, launch);
> -}
> -
> -static void mmio_invalidate_range(struct mmio_atsd_reg
> -			mmio_atsd_reg[NV_MAX_NPUS], unsigned long pid,
> -			unsigned long start, unsigned long psize)
> -{
> -	unsigned long launch = get_atsd_launch_val(pid, psize);
> -
> -	/* Write all VAs first */
> -	mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_AVA, start);
> -
> -	/* Issue one barrier for all address writes */
> -	eieio();
> -
> -	/* Launch */
> -	mmio_atsd_regs_write(mmio_atsd_reg, XTS_ATSD_LAUNCH, launch);
> -}
> -
> -#define mn_to_npu_context(x) container_of(x, struct npu_context, mn)
> -
> -static void mmio_invalidate_wait(
> -	struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS])
> -{
> -	struct npu *npu;
> -	int i, reg;
> -
> -	/* Wait for all invalidations to complete */
> -	for (i = 0; i <= max_npu2_index; i++) {
> -		if (mmio_atsd_reg[i].reg < 0)
> -			continue;
> -
> -		/* Wait for completion */
> -		npu = mmio_atsd_reg[i].npu;
> -		reg = mmio_atsd_reg[i].reg;
> -		while (__raw_readq(npu->mmio_atsd_regs[reg] + XTS_ATSD_STAT))
> -			cpu_relax();
> -	}
> -}
> -
> -/*
> - * Acquires all the address translation shootdown (ATSD) registers required to
> - * launch an ATSD on all links this npu_context is active on.
> - */
> -static void acquire_atsd_reg(struct npu_context *npu_context,
> -			struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS])
> -{
> -	int i, j;
> -	struct npu *npu;
> -	struct pci_dev *npdev;
> -
> -	for (i = 0; i <= max_npu2_index; i++) {
> -		mmio_atsd_reg[i].reg = -1;
> -		for (j = 0; j < NV_MAX_LINKS; j++) {
> -			/*
> -			 * There are no ordering requirements with respect to
> -			 * the setup of struct npu_context, but to ensure
> -			 * consistent behaviour we need to ensure npdev[][] is
> -			 * only read once.
> -			 */
> -			npdev = READ_ONCE(npu_context->npdev[i][j]);
> -			if (!npdev)
> -				continue;
> -
> -			npu = pci_bus_to_host(npdev->bus)->npu;
> -			if (!npu)
> -				continue;
> -
> -			mmio_atsd_reg[i].npu = npu;
> -			mmio_atsd_reg[i].reg = get_mmio_atsd_reg(npu);
> -			while (mmio_atsd_reg[i].reg < 0) {
> -				mmio_atsd_reg[i].reg = get_mmio_atsd_reg(npu);
> -				cpu_relax();
> -			}
> -			break;
> -		}
> -	}
> -}
> -
> -/*
> - * Release previously acquired ATSD registers. To avoid deadlocks the registers
> - * must be released in the same order they were acquired above in
> - * acquire_atsd_reg.
> - */
> -static void release_atsd_reg(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS])
> -{
> -	int i;
> -
> -	for (i = 0; i <= max_npu2_index; i++) {
> -		/*
> -		 * We can't rely on npu_context->npdev[][] being the same here
> -		 * as when acquire_atsd_reg() was called, hence we use the
> -		 * values stored in mmio_atsd_reg during the acquire phase
> -		 * rather than re-reading npdev[][].
> -		 */
> -		if (mmio_atsd_reg[i].reg < 0)
> -			continue;
> -
> -		put_mmio_atsd_reg(mmio_atsd_reg[i].npu, mmio_atsd_reg[i].reg);
> -	}
> -}
> -
> -/*
> - * Invalidate a virtual address range
> - */
> -static void mmio_invalidate(struct npu_context *npu_context,
> -			unsigned long start, unsigned long size)
> -{
> -	struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS];
> -	unsigned long pid = npu_context->mm->context.id;
> -	unsigned long atsd_start = 0;
> -	unsigned long end = start + size - 1;
> -	int atsd_psize = MMU_PAGE_COUNT;
> -
> -	/*
> -	 * Convert the input range into one of the supported sizes. If the range
> -	 * doesn't fit, use the next larger supported size. Invalidation latency
> -	 * is high, so over-invalidation is preferred to issuing multiple
> -	 * invalidates.
> -	 *
> -	 * A 4K page size isn't supported by NPU/GPU ATS, so that case is
> -	 * ignored.
> -	 */
> -	if (size == SZ_64K) {
> -		atsd_start = start;
> -		atsd_psize = MMU_PAGE_64K;
> -	} else if (ALIGN_DOWN(start, SZ_2M) == ALIGN_DOWN(end, SZ_2M)) {
> -		atsd_start = ALIGN_DOWN(start, SZ_2M);
> -		atsd_psize = MMU_PAGE_2M;
> -	} else if (ALIGN_DOWN(start, SZ_1G) == ALIGN_DOWN(end, SZ_1G)) {
> -		atsd_start = ALIGN_DOWN(start, SZ_1G);
> -		atsd_psize = MMU_PAGE_1G;
> -	}
> -
> -	if (npu_context->nmmu_flush)
> -		/*
> -		 * Unfortunately the nest mmu does not support flushing specific
> -		 * addresses so we have to flush the whole mm once before
> -		 * shooting down the GPU translation.
> -		 */
> -		flush_all_mm(npu_context->mm);
> -
> -	/*
> -	 * Loop over all the NPUs this process is active on and launch
> -	 * an invalidate.
> -	 */
> -	acquire_atsd_reg(npu_context, mmio_atsd_reg);
> -
> -	if (atsd_psize == MMU_PAGE_COUNT)
> -		mmio_invalidate_pid(mmio_atsd_reg, pid);
> -	else
> -		mmio_invalidate_range(mmio_atsd_reg, pid, atsd_start,
> -					atsd_psize);
> -
> -	mmio_invalidate_wait(mmio_atsd_reg);
> -
> -	/*
> -	 * The GPU requires two flush ATSDs to ensure all entries have been
> -	 * flushed. We use PID 0 as it will never be used for a process on the
> -	 * GPU.
> -	 */
> -	mmio_invalidate_pid(mmio_atsd_reg, 0);
> -	mmio_invalidate_wait(mmio_atsd_reg);
> -	mmio_invalidate_pid(mmio_atsd_reg, 0);
> -	mmio_invalidate_wait(mmio_atsd_reg);
> -
> -	release_atsd_reg(mmio_atsd_reg);
> -}
> -
> -static void pnv_npu2_mn_release(struct mmu_notifier *mn,
> -				struct mm_struct *mm)
> -{
> -	struct npu_context *npu_context = mn_to_npu_context(mn);
> -
> -	/* Call into device driver to stop requests to the NMMU */
> -	if (npu_context->release_cb)
> -		npu_context->release_cb(npu_context, npu_context->priv);
> -
> -	/*
> -	 * There should be no more translation requests for this PID, but we
> -	 * need to ensure any entries for it are removed from the TLB.
> -	 */
> -	mmio_invalidate(npu_context, 0, ~0UL);
> -}
> -
> -static void pnv_npu2_mn_invalidate_range(struct mmu_notifier *mn,
> -					struct mm_struct *mm,
> -					unsigned long start, unsigned long end)
> -{
> -	struct npu_context *npu_context = mn_to_npu_context(mn);
> -	mmio_invalidate(npu_context, start, end - start);
> -}
> -
> -static const struct mmu_notifier_ops nv_nmmu_notifier_ops = {
> -	.release = pnv_npu2_mn_release,
> -	.invalidate_range = pnv_npu2_mn_invalidate_range,
> -};
> -
> -/*
> - * Call into OPAL to setup the nmmu context for the current task in
> - * the NPU. This must be called to setup the context tables before the
> - * GPU issues ATRs. pdev should be a pointed to PCIe GPU device.
> - *
> - * A release callback should be registered to allow a device driver to
> - * be notified that it should not launch any new translation requests
> - * as the final TLB invalidate is about to occur.
> - *
> - * Returns an error if there no contexts are currently available or a
> - * npu_context which should be passed to pnv_npu2_handle_fault().
> - *
> - * mmap_sem must be held in write mode and must not be called from interrupt
> - * context.
> - */
> -struct npu_context *pnv_npu2_init_context(struct pci_dev *gpdev,
> -			unsigned long flags,
> -			void (*cb)(struct npu_context *, void *),
> -			void *priv)
> -{
> -	int rc;
> -	u32 nvlink_index;
> -	struct device_node *nvlink_dn;
> -	struct mm_struct *mm = current->mm;
> -	struct npu *npu;
> -	struct npu_context *npu_context;
> -	struct pci_controller *hose;
> -
> -	/*
> -	 * At present we don't support GPUs connected to multiple NPUs and I'm
> -	 * not sure the hardware does either.
> -	 */
> -	struct pci_dev *npdev = pnv_pci_get_npu_dev(gpdev, 0);
> -
> -	if (!npdev)
> -		/* No nvlink associated with this GPU device */
> -		return ERR_PTR(-ENODEV);
> -
> -	/* We only support DR/PR/HV in pnv_npu2_map_lpar_dev() */
> -	if (flags & ~(MSR_DR | MSR_PR | MSR_HV))
> -		return ERR_PTR(-EINVAL);
> -
> -	nvlink_dn = of_parse_phandle(npdev->dev.of_node, "ibm,nvlink", 0);
> -	if (WARN_ON(of_property_read_u32(nvlink_dn, "ibm,npu-link-index",
> -							&nvlink_index)))
> -		return ERR_PTR(-ENODEV);
> -
> -	if (!mm || mm->context.id == 0) {
> -		/*
> -		 * Kernel thread contexts are not supported and context id 0 is
> -		 * reserved on the GPU.
> -		 */
> -		return ERR_PTR(-EINVAL);
> -	}
> -
> -	hose = pci_bus_to_host(npdev->bus);
> -	npu = hose->npu;
> -	if (!npu)
> -		return ERR_PTR(-ENODEV);
> -
> -	/*
> -	 * We store the npu pci device so we can more easily get at the
> -	 * associated npus.
> -	 */
> -	spin_lock(&npu_context_lock);
> -	npu_context = mm->context.npu_context;
> -	if (npu_context) {
> -		if (npu_context->release_cb != cb ||
> -			npu_context->priv != priv) {
> -			spin_unlock(&npu_context_lock);
> -			return ERR_PTR(-EINVAL);
> -		}
> -
> -		WARN_ON(!kref_get_unless_zero(&npu_context->kref));
> -	}
> -	spin_unlock(&npu_context_lock);
> -
> -	if (!npu_context) {
> -		/*
> -		 * We can set up these fields without holding the
> -		 * npu_context_lock as the npu_context hasn't been returned to
> -		 * the caller meaning it can't be destroyed. Parallel allocation
> -		 * is protected against by mmap_sem.
> -		 */
> -		rc = -ENOMEM;
> -		npu_context = kzalloc(sizeof(struct npu_context), GFP_KERNEL);
> -		if (npu_context) {
> -			kref_init(&npu_context->kref);
> -			npu_context->mm = mm;
> -			npu_context->mn.ops = &nv_nmmu_notifier_ops;
> -			rc = __mmu_notifier_register(&npu_context->mn, mm);
> -		}
> -
> -		if (rc) {
> -			kfree(npu_context);
> -			return ERR_PTR(rc);
> -		}
> -
> -		mm->context.npu_context = npu_context;
> -	}
> -
> -	npu_context->release_cb = cb;
> -	npu_context->priv = priv;
> -
> -	/*
> -	 * npdev is a pci_dev pointer setup by the PCI code. We assign it to
> -	 * npdev[][] to indicate to the mmu notifiers that an invalidation
> -	 * should also be sent over this nvlink. The notifiers don't use any
> -	 * other fields in npu_context, so we just need to ensure that when they
> -	 * deference npu_context->npdev[][] it is either a valid pointer or
> -	 * NULL.
> -	 */
> -	WRITE_ONCE(npu_context->npdev[npu->index][nvlink_index], npdev);
> -
> -	if (!npu->nmmu_flush) {
> -		/*
> -		 * If we're not explicitly flushing ourselves we need to mark
> -		 * the thread for global flushes
> -		 */
> -		npu_context->nmmu_flush = false;
> -		mm_context_add_copro(mm);
> -	} else
> -		npu_context->nmmu_flush = true;
> -
> -	return npu_context;
> -}
> -EXPORT_SYMBOL(pnv_npu2_init_context);
> -
> -static void pnv_npu2_release_context(struct kref *kref)
> -{
> -	struct npu_context *npu_context =
> -		container_of(kref, struct npu_context, kref);
> -
> -	if (!npu_context->nmmu_flush)
> -		mm_context_remove_copro(npu_context->mm);
> -
> -	npu_context->mm->context.npu_context = NULL;
> -}
> -
> -/*
> - * Destroy a context on the given GPU. May free the npu_context if it is no
> - * longer active on any GPUs. Must not be called from interrupt context.
> - */
> -void pnv_npu2_destroy_context(struct npu_context *npu_context,
> -			struct pci_dev *gpdev)
> -{
> -	int removed;
> -	struct npu *npu;
> -	struct pci_dev *npdev = pnv_pci_get_npu_dev(gpdev, 0);
> -	struct device_node *nvlink_dn;
> -	u32 nvlink_index;
> -	struct pci_controller *hose;
> -
> -	if (WARN_ON(!npdev))
> -		return;
> -
> -	hose = pci_bus_to_host(npdev->bus);
> -	npu = hose->npu;
> -	if (!npu)
> -		return;
> -	nvlink_dn = of_parse_phandle(npdev->dev.of_node, "ibm,nvlink", 0);
> -	if (WARN_ON(of_property_read_u32(nvlink_dn, "ibm,npu-link-index",
> -							&nvlink_index)))
> -		return;
> -	WRITE_ONCE(npu_context->npdev[npu->index][nvlink_index], NULL);
> -	spin_lock(&npu_context_lock);
> -	removed = kref_put(&npu_context->kref, pnv_npu2_release_context);
> -	spin_unlock(&npu_context_lock);
> -
> -	/*
> -	 * We need to do this outside of pnv_npu2_release_context so that it is
> -	 * outside the spinlock as mmu_notifier_destroy uses SRCU.
> -	 */
> -	if (removed) {
> -		mmu_notifier_unregister(&npu_context->mn,
> -					npu_context->mm);
> -
> -		kfree(npu_context);
> -	}
> -
> -}
> -EXPORT_SYMBOL(pnv_npu2_destroy_context);
> -
> -/*
> - * Assumes mmap_sem is held for the contexts associated mm.
> - */
> -int pnv_npu2_handle_fault(struct npu_context *context, uintptr_t *ea,
> -			unsigned long *flags, unsigned long *status, int count)
> -{
> -	u64 rc = 0, result = 0;
> -	int i, is_write;
> -	struct page *page[1];
> -	const char __user *u;
> -	char c;
> -
> -	/* mmap_sem should be held so the struct_mm must be present */
> -	struct mm_struct *mm = context->mm;
> -
> -	WARN_ON(!rwsem_is_locked(&mm->mmap_sem));
> -
> -	for (i = 0; i < count; i++) {
> -		is_write = flags[i] & NPU2_WRITE;
> -		rc = get_user_pages_remote(NULL, mm, ea[i], 1,
> -					is_write ? FOLL_WRITE : 0,
> -					page, NULL, NULL);
> -
> -		if (rc != 1) {
> -			status[i] = rc;
> -			result = -EFAULT;
> -			continue;
> -		}
> -
> -		/* Make sure partition scoped tree gets a pte */
> -		u = page_address(page[0]);
> -		if (__get_user(c, u))
> -			result = -EFAULT;
> -
> -		status[i] = 0;
> -		put_page(page[0]);
> -	}
> -
> -	return result;
> -}
> -EXPORT_SYMBOL(pnv_npu2_handle_fault);
> -
>  int pnv_npu2_init(struct pci_controller *hose)
>  {
> -	unsigned int i;
> -	u64 mmio_atsd;
>  	static int npu_index;
>  	struct npu *npu;
>  	int ret;
> @@ -1176,33 +635,18 @@ int pnv_npu2_init(struct pci_controller *hose)
>  	if (!npu)
>  		return -ENOMEM;
>  
> -	npu->nmmu_flush = of_property_read_bool(hose->dn, "ibm,nmmu-flush");
> -
> -	for (i = 0; i < ARRAY_SIZE(npu->mmio_atsd_regs) &&
> -			!of_property_read_u64_index(hose->dn, "ibm,mmio-atsd",
> -				i, &mmio_atsd); i++)
> -		npu->mmio_atsd_regs[i] = ioremap(mmio_atsd, 32);
> -
> -	pr_info("NPU%d: Found %d MMIO ATSD registers", hose->global_number, i);
> -	npu->mmio_atsd_count = i;
> -	npu->mmio_atsd_usage = 0;
>  	npu_index++;
>  	if (WARN_ON(npu_index >= NV_MAX_NPUS)) {
>  		ret = -ENOSPC;
>  		goto fail_exit;
>  	}
> -	max_npu2_index = npu_index;
>  	npu->index = npu_index;
>  	hose->npu = npu;
>  
>  	return 0;
>  
>  fail_exit:
> -	for (i = 0; i < npu->mmio_atsd_count; ++i)
> -		iounmap(npu->mmio_atsd_regs[i]);
> -
>  	kfree(npu);
> -
>  	return ret;
>  }
>  
> 

-- 
Alexey

^ permalink raw reply

* [PATCH kernel v2] powerpc/pci/of: Parse unassigned resources
From: Alexey Kardashevskiy @ 2019-06-26  2:37 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Alexey Kardashevskiy, Alistair Popple, Sam Bobroff,
	Paul Mackerras, Oliver O'Halloran, David Gibson

The pseries platform uses the PCI_PROBE_DEVTREE method of PCI probing
which reads "assigned-addresses" of every PCI device and initializes
the device resources. However if the property is missing or zero sized,
then there is no fallback of any kind and the PCI resources remain
undiscovered, i.e. pdev->resource[] array remains empty.

This adds a fallback which parses the "reg" property in pretty much same
way except it marks resources as "unset" which later make Linux assign
those resources proper addresses.

This has an effect when:
1. a hypervisor failed to assign any resource for a device;
2. /chosen/linux,pci-probe-only=0 is in the DT so the system may try
assigning a resource.
Neither is likely to happen under PowerVM.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---

This is an attempts to boot linux directly under QEMU without slof/rtas;
the aim is to use petitboot instead and let the guest kernel configure
devices.

QEMU does not allocate resources, it creates correct "reg" and zero length
"assigned-addresses" (which is probably a bug on its own) which is
normally populated by SLOF later but not during this exercise.

---
Changes:
v2:
* updated commit log
* fixed a bug with checking "addrs" which made the whole patch pointless
* s/unset/mark_unset/
---
 arch/powerpc/kernel/pci_of_scan.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index 64ad92016b63..bd78f325a636 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -82,10 +82,16 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
 	const __be32 *addrs;
 	u32 i;
 	int proplen;
+	bool mark_unset = false;
 
 	addrs = of_get_property(node, "assigned-addresses", &proplen);
-	if (!addrs)
-		return;
+	if (!addrs || !proplen) {
+		addrs = of_get_property(node, "reg", &proplen);
+		if (!addrs || !proplen)
+			return;
+		mark_unset = true;
+	}
+
 	pr_debug("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
 	for (; proplen >= 20; proplen -= 20, addrs += 5) {
 		flags = pci_parse_of_flags(of_read_number(addrs, 1), 0);
@@ -110,6 +116,8 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
 			continue;
 		}
 		res->flags = flags;
+		if (mark_unset)
+			res->flags |= IORESOURCE_UNSET;
 		res->name = pci_name(dev);
 		region.start = base;
 		region.end = base + size - 1;
-- 
2.17.1


^ permalink raw reply related

* Re: [PATCH v2 1/3] powerpc/pseries: Update SCM hcall op-codes in hvcall.h
From: Oliver O'Halloran @ 2019-06-26  3:17 UTC (permalink / raw)
  To: Vaibhav Jain
  Cc: Laurent Dufour, linuxppc-dev, Aneesh Kumar K . V, David Gibson
In-Reply-To: <20190625122709.11846-2-vaibhav@linux.ibm.com>

On Tue, Jun 25, 2019 at 10:27 PM Vaibhav Jain <vaibhav@linux.ibm.com> wrote:
>
> Update the hvcalls.h to include op-codes for new hcalls introduce to
> manage SCM memory. Also update existing hcall definitions to reflect
> current papr specification for SCM.
>
> Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
> ---
> Change-log:
>
> v2:
> * None new patch in this series.
> ---
>  arch/powerpc/include/asm/hvcall.h | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
> index 463c63a9fcf1..1f5f917dae8c 100644
> --- a/arch/powerpc/include/asm/hvcall.h
> +++ b/arch/powerpc/include/asm/hvcall.h
> @@ -302,9 +302,14 @@
>  #define H_SCM_UNBIND_MEM        0x3F0
>  #define H_SCM_QUERY_BLOCK_MEM_BINDING 0x3F4
>  #define H_SCM_QUERY_LOGICAL_MEM_BINDING 0x3F8
> -#define H_SCM_MEM_QUERY                0x3FC
> +#define H_SCM_UNBIND_ALL        0x3FC
>  #define H_SCM_BLOCK_CLEAR       0x400

The BLOCK_CLEAR hcall was removed from the spec and the 0x400 hcall
number is now used by H_SCM_HEALTH.

> -#define MAX_HCALL_OPCODE       H_SCM_BLOCK_CLEAR
> +#define H_SCM_PERFORMANCE_STATS 0x418
> +#define MAX_HCALL_OPCODE       H_SCM_PERFORMANCE_STATS
> +
> +/* Scope args for H_SCM_UNBIND_ALL */
> +#define H_UNBIND_SCOPE_ALL (0x1)
> +#define H_UNBIND_SCOPE_DRC (0x2)
>
>  /* H_VIOCTL functions */
>  #define H_GET_VIOA_DUMP_SIZE   0x01
> --
> 2.21.0
>

^ permalink raw reply

* Re: [PATCH v2 3/3] powerpc/papr_scm: Force a scm-unbind if initial scm-bind fails
From: Oliver O'Halloran @ 2019-06-26  3:24 UTC (permalink / raw)
  To: Vaibhav Jain
  Cc: Laurent Dufour, linuxppc-dev, Aneesh Kumar K . V, David Gibson
In-Reply-To: <20190625122709.11846-4-vaibhav@linux.ibm.com>

On Tue, Jun 25, 2019 at 10:27 PM Vaibhav Jain <vaibhav@linux.ibm.com> wrote:
>
> In some cases initial bind of scm memory for an lpar can fail if
> previously it wasn't released using a scm-unbind hcall. This situation
> can arise due to panic of the previous kernel or forced lpar
> fadump. In such cases the H_SCM_BIND_MEM return a H_OVERLAP error.
>
> To mitigate such cases the patch updates papr_scm_probe() to force a
> call to drc_pmem_unbind() in case the initial bind of scm memory fails
> with EBUSY error. In case scm-bind operation again fails after the
> forced scm-unbind then we follow the existing error path. We also
> update drc_pmem_bind() to handle the H_OVERLAP error returned by phyp
> and indicate it as a EBUSY error back to the caller.
>
> Suggested-by: "Oliver O'Halloran" <oohall@gmail.com>
> Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
> ---
> Change-log:
>
> v2:
> * Moved the retry code from drc_pmem_bind() to papr_scm_probe()
>   [Oliver]
> * Changed the type of variable 'rc' in drc_pmem_bind() to
>   int64_t. [Oliver]
> ---
>  arch/powerpc/platforms/pseries/papr_scm.c | 15 ++++++++++++++-
>  1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c
> index a4e1674bb15c..2c90cbe88313 100644
> --- a/arch/powerpc/platforms/pseries/papr_scm.c
> +++ b/arch/powerpc/platforms/pseries/papr_scm.c
> @@ -43,8 +43,9 @@ struct papr_scm_priv {
>  static int drc_pmem_bind(struct papr_scm_priv *p)
>  {
>         unsigned long ret[PLPAR_HCALL_BUFSIZE];
> -       uint64_t rc, token;
>         uint64_t saved = 0;
> +       uint64_t token;
> +       int64_t rc;
>
>         /*
>          * When the hypervisor cannot map all the requested memory in a single
> @@ -64,6 +65,10 @@ static int drc_pmem_bind(struct papr_scm_priv *p)
>         } while (rc == H_BUSY);
>
>         if (rc) {
> +               /* H_OVERLAP needs a separate error path */
> +               if (rc == H_OVERLAP)
> +                       return -EBUSY;
> +
>                 dev_err(&p->pdev->dev, "bind err: %lld\n", rc);
>                 return -ENXIO;
>         }
> @@ -331,6 +336,14 @@ static int papr_scm_probe(struct platform_device *pdev)
>
>         /* request the hypervisor to bind this region to somewhere in memory */
>         rc = drc_pmem_bind(p);
> +
> +       /* If phyp reports drc memory still bound the force unbound and retry */

"the force" should be "then force"?

> +       if (rc == -EBUSY) {
> +               dev_warn(&pdev->dev, "Retrying bind after unbinding\n");


Looks good otherwise,

Reviewed-by: Oliver O'Halloran <oohall@gmail.com>

^ permalink raw reply

* Re: [PATCH v2 2/3] powerpc/papr_scm: Update drc_pmem_unbind() to use H_SCM_UNBIND_ALL
From: Oliver O'Halloran @ 2019-06-26  3:47 UTC (permalink / raw)
  To: Vaibhav Jain
  Cc: Laurent Dufour, linuxppc-dev, Aneesh Kumar K . V, David Gibson
In-Reply-To: <20190625122709.11846-3-vaibhav@linux.ibm.com>

On Tue, Jun 25, 2019 at 10:27 PM Vaibhav Jain <vaibhav@linux.ibm.com> wrote:
>
> The new hcall named H_SCM_UNBIND_ALL has been introduce that can
> unbind all the memory drc memory-blocks assigned to an lpar.

This is a little muddy. For normal memory each block has a DRC so you
can add/remove individual blocks by configuring or deconfiguring the
DRC for that block. For storage class memory the DRC refers to the SCM
volume as a whole rather than an individual block so a "memory DRC"
isn't really what you're taking about here.

This is probably being a little pedantic, but I find the whole DRC
system confusing enough as-is so it's good to be clear about these
things.

> more efficient than using H_SCM_UNBIND_MEM as currently we don't
> support partial unbind of drc memory-blocks.
>
> Hence this patch proposes following changes to drc_pmem_unbind():
>
>     * Update drc_pmem_unbind() to replace hcall H_SCM_UNBIND_MEM to
>       H_SCM_UNBIND_ALL.
>
>     * Update drc_pmem_unbind() to handles cases when PHYP asks the guest
>       kernel to wait for specific amount of time before retrying the
>       hcall via the 'LONG_BUSY' return value.
>
> * Ensure appropriate error code is returned back from the function
>       in case of an error.
>
> Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
> ---
> Change-log:
>
> v2:
> * Added a dev_dbg when unbind operation succeeds [Oliver]
> * Changed type of variable 'rc' to int64_t [Oliver]
> * Removed the code that was logging a warning in case bind operation
>   takes >1-seconds [Oliver]
> * Spinned off changes to hvcall.h as a separate patch. [Oliver]

Looks good otherwise, when you respin feel free to add:

Reviewed-by: Oliver O'Halloran <oohall@gmail.com>

^ permalink raw reply

* Re: Bisected regression in v5.1 on PowerBook G3 (Wallstreet)
From: Christophe Leroy @ 2019-06-26  5:49 UTC (permalink / raw)
  To: Finn Thain; +Cc: linuxppc-dev, Stan
In-Reply-To: <alpine.LNX.2.21.1906261134540.121@nippy.intranet>

Hi Finn,

On 06/26/2019 02:06 AM, Finn Thain wrote:
> Hi Christophe,
> 
> I received a report of a regression between v5.0 and v5.1 which causes the
> current release to crash during boot with a machine check exception.
> Please see console log below.
> 
> Stan (whom I've Cc'd) tells me that this happens on every attempt to boot.
> I asked him to try 'git bisect'. The results are given below. Can you see
> anything in commit 93c4a162b014 that might explain this?

Might be a false positive. That commit has a problem, but that problem 
is fixed by 4622a2d43101 ("powerpc/6xx: fix setup and use of 
SPRN_SPRG_PGDIR for hash32")

I would bet your problem is related to commit f7354ccac844 ("powerpc/32: 
Remove CURRENT_THREAD_INFO and rename TI_CPU").
That problem is fixed by commit 397d2300b08c ("powerpc/32s: fix 
flush_hash_pages() on SMP") upstream, and in linux 5.1.4 by commit 
fda49aec2515 on stable/linux-5.1.y

Can you test ?

Thanks
Christophe

> 
> I can also provide the .config if it would help.
> 
> 
> $ cat bisect.log
> 5.0.0-pmac-ide-03515-g3478588b5136 #2 worked
> 5.0.0-pmac-ide-05504-gda2577fe63f8 #3 worked
> 5.0.0-pmac-ide-06224-g67e79a6dc266 #4 worked
> 5.0.0-pmac-ide-06622-g1fc1cd8399ab #5 worked
> 5.0.0-rc2-pmac-ide-00215=g9580b71b5a78 #6 failed
> 5.0.0-rc2-pmac-ide-00113-gfe1ef6bcdb4f #7 worked
> 5.0.0-rc2-pmac-ide-00164-gd5f17ee96447 #8 failed
> 5.0.0-rc2-pmac-ide-00138-g84de6ab0e904 #9 failed
> 5.0.0-rc2-pmac-ide-00125-ge995265252fa #10 worked
> 5.0.0-rc2-pmac-ide-00131-g93c4a162b014 #11 failed
> 5.0.0-rc2-pmac-ide-00128-g36da5ff0bea2 #12 worked
> 
> 
> 93c4a162b014d238a287f8264adb25c009c79e61 is the first bad commit
> commit 93c4a162b014d238a287f8264adb25c009c79e61
> Author: Christophe Leroy <christophe.leroy@c-s.fr>
> Date:   Thu Feb 21 10:37:55 2019 +0000
> 
>      powerpc/6xx: Store PGDIR physical address in a SPRG
> 
>      Use SPRN_SPRG2 to store the current thread PGDIR and
>      avoid reading thread_struct.pgdir at every TLB miss.
> 
>      Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
>      Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> 
> :040000 040000 dcd7171dff5ba5bf895e4399d9d859c91c5a8293
> c51e7def7720499289420ace421cf755bf3bf37e M      arch
> 
> 
> [    0.000000] printk: debug: ignoring loglevel setting.
> [    0.000000] Total memory = 512MB; using 1024kB for hash table (at (ptrval))
> [    0.000000] Linux version 5.1.0-pmac-ide (fthain@nippy) (gcc version 4.6.4 (btc)) #1 SMP Sun Jun 23 14:46:26 AEST 2019
> [    0.000000] Found a Gatwick mac-io controller, rev: 0, mapped at 0x(ptrval)
> [    0.000000] Found a Heathrow mac-io controller, rev: 0, mapped at 0x(ptrval)
> [    0.000000] PowerMac motherboard: PowerBook Wallstreet
> [    0.000000] PMU driver v2 initialized for PowerBook G3 Series, firmware: 0a
> [    0.000000] Using PowerMac machine description
> [    0.000000] printk: bootconsole [udbg0] enabled
> [    0.000000] CPU maps initialized for 1 thread per core
> [    0.000000]  (thread shift is 0)
> [    0.000000] -----------------------------------------------------
> [    0.000000] Hash_size         = 0x100000
> [    0.000000] phys_mem_size     = 0x20000000
> [    0.000000] dcache_bsize      = 0x20
> [    0.000000] icache_bsize      = 0x20
> [    0.000000] cpu_features      = 0x000000000501a008
> [    0.000000]   possible        = 0x000000002f7ff14b
> [    0.000000]   always          = 0x0000000001000000
> [    0.000000] cpu_user_features = 0x8c000001 0x00000000
> [    0.000000] mmu_features      = 0x00000001
> [    0.000000] Hash              = 0x(ptrval)
> [    0.000000] Hash_mask         = 0x3fff
> [    0.000000] -----------------------------------------------------
> [    0.000000] Found Grackle (MPC106) PCI host bridge at 0x0000000080000000. Firmware bus number: 0->0
> [    0.000000] PCI host bridge /pci (primary) ranges:
> [    0.000000]   IO 0x00000000fe000000..0x00000000fe7fffff -> 0x0000000000000000
> [    0.000000]  MEM 0x00000000fd000000..0x00000000fdffffff -> 0x0000000000000000
> [    0.000000]  MEM 0x0000000080000000..0x00000000fcffffff -> 0x0000000080000000
> [    0.000000] nvram: OF partition at 0x1800
> [    0.000000] nvram: XP partition at 0x1300
> [    0.000000] nvram: NR partition at 0x1400
> [    0.000000] Top of RAM: 0x20000000, Total RAM: 0x20000000
> [    0.000000] Memory hole size: 0MB
> [    0.000000] Zone ranges:
> [    0.000000]   Normal   [mem 0x0000000000000000-0x000000001fffffff]
> [    0.000000]   HighMem  empty
> [    0.000000] Movable zone start for each node
> [    0.000000] Early memory node ranges
> [    0.000000]   node   0: [mem 0x0000000000000000-0x000000001fffffff]
> [    0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x000000001fffffff]
> [    0.000000] On node 0 totalpages: 131072
> [    0.000000]   Normal zone: 1024 pages used for memmap
> [    0.000000]   Normal zone: 0 pages reserved
> [    0.000000]   Normal zone: 131072 pages, LIFO batch:31
> [    0.000000] percpu: Embedded 14 pages/cpu s24972 r8192 d24180 u57344
> [    0.000000] pcpu-alloc: s24972 r8192 d24180 u57344 alloc=14*4096
> [    0.000000] pcpu-alloc: [0] 0 [0] 1
> [    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 130048
> [    0.000000] Kernel command line: root=/dev/hda11 video=atyfb:vmode:14,cmode:32 ignore_loglevel printk.time console=ttyS0,9600n8 console=tty
> [    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
> [    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
> [    0.000000] Memory: 503332K/524288K available (5468K kernel code, 272K rwdata, 1364K rodata, 264K init, 182K bss, 20956K reserved, 0K cma-reserved, 0K highmem)
> [    0.000000] Kernel virtual memory layout:
> [    0.000000]   * 0xfffbf000..0xfffff000  : fixmap
> [    0.000000]   * 0xff800000..0xffc00000  : highmem PTEs
> [    0.000000]   * 0xfeefb000..0xff800000  : early ioremap
> [    0.000000]   * 0xe1000000..0xfeefb000  : vmalloc & ioremap
> [    0.000000] rcu: Hierarchical RCU implementation.
> [    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
> [    0.000000] NR_IRQS: 512, nr_irqs: 512, preallocated irqs: 16
> [    0.000000] irq: Found primary Apple PIC /pci/mac-io for 64 irqs
> [    0.000000] irq: Found slave Apple PIC /pci/mac-io for 64 irqs cascade: 27
> [    0.000000] irq: System has 128 possible interrupts
> [    0.000000] GMT Delta read from XPRAM: -360 minutes, DST: on
> [    0.000000] time_init: decrementer frequency = 16.671483 MHz
> [    0.000000] time_init: processor frequency   = 264.000000 MHz
> [    0.000064] clocksource: timebase: mask: 0xffffffffffffffff max_cycles: 0x3d84ef27e, max_idle_ns: 440795202259 ns
> [    0.000100] clocksource: timebase mult[3bfb9003] shift[24] registered
> [    0.000195] clockevent: decrementer mult[4449512] shift[32] cpu[0]
> [    0.001150] Console: colour dummy device 80x25
> [    0.001193] printk: console [tty0] enabled
> [    0.001239] printk: bootconsole [udbg0] disabled
> [    0.001625] pmac_zilog: serial modem detected
> [    4.977278] printk: console [ttyS0] enabled
> [    5.027516] pid_max: default: 32768 minimum: 301
> [    5.083376] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
> [    5.162419] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
> [    5.248523] *** VALIDATE proc ***
> [    5.287109] *** VALIDATE cgroup1 ***
> [    5.329716] *** VALIDATE cgroup2 ***
> [    5.375172] rcu: Hierarchical SRCU implementation.
> [    5.431972] smp: Bringing up secondary CPUs ...
> [    5.484998] smp: Brought up 1 node, 1 CPU
> [    5.533075] Using standard scheduler topology
> [    5.586632] devtmpfs: initialized
> [    5.625731] Duplicate name in PowerPC,750, renamed to "l2-cache#1"
> [    5.702735] Duplicate name in pci, renamed to "mac-io#1"
> [    5.766262] Duplicate name in pci, renamed to "pccard#1"
> [    5.830071] random: get_random_u32 called from bucket_table_alloc+0x94/0x1c4 with crng_init=0
> [    5.932144] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
> [    6.049531] futex hash table entries: 512 (order: 2, 16384 bytes)
> [    6.123224] NET: Registered protocol family 16
> [    6.181111] PMU i2c /pci/mac-io/via-pmu
> [    6.226470]  channel 1 bus <multibus>
> [    6.269024]  channel 2 bus <multibus>
> [    6.315157] PCI: Probing PCI hardware
> [    6.358004] PCI host bridge to bus 0000:00
> [    6.406370] pci_bus 0000:00: root bus resource [io  0x0000-0x7fffff]
> [    6.482602] pci_bus 0000:00: root bus resource [mem 0xfd000000-0xfdffffff] (bus address [0x00000000-0x00ffffff])
> [    6.604898] pci_bus 0000:00: root bus resource [mem 0x80000000-0xfcffffff]
> [    6.687515] pci_bus 0000:00: root bus resource [bus 00-ff]
> [    6.753382] pci_bus 0000:00: busn_res: [bus 00-ff] end is updated to ff
> [    6.833106] pci 0000:00:00.0: [1057:0002] type 00 class 0x060000
> [    6.906583] pci 0000:00:0d.0: [106b:0017] type 00 class 0xff0000
> [    6.977163] pci 0000:00:0d.0: reg 0x10: [mem 0xf4000000-0xf407ffff]
> [    7.053429] pci 0000:00:10.0: [106b:0017] type 00 class 0xff0000
> [    7.124631] pci 0000:00:10.0: reg 0x10: [mem 0xf3000000-0xf307ffff]
> [    7.200827] pci 0000:00:11.0: [1002:4c50] type 00 class 0x038000
> [    7.272082] pci 0000:00:11.0: reg 0x10: [mem 0x82000000-0x82ffffff]
> [    7.347336] pci 0000:00:11.0: reg 0x14: [io  0x0400-0x04ff]
> [    7.414246] pci 0000:00:11.0: reg 0x18: [mem 0x82fff000-0x82ffffff]
> [    7.489567] pci 0000:00:11.0: reg 0x30: [mem 0xfd000000-0xfd01ffff pref]
> [    7.570113] pci 0000:00:11.0: supports D1 D2
> [    7.622206] pci 0000:00:13.0: [104c:ac15] type 02 class 0x060700
> [    7.693527] pci 0000:00:13.0: reg 0x10: [mem 0x81803000-0x81803fff]
> [    7.769592] pci 0000:00:13.1: [104c:ac15] type 02 class 0x060700
> [    7.841140] pci 0000:00:13.1: reg 0x10: [mem 0x81802000-0x81802fff]
> [    7.918261] pci_bus 0000:01: extended config space not accessible
> [    7.990055] pci_bus 0000:01: busn_res: [bus 01-ff] end is updated to 04
> [    8.069175] pci_bus 0000:05: extended config space not accessible
> [    8.142536] pci_bus 0000:05: busn_res: [bus 05-ff] end is updated to 08
> [    8.221620] pci_bus 0000:00: busn_res: [bus 00-ff] end is updated to 08
> [    8.301308] PCI: Cannot allocate resource region 2 of device 0000:00:11.0, will remap
> [    8.395264] PCI 0000:00 Cannot reserve Legacy IO [io  0x0000-0x0fff]
> [    8.471672] pci 0000:00:13.0: BAR 9: assigned [mem 0x84000000-0x87ffffff pref]
> [    8.558317] pci 0000:00:13.0: BAR 10: assigned [mem 0x88000000-0x8bffffff]
> [    8.640898] pci 0000:00:13.1: BAR 9: assigned [mem 0x8c000000-0x8fffffff pref]
> [    8.727690] pci 0000:00:13.1: BAR 10: assigned [mem 0x90000000-0x93ffffff]
> [    8.810457] pci 0000:00:11.0: BAR 6: assigned [mem 0xfd000000-0xfd01ffff pref]
> [    8.897101] pci 0000:00:11.0: BAR 2: assigned [mem 0xfd020000-0xfd020fff]
> [    8.978667] pci 0000:00:13.0: BAR 7: assigned [io  0x1000-0x10ff]
> [    9.051864] pci 0000:00:13.0: BAR 8: assigned [io  0x1100-0x11ff]
> [    9.125064] pci 0000:00:13.1: BAR 7: assigned [io  0x1200-0x12ff]
> [    9.198269] pci 0000:00:13.1: BAR 8: assigned [io  0x1300-0x13ff]
> [    9.271483] pci 0000:00:13.0: CardBus bridge to [bus 01-04]
> [    9.338395] pci 0000:00:13.0:   bridge window [io  0x1000-0x10ff]
> [    9.411598] pci 0000:00:13.0:   bridge window [io  0x1100-0x11ff]
> [    9.484802] pci 0000:00:13.0:   bridge window [mem 0x84000000-0x87ffffff pref]
> [    9.571597] pci 0000:00:13.0:   bridge window [mem 0x88000000-0x8bffffff]
> [    9.653165] pci 0000:00:13.1: CardBus bridge to [bus 05-08]
> [    9.720086] pci 0000:00:13.1:   bridge window [io  0x1200-0x12ff]
> [    9.793366] pci 0000:00:13.1:   bridge window [io  0x1300-0x13ff]
> [    9.866498] pci 0000:00:13.1:   bridge window [mem 0x8c000000-0x8fffffff pref]
> [    9.953294] pci 0000:00:13.1:   bridge window [mem 0x90000000-0x93ffffff]
> [   10.034865] pci_bus 0000:00: resource 4 [io  0x0000-0x7fffff]
> [   10.103874] pci_bus 0000:00: resource 5 [mem 0xfd000000-0xfdffffff]
> [   10.179168] pci_bus 0000:00: resource 6 [mem 0x80000000-0xfcffffff]
> [   10.254461] pci_bus 0000:01: resource 0 [io  0x1000-0x10ff]
> [   10.321391] pci_bus 0000:01: resource 1 [io  0x1100-0x11ff]
> [   10.388316] pci_bus 0000:01: resource 2 [mem 0x84000000-0x87ffffff pref]
> [   10.468841] pci_bus 0000:01: resource 3 [mem 0x88000000-0x8bffffff]
> [   10.544134] pci_bus 0000:05: resource 0 [io  0x1200-0x12ff]
> [   10.611058] pci_bus 0000:05: resource 1 [io  0x1300-0x13ff]
> [   10.677989] pci_bus 0000:05: resource 2 [mem 0x8c000000-0x8fffffff pref]
> [   10.758507] pci_bus 0000:05: resource 3 [mem 0x90000000-0x93ffffff]
> [   10.898594] vgaarb: loaded
> [   10.931312] SCSI subsystem initialized
> [   10.975369] usbcore: registered new interface driver usbfs
> [   11.040901] usbcore: registered new interface driver hub
> [   11.104378] usbcore: registered new device driver usb
> [   11.170053] clocksource: Switched to clocksource timebase
> [   11.276916] NET: Registered protocol family 2
> [   11.330625] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes)
> [   11.420991] TCP established hash table entries: 4096 (order: 2, 16384 bytes)
> [   11.505653] TCP bind hash table entries: 4096 (order: 3, 32768 bytes)
> [   11.583095] TCP: Hash tables configured (established 4096 bind 4096)
> [   11.659434] UDP hash table entries: 256 (order: 1, 8192 bytes)
> [   11.729313] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
> [   11.805155] NET: Registered protocol family 1
> [   11.857851] RPC: Registered named UNIX socket transport module.
> [   11.927797] RPC: Registered udp transport module.
> [   11.984240] RPC: Registered tcp transport module.
> [   12.040709] RPC: Registered tcp NFSv4.1 backchannel transport module.
> [   12.118278] PCI: CLS 32 bytes, default 32
> [   12.167681] Thermal assist unit
> [   12.167688] using timers,
> [   12.204947] shrink_timer: 200 jiffies
> [   12.285360] Initialise system trusted keyrings
> [   12.338272] workingset: timestamp_bits=30 max_order=17 bucket_order=0
> [   12.415177] squashfs: version 4.0 (2009/01/31) Phillip Lougher
> [   24.651142] Key type asymmetric registered
> [   24.698347] Asymmetric key parser 'x509' registered
> [   24.757356] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
> [   24.845895] io scheduler mq-deadline registered
> [   24.900069] io scheduler kyber registered
> [   24.949721] atyfb 0000:00:11.0: enabling device (0086 -> 0087)
> [   25.018669] atyfb: using auxiliary register aperture
> [   25.078882] atyfb: 3D RAGE LT PRO (Mach64 LP, PCI) [0x4c50 rev 0xdc]
> [   25.154242] atyfb: 4M SGRAM (1:1), 29.498928 MHz XTAL, 230 MHz PLL, 100 Mhz MCLK, 100 MHz XCLK
> [   25.311727] Console: switching to colour frame buffer device 128x48
> [   25.393746] atyfb: fb0: ATY Mach64 frame buffer device on PCI
> [   25.465544] pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)
> [   25.553288] Non-volatile memory driver v1.3
> [   25.611564] brd: module loaded
> [   25.669889] loop: module loaded
> [   25.706428] MacIO PCI driver attached to Gatwick chipset
> [   25.769945] MacIO PCI driver attached to Heathrow chipset
> [   25.842400] swim3 0.00015000:floppy: [fd0] SWIM3 floppy controller in media bay
> [   25.932618] 0.00013020:ch-a: ttyS0 at MMIO 0xf3013020 (irq = 16, base_baud = 230400) is a Z85c30 ESCC - Serial port
> [   26.058459] 0.00013000:ch-b: ttyS1 at MMIO 0xf3013000 (irq = 17, base_baud = 230400) is a Z85c30 ESCC - Infrared port
> [   26.186786] macio: fixed media-bay irq on gatwick
> [   26.242712] macio: fixed left floppy irqs
> [   26.290523] swim3 1.00015000:floppy: [fd1] Couldn't request interrupt
> [   26.367458] swim3: probe of 1.00015000:floppy failed with error -16
> [   26.442501] macio: fixed left ide irqs
> [   26.487653] macio: fixed SCC irqs on gatwick
> [   26.539043] 1.00013020:ch-a: ttyS2 at MMIO 0xf4013020 (irq = 79, base_baud = 230400) is a Z85c30 ESCC - Internal modem
> [   26.668762] mediabay0: Registered Heathrow media-bay
> [   26.939422] mediabay1: Registered Heathrow media-bay
> [   26.997073] mediabay0: Bay contains an ATA device
> [   27.210473] PMU Backlight initialized (pmubl)
> [   27.262723] Uniform Multi-Platform E-IDE driver
> [   28.368835] ide-pmac: Found Apple Heathrow ATA controller (macio), bus ID 0, irq 30
> [   28.463347] Probing IDE interface ide0...
> [   28.869051] hda: SAMSUNG HM100JC, ATA DISK drive
> [   29.453887] random: fast init done
> [   29.570254] adb device [2]: 2 0xC3
> [   29.618380] adb device [3]: 3 0x1
> [   29.663900] adb device [7]: 7 0x1F
> [   29.720910] ADB keyboard at 2 has handler 0xC3
> [   29.776681] Detected ADB keyboard, type ANSI.
> [   29.831871] input: ADB keyboard as /devices/virtual/input/input0
> [   29.906693] hda: host max PIO4 wanted PIO255(auto-tune) selected PIO4
> [   29.986514] hda: MWDMA2 mode selected
> [   30.033814] input: ADB Powerbook buttons as /devices/virtual/input/input1
> [   30.118138] ide0 at 0xe1045000-0xe1045070,0xe1045160 on irq 30
> [   30.192469] ide-pmac: Found Apple Heathrow ATA controller (macio), bus ID 1 (mediabay), irq 36
> [   30.299391] Probing IDE interface ide1...
> [   30.412609] ADB mouse (trackpad) at 3 has handler 0x4
> [   30.476206] input: ADB mouse as /devices/virtual/input/input2
> [   30.889011] hdc: MATSHITADVD-ROM SR-8182, ATAPI CD/DVD-ROM drive
> [   31.379281] hdc: host max PIO4 wanted PIO255(auto-tune) selected PIO4
> [   31.459300] hdc: MWDMA2 mode selected
> [   31.506018] ide1 at 0xe104b000-0xe104b070,0xe104b160 on irq 36
> [   31.580403] ide-pmac: Found Apple Heathrow ATA controller (macio), bus ID 4 (mediabay), irq 36
> [   31.687369] genirq: Flags mismatch irq 36. 00000000 (ide2) vs. 00000000 (ide1)
> [   31.776841] ide2: disabled, unable to get IRQ 36
> [   31.834841] ide2: failed to initialize IDE interface
> [   31.897376] ide2: disabling port
> [   31.938867] ide-pmac: probe of 1.00021000:ata4 failed with error -1
> [   32.017021] ide-gd driver 1.18
> [   32.056731] hda: max request size: 1024KiB
> [   34.309043] hda: 195371568 sectors (100030 MB) w/8192KiB Cache, CHS=16383/255/63
> [   34.400766] hda: cache flushes supported
> [   34.463701]  hda: [mac] hda1 hda2 hda3 hda4 hda5 hda6 hda7 hda8 hda9 hda10 hda11 hda12 hda13 hda14 hda15
> [   34.589982] ide-cd driver 5.00
> [   34.633445] ide-cd: hdc: ATAPI 12X DVD-ROM drive, 512kB Cache
> [   34.705160] cdrom: Uniform CD-ROM driver Revision: 3.20
> [   34.777383] mesh: configured for synchronous 5 MB/s
> [   35.058944] mesh: performing initial bus reset...
> [   39.168977] scsi host0: MESH
> [   41.986409] eth0: BMAC at 00:05:02:07:5a:a6
> [   41.986423]
> [   42.065206] aoe: cannot create debugfs directory
> [   42.124930] aoe: AoE v85 initialised.
> [   42.171200] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
> [   42.252472] ehci-pci: EHCI PCI platform driver
> [   42.308931] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
> [   42.386046] ohci-pci: OHCI PCI platform driver
> [   42.442614] usbcore: registered new interface driver uas
> [   42.509535] usbcore: registered new interface driver usb-storage
> [   42.587749] mousedev: PS/2 mouse device common for all mice
> [   42.661012] rtc-generic rtc-generic: registered as rtc0
> [   42.727259] i2c /dev entries driver
> [   42.773732] PowerMac i2c bus pmu 2 registered
> [   42.830093] PowerMac i2c bus pmu 1 registered
> [   42.891093] usbcore: registered new interface driver usbhid
> [   42.960484] usbhid: USB HID core driver
> [   43.012330] NET: Registered protocol family 17
> [   43.068724] drmem: No dynamic reconfiguration memory found
> [   43.138959] Loading compiled-in X.509 certificates
> [   43.637737] EXT4-fs (hda11): mounting ext3 file system using the ext4 subsystem
> [   43.759598] EXT4-fs (hda11): mounted filesystem with ordered data mode. Opts: (null)
> [   43.855814] VFS: Mounted root (ext3 filesystem) readonly on device 3:11.
> [   43.941974] Freeing unused kernel memory: 264K
> [   43.997598] This architecture does not have kernel memory protection.
> [   44.077215] Run /sbin/init as init process
> [   46.583096] Disabling lock debugging due to kernel taint
> [   46.649135] Machine check in kernel mode.
> [   46.699359] Caused by (from SRR1=41020): Transfer error ack signal
> [   46.776706] Oops: Machine check, sig: 7 [#1]
> [   46.830093] BE PAGE_SIZE=4K MMU=Hash SMP NR_CPUS=2 PowerMac
> [   46.899131] Modules linked in:
> [   46.937774] CPU: 0 PID: 1 Comm: init Tainted: G   M              5.1.0-pmac-ide #1
> [   47.030839] NIP:  c0018aa8 LR: c0018fcc CTR: 00000000
> [   47.093580] REGS: df437d40 TRAP: 0200   Tainted: G   M               (5.1.0-pmac-ide)
> [   47.189853] MSR:  00041020 <ME,IR>  CR: 42428084  XER: 00000000
> [   47.263133] DAR: 00000000 DSISR: dec05da0
> [   47.263133] GPR00: 00000bbb df437df0 df435160 000043cb b7ad4000 1ec0cb50 00000001 00020768
> [   47.263133] GPR08: 00000000 00739578 00009032 8021e59e 20424084 00000000 00000000 00000000
> [   47.263133] GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 dec0c000 c0730000
> [   47.263133] GPR24: dec0cb50 1fb21595 dec05da0 df437e18 dec07440 dffe13c0 1fb1e117 df437e18
> [   47.733625] NIP [c0018aa8] flush_hash_pages+0x70/0x164
> [   47.797425] LR [c0018fcc] flush_tlb_page+0x54/0x78
> [   47.857012] Call Trace:
> [   47.888320] [df437df0] [dffe13c0] 0xdffe13c0 (unreliable)
> [   47.955245] [df437e00] [c00f9418] ptep_clear_flush+0x3c/0x58
> [   48.025313] [df437e10] [c00ecf34] wp_page_copy+0x198/0x530
> [   48.093280] [df437e50] [c00ef5e0] do_wp_page+0x188/0x604
> [   48.159151] [df437e90] [c00f0838] handle_mm_fault+0x2f8/0x99c
> [   48.230265] [df437f00] [c0016528] do_page_fault+0x2a0/0x6b8
> [   48.299289] [df437f40] [c0012314] handle_page_fault+0x14/0x40
> [   48.370397] --- interrupt: 301 at 0xb7ab6444
> [   48.370397]     LR = 0xb7ab634c
> [   48.465462] Instruction dump:
> [   48.502950] 38c6ffff 4bffffe0 1c633810 5480273e 1c000111 7c630214 546b3870 508b56be
> [   48.598090] 656b8000 3d200074 39299578 8102009c <65080009> 7c004828 2c000000 4082000c
> [   48.695375] ---[ end trace c4d36e2b09ab4631 ]---
> [   48.752918]
> 

^ permalink raw reply

* Re: [PATCH 14/16] mm: move the powerpc hugepd code to mm/gup.c
From: Christoph Hellwig @ 2019-06-26  5:49 UTC (permalink / raw)
  To: Andrew Morton
  Cc: x86, Rich Felker, Yoshinori Sato, linux-sh, James Hogan,
	linuxppc-dev, Khalid Aziz, Nicholas Piggin, David S. Miller,
	linux-mm, Paul Burton, Paul Mackerras, Andrey Konovalov,
	sparclinux, linux-mips, Linus Torvalds, Christoph Hellwig,
	linux-kernel
In-Reply-To: <20190625123757.ec7e886747bb5a9bc364107d@linux-foundation.org>

On Tue, Jun 25, 2019 at 12:37:57PM -0700, Andrew Morton wrote:
> On Tue, 25 Jun 2019 16:37:13 +0200 Christoph Hellwig <hch@lst.de> wrote:
> 
> > +static int gup_huge_pd(hugepd_t hugepd
> 
> Naming nitlet: we have hugepd and we also have huge_pd.  We have
> hugepte and we also have huge_pte.  It make things a bit hard to
> remember and it would be nice to make it all consistent sometime.
> 
> We're consistent with huge_pud and almost consistent with huge_pmd.
> 
> To be fully consistent I guess we should make all of them have the
> underscore.  Or not have it.  

Either way is fine with me.  Feel free to fix up per your preference.

^ permalink raw reply

* Re: [PATCH 1/5] mm: Enable CONFIG_NODES_SPAN_OTHER_NODES by default for NUMA
From: Michal Hocko @ 2019-06-26  6:11 UTC (permalink / raw)
  To: Hoan Tran OS
  Cc: Catalin Marinas, Heiko Carstens, open list:MEMORY MANAGEMENT,
	Paul Mackerras, H . Peter Anvin, sparclinux@vger.kernel.org,
	Alexander Duyck, linux-s390@vger.kernel.org, x86@kernel.org,
	Mike Rapoport, Christian Borntraeger, Ingo Molnar,
	Vlastimil Babka, Open Source Submission, Pavel Tatashin,
	Vasily Gorbik, Will Deacon, Borislav Petkov, Thomas Gleixner,
	linux-arm-kernel@lists.infradead.org, Oscar Salvador,
	linux-kernel@vger.kernel.org, Andrew Morton,
	linuxppc-dev@lists.ozlabs.org, David S . Miller
In-Reply-To: <1561501810-25163-2-git-send-email-Hoan@os.amperecomputing.com>

On Tue 25-06-19 22:30:24, Hoan Tran OS wrote:
> This patch enables CONFIG_NODES_SPAN_OTHER_NODES by default
> for NUMA. As some NUMA nodes have memory ranges that span other
> nodes. Even though a pfn is valid and between a node's start and
> end pfns, it may not reside on that node.

Please describe the problem more thoroughly. What is the layout, what
doesn't work with the default configuration and why do we need this
particular fix rather than enabling of the config option for the
specific HW.

> 
> Signed-off-by: Hoan Tran <Hoan@os.amperecomputing.com>
> ---
>  mm/page_alloc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index d66bc8a..6335505 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -1413,7 +1413,7 @@ int __meminit early_pfn_to_nid(unsigned long pfn)
>  }
>  #endif
>  
> -#ifdef CONFIG_NODES_SPAN_OTHER_NODES
> +#ifdef CONFIG_NUMA
>  /* Only safe to use early in boot when initialisation is single-threaded */
>  static inline bool __meminit early_pfn_in_nid(unsigned long pfn, int node)
>  {
> -- 
> 2.7.4
> 

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply

* Re: DMA coherency in drivers/tty/serial/mpsc.c
From: Christoph Hellwig @ 2019-06-26  6:48 UTC (permalink / raw)
  To: Mark Greer
  Cc: Greg Kroah-Hartman, linux-kernel, Paul Gortmaker, linux-serial,
	Dale Farnsworth, linuxppc-dev, Christoph Hellwig
In-Reply-To: <20190625163722.GA18626@animalcreek.com>

On Tue, Jun 25, 2019 at 09:37:22AM -0700, Mark Greer wrote:
> Yeah, the mpsc driver had lots of ugly cache related hacks because of
> cache coherency bugs in the early version of the MV64x60 bridge chips
> that it was embedded in.  That chip is pretty much dead now and I've
> removed core support for it from the powerpc tree.  Removing the mpsc
> driver is on my todo list but I've been busy and lazy.  So, to sum it
> up, don't spend any more time worrying about it as it should be removed.
> 
> I'll post a patch to do that tonight and I'm sorry for any time you've
> spent looking at it so far.

No problem.  And if future such broken chips show up we now have
support for per-device DMA coherency settings and could actually
handle it in a reaѕonably clean way.

^ permalink raw reply

* Bisected regression in v5.1 on PowerBook G3 (Wallstreet)
From: Finn Thain @ 2019-06-26  2:06 UTC (permalink / raw)
  To: Christophe Leroy; +Cc: linuxppc-dev, Stan

Hi Christophe,

I received a report of a regression between v5.0 and v5.1 which causes the 
current release to crash during boot with a machine check exception. 
Please see console log below.

Stan (whom I've Cc'd) tells me that this happens on every attempt to boot. 
I asked him to try 'git bisect'. The results are given below. Can you see 
anything in commit 93c4a162b014 that might explain this?

I can also provide the .config if it would help.


$ cat bisect.log
5.0.0-pmac-ide-03515-g3478588b5136 #2 worked
5.0.0-pmac-ide-05504-gda2577fe63f8 #3 worked
5.0.0-pmac-ide-06224-g67e79a6dc266 #4 worked
5.0.0-pmac-ide-06622-g1fc1cd8399ab #5 worked
5.0.0-rc2-pmac-ide-00215=g9580b71b5a78 #6 failed
5.0.0-rc2-pmac-ide-00113-gfe1ef6bcdb4f #7 worked
5.0.0-rc2-pmac-ide-00164-gd5f17ee96447 #8 failed
5.0.0-rc2-pmac-ide-00138-g84de6ab0e904 #9 failed
5.0.0-rc2-pmac-ide-00125-ge995265252fa #10 worked
5.0.0-rc2-pmac-ide-00131-g93c4a162b014 #11 failed
5.0.0-rc2-pmac-ide-00128-g36da5ff0bea2 #12 worked


93c4a162b014d238a287f8264adb25c009c79e61 is the first bad commit
commit 93c4a162b014d238a287f8264adb25c009c79e61
Author: Christophe Leroy <christophe.leroy@c-s.fr>
Date:   Thu Feb 21 10:37:55 2019 +0000

    powerpc/6xx: Store PGDIR physical address in a SPRG

    Use SPRN_SPRG2 to store the current thread PGDIR and
    avoid reading thread_struct.pgdir at every TLB miss.

    Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
    Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

:040000 040000 dcd7171dff5ba5bf895e4399d9d859c91c5a8293
c51e7def7720499289420ace421cf755bf3bf37e M      arch


[    0.000000] printk: debug: ignoring loglevel setting.
[    0.000000] Total memory = 512MB; using 1024kB for hash table (at (ptrval))
[    0.000000] Linux version 5.1.0-pmac-ide (fthain@nippy) (gcc version 4.6.4 (btc)) #1 SMP Sun Jun 23 14:46:26 AEST 2019
[    0.000000] Found a Gatwick mac-io controller, rev: 0, mapped at 0x(ptrval)
[    0.000000] Found a Heathrow mac-io controller, rev: 0, mapped at 0x(ptrval)
[    0.000000] PowerMac motherboard: PowerBook Wallstreet
[    0.000000] PMU driver v2 initialized for PowerBook G3 Series, firmware: 0a
[    0.000000] Using PowerMac machine description
[    0.000000] printk: bootconsole [udbg0] enabled
[    0.000000] CPU maps initialized for 1 thread per core
[    0.000000]  (thread shift is 0)
[    0.000000] -----------------------------------------------------
[    0.000000] Hash_size         = 0x100000
[    0.000000] phys_mem_size     = 0x20000000
[    0.000000] dcache_bsize      = 0x20
[    0.000000] icache_bsize      = 0x20
[    0.000000] cpu_features      = 0x000000000501a008
[    0.000000]   possible        = 0x000000002f7ff14b
[    0.000000]   always          = 0x0000000001000000
[    0.000000] cpu_user_features = 0x8c000001 0x00000000
[    0.000000] mmu_features      = 0x00000001
[    0.000000] Hash              = 0x(ptrval)
[    0.000000] Hash_mask         = 0x3fff
[    0.000000] -----------------------------------------------------
[    0.000000] Found Grackle (MPC106) PCI host bridge at 0x0000000080000000. Firmware bus number: 0->0
[    0.000000] PCI host bridge /pci (primary) ranges:
[    0.000000]   IO 0x00000000fe000000..0x00000000fe7fffff -> 0x0000000000000000
[    0.000000]  MEM 0x00000000fd000000..0x00000000fdffffff -> 0x0000000000000000 
[    0.000000]  MEM 0x0000000080000000..0x00000000fcffffff -> 0x0000000080000000 
[    0.000000] nvram: OF partition at 0x1800
[    0.000000] nvram: XP partition at 0x1300
[    0.000000] nvram: NR partition at 0x1400
[    0.000000] Top of RAM: 0x20000000, Total RAM: 0x20000000
[    0.000000] Memory hole size: 0MB
[    0.000000] Zone ranges:
[    0.000000]   Normal   [mem 0x0000000000000000-0x000000001fffffff]
[    0.000000]   HighMem  empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000000000-0x000000001fffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x000000001fffffff]
[    0.000000] On node 0 totalpages: 131072
[    0.000000]   Normal zone: 1024 pages used for memmap
[    0.000000]   Normal zone: 0 pages reserved
[    0.000000]   Normal zone: 131072 pages, LIFO batch:31
[    0.000000] percpu: Embedded 14 pages/cpu s24972 r8192 d24180 u57344
[    0.000000] pcpu-alloc: s24972 r8192 d24180 u57344 alloc=14*4096
[    0.000000] pcpu-alloc: [0] 0 [0] 1 
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 130048
[    0.000000] Kernel command line: root=/dev/hda11 video=atyfb:vmode:14,cmode:32 ignore_loglevel printk.time console=ttyS0,9600n8 console=tty
[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.000000] Memory: 503332K/524288K available (5468K kernel code, 272K rwdata, 1364K rodata, 264K init, 182K bss, 20956K reserved, 0K cma-reserved, 0K highmem)
[    0.000000] Kernel virtual memory layout:
[    0.000000]   * 0xfffbf000..0xfffff000  : fixmap
[    0.000000]   * 0xff800000..0xffc00000  : highmem PTEs
[    0.000000]   * 0xfeefb000..0xff800000  : early ioremap
[    0.000000]   * 0xe1000000..0xfeefb000  : vmalloc & ioremap
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[    0.000000] NR_IRQS: 512, nr_irqs: 512, preallocated irqs: 16
[    0.000000] irq: Found primary Apple PIC /pci/mac-io for 64 irqs
[    0.000000] irq: Found slave Apple PIC /pci/mac-io for 64 irqs cascade: 27
[    0.000000] irq: System has 128 possible interrupts
[    0.000000] GMT Delta read from XPRAM: -360 minutes, DST: on
[    0.000000] time_init: decrementer frequency = 16.671483 MHz
[    0.000000] time_init: processor frequency   = 264.000000 MHz
[    0.000064] clocksource: timebase: mask: 0xffffffffffffffff max_cycles: 0x3d84ef27e, max_idle_ns: 440795202259 ns
[    0.000100] clocksource: timebase mult[3bfb9003] shift[24] registered
[    0.000195] clockevent: decrementer mult[4449512] shift[32] cpu[0]
[    0.001150] Console: colour dummy device 80x25
[    0.001193] printk: console [tty0] enabled
[    0.001239] printk: bootconsole [udbg0] disabled
[    0.001625] pmac_zilog: serial modem detected
[    4.977278] printk: console [ttyS0] enabled
[    5.027516] pid_max: default: 32768 minimum: 301
[    5.083376] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    5.162419] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    5.248523] *** VALIDATE proc ***
[    5.287109] *** VALIDATE cgroup1 ***
[    5.329716] *** VALIDATE cgroup2 ***
[    5.375172] rcu: Hierarchical SRCU implementation.
[    5.431972] smp: Bringing up secondary CPUs ...
[    5.484998] smp: Brought up 1 node, 1 CPU
[    5.533075] Using standard scheduler topology
[    5.586632] devtmpfs: initialized
[    5.625731] Duplicate name in PowerPC,750, renamed to "l2-cache#1"
[    5.702735] Duplicate name in pci, renamed to "mac-io#1"
[    5.766262] Duplicate name in pci, renamed to "pccard#1"
[    5.830071] random: get_random_u32 called from bucket_table_alloc+0x94/0x1c4 with crng_init=0
[    5.932144] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    6.049531] futex hash table entries: 512 (order: 2, 16384 bytes)
[    6.123224] NET: Registered protocol family 16
[    6.181111] PMU i2c /pci/mac-io/via-pmu
[    6.226470]  channel 1 bus <multibus>
[    6.269024]  channel 2 bus <multibus>
[    6.315157] PCI: Probing PCI hardware
[    6.358004] PCI host bridge to bus 0000:00
[    6.406370] pci_bus 0000:00: root bus resource [io  0x0000-0x7fffff]
[    6.482602] pci_bus 0000:00: root bus resource [mem 0xfd000000-0xfdffffff] (bus address [0x00000000-0x00ffffff])
[    6.604898] pci_bus 0000:00: root bus resource [mem 0x80000000-0xfcffffff]
[    6.687515] pci_bus 0000:00: root bus resource [bus 00-ff]
[    6.753382] pci_bus 0000:00: busn_res: [bus 00-ff] end is updated to ff
[    6.833106] pci 0000:00:00.0: [1057:0002] type 00 class 0x060000
[    6.906583] pci 0000:00:0d.0: [106b:0017] type 00 class 0xff0000
[    6.977163] pci 0000:00:0d.0: reg 0x10: [mem 0xf4000000-0xf407ffff]
[    7.053429] pci 0000:00:10.0: [106b:0017] type 00 class 0xff0000
[    7.124631] pci 0000:00:10.0: reg 0x10: [mem 0xf3000000-0xf307ffff]
[    7.200827] pci 0000:00:11.0: [1002:4c50] type 00 class 0x038000
[    7.272082] pci 0000:00:11.0: reg 0x10: [mem 0x82000000-0x82ffffff]
[    7.347336] pci 0000:00:11.0: reg 0x14: [io  0x0400-0x04ff]
[    7.414246] pci 0000:00:11.0: reg 0x18: [mem 0x82fff000-0x82ffffff]
[    7.489567] pci 0000:00:11.0: reg 0x30: [mem 0xfd000000-0xfd01ffff pref]
[    7.570113] pci 0000:00:11.0: supports D1 D2
[    7.622206] pci 0000:00:13.0: [104c:ac15] type 02 class 0x060700
[    7.693527] pci 0000:00:13.0: reg 0x10: [mem 0x81803000-0x81803fff]
[    7.769592] pci 0000:00:13.1: [104c:ac15] type 02 class 0x060700
[    7.841140] pci 0000:00:13.1: reg 0x10: [mem 0x81802000-0x81802fff]
[    7.918261] pci_bus 0000:01: extended config space not accessible
[    7.990055] pci_bus 0000:01: busn_res: [bus 01-ff] end is updated to 04
[    8.069175] pci_bus 0000:05: extended config space not accessible
[    8.142536] pci_bus 0000:05: busn_res: [bus 05-ff] end is updated to 08
[    8.221620] pci_bus 0000:00: busn_res: [bus 00-ff] end is updated to 08
[    8.301308] PCI: Cannot allocate resource region 2 of device 0000:00:11.0, will remap
[    8.395264] PCI 0000:00 Cannot reserve Legacy IO [io  0x0000-0x0fff]
[    8.471672] pci 0000:00:13.0: BAR 9: assigned [mem 0x84000000-0x87ffffff pref]
[    8.558317] pci 0000:00:13.0: BAR 10: assigned [mem 0x88000000-0x8bffffff]
[    8.640898] pci 0000:00:13.1: BAR 9: assigned [mem 0x8c000000-0x8fffffff pref]
[    8.727690] pci 0000:00:13.1: BAR 10: assigned [mem 0x90000000-0x93ffffff]
[    8.810457] pci 0000:00:11.0: BAR 6: assigned [mem 0xfd000000-0xfd01ffff pref]
[    8.897101] pci 0000:00:11.0: BAR 2: assigned [mem 0xfd020000-0xfd020fff]
[    8.978667] pci 0000:00:13.0: BAR 7: assigned [io  0x1000-0x10ff]
[    9.051864] pci 0000:00:13.0: BAR 8: assigned [io  0x1100-0x11ff]
[    9.125064] pci 0000:00:13.1: BAR 7: assigned [io  0x1200-0x12ff]
[    9.198269] pci 0000:00:13.1: BAR 8: assigned [io  0x1300-0x13ff]
[    9.271483] pci 0000:00:13.0: CardBus bridge to [bus 01-04]
[    9.338395] pci 0000:00:13.0:   bridge window [io  0x1000-0x10ff]
[    9.411598] pci 0000:00:13.0:   bridge window [io  0x1100-0x11ff]
[    9.484802] pci 0000:00:13.0:   bridge window [mem 0x84000000-0x87ffffff pref]
[    9.571597] pci 0000:00:13.0:   bridge window [mem 0x88000000-0x8bffffff]
[    9.653165] pci 0000:00:13.1: CardBus bridge to [bus 05-08]
[    9.720086] pci 0000:00:13.1:   bridge window [io  0x1200-0x12ff]
[    9.793366] pci 0000:00:13.1:   bridge window [io  0x1300-0x13ff]
[    9.866498] pci 0000:00:13.1:   bridge window [mem 0x8c000000-0x8fffffff pref]
[    9.953294] pci 0000:00:13.1:   bridge window [mem 0x90000000-0x93ffffff]
[   10.034865] pci_bus 0000:00: resource 4 [io  0x0000-0x7fffff]
[   10.103874] pci_bus 0000:00: resource 5 [mem 0xfd000000-0xfdffffff]
[   10.179168] pci_bus 0000:00: resource 6 [mem 0x80000000-0xfcffffff]
[   10.254461] pci_bus 0000:01: resource 0 [io  0x1000-0x10ff]
[   10.321391] pci_bus 0000:01: resource 1 [io  0x1100-0x11ff]
[   10.388316] pci_bus 0000:01: resource 2 [mem 0x84000000-0x87ffffff pref]
[   10.468841] pci_bus 0000:01: resource 3 [mem 0x88000000-0x8bffffff]
[   10.544134] pci_bus 0000:05: resource 0 [io  0x1200-0x12ff]
[   10.611058] pci_bus 0000:05: resource 1 [io  0x1300-0x13ff]
[   10.677989] pci_bus 0000:05: resource 2 [mem 0x8c000000-0x8fffffff pref]
[   10.758507] pci_bus 0000:05: resource 3 [mem 0x90000000-0x93ffffff]
[   10.898594] vgaarb: loaded
[   10.931312] SCSI subsystem initialized
[   10.975369] usbcore: registered new interface driver usbfs
[   11.040901] usbcore: registered new interface driver hub
[   11.104378] usbcore: registered new device driver usb
[   11.170053] clocksource: Switched to clocksource timebase
[   11.276916] NET: Registered protocol family 2
[   11.330625] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes)
[   11.420991] TCP established hash table entries: 4096 (order: 2, 16384 bytes)
[   11.505653] TCP bind hash table entries: 4096 (order: 3, 32768 bytes)
[   11.583095] TCP: Hash tables configured (established 4096 bind 4096)
[   11.659434] UDP hash table entries: 256 (order: 1, 8192 bytes)
[   11.729313] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
[   11.805155] NET: Registered protocol family 1
[   11.857851] RPC: Registered named UNIX socket transport module.
[   11.927797] RPC: Registered udp transport module.
[   11.984240] RPC: Registered tcp transport module.
[   12.040709] RPC: Registered tcp NFSv4.1 backchannel transport module.
[   12.118278] PCI: CLS 32 bytes, default 32
[   12.167681] Thermal assist unit 
[   12.167688] using timers, 
[   12.204947] shrink_timer: 200 jiffies
[   12.285360] Initialise system trusted keyrings
[   12.338272] workingset: timestamp_bits=30 max_order=17 bucket_order=0
[   12.415177] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[   24.651142] Key type asymmetric registered
[   24.698347] Asymmetric key parser 'x509' registered
[   24.757356] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
[   24.845895] io scheduler mq-deadline registered
[   24.900069] io scheduler kyber registered
[   24.949721] atyfb 0000:00:11.0: enabling device (0086 -> 0087)
[   25.018669] atyfb: using auxiliary register aperture
[   25.078882] atyfb: 3D RAGE LT PRO (Mach64 LP, PCI) [0x4c50 rev 0xdc]
[   25.154242] atyfb: 4M SGRAM (1:1), 29.498928 MHz XTAL, 230 MHz PLL, 100 Mhz MCLK, 100 MHz XCLK
[   25.311727] Console: switching to colour frame buffer device 128x48
[   25.393746] atyfb: fb0: ATY Mach64 frame buffer device on PCI
[   25.465544] pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)
[   25.553288] Non-volatile memory driver v1.3
[   25.611564] brd: module loaded
[   25.669889] loop: module loaded
[   25.706428] MacIO PCI driver attached to Gatwick chipset
[   25.769945] MacIO PCI driver attached to Heathrow chipset
[   25.842400] swim3 0.00015000:floppy: [fd0] SWIM3 floppy controller in media bay
[   25.932618] 0.00013020:ch-a: ttyS0 at MMIO 0xf3013020 (irq = 16, base_baud = 230400) is a Z85c30 ESCC - Serial port
[   26.058459] 0.00013000:ch-b: ttyS1 at MMIO 0xf3013000 (irq = 17, base_baud = 230400) is a Z85c30 ESCC - Infrared port
[   26.186786] macio: fixed media-bay irq on gatwick
[   26.242712] macio: fixed left floppy irqs
[   26.290523] swim3 1.00015000:floppy: [fd1] Couldn't request interrupt
[   26.367458] swim3: probe of 1.00015000:floppy failed with error -16
[   26.442501] macio: fixed left ide irqs
[   26.487653] macio: fixed SCC irqs on gatwick
[   26.539043] 1.00013020:ch-a: ttyS2 at MMIO 0xf4013020 (irq = 79, base_baud = 230400) is a Z85c30 ESCC - Internal modem
[   26.668762] mediabay0: Registered Heathrow media-bay
[   26.939422] mediabay1: Registered Heathrow media-bay
[   26.997073] mediabay0: Bay contains an ATA device
[   27.210473] PMU Backlight initialized (pmubl)
[   27.262723] Uniform Multi-Platform E-IDE driver
[   28.368835] ide-pmac: Found Apple Heathrow ATA controller (macio), bus ID 0, irq 30
[   28.463347] Probing IDE interface ide0...
[   28.869051] hda: SAMSUNG HM100JC, ATA DISK drive
[   29.453887] random: fast init done
[   29.570254] adb device [2]: 2 0xC3
[   29.618380] adb device [3]: 3 0x1
[   29.663900] adb device [7]: 7 0x1F
[   29.720910] ADB keyboard at 2 has handler 0xC3
[   29.776681] Detected ADB keyboard, type ANSI.
[   29.831871] input: ADB keyboard as /devices/virtual/input/input0
[   29.906693] hda: host max PIO4 wanted PIO255(auto-tune) selected PIO4
[   29.986514] hda: MWDMA2 mode selected
[   30.033814] input: ADB Powerbook buttons as /devices/virtual/input/input1
[   30.118138] ide0 at 0xe1045000-0xe1045070,0xe1045160 on irq 30
[   30.192469] ide-pmac: Found Apple Heathrow ATA controller (macio), bus ID 1 (mediabay), irq 36
[   30.299391] Probing IDE interface ide1...
[   30.412609] ADB mouse (trackpad) at 3 has handler 0x4
[   30.476206] input: ADB mouse as /devices/virtual/input/input2
[   30.889011] hdc: MATSHITADVD-ROM SR-8182, ATAPI CD/DVD-ROM drive
[   31.379281] hdc: host max PIO4 wanted PIO255(auto-tune) selected PIO4
[   31.459300] hdc: MWDMA2 mode selected
[   31.506018] ide1 at 0xe104b000-0xe104b070,0xe104b160 on irq 36
[   31.580403] ide-pmac: Found Apple Heathrow ATA controller (macio), bus ID 4 (mediabay), irq 36
[   31.687369] genirq: Flags mismatch irq 36. 00000000 (ide2) vs. 00000000 (ide1)
[   31.776841] ide2: disabled, unable to get IRQ 36
[   31.834841] ide2: failed to initialize IDE interface
[   31.897376] ide2: disabling port
[   31.938867] ide-pmac: probe of 1.00021000:ata4 failed with error -1
[   32.017021] ide-gd driver 1.18
[   32.056731] hda: max request size: 1024KiB
[   34.309043] hda: 195371568 sectors (100030 MB) w/8192KiB Cache, CHS=16383/255/63
[   34.400766] hda: cache flushes supported
[   34.463701]  hda: [mac] hda1 hda2 hda3 hda4 hda5 hda6 hda7 hda8 hda9 hda10 hda11 hda12 hda13 hda14 hda15
[   34.589982] ide-cd driver 5.00
[   34.633445] ide-cd: hdc: ATAPI 12X DVD-ROM drive, 512kB Cache
[   34.705160] cdrom: Uniform CD-ROM driver Revision: 3.20
[   34.777383] mesh: configured for synchronous 5 MB/s
[   35.058944] mesh: performing initial bus reset...
[   39.168977] scsi host0: MESH
[   41.986409] eth0: BMAC at 00:05:02:07:5a:a6
[   41.986423] 
[   42.065206] aoe: cannot create debugfs directory
[   42.124930] aoe: AoE v85 initialised.
[   42.171200] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[   42.252472] ehci-pci: EHCI PCI platform driver
[   42.308931] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[   42.386046] ohci-pci: OHCI PCI platform driver
[   42.442614] usbcore: registered new interface driver uas
[   42.509535] usbcore: registered new interface driver usb-storage
[   42.587749] mousedev: PS/2 mouse device common for all mice
[   42.661012] rtc-generic rtc-generic: registered as rtc0
[   42.727259] i2c /dev entries driver
[   42.773732] PowerMac i2c bus pmu 2 registered
[   42.830093] PowerMac i2c bus pmu 1 registered
[   42.891093] usbcore: registered new interface driver usbhid
[   42.960484] usbhid: USB HID core driver
[   43.012330] NET: Registered protocol family 17
[   43.068724] drmem: No dynamic reconfiguration memory found
[   43.138959] Loading compiled-in X.509 certificates
[   43.637737] EXT4-fs (hda11): mounting ext3 file system using the ext4 subsystem
[   43.759598] EXT4-fs (hda11): mounted filesystem with ordered data mode. Opts: (null)
[   43.855814] VFS: Mounted root (ext3 filesystem) readonly on device 3:11.
[   43.941974] Freeing unused kernel memory: 264K
[   43.997598] This architecture does not have kernel memory protection.
[   44.077215] Run /sbin/init as init process
[   46.583096] Disabling lock debugging due to kernel taint
[   46.649135] Machine check in kernel mode.
[   46.699359] Caused by (from SRR1=41020): Transfer error ack signal
[   46.776706] Oops: Machine check, sig: 7 [#1]
[   46.830093] BE PAGE_SIZE=4K MMU=Hash SMP NR_CPUS=2 PowerMac
[   46.899131] Modules linked in:
[   46.937774] CPU: 0 PID: 1 Comm: init Tainted: G   M              5.1.0-pmac-ide #1
[   47.030839] NIP:  c0018aa8 LR: c0018fcc CTR: 00000000
[   47.093580] REGS: df437d40 TRAP: 0200   Tainted: G   M               (5.1.0-pmac-ide)
[   47.189853] MSR:  00041020 <ME,IR>  CR: 42428084  XER: 00000000
[   47.263133] DAR: 00000000 DSISR: dec05da0 
[   47.263133] GPR00: 00000bbb df437df0 df435160 000043cb b7ad4000 1ec0cb50 00000001 00020768 
[   47.263133] GPR08: 00000000 00739578 00009032 8021e59e 20424084 00000000 00000000 00000000 
[   47.263133] GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 dec0c000 c0730000 
[   47.263133] GPR24: dec0cb50 1fb21595 dec05da0 df437e18 dec07440 dffe13c0 1fb1e117 df437e18 
[   47.733625] NIP [c0018aa8] flush_hash_pages+0x70/0x164
[   47.797425] LR [c0018fcc] flush_tlb_page+0x54/0x78
[   47.857012] Call Trace:
[   47.888320] [df437df0] [dffe13c0] 0xdffe13c0 (unreliable)
[   47.955245] [df437e00] [c00f9418] ptep_clear_flush+0x3c/0x58
[   48.025313] [df437e10] [c00ecf34] wp_page_copy+0x198/0x530
[   48.093280] [df437e50] [c00ef5e0] do_wp_page+0x188/0x604
[   48.159151] [df437e90] [c00f0838] handle_mm_fault+0x2f8/0x99c
[   48.230265] [df437f00] [c0016528] do_page_fault+0x2a0/0x6b8
[   48.299289] [df437f40] [c0012314] handle_page_fault+0x14/0x40
[   48.370397] --- interrupt: 301 at 0xb7ab6444
[   48.370397]     LR = 0xb7ab634c
[   48.465462] Instruction dump:
[   48.502950] 38c6ffff 4bffffe0 1c633810 5480273e 1c000111 7c630214 546b3870 508b56be 
[   48.598090] 656b8000 3d200074 39299578 8102009c <65080009> 7c004828 2c000000 4082000c 
[   48.695375] ---[ end trace c4d36e2b09ab4631 ]---
[   48.752918] 

-- 

^ permalink raw reply

* Re: [RFC PATCH 03/12] powerpc/prom_init: Add the ESM call to prom_init
From: Alexey Kardashevskiy @ 2019-06-26  7:44 UTC (permalink / raw)
  To: Thiago Jung Bauermann, linuxppc-dev
  Cc: Anshuman Khandual, Mike Anderson, Ram Pai, linux-kernel,
	Claudio Carvalho, Paul Mackerras, Christoph Hellwig
In-Reply-To: <20190521044912.1375-4-bauerman@linux.ibm.com>



On 21/05/2019 14:49, Thiago Jung Bauermann wrote:
> From: Ram Pai <linuxram@us.ibm.com>
> 
> Make the Enter-Secure-Mode (ESM) ultravisor call to switch the VM to secure
> mode. Add "svm=" command line option to turn off switching to secure mode.
> Introduce CONFIG_PPC_SVM to control support for secure guests.
> 
> Signed-off-by: Ram Pai <linuxram@us.ibm.com>
> [ Generate an RTAS os-term hcall when the ESM ucall fails. ]
> Signed-off-by: Michael Anderson <andmike@linux.ibm.com>
> [ Cleaned up the code a bit. ]
> Signed-off-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
> ---
>  .../admin-guide/kernel-parameters.txt         |   5 +
>  arch/powerpc/include/asm/ultravisor-api.h     |   1 +
>  arch/powerpc/kernel/prom_init.c               | 124 ++++++++++++++++++
>  3 files changed, 130 insertions(+)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index c45a19d654f3..7237d86b25c6 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -4501,6 +4501,11 @@
>  			/sys/power/pm_test). Only available when CONFIG_PM_DEBUG
>  			is set. Default value is 5.
>  
> +	svm=		[PPC]
> +			Format: { on | off | y | n | 1 | 0 }
> +			This parameter controls use of the Protected
> +			Execution Facility on pSeries.
> +
>  	swapaccount=[0|1]
>  			[KNL] Enable accounting of swap in memory resource
>  			controller if no parameter or 1 is given or disable
> diff --git a/arch/powerpc/include/asm/ultravisor-api.h b/arch/powerpc/include/asm/ultravisor-api.h
> index 15e6ce77a131..0e8b72081718 100644
> --- a/arch/powerpc/include/asm/ultravisor-api.h
> +++ b/arch/powerpc/include/asm/ultravisor-api.h
> @@ -19,6 +19,7 @@
>  
>  /* opcodes */
>  #define UV_WRITE_PATE			0xF104
> +#define UV_ESM				0xF110
>  #define UV_RETURN			0xF11C
>  
>  #endif /* _ASM_POWERPC_ULTRAVISOR_API_H */
> diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
> index 523bb99d7676..5d8a3efb54f2 100644
> --- a/arch/powerpc/kernel/prom_init.c
> +++ b/arch/powerpc/kernel/prom_init.c
> @@ -44,6 +44,7 @@
>  #include <asm/sections.h>
>  #include <asm/machdep.h>
>  #include <asm/asm-prototypes.h>
> +#include <asm/ultravisor-api.h>
>  
>  #include <linux/linux_logo.h>
>  
> @@ -174,6 +175,10 @@ static unsigned long __prombss prom_tce_alloc_end;
>  static bool __prombss prom_radix_disable;
>  #endif
>  
> +#ifdef CONFIG_PPC_SVM
> +static bool __prombss prom_svm_disable;
> +#endif
> +
>  struct platform_support {
>  	bool hash_mmu;
>  	bool radix_mmu;
> @@ -809,6 +814,17 @@ static void __init early_cmdline_parse(void)
>  	if (prom_radix_disable)
>  		prom_debug("Radix disabled from cmdline\n");
>  #endif /* CONFIG_PPC_PSERIES */
> +
> +#ifdef CONFIG_PPC_SVM
> +	opt = prom_strstr(prom_cmd_line, "svm=");
> +	if (opt) {
> +		bool val;
> +
> +		opt += sizeof("svm=") - 1;
> +		if (!prom_strtobool(opt, &val))
> +			prom_svm_disable = !val;
> +	}
> +#endif /* CONFIG_PPC_SVM */
>  }
>  
>  #ifdef CONFIG_PPC_PSERIES
> @@ -1707,6 +1723,43 @@ static void __init prom_close_stdin(void)
>  	}
>  }
>  
> +#ifdef CONFIG_PPC_SVM
> +static int prom_rtas_os_term_hcall(uint64_t args)


This is just an rtas hcall, nothing special about "os-term".


> +{
> +	register uint64_t arg1 asm("r3") = 0xf000;
> +	register uint64_t arg2 asm("r4") = args;
> +
> +	asm volatile("sc 1\n" : "=r" (arg1) :
> +			"r" (arg1),
> +			"r" (arg2) :);
> +	return arg1;
> +}
> +
> +static struct rtas_args __prombss os_term_args;
> +
> +static void __init prom_rtas_os_term(char *str)
> +{
> +	phandle rtas_node;
> +	__be32 val;
> +	u32 token;
> +
> +	prom_printf("%s: start...\n", __func__);
> +	rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
> +	prom_printf("rtas_node: %x\n", rtas_node);
> +	if (!PHANDLE_VALID(rtas_node))
> +		return;
> +
> +	val = 0;
> +	prom_getprop(rtas_node, "ibm,os-term", &val, sizeof(val));
> +	token = be32_to_cpu(val);
> +	prom_printf("ibm,os-term: %x\n", token);
> +	if (token == 0)
> +		prom_panic("Could not get token for ibm,os-term\n");
> +	os_term_args.token = cpu_to_be32(token);
> +	prom_rtas_os_term_hcall((uint64_t)&os_term_args);
> +}
> +#endif /* CONFIG_PPC_SVM */
> +
>  /*
>   * Allocate room for and instantiate RTAS
>   */
> @@ -3162,6 +3215,74 @@ static void unreloc_toc(void)
>  #endif
>  #endif
>  
> +#ifdef CONFIG_PPC_SVM
> +/*
> + * The ESM blob is a data structure with information needed by the Ultravisor to
> + * validate the integrity of the secure guest.
> + */
> +static void *get_esm_blob(void)
> +{
> +	/*
> +	 * FIXME: We are still finalizing the details on how prom_init will grab
> +	 * the ESM blob. When that is done, this function will be updated.
> +	 */
> +	return (void *)0xdeadbeef;
> +}
> +
> +/*
> + * Perform the Enter Secure Mode ultracall.
> + */
> +static int enter_secure_mode(void *esm_blob, void *retaddr, void *fdt)
> +{
> +	register uint64_t func asm("r0") = UV_ESM;
> +	register uint64_t arg1 asm("r3") = (uint64_t)esm_blob;
> +	register uint64_t arg2 asm("r4") = (uint64_t)retaddr;
> +	register uint64_t arg3 asm("r5") = (uint64_t)fdt;
> +
> +	asm volatile("sc 2\n"
> +		     : "=r"(arg1)
> +		     : "r"(func), "0"(arg1), "r"(arg2), "r"(arg3)
> +		     :);
> +
> +	return (int)arg1;
> +}
> +
> +/*
> + * Call the Ultravisor to transfer us to secure memory if we have an ESM blob.
> + */
> +static void setup_secure_guest(void *fdt)
> +{
> +	void *esm_blob;
> +	int ret;
> +
> +	if (prom_svm_disable) {
> +		prom_printf("Secure mode is OFF\n");
> +		return;
> +	}
> +
> +	esm_blob = get_esm_blob();
> +	if (esm_blob == NULL)
> +		/*
> +		 * Absence of an ESM blob isn't an error, it just means we
> +		 * shouldn't switch to secure mode.
> +		 */
> +		return;
> +
> +	/* Switch to secure mode. */
> +	prom_printf("Switching to secure mode.\n");
> +
> +	ret = enter_secure_mode(esm_blob, NULL, fdt);
> +	if (ret != U_SUCCESS) {
> +		prom_printf("Returned %d from switching to secure mode.\n", ret);
> +		prom_rtas_os_term("Switch to secure mode failed.\n");
> +	}
> +}
> +#else
> +static void setup_secure_guest(void *fdt)
> +{
> +}
> +#endif /* CONFIG_PPC_SVM */
> +
>  /*
>   * We enter here early on, when the Open Firmware prom is still
>   * handling exceptions and the MMU hash table for us.
> @@ -3360,6 +3481,9 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
>  	unreloc_toc();
>  #endif
>  
> +	/* Move to secure memory if we're supposed to be secure guests. */
> +	setup_secure_guest((void *)hdr);
> +
>  	__start(hdr, kbase, 0, 0, 0, 0, 0);
>  
>  	return 0;
> 

-- 
Alexey

^ permalink raw reply

* Re: [PATCH 3/4] powerpc/powernv: remove unused NPU DMA code
From: Christoph Hellwig @ 2019-06-26  7:49 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: linux-kernel, Oliver O'Halloran, Frederic Barrat,
	Paul Mackerras, linuxppc-dev, Christoph Hellwig
In-Reply-To: <7bde96e0-7bc5-d5fe-f151-52c29660633c@ozlabs.ru>

On Wed, Jun 26, 2019 at 10:44:38AM +1000, Alexey Kardashevskiy wrote:
> 
> 
> On 26/06/2019 00:52, Christoph Hellwig wrote:
> > None of these routines were ever used anywhere in the kernel tree
> > since they were added to the kernel.
> 
> 
> So none of my comments has been addressed. Nice.

Which comment?  Last time I asked you complaint "it is still used in
exactly the same way as before" which you later clarified that you
have a hidden out of tree user somewhere, and you only objected to
the word "dead".  That has been fixed and there were no further
comments.

^ permalink raw reply

* Re: [PATCH v2 1/1] cpuidle-powernv : forced wakeup for stop states
From: Abhishek @ 2019-06-26  9:09 UTC (permalink / raw)
  To: Nicholas Piggin, linux-kernel, linux-pm, linuxppc-dev
  Cc: ego, daniel.lezcano, rjw, dja
In-Reply-To: <1560938644.5ukemauqsy.astroid@bobo.none>

Hi Nick,


On 06/19/2019 03:39 PM, Nicholas Piggin wrote:
> Abhishek's on June 19, 2019 7:08 pm:
>> Hi Nick,
>>
>> Thanks for the review. Some replies below.
>>
>> On 06/19/2019 09:53 AM, Nicholas Piggin wrote:
>>> Abhishek Goel's on June 17, 2019 7:56 pm:
>>>> Currently, the cpuidle governors determine what idle state a idling CPU
>>>> should enter into based on heuristics that depend on the idle history on
>>>> that CPU. Given that no predictive heuristic is perfect, there are cases
>>>> where the governor predicts a shallow idle state, hoping that the CPU will
>>>> be busy soon. However, if no new workload is scheduled on that CPU in the
>>>> near future, the CPU may end up in the shallow state.
>>>>
>>>> This is problematic, when the predicted state in the aforementioned
>>>> scenario is a shallow stop state on a tickless system. As we might get
>>>> stuck into shallow states for hours, in absence of ticks or interrupts.
>>>>
>>>> To address this, We forcefully wakeup the cpu by setting the
>>>> decrementer. The decrementer is set to a value that corresponds with the
>>>> residency of the next available state. Thus firing up a timer that will
>>>> forcefully wakeup the cpu. Few such iterations will essentially train the
>>>> governor to select a deeper state for that cpu, as the timer here
>>>> corresponds to the next available cpuidle state residency. Thus, cpu will
>>>> eventually end up in the deepest possible state.
>>>>
>>>> Signed-off-by: Abhishek Goel <huntbag@linux.vnet.ibm.com>
>>>> ---
>>>>
>>>> Auto-promotion
>>>>    v1 : started as auto promotion logic for cpuidle states in generic
>>>> driver
>>>>    v2 : Removed timeout_needed and rebased the code to upstream kernel
>>>> Forced-wakeup
>>>>    v1 : New patch with name of forced wakeup started
>>>>    v2 : Extending the forced wakeup logic for all states. Setting the
>>>> decrementer instead of queuing up a hrtimer to implement the logic.
>>>>
>>>>    drivers/cpuidle/cpuidle-powernv.c | 38 +++++++++++++++++++++++++++++++
>>>>    1 file changed, 38 insertions(+)
>>>>
>>>> diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
>>>> index 84b1ebe212b3..bc9ca18ae7e3 100644
>>>> --- a/drivers/cpuidle/cpuidle-powernv.c
>>>> +++ b/drivers/cpuidle/cpuidle-powernv.c
>>>> @@ -46,6 +46,26 @@ static struct stop_psscr_table stop_psscr_table[CPUIDLE_STATE_MAX] __read_mostly
>>>>    static u64 default_snooze_timeout __read_mostly;
>>>>    static bool snooze_timeout_en __read_mostly;
>>>>    
>>>> +static u64 forced_wakeup_timeout(struct cpuidle_device *dev,
>>>> +				 struct cpuidle_driver *drv,
>>>> +				 int index)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	for (i = index + 1; i < drv->state_count; i++) {
>>>> +		struct cpuidle_state *s = &drv->states[i];
>>>> +		struct cpuidle_state_usage *su = &dev->states_usage[i];
>>>> +
>>>> +		if (s->disabled || su->disable)
>>>> +			continue;
>>>> +
>>>> +		return (s->target_residency + 2 * s->exit_latency) *
>>>> +			tb_ticks_per_usec;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>> It would be nice to not have this kind of loop iteration in the
>>> idle fast path. Can we add a flag or something to the idle state?
>> Currently, we do not have any callback notification or some feedback that
>> notifies the driver everytime some state is enabled/disabled. So we have
>> to parse everytime to get the next enabled state.
> Ahh, that's why you're doing that.
>
>> Are you suggesting to
>> add something like next_enabled_state in cpuidle state structure itself
>> which will be updated when a state is enabled or disabled?
> Hmm, I guess it normally should not iterate over more than one state
> unless some idle states are disabled.
>
> What would have been nice is each state just have its own timeout
> field with ticks already calculated, if that could be updated when
> a state is enabled or disabled. How hard is that to add to the
> cpuidle core?

I have implemented a prototype which does what you have asked for. Added
a  disable_callback which will update timeout whenever a state is 
enabled or
disabled. But It would mean adding some code to cpuidle.h and 
cpuidle/sysfs.c.
If that is not an issue, should I go ahead and post it?
>>>> +
>>>>    static u64 get_snooze_timeout(struct cpuidle_device *dev,
>>>>    			      struct cpuidle_driver *drv,
>>>>    			      int index)
>>>> @@ -144,8 +164,26 @@ static int stop_loop(struct cpuidle_device *dev,
>>>>    		     struct cpuidle_driver *drv,
>>>>    		     int index)
>>>>    {
>>>> +	u64 dec_expiry_tb, dec, timeout_tb, forced_wakeup;
>>>> +
>>>> +	dec = mfspr(SPRN_DEC);
>>>> +	timeout_tb = forced_wakeup_timeout(dev, drv, index);
>>>> +	forced_wakeup = 0;
>>>> +
>>>> +	if (timeout_tb && timeout_tb < dec) {
>>>> +		forced_wakeup = 1;
>>>> +		dec_expiry_tb = mftb() + dec;
>>>> +	}
>>> The compiler probably can't optimise away the SPR manipulations so try
>>> to avoid them if possible.
>> Are you suggesting something like set_dec_before_idle?(in line with
>> what you have suggested to do after idle, reset_dec_after_idle)
> I should have been clear, I meant don't mfspr(SPRN_DEC) until you
> have tested timeout_tb.
>
>>>> +
>>>> +	if (forced_wakeup)
>>>> +		mtspr(SPRN_DEC, timeout_tb);
>>> This should just be put in the above 'if'.
>> Fair point.
>>>> +
>>>>    	power9_idle_type(stop_psscr_table[index].val,
>>>>    			 stop_psscr_table[index].mask);
>>>> +
>>>> +	if (forced_wakeup)
>>>> +		mtspr(SPRN_DEC, dec_expiry_tb - mftb());
>>> This will sometimes go negative and result in another timer interrupt.
>>>
>>> It also breaks irq work (which can be set here by machine check I
>>> believe.
>>>
>>> May need to implement some timer code to do this for you.
>>>
>>> static void reset_dec_after_idle(void)
>>> {
>>> 	u64 now;
>>>           u64 *next_tb;
>>>
>>> 	if (test_irq_work_pending())
>>> 		return;
>>> 	now = mftb;
>>> 	next_tb = this_cpu_ptr(&decrementers_next_tb);
>>>
>>> 	if (now >= *next_tb)
>>> 		return;
>>> 	set_dec(*next_tb - now);
>>> 	if (test_irq_work_pending())
>>> 		set_dec(1);
>>> }
>>>
>>> Something vaguely like that. See timer_interrupt().
>> Ah, Okay. Will go through timer_interrupt().
> Thanks,
> Nick

Thanks,
Abhishek


^ permalink raw reply

* [PATCH] powerpc/pseries: Fix maximum memory value
From: Aravinda Prasad @ 2019-06-26  9:36 UTC (permalink / raw)
  To: mpe, linuxppc-dev; +Cc: aravinda, naveen.n.rao

Calculating the maximum memory based on the number of lmbs
and lmb size does not account for the RMA region. Hence
use drmem_lmb_memory_max(), which already accounts for the
RMA region, to fetch the maximum memory value.

Fixes: 772b039fd9a7: ("powerpc/pseries: Export maximum memory value")
Signed-off-by: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/pseries/lparcfg.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c
index e33e8bc..f425842 100644
--- a/arch/powerpc/platforms/pseries/lparcfg.c
+++ b/arch/powerpc/platforms/pseries/lparcfg.c
@@ -435,7 +435,7 @@ static void maxmem_data(struct seq_file *m)
 {
 	unsigned long maxmem = 0;
 
-	maxmem += drmem_info->n_lmbs * drmem_info->lmb_size;
+	maxmem += drmem_lmb_memory_max();
 	maxmem += hugetlb_total_pages() * PAGE_SIZE;
 
 	seq_printf(m, "MaxMem=%ld\n", maxmem);


^ permalink raw reply related

* Re: [PATCH 7/7] powerpc/kprobes: Allow probing on any ftrace address
From: Naveen N. Rao @ 2019-06-26  9:39 UTC (permalink / raw)
  To: Masami Hiramatsu, Joe Perches
  Cc: linux-kernel, Steven Rostedt, Nicholas Piggin, linuxppc-dev,
	Ingo Molnar
In-Reply-To: <20190621235034.acc00fc3e2b2c7e89caa1fd5@kernel.org>

Masami Hiramatsu wrote:
> On Tue, 18 Jun 2019 20:17:06 +0530
> "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
> 
>> With KPROBES_ON_FTRACE, kprobe is allowed to be inserted on instructions
>> that branch to _mcount (referred to as ftrace location). With
>> -mprofile-kernel, we now include the preceding 'mflr r0' as being part
>> of the ftrace location.
>> 
>> However, by default, probing on an instruction that is not actually the
>> branch to _mcount() is prohibited, as that is considered to not be at an
>> instruction boundary. This is not the case on powerpc, so allow the same
>> by overriding arch_check_ftrace_location()
>> 
>> In addition, we update kprobe_ftrace_handler() to detect this scenarios
>> and to pass the proper nip to the pre and post probe handlers.
>> 
>> Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
>> ---
>>  arch/powerpc/kernel/kprobes-ftrace.c | 30 ++++++++++++++++++++++++++++
>>  1 file changed, 30 insertions(+)
>> 
>> diff --git a/arch/powerpc/kernel/kprobes-ftrace.c b/arch/powerpc/kernel/kprobes-ftrace.c
>> index 972cb28174b2..6a0bd3c16cb6 100644
>> --- a/arch/powerpc/kernel/kprobes-ftrace.c
>> +++ b/arch/powerpc/kernel/kprobes-ftrace.c
>> @@ -12,14 +12,34 @@
>>  #include <linux/preempt.h>
>>  #include <linux/ftrace.h>
>>  
>> +/*
>> + * With -mprofile-kernel, we patch two instructions -- the branch to _mcount
>> + * as well as the preceding 'mflr r0'. Both these instructions are claimed
>> + * by ftrace and we should allow probing on either instruction.
>> + */
>> +int arch_check_ftrace_location(struct kprobe *p)
>> +{
>> +	if (ftrace_location((unsigned long)p->addr))
>> +		p->flags |= KPROBE_FLAG_FTRACE;
>> +	return 0;
>> +}
>> +
>>  /* Ftrace callback handler for kprobes */
>>  void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip,
>>  			   struct ftrace_ops *ops, struct pt_regs *regs)
>>  {
>>  	struct kprobe *p;
>> +	int mflr_kprobe = 0;
>>  	struct kprobe_ctlblk *kcb;
>>  
>>  	p = get_kprobe((kprobe_opcode_t *)nip);
>> +	if (unlikely(!p)) {
> 
> Hmm, is this really unlikely? If we put a kprobe on the second instruction address,
> we will see p == NULL always.
> 
>> +		p = get_kprobe((kprobe_opcode_t *)(nip - MCOUNT_INSN_SIZE));
>> +		if (!p)
> 
> Here will be unlikely, because we can not find kprobe at both of nip and
> nip - MCOUNT_INSN_SIZE.
> 
>> +			return;
>> +		mflr_kprobe = 1;
>> +	}
>> +
>>  	if (unlikely(!p) || kprobe_disabled(p))
> 
> "unlikely(!p)" is not needed here.

...

Joe Perches wrote:
> On Fri, 2019-06-21 at 23:50 +0900, Masami Hiramatsu wrote:
>> On Tue, 18 Jun 2019 20:17:06 +0530
>> "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> wrote:
> 
> trivia:
> 
>> > diff --git a/arch/powerpc/kernel/kprobes-ftrace.c b/arch/powerpc/kernel/kprobes-ftrace.c
> []
>> > @@ -57,6 +82,11 @@ NOKPROBE_SYMBOL(kprobe_ftrace_handler);
>> >  
>> >  int arch_prepare_kprobe_ftrace(struct kprobe *p)
>> >  {
>> > +	if ((unsigned long)p->addr & 0x03) {
>> > +		printk("Attempt to register kprobe at an unaligned address\n");
> 
> Please use the appropriate KERN_<LEVEL> or pr_<level>
> 

All good points. Thanks for the review.


- Naveen



^ permalink raw reply

* [PATCHv2 1/2] PCI: layerscape: Add the bar_fixed_64bit property in EP driver.
From: Xiaowei Bao @ 2019-06-26 11:11 UTC (permalink / raw)
  To: bhelgaas, robh+dt, mark.rutland, shawnguo, leoyang.li, kishon,
	lorenzo.pieralisi, arnd, gregkh, minghuan.Lian, mingkai.hu,
	roy.zang, kstewart, pombredanne, shawn.lin, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linuxppc-dev
  Cc: Xiaowei Bao

The PCIe controller of layerscape just have 4 BARs, BAR0 and BAR1
is 32bit, BAR3 and BAR4 is 64bit, this is determined by hardware,
so set the bar_fixed_64bit with 0x14.

Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
---
v2:
 - Replace value 0x14 with a macro.

 drivers/pci/controller/dwc/pci-layerscape-ep.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index be61d96..227c33b 100644
--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
+++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
@@ -44,6 +44,7 @@ static int ls_pcie_establish_link(struct dw_pcie *pci)
 	.linkup_notifier = false,
 	.msi_capable = true,
 	.msix_capable = false,
+	.bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4),
 };
 
 static const struct pci_epc_features*
-- 
1.7.1


^ permalink raw reply related

* [PATCHv2 2/2] PCI: layerscape: EP and RC drivers are compiled separately
From: Xiaowei Bao @ 2019-06-26 11:11 UTC (permalink / raw)
  To: bhelgaas, robh+dt, mark.rutland, shawnguo, leoyang.li, kishon,
	lorenzo.pieralisi, arnd, gregkh, minghuan.Lian, mingkai.hu,
	roy.zang, kstewart, pombredanne, shawn.lin, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linuxppc-dev
  Cc: Xiaowei Bao
In-Reply-To: <20190626111139.32878-1-xiaowei.bao@nxp.com>

Compile the EP and RC drivers separately with different configuration
options, this looks clearer.

Signed-off-by: Xiaowei Bao <xiaowei.bao@nxp.com>
---
v2:
 - No change.

 drivers/pci/controller/dwc/Kconfig  |   20 ++++++++++++++++++--
 drivers/pci/controller/dwc/Makefile |    3 ++-
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index a6ce1ee..a41ccf5 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -131,13 +131,29 @@ config PCI_KEYSTONE_EP
 	  DesignWare core functions to implement the driver.
 
 config PCI_LAYERSCAPE
-	bool "Freescale Layerscape PCIe controller"
+	bool "Freescale Layerscape PCIe controller - Host mode"
 	depends on OF && (ARM || ARCH_LAYERSCAPE || COMPILE_TEST)
 	depends on PCI_MSI_IRQ_DOMAIN
 	select MFD_SYSCON
 	select PCIE_DW_HOST
 	help
-	  Say Y here if you want PCIe controller support on Layerscape SoCs.
+	  Say Y here if you want to enable PCIe controller support on Layerscape
+	  SoCs to work in Host mode.
+	  This controller can work either as EP or RC. The RCW[HOST_AGT_PEX]
+	  determines which PCIe controller works in EP mode and which PCIe
+	  controller works in RC mode.
+
+config PCI_LAYERSCAPE_EP
+	bool "Freescale Layerscape PCIe controller - Endpoint mode"
+	depends on OF && (ARM || ARCH_LAYERSCAPE || COMPILE_TEST)
+	depends on PCI_ENDPOINT
+	select PCIE_DW_EP
+	help
+	  Say Y here if you want to enable PCIe controller support on Layerscape
+	  SoCs to work in Endpoint mode.
+	  This controller can work either as EP or RC. The RCW[HOST_AGT_PEX]
+	  determines which PCIe controller works in EP mode and which PCIe
+	  controller works in RC mode.
 
 config PCI_HISI
 	depends on OF && (ARM64 || COMPILE_TEST)
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index b085dfd..824fde7 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -8,7 +8,8 @@ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
 obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
-obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o pci-layerscape-ep.o
+obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
+obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o
 obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
 obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
-- 
1.7.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox