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