* [PATCH 4/8] Read/Write oops nvram partition via pstore
From: Aruna Balakrishnaiah @ 2013-04-10 7:23 UTC (permalink / raw)
To: linuxppc-dev, paulus, linux-kernel, benh; +Cc: jkenisto, mahesh, anton
In-Reply-To: <20130410071835.20150.56489.stgit@aruna-ThinkPad-T420>
This patch exploits pstore infrastructure in power systems.
IBM's system p machines provide persistent storage for LPARs
through NVRAM. NVRAM's lnx,oops-log partition is used to log
oops messages. In case pstore registration fails it will
fall back to kmsg_dump mechanism.
This patch will read/write the oops messages from/to this
partition via pstore.
Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/nvram.c | 145 ++++++++++++++++++++++++++++++++
1 file changed, 145 insertions(+)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 6701b71..82d32a2 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/kmsg_dump.h>
+#include <linux/pstore.h>
#include <linux/ctype.h>
#include <linux/zlib.h>
#include <asm/uaccess.h>
@@ -87,6 +88,25 @@ static struct kmsg_dumper nvram_kmsg_dumper = {
.dump = oops_to_nvram
};
+static int nvram_pstore_open(struct pstore_info *psi);
+
+static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
+ int *count, struct timespec *time, char **buf,
+ struct pstore_info *psi);
+
+static int nvram_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason, u64 *id,
+ unsigned int part, int count, size_t size,
+ struct pstore_info *psi);
+
+static struct pstore_info nvram_pstore_info = {
+ .owner = THIS_MODULE,
+ .name = "nvram",
+ .open = nvram_pstore_open,
+ .read = nvram_pstore_read,
+ .write = nvram_pstore_write,
+};
+
/* See clobbering_unread_rtas_event() */
#define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */
static unsigned long last_unread_rtas_event; /* timestamp */
@@ -121,6 +141,13 @@ static char *big_oops_buf, *oops_buf;
static char *oops_data;
static size_t oops_data_sz;
+#ifdef CONFIG_PSTORE
+static enum pstore_type_id nvram_type_ids[] = {
+ PSTORE_TYPE_DMESG,
+ -1
+};
+static int read_type;
+#endif
/* Compression parameters */
#define COMPR_LEVEL 6
#define WINDOW_BITS 12
@@ -455,6 +482,23 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
oops_data = oops_buf + sizeof(struct oops_log_info);
oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
+ nvram_pstore_info.buf = oops_data;
+ nvram_pstore_info.bufsize = oops_data_sz;
+
+ rc = pstore_register(&nvram_pstore_info);
+
+ if (rc != 0) {
+ pr_err("nvram: pstore_register() failed, defaults to "
+ "kmsg_dump; returned %d\n", rc);
+ goto kmsg_dump;
+ } else {
+ /*TODO: Support compression when pstore is configured */
+ pr_info("nvram: Compression of oops text supported only when "
+ "pstore is not configured");
+ return;
+ }
+
+kmsg_dump:
/*
* Figure compression (preceded by elimination of each line's <n>
* severity prefix) will reduce the oops/panic report to at most
@@ -663,3 +707,104 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
spin_unlock_irqrestore(&lock, flags);
}
+
+#ifdef CONFIG_PSTORE
+static int nvram_pstore_open(struct pstore_info *psi)
+{
+ read_type = -1;
+ return 0;
+}
+
+/*
+ * Called by pstore_dump() when an oops or panic report is logged to the printk
+ * buffer. @size bytes have been written to oops_buf, starting after the
+ * oops_log_info header.
+ */
+static int nvram_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason,
+ u64 *id, unsigned int part, int count,
+ size_t size, struct pstore_info *psi)
+{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf;
+
+ /* part 1 has the recent messages from printk buffer */
+ if (part > 1 || clobbering_unread_rtas_event())
+ return -1;
+
+ BUG_ON(type != PSTORE_TYPE_DMESG);
+ BUG_ON(sizeof(*oops_hdr) + size > oops_log_partition.size);
+ oops_hdr->version = OOPS_HDR_VERSION;
+ oops_hdr->report_length = (u16) size;
+ oops_hdr->timestamp = get_seconds();
+ (void) nvram_write_os_partition(&oops_log_partition, oops_buf,
+ (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC,
+ count);
+ *id = part;
+
+ return 0;
+}
+
+/*
+ * Reads the oops/panic report.
+ * Returns the length of the data we read from each partition.
+ * Returns 0 if we've been called before.
+ */
+static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
+ int *count, struct timespec *time, char **buf,
+ struct pstore_info *psi)
+{
+ struct oops_log_info *oops_hdr;
+ unsigned int err_type, id_no;
+ struct nvram_os_partition *part = NULL;
+ char *buff = NULL;
+
+ read_type++;
+
+ switch (nvram_type_ids[read_type]) {
+ case PSTORE_TYPE_DMESG:
+ part = &oops_log_partition;
+ *type = PSTORE_TYPE_DMESG;
+ break;
+ default:
+ return 0;
+ }
+
+ buff = kmalloc(part->size, GFP_KERNEL);
+
+ if (!buff)
+ return -ENOMEM;
+
+ if (nvram_read_partition(part, buff, part->size, &err_type, &id_no)) {
+ kfree(buff);
+ return 0;
+ }
+
+ *count = 0;
+ *id = id_no;
+ oops_hdr = (struct oops_log_info *)buff;
+ *buf = buff + sizeof(*oops_hdr);
+ time->tv_sec = oops_hdr->timestamp;
+ time->tv_nsec = 0;
+ return oops_hdr->report_length;
+}
+#else
+static int nvram_pstore_open(struct pstore_info *psi)
+{
+ return 0;
+}
+
+static int nvram_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason, u64 *id,
+ unsigned int part, int count, size_t size,
+ struct pstore_info *psi)
+{
+ return 0;
+}
+
+static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
+ int *count, struct timespec *time, char **buf,
+ struct pstore_info *psi)
+{
+ return 0;
+}
+#endif
^ permalink raw reply related
* [PATCH 3/8] Introduce generic read function to read nvram-partitions
From: Aruna Balakrishnaiah @ 2013-04-10 7:21 UTC (permalink / raw)
To: linuxppc-dev, paulus, linux-kernel, benh; +Cc: jkenisto, mahesh, anton
In-Reply-To: <20130410071835.20150.56489.stgit@aruna-ThinkPad-T420>
Introduce generic read function to read nvram partitions other than rtas.
nvram_read_error_log will be retained which is used to read rtas partition
from rtasd. nvram_read_partition is the generic read function to read from
any nvram partition.
Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
Reviewed-by: Jim Keniston <jkenisto@us.ibm.com>
---
arch/powerpc/platforms/pseries/nvram.c | 34 +++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 742735a..6701b71 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -293,34 +293,37 @@ int nvram_write_error_log(char * buff, int length,
return rc;
}
-/* nvram_read_error_log
+/* nvram_read_partition
*
- * Reads nvram for error log for at most 'length'
+ * Reads nvram partition for at most 'length'
*/
-int nvram_read_error_log(char * buff, int length,
- unsigned int * err_type, unsigned int * error_log_cnt)
+int nvram_read_partition(struct nvram_os_partition *part, char *buff,
+ int length, unsigned int *err_type,
+ unsigned int *error_log_cnt)
{
int rc;
loff_t tmp_index;
struct err_log_info info;
- if (rtas_log_partition.index == -1)
+ if (part->index == -1)
return -1;
- if (length > rtas_log_partition.size)
- length = rtas_log_partition.size;
+ if (length > part->size)
+ length = part->size;
- tmp_index = rtas_log_partition.index;
+ tmp_index = part->index;
rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
if (rc <= 0) {
- printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
+ printk(KERN_ERR "nvram_read_partition: "
+ "Failed nvram_read (%d)\n", rc);
return rc;
}
rc = ppc_md.nvram_read(buff, length, &tmp_index);
if (rc <= 0) {
- printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
+ printk(KERN_ERR "nvram_read_partition: "
+ "Failed nvram_read (%d)\n", rc);
return rc;
}
@@ -330,6 +333,17 @@ int nvram_read_error_log(char * buff, int length,
return 0;
}
+/* nvram_read_error_log
+ *
+ * Reads nvram for error log for at most 'length'
+ */
+int nvram_read_error_log(char *buff, int length,
+ unsigned int *err_type, unsigned int *error_log_cnt)
+{
+ return nvram_read_partition(&rtas_log_partition, buff, length,
+ err_type, error_log_cnt);
+}
+
/* This doesn't actually zero anything, but it sets the event_logged
* word to tell that this event is safely in syslog.
*/
^ permalink raw reply related
* [PATCH 2/8] Add version and timestamp to oops header
From: Aruna Balakrishnaiah @ 2013-04-10 7:21 UTC (permalink / raw)
To: linuxppc-dev, paulus, linux-kernel, benh; +Cc: jkenisto, mahesh, anton
In-Reply-To: <20130410071835.20150.56489.stgit@aruna-ThinkPad-T420>
Introduce version and timestamp information in the oops header.
oops_log_info (oops header) holds version (to distinguish between old
and new format oops header), length of the oops text
(compressed or uncompressed) and timestamp.
Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
Reviewed-by: Jim Keniston <jkenisto@us.ibm.com>
---
arch/powerpc/platforms/pseries/nvram.c | 57 +++++++++++++++++++++-----------
1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index e54a8b7..742735a 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -29,6 +29,13 @@
/* Max bytes to read/write in one go */
#define NVRW_CNT 0x20
+/*
+ * Set oops header version to distingush between old and new format header.
+ * lnx,oops-log partition max size is 4000, header version > 4000 will
+ * help in identifying new header.
+ */
+#define OOPS_HDR_VERSION 5000
+
static unsigned int nvram_size;
static int nvram_fetch, nvram_store;
static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
@@ -67,6 +74,12 @@ static const char *pseries_nvram_os_partitions[] = {
NULL
};
+struct oops_log_info {
+ u16 version;
+ u16 report_length;
+ u64 timestamp;
+} __attribute__((packed));
+
static void oops_to_nvram(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason);
@@ -83,28 +96,28 @@ static unsigned long last_unread_rtas_event; /* timestamp */
* big_oops_buf[] holds the uncompressed text we're capturing.
*
- * oops_buf[] holds the compressed text, preceded by a prefix.
- * The prefix is just a u16 holding the length of the compressed* text.
- * (*Or uncompressed, if compression fails.) oops_buf[] gets written
- * to NVRAM.
+ * oops_buf[] holds the compressed text, preceded by a oops header.
+ * oops header has u16 holding the version of oops header (to differentiate
+ * between old and new format header) followed by u16 holding the length of
+ * the compressed* text (*Or uncompressed, if compression fails.) and u64
+ * holding the timestamp. oops_buf[] gets written to NVRAM.
*
- * oops_len points to the prefix. oops_data points to the compressed text.
+ * oops_log_info points to the header. oops_data points to the compressed text.
*
* +- oops_buf
- * | +- oops_data
- * v v
- * +------------+-----------------------------------------------+
- * | length | text |
- * | (2 bytes) | (oops_data_sz bytes) |
- * +------------+-----------------------------------------------+
+ * | +- oops_data
+ * v v
+ * +-----------+-----------+-----------+------------------------+
+ * | version | length | timestamp | text |
+ * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) |
+ * +-----------+-----------+-----------+------------------------+
* ^
- * +- oops_len
+ * +- oops_log_info
*
* We preallocate these buffers during init to avoid kmalloc during oops/panic.
*/
static size_t big_oops_buf_sz;
static char *big_oops_buf, *oops_buf;
-static u16 *oops_len;
static char *oops_data;
static size_t oops_data_sz;
@@ -425,9 +438,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
oops_log_partition.name);
return;
}
- oops_len = (u16*) oops_buf;
- oops_data = oops_buf + sizeof(u16);
- oops_data_sz = oops_log_partition.size - sizeof(u16);
+ oops_data = oops_buf + sizeof(struct oops_log_info);
+ oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
/*
* Figure compression (preceded by elimination of each line's <n>
@@ -555,6 +567,7 @@ error:
/* Compress the text from big_oops_buf into oops_buf. */
static int zip_oops(size_t text_len)
{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len,
oops_data_sz);
if (zipped_len < 0) {
@@ -562,7 +575,9 @@ static int zip_oops(size_t text_len)
pr_err("nvram: logging uncompressed oops/panic report\n");
return -1;
}
- *oops_len = (u16) zipped_len;
+ oops_hdr->version = OOPS_HDR_VERSION;
+ oops_hdr->report_length = (u16) zipped_len;
+ oops_hdr->timestamp = get_seconds();
return 0;
}
@@ -576,6 +591,7 @@ static int zip_oops(size_t text_len)
static void oops_to_nvram(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason)
{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
static unsigned int oops_count = 0;
static bool panicking = false;
static DEFINE_SPINLOCK(lock);
@@ -622,11 +638,14 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
kmsg_dump_get_buffer(dumper, false,
oops_data, oops_data_sz, &text_len);
err_type = ERR_TYPE_KERNEL_PANIC;
- *oops_len = (u16) text_len;
+ oops_hdr->version = OOPS_HDR_VERSION;
+ oops_hdr->report_length = (u16) text_len;
+ oops_hdr->timestamp = get_seconds();
}
(void) nvram_write_os_partition(&oops_log_partition, oops_buf,
- (int) (sizeof(*oops_len) + *oops_len), err_type, ++oops_count);
+ (int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type,
+ ++oops_count);
spin_unlock_irqrestore(&lock, flags);
}
^ permalink raw reply related
* Re: [PATCH -V5 19/25] powerpc/THP: Differentiate THP PMD entries from HUGETLB PMD entries
From: Michael Ellerman @ 2013-04-10 7:21 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1365055083-31956-20-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On Thu, Apr 04, 2013 at 11:27:57AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>
> HUGETLB clear the top bit of PMD entries and use that to indicate
> a HUGETLB page directory. Since we store pfns in PMDs for THP,
> we would have the top bit cleared by default. Add the top bit mask
> for THP PMD entries and clear that when we are looking for pmd_pfn.
>
> @@ -44,6 +44,14 @@ struct mm_struct;
> #define PMD_HUGE_RPN_SHIFT PTE_RPN_SHIFT
> #define HUGE_PAGE_SIZE (ASM_CONST(1) << 24)
> #define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1))
> +/*
> + * HugeTLB looks at the top bit of the Linux page table entries to
> + * decide whether it is a huge page directory or not. Mark HUGE
> + * PMD to differentiate
> + */
> +#define PMD_HUGE_NOT_HUGETLB (ASM_CONST(1) << 63)
> +#define PMD_ISHUGE (_PMD_ISHUGE | PMD_HUGE_NOT_HUGETLB)
> +#define PMD_HUGE_PROTBITS (0xfff | PMD_HUGE_NOT_HUGETLB)
>
> #ifndef __ASSEMBLY__
> extern void hpte_need_hugepage_flush(struct mm_struct *mm, unsigned long addr,
> @@ -84,7 +93,8 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
> /*
> * Only called for hugepage pmd
> */
> - return pmd_val(pmd) >> PMD_HUGE_RPN_SHIFT;
> + unsigned long val = pmd_val(pmd) & ~PMD_HUGE_PROTBITS;
> + return val >> PMD_HUGE_RPN_SHIFT;
> }
This is breaking the 32-bit build for me (pmac32_defconfig):
arch/powerpc/include/asm/pgtable.h:123:2: error: left shift count >= width of type [-Werror]
cheers
^ permalink raw reply
* [PATCH 1/8] Remove syslog prefix in uncompressed oops text
From: Aruna Balakrishnaiah @ 2013-04-10 7:21 UTC (permalink / raw)
To: linuxppc-dev, paulus, linux-kernel, benh; +Cc: jkenisto, mahesh, anton
In-Reply-To: <20130410071835.20150.56489.stgit@aruna-ThinkPad-T420>
Removal of syslog prefix in the uncompressed oops text will
help in capturing more oops data.
Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
Reviewed-by: Jim Keniston <jkenisto@us.ibm.com>
---
arch/powerpc/platforms/pseries/nvram.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 8733a86..e54a8b7 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -619,7 +619,7 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
}
if (rc != 0) {
kmsg_dump_rewind(dumper);
- kmsg_dump_get_buffer(dumper, true,
+ kmsg_dump_get_buffer(dumper, false,
oops_data, oops_data_sz, &text_len);
err_type = ERR_TYPE_KERNEL_PANIC;
*oops_len = (u16) text_len;
^ permalink raw reply related
* [PATCH 0/8] Nvram-to-pstore
From: Aruna Balakrishnaiah @ 2013-04-10 7:20 UTC (permalink / raw)
To: linuxppc-dev, paulus, linux-kernel, benh; +Cc: jkenisto, mahesh, anton
Currently the kernel provides the contents of p-series NVRAM only as a
simple stream of bytes via /dev/nvram, which must be interpreted in user
space by the nvram command in the powerpc-utils package. This patch set
exploits the pstore subsystem to expose each partition in NVRAM as a
separate file in /dev/pstore. For instance Oops messages will stored in a
file named [dmesg-nvram-2].
---
Aruna Balakrishnaiah (8):
Remove syslog prefix in uncompressed oops text
Add version and timestamp to oops header
Introduce generic read function to read nvram-partitions
Read/Write oops nvram partition via pstore
Read rtas partition via pstore
Distinguish between a os-partition and non-os partition
Read of-config partition via pstore
Read common partition via pstore
arch/powerpc/platforms/pseries/nvram.c | 329 ++++++++++++++++++++++++++++----
fs/pstore/inode.c | 9 +
include/linux/pstore.h | 4
3 files changed, 304 insertions(+), 38 deletions(-)
--
^ permalink raw reply
* Re: [PATCH -V5 08/25] powerpc: Decode the pte-lp-encoding bits correctly.
From: David Gibson @ 2013-04-10 7:19 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1365055083-31956-9-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 31290 bytes --]
On Thu, Apr 04, 2013 at 11:27:46AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>
> We look at both the segment base page size and actual page size and store
> the pte-lp-encodings in an array per base page size.
>
> We also update all relevant functions to take actual page size argument
> so that we can use the correct PTE LP encoding in HPTE. This should also
> get the basic Multiple Page Size per Segment (MPSS) support. This is needed
> to enable THP on ppc64.
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/machdep.h | 3 +-
> arch/powerpc/include/asm/mmu-hash64.h | 33 ++++----
> arch/powerpc/kvm/book3s_hv.c | 2 +-
> arch/powerpc/mm/hash_low_64.S | 18 ++--
> arch/powerpc/mm/hash_native_64.c | 138 ++++++++++++++++++++++---------
> arch/powerpc/mm/hash_utils_64.c | 121 +++++++++++++++++----------
> arch/powerpc/mm/hugetlbpage-hash64.c | 4 +-
> arch/powerpc/platforms/cell/beat_htab.c | 16 ++--
> arch/powerpc/platforms/ps3/htab.c | 6 +-
> arch/powerpc/platforms/pseries/lpar.c | 6 +-
> 10 files changed, 230 insertions(+), 117 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
> index 19d9d96..6cee6e0 100644
> --- a/arch/powerpc/include/asm/machdep.h
> +++ b/arch/powerpc/include/asm/machdep.h
> @@ -50,7 +50,8 @@ struct machdep_calls {
> unsigned long prpn,
> unsigned long rflags,
> unsigned long vflags,
> - int psize, int ssize);
> + int psize, int apsize,
> + int ssize);
> long (*hpte_remove)(unsigned long hpte_group);
> void (*hpte_removebolted)(unsigned long ea,
> int psize, int ssize);
> diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
> index 300ac3c..e42f4a3 100644
> --- a/arch/powerpc/include/asm/mmu-hash64.h
> +++ b/arch/powerpc/include/asm/mmu-hash64.h
> @@ -154,7 +154,7 @@ extern unsigned long htab_hash_mask;
> struct mmu_psize_def
> {
> unsigned int shift; /* number of bits */
> - unsigned int penc; /* HPTE encoding */
> + int penc[MMU_PAGE_COUNT]; /* HPTE encoding */
> unsigned int tlbiel; /* tlbiel supported for that page size */
> unsigned long avpnm; /* bits to mask out in AVPN in the HPTE */
> unsigned long sllp; /* SLB L||LP (exact mask to use in slbmte) */
> @@ -181,6 +181,13 @@ struct mmu_psize_def
> */
> #define VPN_SHIFT 12
>
> +/*
> + * HPTE Large Page (LP) details
> + */
> +#define LP_SHIFT 12
> +#define LP_BITS 8
> +#define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT)
> +
> #ifndef __ASSEMBLY__
>
> static inline int segment_shift(int ssize)
> @@ -237,14 +244,14 @@ static inline unsigned long hpte_encode_avpn(unsigned long vpn, int psize,
>
> /*
> * This function sets the AVPN and L fields of the HPTE appropriately
> - * for the page size
> + * using the base page size and actual page size.
> */
> -static inline unsigned long hpte_encode_v(unsigned long vpn,
> - int psize, int ssize)
> +static inline unsigned long hpte_encode_v(unsigned long vpn, int base_psize,
> + int actual_psize, int ssize)
> {
> unsigned long v;
> - v = hpte_encode_avpn(vpn, psize, ssize);
> - if (psize != MMU_PAGE_4K)
> + v = hpte_encode_avpn(vpn, base_psize, ssize);
> + if (actual_psize != MMU_PAGE_4K)
> v |= HPTE_V_LARGE;
> return v;
> }
> @@ -254,19 +261,17 @@ static inline unsigned long hpte_encode_v(unsigned long vpn,
> * for the page size. We assume the pa is already "clean" that is properly
> * aligned for the requested page size
> */
> -static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
> +static inline unsigned long hpte_encode_r(unsigned long pa, int base_psize,
> + int actual_psize)
> {
> - unsigned long r;
> -
> /* A 4K page needs no special encoding */
> - if (psize == MMU_PAGE_4K)
> + if (actual_psize == MMU_PAGE_4K)
> return pa & HPTE_R_RPN;
> else {
> - unsigned int penc = mmu_psize_defs[psize].penc;
> - unsigned int shift = mmu_psize_defs[psize].shift;
> - return (pa & ~((1ul << shift) - 1)) | (penc << 12);
> + unsigned int penc = mmu_psize_defs[base_psize].penc[actual_psize];
> + unsigned int shift = mmu_psize_defs[actual_psize].shift;
> + return (pa & ~((1ul << shift) - 1)) | (penc << LP_SHIFT);
> }
> - return r;
> }
>
> /*
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 71d0c90..48f6d99 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -1515,7 +1515,7 @@ static void kvmppc_add_seg_page_size(struct kvm_ppc_one_seg_page_size **sps,
> (*sps)->page_shift = def->shift;
> (*sps)->slb_enc = def->sllp;
> (*sps)->enc[0].page_shift = def->shift;
> - (*sps)->enc[0].pte_enc = def->penc;
> + (*sps)->enc[0].pte_enc = def->penc[linux_psize];
> (*sps)++;
> }
>
> diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
> index abdd5e2..0e980ac 100644
> --- a/arch/powerpc/mm/hash_low_64.S
> +++ b/arch/powerpc/mm/hash_low_64.S
> @@ -196,7 +196,8 @@ htab_insert_pte:
> mr r4,r29 /* Retrieve vpn */
> li r7,0 /* !bolted, !secondary */
> li r8,MMU_PAGE_4K /* page size */
> - ld r9,STK_PARAM(R9)(r1) /* segment size */
> + li r9,MMU_PAGE_4K /* actual page size */
> + ld r10,STK_PARAM(R9)(r1) /* segment size */
> _GLOBAL(htab_call_hpte_insert1)
> bl . /* Patched by htab_finish_init() */
> cmpdi 0,r3,0
> @@ -219,7 +220,8 @@ _GLOBAL(htab_call_hpte_insert1)
> mr r4,r29 /* Retrieve vpn */
> li r7,HPTE_V_SECONDARY /* !bolted, secondary */
> li r8,MMU_PAGE_4K /* page size */
> - ld r9,STK_PARAM(R9)(r1) /* segment size */
> + li r9,MMU_PAGE_4K /* actual page size */
> + ld r10,STK_PARAM(R9)(r1) /* segment size */
> _GLOBAL(htab_call_hpte_insert2)
> bl . /* Patched by htab_finish_init() */
> cmpdi 0,r3,0
> @@ -515,7 +517,8 @@ htab_special_pfn:
> mr r4,r29 /* Retrieve vpn */
> li r7,0 /* !bolted, !secondary */
> li r8,MMU_PAGE_4K /* page size */
> - ld r9,STK_PARAM(R9)(r1) /* segment size */
> + li r9,MMU_PAGE_4K /* actual page size */
> + ld r10,STK_PARAM(R9)(r1) /* segment size */
> _GLOBAL(htab_call_hpte_insert1)
> bl . /* patched by htab_finish_init() */
> cmpdi 0,r3,0
> @@ -542,7 +545,8 @@ _GLOBAL(htab_call_hpte_insert1)
> mr r4,r29 /* Retrieve vpn */
> li r7,HPTE_V_SECONDARY /* !bolted, secondary */
> li r8,MMU_PAGE_4K /* page size */
> - ld r9,STK_PARAM(R9)(r1) /* segment size */
> + li r9,MMU_PAGE_4K /* actual page size */
> + ld r10,STK_PARAM(R9)(r1) /* segment size */
> _GLOBAL(htab_call_hpte_insert2)
> bl . /* patched by htab_finish_init() */
> cmpdi 0,r3,0
> @@ -840,7 +844,8 @@ ht64_insert_pte:
> mr r4,r29 /* Retrieve vpn */
> li r7,0 /* !bolted, !secondary */
> li r8,MMU_PAGE_64K
> - ld r9,STK_PARAM(R9)(r1) /* segment size */
> + li r9,MMU_PAGE_64K /* actual page size */
> + ld r10,STK_PARAM(R9)(r1) /* segment size */
> _GLOBAL(ht64_call_hpte_insert1)
> bl . /* patched by htab_finish_init() */
> cmpdi 0,r3,0
> @@ -863,7 +868,8 @@ _GLOBAL(ht64_call_hpte_insert1)
> mr r4,r29 /* Retrieve vpn */
> li r7,HPTE_V_SECONDARY /* !bolted, secondary */
> li r8,MMU_PAGE_64K
> - ld r9,STK_PARAM(R9)(r1) /* segment size */
> + li r9,MMU_PAGE_64K /* actual page size */
> + ld r10,STK_PARAM(R9)(r1) /* segment size */
> _GLOBAL(ht64_call_hpte_insert2)
> bl . /* patched by htab_finish_init() */
> cmpdi 0,r3,0
> diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
> index 9d8983a..aa0499b 100644
> --- a/arch/powerpc/mm/hash_native_64.c
> +++ b/arch/powerpc/mm/hash_native_64.c
> @@ -39,7 +39,7 @@
>
> DEFINE_RAW_SPINLOCK(native_tlbie_lock);
>
> -static inline void __tlbie(unsigned long vpn, int psize, int ssize)
> +static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
> {
> unsigned long va;
> unsigned int penc;
> @@ -68,7 +68,7 @@ static inline void __tlbie(unsigned long vpn, int psize, int ssize)
> break;
> default:
> /* We need 14 to 14 + i bits of va */
> - penc = mmu_psize_defs[psize].penc;
> + penc = mmu_psize_defs[psize].penc[apsize];
> va &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
> va |= penc << 12;
> va |= ssize << 8;
> @@ -80,7 +80,7 @@ static inline void __tlbie(unsigned long vpn, int psize, int ssize)
> }
> }
>
> -static inline void __tlbiel(unsigned long vpn, int psize, int ssize)
> +static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
> {
> unsigned long va;
> unsigned int penc;
> @@ -102,7 +102,7 @@ static inline void __tlbiel(unsigned long vpn, int psize, int ssize)
> break;
> default:
> /* We need 14 to 14 + i bits of va */
> - penc = mmu_psize_defs[psize].penc;
> + penc = mmu_psize_defs[psize].penc[apsize];
> va &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
> va |= penc << 12;
> va |= ssize << 8;
> @@ -114,7 +114,8 @@ static inline void __tlbiel(unsigned long vpn, int psize, int ssize)
>
> }
>
> -static inline void tlbie(unsigned long vpn, int psize, int ssize, int local)
> +static inline void tlbie(unsigned long vpn, int psize, int apsize,
> + int ssize, int local)
> {
> unsigned int use_local = local && mmu_has_feature(MMU_FTR_TLBIEL);
> int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
> @@ -125,10 +126,10 @@ static inline void tlbie(unsigned long vpn, int psize, int ssize, int local)
> raw_spin_lock(&native_tlbie_lock);
> asm volatile("ptesync": : :"memory");
> if (use_local) {
> - __tlbiel(vpn, psize, ssize);
> + __tlbiel(vpn, psize, apsize, ssize);
> asm volatile("ptesync": : :"memory");
> } else {
> - __tlbie(vpn, psize, ssize);
> + __tlbie(vpn, psize, apsize, ssize);
> asm volatile("eieio; tlbsync; ptesync": : :"memory");
> }
> if (lock_tlbie && !use_local)
> @@ -156,7 +157,7 @@ static inline void native_unlock_hpte(struct hash_pte *hptep)
>
> static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn,
> unsigned long pa, unsigned long rflags,
> - unsigned long vflags, int psize, int ssize)
> + unsigned long vflags, int psize, int apsize, int ssize)
> {
> struct hash_pte *hptep = htab_address + hpte_group;
> unsigned long hpte_v, hpte_r;
> @@ -183,8 +184,8 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn,
> if (i == HPTES_PER_GROUP)
> return -1;
>
> - hpte_v = hpte_encode_v(vpn, psize, ssize) | vflags | HPTE_V_VALID;
> - hpte_r = hpte_encode_r(pa, psize) | rflags;
> + hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
> + hpte_r = hpte_encode_r(pa, psize, apsize) | rflags;
>
> if (!(vflags & HPTE_V_BOLTED)) {
> DBG_LOW(" i=%x hpte_v=%016lx, hpte_r=%016lx\n",
> @@ -244,6 +245,48 @@ static long native_hpte_remove(unsigned long hpte_group)
> return i;
> }
>
> +static inline int hpte_actual_psize(struct hash_pte *hptep, int psize)
> +{
> + int i, shift;
> + unsigned int mask;
> + /* Look at the 8 bit LP value */
> + unsigned int lp = (hptep->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
> +
> + if (!(hptep->v & HPTE_V_VALID))
> + return -1;
Folding the validity check into the size check seems confusing to me.
> + /* First check if it is large page */
> + if (!(hptep->v & HPTE_V_LARGE))
> + return MMU_PAGE_4K;
> +
> + /* start from 1 ignoring MMU_PAGE_4K */
> + for (i = 1; i < MMU_PAGE_COUNT; i++) {
> + /* valid entries have a shift value */
> + if (!mmu_psize_defs[i].shift)
> + continue;
Isn't this check redundant with the one below?
> + /* invalid penc */
> + if (mmu_psize_defs[psize].penc[i] == -1)
> + continue;
> + /*
> + * encoding bits per actual page size
> + * PTE LP actual page size
> + * rrrr rrrz >=8KB
> + * rrrr rrzz >=16KB
> + * rrrr rzzz >=32KB
> + * rrrr zzzz >=64KB
> + * .......
> + */
> + shift = mmu_psize_defs[i].shift - LP_SHIFT;
> + if (shift > LP_BITS)
> + shift = LP_BITS;
> + mask = (1 << shift) - 1;
> + if ((lp & mask) == mmu_psize_defs[psize].penc[i])
> + return i;
> + }
Shouldn't we have a BUG() or something here. If we get here we've
somehow created a PTE with LP bits we can't interpret, yes?
> + return -1;
> +}
> +
> static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
> unsigned long vpn, int psize, int ssize,
> int local)
> @@ -251,6 +294,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
> struct hash_pte *hptep = htab_address + slot;
> unsigned long hpte_v, want_v;
> int ret = 0;
> + int actual_psize;
>
> want_v = hpte_encode_avpn(vpn, psize, ssize);
>
> @@ -260,9 +304,13 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
> native_lock_hpte(hptep);
>
> hpte_v = hptep->v;
> -
> + actual_psize = hpte_actual_psize(hptep, psize);
> + if (actual_psize < 0) {
> + native_unlock_hpte(hptep);
> + return -1;
> + }
Wouldn't it make more sense to only do the psize lookup once you've
found a matching hpte?
> /* Even if we miss, we need to invalidate the TLB */
> - if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
> + if (!HPTE_V_COMPARE(hpte_v, want_v)) {
> DBG_LOW(" -> miss\n");
> ret = -1;
> } else {
> @@ -274,7 +322,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
> native_unlock_hpte(hptep);
>
> /* Ensure it is out of the tlb too. */
> - tlbie(vpn, psize, ssize, local);
> + tlbie(vpn, psize, actual_psize, ssize, local);
>
> return ret;
> }
> @@ -315,6 +363,7 @@ static long native_hpte_find(unsigned long vpn, int psize, int ssize)
> static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
> int psize, int ssize)
> {
> + int actual_psize;
> unsigned long vpn;
> unsigned long vsid;
> long slot;
> @@ -327,13 +376,16 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
> if (slot == -1)
> panic("could not find page to bolt\n");
> hptep = htab_address + slot;
> + actual_psize = hpte_actual_psize(hptep, psize);
> + if (actual_psize < 0)
> + return;
>
> /* Update the HPTE */
> hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
> (newpp & (HPTE_R_PP | HPTE_R_N));
>
> /* Ensure it is out of the tlb too. */
> - tlbie(vpn, psize, ssize, 0);
> + tlbie(vpn, psize, actual_psize, ssize, 0);
> }
>
> static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
> @@ -343,6 +395,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
> unsigned long hpte_v;
> unsigned long want_v;
> unsigned long flags;
> + int actual_psize;
>
> local_irq_save(flags);
>
> @@ -352,35 +405,38 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
> native_lock_hpte(hptep);
> hpte_v = hptep->v;
>
> + actual_psize = hpte_actual_psize(hptep, psize);
> + if (actual_psize < 0) {
> + native_unlock_hpte(hptep);
> + local_irq_restore(flags);
> + return;
> + }
> /* Even if we miss, we need to invalidate the TLB */
> - if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
> + if (!HPTE_V_COMPARE(hpte_v, want_v))
> native_unlock_hpte(hptep);
> else
> /* Invalidate the hpte. NOTE: this also unlocks it */
> hptep->v = 0;
>
> /* Invalidate the TLB */
> - tlbie(vpn, psize, ssize, local);
> + tlbie(vpn, psize, actual_psize, ssize, local);
>
> local_irq_restore(flags);
> }
>
> -#define LP_SHIFT 12
> -#define LP_BITS 8
> -#define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT)
> -
> static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
> - int *psize, int *ssize, unsigned long *vpn)
> + int *psize, int *apsize, int *ssize, unsigned long *vpn)
> {
> unsigned long avpn, pteg, vpi;
> unsigned long hpte_r = hpte->r;
> unsigned long hpte_v = hpte->v;
> unsigned long vsid, seg_off;
> - int i, size, shift, penc;
> + int i, size, a_size, shift, penc;
>
> - if (!(hpte_v & HPTE_V_LARGE))
> - size = MMU_PAGE_4K;
> - else {
> + if (!(hpte_v & HPTE_V_LARGE)) {
> + size = MMU_PAGE_4K;
> + a_size = MMU_PAGE_4K;
> + } else {
> for (i = 0; i < LP_BITS; i++) {
> if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1))
> break;
> @@ -388,19 +444,26 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
> penc = LP_MASK(i+1) >> LP_SHIFT;
> for (size = 0; size < MMU_PAGE_COUNT; size++) {
>
> - /* 4K pages are not represented by LP */
> - if (size == MMU_PAGE_4K)
> - continue;
> -
> /* valid entries have a shift value */
> if (!mmu_psize_defs[size].shift)
> continue;
> + for (a_size = 0; a_size < MMU_PAGE_COUNT; a_size++) {
Can't you resize hpte_actual_psize() here instead of recoding the lookup?
> - if (penc == mmu_psize_defs[size].penc)
> - break;
> + /* 4K pages are not represented by LP */
> + if (a_size == MMU_PAGE_4K)
> + continue;
> +
> + /* valid entries have a shift value */
> + if (!mmu_psize_defs[a_size].shift)
> + continue;
> +
> + if (penc == mmu_psize_defs[size].penc[a_size])
> + goto out;
> + }
> }
> }
>
> +out:
> /* This works for all page sizes, and for 256M and 1T segments */
> *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT;
> shift = mmu_psize_defs[size].shift;
> @@ -433,7 +496,8 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
> default:
> *vpn = size = 0;
> }
> - *psize = size;
> + *psize = size;
> + *apsize = a_size;
> }
>
> /*
> @@ -451,7 +515,7 @@ static void native_hpte_clear(void)
> struct hash_pte *hptep = htab_address;
> unsigned long hpte_v;
> unsigned long pteg_count;
> - int psize, ssize;
> + int psize, apsize, ssize;
>
> pteg_count = htab_hash_mask + 1;
>
> @@ -477,9 +541,9 @@ static void native_hpte_clear(void)
> * already hold the native_tlbie_lock.
> */
> if (hpte_v & HPTE_V_VALID) {
> - hpte_decode(hptep, slot, &psize, &ssize, &vpn);
> + hpte_decode(hptep, slot, &psize, &apsize, &ssize, &vpn);
> hptep->v = 0;
> - __tlbie(vpn, psize, ssize);
> + __tlbie(vpn, psize, apsize, ssize);
> }
> }
>
> @@ -540,7 +604,7 @@ static void native_flush_hash_range(unsigned long number, int local)
>
> pte_iterate_hashed_subpages(pte, psize,
> vpn, index, shift) {
> - __tlbiel(vpn, psize, ssize);
> + __tlbiel(vpn, psize, psize, ssize);
> } pte_iterate_hashed_end();
> }
> asm volatile("ptesync":::"memory");
> @@ -557,7 +621,7 @@ static void native_flush_hash_range(unsigned long number, int local)
>
> pte_iterate_hashed_subpages(pte, psize,
> vpn, index, shift) {
> - __tlbie(vpn, psize, ssize);
> + __tlbie(vpn, psize, psize, ssize);
> } pte_iterate_hashed_end();
> }
> asm volatile("eieio; tlbsync; ptesync":::"memory");
> diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> index bfeab83..a5a5067 100644
> --- a/arch/powerpc/mm/hash_utils_64.c
> +++ b/arch/powerpc/mm/hash_utils_64.c
> @@ -125,7 +125,7 @@ static struct mmu_psize_def mmu_psize_defaults_old[] = {
> [MMU_PAGE_4K] = {
> .shift = 12,
> .sllp = 0,
> - .penc = 0,
> + .penc = {[MMU_PAGE_4K] = 0, [1 ... MMU_PAGE_COUNT - 1] = -1},
> .avpnm = 0,
> .tlbiel = 0,
> },
> @@ -139,14 +139,15 @@ static struct mmu_psize_def mmu_psize_defaults_gp[] = {
> [MMU_PAGE_4K] = {
> .shift = 12,
> .sllp = 0,
> - .penc = 0,
> + .penc = {[MMU_PAGE_4K] = 0, [1 ... MMU_PAGE_COUNT - 1] = -1},
> .avpnm = 0,
> .tlbiel = 1,
> },
> [MMU_PAGE_16M] = {
> .shift = 24,
> .sllp = SLB_VSID_L,
> - .penc = 0,
> + .penc = {[0 ... MMU_PAGE_16M - 1] = -1, [MMU_PAGE_16M] = 0,
> + [MMU_PAGE_16M + 1 ... MMU_PAGE_COUNT - 1] = -1 },
> .avpnm = 0x1UL,
> .tlbiel = 0,
> },
> @@ -208,7 +209,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
>
> BUG_ON(!ppc_md.hpte_insert);
> ret = ppc_md.hpte_insert(hpteg, vpn, paddr, tprot,
> - HPTE_V_BOLTED, psize, ssize);
> + HPTE_V_BOLTED, psize, psize, ssize);
>
> if (ret < 0)
> break;
> @@ -275,6 +276,30 @@ static void __init htab_init_seg_sizes(void)
> of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL);
> }
>
> +static int __init get_idx_from_shift(unsigned int shift)
> +{
> + int idx = -1;
> +
> + switch (shift) {
> + case 0xc:
> + idx = MMU_PAGE_4K;
> + break;
> + case 0x10:
> + idx = MMU_PAGE_64K;
> + break;
> + case 0x14:
> + idx = MMU_PAGE_1M;
> + break;
> + case 0x18:
> + idx = MMU_PAGE_16M;
> + break;
> + case 0x22:
> + idx = MMU_PAGE_16G;
> + break;
> + }
> + return idx;
> +}
> +
> static int __init htab_dt_scan_page_sizes(unsigned long node,
> const char *uname, int depth,
> void *data)
> @@ -294,60 +319,61 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
> size /= 4;
> cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE);
> while(size > 0) {
> - unsigned int shift = prop[0];
> + unsigned int base_shift = prop[0];
> unsigned int slbenc = prop[1];
> unsigned int lpnum = prop[2];
> - unsigned int lpenc = 0;
> struct mmu_psize_def *def;
> - int idx = -1;
> + int idx, base_idx;
>
> size -= 3; prop += 3;
> - while(size > 0 && lpnum) {
> - if (prop[0] == shift)
> - lpenc = prop[1];
> - prop += 2; size -= 2;
> - lpnum--;
> + base_idx = get_idx_from_shift(base_shift);
> + if (base_idx < 0) {
> + /*
> + * skip the pte encoding also
> + */
> + prop += lpnum * 2; size -= lpnum * 2;
> + continue;
> }
> - switch(shift) {
> - case 0xc:
> - idx = MMU_PAGE_4K;
> - break;
> - case 0x10:
> - idx = MMU_PAGE_64K;
> - break;
> - case 0x14:
> - idx = MMU_PAGE_1M;
> - break;
> - case 0x18:
> - idx = MMU_PAGE_16M;
> + def = &mmu_psize_defs[base_idx];
> + if (base_idx == MMU_PAGE_16M)
> cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE;
> - break;
> - case 0x22:
> - idx = MMU_PAGE_16G;
> - break;
> - }
> - if (idx < 0)
> - continue;
> - def = &mmu_psize_defs[idx];
> - def->shift = shift;
> - if (shift <= 23)
> +
> + def->shift = base_shift;
> + if (base_shift <= 23)
> def->avpnm = 0;
> else
> - def->avpnm = (1 << (shift - 23)) - 1;
> + def->avpnm = (1 << (base_shift - 23)) - 1;
> def->sllp = slbenc;
> - def->penc = lpenc;
> - /* We don't know for sure what's up with tlbiel, so
> + /*
> + * We don't know for sure what's up with tlbiel, so
> * for now we only set it for 4K and 64K pages
> */
> - if (idx == MMU_PAGE_4K || idx == MMU_PAGE_64K)
> + if (base_idx == MMU_PAGE_4K || base_idx == MMU_PAGE_64K)
> def->tlbiel = 1;
> else
> def->tlbiel = 0;
>
> - DBG(" %d: shift=%02x, sllp=%04lx, avpnm=%08lx, "
> - "tlbiel=%d, penc=%d\n",
> - idx, shift, def->sllp, def->avpnm, def->tlbiel,
> - def->penc);
> + while (size > 0 && lpnum) {
> + unsigned int shift = prop[0];
> + int penc = prop[1];
> +
> + prop += 2; size -= 2;
> + lpnum--;
> +
> + idx = get_idx_from_shift(shift);
> + if (idx < 0)
> + continue;
> +
> + if (penc == -1)
> + pr_err("Invalid penc for base_shift=%d "
> + "shift=%d\n", base_shift, shift);
> +
> + def->penc[idx] = penc;
> + DBG(" %d: shift=%02x, sllp=%04lx, "
> + "avpnm=%08lx, tlbiel=%d, penc=%d\n",
> + idx, shift, def->sllp, def->avpnm,
> + def->tlbiel, def->penc[idx]);
> + }
> }
> return 1;
> }
> @@ -396,10 +422,21 @@ static int __init htab_dt_scan_hugepage_blocks(unsigned long node,
> }
> #endif /* CONFIG_HUGETLB_PAGE */
>
> +static void mmu_psize_set_default_penc(void)
> +{
> + int bpsize, apsize;
> + for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++)
> + for (apsize = 0; apsize < MMU_PAGE_COUNT; apsize++)
> + mmu_psize_defs[bpsize].penc[apsize] = -1;
> +}
> +
> static void __init htab_init_page_sizes(void)
> {
> int rc;
>
> + /* se the invalid penc to -1 */
> + mmu_psize_set_default_penc();
> +
> /* Default to 4K pages only */
> memcpy(mmu_psize_defs, mmu_psize_defaults_old,
> sizeof(mmu_psize_defaults_old));
> diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c
> index cecad34..e0d52ee 100644
> --- a/arch/powerpc/mm/hugetlbpage-hash64.c
> +++ b/arch/powerpc/mm/hugetlbpage-hash64.c
> @@ -103,7 +103,7 @@ repeat:
>
> /* Insert into the hash table, primary slot */
> slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
> - mmu_psize, ssize);
> + mmu_psize, mmu_psize, ssize);
>
> /* Primary is full, try the secondary */
> if (unlikely(slot == -1)) {
> @@ -111,7 +111,7 @@ repeat:
> HPTES_PER_GROUP) & ~0x7UL;
> slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags,
> HPTE_V_SECONDARY,
> - mmu_psize, ssize);
> + mmu_psize, mmu_psize, ssize);
> if (slot == -1) {
> if (mftb() & 0x1)
> hpte_group = ((hash & htab_hash_mask) *
> diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c
> index 472f9a7..246e1d8 100644
> --- a/arch/powerpc/platforms/cell/beat_htab.c
> +++ b/arch/powerpc/platforms/cell/beat_htab.c
> @@ -90,7 +90,7 @@ static inline unsigned int beat_read_mask(unsigned hpte_group)
> static long beat_lpar_hpte_insert(unsigned long hpte_group,
> unsigned long vpn, unsigned long pa,
> unsigned long rflags, unsigned long vflags,
> - int psize, int ssize)
> + int psize, int apsize, int ssize)
> {
> unsigned long lpar_rc;
> u64 hpte_v, hpte_r, slot;
> @@ -103,9 +103,9 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group,
> "rflags=%lx, vflags=%lx, psize=%d)\n",
> hpte_group, va, pa, rflags, vflags, psize);
>
> - hpte_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M) |
> + hpte_v = hpte_encode_v(vpn, psize, apsize, MMU_SEGSIZE_256M) |
> vflags | HPTE_V_VALID;
> - hpte_r = hpte_encode_r(pa, psize) | rflags;
> + hpte_r = hpte_encode_r(pa, psize, apsize) | rflags;
>
> if (!(vflags & HPTE_V_BOLTED))
> DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
> @@ -314,7 +314,7 @@ void __init hpte_init_beat(void)
> static long beat_lpar_hpte_insert_v3(unsigned long hpte_group,
> unsigned long vpn, unsigned long pa,
> unsigned long rflags, unsigned long vflags,
> - int psize, int ssize)
> + int psize, int apsize, int ssize)
> {
> unsigned long lpar_rc;
> u64 hpte_v, hpte_r, slot;
> @@ -327,9 +327,9 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group,
> "rflags=%lx, vflags=%lx, psize=%d)\n",
> hpte_group, vpn, pa, rflags, vflags, psize);
>
> - hpte_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M) |
> + hpte_v = hpte_encode_v(vpn, psize, apsize, MMU_SEGSIZE_256M) |
> vflags | HPTE_V_VALID;
> - hpte_r = hpte_encode_r(pa, psize) | rflags;
> + hpte_r = hpte_encode_r(pa, psize, apsize) | rflags;
>
> if (!(vflags & HPTE_V_BOLTED))
> DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
> @@ -373,7 +373,7 @@ static long beat_lpar_hpte_updatepp_v3(unsigned long slot,
> unsigned long pss;
>
> want_v = hpte_encode_avpn(vpn, psize, MMU_SEGSIZE_256M);
> - pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc;
> + pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc[psize];
>
> DBG_LOW(" update: "
> "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ",
> @@ -403,7 +403,7 @@ static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long vpn,
> DBG_LOW(" inval : slot=%lx, vpn=%016lx, psize: %d, local: %d\n",
> slot, vpn, psize, local);
> want_v = hpte_encode_avpn(vpn, psize, MMU_SEGSIZE_256M);
> - pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc;
> + pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc[psize];
>
> lpar_rc = beat_invalidate_htab_entry3(0, slot, want_v, pss);
>
> diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
> index 07a4bba..44f06d2 100644
> --- a/arch/powerpc/platforms/ps3/htab.c
> +++ b/arch/powerpc/platforms/ps3/htab.c
> @@ -45,7 +45,7 @@ static DEFINE_SPINLOCK(ps3_htab_lock);
>
> static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn,
> unsigned long pa, unsigned long rflags, unsigned long vflags,
> - int psize, int ssize)
> + int psize, int apsize, int ssize)
> {
> int result;
> u64 hpte_v, hpte_r;
> @@ -61,8 +61,8 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn,
> */
> vflags &= ~HPTE_V_SECONDARY;
>
> - hpte_v = hpte_encode_v(vpn, psize, ssize) | vflags | HPTE_V_VALID;
> - hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags;
> + hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
> + hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize) | rflags;
>
> spin_lock_irqsave(&ps3_htab_lock, flags);
>
> diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
> index a77c35b..3daced3 100644
> --- a/arch/powerpc/platforms/pseries/lpar.c
> +++ b/arch/powerpc/platforms/pseries/lpar.c
> @@ -109,7 +109,7 @@ void vpa_init(int cpu)
> static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
> unsigned long vpn, unsigned long pa,
> unsigned long rflags, unsigned long vflags,
> - int psize, int ssize)
> + int psize, int apsize, int ssize)
> {
> unsigned long lpar_rc;
> unsigned long flags;
> @@ -121,8 +121,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
> "pa=%016lx, rflags=%lx, vflags=%lx, psize=%d)\n",
> hpte_group, vpn, pa, rflags, vflags, psize);
>
> - hpte_v = hpte_encode_v(vpn, psize, ssize) | vflags | HPTE_V_VALID;
> - hpte_r = hpte_encode_r(pa, psize) | rflags;
> + hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID;
> + hpte_r = hpte_encode_r(pa, psize, apsize) | rflags;
>
> if (!(vflags & HPTE_V_BOLTED))
> pr_devel(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* [RESEND PATCH 3/4] Use vmap_area_list to get vmalloc_start for ppc32.
From: Atsushi Kumagai @ 2013-04-10 7:10 UTC (permalink / raw)
To: kexec; +Cc: linuxppc-dev
In-Reply-To: <20130410150524.804cd23b99a697f71146be67@mxc.nes.nec.co.jp>
From: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Date: Fri, 15 Mar 2013 19:30:23 +0900
Subject: [PATCH 3/4] Use vmap_area_list to get vmalloc_start for ppc32.
Try to get vmalloc_start value from vmap_area_list first for
newer ppc32 kernels.
Signed-off-by: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
---
arch/ppc.c | 44 +++++++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 13 deletions(-)
diff --git a/arch/ppc.c b/arch/ppc.c
index 2bc8d5f..a9b4812 100644
--- a/arch/ppc.c
+++ b/arch/ppc.c
@@ -44,22 +44,40 @@ get_machdep_info_ppc(void)
DEBUG_MSG("kernel_start : %lx\n", info->kernel_start);
/*
- * For the compatibility, makedumpfile should run without the symbol
- * vmlist and the offset of vm_struct.addr if they are not necessary.
+ * Get vmalloc_start value from either vmap_area_list or vmlist.
*/
- if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL)
- || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) {
+ if ((SYMBOL(vmap_area_list) != NOT_FOUND_SYMBOL)
+ && (OFFSET(vmap_area.va_start) != NOT_FOUND_STRUCTURE)
+ && (OFFSET(vmap_area.list) != NOT_FOUND_STRUCTURE)) {
+ if (!readmem(VADDR, SYMBOL(vmap_area_list) + OFFSET(list_head.next),
+ &vmap_area_list, sizeof(vmap_area_list))) {
+ ERRMSG("Can't get vmap_area_list.\n");
+ return FALSE;
+ }
+ if (!readmem(VADDR, vmap_area_list - OFFSET(vmap_area.list) +
+ OFFSET(vmap_area.va_start), &vmalloc_start,
+ sizeof(vmalloc_start))) {
+ ERRMSG("Can't get vmalloc_start.\n");
+ return FALSE;
+ }
+ } else if ((SYMBOL(vmlist) != NOT_FOUND_SYMBOL)
+ && (OFFSET(vm_struct.addr) != NOT_FOUND_STRUCTURE)) {
+ if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) {
+ ERRMSG("Can't get vmlist.\n");
+ return FALSE;
+ }
+ if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start,
+ sizeof(vmalloc_start))) {
+ ERRMSG("Can't get vmalloc_start.\n");
+ return FALSE;
+ }
+ } else {
+ /*
+ * For the compatibility, makedumpfile should run without the symbol
+ * vmlist and the offset of vm_struct.addr if they are not necessary.
+ */
return TRUE;
}
- if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) {
- ERRMSG("Can't get vmlist.\n");
- return FALSE;
- }
- if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start,
- sizeof(vmalloc_start))) {
- ERRMSG("Can't get vmalloc_start.\n");
- return FALSE;
- }
info->vmalloc_start = vmalloc_start;
DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start);
--
1.8.0.2
^ permalink raw reply related
* [RESEND PATCH 2/4] Use vmap_area_list to get vmalloc_start for i386.
From: Atsushi Kumagai @ 2013-04-10 7:10 UTC (permalink / raw)
To: kexec; +Cc: linuxppc-dev
In-Reply-To: <20130410150524.804cd23b99a697f71146be67@mxc.nes.nec.co.jp>
From: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Date: Thu, 14 Mar 2013 19:10:49 +0900
Subject: [PATCH 2/4] Use vmap_area_list to get vmalloc_start for i386.
Try to get vmalloc_start value from vmap_area_list first for
newer i386 kernels.
Signed-off-by: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
---
arch/x86.c | 46 ++++++++++++++++++++++++++++++++--------------
1 file changed, 32 insertions(+), 14 deletions(-)
diff --git a/arch/x86.c b/arch/x86.c
index ef29e3c..e397905 100644
--- a/arch/x86.c
+++ b/arch/x86.c
@@ -70,7 +70,7 @@ remap_init(void)
int
get_machdep_info_x86(void)
{
- unsigned long vmlist, vmalloc_start;
+ unsigned long vmlist, vmap_area_list, vmalloc_start;
/* PAE */
if ((vt.mem_flags & MEMORY_X86_PAE)
@@ -100,22 +100,40 @@ get_machdep_info_x86(void)
return FALSE;
/*
- * For the compatibility, makedumpfile should run without the symbol
- * vmlist and the offset of vm_struct.addr if they are not necessary.
+ * Get vmalloc_start value from either vmap_area_list or vmlist.
*/
- if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL)
- || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) {
+ if ((SYMBOL(vmap_area_list) != NOT_FOUND_SYMBOL)
+ && (OFFSET(vmap_area.va_start) != NOT_FOUND_STRUCTURE)
+ && (OFFSET(vmap_area.list) != NOT_FOUND_STRUCTURE)) {
+ if (!readmem(VADDR, SYMBOL(vmap_area_list) + OFFSET(list_head.next),
+ &vmap_area_list, sizeof(vmap_area_list))) {
+ ERRMSG("Can't get vmap_area_list.\n");
+ return FALSE;
+ }
+ if (!readmem(VADDR, vmap_area_list - OFFSET(vmap_area.list) +
+ OFFSET(vmap_area.va_start), &vmalloc_start,
+ sizeof(vmalloc_start))) {
+ ERRMSG("Can't get vmalloc_start.\n");
+ return FALSE;
+ }
+ } else if ((SYMBOL(vmlist) != NOT_FOUND_SYMBOL)
+ && (OFFSET(vm_struct.addr) != NOT_FOUND_STRUCTURE)) {
+ if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) {
+ ERRMSG("Can't get vmlist.\n");
+ return FALSE;
+ }
+ if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start,
+ sizeof(vmalloc_start))) {
+ ERRMSG("Can't get vmalloc_start.\n");
+ return FALSE;
+ }
+ } else {
+ /*
+ * For the compatibility, makedumpfile should run without the symbol
+ * used to get vmalloc_start value if they are not necessary.
+ */
return TRUE;
}
- if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) {
- ERRMSG("Can't get vmlist.\n");
- return FALSE;
- }
- if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start,
- sizeof(vmalloc_start))) {
- ERRMSG("Can't get vmalloc_start.\n");
- return FALSE;
- }
info->vmalloc_start = vmalloc_start;
DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start);
--
1.8.0.2
^ permalink raw reply related
* [RESEND PATCH 1/4] Introduce new symbols to look at the first vmap_area.
From: Atsushi Kumagai @ 2013-04-10 7:10 UTC (permalink / raw)
To: kexec; +Cc: linuxppc-dev
In-Reply-To: <20130410150524.804cd23b99a697f71146be67@mxc.nes.nec.co.jp>
From: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Date: Thu, 14 Mar 2013 11:08:57 +0900
Subject: [PATCH 1/4] Introduce new symbols to look at the first vmap_area.
struct vmlist which we used to get vmalloc_start value will be
removed from kernel soon, so we have to look at the first vmap_area
in the sorted vmap_area_list instead of vmlist.
The address which contains vmalloc_start value is represented as
below:
vmap_area_list.next - OFFSET(vmap_area.list) + OFFSET(vmap_area.va_start)
This patch introduces these symbols.
Signed-off-by: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
---
makedumpfile.c | 9 +++++++++
makedumpfile.h | 5 +++++
2 files changed, 14 insertions(+)
diff --git a/makedumpfile.c b/makedumpfile.c
index 6de0581..9cf907c 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -854,6 +854,7 @@ get_symbol_info(void)
SYMBOL_INIT(swapper_pg_dir, "swapper_pg_dir");
SYMBOL_INIT(init_level4_pgt, "init_level4_pgt");
SYMBOL_INIT(vmlist, "vmlist");
+ SYMBOL_INIT(vmap_area_list, "vmap_area_list");
SYMBOL_INIT(phys_base, "phys_base");
SYMBOL_INIT(node_online_map, "node_online_map");
SYMBOL_INIT(node_states, "node_states");
@@ -989,6 +990,8 @@ get_structure_info(void)
OFFSET_INIT(node_memblk_s.nid, "node_memblk_s", "nid");
OFFSET_INIT(vm_struct.addr, "vm_struct", "addr");
+ OFFSET_INIT(vmap_area.va_start, "vmap_area", "va_start");
+ OFFSET_INIT(vmap_area.list, "vmap_area", "list");
/*
* Get offset of the module members.
@@ -1368,6 +1371,7 @@ write_vmcoreinfo_data(void)
WRITE_SYMBOL("swapper_pg_dir", swapper_pg_dir);
WRITE_SYMBOL("init_level4_pgt", init_level4_pgt);
WRITE_SYMBOL("vmlist", vmlist);
+ WRITE_SYMBOL("vmap_area_list", vmap_area_list);
WRITE_SYMBOL("phys_base", phys_base);
WRITE_SYMBOL("node_online_map", node_online_map);
WRITE_SYMBOL("node_states", node_states);
@@ -1430,6 +1434,8 @@ write_vmcoreinfo_data(void)
WRITE_MEMBER_OFFSET("node_memblk_s.size", node_memblk_s.size);
WRITE_MEMBER_OFFSET("node_memblk_s.nid", node_memblk_s.nid);
WRITE_MEMBER_OFFSET("vm_struct.addr", vm_struct.addr);
+ WRITE_MEMBER_OFFSET("vmap_area.va_start", vmap_area.va_start);
+ WRITE_MEMBER_OFFSET("vmap_area.list", vmap_area.list);
WRITE_MEMBER_OFFSET("log.ts_nsec", log.ts_nsec);
WRITE_MEMBER_OFFSET("log.len", log.len);
WRITE_MEMBER_OFFSET("log.text_len", log.text_len);
@@ -1684,6 +1690,7 @@ read_vmcoreinfo(void)
READ_SYMBOL("swapper_pg_dir", swapper_pg_dir);
READ_SYMBOL("init_level4_pgt", init_level4_pgt);
READ_SYMBOL("vmlist", vmlist);
+ READ_SYMBOL("vmap_area_list", vmap_area_list);
READ_SYMBOL("phys_base", phys_base);
READ_SYMBOL("node_online_map", node_online_map);
READ_SYMBOL("node_states", node_states);
@@ -1739,6 +1746,8 @@ read_vmcoreinfo(void)
READ_MEMBER_OFFSET("node_memblk_s.size", node_memblk_s.size);
READ_MEMBER_OFFSET("node_memblk_s.nid", node_memblk_s.nid);
READ_MEMBER_OFFSET("vm_struct.addr", vm_struct.addr);
+ READ_MEMBER_OFFSET("vmap_area.va_start", vmap_area.va_start);
+ READ_MEMBER_OFFSET("vmap_area.list", vmap_area.list);
READ_MEMBER_OFFSET("log.ts_nsec", log.ts_nsec);
READ_MEMBER_OFFSET("log.len", log.len);
READ_MEMBER_OFFSET("log.text_len", log.text_len);
diff --git a/makedumpfile.h b/makedumpfile.h
index de329f3..36cb9fd 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1096,6 +1096,7 @@ struct symbol_table {
unsigned long long swapper_pg_dir;
unsigned long long init_level4_pgt;
unsigned long long vmlist;
+ unsigned long long vmap_area_list;
unsigned long long phys_base;
unsigned long long node_online_map;
unsigned long long node_states;
@@ -1233,6 +1234,10 @@ struct offset_table {
struct vm_struct {
long addr;
} vm_struct;
+ struct vmap_area {
+ long va_start;
+ long list;
+ } vmap_area;
/*
* for Xen extraction
--
1.8.0.2
^ permalink raw reply related
* Re: [PATCH -V5 06/25] powerpc: Reduce PTE table memory wastage
From: Michael Ellerman @ 2013-04-10 7:14 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1365055083-31956-7-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On Thu, Apr 04, 2013 at 11:27:44AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>
> We allocate one page for the last level of linux page table. With THP and
> large page size of 16MB, that would mean we are wasting large part
> of that page. To map 16MB area, we only need a PTE space of 2K with 64K
> page size. This patch reduce the space wastage by sharing the page
> allocated for the last level of linux page table with multiple pmd
> entries. We call these smaller chunks PTE page fragments and allocated
> page, PTE page.
This is not compiling for me:
arch/powerpc/mm/mmu_context_hash64.c:118:3: error: implicit declaration of function 'reset_page_mapcount'
And similar.
cheers
^ permalink raw reply
* Re: [PATCH -V5 06/25] powerpc: Reduce PTE table memory wastage
From: David Gibson @ 2013-04-10 7:04 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <8738uyq4om.fsf@linux.vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 4253 bytes --]
On Wed, Apr 10, 2013 at 11:59:29AM +0530, Aneesh Kumar K.V wrote:
> David Gibson <dwg@au1.ibm.com> writes:
> > On Thu, Apr 04, 2013 at 11:27:44AM +0530, Aneesh Kumar K.V wrote:
[snip]
> >> @@ -97,13 +100,45 @@ void __destroy_context(int context_id)
> >> }
> >> EXPORT_SYMBOL_GPL(__destroy_context);
> >>
> >> +#ifdef CONFIG_PPC_64K_PAGES
> >> +static void destroy_pagetable_page(struct mm_struct *mm)
> >> +{
> >> + int count;
> >> + struct page *page;
> >> +
> >> + page = mm->context.pgtable_page;
> >> + if (!page)
> >> + return;
> >> +
> >> + /* drop all the pending references */
> >> + count = atomic_read(&page->_mapcount) + 1;
> >> + /* We allow PTE_FRAG_NR(16) fragments from a PTE page */
> >> + count = atomic_sub_return(16 - count, &page->_count);
> >
> > You should really move PTE_FRAG_NR to a header so you can actually use
> > it here rather than hard coding 16.
> >
> > It took me a fair while to convince myself that there is no race here
> > with something altering mapcount and count between the atomic_read()
> > and the atomic_sub_return(). It could do with a comment to explain
> > why that is safe.
> >
> > Re-using the mapcount field for your index also seems odd, and it took
> > me a while to convince myself that that's safe too. Wouldn't it be
> > simpler to store a pointer to the next sub-page in the mm_context
> > instead? You can get from that to the struct page easily enough with a
> > shift and pfn_to_page().
>
> I found using _mapcount simpler in this case. I was looking at it not
> as an index, but rather how may fragments are mapped/used already.
Except that it's actually (#fragments - 1). Using subpage pointer
makes the fragments calculation (very slightly) harder, but the
calculation of the table address easier. More importantly it avoids
adding effectively an extra variable - which is then shoehorned into a
structure not really designed to hold it.
> Using
> subpage pointer in mm->context.xyz means, we have to calculate the
> number of fragments used/mapped via the pointer. We need the fragment
> count so that we can drop page reference count correctly here.
>
>
> >
> >> + if (!count) {
> >> + pgtable_page_dtor(page);
> >> + reset_page_mapcount(page);
> >> + free_hot_cold_page(page, 0);
> >
> > It would be nice to use put_page() somehow instead of duplicating its
> > logic, though I realise the sparc code you've based this on does the
> > same thing.
>
> That is not exactly put_page. We can avoid lots of check in this
> specific case.
[snip]
> >> +static pte_t *__alloc_for_cache(struct mm_struct *mm, int kernel)
> >> +{
> >> + pte_t *ret = NULL;
> >> + struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK |
> >> + __GFP_REPEAT | __GFP_ZERO);
> >> + if (!page)
> >> + return NULL;
> >> +
> >> + spin_lock(&mm->page_table_lock);
> >> + /*
> >> + * If we find pgtable_page set, we return
> >> + * the allocated page with single fragement
> >> + * count.
> >> + */
> >> + if (likely(!mm->context.pgtable_page)) {
> >> + atomic_set(&page->_count, PTE_FRAG_NR);
> >> + atomic_set(&page->_mapcount, 0);
> >> + mm->context.pgtable_page = page;
> >> + }
> >
> > .. and in the unlikely case where there *is* a pgtable_page already
> > set, what then? Seems like you should BUG_ON, or at least return NULL
> > - as it is you will return the first sub-page of that page again,
> > which is very likely in use.
>
>
> As explained in the comment above, we return with the allocated page
> with fragment count set to 1. So we end up having only one fragment. The
> other option I had was to to free the allocated page and do a
> get_from_cache under the page_table_lock. But since we already allocated
> the page, why not use that ?. It also keep the code similar to
> sparc.
My point is that I can't see any circumstance under which we should
ever hit this case. Which means if we do something is badly messed up
and we should BUG() (or at least WARN()).
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH v2 11/11] Add /proc interface to control topology updates
From: Michael Ellerman @ 2013-04-10 6:59 UTC (permalink / raw)
To: Nathan Fontenot; +Cc: linuxppc-dev
In-Reply-To: <51509F31.8010300@linux.vnet.ibm.com>
On Mon, Mar 25, 2013 at 02:02:09PM -0500, Nathan Fontenot wrote:
> There are instances in which we do not want topology updates to occur.
> In order to allow this a /proc interface (/proc/powerpc/topology_updates)
> is introduced so that topology updates can be enabled and disabled.
>
> This patch also adds a prrn_is_enabled() call so that PRRN events are
> handled in the kernel only if topology updating is enabled.
Hi Nathan,
> Index: powerpc/arch/powerpc/mm/numa.c
> ===================================================================
> --- powerpc.orig/arch/powerpc/mm/numa.c 2013-03-20 12:27:48.000000000 -0500
> +++ powerpc/arch/powerpc/mm/numa.c 2013-03-20 12:27:52.000000000 -0500
> @@ -1577,4 +1579,62 @@
>
> return rc;
> }
> +
> +inline int prrn_is_enabled(void)
> +{
> + return prrn_enabled;
> +}
...
> Index: powerpc/arch/powerpc/include/asm/topology.h
> ===================================================================
> --- powerpc.orig/arch/powerpc/include/asm/topology.h 2013-03-20 12:25:37.000000000 -0500
> +++ powerpc/arch/powerpc/include/asm/topology.h 2013-03-20 12:27:52.000000000 -0500
> @@ -71,6 +71,7 @@
> #if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
> extern int start_topology_update(void);
> extern int stop_topology_update(void);
> +extern inline int prrn_is_enabled(void);
This doesn't compile for me, with:
arch/powerpc/kernel/rtasd.c: In function 'rtas_event_scan':
arch/powerpc/include/asm/topology.h:74:19: sorry, unimplemented: inlining failed in call to 'prrn_is_enabled': function body not available
arch/powerpc/kernel/rtasd.c:299:22: sorry, unimplemented: called from here
cheers
^ permalink raw reply
* Re: [PATCH -V5 06/25] powerpc: Reduce PTE table memory wastage
From: Aneesh Kumar K.V @ 2013-04-10 6:29 UTC (permalink / raw)
To: David Gibson; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <20130410044611.GF8165@truffula.fritz.box>
David Gibson <dwg@au1.ibm.com> writes:
> On Thu, Apr 04, 2013 at 11:27:44AM +0530, Aneesh Kumar K.V wrote:
>> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>>
>> We allocate one page for the last level of linux page table. With THP and
>> large page size of 16MB, that would mean we are wasting large part
>> of that page. To map 16MB area, we only need a PTE space of 2K with 64K
>> page size. This patch reduce the space wastage by sharing the page
>> allocated for the last level of linux page table with multiple pmd
>> entries. We call these smaller chunks PTE page fragments and allocated
>> page, PTE page.
>>
>> In order to support systems which doesn't have 64K HPTE support, we also
>> add another 2K to PTE page fragment. The second half of the PTE fragments
>> is used for storing slot and secondary bit information of an HPTE. With this
>> we now have a 4K PTE fragment.
>>
>> We use a simple approach to share the PTE page. On allocation, we bump the
>> PTE page refcount to 16 and share the PTE page with the next 16 pte alloc
>> request. This should help in the node locality of the PTE page fragment,
>> assuming that the immediate pte alloc request will mostly come from the
>> same NUMA node. We don't try to reuse the freed PTE page fragment. Hence
>> we could be waisting some space.
>>
>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>> ---
>> arch/powerpc/include/asm/mmu-book3e.h | 4 +
>> arch/powerpc/include/asm/mmu-hash64.h | 4 +
>> arch/powerpc/include/asm/page.h | 4 +
>> arch/powerpc/include/asm/pgalloc-64.h | 72 ++++-------------
>> arch/powerpc/kernel/setup_64.c | 4 +-
>> arch/powerpc/mm/mmu_context_hash64.c | 35 +++++++++
>> arch/powerpc/mm/pgtable_64.c | 137 +++++++++++++++++++++++++++++++++
>> 7 files changed, 202 insertions(+), 58 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
>> index 99d43e0..affbd68 100644
>> --- a/arch/powerpc/include/asm/mmu-book3e.h
>> +++ b/arch/powerpc/include/asm/mmu-book3e.h
>> @@ -231,6 +231,10 @@ typedef struct {
>> u64 high_slices_psize; /* 4 bits per slice for now */
>> u16 user_psize; /* page size index */
>> #endif
>> +#ifdef CONFIG_PPC_64K_PAGES
>> + /* for 4K PTE fragment support */
>> + struct page *pgtable_page;
>> +#endif
>> } mm_context_t;
>>
>> /* Page size definitions, common between 32 and 64-bit
>> diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
>> index 35bb51e..300ac3c 100644
>> --- a/arch/powerpc/include/asm/mmu-hash64.h
>> +++ b/arch/powerpc/include/asm/mmu-hash64.h
>> @@ -498,6 +498,10 @@ typedef struct {
>> unsigned long acop; /* mask of enabled coprocessor types */
>> unsigned int cop_pid; /* pid value used with coprocessors */
>> #endif /* CONFIG_PPC_ICSWX */
>> +#ifdef CONFIG_PPC_64K_PAGES
>> + /* for 4K PTE fragment support */
>> + struct page *pgtable_page;
>> +#endif
>> } mm_context_t;
>>
>>
>> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
>> index f072e97..38e7ff6 100644
>> --- a/arch/powerpc/include/asm/page.h
>> +++ b/arch/powerpc/include/asm/page.h
>> @@ -378,7 +378,11 @@ void arch_free_page(struct page *page, int order);
>>
>> struct vm_area_struct;
>>
>> +#ifdef CONFIG_PPC_64K_PAGES
>> +typedef pte_t *pgtable_t;
>> +#else
>> typedef struct page *pgtable_t;
>> +#endif
>
> Ugh, that's pretty horrible, though I don't see an easy way around it.
>
>> #include <asm-generic/memory_model.h>
>> #endif /* __ASSEMBLY__ */
>> diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h
>> index cdbf555..3418989 100644
>> --- a/arch/powerpc/include/asm/pgalloc-64.h
>> +++ b/arch/powerpc/include/asm/pgalloc-64.h
>> @@ -150,6 +150,13 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
>>
>> #else /* if CONFIG_PPC_64K_PAGES */
>>
>> +extern pte_t *page_table_alloc(struct mm_struct *, unsigned long, int);
>> +extern void page_table_free(struct mm_struct *, unsigned long *, int);
>> +extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift);
>> +#ifdef CONFIG_SMP
>> +extern void __tlb_remove_table(void *_table);
>> +#endif
>> +
>> #define pud_populate(mm, pud, pmd) pud_set(pud, (unsigned long)pmd)
>>
>> static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
>> @@ -161,90 +168,42 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
>> static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
>> pgtable_t pte_page)
>> {
>> - pmd_populate_kernel(mm, pmd, page_address(pte_page));
>> + pmd_set(pmd, (unsigned long)pte_page);
>> }
>>
>> static inline pgtable_t pmd_pgtable(pmd_t pmd)
>> {
>> - return pmd_page(pmd);
>> + return (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE);
>> }
>>
>> static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
>> unsigned long address)
>> {
>> - return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
>> + return (pte_t *)page_table_alloc(mm, address, 1);
>> }
>>
>> static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
>> - unsigned long address)
>> + unsigned long address)
>> {
>> - struct page *page;
>> - pte_t *pte;
>> -
>> - pte = pte_alloc_one_kernel(mm, address);
>> - if (!pte)
>> - return NULL;
>> - page = virt_to_page(pte);
>> - pgtable_page_ctor(page);
>> - return page;
>> + return (pgtable_t)page_table_alloc(mm, address, 0);
>> }
>>
>> static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
>> {
>> - free_page((unsigned long)pte);
>> + page_table_free(mm, (unsigned long *)pte, 1);
>> }
>>
>> static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
>> {
>> - pgtable_page_dtor(ptepage);
>> - __free_page(ptepage);
>> -}
>> -
>> -static inline void pgtable_free(void *table, unsigned index_size)
>> -{
>> - if (!index_size)
>> - free_page((unsigned long)table);
>> - else {
>> - BUG_ON(index_size > MAX_PGTABLE_INDEX_SIZE);
>> - kmem_cache_free(PGT_CACHE(index_size), table);
>> - }
>> + page_table_free(mm, (unsigned long *)ptepage, 0);
>> }
>>
>> -#ifdef CONFIG_SMP
>> -static inline void pgtable_free_tlb(struct mmu_gather *tlb,
>> - void *table, int shift)
>> -{
>> - unsigned long pgf = (unsigned long)table;
>> - BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
>> - pgf |= shift;
>> - tlb_remove_table(tlb, (void *)pgf);
>> -}
>> -
>> -static inline void __tlb_remove_table(void *_table)
>> -{
>> - void *table = (void *)((unsigned long)_table & ~MAX_PGTABLE_INDEX_SIZE);
>> - unsigned shift = (unsigned long)_table & MAX_PGTABLE_INDEX_SIZE;
>> -
>> - pgtable_free(table, shift);
>> -}
>> -#else /* !CONFIG_SMP */
>> -static inline void pgtable_free_tlb(struct mmu_gather *tlb,
>> - void *table, int shift)
>> -{
>> - pgtable_free(table, shift);
>> -}
>> -#endif /* CONFIG_SMP */
>> -
>> static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
>> unsigned long address)
>> {
>> - struct page *page = page_address(table);
>> -
>> tlb_flush_pgtable(tlb, address);
>> - pgtable_page_dtor(page);
>> - pgtable_free_tlb(tlb, page, 0);
>> + pgtable_free_tlb(tlb, table, 0);
>> }
>> -
>> #endif /* CONFIG_PPC_64K_PAGES */
>>
>> static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
>> @@ -258,7 +217,6 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
>> kmem_cache_free(PGT_CACHE(PMD_INDEX_SIZE), pmd);
>> }
>>
>> -
>> #define __pmd_free_tlb(tlb, pmd, addr) \
>> pgtable_free_tlb(tlb, pmd, PMD_INDEX_SIZE)
>> #ifndef CONFIG_PPC_64K_PAGES
>> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
>> index 6da881b..04d833c 100644
>> --- a/arch/powerpc/kernel/setup_64.c
>> +++ b/arch/powerpc/kernel/setup_64.c
>> @@ -575,7 +575,9 @@ void __init setup_arch(char **cmdline_p)
>> init_mm.end_code = (unsigned long) _etext;
>> init_mm.end_data = (unsigned long) _edata;
>> init_mm.brk = klimit;
>> -
>> +#ifdef CONFIG_PPC_64K_PAGES
>> + init_mm.context.pgtable_page = NULL;
>> +#endif
>> irqstack_early_init();
>> exc_lvl_early_init();
>> emergency_stack_init();
>> diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
>> index 59cd773..fbfdca2 100644
>> --- a/arch/powerpc/mm/mmu_context_hash64.c
>> +++ b/arch/powerpc/mm/mmu_context_hash64.c
>> @@ -86,6 +86,9 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
>> spin_lock_init(mm->context.cop_lockp);
>> #endif /* CONFIG_PPC_ICSWX */
>>
>> +#ifdef CONFIG_PPC_64K_PAGES
>> + mm->context.pgtable_page = NULL;
>> +#endif
>> return 0;
>> }
>>
>> @@ -97,13 +100,45 @@ void __destroy_context(int context_id)
>> }
>> EXPORT_SYMBOL_GPL(__destroy_context);
>>
>> +#ifdef CONFIG_PPC_64K_PAGES
>> +static void destroy_pagetable_page(struct mm_struct *mm)
>> +{
>> + int count;
>> + struct page *page;
>> +
>> + page = mm->context.pgtable_page;
>> + if (!page)
>> + return;
>> +
>> + /* drop all the pending references */
>> + count = atomic_read(&page->_mapcount) + 1;
>> + /* We allow PTE_FRAG_NR(16) fragments from a PTE page */
>> + count = atomic_sub_return(16 - count, &page->_count);
>
> You should really move PTE_FRAG_NR to a header so you can actually use
> it here rather than hard coding 16.
>
> It took me a fair while to convince myself that there is no race here
> with something altering mapcount and count between the atomic_read()
> and the atomic_sub_return(). It could do with a comment to explain
> why that is safe.
>
> Re-using the mapcount field for your index also seems odd, and it took
> me a while to convince myself that that's safe too. Wouldn't it be
> simpler to store a pointer to the next sub-page in the mm_context
> instead? You can get from that to the struct page easily enough with a
> shift and pfn_to_page().
I found using _mapcount simpler in this case. I was looking at it not
as an index, but rather how may fragments are mapped/used already. Using
subpage pointer in mm->context.xyz means, we have to calculate the
number of fragments used/mapped via the pointer. We need the fragment
count so that we can drop page reference count correctly here.
>
>> + if (!count) {
>> + pgtable_page_dtor(page);
>> + reset_page_mapcount(page);
>> + free_hot_cold_page(page, 0);
>
> It would be nice to use put_page() somehow instead of duplicating its
> logic, though I realise the sparc code you've based this on does the
> same thing.
That is not exactly put_page. We can avoid lots of check in this
specific case.
>
>> + }
>> +}
>> +
>> +#else
>> +static inline void destroy_pagetable_page(struct mm_struct *mm)
>> +{
>> + return;
>> +}
>> +#endif
>> +
>> +
>> void destroy_context(struct mm_struct *mm)
>> {
>> +
>> #ifdef CONFIG_PPC_ICSWX
>> drop_cop(mm->context.acop, mm);
>> kfree(mm->context.cop_lockp);
>> mm->context.cop_lockp = NULL;
>> #endif /* CONFIG_PPC_ICSWX */
>> +
>> + destroy_pagetable_page(mm);
>> __destroy_context(mm->context.id);
>> subpage_prot_free(mm);
>> mm->context.id = MMU_NO_CONTEXT;
>> diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
>> index e212a27..e79840b 100644
>> --- a/arch/powerpc/mm/pgtable_64.c
>> +++ b/arch/powerpc/mm/pgtable_64.c
>> @@ -337,3 +337,140 @@ EXPORT_SYMBOL(__ioremap_at);
>> EXPORT_SYMBOL(iounmap);
>> EXPORT_SYMBOL(__iounmap);
>> EXPORT_SYMBOL(__iounmap_at);
>> +
>> +#ifdef CONFIG_PPC_64K_PAGES
>> +/*
>> + * we support 16 fragments per PTE page. This is limited by how many
>> + * bits we can pack in page->_mapcount. We use the first half for
>> + * tracking the usage for rcu page table free.
>> + */
>> +#define PTE_FRAG_NR 16
>> +/*
>> + * We use a 2K PTE page fragment and another 2K for storing
>> + * real_pte_t hash index
>> + */
>> +#define PTE_FRAG_SIZE (2 * PTRS_PER_PTE * sizeof(pte_t))
>> +
>> +static pte_t *get_from_cache(struct mm_struct *mm)
>> +{
>> + int index;
>> + pte_t *ret = NULL;
>> + struct page *page;
>> +
>> + spin_lock(&mm->page_table_lock);
>> + page = mm->context.pgtable_page;
>> + if (page) {
>> + void *p = page_address(page);
>> + index = atomic_add_return(1, &page->_mapcount);
>> + ret = (pte_t *) (p + (index * PTE_FRAG_SIZE));
>> + /*
>> + * If we have taken up all the fragments mark PTE page NULL
>> + */
>> + if (index == PTE_FRAG_NR - 1)
>> + mm->context.pgtable_page = NULL;
>> + }
>> + spin_unlock(&mm->page_table_lock);
>> + return ret;
>> +}
>> +
>> +static pte_t *__alloc_for_cache(struct mm_struct *mm, int kernel)
>> +{
>> + pte_t *ret = NULL;
>> + struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK |
>> + __GFP_REPEAT | __GFP_ZERO);
>> + if (!page)
>> + return NULL;
>> +
>> + spin_lock(&mm->page_table_lock);
>> + /*
>> + * If we find pgtable_page set, we return
>> + * the allocated page with single fragement
>> + * count.
>> + */
>> + if (likely(!mm->context.pgtable_page)) {
>> + atomic_set(&page->_count, PTE_FRAG_NR);
>> + atomic_set(&page->_mapcount, 0);
>> + mm->context.pgtable_page = page;
>> + }
>
> .. and in the unlikely case where there *is* a pgtable_page already
> set, what then? Seems like you should BUG_ON, or at least return NULL
> - as it is you will return the first sub-page of that page again,
> which is very likely in use.
As explained in the comment above, we return with the allocated page
with fragment count set to 1. So we end up having only one fragment. The
other option I had was to to free the allocated page and do a
get_from_cache under the page_table_lock. But since we already allocated
the page, why not use that ?. It also keep the code similar to sparc.
>
>> + spin_unlock(&mm->page_table_lock);
>> +
>> + ret = (unsigned long *)page_address(page);
>> + if (!kernel)
>> + pgtable_page_ctor(page);
>> +
>> + return ret;
>> +}
>> +
>> +pte_t *page_table_alloc(struct mm_struct *mm, unsigned long vmaddr, int kernel)
>> +{
>> + pte_t *pte;
>> +
>> + pte = get_from_cache(mm);
>> + if (pte)
>> + return pte;
>> +
>> + return __alloc_for_cache(mm, kernel);
>> +}
>> +
>> +void page_table_free(struct mm_struct *mm, unsigned long *table, int kernel)
>> +{
>> + struct page *page = virt_to_page(table);
>> + if (put_page_testzero(page)) {
>> + if (!kernel)
>> + pgtable_page_dtor(page);
>> + reset_page_mapcount(page);
>> + free_hot_cold_page(page, 0);
>> + }
>> +}
>> +
>> +#ifdef CONFIG_SMP
>> +static void page_table_free_rcu(void *table)
>> +{
>> + struct page *page = virt_to_page(table);
>> + if (put_page_testzero(page)) {
>> + pgtable_page_dtor(page);
>> + reset_page_mapcount(page);
>> + free_hot_cold_page(page, 0);
>> + }
>> +}
>> +
>> +void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
>> +{
>> + unsigned long pgf = (unsigned long)table;
>> +
>> + BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
>> + pgf |= shift;
>> + tlb_remove_table(tlb, (void *)pgf);
>> +}
>> +
>> +void __tlb_remove_table(void *_table)
>> +{
>> + void *table = (void *)((unsigned long)_table & ~MAX_PGTABLE_INDEX_SIZE);
>> + unsigned shift = (unsigned long)_table & MAX_PGTABLE_INDEX_SIZE;
>> +
>> + if (!shift)
>> + /* PTE page needs special handling */
>> + page_table_free_rcu(table);
>> + else {
>> + BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
>> + kmem_cache_free(PGT_CACHE(shift), table);
>> + }
>> +}
>> +#else
>> +void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
>> +{
>> + if (!shift) {
>> + /* PTE page needs special handling */
>> + struct page *page = virt_to_page(table);
>> + if (put_page_testzero(page)) {
>> + pgtable_page_dtor(page);
>> + reset_page_mapcount(page);
>> + free_hot_cold_page(page, 0);
>> + }
>> + } else {
>> + BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
>> + kmem_cache_free(PGT_CACHE(shift), table);
>> + }
>> +}
>> +#endif
>> +#endif /* CONFIG_PPC_64K_PAGES */
>
> --
> David Gibson | I'll have my music baroque, and my code
> david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
> | _way_ _around_!
> http://www.ozlabs.org/~dgibson
^ permalink raw reply
* [patch] mm, hotplug: avoid compiling memory hotremove functions when disabled
From: David Rientjes @ 2013-04-10 6:07 UTC (permalink / raw)
To: Andrew Morton
Cc: Toshi Kani, Wen Congyang, linux-kernel, Tang Chen, linux-mm,
Yasuaki Ishimatsu, Paul Mackerras, Greg Kroah-Hartman,
linuxppc-dev
In-Reply-To: <alpine.DEB.2.02.1304092155220.25293@chino.kir.corp.google.com>
__remove_pages() is only necessary for CONFIG_MEMORY_HOTREMOVE. PowerPC
pseries will return -EOPNOTSUPP if unsupported.
Adding an #ifdef causes several other functions it depends on to also
become unnecessary, which saves in .text when disabled (it's disabled in
most defconfigs besides powerpc, including x86). remove_memory_block()
becomes static since it is not referenced outside of
drivers/base/memory.c.
Build tested on x86 and powerpc with CONFIG_MEMORY_HOTREMOVE both enabled
and disabled.
Signed-off-by: David Rientjes <rientjes@google.com>
---
arch/powerpc/platforms/pseries/hotplug-memory.c | 12 +++++
drivers/base/memory.c | 44 +++++++--------
include/linux/memory.h | 3 +-
include/linux/memory_hotplug.h | 4 +-
mm/memory_hotplug.c | 68 +++++++++++------------
mm/sparse.c | 72 +++++++++++++------------
6 files changed, 113 insertions(+), 90 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -72,6 +72,7 @@ unsigned long memory_block_size_bytes(void)
return get_memblock_size();
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
{
unsigned long start, start_pfn;
@@ -153,6 +154,17 @@ static int pseries_remove_memory(struct device_node *np)
ret = pseries_remove_memblock(base, lmb_size);
return ret;
}
+#else
+static inline int pseries_remove_memblock(unsigned long base,
+ unsigned int memblock_size)
+{
+ return -EOPNOTSUPP;
+}
+static inline int pseries_remove_memory(struct device_node *np)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
static int pseries_add_memory(struct device_node *np)
{
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -93,16 +93,6 @@ int register_memory(struct memory_block *memory)
return error;
}
-static void
-unregister_memory(struct memory_block *memory)
-{
- BUG_ON(memory->dev.bus != &memory_subsys);
-
- /* drop the ref. we got in remove_memory_block() */
- kobject_put(&memory->dev.kobj);
- device_unregister(&memory->dev);
-}
-
unsigned long __weak memory_block_size_bytes(void)
{
return MIN_MEMORY_BLOCK_SIZE;
@@ -637,8 +627,28 @@ static int add_memory_section(int nid, struct mem_section *section,
return ret;
}
-int remove_memory_block(unsigned long node_id, struct mem_section *section,
- int phys_device)
+/*
+ * need an interface for the VM to add new memory regions,
+ * but without onlining it.
+ */
+int register_new_memory(int nid, struct mem_section *section)
+{
+ return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
+}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+static void
+unregister_memory(struct memory_block *memory)
+{
+ BUG_ON(memory->dev.bus != &memory_subsys);
+
+ /* drop the ref. we got in remove_memory_block() */
+ kobject_put(&memory->dev.kobj);
+ device_unregister(&memory->dev);
+}
+
+static int remove_memory_block(unsigned long node_id,
+ struct mem_section *section, int phys_device)
{
struct memory_block *mem;
@@ -661,15 +671,6 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
return 0;
}
-/*
- * need an interface for the VM to add new memory regions,
- * but without onlining it.
- */
-int register_new_memory(int nid, struct mem_section *section)
-{
- return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
-}
-
int unregister_memory_section(struct mem_section *section)
{
if (!present_section(section))
@@ -677,6 +678,7 @@ int unregister_memory_section(struct mem_section *section)
return remove_memory_block(0, section, 0);
}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
/*
* offline one memory block. If the memory block has been offlined, do nothing.
diff --git a/include/linux/memory.h b/include/linux/memory.h
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -114,9 +114,10 @@ extern void unregister_memory_notifier(struct notifier_block *nb);
extern int register_memory_isolate_notifier(struct notifier_block *nb);
extern void unregister_memory_isolate_notifier(struct notifier_block *nb);
extern int register_new_memory(int, struct mem_section *);
+#ifdef CONFIG_MEMORY_HOTREMOVE
extern int unregister_memory_section(struct mem_section *);
+#endif
extern int memory_dev_init(void);
-extern int remove_memory_block(unsigned long, struct mem_section *, int);
extern int memory_notify(unsigned long val, void *v);
extern int memory_isolate_notify(unsigned long val, void *v);
extern struct memory_block *find_memory_block_hinted(struct mem_section *,
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -97,13 +97,13 @@ extern void __online_page_free(struct page *page);
#ifdef CONFIG_MEMORY_HOTREMOVE
extern bool is_pageblock_removable_nolock(struct page *page);
extern int arch_remove_memory(u64 start, u64 size);
+extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
+ unsigned long nr_pages);
#endif /* CONFIG_MEMORY_HOTREMOVE */
/* reasonably generic interface to expand the physical pages in a zone */
extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn,
unsigned long nr_pages);
-extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
- unsigned long nr_pages);
#ifdef CONFIG_NUMA
extern int memory_add_physaddr_to_nid(u64 start);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -436,6 +436,40 @@ static int __meminit __add_section(int nid, struct zone *zone,
return register_new_memory(nid, __pfn_to_section(phys_start_pfn));
}
+/*
+ * Reasonably generic function for adding memory. It is
+ * expected that archs that support memory hotplug will
+ * call this function after deciding the zone to which to
+ * add the new pages.
+ */
+int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
+ unsigned long nr_pages)
+{
+ unsigned long i;
+ int err = 0;
+ int start_sec, end_sec;
+ /* during initialize mem_map, align hot-added range to section */
+ start_sec = pfn_to_section_nr(phys_start_pfn);
+ end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
+
+ for (i = start_sec; i <= end_sec; i++) {
+ err = __add_section(nid, zone, i << PFN_SECTION_SHIFT);
+
+ /*
+ * EEXIST is finally dealt with by ioresource collision
+ * check. see add_memory() => register_memory_resource()
+ * Warning will be printed if there is collision.
+ */
+ if (err && (err != -EEXIST))
+ break;
+ err = 0;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(__add_pages);
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
/* find the smallest valid pfn in the range [start_pfn, end_pfn) */
static int find_smallest_section_pfn(int nid, struct zone *zone,
unsigned long start_pfn,
@@ -658,39 +692,6 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)
return 0;
}
-/*
- * Reasonably generic function for adding memory. It is
- * expected that archs that support memory hotplug will
- * call this function after deciding the zone to which to
- * add the new pages.
- */
-int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
- unsigned long nr_pages)
-{
- unsigned long i;
- int err = 0;
- int start_sec, end_sec;
- /* during initialize mem_map, align hot-added range to section */
- start_sec = pfn_to_section_nr(phys_start_pfn);
- end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
-
- for (i = start_sec; i <= end_sec; i++) {
- err = __add_section(nid, zone, i << PFN_SECTION_SHIFT);
-
- /*
- * EEXIST is finally dealt with by ioresource collision
- * check. see add_memory() => register_memory_resource()
- * Warning will be printed if there is collision.
- */
- if (err && (err != -EEXIST))
- break;
- err = 0;
- }
-
- return err;
-}
-EXPORT_SYMBOL_GPL(__add_pages);
-
/**
* __remove_pages() - remove sections of pages from a zone
* @zone: zone from which pages need to be removed
@@ -726,6 +727,7 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
return ret;
}
EXPORT_SYMBOL_GPL(__remove_pages);
+#endif /* CONFIG_MEMORY_HOTREMOVE */
int set_online_page_callback(online_page_callback_t callback)
{
diff --git a/mm/sparse.c b/mm/sparse.c
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -620,6 +620,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
vmemmap_free(start, end);
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
{
unsigned long start = (unsigned long)memmap;
@@ -627,6 +628,7 @@ static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
vmemmap_free(start, end);
}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
#else
static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
{
@@ -664,6 +666,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
get_order(sizeof(struct page) * nr_pages));
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
{
unsigned long maps_section_nr, removing_section_nr, i;
@@ -690,40 +693,9 @@ static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
put_page_bootmem(page);
}
}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
-static void free_section_usemap(struct page *memmap, unsigned long *usemap)
-{
- struct page *usemap_page;
- unsigned long nr_pages;
-
- if (!usemap)
- return;
-
- usemap_page = virt_to_page(usemap);
- /*
- * Check to see if allocation came from hot-plug-add
- */
- if (PageSlab(usemap_page) || PageCompound(usemap_page)) {
- kfree(usemap);
- if (memmap)
- __kfree_section_memmap(memmap, PAGES_PER_SECTION);
- return;
- }
-
- /*
- * The usemap came from bootmem. This is packed with other usemaps
- * on the section which has pgdat at boot time. Just keep it as is now.
- */
-
- if (memmap) {
- nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
- >> PAGE_SHIFT;
-
- free_map_bootmem(memmap, nr_pages);
- }
-}
-
/*
* returns the number of sections whose mem_maps were properly
* set. If this is <=0, then that means that the passed-in
@@ -800,6 +772,39 @@ static inline void clear_hwpoisoned_pages(struct page *memmap, int nr_pages)
}
#endif
+#ifdef CONFIG_MEMORY_HOTREMOVE
+static void free_section_usemap(struct page *memmap, unsigned long *usemap)
+{
+ struct page *usemap_page;
+ unsigned long nr_pages;
+
+ if (!usemap)
+ return;
+
+ usemap_page = virt_to_page(usemap);
+ /*
+ * Check to see if allocation came from hot-plug-add
+ */
+ if (PageSlab(usemap_page) || PageCompound(usemap_page)) {
+ kfree(usemap);
+ if (memmap)
+ __kfree_section_memmap(memmap, PAGES_PER_SECTION);
+ return;
+ }
+
+ /*
+ * The usemap came from bootmem. This is packed with other usemaps
+ * on the section which has pgdat at boot time. Just keep it as is now.
+ */
+
+ if (memmap) {
+ nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
+ >> PAGE_SHIFT;
+
+ free_map_bootmem(memmap, nr_pages);
+ }
+}
+
void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
{
struct page *memmap = NULL;
@@ -819,4 +824,5 @@ void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
clear_hwpoisoned_pages(memmap, PAGES_PER_SECTION);
free_section_usemap(memmap, usemap);
}
-#endif
+#endif /* CONFIG_MEMORY_HOTREMOVE */
+#endif /* CONFIG_MEMORY_HOTPLUG */
^ permalink raw reply
* Re: [RFC PATCH v2 6/6] powerpc: Use generic code for exception handling
From: Li Zhong @ 2013-04-10 5:56 UTC (permalink / raw)
To: Michael Ellerman; +Cc: fweisbec, paulmck, paulus, linux-kernel, linuxppc-dev
In-Reply-To: <1365571931.10616.12.camel@ThinkPad-T5421>
On Wed, 2013-04-10 at 13:32 +0800, Li Zhong wrote:
> On Wed, 2013-04-10 at 14:56 +1000, Michael Ellerman wrote:
> > On Fri, Mar 29, 2013 at 06:00:21PM +0800, Li Zhong wrote:
> > > After the exception handling moved to generic code, and some changes in
> > ...
> > > diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> > > index 360fba8..eeab30f 100644
> > > --- a/arch/powerpc/mm/hash_utils_64.c
> > > +++ b/arch/powerpc/mm/hash_utils_64.c
> > > @@ -33,6 +33,7 @@
> > > #include <linux/init.h>
> > > #include <linux/signal.h>
> > > #include <linux/memblock.h>
> > > +#include <linux/context_tracking.h>
> > >
> > > #include <asm/processor.h>
> > > #include <asm/pgtable.h>
> > > @@ -56,7 +57,6 @@
> > > #include <asm/fadump.h>
> > > #include <asm/firmware.h>
> > > #include <asm/tm.h>
> > > -#include <asm/context_tracking.h>
> > >
> > > #ifdef DEBUG
> > > #define DBG(fmt...) udbg_printf(fmt)
> > > @@ -919,13 +919,17 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
> > > const struct cpumask *tmp;
> > > int rc, user_region = 0, local = 0;
> > > int psize, ssize;
> > > + enum ctx_state prev_state;
> > > +
> > > + prev_state = exception_enter();
> > >
> > > DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n",
> > > ea, access, trap);
> > >
> > > if ((ea & ~REGION_MASK) >= PGTABLE_RANGE) {
> > > DBG_LOW(" out of pgtable range !\n");
> > > - return 1;
> > > + rc = 1;
> > > + goto exit;
> > > }
> > >
> > > /* Get region & vsid */
> >
> > This no longer applies on mainline, please send an updated version.
>
> Yes, for current mainline (powerpc tree), only previous five patches
> could be applied. The dependency of this patch is current in tip tree,
> and seems would be in for 3.10.
>
> There are some more details in the cover letter (#0):
>
> "I assume these patches would get in through powerpc tree, so I didn't
> combine the new patch (#6) with the original one (#2). So that if
> powerpc tree picks these, it could pick the first five patches, and
> apply patch #6 later when the dependency enters into powerpc tree (maybe
> on some 3.10-rcs)."
And I will send an updated version of this one when I see the dependency
commits in mainline.
Thanks, Zhong
> Thanks, Zhong
>
> > cheers
> >
>
^ permalink raw reply
* Re: [RFC PATCH v2 6/6] powerpc: Use generic code for exception handling
From: Li Zhong @ 2013-04-10 5:32 UTC (permalink / raw)
To: Michael Ellerman; +Cc: fweisbec, paulmck, paulus, linux-kernel, linuxppc-dev
In-Reply-To: <20130410045659.GB15929@concordia>
On Wed, 2013-04-10 at 14:56 +1000, Michael Ellerman wrote:
> On Fri, Mar 29, 2013 at 06:00:21PM +0800, Li Zhong wrote:
> > After the exception handling moved to generic code, and some changes in
> ...
> > diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> > index 360fba8..eeab30f 100644
> > --- a/arch/powerpc/mm/hash_utils_64.c
> > +++ b/arch/powerpc/mm/hash_utils_64.c
> > @@ -33,6 +33,7 @@
> > #include <linux/init.h>
> > #include <linux/signal.h>
> > #include <linux/memblock.h>
> > +#include <linux/context_tracking.h>
> >
> > #include <asm/processor.h>
> > #include <asm/pgtable.h>
> > @@ -56,7 +57,6 @@
> > #include <asm/fadump.h>
> > #include <asm/firmware.h>
> > #include <asm/tm.h>
> > -#include <asm/context_tracking.h>
> >
> > #ifdef DEBUG
> > #define DBG(fmt...) udbg_printf(fmt)
> > @@ -919,13 +919,17 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
> > const struct cpumask *tmp;
> > int rc, user_region = 0, local = 0;
> > int psize, ssize;
> > + enum ctx_state prev_state;
> > +
> > + prev_state = exception_enter();
> >
> > DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n",
> > ea, access, trap);
> >
> > if ((ea & ~REGION_MASK) >= PGTABLE_RANGE) {
> > DBG_LOW(" out of pgtable range !\n");
> > - return 1;
> > + rc = 1;
> > + goto exit;
> > }
> >
> > /* Get region & vsid */
>
> This no longer applies on mainline, please send an updated version.
Yes, for current mainline (powerpc tree), only previous five patches
could be applied. The dependency of this patch is current in tip tree,
and seems would be in for 3.10.
There are some more details in the cover letter (#0):
"I assume these patches would get in through powerpc tree, so I didn't
combine the new patch (#6) with the original one (#2). So that if
powerpc tree picks these, it could pick the first five patches, and
apply patch #6 later when the dependency enters into powerpc tree (maybe
on some 3.10-rcs)."
Thanks, Zhong
> cheers
>
^ permalink raw reply
* Re: [RFC PATCH powerpc] try secondary hash before BUG in kernel_map_linear_page()
From: Li Zhong @ 2013-04-10 5:29 UTC (permalink / raw)
To: Michael Ellerman; +Cc: Paul Mackerras, PowerPC email list
In-Reply-To: <20130410022107.GA15929@concordia>
On Wed, 2013-04-10 at 12:21 +1000, Michael Ellerman wrote:
> On Mon, Feb 25, 2013 at 05:29:35PM +0800, Li Zhong wrote:
> > This patch tries to fix following issue when CONFIG_DEBUG_PAGEALLOC
> > is enabled:
> >
> > [ 543.075675] ------------[ cut here ]------------
> > [ 543.075701] kernel BUG at arch/powerpc/mm/hash_utils_64.c:1239!
> > [ 543.075714] Oops: Exception in kernel mode, sig: 5 [#1]
Hi Michael,
Thanks for the review.
> So the issue is that kernel_map_linear_page() doesn't try the secondary
> hash slot.
It seems so.
> > The code is borrowed from that in __hash_page_huge().
>
> It is, and in fact there is another copy in hash_low_64.S - in assembler.
>
> So I think we should at least try and keep ourselves to two
> implementations, one in asm and one in C. So can you split it out into a
> helper routine called by both kernel_map_linear_page() and
> __hash_page_huge() ?
OK, I'll try to update it as you suggested.
Thanks, Zhong
> cheers
>
^ permalink raw reply
* RE: [PATCH 2/2] powerpc/dma/raidengine: enable Freescale RaidEngine device
From: Shi Xuelin-B29237 @ 2013-04-10 5:07 UTC (permalink / raw)
To: dan.j.williams@gmail.com, vinod.koul@intel.com
Cc: linuxppc-dev@lists.ozlabs.org, Burmi Naveen-B16502,
Rai Harninder-B01044, linux-kernel@vger.kernel.org,
iws@ovro.caltech.edu
In-Reply-To: <1353488481-14371-2-git-send-email-b29237@freescale.com>
SGkgRGFuICYgdmlub2QsDQoNCkRvIHlvdSBoYXZlIGFueSBjb21tZW50cyBhYm91dCB0aGlzIHBh
dGNoPw0KDQpUaGFua3MsDQpGb3JyZXN0DQoNCi0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQpG
cm9tOiBTaGkgWHVlbGluLUIyOTIzNyANClNlbnQ6IDIwMTLE6jEx1MIyMcjVIDE3OjAxDQpUbzog
ZGFuLmoud2lsbGlhbXNAZ21haWwuY29tOyB2aW5vZC5rb3VsQGludGVsLmNvbTsgbGludXhwcGMt
ZGV2QGxpc3RzLm96bGFicy5vcmc7IGxpbnV4LWtlcm5lbEB2Z2VyLmtlcm5lbC5vcmcNCkNjOiBp
d3NAb3Zyby5jYWx0ZWNoLmVkdTsgU2hpIFh1ZWxpbi1CMjkyMzc7IFJhaSBIYXJuaW5kZXItQjAx
MDQ0OyBCdXJtaSBOYXZlZW4tQjE2NTAyDQpTdWJqZWN0OiBbUEFUQ0ggMi8yXSBwb3dlcnBjL2Rt
YS9yYWlkZW5naW5lOiBlbmFibGUgRnJlZXNjYWxlIFJhaWRFbmdpbmUgZGV2aWNlDQoNCkZyb206
IFh1ZWxpbiBTaGkgPGIyOTIzN0BmcmVlc2NhbGUuY29tPg0KDQpUaGUgUmFpZEVuZ2luZSBpcyBh
IG5ldyBGU0wgaGFyZHdhcmUgdGhhdCB1c2VkIGFzIGhhcmR3YXJlIGFjY2VyYXRpb24gZm9yIFJB
SUQ1LzYuDQoNClRoaXMgcGF0Y2ggZW5hYmxlcyB0aGUgUmFpZEVuZ2luZSBmdW5jdGlvbmFsaXR5
IGFuZCBwcm92aWRlcyBoYXJkd2FyZSBvZmZsb2FkaW5nIGNhcGFiaWxpdHkgZm9yIG1lbWNweSwg
eG9yIGFuZCByYWlkNiBwcSBjb21wdXRhdGlvbi4gSXQgd29ya3MgdW5kZXIgZG1hZW5naW5lIGNv
bnRyb2wgd2l0aCBhc3luY19sYXllciBpbnRlcmZhY2UuDQoNClNpZ25lZC1vZmYtYnk6IEhhcm5p
bmRlciBSYWkgPGhhcm5pbmRlci5yYWlAZnJlZXNjYWxlLmNvbT4NClNpZ25lZC1vZmYtYnk6IE5h
dmVlbiBCdXJtaSA8bmF2ZWVuYnVybWlAZnJlZXNjYWxlLmNvbT4NClNpZ25lZC1vZmYtYnk6IFh1
ZWxpbiBTaGkgPGIyOTIzN0BmcmVlc2NhbGUuY29tPg0KLS0tDQogZHJpdmVycy9kbWEvS2NvbmZp
ZyAgICB8ICAgMTQgKw0KIGRyaXZlcnMvZG1hL01ha2VmaWxlICAgfCAgICAxICsNCiBkcml2ZXJz
L2RtYS9mc2xfcmFpZC5jIHwgIDk5MCArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrKysNCiBkcml2ZXJzL2RtYS9mc2xfcmFpZC5oIHwgIDMxNyArKysrKysrKysr
KysrKysrDQogNCBmaWxlcyBjaGFuZ2VkLCAxMzIyIGluc2VydGlvbnMoKykNCiBjcmVhdGUgbW9k
ZSAxMDA2NDQgZHJpdmVycy9kbWEvZnNsX3JhaWQuYyAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZl
cnMvZG1hL2ZzbF9yYWlkLmgNCg0KZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1hL0tjb25maWcgYi9k
cml2ZXJzL2RtYS9LY29uZmlnIGluZGV4IGQ0YzEyMTguLmFhMzcyNzkgMTAwNjQ0DQotLS0gYS9k
cml2ZXJzL2RtYS9LY29uZmlnDQorKysgYi9kcml2ZXJzL2RtYS9LY29uZmlnDQpAQCAtMzIwLDYg
KzMyMCwyMCBAQCBjb25maWcgTU1QX1BETUENCiAJaGVscA0KIAkgIFN1cHBvcnQgdGhlIE1NUCBQ
RE1BIGVuZ2luZSBmb3IgUFhBIGFuZCBNTVAgcGxhdGZyb20uDQogDQorY29uZmlnIEZTTF9SQUlE
DQorICAgICAgICB0cmlzdGF0ZSAiRnJlZXNjYWxlIFJBSUQgRW5naW5lIERldmljZSBEcml2ZXIi
DQorICAgICAgICBkZXBlbmRzIG9uIEZTTF9TT0MgJiYgIUZTTF9ETUENCisgICAgICAgIHNlbGVj
dCBETUFfRU5HSU5FDQorICAgICAgICBzZWxlY3QgQVNZTkNfVFhfRU5BQkxFX0NIQU5ORUxfU1dJ
VENIDQorICAgICAgICBzZWxlY3QgQVNZTkNfTUVNQ1BZDQorICAgICAgICBzZWxlY3QgQVNZTkNf
WE9SDQorICAgICAgICBzZWxlY3QgQVNZTkNfUFENCisgICAgICAgIC0tLWhlbHAtLS0NCisgICAg
ICAgICAgRW5hYmxlIHN1cHBvcnQgZm9yIEZyZWVzY2FsZSBSQUlEIEVuZ2luZS4gUkFJRCBFbmdp
bmUgaXMNCisgICAgICAgICAgYXZhaWxhYmxlIG9uIHNvbWUgUW9ySVEgU29DcyAobGlrZSBQNTAy
MCkuIEl0IGhhcw0KKyAgICAgICAgICB0aGUgY2FwYWJpbGl0eSB0byBvZmZsb2FkIFJBSUQ1L1JB
SUQ2IG9wZXJhdGlvbnMgZnJvbSBDUFUuDQorICAgICAgICAgIFJBSUQ1IGlzIFhPUiBhbmQgbWVt
Y3B5LiBSQUlENiBpcyBQL1EgYW5kIG1lbWNweQ0KKw0KIGNvbmZpZyBETUFfRU5HSU5FDQogCWJv
b2wNCiANCmRpZmYgLS1naXQgYS9kcml2ZXJzL2RtYS9NYWtlZmlsZSBiL2RyaXZlcnMvZG1hL01h
a2VmaWxlIGluZGV4IDc0MjhmZWEuLjI5YjY1ZWIgMTAwNjQ0DQotLS0gYS9kcml2ZXJzL2RtYS9N
YWtlZmlsZQ0KKysrIGIvZHJpdmVycy9kbWEvTWFrZWZpbGUNCkBAIC05LDYgKzksNyBAQCBvYmot
JChDT05GSUdfRE1BVEVTVCkgKz0gZG1hdGVzdC5vDQogb2JqLSQoQ09ORklHX0lOVEVMX0lPQVRE
TUEpICs9IGlvYXQvDQogb2JqLSQoQ09ORklHX0lOVEVMX0lPUF9BRE1BKSArPSBpb3AtYWRtYS5v
DQogb2JqLSQoQ09ORklHX0ZTTF9ETUEpICs9IGZzbGRtYS5vDQorb2JqLSQoQ09ORklHX0ZTTF9S
QUlEKSArPSBmc2xfcmFpZC5vDQogb2JqLSQoQ09ORklHX01QQzUxMlhfRE1BKSArPSBtcGM1MTJ4
X2RtYS5vDQogb2JqLSQoQ09ORklHX01WX1hPUikgKz0gbXZfeG9yLm8NCiBvYmotJChDT05GSUdf
RFdfRE1BQykgKz0gZHdfZG1hYy5vDQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9kbWEvZnNsX3JhaWQu
YyBiL2RyaXZlcnMvZG1hL2ZzbF9yYWlkLmMgbmV3IGZpbGUgbW9kZSAxMDA2NDQgaW5kZXggMDAw
MDAwMC4uZWMxOTgxNw0KLS0tIC9kZXYvbnVsbA0KKysrIGIvZHJpdmVycy9kbWEvZnNsX3JhaWQu
Yw0KQEAgLTAsMCArMSw5OTAgQEANCisvKg0KKyAqIGRyaXZlcnMvZG1hL2ZzbF9yYWlkLmMNCisg
Kg0KKyAqIEZyZWVzY2FsZSBSQUlEIEVuZ2luZSBkZXZpY2UgZHJpdmVyDQorICoNCisgKiBBdXRo
b3I6DQorICoJSGFybmluZGVyIFJhaSA8aGFybmluZGVyLnJhaUBmcmVlc2NhbGUuY29tPg0KKyAq
CU5hdmVlbiBCdXJtaSA8bmF2ZWVuYnVybWlAZnJlZXNjYWxlLmNvbT4NCisgKg0KKyAqIENvcHly
aWdodCAoYykgMjAxMC0yMDEyIEZyZWVzY2FsZSBTZW1pY29uZHVjdG9yLCBJbmMuDQorICoNCisg
KiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRo
IG9yIHdpdGhvdXQNCisgKiBtb2RpZmljYXRpb24sIGFyZSBwZXJtaXR0ZWQgcHJvdmlkZWQgdGhh
dCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnMgYXJlIG1ldDoNCisgKiAgICAgKiBSZWRpc3RyaWJ1
dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodA0KKyAq
ICAgICAgIG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcg
ZGlzY2xhaW1lci4NCisgKiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVz
dCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KKyAqICAgICAgIG5vdGljZSwgdGhpcyBs
aXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUNCisg
KiAgICAgICBkb2N1bWVudGF0aW9uIGFuZC9vciBvdGhlciBtYXRlcmlhbHMgcHJvdmlkZWQgd2l0
aCB0aGUgZGlzdHJpYnV0aW9uLg0KKyAqICAgICAqIE5laXRoZXIgdGhlIG5hbWUgb2YgRnJlZXNj
YWxlIFNlbWljb25kdWN0b3Igbm9yIHRoZQ0KKyAqICAgICAgIG5hbWVzIG9mIGl0cyBjb250cmli
dXRvcnMgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzDQorICogICAg
ICAgZGVyaXZlZCBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYyBwcmlvciB3cml0
dGVuIHBlcm1pc3Npb24uDQorICoNCisgKiBBTFRFUk5BVElWRUxZLCB0aGlzIHNvZnR3YXJlIG1h
eSBiZSBkaXN0cmlidXRlZCB1bmRlciB0aGUgdGVybXMgb2YgDQordGhlDQorICogR05VIEdlbmVy
YWwgUHVibGljIExpY2Vuc2UgKCJHUEwiKSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdh
cmUNCisgKiBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAyIG9mIHRoYXQgTGljZW5zZSBvciAo
YXQgeW91ciBvcHRpb24pIGFueQ0KKyAqIGxhdGVyIHZlcnNpb24uDQorICoNCisgKiBUSElTIFNP
RlRXQVJFIElTIFBST1ZJREVEIEJZIEZyZWVzY2FsZSBTZW1pY29uZHVjdG9yIGBgQVMgSVMnJyBB
TkQgDQorQU5ZDQorICogRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywg
QlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUgDQorSU1QTElFRA0KKyAqIFdBUlJBTlRJRVMgT0YgTUVS
Q0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSANCitBUkUN
CisgKiBESVNDTEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBGcmVlc2NhbGUgU2VtaWNvbmR1Y3Rv
ciBCRSBMSUFCTEUgRk9SIA0KK0FOWQ0KKyAqIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUws
IFNQRUNJQUwsIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTCANCitEQU1BR0VTDQorICogKElO
Q0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdP
T0RTIE9SIA0KK1NFUlZJQ0VTOw0KKyAqIExPU1MgT0YgVVNFLCBEQVRBLCBPUiBQUk9GSVRTOyBP
UiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgDQorQ0FVU0VEIEFORA0KKyAqIE9OIEFO
WSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklM
SVRZLCANCitPUiBUT1JUDQorICogKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkg
QVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgDQorVVNFIE9GIFRISVMNCisgKiBTT0ZUV0FS
RSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS4NCisg
Kg0KKyAqIFRoZW9yeSBvZiBvcGVyYXRpb246DQorICoNCisgKiBHZW5lcmFsIGNhcGFiaWxpdGll
czoNCisgKglSQUlEIEVuZ2luZSAoUkUpIGJsb2NrIGlzIGNhcGFibGUgb2Ygb2ZmbG9hZGluZyBY
T1IsIG1lbWNweSBhbmQgUC9RDQorICoJY2FsY3VsYXRpb25zIHJlcXVpcmVkIGluIFJBSUQ1IGFu
ZCBSQUlENiBvcGVyYXRpb25zLiBSRSBkcml2ZXINCisgKglyZWdpc3RlcnMgd2l0aCBMaW51eCdz
IEFTWU5DIGxheWVyIGFzIGRtYSBkcml2ZXIuIFJFIGhhcmR3YXJlDQorICoJbWFpbnRhaW5zIHN0
cmljdCBvcmRlcmluZyBvZiB0aGUgcmVxdWVzdHMgdGhyb3VnaCBjaGFpbmVkDQorICoJY29tbWFu
ZCBxdWV1ZWluZy4NCisgKg0KKyAqIERhdGEgZmxvdzoNCisgKglTb2Z0d2FyZSBSQUlEIGxheWVy
IG9mIExpbnV4IChNRCBsYXllcikgbWFpbnRhaW5zIFJBSUQgcGFydGl0aW9ucywNCisgKglzdHJp
cHMsIHN0cmlwZXMgZXRjLiBJdCBzZW5kcyByZXF1ZXN0cyB0byB0aGUgdW5kZXJseWluZyBBWVNO
QyBsYXllcg0KKyAqCXdoaWNoIGZ1cnRoZXIgcGFzc2VzIGl0IHRvIFJFIGRyaXZlci4gQVNZTkMg
bGF5ZXIgZGVjaWRlcyB3aGljaCByZXF1ZXN0DQorICoJZ29lcyB0byB3aGljaCBqb2IgcmluZyBv
ZiBSRSBoYXJkd2FyZS4gRm9yIGV2ZXJ5IHJlcXVlc3QgcHJvY2Vzc2VkIGJ5DQorICoJUkFJRCBF
bmdpbmUsIGRyaXZlciBnZXRzIGFuIGludGVycnVwdCB1bmxlc3MgY29hbGVzY2luZyBpcyBzZXQu
IFRoZQ0KKyAqCXBlciBqb2IgcmluZyBpbnRlcnJ1cHQgaGFuZGxlciBjaGVja3MgdGhlIHN0YXR1
cyByZWdpc3RlciBmb3IgZXJyb3JzLA0KKyAqCWNsZWFycyB0aGUgaW50ZXJydXB0IGFuZCBzY2hl
ZHVsZXMgYSB0YXNrbGV0LiBNYWluIHJlcXVlc3QgcHJvY2Vzc2luZw0KKyAqCWlzIGRvbmUgaW4g
dGFza2xldC4gQSBzb2Z0d2FyZSBzaGFkb3cgY29weSBvZiB0aGUgSFcgcmluZyBpcyBrZXB0IHRv
DQorICoJbWFpbnRhaW4gdmlydHVhbCB0byBwaHlzaWNhbCB0cmFuc2xhdGlvbi4gQmFzZWQgb24g
dGhlIGludGVybmFsIGluZGV4ZXMNCisgKgltYWludGFpbmVkLCB0aGUgdGFza2xldCBwaWNrcyB0
aGUgZGVzY3JpcHRvciBhZGRyZXNzIGZyb20gc2hhZG93IGNvcHksDQorICoJdXBkYXRlcyB0aGUg
Y29ycmVzcG9uZGluZyBjb29raWUsIHVwZGF0ZXMgdGhlIG91dGJvdW5kIHJpbmcgam9iIHJlbW92
ZWQNCisgKglyZWdpc3RlciBpbiBSRSBoYXJkd2FyZSBhbmQgZXZlbnR1YWxseSBjYWxscyB0aGUg
Y2FsbGJhY2sgZnVuY3Rpb24uIFRoaXMNCisgKgljYWxsYmFjayBmdW5jdGlvbiBnZXRzIHBhc3Nl
ZCBhcyBwYXJ0IG9mIHJlcXVlc3QgZnJvbSBNRCBsYXllci4NCisgKi8NCisNCisjaW5jbHVkZSA8
bGludXgvaW50ZXJydXB0Lmg+DQorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KKyNpbmNsdWRl
IDxsaW51eC9vZl9wbGF0Zm9ybS5oPg0KKyNpbmNsdWRlIDxsaW51eC9kbWEtbWFwcGluZy5oPg0K
KyNpbmNsdWRlIDxsaW51eC9kbWFwb29sLmg+DQorI2luY2x1ZGUgPGxpbnV4L2RtYWVuZ2luZS5o
Pg0KKyNpbmNsdWRlIDxsaW51eC9pby5oPg0KKyNpbmNsdWRlIDxsaW51eC9zcGlubG9jay5oPg0K
KyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+DQorDQorI2luY2x1ZGUgImZzbF9yYWlkLmgiDQorDQor
I2RlZmluZSBNQVhfWE9SX1NSQ1MJCTE2DQorI2RlZmluZSBNQVhfUFFfU1JDUwkJMTYNCisjZGVm
aW5lIE1BWF9JTklUSUFMX0RFU0NTCTI1Ng0KKyNkZWZpbmUgRlJBTUVfRk9STUFUCQkweDENCisj
ZGVmaW5lIE1BWF9EQVRBX0xFTkdUSAkJKDEwMjQqMTAyNCkNCisNCisjZGVmaW5lIHRvX2ZzbF9y
ZV9kbWFfZGVzYyh0eCkgY29udGFpbmVyX29mKHR4LCBcDQorCQlzdHJ1Y3QgZnNsX3JlX2RtYV9h
c3luY190eF9kZXNjLCBhc3luY190eCkNCisNCisvKiBBZGQgZGVzY3JpcHRvcnMgaW50byBwZXIg
anIgc29mdHdhcmUgcXVldWUgLSBzdWJtaXRfcSAqLyBzdGF0aWMgDQorZG1hX2Nvb2tpZV90IHJl
X2pyX3R4X3N1Ym1pdChzdHJ1Y3QgZG1hX2FzeW5jX3R4X2Rlc2NyaXB0b3IgKnR4KSB7DQorCXN0
cnVjdCBmc2xfcmVfZG1hX2FzeW5jX3R4X2Rlc2MgKmRlc2MgPSBOVUxMOw0KKwlzdHJ1Y3QgcmVf
anIgKmpyID0gTlVMTDsNCisJZG1hX2Nvb2tpZV90IGNvb2tpZTsNCisNCisJZGVzYyA9IGNvbnRh
aW5lcl9vZih0eCwgc3RydWN0IGZzbF9yZV9kbWFfYXN5bmNfdHhfZGVzYywgYXN5bmNfdHgpOw0K
KwlqciA9IGNvbnRhaW5lcl9vZih0eC0+Y2hhbiwgc3RydWN0IHJlX2pyLCBjaGFuKTsNCisNCisJ
c3Bpbl9sb2NrX2JoKCZqci0+aW5iX2xvY2spOw0KKw0KKwlqci0+dGltZXIuZGF0YSA9ICh1bnNp
Z25lZCBsb25nKXR4LT5jaGFuOw0KKwljb29raWUgPSBqci0+Y2hhbi5jb29raWUgKyAxOw0KKwlp
ZiAoY29va2llIDwgMCkNCisJCWNvb2tpZSA9IDE7DQorDQorCWRlc2MtPmFzeW5jX3R4LmNvb2tp
ZSA9IGNvb2tpZTsNCisJanItPmNoYW4uY29va2llID0gZGVzYy0+YXN5bmNfdHguY29va2llOw0K
Kwlqci0+cGVuZF9jb3VudCsrOw0KKw0KKwlpZiAoIXRpbWVyX3BlbmRpbmcoJmpyLT50aW1lcikp
DQorCQlhZGRfdGltZXIoJmpyLT50aW1lcik7DQorDQorCXNwaW5fdW5sb2NrX2JoKCZqci0+aW5i
X2xvY2spOw0KKw0KKwlyZXR1cm4gY29va2llOw0KK30NCisNCitzdGF0aWMgdm9pZCByZV9qcl91
bm1hcF9kZXN0X3NyYyhzdHJ1Y3QgZnNsX3JlX2RtYV9hc3luY190eF9kZXNjICpkZXNjKSANCit7
DQorCWludCBpLCBqOw0KKwlzdHJ1Y3QgY21wbmRfZnJhbWUgKmNmOw0KKwlkbWFfYWRkcl90IGRl
c3QxID0gMCwgZGVzdDIgPSAwLCBzcmM7DQorCXN0cnVjdCBkZXZpY2UgKmRldjsNCisJZW51bSBk
bWFfY3RybF9mbGFncyBmbGFnczsNCisJZW51bSBkbWFfZGF0YV9kaXJlY3Rpb24gZGlyOw0KKw0K
KwlCVUdfT04oIWRlc2MpOw0KKwljZiA9IGRlc2MtPmNmX2FkZHI7DQorCWRlc3QxID0gY2ZbMV0u
YWRkcmVzczsNCisJaiA9IDI7DQorCWlmIChkZXNjLT5kZXN0X2NudCA9PSAyKSB7DQorCQlkZXN0
MiA9IGNmWzJdLmFkZHJlc3M7DQorCQlqID0gMzsNCisJfQ0KKwlkZXYgPSBkZXNjLT5qci0+Y2hh
bi5kZXZpY2UtPmRldjsNCisJZmxhZ3MgPSBkZXNjLT5hc3luY190eC5mbGFnczsNCisJaWYgKCEo
ZmxhZ3MgJiBETUFfQ09NUExfU0tJUF9ERVNUX1VOTUFQKSkgew0KKwkJaWYgKGRlc2MtPmNkYl9v
cGNvZGUgPT0gUkVfTU9WRV9PUENPREUpDQorCQkJZGlyID0gRE1BX0ZST01fREVWSUNFOw0KKwkJ
ZWxzZQ0KKwkJCWRpciA9IERNQV9CSURJUkVDVElPTkFMOw0KKw0KKwkJZG1hX3VubWFwX3BhZ2Uo
ZGV2LCBkZXN0MSwgZGVzYy0+ZG1hX2xlbiwgZGlyKTsNCisNCisJCWlmIChkZXN0MikNCisJCQlk
bWFfdW5tYXBfcGFnZShkZXYsIGRlc3QyLCBkZXNjLT5kbWFfbGVuLCBkaXIpOw0KKwl9DQorDQor
CWlmICghKGZsYWdzICYgRE1BX0NPTVBMX1NLSVBfU1JDX1VOTUFQKSkgew0KKwkJZGlyID0gRE1B
X1RPX0RFVklDRTsNCisJCWZvciAoaSA9IGo7IGkgPCBkZXNjLT5zcmNfY250K2o7IGkrKykgew0K
KwkJCXNyYyA9IGNmW2ldLmFkZHJlc3M7DQorCQkJaWYgKHNyYyA9PSBkZXN0MSB8fCBzcmMgPT0g
ZGVzdDIpDQorCQkJCWNvbnRpbnVlOw0KKwkJCWRtYV91bm1hcF9wYWdlKGRldiwgc3JjLCBkZXNj
LT5kbWFfbGVuLCBkaXIpOw0KKwkJfQ0KKwl9DQorfQ0KKw0KK3N0YXRpYyB2b2lkIHJlX2pyX2Rl
c2NfZG9uZShzdHJ1Y3QgZnNsX3JlX2RtYV9hc3luY190eF9kZXNjICpkZXNjKSB7DQorCXN0cnVj
dCByZV9qciAqZG1hX2pyID0gZGVzYy0+anI7DQorCWRtYV9hc3luY190eF9jYWxsYmFjayBjYWxs
YmFjazsNCisJdm9pZCAqY2FsbGJhY2tfcGFyYW07DQorDQorCWNhbGxiYWNrID0gZGVzYy0+YXN5
bmNfdHguY2FsbGJhY2s7DQorCWNhbGxiYWNrX3BhcmFtID0gZGVzYy0+YXN5bmNfdHguY2FsbGJh
Y2tfcGFyYW07DQorDQorCWRtYV9ydW5fZGVwZW5kZW5jaWVzKCZkZXNjLT5hc3luY190eCk7DQor
DQorCWlmIChkbWFfanItPmNvbXBsZXRlZF9jb29raWUgPCBkZXNjLT5hc3luY190eC5jb29raWUp
IHsNCisJCWRtYV9qci0+Y29tcGxldGVkX2Nvb2tpZSA9IGRlc2MtPmFzeW5jX3R4LmNvb2tpZTsN
CisJCWlmIChkbWFfanItPmNvbXBsZXRlZF9jb29raWUgPT0gRE1BX01BWF9DT09LSUUpDQorCQkJ
ZG1hX2pyLT5jb21wbGV0ZWRfY29va2llID0gRE1BX01JTl9DT09LSUU7DQorCX0NCisNCisJcmVf
anJfdW5tYXBfZGVzdF9zcmMoZGVzYyk7DQorDQorCWlmIChjYWxsYmFjaykNCisJCWNhbGxiYWNr
KGNhbGxiYWNrX3BhcmFtKTsNCisNCit9DQorDQorLyoNCisgKiBHZXQgdGhlIHZpcnR1YWwgYWRk
cmVzcyBvZiBzb2Z0d2FyZSBkZXNjIGZyb20gdmlydF9hZGRyLg0KKyAqIFN0b3JpbmcgdGhlIGFk
ZHJlc3Mgb2Ygc29mdHdhcmUgZGVzYyBsaWtlIHRoaXMgbWFrZXMgdGhlDQorICogb3JkZXIgb2Yg
YWxvZ29yaXRobSBhcyBPKDEpDQorICovDQorc3RhdGljIHZvaWQgcmVfanJfZGVxdWV1ZSh1bnNp
Z25lZCBsb25nIGRhdGEpIHsNCisJc3RydWN0IGRldmljZSAqZGV2Ow0KKwlzdHJ1Y3QgcmVfanIg
KmpyOw0KKwlzdHJ1Y3QgZnNsX3JlX2RtYV9hc3luY190eF9kZXNjICpkZXNjOw0KKwl1bnNpZ25l
ZCBpbnQgY291bnQ7DQorCXN0cnVjdCBmc2xfcmVfZG1hX2FzeW5jX3R4X2Rlc2MgKmFja19kZXNj
ID0gTlVMTCwgKl9hY2tfZGVzYyA9IE5VTEw7DQorDQorCWRldiA9IChzdHJ1Y3QgZGV2aWNlICop
ZGF0YTsNCisJanIgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisNCisJd2hpbGUgKChjb3VudCA9
DQorCQlSRV9KUl9PVUJfU0xPVF9GVUxMKGluX2JlMzIoJmpyLT5qcnJlZ3MtPm91YnJpbmdfc2xv
dF9mdWxsKSkpKSB7DQorCQl3aGlsZSAoY291bnQtLSkgew0KKwkJCXNwaW5fbG9ja19iaCgmanIt
Pm91Yl9sb2NrKTsNCisJCQlqci0+b3ViX2NvdW50ICY9IFJJTkdfU0laRSAtIDE7DQorCQkJZGVz
YyA9ICZqci0+ZGVzY3NbanItPm91Yl9jb3VudCsrXTsNCisNCisJCQkvKiBPbmUgam9iIHByb2Nl
c3NlZCAqLw0KKwkJCW91dF9iZTMyKCZqci0+anJyZWdzLT5vdWJyaW5nX2pvYl9ybXZkLA0KKwkJ
CQlSRV9KUl9PVUJfSk9CX1JFTU9WRSgxKSk7DQorCQkJc3Bpbl91bmxvY2tfYmgoJmpyLT5vdWJf
bG9jayk7DQorDQorCQkJc3Bpbl9sb2NrX2JoKCZqci0+ZGVzY19sb2NrKTsNCisJCQlsaXN0X2Fk
ZF90YWlsKCZkZXNjLT5ub2RlLCAmanItPmFja19xKTsNCisJCQlyZV9qcl9kZXNjX2RvbmUoZGVz
Yyk7DQorCQkJc3Bpbl91bmxvY2tfYmgoJmpyLT5kZXNjX2xvY2spOw0KKwkJfQ0KKwl9DQorDQor
CS8qIFRvIHNhdmUgbWVtb3J5LCBwYXJzZSB0aGUgYWNrX3EgYW5kIGZyZWUgdXAgZGVzY3MgKi8N
CisJbGlzdF9mb3JfZWFjaF9lbnRyeV9zYWZlKGFja19kZXNjLCBfYWNrX2Rlc2MsICZqci0+YWNr
X3EsIG5vZGUpIHsNCisJCWlmIChhc3luY190eF90ZXN0X2FjaygmYWNrX2Rlc2MtPmFzeW5jX3R4
KSkgew0KKwkJCXNwaW5fbG9ja19iaCgmanItPmRlc2NfbG9jayk7DQorCQkJbGlzdF9kZWwoJmFj
a19kZXNjLT5ub2RlKTsNCisJCQlhY2tfZGVzYy0+c3RhdGUgPSBSRV9ERVNDX0VNUFRZOw0KKwkJ
CWFja19kZXNjLT5hc3luY190eC5mbGFncyA9IDA7DQorCQkJc3Bpbl91bmxvY2tfYmgoJmpyLT5k
ZXNjX2xvY2spOw0KKwkJfQ0KKwl9DQorfQ0KKw0KKy8qIFBlciBKb2IgUmluZyBpbnRlcnJ1cHQg
aGFuZGxlciAqLw0KK3N0YXRpYyBpcnFyZXR1cm5fdCByZV9qcl9pbnRlcnJ1cHQoaW50IGlycSwg
dm9pZCAqZGF0YSkgew0KKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSBkYXRhOw0KKwlzdHJ1Y3QgcmVf
anIgKmpyID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXUzMiBpcnFzdGF0ZSwgc3RhdHVzOw0K
Kw0KKwlpcnFzdGF0ZSA9IGluX2JlMzIoJmpyLT5qcnJlZ3MtPmpyX2ludGVycnVwdF9zdGF0dXMp
Ow0KKwlpZiAoIWlycXN0YXRlKQ0KKwkJcmV0dXJuIElSUV9OT05FOw0KKw0KKwkvKg0KKwkgKiBU
aGVyZSdzIG5vIHdheSBpbiB1cHBlciBsYXllciAocmVhZCBNRCBsYXllcikgdG8gcmVjb3ZlciBm
cm9tDQorCSAqIGVycm9yIGNvbmRpdGlvbnMgZXhjZXB0IHJlc3RhcnQgZXZlcnl0aGluZy4gSW4g
bG9uZyB0ZXJtIHdlDQorCSAqIG5lZWQgdG8gZG8gc29tZXRoaW5nIG1vcmUgdGhhbiBqdXN0IGNy
YXNoaW5nDQorCSAqLw0KKwlpZiAoaXJxc3RhdGUgJiBSRV9KUl9FUlJPUikgew0KKwkJc3RhdHVz
ID0gaW5fYmUzMigmanItPmpycmVncy0+anJfc3RhdHVzKTsNCisJCWRldl9lcnIoZGV2LCAiJXM6
IGpyIGVycm9yIGlycXN0YXRlOiAleCwgc3RhdHVzOiAleFxuIiwNCisJCQkJCV9fZnVuY19fLCBp
cnFzdGF0ZSwgc3RhdHVzKTsNCisNCisJCUJVRygpOw0KKwl9DQorDQorCS8qIENsZWFyIGludGVy
cnVwdCAqLw0KKwlvdXRfYmUzMigmanItPmpycmVncy0+anJfaW50ZXJydXB0X3N0YXR1cywgUkVf
SlJfQ0xFQVJfSU5UKTsNCisNCisJdGFza2xldF9zY2hlZHVsZSgmanItPmlycXRhc2spOw0KKw0K
KwlyZXR1cm4gSVJRX0hBTkRMRUQ7DQorfQ0KKw0KK3N0YXRpYyBlbnVtIGRtYV9zdGF0dXMgcmVf
anJfdHhfc3RhdHVzKHN0cnVjdCBkbWFfY2hhbiAqY2hhbiwNCisJCWRtYV9jb29raWVfdCBjb29r
aWUsIHN0cnVjdCBkbWFfdHhfc3RhdGUgKnR4c3RhdGUpIHsNCisJc3RydWN0IHJlX2pyICpqciA9
IE5VTEw7DQorCWRtYV9jb29raWVfdCBsYXN0X3VzZWQ7DQorCWRtYV9jb29raWVfdCBsYXN0X2Nv
bXBsZXRlOw0KKw0KKwlqciA9IGNvbnRhaW5lcl9vZihjaGFuLCBzdHJ1Y3QgcmVfanIsIGNoYW4p
Ow0KKwlsYXN0X3VzZWQgPSBjaGFuLT5jb29raWU7DQorCXNtcF9tYigpOw0KKwlsYXN0X2NvbXBs
ZXRlID0ganItPmNvbXBsZXRlZF9jb29raWU7DQorDQorCWRtYV9zZXRfdHhfc3RhdGUodHhzdGF0
ZSwgbGFzdF9jb21wbGV0ZSwgbGFzdF91c2VkLCAwKTsNCisNCisJcmV0dXJuIGRtYV9hc3luY19p
c19jb21wbGV0ZShjb29raWUsIGxhc3RfY29tcGxldGUsIGxhc3RfdXNlZCk7IH0NCisNCisNCisv
KiBDb3B5IGRlc2NyaXB0b3IgZnJvbSBwZXIganIgc29mdHdhcmUgcXVldWUgaW50byBoYXJkd2Fy
ZSBqb2IgcmluZyAqLyANCit2b2lkIHJlX2pyX2lzc3VlX3BlbmRpbmcoc3RydWN0IGRtYV9jaGFu
ICpjaGFuKSB7DQorCXN0cnVjdCByZV9qciAqanIgPSBOVUxMOw0KKwlpbnQgYXZhaWwgPSAwOw0K
Kw0KKwlqciA9IGNvbnRhaW5lcl9vZihjaGFuLCBzdHJ1Y3QgcmVfanIsIGNoYW4pOw0KKwlpZiAo
dGltZXJfcGVuZGluZygmanItPnRpbWVyKSkNCisJCWRlbF90aW1lcl9zeW5jKCZqci0+dGltZXIp
Ow0KKw0KKwlzcGluX2xvY2tfYmgoJmpyLT5pbmJfbG9jayk7DQorDQorCWF2YWlsID0gDQorUkVf
SlJfSU5CX1NMT1RfQVZBSUwoaW5fYmUzMigmanItPmpycmVncy0+aW5icmluZ19zbG90X2F2YWls
KSk7DQorDQorCWlmICghKGF2YWlsICYmIGpyLT5wZW5kX2NvdW50KSkNCisJCWdvdG8gb3V0X3Vu
bG9jazsNCisNCisJaWYgKGF2YWlsID4ganItPnBlbmRfY291bnQpDQorCQlhdmFpbCA9IGpyLT5w
ZW5kX2NvdW50Ow0KKw0KKwlqci0+cGVuZF9jb3VudCAtPSBhdmFpbDsNCisJanItPmluYl9jb3Vu
dCA9IChqci0+aW5iX2NvdW50ICsgYXZhaWwpICYgKFJJTkdfU0laRSAtIDEpOw0KKw0KKwkvKiBh
ZGQgam9icyBpbnRvIGpvYiByaW5nICovDQorCW91dF9iZTMyKCZqci0+anJyZWdzLT5pbmJyaW5n
X2FkZF9qb2IsIFJFX0pSX0lOQl9KT0JfQUREKGF2YWlsKSk7DQorDQorb3V0X3VubG9jazoNCisJ
c3Bpbl91bmxvY2tfYmgoJmpyLT5pbmJfbG9jayk7DQorfQ0KKw0KKy8qIFBlciBKb2IgUmluZyB0
aW1lciBoYW5kbGVyICovDQorc3RhdGljIHZvaWQgcmFpZGVfdGltZXJfaGFuZGxlcih1bnNpZ25l
ZCBsb25nIGRhdGEpIHsNCisJc3RydWN0IGRtYV9jaGFuICpjaGFuID0gTlVMTDsNCisJY2hhbiA9
IChzdHJ1Y3QgZG1hX2NoYW4gKilkYXRhOw0KKw0KKwlyZV9qcl9pc3N1ZV9wZW5kaW5nKGNoYW4p
Ow0KKw0KKwlyZXR1cm47DQorfQ0KKw0KK2lubGluZSB2b2lkIGZpbGxfY2ZkX2ZyYW1lKHN0cnVj
dCBjbXBuZF9mcmFtZSAqY2YsIHU4IGluZGV4LA0KKwkJc2l6ZV90IGxlbmd0aCwgZG1hX2FkZHJf
dCBhZGRyLCBib29sIGZpbmFsKSB7DQorCWNmW2luZGV4XS5maW5hbCA9IGZpbmFsOw0KKwljZltp
bmRleF0ubGVuZ3RoID0gbGVuZ3RoOw0KKwljZltpbmRleF0uYWRkcmVzcyA9IGFkZHI7DQorfQ0K
Kw0KK3N0YXRpYyBzdHJ1Y3QgZnNsX3JlX2RtYV9hc3luY190eF9kZXNjICpyZV9qcl9pbml0X2Rl
c2Moc3RydWN0IHJlX2pyICpqciwNCisJc3RydWN0IGZzbF9yZV9kbWFfYXN5bmNfdHhfZGVzYyAq
ZGVzYywgdm9pZCAqY2YsIGRtYV9hZGRyX3QgcGFkZHIpIHsNCisJZGVzYy0+anIgPSBqcjsNCisJ
ZGVzYy0+YXN5bmNfdHgudHhfc3VibWl0ID0gcmVfanJfdHhfc3VibWl0Ow0KKwlkbWFfYXN5bmNf
dHhfZGVzY3JpcHRvcl9pbml0KCZkZXNjLT5hc3luY190eCwgJmpyLT5jaGFuKTsNCisJSU5JVF9M
SVNUX0hFQUQoJmRlc2MtPm5vZGUpOw0KKw0KKwlkZXNjLT5od2Rlc2MtPmZvcm1hdCA9IEZSQU1F
X0ZPUk1BVDsNCisJZGVzYy0+aHdkZXNjLT5hZGRyZXNzID0gcGFkZHI7DQorCWRlc2MtPmNmX2Fk
ZHIgPSBjZjsNCisNCisJZGVzYy0+Y2RiX2FkZHIgPSAodm9pZCAqKShjZiArIFJFX0NGX0RFU0Nf
U0laRSk7DQorCWRlc2MtPmNkYl9wYWRkciA9IHBhZGRyICsgUkVfQ0ZfREVTQ19TSVpFOw0KKw0K
KwlyZXR1cm4gZGVzYzsNCit9DQorDQorc3RhdGljIHN0cnVjdCBmc2xfcmVfZG1hX2FzeW5jX3R4
X2Rlc2MgKnJlX2pyX2FsbG9jX2Rlc2Moc3RydWN0IHJlX2pyICpqciwNCisJCXVuc2lnbmVkIGxv
bmcgZmxhZ3MpDQorew0KKwlzdHJ1Y3QgZnNsX3JlX2RtYV9hc3luY190eF9kZXNjICpkZXNjOw0K
Kw0KKwlzcGluX2xvY2tfYmgoJmpyLT5pbmJfbG9jayk7DQorDQorCWpyLT5pbmJfY291bnQgJj0g
UklOR19TSVpFIC0gMTsNCisJZGVzYyA9ICZqci0+ZGVzY3NbanItPmluYl9jb3VudF07DQorDQor
CWlmIChkZXNjLT5zdGF0ZSAhPSBSRV9ERVNDX0VNUFRZKSB7DQorCQlzcGluX3VubG9ja19iaCgm
anItPmluYl9sb2NrKTsNCisJCXJlX2pyX2lzc3VlX3BlbmRpbmcoJmpyLT5jaGFuKTsNCisJCXJl
dHVybiBOVUxMOw0KKwl9DQorCXNwaW5fdW5sb2NrX2JoKCZqci0+aW5iX2xvY2spOw0KKw0KKwlk
ZXNjLT5zdGF0ZSA9IFJFX0RFU0NfQUxMT0M7DQorCWRlc2MtPmFzeW5jX3R4LmZsYWdzID0gZmxh
Z3M7DQorCXJldHVybiBkZXNjOw0KK30NCisNCitzdGF0aWMgc3RydWN0IGRtYV9hc3luY190eF9k
ZXNjcmlwdG9yICpyZV9qcl9wcmVwX2dlbnEoDQorCQlzdHJ1Y3QgZG1hX2NoYW4gKmNoYW4sIGRt
YV9hZGRyX3QgZGVzdCwgZG1hX2FkZHJfdCAqc3JjLA0KKwkJdW5zaWduZWQgaW50IHNyY19jbnQs
IGNvbnN0IHVuc2lnbmVkIGNoYXIgKnNjZiwgc2l6ZV90IGxlbiwNCisJCXVuc2lnbmVkIGxvbmcg
ZmxhZ3MpDQorew0KKwlzdHJ1Y3QgcmVfanIgKmpyID0gTlVMTDsNCisJc3RydWN0IGZzbF9yZV9k
bWFfYXN5bmNfdHhfZGVzYyAqZGVzYyA9IE5VTEw7DQorCXN0cnVjdCB4b3JfY2RiICp4b3IgPSBO
VUxMOw0KKwlzdHJ1Y3QgY21wbmRfZnJhbWUgKmNmOw0KKwl1bnNpZ25lZCBpbnQgaSA9IDA7DQor
CXVuc2lnbmVkIGludCBqID0gMDsNCisNCisJaWYgKGxlbiA+IE1BWF9EQVRBX0xFTkdUSCkgew0K
KwkJcHJfZXJyKCIlczogTGVuZ3RoIGdyZWF0ZXIgdGhhbiAlZCBub3Qgc3VwcG9ydGVkXG4iLA0K
KwkJCQlfX2Z1bmNfXywgTUFYX0RBVEFfTEVOR1RIKTsNCisJCXJldHVybiBOVUxMOw0KKwl9DQor
CWpyID0gY29udGFpbmVyX29mKGNoYW4sIHN0cnVjdCByZV9qciwgY2hhbik7DQorCWRlc2MgPSBy
ZV9qcl9hbGxvY19kZXNjKGpyLCBmbGFncyk7DQorCWlmICghZGVzYyB8fCBkZXNjIDwgMCkNCisJ
CXJldHVybiBOVUxMOw0KKw0KKwlkZXNjLT5kbWFfbGVuID0gbGVuOw0KKwlkZXNjLT5kZXN0X2Nu
dCA9IDE7DQorCWRlc2MtPnNyY19jbnQgPSBzcmNfY250Ow0KKw0KKwlkZXNjLT5jZGJfb3Bjb2Rl
ID0gUkVfWE9SX09QQ09ERTsNCisJZGVzYy0+Y2RiX2xlbiA9IHNpemVvZihzdHJ1Y3QgeG9yX2Nk
Yik7DQorDQorCS8qIEZpbGxpbmcgeG9yIENEQiAqLw0KKwl4b3IgPSBkZXNjLT5jZGJfYWRkcjsN
CisJeG9yLT5vcGNvZGUgPSBSRV9YT1JfT1BDT0RFOw0KKwl4b3ItPm5yY3MgPSAoc3JjX2NudCAt
IDEpOw0KKwl4b3ItPmJsa19zaXplID0gUkVfQkxPQ0tfU0laRTsNCisJeG9yLT5lcnJvcl9hdHRy
aWIgPSBJTlRFUlJVUFRfT05fRVJST1I7DQorCXhvci0+ZGF0YV9kZXBlbmQgPSBEQVRBX0RFUEVO
REVOQ1k7DQorDQorCWlmIChzY2YgIT0gTlVMTCkgew0KKwkJLyogY29tcHV0ZSBxID0gc3JjMCpj
b2VmMF5zcmMxKmNvZWYxXi4uLiwgKiBpcyBHRig4KSBtdWx0ICovDQorCQlmb3IgKGkgPSAwOyBp
IDwgc3JjX2NudDsgaSsrKQ0KKwkJCXhvci0+Z2ZtW2ldID0gc2NmW2ldOw0KKwl9IGVsc2Ugew0K
KwkJLyogY29tcHV0ZSBQLCB0aGF0IGlzIFhPUiBhbGwgc3JjcyAqLw0KKwkJZm9yIChpID0gMDsg
aSA8IHNyY19jbnQ7IGkrKykNCisJCQl4b3ItPmdmbVtpXSA9IDE7DQorCX0NCisNCisJLyogRmls
bGluZyBmcmFtZSAwIG9mIGNvbXBvdW5kIGZyYW1lIGRlc2NyaXB0b3Igd2l0aCBDREIgKi8NCisJ
Y2YgPSBkZXNjLT5jZl9hZGRyOw0KKwlmaWxsX2NmZF9mcmFtZShjZiwgMCwgZGVzYy0+Y2RiX2xl
biwgZGVzYy0+Y2RiX3BhZGRyLCAwKTsNCisNCisJLyogRmlsbCBDRkQncyAxc3QgZnJhbWUgd2l0
aCBkZXN0IGJ1ZmZlciAqLw0KKwlmaWxsX2NmZF9mcmFtZShjZiwgMSwgbGVuLCBkZXN0LCAwKTsN
CisNCisJLyogRmlsbCBDRkQncyByZXN0IG9mIHRoZSBmcmFtZXMgd2l0aCBzb3VyY2UgYnVmZmVy
cyAqLw0KKwlmb3IgKGkgPSAyLCBqID0gMDsgaiA8IHNyY19jbnQ7IGkrKywgaisrKQ0KKwkJZmls
bF9jZmRfZnJhbWUoY2YsIGksIGxlbiwgc3JjW2pdLCAwKTsNCisNCisJLyogU2V0dGluZyB0aGUg
ZmluYWwgYml0IGluIHRoZSBsYXN0IHNvdXJjZSBidWZmZXIgZnJhbWUgaW4gQ0ZEICovDQorCWNm
W2kgLSAxXS5maW5hbCA9IDE7DQorDQorCXJldHVybiAmZGVzYy0+YXN5bmNfdHg7DQorfQ0KKw0K
Ky8qDQorICogUHJlcCBmdW5jdGlvbiBmb3IgUCBwYXJpdHkgY2FsY3VsYXRpb24uSW4gUkFJRCBF
bmdpbmUgdGVybWlub2xvZ3ksDQorICogWE9SIGNhbGN1bGF0aW9uIGlzIGNhbGxlZCBHZW5RIGNh
bGN1bGF0aW9uIGRvbmUgdGhyb3VnaCBHZW5RIGNvbW1hbmQgIA0KKyovIHN0YXRpYyBzdHJ1Y3Qg
ZG1hX2FzeW5jX3R4X2Rlc2NyaXB0b3IgKnJlX2pyX3ByZXBfZG1hX3hvcigNCisJCXN0cnVjdCBk
bWFfY2hhbiAqY2hhbiwgZG1hX2FkZHJfdCBkZXN0LCBkbWFfYWRkcl90ICpzcmMsDQorCQl1bnNp
Z25lZCBpbnQgc3JjX2NudCwgc2l6ZV90IGxlbiwgdW5zaWduZWQgbG9uZyBmbGFncykgew0KKwkv
KiBOVUxMIGxldCBnZW5xIHRha2UgYWxsIGNvZWYgYXMgMSAqLw0KKwlyZXR1cm4gcmVfanJfcHJl
cF9nZW5xKGNoYW4sIGRlc3QsIHNyYywgc3JjX2NudCwgTlVMTCwgbGVuLCBmbGFncyk7IH0NCisN
CisvKg0KKyAqIFByZXAgZnVuY3Rpb24gZm9yIFAvUSBwYXJpdHkgY2FsY3VsYXRpb24uSW4gUkFJ
RCBFbmdpbmUgdGVybWlub2xvZ3ksDQorICogUC9RIGNhbGN1bGF0aW9uIGlzIGNhbGxlZCBHZW5R
USBkb25lIHRocm91Z2ggR2VuUVEgY29tbWFuZCAgKi8gDQorc3RhdGljIHN0cnVjdCBkbWFfYXN5
bmNfdHhfZGVzY3JpcHRvciAqcmVfanJfcHJlcF9wcSgNCisJCXN0cnVjdCBkbWFfY2hhbiAqY2hh
biwgZG1hX2FkZHJfdCAqZGVzdCwgZG1hX2FkZHJfdCAqc3JjLA0KKwkJdW5zaWduZWQgaW50IHNy
Y19jbnQsIGNvbnN0IHVuc2lnbmVkIGNoYXIgKnNjZiwgc2l6ZV90IGxlbiwNCisJCXVuc2lnbmVk
IGxvbmcgZmxhZ3MpDQorew0KKwlzdHJ1Y3QgcmVfanIgKmpyID0gTlVMTDsNCisJc3RydWN0IGZz
bF9yZV9kbWFfYXN5bmNfdHhfZGVzYyAqZGVzYyA9IE5VTEw7DQorCXN0cnVjdCBwcV9jZGIgKnBx
ID0gTlVMTDsNCisJc3RydWN0IGNtcG5kX2ZyYW1lICpjZjsNCisJdTggKnA7DQorCWludCBnZm1x
X2xlbiwgaSwgajsNCisNCisJaWYgKGxlbiA+IE1BWF9EQVRBX0xFTkdUSCkgew0KKwkJcHJfZXJy
KCIlczogTGVuZ3RoIGdyZWF0ZXIgdGhhbiAlZCBub3Qgc3VwcG9ydGVkXG4iLA0KKwkJCQlfX2Z1
bmNfXywgTUFYX0RBVEFfTEVOR1RIKTsNCisJCXJldHVybiBOVUxMOw0KKwl9DQorDQorCS8qDQor
CSAqIFJFIHJlcXVpcmVzIGF0IGxlYXN0IDIgc291cmNlcywgaWYgZ2l2ZW4gb25seSBvbmUgc291
cmNlLCB3ZSBwYXNzIHRoZQ0KKwkgKiBzZWNvbmQgc291cmNlIHNhbWUgYXMgdGhlIGZpcnN0IG9u
ZS4NCisJICogV2l0aCBvbmx5IG9uZSBzb3VyY2UsIGdlbmVyYXRlIFAgaXMgbWVhbmluZ2xlc3Ms
IG9ubHkgY2FyZSBRLg0KKwkgKi8NCisJaWYgKHNyY19jbnQgPT0gMSkgew0KKwkJc3RydWN0IGRt
YV9hc3luY190eF9kZXNjcmlwdG9yICp0eCA9IE5VTEw7DQorCQlkbWFfYWRkcl90IGRtYV9zcmNb
Ml07DQorCQl1bnNpZ25lZCBjaGFyIGNvZWZbMl07DQorCQlkbWFfc3JjWzBdID0gKnNyYzsNCisJ
CWNvZWZbMF0gPSAqc2NmOw0KKwkJZG1hX3NyY1sxXSA9ICpzcmM7DQorCQljb2VmWzFdID0gMDsN
CisJCXR4ID0gcmVfanJfcHJlcF9nZW5xKGNoYW4sIGRlc3RbMV0sIGRtYV9zcmMsIDIsIGNvZWYs
IGxlbiwNCisJCQkJZmxhZ3MpOw0KKwkJaWYgKHR4KSB7DQorCQkJZGVzYyA9IHRvX2ZzbF9yZV9k
bWFfZGVzYyh0eCk7DQorCQkJZGVzYy0+c3JjX2NudCA9IDE7DQorCQl9DQorCQlyZXR1cm4gdHg7
DQorCX0NCisNCisJLyoNCisJICogRHVyaW5nIFJBSUQ2IGFycmF5IGNyZWF0aW9uLCBMaW51eCdz
IE1EIGxheWVyIGdldHMgUCBhbmQgUQ0KKwkgKiBjYWxjdWxhdGVkIHNlcGFyYXRlbHkgaW4gdHdv
IHN0ZXBzLiBCdXQgb3VyIFJBSUQgRW5naW5lIGhhcw0KKwkgKiB0aGUgY2FwYWJpbGl0eSB0byBj
YWxjdWxhdGUgYm90aCBQIGFuZCBRIHdpdGggYSBzaW5nbGUgY29tbWFuZA0KKwkgKiBIZW5jZSB0
byBtZXJnZSB3ZWxsIHdpdGggTUQgbGF5ZXIsIHdlIG5lZWQgdG8gcHJvdmlkZSBhIGhvb2sNCisJ
ICogaGVyZSBhbmQgY2FsbCByZV9qcV9wcmVwX2dlbnEoKSBmdW5jdGlvbg0KKwkgKi8NCisNCisJ
aWYgKGZsYWdzICYgRE1BX1BSRVBfUFFfRElTQUJMRV9QKQ0KKwkJcmV0dXJuIHJlX2pyX3ByZXBf
Z2VucShjaGFuLCBkZXN0WzFdLCBzcmMsIHNyY19jbnQsDQorCQkJCXNjZiwgbGVuLCBmbGFncyk7
DQorDQorCWpyID0gY29udGFpbmVyX29mKGNoYW4sIHN0cnVjdCByZV9qciwgY2hhbik7DQorCWRl
c2MgPSByZV9qcl9hbGxvY19kZXNjKGpyLCBmbGFncyk7DQorCWlmICghZGVzYyB8fCBkZXNjIDwg
MCkNCisJCXJldHVybiBOVUxMOw0KKw0KKwlkZXNjLT5kbWFfbGVuID0gbGVuOw0KKwlkZXNjLT5k
ZXN0X2NudCA9IDI7DQorCWRlc2MtPnNyY19jbnQgPSBzcmNfY250Ow0KKw0KKwlkZXNjLT5jZGJf
b3Bjb2RlID0gUkVfUFFfT1BDT0RFOw0KKwlkZXNjLT5jZGJfbGVuID0gc2l6ZW9mKHN0cnVjdCBw
cV9jZGIpOw0KKw0KKwkvKiBGaWxsaW5nIEdlblFRIENEQiAqLw0KKwlwcSA9IGRlc2MtPmNkYl9h
ZGRyOw0KKwlwcS0+b3Bjb2RlID0gUkVfUFFfT1BDT0RFOw0KKwlwcS0+YmxrX3NpemUgPSBSRV9C
TE9DS19TSVpFOw0KKwlwcS0+YnVmZmVyX2F0dHJpYiA9IEJVRkZFUkFCTEVfT1VUUFVUOw0KKwlw
cS0+ZGF0YV9kZXBlbmQgPSBEQVRBX0RFUEVOREVOQ1k7DQorCXBxLT5ucmNzID0gKHNyY19jbnQg
LSAxKTsNCisNCisJcCA9IHBxLT5nZm1fcTE7DQorCS8qIEluaXQgZ2ZtX3ExW10gKi8NCisJZm9y
IChpID0gMDsgaSA8IHNyY19jbnQ7IGkrKykNCisJCXBbaV0gPSAxOw0KKw0KKwkvKiBBbGlnbiBn
Zm1bXSB0byAzMmJpdCAqLw0KKwlnZm1xX2xlbiA9ICgoc3JjX2NudCszKS80KSo0Ow0KKw0KKwkv
KiBJbml0IGdmbV9xMltdICovDQorCXAgKz0gZ2ZtcV9sZW47DQorCWZvciAoaSA9IDA7IGkgPCBz
cmNfY250OyBpKyspDQorCQlwW2ldID0gc2NmW2ldOw0KKw0KKwkvKiBGaWxsaW5nIGZyYW1lIDAg
b2YgY29tcG91bmQgZnJhbWUgZGVzY3JpcHRvciB3aXRoIENEQiAqLw0KKwljZiA9IGRlc2MtPmNm
X2FkZHI7DQorCWZpbGxfY2ZkX2ZyYW1lKGNmLCAwLCBkZXNjLT5jZGJfbGVuLCBkZXNjLT5jZGJf
cGFkZHIsIDApOw0KKw0KKwkvKiBGaWxsIENGRCdzIDFzdCAmIDJuZCBmcmFtZSB3aXRoIGRlc3Qg
YnVmZmVycyAqLw0KKwlmb3IgKGkgPSAxLCBqID0gMDsgaSA8IDM7IGkrKywgaisrKQ0KKwkJZmls
bF9jZmRfZnJhbWUoY2YsIGksIGxlbiwgZGVzdFtqXSwgMCk7DQorDQorCS8qIEZpbGwgQ0ZEJ3Mg
cmVzdCBvZiB0aGUgZnJhbWVzIHdpdGggc291cmNlIGJ1ZmZlcnMgKi8NCisJZm9yIChpID0gMywg
aiA9IDA7IGogPCBzcmNfY250OyBpKyssIGorKykNCisJCWZpbGxfY2ZkX2ZyYW1lKGNmLCBpLCBs
ZW4sIHNyY1tqXSwgMCk7DQorDQorCS8qIFNldHRpbmcgdGhlIGZpbmFsIGJpdCBpbiB0aGUgbGFz
dCBzb3VyY2UgYnVmZmVyIGZyYW1lIGluIENGRCAqLw0KKwljZltpIC0gMV0uZmluYWwgPSAxOw0K
Kw0KKwlyZXR1cm4gJmRlc2MtPmFzeW5jX3R4Ow0KK30NCisNCisvKg0KKyAqIFByZXAgZnVuY3Rp
b24gZm9yIG1lbWNweS4gSW4gUkFJRCBFbmdpbmUsIG1lbWNweSBpcyBkb25lIHRocm91Z2ggDQor
TU9WRQ0KKyAqIGNvbW1hbmQuIExvZ2ljIG9mIHRoaXMgZnVuY3Rpb24gd2lsbCBuZWVkIHRvIGJl
IG1vZGlmaWVkIG9uY2UgDQorbXVsdGlwYWdlDQorICogc3VwcG9ydCBpcyBhZGRlZCBpbiBMaW51
eCdzIE1EL0FTWU5DIExheWVyICAqLyBzdGF0aWMgc3RydWN0IA0KK2RtYV9hc3luY190eF9kZXNj
cmlwdG9yICpyZV9qcl9wcmVwX21lbWNweSgNCisJCXN0cnVjdCBkbWFfY2hhbiAqY2hhbiwgZG1h
X2FkZHJfdCBkZXN0LCBkbWFfYWRkcl90IHNyYywNCisJCXNpemVfdCBsZW4sIHVuc2lnbmVkIGxv
bmcgZmxhZ3MpDQorew0KKwlzdHJ1Y3QgcmVfanIgKmpyID0gTlVMTDsNCisJc3RydWN0IGZzbF9y
ZV9kbWFfYXN5bmNfdHhfZGVzYyAqZGVzYyA9IE5VTEw7DQorCXNpemVfdCBsZW5ndGggPSAwOw0K
KwlzdHJ1Y3QgY21wbmRfZnJhbWUgKmNmID0gTlVMTDsNCisJc3RydWN0IG1vdmVfY2RiICptb3Zl
ID0gTlVMTDsNCisNCisJanIgPSBjb250YWluZXJfb2YoY2hhbiwgc3RydWN0IHJlX2pyLCBjaGFu
KTsNCisNCisJaWYgKGxlbiA+IE1BWF9EQVRBX0xFTkdUSCkgew0KKwkJcHJfZXJyKCIlczogTGVu
Z3RoIGdyZWF0ZXIgdGhhbiAlZCBub3Qgc3VwcG9ydGVkXG4iLA0KKwkJCQlfX2Z1bmNfXywgTUFY
X0RBVEFfTEVOR1RIKTsNCisJCXJldHVybiBOVUxMOw0KKwl9DQorDQorCWRlc2MgPSByZV9qcl9h
bGxvY19kZXNjKGpyLCBmbGFncyk7DQorCWlmICghZGVzYyB8fCBkZXNjIDwgMCkNCisJCXJldHVy
biBOVUxMOw0KKw0KKwlkZXNjLT5kbWFfbGVuID0gbGVuOw0KKwlkZXNjLT5zcmNfY250ID0gMTsN
CisJZGVzYy0+ZGVzdF9jbnQgPSAxOw0KKw0KKwlkZXNjLT5jZGJfb3Bjb2RlID0gUkVfTU9WRV9P
UENPREU7DQorCWRlc2MtPmNkYl9sZW4gPSBzaXplb2Yoc3RydWN0IG1vdmVfY2RiKTsNCisNCisJ
LyogRmlsbGluZyBtb3ZlIENEQiAqLw0KKwltb3ZlID0gZGVzYy0+Y2RiX2FkZHI7DQorCW1vdmUt
Pm9wY29kZSA9IFJFX01PVkVfT1BDT0RFOyAvKiBVbmljYXN0IG1vdmUgKi8NCisJbW92ZS0+Ymxr
X3NpemUgPSBSRV9CTE9DS19TSVpFOw0KKwltb3ZlLT5lcnJvcl9hdHRyaWIgPSBJTlRFUlJVUFRf
T05fRVJST1I7DQorCW1vdmUtPmRhdGFfZGVwZW5kID0gREFUQV9ERVBFTkRFTkNZOw0KKw0KKwkv
KiBGaWxsaW5nIGZyYW1lIDAgb2YgQ0ZEIHdpdGggbW92ZSBDREIgKi8NCisJY2YgPSBkZXNjLT5j
Zl9hZGRyOw0KKwlmaWxsX2NmZF9mcmFtZShjZiwgMCwgZGVzYy0+Y2RiX2xlbiwgZGVzYy0+Y2Ri
X3BhZGRyLCAwKTsNCisNCisJbGVuZ3RoID0gbWluX3Qoc2l6ZV90LCBsZW4sIE1BWF9EQVRBX0xF
TkdUSCk7DQorDQorCS8qIEZpbGwgQ0ZEJ3MgMXN0IGZyYW1lIHdpdGggZGVzdCBidWZmZXIgKi8N
CisJZmlsbF9jZmRfZnJhbWUoY2YsIDEsIGxlbmd0aCwgZGVzdCwgMCk7DQorDQorCS8qIEZpbGwg
Q0ZEJ3MgMm5kIGZyYW1lIHdpdGggc3JjIGJ1ZmZlciAqLw0KKwlmaWxsX2NmZF9mcmFtZShjZiwg
MiwgbGVuZ3RoLCBzcmMsIDEpOw0KKw0KKwlyZXR1cm4gJmRlc2MtPmFzeW5jX3R4Ow0KK30NCisN
CitzdGF0aWMgaW50IHJlX2pyX2FsbG9jX2NoYW5fcmVzb3VyY2VzKHN0cnVjdCBkbWFfY2hhbiAq
Y2hhbikgew0KKwlpbnQgaTsNCisJc3RydWN0IGZzbF9yZV9kbWFfYXN5bmNfdHhfZGVzYyAqZGVz
YzsNCisJc3RydWN0IHJlX2pyICpqciA9IGNvbnRhaW5lcl9vZihjaGFuLCBzdHJ1Y3QgcmVfanIs
IGNoYW4pOw0KKwl2b2lkICpjZiA9IE5VTEw7DQorCWRtYV9hZGRyX3QgcGFkZHI7DQorDQorCWpy
LT5kZXNjcyA9IGt6YWxsb2Moc2l6ZW9mKCpkZXNjKSAqIFJJTkdfU0laRSwgR0ZQX0tFUk5FTCk7
DQorCWlmICghanItPmRlc2NzKSB7DQorCQlkZXZfZXJyKGpyLT5kZXYsICIlczogTm8gbWVtb3J5
IGZvciBzdyBkZXNjcmlwdG9yIHJpbmdcbiIsDQorCQkJX19mdW5jX18pOw0KKwkJZ290byBlcnJf
ZnJlZTsNCisJfQ0KKw0KKwljZiA9IGRtYV9wb29sX2FsbG9jKGpyLT5yZV9kZXYtPmRlc2NfcG9v
bCwgR0ZQX0FUT01JQywgJnBhZGRyKTsNCisJaWYgKCFjZikgew0KKwkJZGV2X2Vycihqci0+ZGV2
LCAiJXM6IE5vIG1lbW9yeSBmb3IgZG1hIGRlc2NyaXB0b3IgcmluZ1xuIiwNCisJCQlfX2Z1bmNf
Xyk7DQorCQlnb3RvIGVycl9mcmVlOw0KKwl9DQorCW1lbXNldChjZiwgMCwgUkVfQ0ZfQ0RCX1NJ
WkUgKiBSSU5HX1NJWkUpOw0KKwlqci0+Y2ZzID0gY2Y7DQorCWpyLT5waHlzID0gcGFkZHI7DQor
DQorCWZvciAoaSA9IDA7IGkgPCBSSU5HX1NJWkU7IGkrKykgew0KKwkJdTMyIG9mZnNldCA9IGkg
KiBSRV9DRl9DREJfU0laRTsNCisJCWRlc2MgPSAmanItPmRlc2NzW2ldOw0KKwkJZGVzYy0+aHdk
ZXNjID0gJmpyLT5pbmJfcmluZ192aXJ0X2FkZHJbaV07DQorCQlyZV9qcl9pbml0X2Rlc2MoanIs
IGRlc2MsIGNmICsgb2Zmc2V0LCBwYWRkciArIG9mZnNldCk7DQorCQlkZXNjLT5zdGF0ZSA9IFJF
X0RFU0NfRU1QVFk7DQorCX0NCisJcmV0dXJuIDA7DQorDQorZXJyX2ZyZWU6DQorCWtmcmVlKGpy
LT5kZXNjcyk7DQorCXJldHVybiAtRU5PTUVNOw0KK30NCisNCitzdGF0aWMgdm9pZCByZV9qcl9m
cmVlX2NoYW5fcmVzb3VyY2VzKHN0cnVjdCBkbWFfY2hhbiAqY2hhbikgew0KKwlzdHJ1Y3QgcmVf
anIgKmpyID0gY29udGFpbmVyX29mKGNoYW4sIHN0cnVjdCByZV9qciwgY2hhbik7DQorCWRtYV9w
b29sX2ZyZWUoanItPnJlX2Rldi0+ZGVzY19wb29sLCBqci0+Y2ZzLCBqci0+cGh5cyk7DQorCWtm
cmVlKGpyLT5kZXNjcyk7DQorCXJldHVybjsNCit9DQorDQoraW50IHJlX2pyX3Byb2JlKHN0cnVj
dCBwbGF0Zm9ybV9kZXZpY2UgKm9mZGV2LA0KKwkJc3RydWN0IGRldmljZV9ub2RlICpucCwgdTgg
cSwgdTMyICpvZmYpIHsNCisJc3RydWN0IGRldmljZSAqZGV2ID0gTlVMTDsNCisJc3RydWN0IHJl
X2Rydl9wcml2YXRlICpyZXByaXYgPSBOVUxMOw0KKwlzdHJ1Y3QgcmVfanIgKmpyID0gTlVMTDsN
CisJc3RydWN0IGRtYV9kZXZpY2UgKmRtYV9kZXYgPSBOVUxMOw0KKwl1MzIgKnB0ciA9IE5VTEw7
DQorCXUzMiBzdGF0dXM7DQorCWludCByZXQgPSAwOw0KKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNl
ICpqcl9vZmRldiA9IE5VTEw7DQorDQorCWRldiA9ICZvZmRldi0+ZGV2Ow0KKwlyZXByaXYgPSBk
ZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisJZG1hX2RldiA9ICZyZXByaXYtPmRtYV9kZXY7DQorDQor
CWpyID0ga3phbGxvYyhzaXplb2Yoc3RydWN0IHJlX2pyKSwgR0ZQX0tFUk5FTCk7DQorCWlmICgh
anIpIHsNCisJCWRldl9lcnIoZGV2LCAiJXM6IE5vIGZyZWUgbWVtb3J5IGZvciBhbGxvY2F0aW5n
IEpSIHN0cnVjdFxuIiwNCisJCQlfX2Z1bmNfXyk7DQorCQlyZXR1cm4gLUVOT01FTTsNCisJfQ0K
Kw0KKwlqcl9vZmRldiA9IG9mX3BsYXRmb3JtX2RldmljZV9jcmVhdGUobnAsIE5VTEwsIGRldik7
DQorCWlmIChqcl9vZmRldiA9PSBOVUxMKSB7DQorCQlkZXZfZXJyKGRldiwgIiVzOiBOb3QgYWJs
ZSB0byBjcmVhdGUgb2ZkZXYgZm9yIGpyICVkXG4iLA0KKwkJCV9fZnVuY19fLCBxKTsNCisJCXJl
dCA9IC1FSU5WQUw7DQorCQlnb3RvIGVycl9mcmVlOw0KKwl9DQorCWRldl9zZXRfZHJ2ZGF0YSgm
anJfb2ZkZXYtPmRldiwganIpOw0KKw0KKwlwdHIgPSAodTMyICopb2ZfZ2V0X3Byb3BlcnR5KG5w
LCAicmVnIiwgTlVMTCk7DQorCWlmICghcHRyKSB7DQorCQlkZXZfZXJyKGRldiwgIiVzOiBSZWcg
cHJvcGVydHkgbm90IGZvdW5kIGluIEpSIG51bWJlciAlZFxuIiwNCisJCQlfX2Z1bmNfXywgcSk7
DQorCQlyZXQgPSAtRU5PREVWOw0KKwkJZ290byBlcnJfZnJlZTsNCisJfQ0KKw0KKwlqci0+anJy
ZWdzID0gKHN0cnVjdCBqcl9jb25maWdfcmVncyAqKSgodTggKilyZXByaXYtPnJlX3JlZ3MgKw0K
KwkJCSpvZmYgKyAqcHRyKTsNCisNCisJanItPmlycSA9IGlycV9vZl9wYXJzZV9hbmRfbWFwKG5w
LCAwKTsNCisJaWYgKGpyLT5pcnEgPT0gTk9fSVJRKSB7DQorCQlkZXZfZXJyKGRldiwgIiVzOiBO
byBJUlEgZGVmaW5lZCBmb3IgSlIgJWRcbiIsIF9fZnVuY19fLCBxKTsNCisJCXJldCA9IC1FTk9E
RVY7DQorCQlnb3RvIGVycl9mcmVlOw0KKwl9DQorDQorCXRhc2tsZXRfaW5pdCgmanItPmlycXRh
c2ssIHJlX2pyX2RlcXVldWUsDQorCQkJKHVuc2lnbmVkIGxvbmcpJmpyX29mZGV2LT5kZXYpOw0K
Kw0KKwlyZXQgPSByZXF1ZXN0X2lycShqci0+aXJxLCByZV9qcl9pbnRlcnJ1cHQsIDAsICJyZS1q
ciIsICZqcl9vZmRldi0+ZGV2KTsNCisJaWYgKHJldCkgew0KKwkJZGV2X2VycihkZXYsICIlczog
VW5hYmxlIHRvIHJlZ2lzdGVyIEpSIGludGVycnVwdCBmb3IgSlIgJWRcbiIsDQorCQkJX19mdW5j
X18sIHEpOw0KKwkJcmV0ID0gLUVJTlZBTDsNCisJCWdvdG8gZXJyX2ZyZWU7DQorCX0NCisNCisJ
cmVwcml2LT5yZV9qcnNbcV0gPSBqcjsNCisJanItPmNoYW4uZGV2aWNlID0gZG1hX2RldjsNCisJ
anItPmNoYW4ucHJpdmF0ZSA9IGpyOw0KKwlqci0+ZGV2ID0gJmpyX29mZGV2LT5kZXY7DQorCWpy
LT5yZV9kZXYgPSByZXByaXY7DQorCWpyLT5wZW5kX2NvdW50ID0gMDsNCisJSU5JVF9MSVNUX0hF
QUQoJmpyLT5hY2tfcSk7DQorCXNwaW5fbG9ja19pbml0KCZqci0+ZGVzY19sb2NrKTsNCisJc3Bp
bl9sb2NrX2luaXQoJmpyLT5pbmJfbG9jayk7DQorCXNwaW5fbG9ja19pbml0KCZqci0+b3ViX2xv
Y2spOw0KKw0KKwlpbml0X3RpbWVyKCZqci0+dGltZXIpOw0KKwlqci0+dGltZXIuZXhwaXJlcyA9
IGppZmZpZXMgKyAxMCpIWjsNCisJanItPnRpbWVyLmZ1bmN0aW9uID0gcmFpZGVfdGltZXJfaGFu
ZGxlcjsNCisNCisJbGlzdF9hZGRfdGFpbCgmanItPmNoYW4uZGV2aWNlX25vZGUsICZkbWFfZGV2
LT5jaGFubmVscyk7DQorCWRtYV9kZXYtPmNoYW5jbnQrKzsNCisNCisJanItPmluYl9yaW5nX3Zp
cnRfYWRkciA9IGRtYV9wb29sX2FsbG9jKGpyLT5yZV9kZXYtPmh3X2Rlc2NfcG9vbCwNCisJCUdG
UF9BVE9NSUMsICZqci0+aW5iX3BoeXNfYWRkcik7DQorDQorCWlmICghanItPmluYl9yaW5nX3Zp
cnRfYWRkcikgew0KKwkJZGV2X2VycihkZXYsICIlczpObyBkbWEgbWVtb3J5IGZvciBpbmJfcmlu
Z192aXJ0X2FkZHJcbiIsDQorCQkJX19mdW5jX18pOw0KKwkJcmV0ID0gLUVOT01FTTsNCisJCWdv
dG8gZXJyX2ZyZWU7DQorCX0NCisNCisJanItPm91Yl9yaW5nX3ZpcnRfYWRkciA9IGRtYV9wb29s
X2FsbG9jKGpyLT5yZV9kZXYtPmh3X2Rlc2NfcG9vbCwNCisJCUdGUF9BVE9NSUMsICZqci0+b3Vi
X3BoeXNfYWRkcik7DQorDQorCWlmICghanItPm91Yl9yaW5nX3ZpcnRfYWRkcikgew0KKwkJZGV2
X2VycihkZXYsICIlczpObyBkbWEgbWVtb3J5IGZvciBvdWJfcmluZ192aXJ0X2FkZHJcbiIsDQor
CQkJX19mdW5jX18pOw0KKwkJcmV0ID0gLUVOT01FTTsNCisJCWdvdG8gZXJyX2ZyZWU7DQorCX0N
CisNCisJanItPmluYl9jb3VudCA9IDA7DQorCWpyLT5wZW5kX2NvdW50ID0gMDsNCisJanItPm91
Yl9jb3VudCA9IDA7DQorDQorCXN0YXR1cyA9IGluX2JlMzIoJmpyLT5qcnJlZ3MtPmpyX3N0YXR1
cyk7DQorDQorCWlmIChzdGF0dXMgJiBSRV9KUl9QQVVTRSkgew0KKwkJZGV2X2luZm8oZGV2LCAi
JXM6IEpSIGlzIGluIHBhdXNlZCBzdGF0ZS4uLmVuYWJsZSBpdFxuIiwNCisJCQlfX2Z1bmNfXyk7
DQorCX0gZWxzZSB7DQorCQlkZXZfZXJyKGRldiwgIiVzOiBFcnJvcjotIEpSIHNodWQgYmUgaW4g
cGF1c2VkIHN0YXRlXG4iLA0KKwkJCV9fZnVuY19fKTsNCisJCXJldCA9IC1FSU5WQUw7DQorCQln
b3RvIHBvb2xfZnJlZTsNCisJfQ0KKw0KKwkvKiBQcm9ncmFtIHRoZSBJbmJvdW5kL091dGJvdW5k
IHJpbmcgYmFzZSBhZGRyZXNzZXMgYW5kIHNpemUgKi8NCisJb3V0X2JlMzIoJmpyLT5qcnJlZ3Mt
PmluYnJpbmdfYmFzZV9oLA0KKwkJCWpyLT5pbmJfcGh5c19hZGRyICYgUkVfSlJfQUREUkVTU19C
SVRfTUFTSyk7DQorCW91dF9iZTMyKCZqci0+anJyZWdzLT5vdWJyaW5nX2Jhc2VfaCwNCisJCQlq
ci0+b3ViX3BoeXNfYWRkciAmIFJFX0pSX0FERFJFU1NfQklUX01BU0spOw0KKwlvdXRfYmUzMigm
anItPmpycmVncy0+aW5icmluZ19iYXNlX2wsDQorCQkJanItPmluYl9waHlzX2FkZHIgPj4gUkVf
SlJfQUREUkVTU19CSVRfU0hJRlQpOw0KKwlvdXRfYmUzMigmanItPmpycmVncy0+b3VicmluZ19i
YXNlX2wsDQorCQkJanItPm91Yl9waHlzX2FkZHIgPj4gUkVfSlJfQUREUkVTU19CSVRfU0hJRlQp
Ow0KKwlvdXRfYmUzMigmanItPmpycmVncy0+aW5icmluZ19zaXplLCBSSU5HX1NJWkUgPDwgUklO
R19TSVpFX1NISUZUKTsNCisJb3V0X2JlMzIoJmpyLT5qcnJlZ3MtPm91YnJpbmdfc2l6ZSwgUklO
R19TSVpFIDw8IFJJTkdfU0laRV9TSElGVCk7DQorDQorCS8qIFJlYWQgTElPRE4gdmFsdWUgZnJv
bSB1LWJvb3QgKi8NCisJc3RhdHVzID0gaW5fYmUzMigmanItPmpycmVncy0+anJfY29uZmlnXzEp
ICYgUkVfSlJfUkVHX0xJT0ROX01BU0s7DQorDQorCS8qIFByb2dyYW0gdGhlIENGRyByZWcgKi8N
CisJb3V0X2JlMzIoJmpyLT5qcnJlZ3MtPmpyX2NvbmZpZ18xLA0KKwkJCVJFX0pSX0NGRzFfQ0JT
SSB8IFJFX0pSX0NGRzFfQ0JTMCB8IHN0YXR1cyk7DQorDQorCS8qIEVuYWJsZSBSRS9KUiAqLw0K
KwlvdXRfYmUzMigmanItPmpycmVncy0+anJfY29tbWFuZCwgUkVfSlJfRU5BQkxFKTsNCisNCisJ
cmV0dXJuIDA7DQorDQorcG9vbF9mcmVlOg0KKwlkbWFfcG9vbF9mcmVlKGpyLT5yZV9kZXYtPmh3
X2Rlc2NfcG9vbCwganItPmluYl9yaW5nX3ZpcnRfYWRkciwNCisJCQlqci0+aW5iX3BoeXNfYWRk
cik7DQorZXJyX2ZyZWU6DQorCWtmcmVlKGpyKTsNCisJcmV0dXJuIHJldDsNCit9DQorDQorLyog
UHJvYmUgZnVuY3Rpb24gZm9yIFJBSUQgRW5naW5lICovDQorc3RhdGljIGludCBfX2RldmluaXQg
cmFpZGVfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqb2ZkZXYpIHsNCisJc3RydWN0IHJl
X2Rydl9wcml2YXRlICpyZXByaXYgPSBOVUxMOw0KKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSBOVUxM
Ow0KKwlzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wID0gTlVMTDsNCisJc3RydWN0IGRldmljZV9ub2Rl
ICpjaGlsZCA9IE5VTEw7DQorCXUzMiAqb2ZmID0gTlVMTDsNCisJdTggcmlkeCA9IDA7DQorCXN0
cnVjdCBkbWFfZGV2aWNlICpkbWFfZGV2ID0gTlVMTDsNCisJaW50IHJldCA9IDA7DQorDQorCWRl
dl9pbmZvKCZvZmRldi0+ZGV2LCAiRnJlZXNjYWxlIFJBSUQgRW5naW5lIGRyaXZlclxuIik7DQor
DQorCXJlcHJpdiA9IGt6YWxsb2Moc2l6ZW9mKHN0cnVjdCByZV9kcnZfcHJpdmF0ZSksIEdGUF9L
RVJORUwpOw0KKwlpZiAoIXJlcHJpdikgew0KKwkJZGV2X2VycihkZXYsICIlczogTm8gbWVtb3J5
IGZvciByZXByaXZcbiIsIF9fZnVuY19fKTsNCisJCXJldHVybiAtRU5PTUVNOw0KKwl9DQorDQor
CWRldiA9ICZvZmRldi0+ZGV2Ow0KKwlkZXZfc2V0X2RydmRhdGEoZGV2LCByZXByaXYpOw0KKw0K
KwkvKiBJT01BUCB0aGUgZW50aXJlIFJBSUQgRW5naW5lIHJlZ2lvbiAqLw0KKwlyZXByaXYtPnJl
X3JlZ3MgPSBvZl9pb21hcChvZmRldi0+ZGV2Lm9mX25vZGUsIDApOw0KKwlpZiAocmVwcml2LT5y
ZV9yZWdzID09IE5VTEwpIHsNCisJCWRldl9lcnIoZGV2LCAiJXM6IG9mX2lvbWFwIGZhaWxlZFxu
IiwgX19mdW5jX18pOw0KKwkJa2ZyZWUocmVwcml2KTsNCisJCXJldCA9IC1FTk9NRU07DQorCQln
b3RvIGVycl9mcmVlXzQ7DQorCX0NCisNCisJLyogUHJpbnQgdGhlIFJFIHZlcnNpb24gdG8gbWFr
ZSBzdXJlIFJFIGlzIGFsaXZlICovDQorCWRldl9pbmZvKGRldiwgIlZlciA9ICV4XG4iLCBpbl9i
ZTMyKCZyZXByaXYtPnJlX3JlZ3MtPnJlX3ZlcnNpb25faWQpKTsNCisNCisJLyogUHJvZ3JhbSB0
aGUgUkUgbW9kZSAqLw0KKwlvdXRfYmUzMigmcmVwcml2LT5yZV9yZWdzLT5nbG9iYWxfY29uZmln
LCBSRV9OT05fRFBBQV9NT0RFKTsNCisJZGV2X2luZm8oZGV2LCAiJXM6UkUgbW9kZSBpcyAleFxu
IiwgX19mdW5jX18sDQorCQkJaW5fYmUzMigmcmVwcml2LT5yZV9yZWdzLT5nbG9iYWxfY29uZmln
KSk7DQorDQorCS8qIFByb2dyYW0gR2Fsb2lzIEZpZWxkIHBvbHlub21pYWwgKi8NCisJb3V0X2Jl
MzIoJnJlcHJpdi0+cmVfcmVncy0+Z2Fsb2lzX2ZpZWxkX2NvbmZpZywgUkVfR0ZNX1BPTFkpOw0K
KwlkZXZfaW5mbyhkZXYsICIlczpHYWxvaXMgRmllbGQgUG9seW5vbWlhbCBpcyAleFxuIiwgX19m
dW5jX18sDQorCQkJaW5fYmUzMigmcmVwcml2LT5yZV9yZWdzLT5nYWxvaXNfZmllbGRfY29uZmln
KSk7DQorDQorCWRtYV9kZXYgPSAmcmVwcml2LT5kbWFfZGV2Ow0KKwlkbWFfZGV2LT5kZXYgPSBk
ZXY7DQorCUlOSVRfTElTVF9IRUFEKCZkbWFfZGV2LT5jaGFubmVscyk7DQorCWRtYV9zZXRfbWFz
ayhkZXYsIERNQV9CSVRfTUFTSyg0MCkpOw0KKw0KKwlkbWFfZGV2LT5kZXZpY2VfYWxsb2NfY2hh
bl9yZXNvdXJjZXMgPSByZV9qcl9hbGxvY19jaGFuX3Jlc291cmNlczsNCisJZG1hX2Rldi0+ZGV2
aWNlX3R4X3N0YXR1cyA9IHJlX2pyX3R4X3N0YXR1czsNCisJZG1hX2Rldi0+ZGV2aWNlX2lzc3Vl
X3BlbmRpbmcgPSByZV9qcl9pc3N1ZV9wZW5kaW5nOw0KKw0KKwlkbWFfZGV2LT5tYXhfeG9yID0g
TUFYX1hPUl9TUkNTOw0KKwlkbWFfZGV2LT5kZXZpY2VfcHJlcF9kbWFfeG9yID0gcmVfanJfcHJl
cF9kbWFfeG9yOw0KKwlkbWFfY2FwX3NldChETUFfWE9SLCBkbWFfZGV2LT5jYXBfbWFzayk7DQor
DQorCWRtYV9kZXYtPm1heF9wcSA9IE1BWF9QUV9TUkNTOw0KKwlkbWFfZGV2LT5kZXZpY2VfcHJl
cF9kbWFfcHEgPSByZV9qcl9wcmVwX3BxOw0KKwlkbWFfY2FwX3NldChETUFfUFEsIGRtYV9kZXYt
PmNhcF9tYXNrKTsNCisNCisJZG1hX2Rldi0+ZGV2aWNlX3ByZXBfZG1hX21lbWNweSA9IHJlX2py
X3ByZXBfbWVtY3B5Ow0KKwlkbWFfY2FwX3NldChETUFfTUVNQ1BZLCBkbWFfZGV2LT5jYXBfbWFz
ayk7DQorDQorCWRtYV9kZXYtPmRldmljZV9mcmVlX2NoYW5fcmVzb3VyY2VzID0gcmVfanJfZnJl
ZV9jaGFuX3Jlc291cmNlczsNCisNCisJcmVwcml2LT50b3RhbF9qcnMgPSAwOw0KKw0KKwlyZXBy
aXYtPmRlc2NfcG9vbCA9IGRtYV9wb29sX2NyZWF0ZSgicmVfZG1hX2Rlc2NfcG9vbCIsIGRldiwN
CisJCQkJCVJFX0NGX0NEQl9TSVpFICogUklOR19TSVpFLA0KKwkJCQkJUkVfQ0ZfQ0RCX0FMSUdO
LCAwKTsNCisNCisJaWYgKCFyZXByaXYtPmRlc2NfcG9vbCkgew0KKwkJcHJfZXJyKCIlczpObyBt
ZW1vcnkgZm9yIGRtYSBkZXNjIHBvb2xcbiIsIF9fZnVuY19fKTsNCisJCXJldCA9IC1FTk9NRU07
DQorCQlnb3RvIGVycl9mcmVlXzM7DQorCX0NCisNCisJcmVwcml2LT5od19kZXNjX3Bvb2wgPSBk
bWFfcG9vbF9jcmVhdGUoInJlX2h3X2Rlc2NfcG9vbCIsIGRldiwNCisJCQkJc2l6ZW9mKHN0cnVj
dCBqcl9od19kZXNjKSAqIFJJTkdfU0laRSwNCisJCQkJRlJBTUVfREVTQ19BTElHTk1FTlQsIDAp
Ow0KKwlpZiAoIXJlcHJpdi0+aHdfZGVzY19wb29sKSB7DQorCQlwcl9lcnIoIiVzOk5vIG1lbW9y
eSBmb3IgaHcgZGVzYyBwb29sXG4iLCBfX2Z1bmNfXyk7DQorCQlyZXQgPSAtRU5PTUVNOw0KKwkJ
Z290byBlcnJfZnJlZV8yOw0KKwl9DQorDQorCS8qIFBhcnNlIERldmljZSB0cmVlIHRvIGZpbmQg
b3V0IHRoZSB0b3RhbCBudW1iZXIgb2YgSlFzIHByZXNlbnQgKi8NCisJZm9yX2VhY2hfY29tcGF0
aWJsZV9ub2RlKG5wLCBOVUxMLCAiZnNsLHJhaWRlbmctdjEuMC1qb2ItcXVldWUiKSB7DQorCQlv
ZmYgPSAodTMyICopb2ZfZ2V0X3Byb3BlcnR5KG5wLCAicmVnIiwgTlVMTCk7DQorCQlpZiAoIW9m
Zikgew0KKwkJCWRldl9lcnIoZGV2LCAiJXM6IFJlZyBwcm9wZXJ0eSBub3QgZm91bmQgaW4gSlEg
bm9kZVxuIiwNCisJCQkJX19mdW5jX18pOw0KKwkJCXJldHVybiAtRU5PREVWOw0KKwkJfQ0KKw0K
KwkJLyogRmluZCBvdXQgdGhlIEpvYiBSaW5ncyBwcmVzZW50IHVuZGVyIGVhY2ggSlEgKi8NCisJ
CWZvcl9lYWNoX2NoaWxkX29mX25vZGUobnAsIGNoaWxkKSB7DQorCQkJaWYgKG9mX2RldmljZV9p
c19jb21wYXRpYmxlKGNoaWxkLA0KKwkJCQkiZnNsLHJhaWRlbmctdjEuMC1qb2ItcmluZyIpKSB7
DQorCQkJCXJlX2pyX3Byb2JlKG9mZGV2LCBjaGlsZCwgcmlkeCsrLCBvZmYpOw0KKwkJCQlyZXBy
aXYtPnRvdGFsX2pycysrOw0KKwkJCX0NCisJCX0NCisJfQ0KKw0KKwlkbWFfYXN5bmNfZGV2aWNl
X3JlZ2lzdGVyKGRtYV9kZXYpOw0KKwlyZXR1cm4gMDsNCisNCitlcnJfZnJlZV8yOg0KKwlkbWFf
cG9vbF9kZXN0cm95KHJlcHJpdi0+ZGVzY19wb29sKTsNCitlcnJfZnJlZV8zOg0KKwlpb3VubWFw
KHJlcHJpdi0+cmVfcmVncyk7DQorZXJyX2ZyZWVfNDoNCisJa2ZyZWUocmVwcml2KTsNCisNCisJ
cmV0dXJuIHJldDsNCit9DQorDQorc3RhdGljIHZvaWQgcmVsZWFzZV9qcihzdHJ1Y3QgcmVfanIg
KmpyKSB7DQorCS8qIEZyZWUgdGhlIG1lbW9yeSBhbGxvY2F0ZWQgZnJvbSBETUEgcG9vbHMgYW5k
IGRlc3Ryb3kgdGhlbSAqLw0KKwlkbWFfcG9vbF9mcmVlKGpyLT5yZV9kZXYtPmh3X2Rlc2NfcG9v
bCwganItPmluYl9yaW5nX3ZpcnRfYWRkciwNCisJCWpyLT5pbmJfcGh5c19hZGRyKTsNCisJa2Zy
ZWUoanIpOw0KK30NCisNCitzdGF0aWMgaW50IHJhaWRlX3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1f
ZGV2aWNlICpvZmRldikgew0KKwlzdHJ1Y3QgcmVfZHJ2X3ByaXZhdGUgKnJlcHJpdiA9IE5VTEw7
DQorCXN0cnVjdCBkZXZpY2UgKmRldiA9IE5VTEw7DQorCWludCBpOw0KKw0KKwlkZXYgPSAmb2Zk
ZXYtPmRldjsNCisJcmVwcml2ID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorDQorCS8qIENsZWFu
dXAgSlIgcmVsYXRlZCBtZW1vcnkgYXJlYXMgKi8NCisJZm9yIChpID0gMDsgaSA8IHJlcHJpdi0+
dG90YWxfanJzOyBpKyspDQorCQlyZWxlYXNlX2pyKHJlcHJpdi0+cmVfanJzW2ldKTsNCisNCisJ
ZG1hX3Bvb2xfZGVzdHJveShyZXByaXYtPmh3X2Rlc2NfcG9vbCk7DQorCWRtYV9wb29sX2Rlc3Ry
b3kocmVwcml2LT5kZXNjX3Bvb2wpOw0KKw0KKwkvKiBVbnJlZ2lzdGVyIHRoZSBkcml2ZXIgKi8N
CisJZG1hX2FzeW5jX2RldmljZV91bnJlZ2lzdGVyKCZyZXByaXYtPmRtYV9kZXYpOw0KKw0KKwkv
KiBVbm1hcCB0aGUgUkFJRCBFbmdpbmUgcmVnaW9uICovDQorCWlvdW5tYXAocmVwcml2LT5yZV9y
ZWdzKTsNCisNCisJa2ZyZWUocmVwcml2KTsNCisNCisJcmV0dXJuIDA7DQorfQ0KKw0KK3N0YXRp
YyBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkIHJhaWRlX2lkc1tdID0gew0KKwl7IC5jb21wYXRpYmxlID0g
ImZzbCxyYWlkZW5nLXYxLjAiLCB9LA0KKwl7fQ0KK307DQorDQorc3RhdGljIHN0cnVjdCBwbGF0
Zm9ybV9kcml2ZXIgcmFpZGVfZHJpdmVyID0gew0KKwkuZHJpdmVyID0gew0KKwkJLm5hbWUgPSAi
ZnNsLXJhaWRlbmciLA0KKwkJLm93bmVyID0gVEhJU19NT0RVTEUsDQorCQkub2ZfbWF0Y2hfdGFi
bGUgPSByYWlkZV9pZHMsDQorCX0sDQorCS5wcm9iZSA9IHJhaWRlX3Byb2JlLA0KKwkucmVtb3Zl
ID0gcmFpZGVfcmVtb3ZlLA0KK307DQorDQorc3RhdGljIF9faW5pdCBpbnQgcmFpZGVfaW5pdCh2
b2lkKQ0KK3sNCisJaW50IHJldCA9IDA7DQorDQorCXJldCA9IHBsYXRmb3JtX2RyaXZlcl9yZWdp
c3RlcigmcmFpZGVfZHJpdmVyKTsNCisJaWYgKHJldCkNCisJCXByX2VycigiZnNsLXJhaWQ6IEZh
aWxlZCB0byByZWdpc3RlciBwbGF0Zm9ybSBkcml2ZXJcbiIpOw0KKw0KKwlyZXR1cm4gcmV0Ow0K
K30NCisNCitzdGF0aWMgdm9pZCBfX2V4aXQgcmFpZGVfZXhpdCh2b2lkKQ0KK3sNCisJcGxhdGZv
cm1fZHJpdmVyX3VucmVnaXN0ZXIoJnJhaWRlX2RyaXZlcik7DQorfQ0KKw0KK3N1YnN5c19pbml0
Y2FsbChyYWlkZV9pbml0KTsNCittb2R1bGVfZXhpdChyYWlkZV9leGl0KTsNCisNCitNT0RVTEVf
QVVUSE9SKCJIYXJuaW5kZXIgUmFpIDxoYXJuaW5kZXIucmFpQGZyZWVzY2FsZS5jb20+Iik7IA0K
K01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsgTU9EVUxFX0RFU0NSSVBUSU9OKCJGcmVlc2NhbGUg
UkFJRCBFbmdpbmUgDQorRGV2aWNlIERyaXZlciIpOw0KZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1h
L2ZzbF9yYWlkLmggYi9kcml2ZXJzL2RtYS9mc2xfcmFpZC5oIG5ldyBmaWxlIG1vZGUgMTAwNjQ0
IGluZGV4IDAwMDAwMDAuLjNjYjg0NTQNCi0tLSAvZGV2L251bGwNCisrKyBiL2RyaXZlcnMvZG1h
L2ZzbF9yYWlkLmgNCkBAIC0wLDAgKzEsMzE3IEBADQorLyoNCisgKiBkcml2ZXJzL2RtYS9mc2xf
cmFpZC5oDQorICoNCisgKiBGcmVlc2NhbGUgUkFJRCBFbmdpbmUgZGV2aWNlIGRyaXZlcg0KKyAq
DQorICogQXV0aG9yOg0KKyAqCUhhcm5pbmRlciBSYWkgPGhhcm5pbmRlci5yYWlAZnJlZXNjYWxl
LmNvbT4NCisgKglOYXZlZW4gQnVybWkgPG5hdmVlbmJ1cm1pQGZyZWVzY2FsZS5jb20+DQorICoN
CisgKiBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMiBGcmVlc2NhbGUgU2VtaWNvbmR1Y3RvciwgSW5j
Lg0KKyAqDQorICogUmVkaXN0cmlidXRpb24gYW5kIHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBm
b3Jtcywgd2l0aCBvciB3aXRob3V0DQorICogbW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHBy
b3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFyZSBtZXQ6DQorICogICAgICog
UmVkaXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3QgcmV0YWluIHRoZSBhYm92ZSBjb3B5
cmlnaHQNCisgKiAgICAgICBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUg
Zm9sbG93aW5nIGRpc2NsYWltZXIuDQorICogICAgICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFy
eSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCisgKiAgICAgICBub3Rp
Y2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIg
aW4gdGhlDQorICogICAgICAgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHBy
b3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4NCisgKiAgICAgKiBOZWl0aGVyIHRoZSBuYW1l
IG9mIEZyZWVzY2FsZSBTZW1pY29uZHVjdG9yIG5vciB0aGUNCisgKiAgICAgICBuYW1lcyBvZiBp
dHMgY29udHJpYnV0b3JzIG1heSBiZSB1c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0
cw0KKyAqICAgICAgIGRlcml2ZWQgZnJvbSB0aGlzIHNvZnR3YXJlIHdpdGhvdXQgc3BlY2lmaWMg
cHJpb3Igd3JpdHRlbiBwZXJtaXNzaW9uLg0KKyAqDQorICogQUxURVJOQVRJVkVMWSwgdGhpcyBz
b2Z0d2FyZSBtYXkgYmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIA0KK3RoZQ0KKyAq
IEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlICgiR1BMIikgYXMgcHVibGlzaGVkIGJ5IHRoZSBG
cmVlIFNvZnR3YXJlDQorICogRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGF0IExp
Y2Vuc2Ugb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkNCisgKiBsYXRlciB2ZXJzaW9uLg0KKyAqDQor
ICogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBGcmVlc2NhbGUgU2VtaWNvbmR1Y3RvciBg
YEFTIElTJycgQU5EIA0KK0FOWQ0KKyAqIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJ
TkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIA0KK0lNUExJRUQNCisgKiBXQVJSQU5U
SUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBP
U0UgDQorQVJFDQorICogRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTEwgRnJlZXNjYWxlIFNl
bWljb25kdWN0b3IgQkUgTElBQkxFIEZPUiANCitBTlkNCisgKiBESVJFQ1QsIElORElSRUNULCBJ
TkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgDQorREFNQUdF
Uw0KKyAqIChJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VC
U1RJVFVURSBHT09EUyBPUiANCitTRVJWSUNFUzsNCisgKiBMT1NTIE9GIFVTRSwgREFUQSwgT1Ig
UFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKSBIT1dFVkVSIA0KK0NBVVNFRCBBTkQN
CisgKiBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RS
SUNUIExJQUJJTElUWSwgDQorT1IgVE9SVA0KKyAqIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBP
VEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIA0KK1VTRSBPRiBUSElTDQor
ICogU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VDSCBE
QU1BR0UuDQorICoNCisgKi8NCisNCisjZGVmaW5lIFJFX0RQQUFfTU9ERQkJKDEgPDwgMzApDQor
I2RlZmluZSBSRV9OT05fRFBBQV9NT0RFCSgxIDw8IDMxKQ0KKyNkZWZpbmUgUkVfR0ZNX1BPTFkJ
CSgweDFkMDAwMDAwKQ0KKyNkZWZpbmUgUkVfSlJfSU5CX0pPQl9BREQoeCkJKCh4KSA8PCAxNikN
CisjZGVmaW5lIFJFX0pSX09VQl9KT0JfUkVNT1ZFKHgpCSgoeCkgPDwgMTYpDQorI2RlZmluZSBS
RV9KUl9DRkcxX0NCU0kJCTB4MDgwMDAwMDANCisjZGVmaW5lIFJFX0pSX0NGRzFfQ0JTMAkJMHgw
MDA4MDAwMA0KKyNkZWZpbmUgUkVfSlJfT1VCX1NMT1RfRlVMTF9TSElGVAk4DQorI2RlZmluZSBS
RV9KUl9PVUJfU0xPVF9GVUxMKHgpCSgoeCkgPj4gUkVfSlJfT1VCX1NMT1RfRlVMTF9TSElGVCkN
CisjZGVmaW5lIFJFX0pSX0lOQl9TTE9UX0FWQUlMX1NISUZUCTgNCisjZGVmaW5lIFJFX0pSX0lO
Ql9TTE9UX0FWQUlMKHgpCSgoeCkgPj4gUkVfSlJfSU5CX1NMT1RfQVZBSUxfU0hJRlQpDQorI2Rl
ZmluZSBSRV9QUV9PUENPREUJCTB4MUINCisjZGVmaW5lIFJFX1hPUl9PUENPREUJCTB4MUENCisj
ZGVmaW5lIFJFX01PVkVfT1BDT0RFCQkweDgNCisjZGVmaW5lIEZSQU1FX0RFU0NfQUxJR05NRU5U
CTE2DQorI2RlZmluZSBSRV9CTE9DS19TSVpFCQkweDMgLyogNDA5NiBieXRlcyAqLw0KKyNkZWZp
bmUgQ0FDSEVBQkxFX0lOUFVUX09VVFBVVAkweDANCisjZGVmaW5lIEJVRkZFUkFCTEVfT1VUUFVU
CTB4MA0KKyNkZWZpbmUgSU5URVJSVVBUX09OX0VSUk9SCTB4MQ0KKyNkZWZpbmUgREFUQV9ERVBF
TkRFTkNZCQkweDENCisjZGVmaW5lIEVOQUJMRV9EUEkJCTB4MA0KKyNkZWZpbmUgUklOR19TSVpF
CQkweDEwMDANCisjZGVmaW5lIFJJTkdfU0laRV9TSElGVAkJOA0KKyNkZWZpbmUgUkVfSlJfQURE
UkVTU19CSVRfU0hJRlQJNA0KKyNkZWZpbmUgUkVfSlJfQUREUkVTU19CSVRfTUFTSwkoKDEgPDwg
UkVfSlJfQUREUkVTU19CSVRfU0hJRlQpIC0gMSkNCisjZGVmaW5lIFJFX0pSX0VSUk9SCQkweDQw
MDAwMDAwDQorI2RlZmluZSBSRV9KUl9JTlRFUlJVUFQJCTB4ODAwMDAwMDANCisjZGVmaW5lIFJF
X0pSX0NMRUFSX0lOVAkJMHg4MDAwMDAwMA0KKyNkZWZpbmUgUkVfSlJfUEFVU0UJCTB4ODAwMDAw
MDANCisjZGVmaW5lIFJFX0pSX0VOQUJMRQkJMHg4MDAwMDAwMA0KKw0KKyNkZWZpbmUgUkVfSlJf
UkVHX0xJT0ROX01BU0sJMHgwMDAwMGZmZg0KKyNkZWZpbmUgUkVfQ0ZfQ0RCX0FMSUdOCQk2NA0K
Ky8qDQorICogdGhlIGxhcmdlc3QgY2YgYmxvY2sgaXMgMTkqc2l6ZW9mKHN0cnVjdCBjbXBuZF9m
cmFtZSksIHdoaWNoIGlzIDMwNCBieXRlcy4NCisgKiBoZXJlIDE5ID0gMShjZGIpKzIoZGVzdCkr
MTYoc3JjKSwgYWxpZ24gdG8gNjRieXRlcywgdGhhdCBpcyAzMjAgYnl0ZXMuDQorICogdGhlIGxh
cmdlc3QgY2RiIGJsb2NrOiBzdHJ1Y3QgcHFfY2RiIHdoaWNoIGlzIDE4MCBieXRlcywgYWRkaW5n
IHRvIA0KK2NmIGJsb2NrDQorICogMzIwKzE4MD01MDAsIGFsaWduIHRvIDY0Ynl0ZXMsIHRoYXQg
aXMgNTEyIGJ5dGVzLg0KKyAqLw0KKyNkZWZpbmUgUkVfQ0ZfREVTQ19TSVpFCQkzMjANCisjZGVm
aW5lIFJFX0NGX0NEQl9TSVpFCQk1MTINCisNCitzdHJ1Y3QgcmVfY3RybCB7DQorCS8qIEdlbmVy
YWwgQ29uZmlndXJhdGlvbiBSZWdpc3RlcnMgKi8NCisJX19iZTMyIGdsb2JhbF9jb25maWc7CS8q
IEdsb2JhbCBDb25maWd1cmF0aW9uIFJlZ2lzdGVyICovDQorCXU4ICAgICByc3ZkMVs0XTsNCisJ
X19iZTMyIGdhbG9pc19maWVsZF9jb25maWc7IC8qIEdhbG9pcyBGaWVsZCBDb25maWd1cmF0aW9u
IFJlZ2lzdGVyICovDQorCXU4ICAgICByc3ZkMls0XTsNCisJX19iZTMyIGpxX3dycl9jb25maWc7
ICAgLyogV1JSIENvbmZpZ3VyYXRpb24gcmVnaXN0ZXIgKi8NCisJdTggICAgIHJzdmQzWzRdOw0K
KwlfX2JlMzIgY3JjX2NvbmZpZzsJLyogQ1JDIENvbmZpZ3VyYXRpb24gcmVnaXN0ZXIgKi8NCisJ
dTggICAgIHJzdmQ0WzIyOF07DQorCV9fYmUzMiBzeXN0ZW1fcmVzZXQ7CS8qIFN5c3RlbSBSZXNl
dCBSZWdpc3RlciAqLw0KKwl1OCAgICAgcnN2ZDVbMjUyXTsNCisJX19iZTMyIGdsb2JhbF9zdGF0
dXM7CS8qIEdsb2JhbCBTdGF0dXMgUmVnaXN0ZXIgKi8NCisJdTggICAgIHJzdmQ2WzgzMl07DQor
CV9fYmUzMiByZV9saW9kbl9iYXNlOwkvKiBMSU9ETiBCYXNlIFJlZ2lzdGVyICovDQorCXU4ICAg
ICByc3ZkN1sxNzEyXTsNCisJX19iZTMyIHJlX3ZlcnNpb25faWQ7CS8qIFZlcnNpb24gSUQgcmVn
aXN0ZXIgb2YgUkUgKi8NCisJX19iZTMyIHJlX3ZlcnNpb25faWRfMjsgLyogVmVyc2lvbiBJRCAy
IHJlZ2lzdGVyIG9mIFJFICovDQorCXU4ICAgICByc3ZkOFs1MTJdOw0KKwlfX2JlMzIgaG9zdF9j
b25maWc7CS8qIEhvc3QgSS9GIENvbmZpZ3VyYXRpb24gUmVnaXN0ZXIgKi8NCit9Ow0KKw0KK3N0
cnVjdCBqcl9jb25maWdfcmVncyB7DQorCS8qIFJlZ2lzdGVycyBmb3IgSlIgaW50ZXJmYWNlICov
DQorCV9fYmUzMiBqcl9jb25maWdfMDsJLyogSm9iIFF1ZXVlIENvbmZpZ3VyYXRpb24gMCBSZWdp
c3RlciAqLw0KKwlfX2JlMzIganJfY29uZmlnXzE7CS8qIEpvYiBRdWV1ZSBDb25maWd1cmF0aW9u
IDEgUmVnaXN0ZXIgKi8NCisJX19iZTMyIGpyX2ludGVycnVwdF9zdGF0dXM7IC8qIEpvYiBRdWV1
ZSBJbnRlcnJ1cHQgU3RhdHVzIFJlZ2lzdGVyICovDQorCXU4ICAgICByc3ZkMVs0XTsNCisJX19i
ZTMyIGpyX2NvbW1hbmQ7CS8qIEpvYiBRdWV1ZSBDb21tYW5kIFJlZ2lzdGVyICovDQorCXU4ICAg
ICByc3ZkMls0XTsNCisJX19iZTMyIGpyX3N0YXR1czsJLyogSm9iIFF1ZXVlIFN0YXR1cyBSZWdp
c3RlciAqLw0KKwl1OCAgICAgcnN2ZDNbMjI4XTsNCisNCisJLyogSW5wdXQgUmluZyAqLw0KKwlf
X2JlMzIgaW5icmluZ19iYXNlX2g7CS8qIEluYm91bmQgUmluZyBCYXNlIEFkZHJlc3MgUmVnaXN0
ZXIgLSBIaWdoICovDQorCV9fYmUzMiBpbmJyaW5nX2Jhc2VfbDsJLyogSW5ib3VuZCBSaW5nIEJh
c2UgQWRkcmVzcyBSZWdpc3RlciAtIExvdyAqLw0KKwlfX2JlMzIgaW5icmluZ19zaXplOwkvKiBJ
bmJvdW5kIFJpbmcgU2l6ZSBSZWdpc3RlciAqLw0KKwl1OCAgICAgcnN2ZDRbNF07DQorCV9fYmUz
MiBpbmJyaW5nX3Nsb3RfYXZhaWw7IC8qIEluYm91bmQgUmluZyBTbG90IEF2YWlsYWJsZSBSZWdp
c3RlciAqLw0KKwl1OCAgICAgcnN2ZDVbNF07DQorCV9fYmUzMiBpbmJyaW5nX2FkZF9qb2I7CS8q
IEluYm91bmQgUmluZyBBZGQgSm9iIFJlZ2lzdGVyICovDQorCXU4ICAgICByc3ZkNls0XTsNCisJ
X19iZTMyIGluYnJpbmdfY25zbXJfaW5keDsgLyogSW5ib3VuZCBSaW5nIENvbnN1bWVyIEluZGV4
IFJlZ2lzdGVyICovDQorCXU4ICAgICByc3ZkN1syMjBdOw0KKw0KKwkvKiBPdXRwdXQgUmluZyAq
Lw0KKwlfX2JlMzIgb3VicmluZ19iYXNlX2g7CS8qIE91dGJvdW5kIFJpbmcgQmFzZSBBZGRyZXNz
IFJlZ2lzdGVyIC0gSGlnaCAqLw0KKwlfX2JlMzIgb3VicmluZ19iYXNlX2w7CS8qIE91dGJvdW5k
IFJpbmcgQmFzZSBBZGRyZXNzIFJlZ2lzdGVyIC0gTG93ICovDQorCV9fYmUzMiBvdWJyaW5nX3Np
emU7CS8qIE91dGJvdW5kIFJpbmcgU2l6ZSBSZWdpc3RlciAqLw0KKwl1OCAgICAgcnN2ZDhbNF07
DQorCV9fYmUzMiBvdWJyaW5nX2pvYl9ybXZkOyAvKiBPdXRib3VuZCBSaW5nIEpvYiBSZW1vdmVk
IFJlZ2lzdGVyICovDQorCXU4ICAgICByc3ZkOVs0XTsNCisJX19iZTMyIG91YnJpbmdfc2xvdF9m
dWxsOyAvKiBPdXRib3VuZCBSaW5nIFNsb3QgRnVsbCBSZWdpc3RlciAqLw0KKwl1OCAgICAgcnN2
ZDEwWzRdOw0KKwlfX2JlMzIgb3VicmluZ19wcmRjcl9pbmR4OyAvKiBPdXRib3VuZCBSaW5nIFBy
b2R1Y2VyIEluZGV4ICovIH07DQorDQorLyoNCisgKiBDb21tYW5kIERlc2NyaXB0b3IgQmxvY2sg
KENEQikgZm9yIHVuaWNhc3QgbW92ZSBjb21tYW5kLg0KKyAqIEluIFJBSUQgRW5naW5lIHRlcm1z
LCBtZW1jcHkgaXMgZG9uZSB0aHJvdWdoIG1vdmUgY29tbWFuZCAgKi8gc3RydWN0IA0KK21vdmVf
Y2RiIHsNCisJdTMyIG9wY29kZTo1Ow0KKwl1MzIgcnN2ZDE6MTE7DQorCXUzMiBibGtfc2l6ZToy
Ow0KKwl1MzIgY2FjaGVfYXR0cmliOjI7DQorCXUzMiBidWZmZXJfYXR0cmliOjE7DQorCXUzMiBl
cnJvcl9hdHRyaWI6MTsNCisJdTMyIHJzdmQyOjY7DQorCXUzMiBkYXRhX2RlcGVuZDoxOw0KKwl1
MzIgZHBpOjE7DQorCXUzMiByc3ZkMzoyOw0KK30gX19wYWNrZWQ7DQorDQorLyogRGF0YSBwcm90
ZWN0aW9uL2ludGVncml0eSByZWxhdGVkIGZpZWxkcyAqLyBzdHJ1Y3QgZHBpX3JlbGF0ZWQgew0K
Kwl1MzIgYXBwc19tdGhkOjI7DQorCXUzMiByZWZfbXRoZDoyOw0KKwl1MzIgZ3VhcmRfbXRoZDoy
Ow0KKwl1MzIgZHBpX2F0dHI6MjsNCisJdTMyIHJzdmQxOjg7DQorCXUzMiBtZXRhX3RhZzoxNjsN
CisJdTMyIHJlZl90YWc6MzI7DQorfSBfX3BhY2tlZDsNCisNCisvKg0KKyAqIENEQiBmb3IgR2Vu
USBjb21tYW5kLiBJbiBSQUlEIEVuZ2luZSB0ZXJtaW5vbG9neSwgWE9SIGlzDQorICogZG9uZSB0
aHJvdWdoIHRoaXMgY29tbWFuZA0KKyAqLw0KK3N0cnVjdCB4b3JfY2RiIHsNCisJdTMyIG9wY29k
ZTo1Ow0KKwl1MzIgcnN2ZDE6MTE7DQorCXUzMiBibGtfc2l6ZToyOw0KKwl1MzIgY2FjaGVfYXR0
cmliOjI7DQorCXUzMiBidWZmZXJfYXR0cmliOjE7DQorCXUzMiBlcnJvcl9hdHRyaWI6MTsNCisJ
dTMyIG5yY3M6NDsNCisJdTMyIHJzdmQyOjI7DQorCXUzMiBkYXRhX2RlcGVuZDoxOw0KKwl1MzIg
ZHBpOjE7DQorCXUzMiByc3ZkMzoyOw0KKwl1OCBnZm1bMTZdOw0KKwlzdHJ1Y3QgZHBpX3JlbGF0
ZWQgZHBpX2Rlc3Rfc3BlYzsNCisJc3RydWN0IGRwaV9yZWxhdGVkIGRwaV9zcmNfc3BlY1sxNl07
DQorfSBfX3BhY2tlZDsNCisNCisvKiBDREIgZm9yIG5vLW9wIGNvbW1hbmQgKi8NCitzdHJ1Y3Qg
bm9vcF9jZGIgew0KKwl1MzIgb3Bjb2RlOjU7DQorCXUzMiByc3ZkMToyMzsNCisJdTMyIGRlcGVu
ZGVuY3k6MTsNCisJdTMyIHJzdmQyOjM7DQorfSBfX3BhY2tlZDsNCisNCisvKg0KKyAqIENEQiBm
b3IgR2VuUVEgY29tbWFuZC4gSW4gUkFJRCBFbmdpbmUgdGVybWlub2xvZ3ksIFAvUSBpcw0KKyAq
IGRvbmUgdGhyb3VnaCB0aGlzIGNvbW1hbmQNCisgKi8NCitzdHJ1Y3QgcHFfY2RiIHsNCisJdTMy
IG9wY29kZTo1Ow0KKwl1MzIgcnN2ZDE6MTsNCisJdTMyIGV4Y2xfZW5hYmxlOjI7DQorCXUzMiBl
eGNsX3ExOjQ7DQorCXUzMiBleGNsX3EyOjQ7DQorCXUzMiBibGtfc2l6ZToyOw0KKwl1MzIgY2Fj
aGVfYXR0cmliOjI7DQorCXUzMiBidWZmZXJfYXR0cmliOjE7DQorCXUzMiBlcnJvcl9hdHRyaWI6
MTsNCisJdTMyIG5yY3M6NDsNCisJdTMyIHJzdmQyOjI7DQorCXUzMiBkYXRhX2RlcGVuZDoxOw0K
Kwl1MzIgZHBpOjE7DQorCXUzMiByc3ZkMzoyOw0KKwl1OCBnZm1fcTFbMTZdOw0KKwl1OCBnZm1f
cTJbMTZdOw0KKwlzdHJ1Y3QgZHBpX3JlbGF0ZWQgZHBpX2Rlc3Rfc3BlY1syXTsNCisJc3RydWN0
IGRwaV9yZWxhdGVkIGRwaV9zcmNfc3BlY1sxNl07DQorfSBfX3BhY2tlZDsNCisNCisvKiBDb21w
b3VuZCBmcmFtZSAqLw0KK3N0cnVjdCBjbXBuZF9mcmFtZSB7DQorCXU2NCByc3ZkMToyNDsNCisJ
dTY0IGFkZHJlc3M6NDA7DQorCXUzMiBleHRlbnNpb246MTsNCisJdTMyIGZpbmFsOjE7DQorCXUz
MiByc3ZkMzoxMDsNCisJdTMyIGxlbmd0aDoyMDsNCisJdTMyIHJzdmQ0Ojg7DQorCXUzMiBicGlk
Ojg7DQorCXUzMiByc3ZkNTozOw0KKwl1MzIgb2Zmc2V0OjEzOw0KK30gX19wYWNrZWQ7DQorDQor
LyogRnJhbWUgZGVzY3JpcHRvciAqLw0KK3N0cnVjdCBqcl9od19kZXNjIHsNCisJdTY0IGRlYnVn
OjI7DQorCXU2NCBsaW9kbl9vZmY6NjsNCisJdTY0IGJwaWQ6ODsNCisJdTY0IGVsaW9kbl9vZmY6
NDsNCisJdTY0IHJzdmQxOjQ7DQorCXU2NCBhZGRyZXNzOjQwOw0KKwl1NjQgZm9ybWF0OjM7DQor
CXU2NCByc3ZkMjoyOTsNCisJdTY0IHN0YXR1czozMjsNCit9IF9fcGFja2VkOw0KKw0KKyNkZWZp
bmUgTUFYX1JFX0pSUwkJNA0KKw0KKy8qIFJhaWQgRW5naW5lIGRldmljZSBwcml2YXRlIGRhdGEg
Ki8NCitzdHJ1Y3QgcmVfZHJ2X3ByaXZhdGUgew0KKwl1OCB0b3RhbF9qcnM7DQorCXN0cnVjdCBk
bWFfZGV2aWNlIGRtYV9kZXY7DQorCXN0cnVjdCByZV9jdHJsICpyZV9yZWdzOw0KKwlzdHJ1Y3Qg
cmVfanIgKnJlX2pyc1tNQVhfUkVfSlJTXTsNCisJc3RydWN0IGRtYV9wb29sICpkZXNjX3Bvb2w7
DQorCXN0cnVjdCBkbWFfcG9vbCAqaHdfZGVzY19wb29sOw0KK307DQorDQorLyogUGVyIGpvYiBy
aW5nIGRhdGEgc3RydWN0dXJlICovDQorc3RydWN0IHJlX2pyIHsNCisJZG1hX2Nvb2tpZV90IGNv
bXBsZXRlZF9jb29raWU7DQorCXNwaW5sb2NrX3QgZGVzY19sb2NrOw0KKwlzdHJ1Y3QgbGlzdF9o
ZWFkIGFja19xOw0KKwlzdHJ1Y3QgZGV2aWNlICpkZXY7DQorCXN0cnVjdCByZV9kcnZfcHJpdmF0
ZSAqcmVfZGV2Ow0KKwlzdHJ1Y3QgZG1hX2NoYW4gY2hhbjsNCisJc3RydWN0IGpyX2NvbmZpZ19y
ZWdzICpqcnJlZ3M7DQorCWludCBpcnE7DQorCXN0cnVjdCB0YXNrbGV0X3N0cnVjdCBpcnF0YXNr
Ow0KKw0KKwkvKiBodyBkZXNjcmlwdG9yIHJpbmcgZm9yIGluYm91bmQgcXVldWUqLw0KKwlkbWFf
YWRkcl90IGluYl9waHlzX2FkZHI7DQorCXN0cnVjdCBqcl9od19kZXNjICppbmJfcmluZ192aXJ0
X2FkZHI7DQorCXUzMiBpbmJfY291bnQ7DQorCXUzMiBwZW5kX2NvdW50Ow0KKwlzcGlubG9ja190
IGluYl9sb2NrOw0KKw0KKwkvKiBodyBkZXNjcmlwdG9yIHJpbmcgZm9yIG91dGJvdW5kIHF1ZXVl
ICovDQorCWRtYV9hZGRyX3Qgb3ViX3BoeXNfYWRkcjsNCisJc3RydWN0IGpyX2h3X2Rlc2MgKm91
Yl9yaW5nX3ZpcnRfYWRkcjsNCisJdTMyIG91Yl9jb3VudDsNCisJc3BpbmxvY2tfdCBvdWJfbG9j
azsNCisNCisJc3RydWN0IGZzbF9yZV9kbWFfYXN5bmNfdHhfZGVzYyAqZGVzY3M7IC8qIHN3IGRl
c2NyaXB0b3IgcmluZyAqLw0KKwl2b2lkICpjZnM7CQkJCS8qIGRtYSBkZXNjcmlwdG9yIHJpbmcg
Ki8NCisJZG1hX2FkZHJfdCBwaHlzOyAgICAgICAgICAvKiBwaHlzIGFkZHIgZm9yIGRtYSBkZXNj
cmlwdG9yIHJpbmcgKi8NCisNCisJc3RydWN0IHRpbWVyX2xpc3QgdGltZXI7DQorfTsNCisNCitl
bnVtIGRlc2Nfc3RhdGUgew0KKwlSRV9ERVNDX0VNUFRZLA0KKwlSRV9ERVNDX0FMTE9DLA0KK307
DQorDQorLyogQXN5bmMgdHJhbnNhY3Rpb24gZGVzY3JpcHRvciAqLw0KK3N0cnVjdCBmc2xfcmVf
ZG1hX2FzeW5jX3R4X2Rlc2Mgew0KKwlzdHJ1Y3QgZG1hX2FzeW5jX3R4X2Rlc2NyaXB0b3IgYXN5
bmNfdHg7DQorCXN0cnVjdCBsaXN0X2hlYWQgbm9kZTsNCisJc3RydWN0IGxpc3RfaGVhZCB0eF9s
aXN0Ow0KKwlzdHJ1Y3QganJfaHdfZGVzYyAqaHdkZXNjOw0KKwlzdHJ1Y3QgcmVfanIgKmpyOw0K
Kw0KKwl2b2lkICpjZl9hZGRyOw0KKwlpbnQgZG1hX2xlbjsNCisJdTggZGVzdF9jbnQ7DQorCXU4
IHNyY19jbnQ7DQorDQorCXUxNiBjZGJfb3Bjb2RlOw0KKwl2b2lkICpjZGJfYWRkcjsNCisJZG1h
X2FkZHJfdCBjZGJfcGFkZHI7DQorCWludCBjZGJfbGVuOw0KKw0KKwllbnVtIGRlc2Nfc3RhdGUg
c3RhdGU7DQorfTsNCi0tDQoxLjcuOS41DQoNCg==
^ permalink raw reply
* Re: [PATCH] powerpc: fixing ptrace_get_reg to return an error
From: Michael Neuling @ 2013-04-10 5:00 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: linuxppc-dev, Paul Mackerras, linux-kernel, David Gibson
In-Reply-To: <1360899863-17181-1-git-send-email-aik@ozlabs.ru>
Alexey Kardashevskiy <aik@ozlabs.ru> wrote:
> Currently ptrace_get_reg returns error as a value
> what make impossible to tell whether it is a correct value or error code.
>
> The patch adds a parameter which points to the real return data and
> returns an error code.
>
> As get_user_msr() never fails and it is used in multiple places so it has not
> been changed by this patch.
>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
FWIW:
Acked-by: Michael Neuling <mikey@neuling.org>
> ---
> arch/powerpc/include/asm/ptrace.h | 3 ++-
> arch/powerpc/kernel/ptrace.c | 29 ++++++++++++++++++-----------
> arch/powerpc/kernel/ptrace32.c | 15 ++++++++++++---
> 3 files changed, 32 insertions(+), 15 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
> index 5f99568..becc08e 100644
> --- a/arch/powerpc/include/asm/ptrace.h
> +++ b/arch/powerpc/include/asm/ptrace.h
> @@ -92,7 +92,8 @@ static inline long regs_return_value(struct pt_regs *regs)
> } while(0)
>
> struct task_struct;
> -extern unsigned long ptrace_get_reg(struct task_struct *task, int regno);
> +extern int ptrace_get_reg(struct task_struct *task, int regno,
> + unsigned long *data);
> extern int ptrace_put_reg(struct task_struct *task, int regno,
> unsigned long data);
>
> diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
> index 245c1b6..d5ff7ea 100644
> --- a/arch/powerpc/kernel/ptrace.c
> +++ b/arch/powerpc/kernel/ptrace.c
> @@ -180,9 +180,10 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
> }
>
> #ifdef CONFIG_PPC64
> -static unsigned long get_user_dscr(struct task_struct *task)
> +static int get_user_dscr(struct task_struct *task, unsigned long *data)
> {
> - return task->thread.dscr;
> + *data = task->thread.dscr;
> + return 0;
> }
>
> static int set_user_dscr(struct task_struct *task, unsigned long dscr)
> @@ -192,7 +193,7 @@ static int set_user_dscr(struct task_struct *task, unsigned long dscr)
> return 0;
> }
> #else
> -static unsigned long get_user_dscr(struct task_struct *task)
> +static int get_user_dscr(struct task_struct *task, unsigned long *data)
> {
> return -EIO;
> }
> @@ -216,19 +217,23 @@ static int set_user_trap(struct task_struct *task, unsigned long trap)
> /*
> * Get contents of register REGNO in task TASK.
> */
> -unsigned long ptrace_get_reg(struct task_struct *task, int regno)
> +int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data)
> {
> - if (task->thread.regs == NULL)
> + if ((task->thread.regs == NULL) || !data)
> return -EIO;
>
> - if (regno == PT_MSR)
> - return get_user_msr(task);
> + if (regno == PT_MSR) {
> + *data = get_user_msr(task);
> + return 0;
> + }
>
> if (regno == PT_DSCR)
> - return get_user_dscr(task);
> + return get_user_dscr(task, data);
>
> - if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
> - return ((unsigned long *)task->thread.regs)[regno];
> + if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
> + *data = ((unsigned long *)task->thread.regs)[regno];
> + return 0;
> + }
>
> return -EIO;
> }
> @@ -1559,7 +1564,9 @@ long arch_ptrace(struct task_struct *child, long request,
>
> CHECK_FULL_REGS(child->thread.regs);
> if (index < PT_FPR0) {
> - tmp = ptrace_get_reg(child, (int) index);
> + ret = ptrace_get_reg(child, (int) index, &tmp);
> + if (ret)
> + break;
> } else {
> unsigned int fpidx = index - PT_FPR0;
>
> diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
> index c0244e7..f51599e 100644
> --- a/arch/powerpc/kernel/ptrace32.c
> +++ b/arch/powerpc/kernel/ptrace32.c
> @@ -95,7 +95,9 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
>
> CHECK_FULL_REGS(child->thread.regs);
> if (index < PT_FPR0) {
> - tmp = ptrace_get_reg(child, index);
> + ret = ptrace_get_reg(child, index, &tmp);
> + if (ret)
> + break;
> } else {
> flush_fp_to_thread(child);
> /*
> @@ -148,7 +150,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
> tmp = ((u64 *)child->thread.fpr)
> [FPRINDEX_3264(numReg)];
> } else { /* register within PT_REGS struct */
> - tmp = ptrace_get_reg(child, numReg);
> + unsigned long tmp2;
> + ret = ptrace_get_reg(child, numReg, &tmp2);
> + if (ret)
> + break;
> + tmp = tmp2;
> }
> reg32bits = ((u32*)&tmp)[part];
> ret = put_user(reg32bits, (u32 __user *)data);
> @@ -232,7 +238,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
> break;
> CHECK_FULL_REGS(child->thread.regs);
> if (numReg < PT_FPR0) {
> - unsigned long freg = ptrace_get_reg(child, numReg);
> + unsigned long freg;
> + ret = ptrace_get_reg(child, numReg, &freg);
> + if (ret)
> + break;
> if (index % 2)
> freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
> else
> --
> 1.7.10.4
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
^ permalink raw reply
* Re: [RFC PATCH v2 6/6] powerpc: Use generic code for exception handling
From: Michael Ellerman @ 2013-04-10 4:56 UTC (permalink / raw)
To: Li Zhong; +Cc: fweisbec, paulmck, paulus, linux-kernel, linuxppc-dev
In-Reply-To: <1364551221-23177-7-git-send-email-zhong@linux.vnet.ibm.com>
On Fri, Mar 29, 2013 at 06:00:21PM +0800, Li Zhong wrote:
> After the exception handling moved to generic code, and some changes in
...
> diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> index 360fba8..eeab30f 100644
> --- a/arch/powerpc/mm/hash_utils_64.c
> +++ b/arch/powerpc/mm/hash_utils_64.c
> @@ -33,6 +33,7 @@
> #include <linux/init.h>
> #include <linux/signal.h>
> #include <linux/memblock.h>
> +#include <linux/context_tracking.h>
>
> #include <asm/processor.h>
> #include <asm/pgtable.h>
> @@ -56,7 +57,6 @@
> #include <asm/fadump.h>
> #include <asm/firmware.h>
> #include <asm/tm.h>
> -#include <asm/context_tracking.h>
>
> #ifdef DEBUG
> #define DBG(fmt...) udbg_printf(fmt)
> @@ -919,13 +919,17 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
> const struct cpumask *tmp;
> int rc, user_region = 0, local = 0;
> int psize, ssize;
> + enum ctx_state prev_state;
> +
> + prev_state = exception_enter();
>
> DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n",
> ea, access, trap);
>
> if ((ea & ~REGION_MASK) >= PGTABLE_RANGE) {
> DBG_LOW(" out of pgtable range !\n");
> - return 1;
> + rc = 1;
> + goto exit;
> }
>
> /* Get region & vsid */
This no longer applies on mainline, please send an updated version.
cheers
^ permalink raw reply
* Re: [PATCH -V5 06/25] powerpc: Reduce PTE table memory wastage
From: David Gibson @ 2013-04-10 4:46 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1365055083-31956-7-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 15308 bytes --]
On Thu, Apr 04, 2013 at 11:27:44AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>
> We allocate one page for the last level of linux page table. With THP and
> large page size of 16MB, that would mean we are wasting large part
> of that page. To map 16MB area, we only need a PTE space of 2K with 64K
> page size. This patch reduce the space wastage by sharing the page
> allocated for the last level of linux page table with multiple pmd
> entries. We call these smaller chunks PTE page fragments and allocated
> page, PTE page.
>
> In order to support systems which doesn't have 64K HPTE support, we also
> add another 2K to PTE page fragment. The second half of the PTE fragments
> is used for storing slot and secondary bit information of an HPTE. With this
> we now have a 4K PTE fragment.
>
> We use a simple approach to share the PTE page. On allocation, we bump the
> PTE page refcount to 16 and share the PTE page with the next 16 pte alloc
> request. This should help in the node locality of the PTE page fragment,
> assuming that the immediate pte alloc request will mostly come from the
> same NUMA node. We don't try to reuse the freed PTE page fragment. Hence
> we could be waisting some space.
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/mmu-book3e.h | 4 +
> arch/powerpc/include/asm/mmu-hash64.h | 4 +
> arch/powerpc/include/asm/page.h | 4 +
> arch/powerpc/include/asm/pgalloc-64.h | 72 ++++-------------
> arch/powerpc/kernel/setup_64.c | 4 +-
> arch/powerpc/mm/mmu_context_hash64.c | 35 +++++++++
> arch/powerpc/mm/pgtable_64.c | 137 +++++++++++++++++++++++++++++++++
> 7 files changed, 202 insertions(+), 58 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
> index 99d43e0..affbd68 100644
> --- a/arch/powerpc/include/asm/mmu-book3e.h
> +++ b/arch/powerpc/include/asm/mmu-book3e.h
> @@ -231,6 +231,10 @@ typedef struct {
> u64 high_slices_psize; /* 4 bits per slice for now */
> u16 user_psize; /* page size index */
> #endif
> +#ifdef CONFIG_PPC_64K_PAGES
> + /* for 4K PTE fragment support */
> + struct page *pgtable_page;
> +#endif
> } mm_context_t;
>
> /* Page size definitions, common between 32 and 64-bit
> diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
> index 35bb51e..300ac3c 100644
> --- a/arch/powerpc/include/asm/mmu-hash64.h
> +++ b/arch/powerpc/include/asm/mmu-hash64.h
> @@ -498,6 +498,10 @@ typedef struct {
> unsigned long acop; /* mask of enabled coprocessor types */
> unsigned int cop_pid; /* pid value used with coprocessors */
> #endif /* CONFIG_PPC_ICSWX */
> +#ifdef CONFIG_PPC_64K_PAGES
> + /* for 4K PTE fragment support */
> + struct page *pgtable_page;
> +#endif
> } mm_context_t;
>
>
> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
> index f072e97..38e7ff6 100644
> --- a/arch/powerpc/include/asm/page.h
> +++ b/arch/powerpc/include/asm/page.h
> @@ -378,7 +378,11 @@ void arch_free_page(struct page *page, int order);
>
> struct vm_area_struct;
>
> +#ifdef CONFIG_PPC_64K_PAGES
> +typedef pte_t *pgtable_t;
> +#else
> typedef struct page *pgtable_t;
> +#endif
Ugh, that's pretty horrible, though I don't see an easy way around it.
> #include <asm-generic/memory_model.h>
> #endif /* __ASSEMBLY__ */
> diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h
> index cdbf555..3418989 100644
> --- a/arch/powerpc/include/asm/pgalloc-64.h
> +++ b/arch/powerpc/include/asm/pgalloc-64.h
> @@ -150,6 +150,13 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
>
> #else /* if CONFIG_PPC_64K_PAGES */
>
> +extern pte_t *page_table_alloc(struct mm_struct *, unsigned long, int);
> +extern void page_table_free(struct mm_struct *, unsigned long *, int);
> +extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift);
> +#ifdef CONFIG_SMP
> +extern void __tlb_remove_table(void *_table);
> +#endif
> +
> #define pud_populate(mm, pud, pmd) pud_set(pud, (unsigned long)pmd)
>
> static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
> @@ -161,90 +168,42 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
> static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
> pgtable_t pte_page)
> {
> - pmd_populate_kernel(mm, pmd, page_address(pte_page));
> + pmd_set(pmd, (unsigned long)pte_page);
> }
>
> static inline pgtable_t pmd_pgtable(pmd_t pmd)
> {
> - return pmd_page(pmd);
> + return (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE);
> }
>
> static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
> unsigned long address)
> {
> - return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
> + return (pte_t *)page_table_alloc(mm, address, 1);
> }
>
> static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
> - unsigned long address)
> + unsigned long address)
> {
> - struct page *page;
> - pte_t *pte;
> -
> - pte = pte_alloc_one_kernel(mm, address);
> - if (!pte)
> - return NULL;
> - page = virt_to_page(pte);
> - pgtable_page_ctor(page);
> - return page;
> + return (pgtable_t)page_table_alloc(mm, address, 0);
> }
>
> static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
> {
> - free_page((unsigned long)pte);
> + page_table_free(mm, (unsigned long *)pte, 1);
> }
>
> static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
> {
> - pgtable_page_dtor(ptepage);
> - __free_page(ptepage);
> -}
> -
> -static inline void pgtable_free(void *table, unsigned index_size)
> -{
> - if (!index_size)
> - free_page((unsigned long)table);
> - else {
> - BUG_ON(index_size > MAX_PGTABLE_INDEX_SIZE);
> - kmem_cache_free(PGT_CACHE(index_size), table);
> - }
> + page_table_free(mm, (unsigned long *)ptepage, 0);
> }
>
> -#ifdef CONFIG_SMP
> -static inline void pgtable_free_tlb(struct mmu_gather *tlb,
> - void *table, int shift)
> -{
> - unsigned long pgf = (unsigned long)table;
> - BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
> - pgf |= shift;
> - tlb_remove_table(tlb, (void *)pgf);
> -}
> -
> -static inline void __tlb_remove_table(void *_table)
> -{
> - void *table = (void *)((unsigned long)_table & ~MAX_PGTABLE_INDEX_SIZE);
> - unsigned shift = (unsigned long)_table & MAX_PGTABLE_INDEX_SIZE;
> -
> - pgtable_free(table, shift);
> -}
> -#else /* !CONFIG_SMP */
> -static inline void pgtable_free_tlb(struct mmu_gather *tlb,
> - void *table, int shift)
> -{
> - pgtable_free(table, shift);
> -}
> -#endif /* CONFIG_SMP */
> -
> static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
> unsigned long address)
> {
> - struct page *page = page_address(table);
> -
> tlb_flush_pgtable(tlb, address);
> - pgtable_page_dtor(page);
> - pgtable_free_tlb(tlb, page, 0);
> + pgtable_free_tlb(tlb, table, 0);
> }
> -
> #endif /* CONFIG_PPC_64K_PAGES */
>
> static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
> @@ -258,7 +217,6 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
> kmem_cache_free(PGT_CACHE(PMD_INDEX_SIZE), pmd);
> }
>
> -
> #define __pmd_free_tlb(tlb, pmd, addr) \
> pgtable_free_tlb(tlb, pmd, PMD_INDEX_SIZE)
> #ifndef CONFIG_PPC_64K_PAGES
> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
> index 6da881b..04d833c 100644
> --- a/arch/powerpc/kernel/setup_64.c
> +++ b/arch/powerpc/kernel/setup_64.c
> @@ -575,7 +575,9 @@ void __init setup_arch(char **cmdline_p)
> init_mm.end_code = (unsigned long) _etext;
> init_mm.end_data = (unsigned long) _edata;
> init_mm.brk = klimit;
> -
> +#ifdef CONFIG_PPC_64K_PAGES
> + init_mm.context.pgtable_page = NULL;
> +#endif
> irqstack_early_init();
> exc_lvl_early_init();
> emergency_stack_init();
> diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
> index 59cd773..fbfdca2 100644
> --- a/arch/powerpc/mm/mmu_context_hash64.c
> +++ b/arch/powerpc/mm/mmu_context_hash64.c
> @@ -86,6 +86,9 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
> spin_lock_init(mm->context.cop_lockp);
> #endif /* CONFIG_PPC_ICSWX */
>
> +#ifdef CONFIG_PPC_64K_PAGES
> + mm->context.pgtable_page = NULL;
> +#endif
> return 0;
> }
>
> @@ -97,13 +100,45 @@ void __destroy_context(int context_id)
> }
> EXPORT_SYMBOL_GPL(__destroy_context);
>
> +#ifdef CONFIG_PPC_64K_PAGES
> +static void destroy_pagetable_page(struct mm_struct *mm)
> +{
> + int count;
> + struct page *page;
> +
> + page = mm->context.pgtable_page;
> + if (!page)
> + return;
> +
> + /* drop all the pending references */
> + count = atomic_read(&page->_mapcount) + 1;
> + /* We allow PTE_FRAG_NR(16) fragments from a PTE page */
> + count = atomic_sub_return(16 - count, &page->_count);
You should really move PTE_FRAG_NR to a header so you can actually use
it here rather than hard coding 16.
It took me a fair while to convince myself that there is no race here
with something altering mapcount and count between the atomic_read()
and the atomic_sub_return(). It could do with a comment to explain
why that is safe.
Re-using the mapcount field for your index also seems odd, and it took
me a while to convince myself that that's safe too. Wouldn't it be
simpler to store a pointer to the next sub-page in the mm_context
instead? You can get from that to the struct page easily enough with a
shift and pfn_to_page().
> + if (!count) {
> + pgtable_page_dtor(page);
> + reset_page_mapcount(page);
> + free_hot_cold_page(page, 0);
It would be nice to use put_page() somehow instead of duplicating its
logic, though I realise the sparc code you've based this on does the
same thing.
> + }
> +}
> +
> +#else
> +static inline void destroy_pagetable_page(struct mm_struct *mm)
> +{
> + return;
> +}
> +#endif
> +
> +
> void destroy_context(struct mm_struct *mm)
> {
> +
> #ifdef CONFIG_PPC_ICSWX
> drop_cop(mm->context.acop, mm);
> kfree(mm->context.cop_lockp);
> mm->context.cop_lockp = NULL;
> #endif /* CONFIG_PPC_ICSWX */
> +
> + destroy_pagetable_page(mm);
> __destroy_context(mm->context.id);
> subpage_prot_free(mm);
> mm->context.id = MMU_NO_CONTEXT;
> diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
> index e212a27..e79840b 100644
> --- a/arch/powerpc/mm/pgtable_64.c
> +++ b/arch/powerpc/mm/pgtable_64.c
> @@ -337,3 +337,140 @@ EXPORT_SYMBOL(__ioremap_at);
> EXPORT_SYMBOL(iounmap);
> EXPORT_SYMBOL(__iounmap);
> EXPORT_SYMBOL(__iounmap_at);
> +
> +#ifdef CONFIG_PPC_64K_PAGES
> +/*
> + * we support 16 fragments per PTE page. This is limited by how many
> + * bits we can pack in page->_mapcount. We use the first half for
> + * tracking the usage for rcu page table free.
> + */
> +#define PTE_FRAG_NR 16
> +/*
> + * We use a 2K PTE page fragment and another 2K for storing
> + * real_pte_t hash index
> + */
> +#define PTE_FRAG_SIZE (2 * PTRS_PER_PTE * sizeof(pte_t))
> +
> +static pte_t *get_from_cache(struct mm_struct *mm)
> +{
> + int index;
> + pte_t *ret = NULL;
> + struct page *page;
> +
> + spin_lock(&mm->page_table_lock);
> + page = mm->context.pgtable_page;
> + if (page) {
> + void *p = page_address(page);
> + index = atomic_add_return(1, &page->_mapcount);
> + ret = (pte_t *) (p + (index * PTE_FRAG_SIZE));
> + /*
> + * If we have taken up all the fragments mark PTE page NULL
> + */
> + if (index == PTE_FRAG_NR - 1)
> + mm->context.pgtable_page = NULL;
> + }
> + spin_unlock(&mm->page_table_lock);
> + return ret;
> +}
> +
> +static pte_t *__alloc_for_cache(struct mm_struct *mm, int kernel)
> +{
> + pte_t *ret = NULL;
> + struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK |
> + __GFP_REPEAT | __GFP_ZERO);
> + if (!page)
> + return NULL;
> +
> + spin_lock(&mm->page_table_lock);
> + /*
> + * If we find pgtable_page set, we return
> + * the allocated page with single fragement
> + * count.
> + */
> + if (likely(!mm->context.pgtable_page)) {
> + atomic_set(&page->_count, PTE_FRAG_NR);
> + atomic_set(&page->_mapcount, 0);
> + mm->context.pgtable_page = page;
> + }
.. and in the unlikely case where there *is* a pgtable_page already
set, what then? Seems like you should BUG_ON, or at least return NULL
- as it is you will return the first sub-page of that page again,
which is very likely in use.
> + spin_unlock(&mm->page_table_lock);
> +
> + ret = (unsigned long *)page_address(page);
> + if (!kernel)
> + pgtable_page_ctor(page);
> +
> + return ret;
> +}
> +
> +pte_t *page_table_alloc(struct mm_struct *mm, unsigned long vmaddr, int kernel)
> +{
> + pte_t *pte;
> +
> + pte = get_from_cache(mm);
> + if (pte)
> + return pte;
> +
> + return __alloc_for_cache(mm, kernel);
> +}
> +
> +void page_table_free(struct mm_struct *mm, unsigned long *table, int kernel)
> +{
> + struct page *page = virt_to_page(table);
> + if (put_page_testzero(page)) {
> + if (!kernel)
> + pgtable_page_dtor(page);
> + reset_page_mapcount(page);
> + free_hot_cold_page(page, 0);
> + }
> +}
> +
> +#ifdef CONFIG_SMP
> +static void page_table_free_rcu(void *table)
> +{
> + struct page *page = virt_to_page(table);
> + if (put_page_testzero(page)) {
> + pgtable_page_dtor(page);
> + reset_page_mapcount(page);
> + free_hot_cold_page(page, 0);
> + }
> +}
> +
> +void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
> +{
> + unsigned long pgf = (unsigned long)table;
> +
> + BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
> + pgf |= shift;
> + tlb_remove_table(tlb, (void *)pgf);
> +}
> +
> +void __tlb_remove_table(void *_table)
> +{
> + void *table = (void *)((unsigned long)_table & ~MAX_PGTABLE_INDEX_SIZE);
> + unsigned shift = (unsigned long)_table & MAX_PGTABLE_INDEX_SIZE;
> +
> + if (!shift)
> + /* PTE page needs special handling */
> + page_table_free_rcu(table);
> + else {
> + BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
> + kmem_cache_free(PGT_CACHE(shift), table);
> + }
> +}
> +#else
> +void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
> +{
> + if (!shift) {
> + /* PTE page needs special handling */
> + struct page *page = virt_to_page(table);
> + if (put_page_testzero(page)) {
> + pgtable_page_dtor(page);
> + reset_page_mapcount(page);
> + free_hot_cold_page(page, 0);
> + }
> + } else {
> + BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
> + kmem_cache_free(PGT_CACHE(shift), table);
> + }
> +}
> +#endif
> +#endif /* CONFIG_PPC_64K_PAGES */
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* [PATCH v2] of/base: release the node correctly in of_parse_phandle_with_args()
From: Yuantian.Tang @ 2013-04-10 3:36 UTC (permalink / raw)
To: grant.likely
Cc: Tang Yuantian, devicetree-discuss, linuxppc-dev, linux-kernel,
rob.herring
From: Tang Yuantian <yuantian.tang@freescale.com>
Call of_node_put() only when the out_args is NULL on success,
or the node's reference count will not be correct because the caller
will call of_node_put() again.
Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
---
v2:
- modified the title and description. the 1st patch title is:
of: remove the unnecessary of_node_put for of_parse_phandle_with_args()
the 1st patch is not good enough.
drivers/of/base.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 321d3ef..ee94f64 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1158,6 +1158,7 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
if (!phandle)
goto err;
+ /* Found it! return success */
if (out_args) {
int i;
if (WARN_ON(count > MAX_PHANDLE_ARGS))
@@ -1166,11 +1167,10 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
out_args->args_count = count;
for (i = 0; i < count; i++)
out_args->args[i] = be32_to_cpup(list++);
+ } else if (node) {
+ of_node_put(node);
}
- /* Found it! return success */
- if (node)
- of_node_put(node);
return 0;
}
--
1.8.0
^ permalink raw reply related
* [PATCH V5] powerpc/MPIC: Add get_version API both for internal and external use
From: Jia Hongtao @ 2013-04-10 2:52 UTC (permalink / raw)
To: linuxppc-dev, galak; +Cc: B07421, hongtao.jia
MPIC version is useful information for both mpic_alloc() and mpic_init().
The patch provide an API to get MPIC version for reusing the code.
Also, some other IP block may need MPIC version for their own use.
The API for external use is also provided.
Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
V5:
* add MPIC_FSL check for fsl_mpic_get_version().
V4:
* change the name of function from mpic_get_version() to
fsl_mpic_get_version().
V3:
* change the name of function from mpic_primary_get_version() to
fsl_mpic_primary_get_version().
* return 0 if mpic_primary is null.
V2:
* Using mpic_get_version() to implement mpic_primary_get_version()
arch/powerpc/include/asm/mpic.h | 3 +++
arch/powerpc/sysdev/mpic.c | 32 +++++++++++++++++++++++++-------
2 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index c0f9ef9..ea6bf72 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -393,6 +393,9 @@ struct mpic
#define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */
#define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */
+/* Get the version of primary MPIC */
+extern u32 fsl_mpic_primary_get_version(void);
+
/* Allocate the controller structure and setup the linux irq descs
* for the range if interrupts passed in. No HW initialization is
* actually performed.
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index d30e6a6..47ef4ba 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1165,10 +1165,33 @@ static struct irq_domain_ops mpic_host_ops = {
.xlate = mpic_host_xlate,
};
+static u32 fsl_mpic_get_version(struct mpic *mpic)
+{
+ u32 brr1;
+
+ if (!(mpic->flags & MPIC_FSL))
+ return 0;
+
+ brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+ MPIC_FSL_BRR1);
+
+ return brr1 & MPIC_FSL_BRR1_VER;
+}
+
/*
* Exported functions
*/
+u32 fsl_mpic_primary_get_version(void)
+{
+ struct mpic *mpic = mpic_primary;
+
+ if (mpic)
+ return fsl_mpic_get_version(mpic);
+
+ return 0;
+}
+
struct mpic * __init mpic_alloc(struct device_node *node,
phys_addr_t phys_addr,
unsigned int flags,
@@ -1315,7 +1338,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
if (mpic->flags & MPIC_FSL) {
- u32 brr1;
int ret;
/*
@@ -1326,9 +1348,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
MPIC_CPU_THISBASE, 0x1000);
- brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- fsl_version = brr1 & MPIC_FSL_BRR1_VER;
+ fsl_version = fsl_mpic_get_version(mpic);
/* Error interrupt mask register (EIMR) is required for
* handling individual device error interrupts. EIMR
@@ -1518,9 +1538,7 @@ void __init mpic_init(struct mpic *mpic)
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
if (mpic->flags & MPIC_FSL) {
- u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- u32 version = brr1 & MPIC_FSL_BRR1_VER;
+ u32 version = fsl_mpic_get_version(mpic);
/*
* Timer group B is present at the latest in MPIC 3.1 (e.g.
--
1.8.0
^ permalink raw reply related
* RE: [PATCH V4] powerpc/MPIC: Add get_version API both for internal and external use
From: Jia Hongtao-B38951 @ 2013-04-10 3:26 UTC (permalink / raw)
To: Wood Scott-B07421; +Cc: linuxppc-dev@lists.ozlabs.org, Li Yang-R58472
In-Reply-To: <1365564008.29365.3@snotra>
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Wednesday, April 10, 2013 11:20 AM
> To: Jia Hongtao-B38951
> Cc: Wood Scott-B07421; linuxppc-dev@lists.ozlabs.org;
> galak@kernel.crashing.org; Li Yang-R58472
> Subject: Re: [PATCH V4] powerpc/MPIC: Add get_version API both for
> internal and external use
>=20
> On 04/09/2013 10:14:06 PM, Jia Hongtao-B38951 wrote:
> >
> >
> > > -----Original Message-----
> > > From: Wood Scott-B07421
> > > Sent: Wednesday, April 10, 2013 11:12 AM
> > > To: Jia Hongtao-B38951
> > > Cc: Wood Scott-B07421; linuxppc-dev@lists.ozlabs.org;
> > > galak@kernel.crashing.org; Li Yang-R58472
> > > Subject: Re: [PATCH V4] powerpc/MPIC: Add get_version API both for
> > > internal and external use
> > >
> > > On 04/09/2013 10:10:37 PM, Jia Hongtao-B38951 wrote:
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Wood Scott-B07421
> > > > > Sent: Wednesday, April 10, 2013 11:08 AM
> > > > > To: Jia Hongtao-B38951
> > > > > Cc: Wood Scott-B07421; linuxppc-dev@lists.ozlabs.org;
> > > > > galak@kernel.crashing.org; Li Yang-R58472
> > > > > Subject: Re: [PATCH V4] powerpc/MPIC: Add get_version API both
> > for
> > > > > internal and external use
> > > > >
> > > > > On 04/09/2013 10:04:44 PM, Jia Hongtao-B38951 wrote:
> > > > > > Since all the functions including mpic_alloc() and
> > mpic_init() do
> > > > the
> > > > > > check for MPIC_FSL before using fsl_mpic_get_version() I'd
> > like
> > > > to add
> > > > > > check just for fsl_mpic_primary_get_version().
> > > > > >
> > > > > > It will be like this:
> > > > > > u32 fsl_mpic_primary_get_version(void)
> > > > > > {
> > > > > > struct mpic *mpic =3D mpic_primary;
> > > > > >
> > > > > > if (mpic && (mpic->flags & MPIC_FSL))
> > > > > > return fsl_mpic_get_version(mpic);
> > > > > >
> > > > > > return 0;
> > > > > > }
> > > > > >
> > > > > > Could we reach an agreement here?
> > > > >
> > > > > Is there any particular reason? It would be more robust and
> > more
> > > > > consistent if the check were done in fsl_mpic_get_version().
> > > > >
> > > > > -Scott
> > > >
> > > > I found out that all the functions using fsl_mpic_get_version()
> > have
> > > > already done the check. Adding the check in fsl_mpic_get_version()
> > > > will cause duplicate check there. This is my consideration.
> > >
> > > Does that duplicate check cause any harm?
> > >
> > > -Scott
> >
> > No harm at all just not necessary.
>=20
> Not *necessary*, but makes it more robust and more consistent.
>=20
> > I wonder if I could add check in fsl_mpic_get_version() and remove
> > all the
> > check from functions in which using fsl_mpic_get_version()?
>=20
> One of the two places that calls it is the place that maps thiscpuregs
> in the first place, so no. :-)
Reasonable enough.
I will just add check in fsl_mpic_get_version().
Thanks.
-Hongtao.
>=20
> The check in mpic_init() for the number of timers could perhaps have
> the check removed if we're comfortable equating a version of zero with
> a non-FSL MPIC. This really isn't something that's worth worrying
> about, though.
>=20
> -Scott
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox