| // 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; | 
 | } |