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  
parse_dwdata(void * dst,const void * src,size_t dwords)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  
format_dwdata(void * dst,const void * src,size_t dwords)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  
tb_property_entry_valid(const struct tb_property_entry * entry,size_t block_len)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  
tb_property_key_valid(const char * key)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 *
tb_property_alloc(const char * key,enum tb_property_type type)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  
tb_property_parse(const u32 * block,size_t block_len,const struct tb_property_entry * entry)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  
__tb_property_parse_dir(const u32 * block,size_t block_len,unsigned int dir_offset,size_t dir_len,bool is_root)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   */
tb_property_parse_dir(const u32 * block,size_t block_len)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   */
tb_property_create_dir(const uuid_t * uuid)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  
tb_property_free(struct tb_property * property)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   */
tb_property_free_dir(struct tb_property_dir * dir)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  
tb_property_dir_length(const struct tb_property_dir * dir,bool recurse,size_t * data_len)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  
__tb_property_format_dir(const struct tb_property_dir * dir,u32 * block,unsigned int start_offset,size_t block_len)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   */
tb_property_format_dir(const struct tb_property_dir * dir,u32 * block,size_t block_len)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_copy_dir() - Take a deep copy of directory
506   * @dir: Directory to copy
507   *
508   * This function takes a deep copy of @dir and returns back the copy. In
509   * case of error returns %NULL. The resulting directory needs to be
510   * released by calling tb_property_free_dir().
511   */
tb_property_copy_dir(const struct tb_property_dir * dir)512  struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir)
513  {
514  	struct tb_property *property, *p = NULL;
515  	struct tb_property_dir *d;
516  
517  	if (!dir)
518  		return NULL;
519  
520  	d = tb_property_create_dir(dir->uuid);
521  	if (!d)
522  		return NULL;
523  
524  	list_for_each_entry(property, &dir->properties, list) {
525  		struct tb_property *p;
526  
527  		p = tb_property_alloc(property->key, property->type);
528  		if (!p)
529  			goto err_free;
530  
531  		p->length = property->length;
532  
533  		switch (property->type) {
534  		case TB_PROPERTY_TYPE_DIRECTORY:
535  			p->value.dir = tb_property_copy_dir(property->value.dir);
536  			if (!p->value.dir)
537  				goto err_free;
538  			break;
539  
540  		case TB_PROPERTY_TYPE_DATA:
541  			p->value.data = kmemdup(property->value.data,
542  						property->length * 4,
543  						GFP_KERNEL);
544  			if (!p->value.data)
545  				goto err_free;
546  			break;
547  
548  		case TB_PROPERTY_TYPE_TEXT:
549  			p->value.text = kzalloc(p->length * 4, GFP_KERNEL);
550  			if (!p->value.text)
551  				goto err_free;
552  			strcpy(p->value.text, property->value.text);
553  			break;
554  
555  		case TB_PROPERTY_TYPE_VALUE:
556  			p->value.immediate = property->value.immediate;
557  			break;
558  
559  		default:
560  			break;
561  		}
562  
563  		list_add_tail(&p->list, &d->properties);
564  	}
565  
566  	return d;
567  
568  err_free:
569  	kfree(p);
570  	tb_property_free_dir(d);
571  
572  	return NULL;
573  }
574  
575  /**
576   * tb_property_add_immediate() - Add immediate property to directory
577   * @parent: Directory to add the property
578   * @key: Key for the property
579   * @value: Immediate value to store with the property
580   */
tb_property_add_immediate(struct tb_property_dir * parent,const char * key,u32 value)581  int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,
582  			      u32 value)
583  {
584  	struct tb_property *property;
585  
586  	if (!tb_property_key_valid(key))
587  		return -EINVAL;
588  
589  	property = tb_property_alloc(key, TB_PROPERTY_TYPE_VALUE);
590  	if (!property)
591  		return -ENOMEM;
592  
593  	property->length = 1;
594  	property->value.immediate = value;
595  
596  	list_add_tail(&property->list, &parent->properties);
597  	return 0;
598  }
599  EXPORT_SYMBOL_GPL(tb_property_add_immediate);
600  
601  /**
602   * tb_property_add_data() - Adds arbitrary data property to directory
603   * @parent: Directory to add the property
604   * @key: Key for the property
605   * @buf: Data buffer to add
606   * @buflen: Number of bytes in the data buffer
607   *
608   * Function takes a copy of @buf and adds it to the directory.
609   */
tb_property_add_data(struct tb_property_dir * parent,const char * key,const void * buf,size_t buflen)610  int tb_property_add_data(struct tb_property_dir *parent, const char *key,
611  			 const void *buf, size_t buflen)
612  {
613  	/* Need to pad to dword boundary */
614  	size_t size = round_up(buflen, 4);
615  	struct tb_property *property;
616  
617  	if (!tb_property_key_valid(key))
618  		return -EINVAL;
619  
620  	property = tb_property_alloc(key, TB_PROPERTY_TYPE_DATA);
621  	if (!property)
622  		return -ENOMEM;
623  
624  	property->length = size / 4;
625  	property->value.data = kzalloc(size, GFP_KERNEL);
626  	if (!property->value.data) {
627  		kfree(property);
628  		return -ENOMEM;
629  	}
630  
631  	memcpy(property->value.data, buf, buflen);
632  
633  	list_add_tail(&property->list, &parent->properties);
634  	return 0;
635  }
636  EXPORT_SYMBOL_GPL(tb_property_add_data);
637  
638  /**
639   * tb_property_add_text() - Adds string property to directory
640   * @parent: Directory to add the property
641   * @key: Key for the property
642   * @text: String to add
643   *
644   * Function takes a copy of @text and adds it to the directory.
645   */
tb_property_add_text(struct tb_property_dir * parent,const char * key,const char * text)646  int tb_property_add_text(struct tb_property_dir *parent, const char *key,
647  			 const char *text)
648  {
649  	/* Need to pad to dword boundary */
650  	size_t size = round_up(strlen(text) + 1, 4);
651  	struct tb_property *property;
652  
653  	if (!tb_property_key_valid(key))
654  		return -EINVAL;
655  
656  	property = tb_property_alloc(key, TB_PROPERTY_TYPE_TEXT);
657  	if (!property)
658  		return -ENOMEM;
659  
660  	property->length = size / 4;
661  	property->value.text = kzalloc(size, GFP_KERNEL);
662  	if (!property->value.text) {
663  		kfree(property);
664  		return -ENOMEM;
665  	}
666  
667  	strcpy(property->value.text, text);
668  
669  	list_add_tail(&property->list, &parent->properties);
670  	return 0;
671  }
672  EXPORT_SYMBOL_GPL(tb_property_add_text);
673  
674  /**
675   * tb_property_add_dir() - Adds a directory to the parent directory
676   * @parent: Directory to add the property
677   * @key: Key for the property
678   * @dir: Directory to add
679   */
tb_property_add_dir(struct tb_property_dir * parent,const char * key,struct tb_property_dir * dir)680  int tb_property_add_dir(struct tb_property_dir *parent, const char *key,
681  			struct tb_property_dir *dir)
682  {
683  	struct tb_property *property;
684  
685  	if (!tb_property_key_valid(key))
686  		return -EINVAL;
687  
688  	property = tb_property_alloc(key, TB_PROPERTY_TYPE_DIRECTORY);
689  	if (!property)
690  		return -ENOMEM;
691  
692  	property->value.dir = dir;
693  
694  	list_add_tail(&property->list, &parent->properties);
695  	return 0;
696  }
697  EXPORT_SYMBOL_GPL(tb_property_add_dir);
698  
699  /**
700   * tb_property_remove() - Removes property from a parent directory
701   * @property: Property to remove
702   *
703   * Note memory for @property is released as well so it is not allowed to
704   * touch the object after call to this function.
705   */
tb_property_remove(struct tb_property * property)706  void tb_property_remove(struct tb_property *property)
707  {
708  	list_del(&property->list);
709  	kfree(property);
710  }
711  EXPORT_SYMBOL_GPL(tb_property_remove);
712  
713  /**
714   * tb_property_find() - Find a property from a directory
715   * @dir: Directory where the property is searched
716   * @key: Key to look for
717   * @type: Type of the property
718   *
719   * Finds and returns property from the given directory. Does not recurse
720   * into sub-directories. Returns %NULL if the property was not found.
721   */
tb_property_find(struct tb_property_dir * dir,const char * key,enum tb_property_type type)722  struct tb_property *tb_property_find(struct tb_property_dir *dir,
723  	const char *key, enum tb_property_type type)
724  {
725  	struct tb_property *property;
726  
727  	list_for_each_entry(property, &dir->properties, list) {
728  		if (property->type == type && !strcmp(property->key, key))
729  			return property;
730  	}
731  
732  	return NULL;
733  }
734  EXPORT_SYMBOL_GPL(tb_property_find);
735  
736  /**
737   * tb_property_get_next() - Get next property from directory
738   * @dir: Directory holding properties
739   * @prev: Previous property in the directory (%NULL returns the first)
740   */
tb_property_get_next(struct tb_property_dir * dir,struct tb_property * prev)741  struct tb_property *tb_property_get_next(struct tb_property_dir *dir,
742  					 struct tb_property *prev)
743  {
744  	if (prev) {
745  		if (list_is_last(&prev->list, &dir->properties))
746  			return NULL;
747  		return list_next_entry(prev, list);
748  	}
749  	return list_first_entry_or_null(&dir->properties, struct tb_property,
750  					list);
751  }
752  EXPORT_SYMBOL_GPL(tb_property_get_next);
753