aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kurz <gkurz@linux.vnet.ibm.com>2015-02-23 10:14:37 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2015-03-17 19:48:59 -0400
commit3338a65badd5758c8723e2b1e5a0db88151f2774 (patch)
tree64d0f14de7a054c890dcd620b8b9281d2d183886
parent4b6cfb2a8cd7520e8a747718e5c1da047697ca31 (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.c54
-rw-r--r--arch/powerpc/mm/vphn.h6
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 */
8int vphn_unpack_associativity(const long *packed, __be32 *unpacked) 24int 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
14extern int vphn_unpack_associativity(const long *packed, __be32 *unpacked); 14extern int vphn_unpack_associativity(const long *packed, __be32 *unpacked);
15 15