^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * apple.c - Apple ACPI quirks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/bitmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/platform_data/x86/apple.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/uuid.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) /* Apple _DSM device properties GUID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static const guid_t apple_prp_guid =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) 0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * @adev: ACPI device for which to retrieve the properties
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Invoke Apple's custom _DSM once to check the protocol version and once more
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * to retrieve the properties. They are marshalled up in a single package as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * alternating key/value elements, unlike _DSD which stores them as a package
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * of 2-element packages. Convert to _DSD format and make them available under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * the primary fwnode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) void acpi_extract_apple_properties(struct acpi_device *adev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) unsigned int i, j = 0, newsize = 0, numprops, numvalid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) union acpi_object *props, *newprops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) unsigned long *valid = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) void *free_space;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (!x86_apple_machine)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) NULL, ACPI_TYPE_BUFFER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (!props)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (!props->buffer.length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (props->buffer.pointer[0] != 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) acpi_handle_info(adev->handle, FW_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) "unsupported properties version %*ph\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) props->buffer.length, props->buffer.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) ACPI_FREE(props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) NULL, ACPI_TYPE_PACKAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (!props)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) numprops = props->package.count / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (!numprops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) valid = bitmap_zalloc(numprops, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (!valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* newsize = key length + value length of each tuple */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) for (i = 0; i < numprops; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) union acpi_object *key = &props->package.elements[i * 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) union acpi_object *val = &props->package.elements[i * 2 + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if ( key->type != ACPI_TYPE_STRING ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) (val->type != ACPI_TYPE_INTEGER &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) val->type != ACPI_TYPE_BUFFER))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) continue; /* skip invalid properties */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) __set_bit(i, valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) newsize += key->string.length + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if ( val->type == ACPI_TYPE_BUFFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) newsize += val->buffer.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) numvalid = bitmap_weight(valid, numprops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (numprops > numvalid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) acpi_handle_info(adev->handle, FW_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) "skipped %u properties: wrong type\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) numprops - numvalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (numvalid == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* newsize += top-level package + 3 objects for each key/value tuple */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) newsize += (1 + 3 * numvalid) * sizeof(union acpi_object);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) newprops = ACPI_ALLOCATE_ZEROED(newsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (!newprops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* layout: top-level package | packages | key/value tuples | strings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) newprops->type = ACPI_TYPE_PACKAGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) newprops->package.count = numvalid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) newprops->package.elements = &newprops[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) free_space = &newprops[1 + 3 * numvalid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) for_each_set_bit(i, valid, numprops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) union acpi_object *key = &props->package.elements[i * 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) union acpi_object *val = &props->package.elements[i * 2 + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) unsigned int k = 1 + numvalid + j * 2; /* index into newprops */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) unsigned int v = k + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) newprops[1 + j].type = ACPI_TYPE_PACKAGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) newprops[1 + j].package.count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) newprops[1 + j].package.elements = &newprops[k];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) newprops[k].type = ACPI_TYPE_STRING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) newprops[k].string.length = key->string.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) newprops[k].string.pointer = free_space;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) memcpy(free_space, key->string.pointer, key->string.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) free_space += key->string.length + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) newprops[v].type = val->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (val->type == ACPI_TYPE_INTEGER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) newprops[v].integer.value = val->integer.value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) newprops[v].buffer.length = val->buffer.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) newprops[v].buffer.pointer = free_space;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) memcpy(free_space, val->buffer.pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) val->buffer.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) free_space += val->buffer.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) j++; /* count valid properties */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) WARN_ON(free_space != (void *)newprops + newsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) adev->data.pointer = newprops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ACPI_FREE(props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) bitmap_free(valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }