diff options
author | Greg Kurz <gkurz@linux.vnet.ibm.com> | 2015-02-23 10:14:37 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-03-17 19:48:59 -0400 |
commit | 3338a65badd5758c8723e2b1e5a0db88151f2774 (patch) | |
tree | 64d0f14de7a054c890dcd620b8b9281d2d183886 | |
parent | 4b6cfb2a8cd7520e8a747718e5c1da047697ca31 (diff) |
powerpc/vphn: parsing code rewrite
The current VPHN parsing logic has some flaws that this patch aims to fix:
1) when the value 0xffff is read, the value 0xffffffff gets added to the
the output list and its element count isn't incremented. This is wrong.
According to PAPR+ the domain identifiers are packed into a sequence
terminated by the "reserved value of all ones". This means that 0xffff
is a stream terminator.
2) the combination of byteswaps and casts make the code hardly readable.
Let's parse the stream one 16-bit field at a time instead.
3) it is assumed that the hypercall returns 12 32-bit values packed into
6 64-bit registers. According to PAPR+, the domain identifiers may be
streamed as 16-bit values. Let's increase the number of expected numbers
to 24.
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/mm/vphn.c | 54 | ||||
-rw-r--r-- | arch/powerpc/mm/vphn.h | 6 |
2 files changed, 40 insertions, 20 deletions
diff --git a/arch/powerpc/mm/vphn.c b/arch/powerpc/mm/vphn.c index c49ed519c381..5f8ef50e5c66 100644 --- a/arch/powerpc/mm/vphn.c +++ b/arch/powerpc/mm/vphn.c | |||
@@ -2,44 +2,64 @@ | |||
2 | #include "vphn.h" | 2 | #include "vphn.h" |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * Convert the associativity domain numbers returned from the hypervisor | 5 | * The associativity domain numbers are returned from the hypervisor as a |
6 | * to the sequence they would appear in the ibm,associativity property. | 6 | * stream of mixed 16-bit and 32-bit fields. The stream is terminated by the |
7 | * special value of "all ones" (aka. 0xffff) and its size may not exceed 48 | ||
8 | * bytes. | ||
9 | * | ||
10 | * --- 16-bit fields --> | ||
11 | * _________________________ | ||
12 | * | 0 | 1 | 2 | 3 | be_packed[0] | ||
13 | * ------+-----+-----+------ | ||
14 | * _________________________ | ||
15 | * | 4 | 5 | 6 | 7 | be_packed[1] | ||
16 | * ------------------------- | ||
17 | * ... | ||
18 | * _________________________ | ||
19 | * | 20 | 21 | 22 | 23 | be_packed[5] | ||
20 | * ------------------------- | ||
21 | * | ||
22 | * Convert to the sequence they would appear in the ibm,associativity property. | ||
7 | */ | 23 | */ |
8 | int vphn_unpack_associativity(const long *packed, __be32 *unpacked) | 24 | int vphn_unpack_associativity(const long *packed, __be32 *unpacked) |
9 | { | 25 | { |
10 | __be64 be_packed[VPHN_REGISTER_COUNT]; | 26 | __be64 be_packed[VPHN_REGISTER_COUNT]; |
11 | int i, nr_assoc_doms = 0; | 27 | int i, nr_assoc_doms = 0; |
12 | const __be16 *field = (const __be16 *) be_packed; | 28 | const __be16 *field = (const __be16 *) be_packed; |
29 | u16 last = 0; | ||
30 | bool is_32bit = false; | ||
13 | 31 | ||
14 | #define VPHN_FIELD_UNUSED (0xffff) | 32 | #define VPHN_FIELD_UNUSED (0xffff) |
15 | #define VPHN_FIELD_MSB (0x8000) | 33 | #define VPHN_FIELD_MSB (0x8000) |
16 | #define VPHN_FIELD_MASK (~VPHN_FIELD_MSB) | 34 | #define VPHN_FIELD_MASK (~VPHN_FIELD_MSB) |
17 | 35 | ||
18 | /* Let's recreate the original stream. */ | 36 | /* Let's fix the values returned by plpar_hcall9() */ |
19 | for (i = 0; i < VPHN_REGISTER_COUNT; i++) | 37 | for (i = 0; i < VPHN_REGISTER_COUNT; i++) |
20 | be_packed[i] = cpu_to_be64(packed[i]); | 38 | be_packed[i] = cpu_to_be64(packed[i]); |
21 | 39 | ||
22 | for (i = 1; i < VPHN_ASSOC_BUFSIZE; i++) { | 40 | for (i = 1; i < VPHN_ASSOC_BUFSIZE; i++) { |
23 | if (be16_to_cpup(field) == VPHN_FIELD_UNUSED) { | 41 | u16 new = be16_to_cpup(field++); |
24 | /* All significant fields processed, and remaining | 42 | |
25 | * fields contain the reserved value of all 1's. | 43 | if (is_32bit) { |
26 | * Just store them. | 44 | /* Let's concatenate the 16 bits of this field to the |
45 | * 15 lower bits of the previous field | ||
27 | */ | 46 | */ |
28 | unpacked[i] = *((__be32 *)field); | 47 | unpacked[++nr_assoc_doms] = |
29 | field += 2; | 48 | cpu_to_be32(last << 16 | new); |
30 | } else if (be16_to_cpup(field) & VPHN_FIELD_MSB) { | 49 | is_32bit = false; |
50 | } else if (new == VPHN_FIELD_UNUSED) | ||
51 | /* This is the list terminator */ | ||
52 | break; | ||
53 | else if (new & VPHN_FIELD_MSB) { | ||
31 | /* Data is in the lower 15 bits of this field */ | 54 | /* Data is in the lower 15 bits of this field */ |
32 | unpacked[i] = cpu_to_be32( | 55 | unpacked[++nr_assoc_doms] = |
33 | be16_to_cpup(field) & VPHN_FIELD_MASK); | 56 | cpu_to_be32(new & VPHN_FIELD_MASK); |
34 | field++; | ||
35 | nr_assoc_doms++; | ||
36 | } else { | 57 | } else { |
37 | /* Data is in the lower 15 bits of this field | 58 | /* Data is in the lower 15 bits of this field |
38 | * concatenated with the next 16 bit field | 59 | * concatenated with the next 16 bit field |
39 | */ | 60 | */ |
40 | unpacked[i] = *((__be32 *)field); | 61 | last = new; |
41 | field += 2; | 62 | is_32bit = true; |
42 | nr_assoc_doms++; | ||
43 | } | 63 | } |
44 | } | 64 | } |
45 | 65 | ||
diff --git a/arch/powerpc/mm/vphn.h b/arch/powerpc/mm/vphn.h index 96af9a474693..fe8b7805b78f 100644 --- a/arch/powerpc/mm/vphn.h +++ b/arch/powerpc/mm/vphn.h | |||
@@ -6,10 +6,10 @@ | |||
6 | #define VPHN_REGISTER_COUNT 6 | 6 | #define VPHN_REGISTER_COUNT 6 |
7 | 7 | ||
8 | /* | 8 | /* |
9 | * 6 64-bit registers unpacked into 12 32-bit associativity values. To form | 9 | * 6 64-bit registers unpacked into up to 24 be32 associativity values. To |
10 | * the complete property we have to add the length in the first cell. | 10 | * form the complete property we have to add the length in the first cell. |
11 | */ | 11 | */ |
12 | #define VPHN_ASSOC_BUFSIZE (VPHN_REGISTER_COUNT*sizeof(u64)/sizeof(u32) + 1) | 12 | #define VPHN_ASSOC_BUFSIZE (VPHN_REGISTER_COUNT*sizeof(u64)/sizeof(u16) + 1) |
13 | 13 | ||
14 | extern int vphn_unpack_associativity(const long *packed, __be32 *unpacked); | 14 | extern int vphn_unpack_associativity(const long *packed, __be32 *unpacked); |
15 | 15 | ||