hc
2023-10-25 6c2073b7aa40e29d0eca7d571dd7bc590c7ecaa7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// SPDX-License-Identifier: GPL-2.0
#include <asm/byteorder.h>
#include "vphn.h"
 
/*
 * The associativity domain numbers are returned from the hypervisor as a
 * stream of mixed 16-bit and 32-bit fields. The stream is terminated by the
 * special value of "all ones" (aka. 0xffff) and its size may not exceed 48
 * bytes.
 *
 *    --- 16-bit fields -->
 *  _________________________
 *  |  0  |  1  |  2  |  3  |   be_packed[0]
 *  ------+-----+-----+------
 *  _________________________
 *  |  4  |  5  |  6  |  7  |   be_packed[1]
 *  -------------------------
 *            ...
 *  _________________________
 *  | 20  | 21  | 22  | 23  |   be_packed[5]
 *  -------------------------
 *
 * Convert to the sequence they would appear in the ibm,associativity property.
 */
int vphn_unpack_associativity(const long *packed, __be32 *unpacked)
{
   __be64 be_packed[VPHN_REGISTER_COUNT];
   int i, nr_assoc_doms = 0;
   const __be16 *field = (const __be16 *) be_packed;
   u16 last = 0;
   bool is_32bit = false;
 
#define VPHN_FIELD_UNUSED    (0xffff)
#define VPHN_FIELD_MSB        (0x8000)
#define VPHN_FIELD_MASK        (~VPHN_FIELD_MSB)
 
   /* Let's fix the values returned by plpar_hcall9() */
   for (i = 0; i < VPHN_REGISTER_COUNT; i++)
       be_packed[i] = cpu_to_be64(packed[i]);
 
   for (i = 1; i < VPHN_ASSOC_BUFSIZE; i++) {
       u16 new = be16_to_cpup(field++);
 
       if (is_32bit) {
           /* Let's concatenate the 16 bits of this field to the
            * 15 lower bits of the previous field
            */
           unpacked[++nr_assoc_doms] =
               cpu_to_be32(last << 16 | new);
           is_32bit = false;
       } else if (new == VPHN_FIELD_UNUSED)
           /* This is the list terminator */
           break;
       else if (new & VPHN_FIELD_MSB) {
           /* Data is in the lower 15 bits of this field */
           unpacked[++nr_assoc_doms] =
               cpu_to_be32(new & VPHN_FIELD_MASK);
       } else {
           /* Data is in the lower 15 bits of this field
            * concatenated with the next 16 bit field
            */
           last = new;
           is_32bit = true;
       }
   }
 
   /* The first cell contains the length of the property */
   unpacked[0] = cpu_to_be32(nr_assoc_doms);
 
   return nr_assoc_doms;
}