ocs_os.h revision 331766
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: head/sys/dev/ocs_fc/ocs_os.h 331766 2018-03-30 15:28:25Z ken $
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
42typedef 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 */
164typedef 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 */
175static 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 */
193static 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 */
210static 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 */
297static inline time_t
298ocs_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
341extern uint64_t ocs_get_tsc(void);
342extern void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size);
343extern int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size);
344extern void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size);
345extern 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
366extern int loglevel;
367
368extern 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
384static inline uint32_t ocs_roundup(uint32_t x, uint32_t y)
385{
386	return (((x + y - 1) / y) * y);
387}
388
389static 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 */
415extern 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 */
425extern 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 */
439typedef 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 */
467static 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 */
483extern 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 */
494extern int32_t ocs_dma_free(ocs_os_handle_t, ocs_dma_t *);
495extern int32_t ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
496extern int32_t ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
497
498static 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 */
516extern 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
532typedef 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 */
544extern 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 */
552static inline void
553ocs_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 */
570static inline void
571ocs_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 */
588static inline void
589ocs_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 */
605typedef 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 */
615static inline void
616ocs_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 */
628static inline void
629ocs_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 */
647static inline int32_t
648ocs_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 */
661static inline void
662ocs_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 */
677static inline void
678ocs_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 */
694typedef 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
714extern 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
732static inline int
733ocs_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
776static inline void
777ocs_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 */
791typedef 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 */
801extern 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 */
809extern 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 */
820extern 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 */
832extern 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 */
841extern void ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit);
842
843extern 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 */
850typedef 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 */
869extern 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 */
879extern 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 */
889extern 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 */
898extern int32_t ocs_del_timer(ocs_timer_t *timer);
899
900/***************************************************************************
901 * Atomics
902 *
903 */
904
905typedef 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
973typedef struct ocs_thread_s ocs_thread_t;
974
975typedef int32_t (*ocs_thread_fctn)(ocs_thread_t *mythread);
976
977struct 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
993typedef enum {
994	OCS_THREAD_RUN,				/*<< run immediately */
995	OCS_THREAD_CREATE,			/*<< create and wait for start request */
996} ocs_thread_start_e;
997
998
999extern 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);
1001extern int32_t ocs_thread_start(ocs_thread_t *thread);
1002extern void *ocs_thread_get_arg(ocs_thread_t *mythread);
1003extern int32_t ocs_thread_terminate(ocs_thread_t *thread);
1004extern int32_t ocs_thread_terminate_requested(ocs_thread_t *thread);
1005extern int32_t ocs_thread_get_retval(ocs_thread_t *thread);
1006extern void ocs_thread_yield(ocs_thread_t *thread);
1007extern ocs_thread_t *ocs_thread_self(void);
1008extern int32_t ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu);
1009extern 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 */
1024typedef 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 */
1055extern int32_t
1056ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
1057
1058extern ocs_t *ocs_get_instance(uint32_t index);
1059extern 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 */
1071extern 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 */
1083extern 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 */
1095extern 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 */
1108extern 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 */
1121extern 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 */
1134extern 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 */
1146extern 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 */
1158extern 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 */
1170extern 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 */
1181extern 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 */
1192extern 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 */
1203extern 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 */
1211extern 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 */
1219extern 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 */
1227extern const char *ocs_pci_model(uint16_t vendor, uint16_t device);
1228
1229extern void ocs_print_stack(void);
1230
1231extern void ocs_abort(void) __attribute__((noreturn));
1232
1233/***************************************************************************
1234 * Reference counting
1235 *
1236 */
1237
1238/**
1239 * @ingroup os
1240 * @brief reference counter object
1241 */
1242typedef void (*ocs_ref_release_t)(void *arg);
1243typedef 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 */
1257static inline void
1258ocs_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 */
1273static inline uint32_t
1274ocs_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 */
1286static inline void
1287ocs_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 */
1308static inline void
1309ocs_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 */
1327static inline uint32_t
1328ocs_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 */
1352static inline uint32_t
1353ocs_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 */
1370static inline uint64_t
1371ocs_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 */
1382static inline uint32_t
1383ocs_get_os_tick_freq(void)
1384{
1385	return hz;
1386}
1387
1388/*****************************************************************************
1389 *
1390 * CPU topology API
1391 */
1392
1393typedef struct {
1394	uint32_t num_cpus;	/* Number of CPU cores */
1395	uint8_t hyper;		/* TRUE if threaded CPUs */
1396} ocs_cpuinfo_t;
1397
1398extern int32_t ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo);
1399extern 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