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
32/**
33 * @file
34 * bsd specific headers common to the driver
35 */
36
37#ifndef _OCS_OS_H
38#define _OCS_OS_H
39
40/***************************************************************************
41 * OS specific includes
42 */
43#include "opt_stack.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/malloc.h>
48#include <sys/kernel.h>
49#include <sys/module.h>
50#include <sys/bus.h>
51#include <sys/rman.h>
52#include <sys/endian.h>
53#include <sys/stddef.h>
54#include <sys/lock.h>
55#include <sys/mutex.h>
56#include <sys/taskqueue.h>
57#include <sys/bitstring.h>
58#include <sys/stack.h>
59
60#include <machine/atomic.h>
61#include <machine/bus.h>
62#include <machine/stdarg.h>
63
64#include <dev/pci/pcivar.h>
65
66#include <sys/sema.h>
67#include <sys/time.h>
68
69#include <sys/proc.h>
70#include <sys/kthread.h>
71#include <sys/unistd.h>
72#include <sys/sched.h>
73
74#include <sys/conf.h>
75#include <sys/sysctl.h>
76#include <sys/ioccom.h>
77#include <sys/ctype.h>
78
79#include <sys/linker.h>		/* for debug of memory allocations */
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)	/* maximum 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
155typedef struct ocs_softc ocs_t;
156
157/**
158 * @ingroup os
159 * @typedef ocs_os_handle_t
160 * @brief OS specific handle or driver context
161 *
162 * This can be anything from a void * to some other OS specific type. The lower
163 * layers make no assumption about its value and pass it back as the first
164 * parameter to most OS functions.
165 */
166typedef ocs_t * ocs_os_handle_t;
167
168/**
169 * @ingroup os
170 * @brief return the lower 32-bits of a bus address
171 *
172 * @param addr Physical or bus address to convert
173 * @return lower 32-bits of a bus address
174 *
175 * @note this may be a good cadidate for an inline or macro
176 */
177static inline uint32_t ocs_addr32_lo(uintptr_t addr)
178{
179#if defined(__LP64__)
180	return (uint32_t)(addr & 0xffffffffUL);
181#else
182	return addr;
183#endif
184}
185
186/**
187 * @ingroup os
188 * @brief return the upper 32-bits of a bus address
189 *
190 * @param addr Physical or bus address to convert
191 * @return upper 32-bits of a bus address
192 *
193 * @note this may be a good cadidate for an inline or macro
194 */
195static inline uint32_t ocs_addr32_hi(uintptr_t addr)
196{
197#if defined(__LP64__)
198	return (uint32_t)(addr >> 32);
199#else
200	return 0;
201#endif
202}
203
204/**
205 * @ingroup os
206 * @brief return the log2(val)
207 *
208 * @param val number to use (assumed to be exact power of 2)
209 *
210 * @return log base 2 of val
211 */
212static inline uint32_t ocs_lg2(uint32_t val)
213{
214#if defined(__GNUC__)
215	/*
216	 * clz = "count leading zero's"
217	 *
218	 * Assuming val is an exact power of 2, the most significant bit
219	 * will be the log base 2 of val
220	 */
221	return 31 - __builtin_clz(val);
222#else
223#error You need to provide a non-GCC version of this function
224#endif
225}
226
227/**
228 * @ingroup os
229 * @brief optimization barrier
230 *
231 * Optimization barrier. Prevents compiler re-ordering
232 * instructions across barrier.
233 *
234 * @return none
235 */
236#define ocs_barrier()	 __asm __volatile("" : : : "memory");
237
238/**
239 * @ingroup os
240 * @brief convert a big endian 32 bit value to the host's native format
241 *
242 * @param val 32 bit big endian value
243 *
244 * @return value converted to the host's native endianness
245 */
246#define ocs_be32toh(val)	be32toh(val)
247
248/**
249 * @ingroup os
250 * @brief convert a 32 bit value from the host's native format to big endian
251 *
252 * @param val 32 bit native endian value
253 *
254 * @return value converted to big endian
255 */
256#define ocs_htobe32(val)	htobe32(val)
257
258/**
259 * @ingroup os
260 * @brief convert a 16 bit value from the host's native format to big endian
261 *
262 * @param v 16 bit native endian value
263 *
264 * @return value converted to big endian
265 */
266#define ocs_htobe16(v)	htobe16(v)
267#define ocs_be16toh(v)	be16toh(v)
268
269#define ocs_htobe64(v)	htobe64(v)
270#define ocs_be64toh(v)	be64toh(v)
271
272/**
273 * @ingroup os
274 * @brief Delay execution by the given number of micro-seconds
275 *
276 * @param usec number of micro-seconds to "busy-wait"
277 *
278 * @note The value of usec may be greater than 1,000,000
279 */
280#define ocs_udelay(usec) DELAY(usec)
281
282/**
283 * @ingroup os
284 * @brief Delay execution by the given number of milli-seconds
285 *
286 * @param msec number of milli-seconds to "busy-wait"
287 *
288 * @note The value of usec may be greater than 1,000,000
289 */
290#define ocs_msleep(msec) ocs_udelay((msec)*1000)
291
292/**
293 * @ingroup os
294 * @brief Get time of day in msec
295 *
296 * @return time of day in msec
297 */
298static inline time_t
299ocs_msectime(void)
300{
301	struct timeval tv;
302
303	getmicrotime(&tv);
304	return (tv.tv_sec*1000) + (tv.tv_usec / 1000);
305}
306
307/**
308 * @ingroup os
309 * @brief Copy length number of bytes from the source to destination address
310 *
311 * @param d pointer to the destination memory
312 * @param s pointer to the source memory
313 * @param l number of bytes to copy
314 *
315 * @return original value of dst pointer
316 */
317#define ocs_memcpy(d, s, l)		memcpy(d, s, l)
318
319#define ocs_strlen(s)			strlen(s)
320#define ocs_strcpy(d,s)			strcpy(d, s)
321#define ocs_strncpy(d,s, n)		strncpy(d, s, n)
322#define ocs_strcat(d, s)		strcat(d, s)
323#define ocs_strtoul(s,ep,b)		strtoul(s,ep,b)
324#define ocs_strtoull(s,ep,b)		((uint64_t)strtouq(s,ep,b))
325#define ocs_atoi(s)			strtol(s, 0, 0)
326#define ocs_strcmp(d,s)			strcmp(d,s)
327#define ocs_strcasecmp(d,s)		strcasecmp(d,s)
328#define ocs_strncmp(d,s,n)		strncmp(d,s,n)
329#define ocs_strstr(h,n)			strstr(h,n)
330#define ocs_strsep(h, n)		strsep(h, n)
331#define ocs_strchr(s,c)			strchr(s,c)
332#define ocs_copy_from_user(dst, src, n)	copyin(src, dst, n)
333#define ocs_copy_to_user(dst, src, n)	copyout(src, dst, n)
334#define ocs_snprintf(buf, n, fmt, ...)	snprintf(buf, n, fmt, ##__VA_ARGS__)
335#define ocs_vsnprintf(buf, n, fmt, ap)	vsnprintf((char*)buf, n, fmt, ap)
336#define ocs_sscanf(buf,fmt, ...)	sscanf(buf, fmt, ##__VA_ARGS__)
337#define ocs_printf			printf
338#define ocs_isspace(c)			isspace(c)
339#define ocs_isdigit(c)			isdigit(c)
340#define ocs_isxdigit(c)			isxdigit(c)
341
342extern uint64_t ocs_get_tsc(void);
343extern void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size);
344extern int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size);
345extern void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size);
346extern char *ocs_strdup(const char *s);
347
348/**
349 * @ingroup os
350 * @brief Set the value of each byte in memory
351 *
352 * @param b pointer to the memory
353 * @param c value used to set memory
354 * @param l number of bytes to set
355 *
356 * @return original value of mem pointer
357 */
358#define ocs_memset(b, c, l) memset(b, c, l)
359
360#define LOG_CRIT	0
361#define LOG_ERR		1
362#define LOG_WARN	2
363#define LOG_INFO	3
364#define LOG_TEST	4
365#define LOG_DEBUG	5
366
367extern int loglevel;
368
369extern void _ocs_log(ocs_t *ocs, const char *func, int line, const char *fmt, ...);
370
371#define ocs_log_crit(os, fmt, ...)	ocs_log(os, LOG_CRIT, fmt, ##__VA_ARGS__);
372#define ocs_log_err(os, fmt, ...)	ocs_log(os, LOG_ERR, fmt, ##__VA_ARGS__);
373#define ocs_log_warn(os, fmt, ...)	ocs_log(os, LOG_WARN, fmt, ##__VA_ARGS__);
374#define ocs_log_info(os, fmt, ...)	ocs_log(os, LOG_INFO, fmt, ##__VA_ARGS__);
375#define ocs_log_test(os, fmt, ...)	ocs_log(os, LOG_TEST, fmt, ##__VA_ARGS__);
376#define ocs_log_debug(os, fmt, ...)	ocs_log(os, LOG_DEBUG, fmt, ##__VA_ARGS__);
377
378#define ocs_log(os, level, fmt, ...)                    \
379	do {                                            \
380		if (level <= loglevel) {                \
381			_ocs_log(os, __func__, __LINE__, fmt, ##__VA_ARGS__);   \
382		}                                       \
383	} while (0)
384
385static inline uint32_t ocs_roundup(uint32_t x, uint32_t y)
386{
387	return (((x + y - 1) / y) * y);
388}
389
390static inline uint32_t ocs_rounddown(uint32_t x, uint32_t y)
391{
392	return ((x / y) * y);
393}
394
395/***************************************************************************
396 * Memory allocation interfaces
397 */
398
399#define OCS_M_ZERO	M_ZERO
400#define OCS_M_NOWAIT	M_NOWAIT
401
402/**
403 * @ingroup os
404 * @brief Allocate host memory
405 *
406 * @param os OS handle
407 * @param size number of bytes to allocate
408 * @param flags additional options
409 *
410 * Flags include
411 *  - OCS_M_ZERO zero memory after allocating
412 *  - OCS_M_NOWAIT do not block/sleep waiting for an allocation request
413 *
414 * @return pointer to allocated memory, NULL otherwise
415 */
416extern void *ocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags);
417
418/**
419 * @ingroup os
420 * @brief Free host memory
421 *
422 * @param os OS handle
423 * @param addr pointer to memory
424 * @param size bytes to free
425 */
426extern void ocs_free(ocs_os_handle_t os, void *addr, size_t size);
427
428/**
429 * @ingroup os
430 * @brief generic DMA memory descriptor for driver allocations
431 *
432 * Memory regions ultimately used by the hardware are described using
433 * this structure. All implementations must include the structure members
434 * defined in the first section, and they may also add their own structure
435 * members in the second section.
436 *
437 * Note that each region described by ocs_dma_s is assumed to be physically
438 * contiguous.
439 */
440typedef struct ocs_dma_s {
441	/*
442	 * OCS layer requires the following members
443	 */
444	void		*virt;	/**< virtual address of the memory used by the CPU */
445	void		*alloc;	/**< originally allocated virtual address used to restore virt if modified */
446	uintptr_t	phys;	/**< physical or bus address of the memory used by the hardware */
447	size_t		size;	/**< size in bytes of the memory */
448	/*
449	 * Implementation specific fields allowed here
450	 */
451	size_t		len;	/**< application specific length */
452	bus_dma_tag_t	tag;
453	bus_dmamap_t	map;
454} ocs_dma_t;
455
456/**
457 * @ingroup os
458 * @brief Returns maximum supported DMA allocation size
459 *
460 * @param os OS specific handle or driver context
461 * @param align alignment requirement for DMA allocation
462 *
463 * Return maximum supported DMA allocation size, given alignment
464 * requirement.
465 *
466 * @return maximum supported DMA allocation size
467 */
468static inline uint32_t ocs_max_dma_alloc(ocs_os_handle_t os, size_t align)
469{
470	return ~((uint32_t)0); /* no max */
471}
472
473/**
474 * @ingroup os
475 * @brief Allocate a DMA capable block of memory
476 *
477 * @param os OS specific handle or driver context
478 * @param dma DMA descriptor containing results of memory allocation
479 * @param size Size in bytes of desired allocation
480 * @param align Alignment in bytes of the requested allocation
481 *
482 * @return 0 on success, non-zero otherwise
483 */
484extern int32_t ocs_dma_alloc(ocs_os_handle_t, ocs_dma_t *, size_t, size_t);
485
486/**
487 * @ingroup os
488 * @brief Free a DMA capable block of memory
489 *
490 * @param os OS specific handle or driver context
491 * @param dma DMA descriptor for memory to be freed
492 *
493 * @return 0 if memory is de-allocated, non-zero otherwise
494 */
495extern int32_t ocs_dma_free(ocs_os_handle_t, ocs_dma_t *);
496extern int32_t ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
497extern int32_t ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length);
498
499static inline int32_t ocs_dma_valid(ocs_dma_t *dma)
500{
501	return (dma->size != 0);
502}
503
504/**
505 * @ingroup os
506 * @brief Synchronize the DMA buffer memory
507 *
508 * Ensures memory coherency between the CPU and device
509 *
510 * @param dma DMA descriptor of memory to synchronize
511 * @param flags Describes direction of synchronization
512 *   - OCS_DMASYNC_PREREAD sync needed before hardware updates host memory
513 *   - OCS_DMASYNC_PREWRITE sync needed after CPU updates host memory but before hardware can access
514 *   - OCS_DMASYNC_POSTREAD sync needed after hardware updates host memory but before CPU can access
515 *   - OCS_DMASYNC_POSTWRITE sync needed after hardware updates host memory
516 */
517extern void ocs_dma_sync(ocs_dma_t *, uint32_t);
518
519#define OCS_DMASYNC_PREWRITE BUS_DMASYNC_PREWRITE
520#define OCS_DMASYNC_POSTREAD BUS_DMASYNC_POSTREAD
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
998extern int32_t ocs_thread_create(ocs_os_handle_t os, ocs_thread_t *thread, ocs_thread_fctn fctn,
999				 const char *name, void *arg, ocs_thread_start_e start_option);
1000extern int32_t ocs_thread_start(ocs_thread_t *thread);
1001extern void *ocs_thread_get_arg(ocs_thread_t *mythread);
1002extern int32_t ocs_thread_terminate(ocs_thread_t *thread);
1003extern int32_t ocs_thread_terminate_requested(ocs_thread_t *thread);
1004extern int32_t ocs_thread_get_retval(ocs_thread_t *thread);
1005extern void ocs_thread_yield(ocs_thread_t *thread);
1006extern ocs_thread_t *ocs_thread_self(void);
1007extern int32_t ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu);
1008extern int32_t ocs_thread_getcpu(void);
1009
1010/***************************************************************************
1011 * PCI
1012 *
1013 * Several functions below refer to a "register set". This is one or
1014 * more PCI BARs that constitute a PCI address. For example, if a MMIO
1015 * region is described using both BAR[0] and BAR[1], the combination of
1016 * BARs defines register set 0.
1017 */
1018
1019/**
1020 * @brief tracks mapped PCI memory regions
1021 */
1022typedef struct ocs_pci_reg_s {
1023	uint32_t		rid;
1024	struct resource		*res;
1025	bus_space_tag_t		btag;
1026	bus_space_handle_t	bhandle;
1027} ocs_pci_reg_t;
1028
1029#define PCI_MAX_BAR				6
1030#define PCI_64BIT_BAR0				0
1031
1032#define PCI_VENDOR_EMULEX			0x10df	/* Emulex */
1033
1034#define PCI_PRODUCT_EMULEX_OCE16001		0xe200	/* OneCore 16Gb FC (lancer) */
1035#define PCI_PRODUCT_EMULEX_OCE16002		0xe200	/* OneCore 16Gb FC (lancer) */
1036#define PCI_PRODUCT_EMULEX_LPE31004		0xe300  /* LightPulse 16Gb x 4 FC (lancer-g6) */
1037#define PCI_PRODUCT_EMULEX_LPE32002		0xe300  /* LightPulse 32Gb x 2 FC (lancer-g6) */
1038#define PCI_PRODUCT_EMULEX_LANCER_G7		0xf400	/* LightPulse 32Gb x 4 FC (lancer-g7) */
1039
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 */
1054extern void
1055ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
1056
1057extern ocs_t *ocs_get_instance(uint32_t index);
1058extern uint32_t ocs_instance(void *os);
1059
1060/**
1061 * @ingroup os
1062 * @brief Read a 32 bit value from the specified configuration register
1063 *
1064 * @param os OS specific handle or driver context
1065 * @param reg register offset
1066 *
1067 * @return The 32 bit value
1068 */
1069extern uint32_t ocs_config_read32(ocs_os_handle_t os, uint32_t reg);
1070
1071/**
1072 * @ingroup os
1073 * @brief Read a 16 bit value from the specified configuration
1074 *        register
1075 *
1076 * @param os OS specific handle or driver context
1077 * @param reg register offset
1078 *
1079 * @return The 16 bit value
1080 */
1081extern uint16_t ocs_config_read16(ocs_os_handle_t os, uint32_t reg);
1082
1083/**
1084 * @ingroup os
1085 * @brief Read a 8 bit value from the specified configuration
1086 *        register
1087 *
1088 * @param os OS specific handle or driver context
1089 * @param reg register offset
1090 *
1091 * @return The 8 bit value
1092 */
1093extern uint8_t ocs_config_read8(ocs_os_handle_t os, uint32_t reg);
1094
1095/**
1096 * @ingroup os
1097 * @brief Write a 8 bit value to the specified configuration
1098 *        register
1099 *
1100 * @param os OS specific handle or driver context
1101 * @param reg register offset
1102 * @param val value to write
1103 *
1104 * @return None
1105 */
1106extern void ocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val);
1107
1108/**
1109 * @ingroup os
1110 * @brief Write a 16 bit value to the specified configuration
1111 *        register
1112 *
1113 * @param os OS specific handle or driver context
1114 * @param reg register offset
1115 * @param val value to write
1116 *
1117 * @return None
1118 */
1119extern void ocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val);
1120
1121/**
1122 * @ingroup os
1123 * @brief Write a 32 bit value to the specified configuration
1124 *        register
1125 *
1126 * @param os OS specific handle or driver context
1127 * @param reg register offset
1128 * @param val value to write
1129 *
1130 * @return None
1131 */
1132extern void ocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val);
1133
1134/**
1135 * @ingroup os
1136 * @brief Read a PCI register
1137 *
1138 * @param os OS specific handle or driver context
1139 * @param rset Which "register set" to use
1140 * @param off  Register offset
1141 *
1142 * @return 32 bit conents of the register
1143 */
1144extern uint32_t ocs_reg_read32(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1145
1146/**
1147 * @ingroup os
1148 * @brief Read a PCI register
1149 *
1150 * @param os OS specific handle or driver context
1151 * @param rset Which "register set" to use
1152 * @param off  Register offset
1153 *
1154 * @return 16 bit conents of the register
1155 */
1156extern uint16_t ocs_reg_read16(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1157
1158/**
1159 * @ingroup os
1160 * @brief Read a PCI register
1161 *
1162 * @param os OS specific handle or driver context
1163 * @param rset Which "register set" to use
1164 * @param off  Register offset
1165 *
1166 * @return 8 bit conents of the register
1167 */
1168extern uint8_t ocs_reg_read8(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1169
1170/**
1171 * @ingroup os
1172 * @brief Write a PCI register
1173 *
1174 * @param os OS specific handle or driver context
1175 * @param rset Which "register set" to use
1176 * @param off  Register offset
1177 * @param val  32-bit value to write
1178 */
1179extern void ocs_reg_write32(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint32_t val);
1180
1181/**
1182 * @ingroup os
1183 * @brief Write a PCI register
1184 *
1185 * @param os OS specific handle or driver context
1186 * @param rset Which "register set" to use
1187 * @param off  Register offset
1188 * @param val  16-bit value to write
1189 */
1190extern void ocs_reg_write16(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint16_t val);
1191
1192/**
1193 * @ingroup os
1194 * @brief Write a PCI register
1195 *
1196 * @param os OS specific handle or driver context
1197 * @param rset Which "register set" to use
1198 * @param off  Register offset
1199 * @param val  8-bit value to write
1200 */
1201extern void ocs_reg_write8(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint8_t val);
1202
1203/**
1204 * @ingroup os
1205 * @brief Disable interrupts
1206 *
1207 * @param os OS specific handle or driver context
1208 */
1209extern void ocs_intr_disable(ocs_os_handle_t os);
1210
1211/**
1212 * @ingroup os
1213 * @brief Enable interrupts
1214 *
1215 * @param os OS specific handle or driver context
1216 */
1217extern void ocs_intr_enable(ocs_os_handle_t os);
1218
1219/**
1220 * @ingroup os
1221 * @brief Return model string
1222 *
1223 * @param os OS specific handle or driver context
1224 */
1225extern const char *ocs_pci_model(uint16_t vendor, uint16_t device);
1226
1227extern void ocs_print_stack(void);
1228
1229extern void ocs_abort(void) __attribute__((noreturn));
1230
1231/***************************************************************************
1232 * Reference counting
1233 *
1234 */
1235
1236/**
1237 * @ingroup os
1238 * @brief reference counter object
1239 */
1240typedef void (*ocs_ref_release_t)(void *arg);
1241typedef struct ocs_ref_s {
1242	ocs_ref_release_t release; /* release function to call */
1243	void *arg;
1244	uint32_t count;		/* ref count; no need to be atomic if we have a lock */
1245} ocs_ref_t;
1246
1247/**
1248 * @ingroup os
1249 * @brief initialize given reference object
1250 *
1251 * @param ref Pointer to reference object
1252 * @param release Function to be called when count is 0.
1253 * @param arg Argument to be passed to release function.
1254 */
1255static inline void
1256ocs_ref_init(ocs_ref_t *ref, ocs_ref_release_t release, void *arg)
1257{
1258	ref->release = release;
1259	ref->arg = arg;
1260	ocs_atomic_init(&ref->count, 1);
1261}
1262
1263/**
1264 * @ingroup os
1265 * @brief Return reference count value
1266 *
1267 * @param ref Pointer to reference object
1268 *
1269 * @return Count value of given reference object
1270 */
1271static inline uint32_t
1272ocs_ref_read_count(ocs_ref_t *ref)
1273{
1274	return ocs_atomic_read(&ref->count);
1275}
1276
1277/**
1278 * @ingroup os
1279 * @brief Set count on given reference object to a value.
1280 *
1281 * @param ref Pointer to reference object
1282 * @param i Set count to this value
1283 */
1284static inline void
1285ocs_ref_set(ocs_ref_t *ref, int i)
1286{
1287	ocs_atomic_set(&ref->count, i);
1288}
1289
1290/**
1291 * @ingroup os
1292 * @brief Take a reference on given object.
1293 *
1294 * @par Description
1295 * This function takes a reference on an object.
1296 *
1297 * Note: this function should only be used if the caller can
1298 * guarantee that the reference count is >= 1 and will stay >= 1
1299 * for the duration of this call (i.e. won't go to zero). If it
1300 * can't (the refcount may go to zero during this call),
1301 * ocs_ref_get_unless_zero() should be used instead.
1302 *
1303 * @param ref Pointer to reference object
1304 *
1305 */
1306static inline void
1307ocs_ref_get(ocs_ref_t *ref)
1308{
1309	ocs_atomic_add_return(&ref->count, 1);
1310}
1311
1312/**
1313 * @ingroup os
1314 * @brief Take a reference on given object if count is not zero.
1315 *
1316 * @par Description
1317 * This function takes a reference on an object if and only if
1318 * the given reference object is "active" or valid.
1319 *
1320 * @param ref Pointer to reference object
1321 *
1322 * @return non-zero if "get" succeeded; Return zero if ref count
1323 * is zero.
1324 */
1325static inline uint32_t
1326ocs_ref_get_unless_zero(ocs_ref_t *ref)
1327{
1328	uint32_t rc = 0;
1329	rc = ocs_atomic_read(&ref->count);
1330		if (rc != 0) {
1331			ocs_atomic_add_return(&ref->count, 1);
1332		}
1333	return rc;
1334}
1335
1336/**
1337 * @ingroup os
1338 * @brief Decrement reference on given object
1339 *
1340 * @par Description
1341 * This function decrements the reference count on the given
1342 * reference object. If the reference count becomes zero, the
1343 * "release" function (set during "init" time) is called.
1344 *
1345 * @param ref Pointer to reference object
1346 *
1347 * @return non-zero if release function was called; zero
1348 * otherwise.
1349 */
1350static inline uint32_t
1351ocs_ref_put(ocs_ref_t *ref)
1352{
1353	uint32_t rc = 0;
1354	if (ocs_atomic_sub_return(&ref->count, 1) == 1) {
1355		ref->release(ref->arg);
1356		rc = 1;
1357	}
1358	return rc;
1359}
1360
1361/**
1362 * @ingroup os
1363 * @brief Get the OS system ticks
1364 *
1365 * @return number of ticks that have occurred since the system
1366 * booted.
1367 */
1368static inline uint64_t
1369ocs_get_os_ticks(void)
1370{
1371	return ticks;
1372}
1373
1374/**
1375 * @ingroup os
1376 * @brief Get the OS system tick frequency
1377 *
1378 * @return frequency of system ticks.
1379 */
1380static inline uint32_t
1381ocs_get_os_tick_freq(void)
1382{
1383	return hz;
1384}
1385
1386/*****************************************************************************
1387 *
1388 * CPU topology API
1389 */
1390
1391typedef struct {
1392	uint32_t num_cpus;	/* Number of CPU cores */
1393	uint8_t hyper;		/* TRUE if threaded CPUs */
1394} ocs_cpuinfo_t;
1395
1396extern int32_t ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo);
1397extern uint32_t ocs_get_num_cpus(void);
1398
1399#include "ocs_list.h"
1400#include "ocs_utils.h"
1401#include "ocs_mgmt.h"
1402#include "ocs_common.h"
1403
1404#endif /* !_OCS_OS_H */
1405