^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Thunderbolt XDomain property support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2017, Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Authors: Michael Jamet <michael.jamet@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Mika Westerberg <mika.westerberg@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/uuid.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/thunderbolt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) struct tb_property_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) u32 key_hi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) u32 key_lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) u16 length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) u8 reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) u8 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct tb_property_rootdir_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u32 magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) u32 length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct tb_property_entry entries[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct tb_property_dir_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 uuid[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct tb_property_entry entries[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) size_t block_len, unsigned int dir_offset, size_t dir_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) bool is_root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static inline void parse_dwdata(void *dst, const void *src, size_t dwords)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) be32_to_cpu_array(dst, src, dwords);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static inline void format_dwdata(void *dst, const void *src, size_t dwords)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) cpu_to_be32_array(dst, src, dwords);
^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) static bool tb_property_entry_valid(const struct tb_property_entry *entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) size_t block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) switch (entry->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) case TB_PROPERTY_TYPE_DIRECTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) case TB_PROPERTY_TYPE_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) case TB_PROPERTY_TYPE_TEXT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (entry->length > block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (entry->value + entry->length > block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) case TB_PROPERTY_TYPE_VALUE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (entry->length != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static bool tb_property_key_valid(const char *key)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return key && strlen(key) <= TB_PROPERTY_KEY_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static struct tb_property *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) tb_property_alloc(const char *key, enum tb_property_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) property = kzalloc(sizeof(*property), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (!property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) strcpy(property->key, key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) property->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) INIT_LIST_HEAD(&property->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) const struct tb_property_entry *entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) char key[TB_PROPERTY_KEY_SIZE + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct tb_property_dir *dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (!tb_property_entry_valid(entry, block_len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) parse_dwdata(key, entry, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) key[TB_PROPERTY_KEY_SIZE] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) property = tb_property_alloc(key, entry->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (!property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) property->length = entry->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) switch (property->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) case TB_PROPERTY_TYPE_DIRECTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) dir = __tb_property_parse_dir(block, block_len, entry->value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) entry->length, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (!dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) kfree(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) property->value.dir = dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) case TB_PROPERTY_TYPE_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) property->value.data = kcalloc(property->length, sizeof(u32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (!property->value.data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) kfree(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) parse_dwdata(property->value.data, block + entry->value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) entry->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) case TB_PROPERTY_TYPE_TEXT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) property->value.text = kcalloc(property->length, sizeof(u32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (!property->value.text) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) kfree(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) parse_dwdata(property->value.text, block + entry->value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) entry->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* Force null termination */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) property->value.text[property->length * 4 - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) case TB_PROPERTY_TYPE_VALUE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) property->value.immediate = entry->value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) property->type = TB_PROPERTY_TYPE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) const struct tb_property_entry *entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) size_t i, content_len, nentries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) unsigned int content_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct tb_property_dir *dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) dir = kzalloc(sizeof(*dir), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (!dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (is_root) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) content_offset = dir_offset + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) content_len = dir_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) dir->uuid = kmemdup(&block[dir_offset], sizeof(*dir->uuid),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (!dir->uuid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) tb_property_free_dir(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) content_offset = dir_offset + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) content_len = dir_len - 4; /* Length includes UUID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) entries = (const struct tb_property_entry *)&block[content_offset];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) nentries = content_len / (sizeof(*entries) / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) INIT_LIST_HEAD(&dir->properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) for (i = 0; i < nentries; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) property = tb_property_parse(block, block_len, &entries[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (!property) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) tb_property_free_dir(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) list_add_tail(&property->list, &dir->properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * tb_property_parse_dir() - Parses properties from given property block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * @block: Property block to parse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * @block_len: Number of dword elements in the property block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * This function parses the XDomain properties data block into format that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * can be traversed using the helper functions provided by this module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * Upon success returns the parsed directory. In case of error returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * %NULL. The resulting &struct tb_property_dir needs to be released by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * calling tb_property_free_dir() when not needed anymore.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * The @block is expected to be root directory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) struct tb_property_dir *tb_property_parse_dir(const u32 *block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) size_t block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) const struct tb_property_rootdir_entry *rootdir =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) (const struct tb_property_rootdir_entry *)block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (rootdir->magic != TB_PROPERTY_ROOTDIR_MAGIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (rootdir->length > block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return __tb_property_parse_dir(block, block_len, 0, rootdir->length,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * tb_property_create_dir() - Creates new property directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * @uuid: UUID used to identify the particular directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Creates new, empty property directory. If @uuid is %NULL then the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * directory is assumed to be root directory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct tb_property_dir *dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) dir = kzalloc(sizeof(*dir), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (!dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) INIT_LIST_HEAD(&dir->properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (uuid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dir->uuid = kmemdup(uuid, sizeof(*dir->uuid), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (!dir->uuid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) kfree(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) EXPORT_SYMBOL_GPL(tb_property_create_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static void tb_property_free(struct tb_property *property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) switch (property->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) case TB_PROPERTY_TYPE_DIRECTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) tb_property_free_dir(property->value.dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) case TB_PROPERTY_TYPE_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) kfree(property->value.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) case TB_PROPERTY_TYPE_TEXT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) kfree(property->value.text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) kfree(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * tb_property_free_dir() - Release memory allocated for property directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * @dir: Directory to release
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * This will release all the memory the directory occupies including all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * descendants. It is OK to pass %NULL @dir, then the function does
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * nothing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) void tb_property_free_dir(struct tb_property_dir *dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct tb_property *property, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (!dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) list_for_each_entry_safe(property, tmp, &dir->properties, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) list_del(&property->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) tb_property_free(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) kfree(dir->uuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) kfree(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) EXPORT_SYMBOL_GPL(tb_property_free_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static size_t tb_property_dir_length(const struct tb_property_dir *dir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) bool recurse, size_t *data_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) const struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (dir->uuid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) len += sizeof(*dir->uuid) / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) len += sizeof(struct tb_property_rootdir_entry) / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) list_for_each_entry(property, &dir->properties, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) len += sizeof(struct tb_property_entry) / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) switch (property->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) case TB_PROPERTY_TYPE_DIRECTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (recurse) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) len += tb_property_dir_length(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) property->value.dir, recurse, data_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /* Reserve dword padding after each directory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (data_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) *data_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) case TB_PROPERTY_TYPE_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) case TB_PROPERTY_TYPE_TEXT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (data_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) *data_len += property->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) u32 *block, unsigned int start_offset, size_t block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) unsigned int data_offset, dir_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) const struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct tb_property_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) size_t dir_len, data_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) * The structure of property block looks like following. Leaf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * data/text is included right after the directory and each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * directory follows each other (even nested ones).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * +----------+ <-- start_offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * | header | <-- root directory header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * +----------+ ---
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * | entry 0 | -^--------------------.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * +----------+ | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * | entry 1 | -|--------------------|--.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * +----------+ | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * | entry 2 | -|-----------------. | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * +----------+ | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * : : | dir_len | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) * . . | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * : : | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * +----------+ | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * | entry n | v | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * +----------+ <-- data_offset | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * | data 0 | <------------------|--' |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * +----------+ | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * | data 1 | <------------------|-----'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * +----------+ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * | 00000000 | padding |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * +----------+ <-- dir_end <------'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * | UUID | <-- directory UUID (child directory)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * +----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * | entry 0 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * +----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * | entry 1 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * +----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * : :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * . .
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * : :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * +----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * | entry n |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * +----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * | data 0 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * +----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * We use dir_end to hold pointer to the end of the directory. It
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * will increase as we add directories and each directory should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * added starting from previous dir_end.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) dir_len = tb_property_dir_length(dir, false, &data_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) data_offset = start_offset + dir_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) dir_end = start_offset + data_len + dir_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (data_offset > dir_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (dir_end > block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /* Write headers first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (dir->uuid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) struct tb_property_dir_entry *pe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) pe = (struct tb_property_dir_entry *)&block[start_offset];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) memcpy(pe->uuid, dir->uuid, sizeof(pe->uuid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) entry = pe->entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct tb_property_rootdir_entry *re;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) re = (struct tb_property_rootdir_entry *)&block[start_offset];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) re->magic = TB_PROPERTY_ROOTDIR_MAGIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) re->length = dir_len - sizeof(*re) / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) entry = re->entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) list_for_each_entry(property, &dir->properties, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) const struct tb_property_dir *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) format_dwdata(entry, property->key, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) entry->type = property->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) switch (property->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) case TB_PROPERTY_TYPE_DIRECTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) child = property->value.dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) ret = __tb_property_format_dir(child, block, dir_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) block_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) entry->length = tb_property_dir_length(child, false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) entry->value = dir_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) dir_end = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) case TB_PROPERTY_TYPE_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) format_dwdata(&block[data_offset], property->value.data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) property->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) entry->length = property->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) entry->value = data_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) data_offset += entry->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) case TB_PROPERTY_TYPE_TEXT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) format_dwdata(&block[data_offset], property->value.text,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) property->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) entry->length = property->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) entry->value = data_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) data_offset += entry->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) case TB_PROPERTY_TYPE_VALUE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) entry->length = property->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) entry->value = property->value.immediate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) entry++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return dir_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * tb_property_format_dir() - Formats directory to the packed XDomain format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) * @dir: Directory to format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) * @block: Property block where the packed data is placed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * @block_len: Length of the property block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) * This function formats the directory to the packed format that can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) * then send over the thunderbolt fabric to receiving host. Returns %0 in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * case of success and negative errno on faulure. Passing %NULL in @block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) * returns number of entries the block takes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) size_t block_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (!block) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) size_t dir_len, data_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) dir_len = tb_property_dir_length(dir, true, &data_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return dir_len + data_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) ret = __tb_property_format_dir(dir, block, 0, block_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return ret < 0 ? ret : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * tb_property_add_immediate() - Add immediate property to directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * @parent: Directory to add the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * @key: Key for the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) * @value: Immediate value to store with the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) u32 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (!tb_property_key_valid(key))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) property = tb_property_alloc(key, TB_PROPERTY_TYPE_VALUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (!property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) property->length = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) property->value.immediate = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) list_add_tail(&property->list, &parent->properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) EXPORT_SYMBOL_GPL(tb_property_add_immediate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * tb_property_add_data() - Adds arbitrary data property to directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) * @parent: Directory to add the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * @key: Key for the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) * @buf: Data buffer to add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) * @buflen: Number of bytes in the data buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * Function takes a copy of @buf and adds it to the directory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) int tb_property_add_data(struct tb_property_dir *parent, const char *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) const void *buf, size_t buflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /* Need to pad to dword boundary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) size_t size = round_up(buflen, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (!tb_property_key_valid(key))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) property = tb_property_alloc(key, TB_PROPERTY_TYPE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (!property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) property->length = size / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) property->value.data = kzalloc(size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (!property->value.data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) kfree(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) memcpy(property->value.data, buf, buflen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) list_add_tail(&property->list, &parent->properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) EXPORT_SYMBOL_GPL(tb_property_add_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * tb_property_add_text() - Adds string property to directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * @parent: Directory to add the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * @key: Key for the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * @text: String to add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) * Function takes a copy of @text and adds it to the directory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) int tb_property_add_text(struct tb_property_dir *parent, const char *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) const char *text)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /* Need to pad to dword boundary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) size_t size = round_up(strlen(text) + 1, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (!tb_property_key_valid(key))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) property = tb_property_alloc(key, TB_PROPERTY_TYPE_TEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (!property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) property->length = size / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) property->value.text = kzalloc(size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (!property->value.text) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) kfree(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) strcpy(property->value.text, text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) list_add_tail(&property->list, &parent->properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) EXPORT_SYMBOL_GPL(tb_property_add_text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * tb_property_add_dir() - Adds a directory to the parent directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * @parent: Directory to add the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) * @key: Key for the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) * @dir: Directory to add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) int tb_property_add_dir(struct tb_property_dir *parent, const char *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) struct tb_property_dir *dir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (!tb_property_key_valid(key))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) property = tb_property_alloc(key, TB_PROPERTY_TYPE_DIRECTORY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (!property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) property->value.dir = dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) list_add_tail(&property->list, &parent->properties);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) EXPORT_SYMBOL_GPL(tb_property_add_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * tb_property_remove() - Removes property from a parent directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * @property: Property to remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * Note memory for @property is released as well so it is not allowed to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * touch the object after call to this function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) void tb_property_remove(struct tb_property *property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) list_del(&property->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) kfree(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) EXPORT_SYMBOL_GPL(tb_property_remove);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * tb_property_find() - Find a property from a directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) * @dir: Directory where the property is searched
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * @key: Key to look for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * @type: Type of the property
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * Finds and returns property from the given directory. Does not recurse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * into sub-directories. Returns %NULL if the property was not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) struct tb_property *tb_property_find(struct tb_property_dir *dir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) const char *key, enum tb_property_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct tb_property *property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) list_for_each_entry(property, &dir->properties, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (property->type == type && !strcmp(property->key, key))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return property;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) EXPORT_SYMBOL_GPL(tb_property_find);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) * tb_property_get_next() - Get next property from directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * @dir: Directory holding properties
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * @prev: Previous property in the directory (%NULL returns the first)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) struct tb_property *tb_property_get_next(struct tb_property_dir *dir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) struct tb_property *prev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (prev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (list_is_last(&prev->list, &dir->properties))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) return list_next_entry(prev, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) return list_first_entry_or_null(&dir->properties, struct tb_property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) EXPORT_SYMBOL_GPL(tb_property_get_next);