property.c 17 KB

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