root/drivers/thunderbolt/property.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parse_dwdata
  2. format_dwdata
  3. tb_property_entry_valid
  4. tb_property_key_valid
  5. tb_property_alloc
  6. tb_property_parse
  7. __tb_property_parse_dir
  8. tb_property_parse_dir
  9. tb_property_create_dir
  10. tb_property_free
  11. tb_property_free_dir
  12. tb_property_dir_length
  13. __tb_property_format_dir
  14. tb_property_format_dir
  15. tb_property_add_immediate
  16. tb_property_add_data
  17. tb_property_add_text
  18. tb_property_add_dir
  19. tb_property_remove
  20. tb_property_find
  21. tb_property_get_next

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

/* [<][>][^][v][top][bottom][index][help] */