Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <asm/byteorder.h>
0003 #include <asm/lppaca.h>
0004 
0005 /*
0006  * The associativity domain numbers are returned from the hypervisor as a
0007  * stream of mixed 16-bit and 32-bit fields. The stream is terminated by the
0008  * special value of "all ones" (aka. 0xffff) and its size may not exceed 48
0009  * bytes.
0010  *
0011  *    --- 16-bit fields -->
0012  *  _________________________
0013  *  |  0  |  1  |  2  |  3  |   be_packed[0]
0014  *  ------+-----+-----+------
0015  *  _________________________
0016  *  |  4  |  5  |  6  |  7  |   be_packed[1]
0017  *  -------------------------
0018  *            ...
0019  *  _________________________
0020  *  | 20  | 21  | 22  | 23  |   be_packed[5]
0021  *  -------------------------
0022  *
0023  * Convert to the sequence they would appear in the ibm,associativity property.
0024  */
0025 static int vphn_unpack_associativity(const long *packed, __be32 *unpacked)
0026 {
0027     __be64 be_packed[VPHN_REGISTER_COUNT];
0028     int i, nr_assoc_doms = 0;
0029     const __be16 *field = (const __be16 *) be_packed;
0030     u16 last = 0;
0031     bool is_32bit = false;
0032 
0033 #define VPHN_FIELD_UNUSED   (0xffff)
0034 #define VPHN_FIELD_MSB      (0x8000)
0035 #define VPHN_FIELD_MASK     (~VPHN_FIELD_MSB)
0036 
0037     /* Let's fix the values returned by plpar_hcall9() */
0038     for (i = 0; i < VPHN_REGISTER_COUNT; i++)
0039         be_packed[i] = cpu_to_be64(packed[i]);
0040 
0041     for (i = 1; i < VPHN_ASSOC_BUFSIZE; i++) {
0042         u16 new = be16_to_cpup(field++);
0043 
0044         if (is_32bit) {
0045             /*
0046              * Let's concatenate the 16 bits of this field to the
0047              * 15 lower bits of the previous field
0048              */
0049             unpacked[++nr_assoc_doms] =
0050                 cpu_to_be32(last << 16 | new);
0051             is_32bit = false;
0052         } else if (new == VPHN_FIELD_UNUSED)
0053             /* This is the list terminator */
0054             break;
0055         else if (new & VPHN_FIELD_MSB) {
0056             /* Data is in the lower 15 bits of this field */
0057             unpacked[++nr_assoc_doms] =
0058                 cpu_to_be32(new & VPHN_FIELD_MASK);
0059         } else {
0060             /*
0061              * Data is in the lower 15 bits of this field
0062              * concatenated with the next 16 bit field
0063              */
0064             last = new;
0065             is_32bit = true;
0066         }
0067     }
0068 
0069     /* The first cell contains the length of the property */
0070     unpacked[0] = cpu_to_be32(nr_assoc_doms);
0071 
0072     return nr_assoc_doms;
0073 }
0074 
0075 /* NOTE: This file is included by a selftest and built in userspace. */
0076 #ifdef __KERNEL__
0077 #include <asm/hvcall.h>
0078 
0079 long hcall_vphn(unsigned long cpu, u64 flags, __be32 *associativity)
0080 {
0081     long rc;
0082     long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
0083 
0084     rc = plpar_hcall9(H_HOME_NODE_ASSOCIATIVITY, retbuf, flags, cpu);
0085     if (rc == H_SUCCESS)
0086         vphn_unpack_associativity(retbuf, associativity);
0087 
0088     return rc;
0089 }
0090 #endif