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