1 /*
2  * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3  * Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 /*
9  * @file	utilities.h
10  * @brief	Utility routines for libmetal.
11  */
12 
13 #ifndef __METAL_UTILITIES__H__
14 #define __METAL_UTILITIES__H__
15 
16 #include <stdint.h>
17 #include <limits.h>
18 #include <metal/assert.h>
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /** \defgroup utilities Simple Utilities
25  *  @{
26  */
27 
28 #ifndef MB
29 #define MB (1024UL << 10UL)
30 #endif
31 
32 #ifndef GB
33 #define GB (MB << 10UL)
34 #endif
35 
36 /** Marker for unused function arguments/variables. */
37 #define metal_unused(x)	do { (x) = (x); } while (0)
38 
39 /** Figure out number of elements in an array. */
40 #define metal_dim(x)	(sizeof(x) / sizeof(x[0]))
41 
42 /** Minimum of two numbers (warning: multiple evaluation!).  */
43 #define metal_min(x, y)	((x) < (y) ? (x) : (y))
44 
45 /** Maximum of two numbers (warning: multiple evaluation!).  */
46 #define metal_max(x, y)	((x) > (y) ? (x) : (y))
47 
48 /** Sign of a number [-1, 0, or 1] (warning: multiple evaluation!).  */
49 #define metal_sign(x)	((x) < 0 ? -1 : ((x) > 0 ? 1 : 0))
50 
51 /** Align 'size' down to a multiple of 'align' (must be a power of two). */
52 #define metal_align_down(size, align)			\
53 	((size) & ~((align) - 1))
54 
55 /** Align 'size' up to a multiple of 'align' (must be a power of two). */
56 #define metal_align_up(size, align)			\
57 	metal_align_down((size) + (align) - 1, align)
58 
59 /** Divide (and round down). */
60 #define metal_div_round_down(num, den)			\
61 	((num) / (den))
62 
63 /** Divide (and round up). */
64 #define metal_div_round_up(num, den)			\
65 	metal_div_round_down((num) + (den) - 1, (den))
66 
67 /** Align 'ptr' down to a multiple of 'align' (must be a power of two). */
68 #define metal_ptr_align_down(ptr, align)		\
69 	(void *)(metal_align_down((uintptr_t)(ptr), (uintptr_t)(align)))
70 
71 /** Align 'ptr' up to a multiple of 'align' (must be a power of two). */
72 #define metal_ptr_align_up(ptr, align)			\
73 	(void *)(metal_align_up((uintptr_t)(ptr), (uintptr_t)(align)))
74 
75 /** Compute offset of a field within a structure. */
76 #define metal_offset_of(structure, member)		\
77 	((uintptr_t)&(((structure *)0)->member))
78 
79 /** Compute pointer to a structure given a pointer to one of its fields. */
80 #define metal_container_of(ptr, structure, member)	\
81 	(void *)((uintptr_t)(ptr) - metal_offset_of(structure, member))
82 
83 #define METAL_BITS_PER_ULONG	(CHAR_BIT * sizeof(unsigned long))
84 
85 #define metal_bit(bit)		(1UL << (bit))
86 
87 #define metal_bitmap_longs(x)	metal_div_round_up((x), METAL_BITS_PER_ULONG)
88 
metal_bitmap_set_bit(unsigned long * bitmap,int bit)89 static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit)
90 {
91 	bitmap[bit / METAL_BITS_PER_ULONG] |=
92 		metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
93 }
94 
metal_bitmap_is_bit_set(unsigned long * bitmap,int bit)95 static inline int metal_bitmap_is_bit_set(unsigned long *bitmap, int bit)
96 {
97 	return ((bitmap[bit / METAL_BITS_PER_ULONG] &
98 		metal_bit(bit & (METAL_BITS_PER_ULONG - 1))) == 0) ? 0 : 1;
99 }
100 
metal_bitmap_clear_bit(unsigned long * bitmap,int bit)101 static inline void metal_bitmap_clear_bit(unsigned long *bitmap, int bit)
102 {
103 	bitmap[bit / METAL_BITS_PER_ULONG] &=
104 		~metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
105 }
106 
metal_bitmap_is_bit_clear(unsigned long * bitmap,int bit)107 static inline int metal_bitmap_is_bit_clear(unsigned long *bitmap, int bit)
108 {
109 	return !metal_bitmap_is_bit_set(bitmap, bit);
110 }
111 
112 static inline unsigned int
metal_bitmap_next_set_bit(unsigned long * bitmap,unsigned int start,unsigned int max)113 metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start,
114 			  unsigned int max)
115 {
116 	unsigned int bit;
117 
118 	for (bit = start;
119 	     bit < max && !metal_bitmap_is_bit_set(bitmap, bit);
120 	     bit++)
121 		;
122 	return bit;
123 }
124 
125 #define metal_bitmap_for_each_set_bit(bitmap, bit, max)			\
126 	for ((bit) = metal_bitmap_next_set_bit((bitmap), 0, (max));	\
127 	     (bit) < (max);						\
128 	     (bit) = metal_bitmap_next_set_bit((bitmap), (bit + 1), (max)))
129 
130 static inline unsigned int
metal_bitmap_next_clear_bit(unsigned long * bitmap,unsigned int start,unsigned int max)131 metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start,
132 			    unsigned int max)
133 {
134 	unsigned int bit;
135 
136 	for (bit = start;
137 	     bit < max + start && !metal_bitmap_is_bit_clear(bitmap, bit % max);
138 	     bit++)
139 		;
140 	return bit % max;
141 }
142 
143 #define metal_bitmap_for_each_clear_bit(bitmap, bit, max)		\
144 	for ((bit) = metal_bitmap_next_clear_bit((bitmap), 0, (max));	\
145 	     (bit) < (max);						\
146 	     (bit) = metal_bitmap_next_clear_bit((bitmap), (bit + 1), (max)))
147 
metal_log2(unsigned long in)148 static inline unsigned long metal_log2(unsigned long in)
149 {
150 	unsigned long result;
151 
152 	metal_assert((in & (in - 1)) == 0);
153 
154 	for (result = 0; (1UL << result) < in; result++)
155 		;
156 	return result;
157 }
158 
159 /** @} */
160 
161 #ifdef __cplusplus
162 }
163 #endif
164 
165 #endif /* __METAL_UTILITIES__H__ */
166