xref: /freebsd/sys/dev/ocs_fc/ocs_os.h (revision 74ca7bf1d4c7173d5575ba168bc4b5f6d181ff5a)
1 /*-
2  * Copyright (c) 2017 Broadcom. All rights reserved.
3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33 
34 /**
35  * @file
36  * bsd specific headers common to the driver
37  */
38 
39 #ifndef _OCS_OS_H
40 #define _OCS_OS_H
41 
42 typedef struct ocs_softc ocs_t;
43 
44 /***************************************************************************
45  * OS specific includes
46  */
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/malloc.h>
50 #include <sys/kernel.h>
51 #include <sys/module.h>
52 #include <sys/bus.h>
53 #include <sys/rman.h>
54 #include <sys/endian.h>
55 #include <sys/stddef.h>
56 #include <sys/lock.h>
57 #include <sys/mutex.h>
58 #include <sys/taskqueue.h>
59 #include <sys/bitstring.h>
60 #include <sys/stack.h>
61 
62 #include <machine/atomic.h>
63 #include <machine/bus.h>
64 #include <machine/stdarg.h>
65 
66 #include <dev/pci/pcivar.h>
67 
68 #include <sys/sema.h>
69 #include <sys/time.h>
70 
71 #include <sys/proc.h>
72 #include <sys/kthread.h>
73 #include <sys/unistd.h>
74 #include <sys/sched.h>
75 
76 #include <sys/conf.h>
77 #include <sys/sysctl.h>
78 #include <sys/ioccom.h>
79 #include <sys/ctype.h>
80 
81 /* OCS_OS_MAX_ISR_TIME_MSEC -  maximum time driver code should spend in an interrupt
82  * or kernel thread context without yielding
83  */
84 #define OCS_OS_MAX_ISR_TIME_MSEC	1000
85 
86 /* BSD driver specific definitions */
87 
88 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof((x)[0]))
89 
90 #define OCS_MAX_LUN			512
91 #define OCS_NUM_UNSOLICITED_FRAMES	1024
92 
93 #define OCS_MAX_DOMAINS			1
94 #define OCS_MAX_REMOTE_NODES		2048
95 #define OCS_MAX_TARGETS			1024
96 #define OCS_MAX_INITIATORS		1024
97 /** Reserve this number of IO for each intiator to return FULL/BUSY status */
98 #define OCS_RSVD_INI_IO			8
99 
100 #define OCS_MIN_DMA_ALIGNMENT		16
101 #define OCS_MAX_DMA_ALLOC		(64*1024)	/* maxium DMA allocation that is expected to reliably succeed  */
102 
103 /*
104  * Macros used to size the CQ hash table. We want to round up to the next
105  * power of 2 for the hash.
106  */
107 #define B2(x)   (   (x) | (   (x) >> 1) )
108 #define B4(x)   ( B2(x) | ( B2(x) >> 2) )
109 #define B8(x)   ( B4(x) | ( B4(x) >> 4) )
110 #define B16(x)  ( B8(x) | ( B8(x) >> 8) )
111 #define B32(x)  (B16(x) | (B16(x) >>16) )
112 #define B32_NEXT_POWER_OF_2(x)      (B32((x)-1) + 1)
113 
114 /*
115  * likely/unlikely - branch prediction hint
116  */
117 #define likely(x)               __builtin_expect(!!(x), 1)
118 #define unlikely(x)             __builtin_expect(!!(x), 0)
119 
120 /***************************************************************************
121  * OS abstraction
122  */
123 
124 /**
125  * @brief Min/Max macros
126  *
127  */
128 #define OCS_MAX(x, y)		((x) > (y) ? (x) : (y))
129 #define OCS_MIN(x, y)		((x) < (y) ? (x) : (y))
130 
131 #define PRIX64	"lX"
132 #define PRIx64	"lx"
133 #define PRId64	"ld"
134 #define PRIu64	"lu"
135 
136 /**
137  * Enable optional features
138  *  - OCS_INCLUDE_DEBUG include low-level SLI debug support
139  */
140 #define OCS_INCLUDE_DEBUG
141 
142 /**
143  * @brief Set the Nth bit
144  *
145  * @todo move to a private file used internally?
146  */
147 #ifndef BIT
148 #define BIT(n)		(1U << (n))
149 #endif
150 
151 /***************************************************************************
152  * Platform specific operations
153  */
154 
155 /**
156  * @ingroup os
157  * @typedef ocs_os_handle_t
158  * @brief OS specific handle or driver context
159  *
160  * This can be anything from a void * to some other OS specific type. The lower
161  * layers make no assumption about its value and pass it back as the first
162  * parameter to most OS functions.
163  */
164 typedef ocs_t * ocs_os_handle_t;
165 
166 /**
167  * @ingroup os
168  * @brief return the lower 32-bits of a bus address
169  *
170  * @param addr Physical or bus address to convert
171  * @return lower 32-bits of a bus address
172  *
173  * @note this may be a good cadidate for an inline or macro
174  */
175 static inline uint32_t ocs_addr32_lo(uintptr_t addr)
176 {
177 #if defined(__LP64__)
178 	return (uint32_t)(addr & 0xffffffffUL);
179 #else
180 	return addr;
181 #endif
182 }
183 
184 /**
185  * @ingroup os
186  * @brief return the upper 32-bits of a bus address
187  *
188  * @param addr Physical or bus address to convert
189  * @return upper 32-bits of a bus address
190  *
191  * @note this may be a good cadidate for an inline or macro
192  */
193 static inline uint32_t ocs_addr32_hi(uintptr_t addr)
194 {
195 #if defined(__LP64__)
196 	return (uint32_t)(addr >> 32);
197 #else
198 	return 0;
199 #endif
200 }
201 
202 /**
203  * @ingroup os
204  * @brief return the log2(val)
205  *
206  * @param val number to use (assumed to be exact power of 2)
207  *
208  * @return log base 2 of val
209  */
210 static inline uint32_t ocs_lg2(uint32_t val)
211 {
212 #if defined(__GNUC__)
213 	/*
214 	 * clz = "count leading zero's"
215 	 *
216 	 * Assuming val is an exact power of 2, the most significant bit
217 	 * will be the log base 2 of val
218 	 */
219 	return 31 - __builtin_clz(val);
220 #else
221 #error You need to provide a non-GCC version of this function
222 #endif
223 }
224 
225 /**
226  * @ingroup os
227  * @brief optimization barrier
228  *
229  * Optimization barrier. Prevents compiler re-ordering
230  * instructions across barrier.
231  *
232  * @return none
233  */
234 #define ocs_barrier()	 __asm __volatile("" : : : "memory");
235 
236 /**
237  * @ingroup os
238  * @brief convert a big endian 32 bit value to the host's native format
239  *
240  * @param val 32 bit big endian value
241  *
242  * @return value converted to the host's native endianness
243  */
244 #define ocs_be32toh(val)	be32toh(val)
245 
246 /**
247  * @ingroup os
248  * @brief convert a 32 bit value from the host's native format to big endian
249  *
250  * @param val 32 bit native endian value
251  *
252  * @return value converted to big endian
253  */
254 #define ocs_htobe32(val)	htobe32(val)
255 
256 /**
257  * @ingroup os
258  * @brief convert a 16 bit value from the host's native format to big endian
259  *
260  * @param v 16 bit native endian value
261  *
262  * @return value converted to big endian
263  */
264 #define ocs_htobe16(v)	htobe16(v)
265 #define ocs_be16toh(v)	be16toh(v)
266 
267 
268 #define ocs_htobe64(v)	htobe64(v)
269 #define ocs_be64toh(v)	be64toh(v)
270 
271 /**
272  * @ingroup os
273  * @brief Delay execution by the given number of micro-seconds
274  *
275  * @param usec number of micro-seconds to "busy-wait"
276  *
277  * @note The value of usec may be greater than 1,000,000
278  */
279 #define ocs_udelay(usec) DELAY(usec)
280 
281 /**
282  * @ingroup os
283  * @brief Delay execution by the given number of milli-seconds
284  *
285  * @param msec number of milli-seconds to "busy-wait"
286  *
287  * @note The value of usec may be greater than 1,000,000
288  */
289 #define ocs_msleep(msec) ocs_udelay((msec)*1000)
290 
291 /**
292  * @ingroup os
293  * @brief Get time of day in msec
294  *
295  * @return time of day in msec
296  */
297 static inline time_t
298 ocs_msectime(void)
299 {
300 	struct timeval tv;
301 
302 	getmicrotime(&tv);
303 	return (tv.tv_sec*1000) + (tv.tv_usec / 1000);
304 }
305 
306 /**
307  * @ingroup os
308  * @brief Copy length number of bytes from the source to destination address
309  *
310  * @param d pointer to the destination memory
311  * @param s pointer to the source memory
312  * @param l number of bytes to copy
313  *
314  * @return original value of dst pointer
315  */
316 #define ocs_memcpy(d, s, l)		memcpy(d, s, l)
317 
318 #define ocs_strlen(s)			strlen(s)
319 #define ocs_strcpy(d,s)			strcpy(d, s)
320 #define ocs_strncpy(d,s, n)		strncpy(d, s, n)
321 #define ocs_strcat(d, s)		strcat(d, s)
322 #define ocs_strtoul(s,ep,b)		strtoul(s,ep,b)
323 #define ocs_strtoull(s,ep,b)		((uint64_t)strtouq(s,ep,b))
324 #define ocs_atoi(s)			strtol(s, 0, 0)
325 #define ocs_strcmp(d,s)			strcmp(d,s)
326 #define ocs_strcasecmp(d,s)		strcasecmp(d,s)
327 #define ocs_strncmp(d,s,n)		strncmp(d,s,n)
328 #define ocs_strstr(h,n)			strstr(h,n)
329 #define ocs_strsep(h, n)		strsep(h, n)
330 #define ocs_strchr(s,c)			strchr(s,c)
331 #define ocs_copy_from_user(dst, src, n)	copyin(src, dst, n)
332 #define ocs_copy_to_user(dst, src, n)	copyout(src, dst, n)
333 #define ocs_snprintf(buf, n, fmt, ...)	snprintf(buf, n, fmt, ##__VA_ARGS__)
334 #define ocs_vsnprintf(buf, n, fmt, ap)	vsnprintf((char*)buf, n, fmt, ap)
335 #define ocs_sscanf(buf,fmt, ...)	sscanf(buf, fmt, ##__VA_ARGS__)
336 #define ocs_printf			printf
337 #define ocs_isspace(c)			isspace(c)
338 #define ocs_isdigit(c)			isdigit(c)
339 #define ocs_isxdigit(c)			isxdigit(c)
340 
341 extern uint64_t ocs_get_tsc(void);
342 extern void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size);
343 extern int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size);
344 extern void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size);
345 extern char *ocs_strdup(const char *s);
346 
347 /**
348  * @ingroup os
349  * @brief Set the value of each byte in memory
350  *
351  * @param b pointer to the memory
352  * @param c value used to set memory
353  * @param l number of bytes to set
354  *
355  * @return original value of mem pointer
356  */
357 #define ocs_memset(b, c, l) memset(b, c, l)
358 
359 #define LOG_CRIT	0
360 #define LOG_ERR		1
361 #define LOG_WARN	2
362 #define LOG_INFO	3
363 #define LOG_TEST	4
364 #define LOG_DEBUG	5
365 
366 extern int loglevel;
367 
368 extern void _ocs_log(ocs_t *ocs, const char *func, int line, const char *fmt, ...);
369 
370 #define ocs_log_crit(os, fmt, ...)	ocs_log(os, LOG_CRIT, fmt, ##__VA_ARGS__);
371 #define ocs_log_err(os, fmt, ...)	ocs_log(os, LOG_ERR, fmt, ##__VA_ARGS__);
372 #define ocs_log_warn(os, fmt, ...)	ocs_log(os, LOG_WARN, fmt, ##__VA_ARGS__);
373 #define ocs_log_info(os, fmt, ...)	ocs_log(os, LOG_INFO, fmt, ##__VA_ARGS__);
374 #define ocs_log_test(os, fmt, ...)	ocs_log(os, LOG_TEST, fmt, ##__VA_ARGS__);
375 #define ocs_log_debug(os, fmt, ...)	ocs_log(os, LOG_DEBUG, fmt, ##__VA_ARGS__);
376 
377 #define ocs_log(os, level, fmt, ...)                    \
378 	do {                                            \
379 		if (level <= loglevel) {                \
380 			_ocs_log(os, __func__, __LINE__, fmt, ##__VA_ARGS__);   \
381 		}                                       \
382 	} while (0)
383 
384 static inline uint32_t ocs_roundup(uint32_t x, uint32_t y)
385 {
386 	return (((x + y - 1) / y) * y);
387 }
388 
389 static inline uint32_t ocs_rounddown(uint32_t x, uint32_t y)
390 {
391 	return ((x / y) * y);
392 }
393 
394 /***************************************************************************
395  * Memory allocation interfaces
396  */
397 
398 #define OCS_M_ZERO	M_ZERO
399 #define OCS_M_NOWAIT	M_NOWAIT
400 
401 /**
402  * @ingroup os
403  * @brief Allocate host memory
404  *
405  * @param os OS handle
406  * @param size number of bytes to allocate
407  * @param flags additional options
408  *
409  * Flags include
410  *  - OCS_M_ZERO zero memory after allocating
411  *  - OCS_M_NOWAIT do not block/sleep waiting for an allocation request
412  *
413  * @return pointer to allocated memory, NULL otherwise
414  */
415 extern void *ocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags);
416 
417 /**
418  * @ingroup os
419  * @brief Free host memory
420  *
421  * @param os OS handle
422  * @param addr pointer to memory
423  * @param size bytes to free
424  */
425 extern void ocs_free(ocs_os_handle_t os, void *addr, size_t size);
426 
427 /**
428  * @ingroup os
429  * @brief generic DMA memory descriptor for driver allocations
430  *
431  * Memory regions ultimately used by the hardware are described using
432  * this structure. All implementations must include the structure members
433  * defined in the first section, and they may also add their own structure
434  * members in the second section.
435  *
436  * Note that each region described by ocs_dma_s is assumed to be physically
437  * contiguous.
438  */
439 typedef struct ocs_dma_s {
440 	/*
441 	 * OCS layer requires the following members
442 	 */
443 	void		*virt;	/**< virtual address of the memory used by the CPU */
444 	void		*alloc;	/**< originally allocated virtual address used to restore virt if modified */
445 	uintptr_t	phys;	/**< physical or bus address of the memory used by the hardware */
446 	size_t		size;	/**< size in bytes of the memory */
447 	/*
448 	 * Implementation specific fields allowed here
449 	 */
450 	size_t		len;	/**< application specific length */
451 	bus_dma_tag_t	tag;
452 	bus_dmamap_t	map;
453 } ocs_dma_t;
454 
455 /**
456  * @ingroup os
457  * @brief Returns maximum supported DMA allocation size
458  *
459  * @param os OS specific handle or driver context
460  * @param align alignment requirement for DMA allocation
461  *
462  * Return maximum supported DMA allocation size, given alignment
463  * requirement.
464  *
465  * @return maxiumum supported DMA allocation size
466  */
467 static inline uint32_t ocs_max_dma_alloc(ocs_os_handle_t os, size_t align)
468 {
469 	return ~((uint32_t)0); /* no max */
470 }
471 
472 /**
473  * @ingroup os
474  * @brief Allocate a DMA capable block of memory
475  *
476  * @param os OS specific handle or driver context
477  * @param dma DMA descriptor containing results of memory allocation
478  * @param size Size in bytes of desired allocation
479  * @param align Alignment in bytes of the requested allocation
480  *
481  * @return 0 on success, non-zero otherwise
482  */
483 extern int32_t ocs_dma_alloc(ocs_os_handle_t, ocs_dma_t *, size_t, size_t);
484 
485 /**
486  * @ingroup os
487  * @brief Free a DMA capable block of memory
488  *
489  * @param os OS specific handle or driver context
490  * @param dma DMA descriptor for memory to be freed
491  *
492  * @return 0 if memory is de-allocated, non-zero otherwise
493  */
494 extern int32_t ocs_dma_free(ocs_os_handle_t, ocs_dma_t *);
495 extern int32_t ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
496 extern int32_t ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
497 
498 static inline int32_t ocs_dma_valid(ocs_dma_t *dma)
499 {
500 	return (dma->size != 0);
501 }
502 
503 /**
504  * @ingroup os
505  * @brief Synchronize the DMA buffer memory
506  *
507  * Ensures memory coherency between the CPU and device
508  *
509  * @param dma DMA descriptor of memory to synchronize
510  * @param flags Describes direction of synchronization
511  *   - OCS_DMASYNC_PREREAD sync needed before hardware updates host memory
512  *   - OCS_DMASYNC_PREWRITE sync needed after CPU updates host memory but before hardware can access
513  *   - OCS_DMASYNC_POSTREAD sync needed after hardware updates host memory but before CPU can access
514  *   - OCS_DMASYNC_POSTWRITE sync needed after hardware updates host memory
515  */
516 extern void ocs_dma_sync(ocs_dma_t *, uint32_t);
517 
518 #define OCS_DMASYNC_PREWRITE BUS_DMASYNC_PREWRITE
519 #define OCS_DMASYNC_POSTREAD BUS_DMASYNC_POSTREAD
520 
521 
522 /***************************************************************************
523  * Locking
524  */
525 
526 /**
527  * @ingroup os
528  * @typedef ocs_lock_t
529  * @brief Define the type used implement locking
530  */
531 #define MAX_LOCK_DESC_LEN	64
532 typedef struct ocs_lock_s {
533 	struct	mtx lock;
534 	char	name[MAX_LOCK_DESC_LEN];
535 } ocs_lock_t;
536 
537 /**
538  * @ingroup os
539  * @brief Initialize a lock
540  *
541  * @param lock lock to initialize
542  * @param name string identifier for the lock
543  */
544 extern void ocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...);
545 
546 /**
547  * @ingroup os
548  * @brief Free a previously allocated lock
549  *
550  * @param lock lock to free
551  */
552 static inline void
553 ocs_lock_free(ocs_lock_t *lock)
554 {
555 
556 	if (mtx_initialized(&(lock)->lock)) {
557 		mtx_assert(&(lock)->lock, MA_NOTOWNED);
558 		mtx_destroy(&(lock)->lock);
559 	} else {
560 		panic("XXX trying to free with un-initialized mtx!?!?\n");
561 	}
562 }
563 
564 /**
565  * @ingroup os
566  * @brief Acquire a lock
567  *
568  * @param lock lock to obtain
569  */
570 static inline void
571 ocs_lock(ocs_lock_t *lock)
572 {
573 
574 	if (mtx_initialized(&(lock)->lock)) {
575 		mtx_assert(&(lock)->lock, MA_NOTOWNED);
576 		mtx_lock(&(lock)->lock);
577 	} else {
578 		panic("XXX trying to lock with un-initialized mtx!?!?\n");
579 	}
580 }
581 
582 /**
583  * @ingroup os
584  * @brief Release a lock
585  *
586  * @param lock lock to release
587  */
588 static inline void
589 ocs_unlock(ocs_lock_t *lock)
590 {
591 
592 	if (mtx_initialized(&(lock)->lock)) {
593 		mtx_assert(&(lock)->lock, MA_OWNED | MA_NOTRECURSED);
594 		mtx_unlock(&(lock)->lock);
595 	} else {
596 		panic("XXX trying to unlock with un-initialized mtx!?!?\n");
597 	}
598 }
599 
600 /**
601  * @ingroup os
602  * @typedef ocs_lock_t
603  * @brief Define the type used implement recursive locking
604  */
605 typedef struct ocs_lock_s ocs_rlock_t;
606 
607 /**
608  * @ingroup os
609  * @brief Initialize a recursive lock
610  *
611  * @param ocs pointer to ocs structure
612  * @param lock lock to initialize
613  * @param name string identifier for the lock
614  */
615 static inline void
616 ocs_rlock_init(ocs_t *ocs, ocs_rlock_t *lock, const char *name)
617 {
618 	ocs_strncpy(lock->name, name, MAX_LOCK_DESC_LEN);
619 	mtx_init(&(lock)->lock, lock->name, NULL, MTX_DEF | MTX_RECURSE | MTX_DUPOK);
620 }
621 
622 /**
623  * @ingroup os
624  * @brief Free a previously allocated recursive lock
625  *
626  * @param lock lock to free
627  */
628 static inline void
629 ocs_rlock_free(ocs_rlock_t *lock)
630 {
631 	if (mtx_initialized(&(lock)->lock)) {
632 		mtx_destroy(&(lock)->lock);
633 	} else {
634 		panic("XXX trying to free with un-initialized mtx!?!?\n");
635 	}
636 }
637 
638 /**
639  * @brief try to acquire a recursive lock
640  *
641  * Attempt to acquire a recursive lock, return TRUE if successful
642  *
643  * @param lock pointer to recursive lock
644  *
645  * @return TRUE if lock was acquired, FALSE if not
646  */
647 static inline int32_t
648 ocs_rlock_try(ocs_rlock_t *lock)
649 {
650 	int rc = mtx_trylock(&(lock)->lock);
651 
652 	return rc != 0;
653 }
654 
655 /**
656  * @ingroup os
657  * @brief Acquire a recursive lock
658  *
659  * @param lock lock to obtain
660  */
661 static inline void
662 ocs_rlock_acquire(ocs_rlock_t *lock)
663 {
664 	if (mtx_initialized(&(lock)->lock)) {
665 		mtx_lock(&(lock)->lock);
666 	} else {
667 		panic("XXX trying to lock with un-initialized mtx!?!?\n");
668 	}
669 }
670 
671 /**
672  * @ingroup os
673  * @brief Release a recursive lock
674  *
675  * @param lock lock to release
676  */
677 static inline void
678 ocs_rlock_release(ocs_rlock_t *lock)
679 {
680 	if (mtx_initialized(&(lock)->lock)) {
681 		mtx_assert(&(lock)->lock, MA_OWNED);
682 		mtx_unlock(&(lock)->lock);
683 	} else {
684 		panic("XXX trying to unlock with un-initialized mtx!?!?\n");
685 	}
686 }
687 
688 /**
689  * @brief counting semaphore
690  *
691  * Declaration of the counting semaphore object
692  *
693  */
694 typedef struct {
695 	char name[32];
696 	struct sema sem;		/**< OS counting semaphore structure */
697 } ocs_sem_t;
698 
699 #define OCS_SEM_FOREVER		(-1)
700 #define OCS_SEM_TRY		(0)
701 
702 /**
703  * @brief Initialize a counting semaphore
704  *
705  * The semaphore is initiatlized to the value
706  *
707  * @param sem pointer to semaphore
708  * @param val initial value
709  * @param name label for the semaphore
710  *
711  * @return returns 0 for success, a negative error code value for failure.
712  */
713 
714 extern int ocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...) __attribute__((format(printf, 3, 4)));
715 
716 /**
717  * @brief execute a P (decrement) operation
718  *
719  * A P (decrement and block if negative) operation is performed on the semaphore.
720  *
721  * If timeout_usec is zero, the semaphore attempts one time and returns 0 if acquired.
722  * If timeout_usec is greater than zero, then the call will block until the semaphore
723  * is acquired, or a timeout occurred.  If timeout_usec is less than zero, then
724  * the call will block until the semaphore is acquired.
725  *
726  * @param sem pointer to semaphore
727  * @param timeout_usec timeout in microseconds
728  *
729  * @return returns 0 for success, negative value if the semaphore was not acquired.
730  */
731 
732 static inline int
733 ocs_sem_p(ocs_sem_t *sem, int timeout_usec)
734 {
735 	int32_t rc = 0;
736 
737 	if (timeout_usec == 0) {
738 		rc = sema_trywait(&sem->sem);
739 		if (rc == 0) {
740 			rc = -1;
741 		}
742 	} else if (timeout_usec > 0) {
743 		struct timeval tv;
744 		uint32_t ticks;
745 
746 		tv.tv_sec = timeout_usec / 1000000;
747 		tv.tv_usec = timeout_usec % 1000000;
748 		ticks = tvtohz(&tv);
749 		if (ticks == 0) {
750 			ticks ++;
751 		}
752 		rc = sema_timedwait(&sem->sem, ticks);
753 		if (rc != 0) {
754 			rc = -1;
755 		}
756 	} else {
757 		sema_wait(&sem->sem);
758 	}
759 	if (rc)
760 		rc = -1;
761 
762 	return rc;
763 }
764 
765 /**
766  * @brief perform a V (increment) operation on a counting semaphore
767  *
768  * The semaphore is incremented, unblocking one thread that is waiting on the
769  * sempahore
770  *
771  * @param sem pointer to the semaphore
772  *
773  * @return none
774  */
775 
776 static inline void
777 ocs_sem_v(ocs_sem_t *sem)
778 {
779 	sema_post(&sem->sem);
780 }
781 
782 /***************************************************************************
783  * Bitmap
784  */
785 
786 /**
787  * @ingroup os
788  * @typedef ocs_bitmap_t
789  * @brief Define the type used implement bit-maps
790  */
791 typedef bitstr_t ocs_bitmap_t;
792 
793 /**
794  * @ingroup os
795  * @brief Allocate a bitmap
796  *
797  * @param n_bits Minimum number of entries in the bit-map
798  *
799  * @return pointer to the bit-map or NULL on error
800  */
801 extern ocs_bitmap_t *ocs_bitmap_alloc(uint32_t n_bits);
802 
803 /**
804  * @ingroup os
805  * @brief Free a bit-map
806  *
807  * @param bitmap Bit-map to free
808  */
809 extern void ocs_bitmap_free(ocs_bitmap_t *bitmap);
810 
811 /**
812  * @ingroup os
813  * @brief Find next unset bit and set it
814  *
815  * @param bitmap bit map to search
816  * @param n_bits number of bits in map
817  *
818  * @return bit position or -1 if map is full
819  */
820 extern int32_t ocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits);
821 
822 /**
823  * @ingroup os
824  * @brief search for next (un)set bit
825  *
826  * @param bitmap bit map to search
827  * @param set search for a set or unset bit
828  * @param n_bits number of bits in map
829  *
830  * @return bit position or -1
831  */
832 extern int32_t ocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits);
833 
834 /**
835  * @ingroup os
836  * @brief clear the specified bit
837  *
838  * @param bitmap pointer to bit map
839  * @param bit bit number to clear
840  */
841 extern void ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit);
842 
843 extern int32_t ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len);
844 
845 /***************************************************************************
846  * Timer Routines
847  *
848  * Functions for setting, querying and canceling timers.
849  */
850 typedef struct {
851 	struct callout	callout;
852 	struct mtx	lock;
853 
854 	void	(*func)(void *);
855 	void	*data;
856 } ocs_timer_t;
857 
858 /**
859  * @ingroup os
860  * @brief Initialize and set a timer
861  *
862  * @param os OS handle
863  * @param timer    pointer to the structure allocated for this timer
864  * @param func     the function to call when the timer expires
865  * @param data     Data to pass to the provided timer function when the timer
866  *                 expires.
867  * @param timeout_ms the timeout in milliseconds
868  */
869 extern int32_t ocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg),
870 			       void *data, uint32_t timeout_ms);
871 
872 /**
873  * @ingroup os
874  * @brief Modify a timer's expiration
875  *
876  * @param timer    pointer to the structure allocated for this timer
877  * @param timeout_ms the timeout in milliseconds
878  */
879 extern int32_t ocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms);
880 
881 /**
882  * @ingroup os
883  * @brief Queries to see if a timer is pending.
884  *
885  * @param timer    pointer to the structure allocated for this timer
886  *
887  * @return non-zero if the timer is pending
888  */
889 extern int32_t ocs_timer_pending(ocs_timer_t *timer);
890 
891 /**
892  * @ingroup os
893  * @brief Remove a pending timer
894  *
895  * @param timer    pointer to the structure allocated for this timer
896  *                 expires.
897  */
898 extern int32_t ocs_del_timer(ocs_timer_t *timer);
899 
900 /***************************************************************************
901  * Atomics
902  *
903  */
904 
905 typedef uint32_t ocs_atomic_t;
906 
907 /**
908  * @ingroup os
909  * @brief initialize an atomic
910  *
911  * @param a    pointer to the atomic object
912  * @param v    initial value
913  *
914  * @return none
915  */
916 #define ocs_atomic_init(a, v)	ocs_atomic_set(a, v)
917 
918 /**
919  * @ingroup os
920  * @brief adds an integer to an atomic value
921  *
922  * @param a    pointer to the atomic object
923  * @param v    value to increment
924  *
925  * @return the value of the atomic before incrementing.
926  */
927 #define ocs_atomic_add_return(a, v)	atomic_fetchadd_32(a, v)
928 
929 /**
930  * @ingroup os
931  * @brief subtracts an integer to an atomic value
932  *
933  * @param a    pointer to the atomic object
934  * @param v    value to increment
935  *
936  * @return the value of the atomic before subtracting.
937  */
938 #define ocs_atomic_sub_return(a, v)     atomic_fetchadd_32(a, (-(v)))
939 
940 /**
941  * @ingroup os
942  * @brief returns the current value of an atomic object
943  *
944  * @param a    pointer to the atomic object
945  *
946  * @return the value of the atomic.
947  */
948 #define ocs_atomic_read(a)		atomic_load_acq_32(a)
949 
950 /**
951  * @ingroup os
952  * @brief sets the current value of an atomic object
953  *
954  * @param a    pointer to the atomic object
955  */
956 #define ocs_atomic_set(a, v)		atomic_store_rel_32(a, v)
957 
958 /**
959  * @ingroup os
960  * @brief Sets atomic to 0, returns previous value
961  *
962  * @param a    pointer to the atomic object
963  *
964  * @return the value of the atomic before the operation.
965  */
966 #define ocs_atomic_read_and_clear	atomic_readandclear_32(a)
967 
968 /**
969  * @brief OCS thread structure
970  *
971  */
972 
973 typedef struct ocs_thread_s ocs_thread_t;
974 
975 typedef int32_t (*ocs_thread_fctn)(ocs_thread_t *mythread);
976 
977 struct ocs_thread_s  {
978 	struct thread *tcb;			/*<< thread control block */
979 	ocs_thread_fctn fctn;			/*<< thread function */
980 	char *name;				/*<< name of thread */
981 	void *arg;				/*<< pointer to thread argument */
982 	ocs_atomic_t terminate;			/*<< terminate request */
983 	int32_t retval;				/*<< return value */
984 	uint32_t cpu_affinity;			/*<< cpu affinity */
985 };
986 #define OCS_THREAD_DEFAULT_STACK_SIZE_PAGES	8
987 
988 /**
989  * @brief OCS thread start options
990  *
991  */
992 
993 typedef enum {
994 	OCS_THREAD_RUN,				/*<< run immediately */
995 	OCS_THREAD_CREATE,			/*<< create and wait for start request */
996 } ocs_thread_start_e;
997 
998 
999 extern int32_t ocs_thread_create(ocs_os_handle_t os, ocs_thread_t *thread, ocs_thread_fctn fctn,
1000 				 const char *name, void *arg, ocs_thread_start_e start_option);
1001 extern int32_t ocs_thread_start(ocs_thread_t *thread);
1002 extern void *ocs_thread_get_arg(ocs_thread_t *mythread);
1003 extern int32_t ocs_thread_terminate(ocs_thread_t *thread);
1004 extern int32_t ocs_thread_terminate_requested(ocs_thread_t *thread);
1005 extern int32_t ocs_thread_get_retval(ocs_thread_t *thread);
1006 extern void ocs_thread_yield(ocs_thread_t *thread);
1007 extern ocs_thread_t *ocs_thread_self(void);
1008 extern int32_t ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu);
1009 extern int32_t ocs_thread_getcpu(void);
1010 
1011 
1012 /***************************************************************************
1013  * PCI
1014  *
1015  * Several functions below refer to a "register set". This is one or
1016  * more PCI BARs that constitute a PCI address. For example, if a MMIO
1017  * region is described using both BAR[0] and BAR[1], the combination of
1018  * BARs defines register set 0.
1019  */
1020 
1021 /**
1022  * @brief tracks mapped PCI memory regions
1023  */
1024 typedef struct ocs_pci_reg_s {
1025 	uint32_t		rid;
1026 	struct resource		*res;
1027 	bus_space_tag_t		btag;
1028 	bus_space_handle_t	bhandle;
1029 } ocs_pci_reg_t;
1030 
1031 #define PCI_MAX_BAR				6
1032 #define PCI_64BIT_BAR0				0
1033 
1034 #define PCI_VENDOR_EMULEX       		0x10df		/* Emulex */
1035 
1036 #define PCI_PRODUCT_EMULEX_OCE16001		0xe200		/* OneCore 16Gb FC (lancer) */
1037 #define PCI_PRODUCT_EMULEX_OCE16002		0xe200		/* OneCore 16Gb FC (lancer) */
1038 #define PCI_PRODUCT_EMULEX_LPE31004		0xe300  /* LightPulse 16Gb x 4 FC (lancer-g6) */
1039 #define PCI_PRODUCT_EMULEX_LPE32002		0xe300  /* LightPulse 32Gb x 2 FC (lancer-g6) */
1040 #define PCI_PRODUCT_EMULEX_OCE1600_VF		0xe208
1041 #define PCI_PRODUCT_EMULEX_OCE50102		0xe260		/* OneCore FCoE (lancer) */
1042 #define PCI_PRODUCT_EMULEX_OCE50102_VF		0xe268
1043 
1044 /**
1045  * @ingroup os
1046  * @brief Get the PCI bus, device, and function values
1047  *
1048  * @param ocs OS specific handle or driver context
1049  * @param bus Pointer to location to store the bus number.
1050  * @param dev Pointer to location to store the device number.
1051  * @param func Pointer to location to store the function number.
1052  *
1053  * @return Returns 0.
1054  */
1055 extern int32_t
1056 ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
1057 
1058 extern ocs_t *ocs_get_instance(uint32_t index);
1059 extern uint32_t ocs_instance(void *os);
1060 
1061 
1062 /**
1063  * @ingroup os
1064  * @brief Read a 32 bit value from the specified configuration register
1065  *
1066  * @param os OS specific handle or driver context
1067  * @param reg register offset
1068  *
1069  * @return The 32 bit value
1070  */
1071 extern uint32_t ocs_config_read32(ocs_os_handle_t os, uint32_t reg);
1072 
1073 /**
1074  * @ingroup os
1075  * @brief Read a 16 bit value from the specified configuration
1076  *        register
1077  *
1078  * @param os OS specific handle or driver context
1079  * @param reg register offset
1080  *
1081  * @return The 16 bit value
1082  */
1083 extern uint16_t ocs_config_read16(ocs_os_handle_t os, uint32_t reg);
1084 
1085 /**
1086  * @ingroup os
1087  * @brief Read a 8 bit value from the specified configuration
1088  *        register
1089  *
1090  * @param os OS specific handle or driver context
1091  * @param reg register offset
1092  *
1093  * @return The 8 bit value
1094  */
1095 extern uint8_t ocs_config_read8(ocs_os_handle_t os, uint32_t reg);
1096 
1097 /**
1098  * @ingroup os
1099  * @brief Write a 8 bit value to the specified configuration
1100  *        register
1101  *
1102  * @param os OS specific handle or driver context
1103  * @param reg register offset
1104  * @param val value to write
1105  *
1106  * @return None
1107  */
1108 extern void ocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val);
1109 
1110 /**
1111  * @ingroup os
1112  * @brief Write a 16 bit value to the specified configuration
1113  *        register
1114  *
1115  * @param os OS specific handle or driver context
1116  * @param reg register offset
1117  * @param val value to write
1118  *
1119  * @return None
1120  */
1121 extern void ocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val);
1122 
1123 /**
1124  * @ingroup os
1125  * @brief Write a 32 bit value to the specified configuration
1126  *        register
1127  *
1128  * @param os OS specific handle or driver context
1129  * @param reg register offset
1130  * @param val value to write
1131  *
1132  * @return None
1133  */
1134 extern void ocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val);
1135 
1136 /**
1137  * @ingroup os
1138  * @brief Read a PCI register
1139  *
1140  * @param os OS specific handle or driver context
1141  * @param rset Which "register set" to use
1142  * @param off  Register offset
1143  *
1144  * @return 32 bit conents of the register
1145  */
1146 extern uint32_t ocs_reg_read32(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1147 
1148 /**
1149  * @ingroup os
1150  * @brief Read a PCI register
1151  *
1152  * @param os OS specific handle or driver context
1153  * @param rset Which "register set" to use
1154  * @param off  Register offset
1155  *
1156  * @return 16 bit conents of the register
1157  */
1158 extern uint16_t ocs_reg_read16(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1159 
1160 /**
1161  * @ingroup os
1162  * @brief Read a PCI register
1163  *
1164  * @param os OS specific handle or driver context
1165  * @param rset Which "register set" to use
1166  * @param off  Register offset
1167  *
1168  * @return 8 bit conents of the register
1169  */
1170 extern uint8_t ocs_reg_read8(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1171 
1172 /**
1173  * @ingroup os
1174  * @brief Write a PCI register
1175  *
1176  * @param os OS specific handle or driver context
1177  * @param rset Which "register set" to use
1178  * @param off  Register offset
1179  * @param val  32-bit value to write
1180  */
1181 extern void ocs_reg_write32(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint32_t val);
1182 
1183 /**
1184  * @ingroup os
1185  * @brief Write a PCI register
1186  *
1187  * @param os OS specific handle or driver context
1188  * @param rset Which "register set" to use
1189  * @param off  Register offset
1190  * @param val  16-bit value to write
1191  */
1192 extern void ocs_reg_write16(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint16_t val);
1193 
1194 /**
1195  * @ingroup os
1196  * @brief Write a PCI register
1197  *
1198  * @param os OS specific handle or driver context
1199  * @param rset Which "register set" to use
1200  * @param off  Register offset
1201  * @param val  8-bit value to write
1202  */
1203 extern void ocs_reg_write8(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint8_t val);
1204 
1205 /**
1206  * @ingroup os
1207  * @brief Disable interrupts
1208  *
1209  * @param os OS specific handle or driver context
1210  */
1211 extern void ocs_intr_disable(ocs_os_handle_t os);
1212 
1213 /**
1214  * @ingroup os
1215  * @brief Enable interrupts
1216  *
1217  * @param os OS specific handle or driver context
1218  */
1219 extern void ocs_intr_enable(ocs_os_handle_t os);
1220 
1221 /**
1222  * @ingroup os
1223  * @brief Return model string
1224  *
1225  * @param os OS specific handle or driver context
1226  */
1227 extern const char *ocs_pci_model(uint16_t vendor, uint16_t device);
1228 
1229 extern void ocs_print_stack(void);
1230 
1231 extern void ocs_abort(void) __attribute__((noreturn));
1232 
1233 /***************************************************************************
1234  * Reference counting
1235  *
1236  */
1237 
1238 /**
1239  * @ingroup os
1240  * @brief reference counter object
1241  */
1242 typedef void (*ocs_ref_release_t)(void *arg);
1243 typedef struct ocs_ref_s {
1244 	ocs_ref_release_t release; /* release function to call */
1245 	void *arg;
1246 	uint32_t count;		/* ref count; no need to be atomic if we have a lock */
1247 } ocs_ref_t;
1248 
1249 /**
1250  * @ingroup os
1251  * @brief initialize given reference object
1252  *
1253  * @param ref Pointer to reference object
1254  * @param release Function to be called when count is 0.
1255  * @param arg Argument to be passed to release function.
1256  */
1257 static inline void
1258 ocs_ref_init(ocs_ref_t *ref, ocs_ref_release_t release, void *arg)
1259 {
1260 	ref->release = release;
1261 	ref->arg = arg;
1262 	ocs_atomic_init(&ref->count, 1);
1263 }
1264 
1265 /**
1266  * @ingroup os
1267  * @brief Return reference count value
1268  *
1269  * @param ref Pointer to reference object
1270  *
1271  * @return Count value of given reference object
1272  */
1273 static inline uint32_t
1274 ocs_ref_read_count(ocs_ref_t *ref)
1275 {
1276 	return ocs_atomic_read(&ref->count);
1277 }
1278 
1279 /**
1280  * @ingroup os
1281  * @brief Set count on given reference object to a value.
1282  *
1283  * @param ref Pointer to reference object
1284  * @param i Set count to this value
1285  */
1286 static inline void
1287 ocs_ref_set(ocs_ref_t *ref, int i)
1288 {
1289 	ocs_atomic_set(&ref->count, i);
1290 }
1291 
1292 /**
1293  * @ingroup os
1294  * @brief Take a reference on given object.
1295  *
1296  * @par Description
1297  * This function takes a reference on an object.
1298  *
1299  * Note: this function should only be used if the caller can
1300  * guarantee that the reference count is >= 1 and will stay >= 1
1301  * for the duration of this call (i.e. won't go to zero). If it
1302  * can't (the refcount may go to zero during this call),
1303  * ocs_ref_get_unless_zero() should be used instead.
1304  *
1305  * @param ref Pointer to reference object
1306  *
1307  */
1308 static inline void
1309 ocs_ref_get(ocs_ref_t *ref)
1310 {
1311 	ocs_atomic_add_return(&ref->count, 1);
1312 }
1313 
1314 /**
1315  * @ingroup os
1316  * @brief Take a reference on given object if count is not zero.
1317  *
1318  * @par Description
1319  * This function takes a reference on an object if and only if
1320  * the given reference object is "active" or valid.
1321  *
1322  * @param ref Pointer to reference object
1323  *
1324  * @return non-zero if "get" succeeded; Return zero if ref count
1325  * is zero.
1326  */
1327 static inline uint32_t
1328 ocs_ref_get_unless_zero(ocs_ref_t *ref)
1329 {
1330 	uint32_t rc = 0;
1331 	rc = ocs_atomic_read(&ref->count);
1332 		if (rc != 0) {
1333 			ocs_atomic_add_return(&ref->count, 1);
1334 		}
1335 	return rc;
1336 }
1337 
1338 /**
1339  * @ingroup os
1340  * @brief Decrement reference on given object
1341  *
1342  * @par Description
1343  * This function decrements the reference count on the given
1344  * reference object. If the reference count becomes zero, the
1345  * "release" function (set during "init" time) is called.
1346  *
1347  * @param ref Pointer to reference object
1348  *
1349  * @return non-zero if release function was called; zero
1350  * otherwise.
1351  */
1352 static inline uint32_t
1353 ocs_ref_put(ocs_ref_t *ref)
1354 {
1355 	uint32_t rc = 0;
1356 	if (ocs_atomic_sub_return(&ref->count, 1) == 1) {
1357 		ref->release(ref->arg);
1358 		rc = 1;
1359 	}
1360 	return rc;
1361 }
1362 
1363 /**
1364  * @ingroup os
1365  * @brief Get the OS system ticks
1366  *
1367  * @return number of ticks that have occurred since the system
1368  * booted.
1369  */
1370 static inline uint64_t
1371 ocs_get_os_ticks(void)
1372 {
1373 	return ticks;
1374 }
1375 
1376 /**
1377  * @ingroup os
1378  * @brief Get the OS system tick frequency
1379  *
1380  * @return frequency of system ticks.
1381  */
1382 static inline uint32_t
1383 ocs_get_os_tick_freq(void)
1384 {
1385 	return hz;
1386 }
1387 
1388 /*****************************************************************************
1389  *
1390  * CPU topology API
1391  */
1392 
1393 typedef struct {
1394 	uint32_t num_cpus;	/* Number of CPU cores */
1395 	uint8_t hyper;		/* TRUE if threaded CPUs */
1396 } ocs_cpuinfo_t;
1397 
1398 extern int32_t ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo);
1399 extern uint32_t ocs_get_num_cpus(void);
1400 
1401 #include "ocs_list.h"
1402 #include "ocs_utils.h"
1403 #include "ocs_mgmt.h"
1404 #include "ocs_common.h"
1405 
1406 #endif /* !_OCS_OS_H */
1407