xref: /haiku/src/add-ons/kernel/drivers/disk/nvme/libnvme/nvme_common.h (revision 495060760727dd782c9f8a90db71e5d727f19748)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   Copyright (c) 2017, Western Digital Corporation or its affiliates.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef __NVME_COMMON_H__
35 #define __NVME_COMMON_H__
36 
37 #define _GNU_SOURCE
38 #define _FILE_OFFSET_BITS 64
39 
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <stdint.h>
43 #include <stddef.h>
44 #include <stdbool.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #include <inttypes.h>
50 #include <unistd.h>
51 #include <limits.h>
52 #include <time.h>
53 #include <sys/types.h>
54 #include <sys/cdefs.h>
55 #include <sys/queue.h>
56 #ifndef __HAIKU__
57 #include <linux/types.h>
58 #endif
59 
60 #include "libnvme/nvme.h"
61 #include "nvme_arch.h"
62 #include "nvme_log.h"
63 
64 /*
65  * Check if a branch is likely to be taken.
66  */
67 #ifndef likely
68 #if __GNUC__ < 3
69 #define likely(x) x
70 #else
71 #define likely(x)  __builtin_expect((x),1)
72 #endif
73 #endif /* likely */
74 
75 /*
76  * Check if a branch is unlikely to be taken.
77  */
78 #ifndef unlikely
79 #if __GNUC__ < 3
80 #define unlikely(x) x
81 #else
82 #define unlikely(x)  __builtin_expect((x),0)
83 #endif
84 #endif /* unlikely */
85 
86 #ifndef typeof
87 #define typeof __typeof__
88 #endif
89 
90 /*
91  * Trim whitespace from a string in place.
92  */
93 extern void nvme_str_trim(char *s);
94 
95 /*
96  * Split string into tokens
97  */
98 extern int nvme_str_split(char *string, int stringlen,
99 			  char **tokens, int maxtokens, char delim);
100 
101 /*
102  * Converts a numeric string to the equivalent uint64_t value.
103  * As well as straight number conversion, also recognises the suffixes
104  * k, m and g for kilobytes, megabytes and gigabytes respectively.
105  *
106  * If a negative number is passed in, zero is returned.
107  * Zero is also returned in the case of an error with the
108  * strtoull call in the function.
109  */
nvme_str2size(const char * str)110 static inline size_t nvme_str2size(const char *str)
111 {
112 	unsigned long long size;
113 	char *endptr;
114 
115 	while (isspace((int)*str))
116 		str++;
117 	if (*str == '-')
118 		return 0;
119 
120 	errno = 0;
121 	size = strtoull(str, &endptr, 0);
122 	if (errno)
123 		return 0;
124 
125 	/* Allow 1 space gap between number and unit */
126 	if (*endptr == ' ')
127 		endptr++;
128 
129 	switch (*endptr){
130 	case 'G':
131 	case 'g':
132 		size *= 1024;
133 		/* Fall through */
134 	case 'M':
135 	case 'm':
136 		/* Fall through */
137 		size *= 1024;
138 	case 'K':
139 	case 'k':
140 		/* Fall through */
141 		size *= 1024;
142 	}
143 
144 	return size;
145 }
146 
147 /*
148  * Function to read a single numeric value from a file on the filesystem.
149  * Used to read information from files on /sys
150  */
151 extern int nvme_parse_sysfs_value(const char *filename, unsigned long *val);
152 
153 /*
154  * Get a file size in Bytes.
155  */
156 extern uint64_t nvme_file_get_size(int fd);
157 
158 /*
159  * Get a block device block size in Bytes.
160  */
161 extern ssize_t nvme_dev_get_blocklen(int fd);
162 
163 /*
164  * Get current time in nano seconds.
165  */
nvme_time_nsec(void)166 static inline unsigned long long nvme_time_nsec(void)
167 {
168 #ifdef __HAIKU__
169 	return (unsigned long long)system_time();
170 #else
171 	struct timespec ts;
172 
173 	clock_gettime(CLOCK_REALTIME, &ts);
174 
175 	return (unsigned long long) ts.tv_sec * 1000000000ULL
176 		+ (unsigned long long) ts.tv_nsec;
177 #endif
178 }
179 
180 /*
181  * Get current time in micro seconds.
182  */
nvme_time_usec(void)183 static inline unsigned long long nvme_time_usec(void)
184 {
185 	return nvme_time_nsec() / 1000;
186 }
187 
188 /*
189  * Get current time in milli seconds.
190  */
nvme_time_msec(void)191 static inline unsigned long long nvme_time_msec(void)
192 {
193 	return nvme_time_nsec() / 1000000;
194 }
195 
196 /*
197  * PAUSE instruction for tight loops (avoid busy waiting)
198  */
199 #ifdef __SSE2__
200 #include <emmintrin.h>
nvme_pause(void)201 static inline void nvme_pause(void)
202 {
203 	_mm_pause();
204 }
205 #else
nvme_pause(void)206 static inline void nvme_pause(void) {}
207 #endif
208 
209 #ifdef __HAIKU__
210 static inline void
nvme_usleep(int usecs)211 nvme_usleep(int usecs)
212 {
213 	snooze(usecs);
214 }
215 
216 static inline void
nvme_msleep(int msecs)217 nvme_msleep(int msecs)
218 {
219 	snooze(msecs * 1000LL);
220 }
221 #else
222 /*
223  * Micro-seconds sleep.
224  */
nvme_usleep(int usecs)225 static inline void nvme_usleep(int usecs)
226 {
227 	struct timeval tv;
228 
229 	tv.tv_sec = usecs / 1000000;
230 	tv.tv_usec = usecs % 1000000;
231 	select(0, NULL, NULL, NULL, &tv);
232 }
233 
234 /*
235  * Milli-seconds sleep.
236  */
nvme_msleep(int msecs)237 static inline void nvme_msleep(int msecs)
238 {
239 	struct timeval tv;
240 
241 	tv.tv_sec = msecs / 1000;
242 	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
243 	select(0, NULL, NULL, NULL, &tv);
244 }
245 #endif
246 
247 #ifndef __HAIKU__
248 /*
249  * Provide notification of a critical non-recoverable error and stop.
250  * This function should not be called directly. Use nvme_panic() instead.
251  */
252 extern void __nvme_panic(const char *funcname , const char *format, ...)
253 #ifdef __GNUC__
254 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2))
255 	__attribute__((cold))
256 #endif
257 #endif
258 	__attribute__((noreturn))
259 	__attribute__((format(printf, 2, 3)));
260 
261 /*
262  * Provide notification of a critical non-recoverable error
263  * and terminate execution abnormally.
264  */
265 #define nvme_panic(format, args...)	\
266 	__nvme_panic(__FUNCTION__, format, ## args)
267 #else
268 #define nvme_panic panic
269 #endif
270 
271 /*
272  * Macro to evaluate a scalar expression and
273  * abort the program if the assertion is false.
274  */
275 #define _nvme_assert_default(exp)					\
276 	do {								\
277 		if (unlikely(!(exp)))					\
278 			nvme_panic("line %d, assert %s failed\n",	\
279 				   __LINE__, # exp);			\
280 	} while (0)
281 
282 #define _nvme_assert_msg(exp, msg)					\
283 	do {								\
284 		if (unlikely(!(exp)))					\
285 			nvme_panic("%s\n", msg);			\
286 	} while (0)
287 
288 #define _NVME_GET_ASSERT_OVERLOAD(_1, _2, NAME, args...) NAME
289 
290 #define nvme_assert(args...) \
291 	_NVME_GET_ASSERT_OVERLOAD(args,					\
292 				  _nvme_assert_msg,			\
293 				  _nvme_assert_default)			\
294 				  (args)
295 
296 /*
297  * Macro to return the minimum of two numbers
298  */
299 #define nvme_min(a, b) ({	     \
300 		typeof (a) _a = (a); \
301 		typeof (b) _b = (b); \
302 		_a < _b ? _a : _b;   \
303 	})
304 
305 /*
306  * Macro to return the maximum of two numbers
307  */
308 #define nvme_max(a, b) ({	     \
309 		typeof (a) _a = (a); \
310 		typeof (b) _b = (b); \
311 		_a > _b ? _a : _b;   \
312 	})
313 
314 /*
315  * Returns true if n is a power of 2.
316  */
nvme_is_pow2(__u64 v)317 static inline int nvme_is_pow2(__u64 v)
318 {
319 	return v && !(v & (v - 1));
320 }
321 
322 /*
323  * Return the power of 2 immediately after v.
324  */
nvme_align_pow2(__u64 v)325 static inline __u64 nvme_align_pow2(__u64 v)
326 {
327 	v--;
328 	v |= v >> 1;
329 	v |= v >> 2;
330 	v |= v >> 4;
331 	v |= v >> 8;
332 	v |= v >> 16;
333 	v |= v >> 32;
334 
335 	return v + 1;
336 }
337 
338 /*
339  * Calculate log2 of a power of 2 size.
340  */
nvme_log2(size_t size)341 static inline size_t nvme_log2(size_t size)
342 {
343 	size_t bits = 0;
344 
345         if (!nvme_is_pow2(size))
346                 return 0;
347 
348         while (size >>= 1)
349 		bits++;
350 
351 	return bits;
352 }
353 
354 /*
355  * Handle alignements.
356  */
357 #define nvme_align_down(val, align)	\
358 	((val) & (~((typeof(val))((align) - 1))))
359 #define nvme_align_up(val, align)	\
360 	nvme_align_down((val) + (align) - 1, (align))
361 
362 /*
363  * Test a bit value.
364  */
test_bit(__u8 * bitmap,unsigned int bit)365 static inline int test_bit(__u8 *bitmap, unsigned int bit)
366 {
367         return bitmap[bit >> 3] & (1U << (bit & 0x7));
368 }
369 
370 /*
371  * Set a bit.
372  */
set_bit(__u8 * bitmap,unsigned int bit)373 static inline void set_bit(__u8 *bitmap, unsigned int bit)
374 {
375         bitmap[bit >> 3] |= 1U << (bit & 0x7);
376 }
377 
378 /*
379  * Clear a bit.
380  */
clear_bit(__u8 * bitmap,unsigned int bit)381 static inline void clear_bit(__u8 *bitmap, unsigned int bit)
382 {
383         bitmap[bit >> 3] &= ~(1U << (bit & 0x7));
384 }
385 
386 /*
387  * Find the first zero bit in a bitmap of size nr_bits.
388  * If no zero bit is found, return -1.
389  */
find_first_zero_bit(__u8 * bitmap,unsigned int nr_bits)390 static inline int find_first_zero_bit(__u8 *bitmap, unsigned int nr_bits)
391 {
392 	__u64 *b = (__u64 *)bitmap;
393 	unsigned int i, j, bit, count = (nr_bits + 63) >> 6;
394 
395 	for(i = 0; i < count; i++) {
396 		if (b[i] != ~0UL)
397 			break;
398 	}
399 
400 	bit = i << 6;
401 	for (j = bit; j < nr_bits; j++) {
402 		if (!test_bit(bitmap, j))
403 			return j;
404 	}
405 
406 	return -1;
407 }
408 
409 /*
410  * Close all open controllers on exit.
411  * Defined in lib/nvme/nvme.c
412  */
413 extern void nvme_ctrlr_cleanup(void);
414 
415 #endif /* __NVME_COMMON_H__ */
416