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) /* 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
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 maxiumum 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_OCE1600_VF 0xe208
1041 #define PCI_PRODUCT_EMULEX_OCE50102 0xe260 /* OneCore FCoE (lancer) */
1042 #define PCI_PRODUCT_EMULEX_OCE50102_VF 0xe268
1043
1044 /**
1045 * @ingroup os
1046 * @brief Get the PCI bus, device, and function values
1047 *
1048 * @param ocs OS specific handle or driver context
1049 * @param bus Pointer to location to store the bus number.
1050 * @param dev Pointer to location to store the device number.
1051 * @param func Pointer to location to store the function number.
1052 *
1053 * @return Returns 0.
1054 */
1055 extern int32_t
1056 ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func);
1057
1058 extern ocs_t *ocs_get_instance(uint32_t index);
1059 extern uint32_t ocs_instance(void *os);
1060
1061 /**
1062 * @ingroup os
1063 * @brief Read a 32 bit value from the specified configuration register
1064 *
1065 * @param os OS specific handle or driver context
1066 * @param reg register offset
1067 *
1068 * @return The 32 bit value
1069 */
1070 extern uint32_t ocs_config_read32(ocs_os_handle_t os, uint32_t reg);
1071
1072 /**
1073 * @ingroup os
1074 * @brief Read a 16 bit value from the specified configuration
1075 * register
1076 *
1077 * @param os OS specific handle or driver context
1078 * @param reg register offset
1079 *
1080 * @return The 16 bit value
1081 */
1082 extern uint16_t ocs_config_read16(ocs_os_handle_t os, uint32_t reg);
1083
1084 /**
1085 * @ingroup os
1086 * @brief Read a 8 bit value from the specified configuration
1087 * register
1088 *
1089 * @param os OS specific handle or driver context
1090 * @param reg register offset
1091 *
1092 * @return The 8 bit value
1093 */
1094 extern uint8_t ocs_config_read8(ocs_os_handle_t os, uint32_t reg);
1095
1096 /**
1097 * @ingroup os
1098 * @brief Write a 8 bit value to the specified configuration
1099 * register
1100 *
1101 * @param os OS specific handle or driver context
1102 * @param reg register offset
1103 * @param val value to write
1104 *
1105 * @return None
1106 */
1107 extern void ocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val);
1108
1109 /**
1110 * @ingroup os
1111 * @brief Write a 16 bit value to the specified configuration
1112 * register
1113 *
1114 * @param os OS specific handle or driver context
1115 * @param reg register offset
1116 * @param val value to write
1117 *
1118 * @return None
1119 */
1120 extern void ocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val);
1121
1122 /**
1123 * @ingroup os
1124 * @brief Write a 32 bit value to the specified configuration
1125 * register
1126 *
1127 * @param os OS specific handle or driver context
1128 * @param reg register offset
1129 * @param val value to write
1130 *
1131 * @return None
1132 */
1133 extern void ocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val);
1134
1135 /**
1136 * @ingroup os
1137 * @brief Read a PCI register
1138 *
1139 * @param os OS specific handle or driver context
1140 * @param rset Which "register set" to use
1141 * @param off Register offset
1142 *
1143 * @return 32 bit conents of the register
1144 */
1145 extern uint32_t ocs_reg_read32(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1146
1147 /**
1148 * @ingroup os
1149 * @brief Read a PCI register
1150 *
1151 * @param os OS specific handle or driver context
1152 * @param rset Which "register set" to use
1153 * @param off Register offset
1154 *
1155 * @return 16 bit conents of the register
1156 */
1157 extern uint16_t ocs_reg_read16(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1158
1159 /**
1160 * @ingroup os
1161 * @brief Read a PCI register
1162 *
1163 * @param os OS specific handle or driver context
1164 * @param rset Which "register set" to use
1165 * @param off Register offset
1166 *
1167 * @return 8 bit conents of the register
1168 */
1169 extern uint8_t ocs_reg_read8(ocs_os_handle_t os, uint32_t rset, uint32_t off);
1170
1171 /**
1172 * @ingroup os
1173 * @brief Write a PCI register
1174 *
1175 * @param os OS specific handle or driver context
1176 * @param rset Which "register set" to use
1177 * @param off Register offset
1178 * @param val 32-bit value to write
1179 */
1180 extern void ocs_reg_write32(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint32_t val);
1181
1182 /**
1183 * @ingroup os
1184 * @brief Write a PCI register
1185 *
1186 * @param os OS specific handle or driver context
1187 * @param rset Which "register set" to use
1188 * @param off Register offset
1189 * @param val 16-bit value to write
1190 */
1191 extern void ocs_reg_write16(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint16_t val);
1192
1193 /**
1194 * @ingroup os
1195 * @brief Write a PCI register
1196 *
1197 * @param os OS specific handle or driver context
1198 * @param rset Which "register set" to use
1199 * @param off Register offset
1200 * @param val 8-bit value to write
1201 */
1202 extern void ocs_reg_write8(ocs_os_handle_t os, uint32_t rset, uint32_t off, uint8_t val);
1203
1204 /**
1205 * @ingroup os
1206 * @brief Disable interrupts
1207 *
1208 * @param os OS specific handle or driver context
1209 */
1210 extern void ocs_intr_disable(ocs_os_handle_t os);
1211
1212 /**
1213 * @ingroup os
1214 * @brief Enable interrupts
1215 *
1216 * @param os OS specific handle or driver context
1217 */
1218 extern void ocs_intr_enable(ocs_os_handle_t os);
1219
1220 /**
1221 * @ingroup os
1222 * @brief Return model string
1223 *
1224 * @param os OS specific handle or driver context
1225 */
1226 extern const char *ocs_pci_model(uint16_t vendor, uint16_t device);
1227
1228 extern void ocs_print_stack(void);
1229
1230 extern void ocs_abort(void) __attribute__((noreturn));
1231
1232 /***************************************************************************
1233 * Reference counting
1234 *
1235 */
1236
1237 /**
1238 * @ingroup os
1239 * @brief reference counter object
1240 */
1241 typedef void (*ocs_ref_release_t)(void *arg);
1242 typedef struct ocs_ref_s {
1243 ocs_ref_release_t release; /* release function to call */
1244 void *arg;
1245 uint32_t count; /* ref count; no need to be atomic if we have a lock */
1246 } ocs_ref_t;
1247
1248 /**
1249 * @ingroup os
1250 * @brief initialize given reference object
1251 *
1252 * @param ref Pointer to reference object
1253 * @param release Function to be called when count is 0.
1254 * @param arg Argument to be passed to release function.
1255 */
1256 static inline void
1257 ocs_ref_init(ocs_ref_t *ref, ocs_ref_release_t release, void *arg)
1258 {
1259 ref->release = release;
1260 ref->arg = arg;
1261 ocs_atomic_init(&ref->count, 1);
1262 }
1263
1264 /**
1265 * @ingroup os
1266 * @brief Return reference count value
1267 *
1268 * @param ref Pointer to reference object
1269 *
1270 * @return Count value of given reference object
1271 */
1272 static inline uint32_t
1273 ocs_ref_read_count(ocs_ref_t *ref)
1274 {
1275 return ocs_atomic_read(&ref->count);
1276 }
1277
1278 /**
1279 * @ingroup os
1280 * @brief Set count on given reference object to a value.
1281 *
1282 * @param ref Pointer to reference object
1283 * @param i Set count to this value
1284 */
1285 static inline void
1286 ocs_ref_set(ocs_ref_t *ref, int i)
1287 {
1288 ocs_atomic_set(&ref->count, i);
1289 }
1290
1291 /**
1292 * @ingroup os
1293 * @brief Take a reference on given object.
1294 *
1295 * @par Description
1296 * This function takes a reference on an object.
1297 *
1298 * Note: this function should only be used if the caller can
1299 * guarantee that the reference count is >= 1 and will stay >= 1
1300 * for the duration of this call (i.e. won't go to zero). If it
1301 * can't (the refcount may go to zero during this call),
1302 * ocs_ref_get_unless_zero() should be used instead.
1303 *
1304 * @param ref Pointer to reference object
1305 *
1306 */
1307 static inline void
1308 ocs_ref_get(ocs_ref_t *ref)
1309 {
1310 ocs_atomic_add_return(&ref->count, 1);
1311 }
1312
1313 /**
1314 * @ingroup os
1315 * @brief Take a reference on given object if count is not zero.
1316 *
1317 * @par Description
1318 * This function takes a reference on an object if and only if
1319 * the given reference object is "active" or valid.
1320 *
1321 * @param ref Pointer to reference object
1322 *
1323 * @return non-zero if "get" succeeded; Return zero if ref count
1324 * is zero.
1325 */
1326 static inline uint32_t
1327 ocs_ref_get_unless_zero(ocs_ref_t *ref)
1328 {
1329 uint32_t rc = 0;
1330 rc = ocs_atomic_read(&ref->count);
1331 if (rc != 0) {
1332 ocs_atomic_add_return(&ref->count, 1);
1333 }
1334 return rc;
1335 }
1336
1337 /**
1338 * @ingroup os
1339 * @brief Decrement reference on given object
1340 *
1341 * @par Description
1342 * This function decrements the reference count on the given
1343 * reference object. If the reference count becomes zero, the
1344 * "release" function (set during "init" time) is called.
1345 *
1346 * @param ref Pointer to reference object
1347 *
1348 * @return non-zero if release function was called; zero
1349 * otherwise.
1350 */
1351 static inline uint32_t
1352 ocs_ref_put(ocs_ref_t *ref)
1353 {
1354 uint32_t rc = 0;
1355 if (ocs_atomic_sub_return(&ref->count, 1) == 1) {
1356 ref->release(ref->arg);
1357 rc = 1;
1358 }
1359 return rc;
1360 }
1361
1362 /**
1363 * @ingroup os
1364 * @brief Get the OS system ticks
1365 *
1366 * @return number of ticks that have occurred since the system
1367 * booted.
1368 */
1369 static inline uint64_t
1370 ocs_get_os_ticks(void)
1371 {
1372 return ticks;
1373 }
1374
1375 /**
1376 * @ingroup os
1377 * @brief Get the OS system tick frequency
1378 *
1379 * @return frequency of system ticks.
1380 */
1381 static inline uint32_t
1382 ocs_get_os_tick_freq(void)
1383 {
1384 return hz;
1385 }
1386
1387 /*****************************************************************************
1388 *
1389 * CPU topology API
1390 */
1391
1392 typedef struct {
1393 uint32_t num_cpus; /* Number of CPU cores */
1394 uint8_t hyper; /* TRUE if threaded CPUs */
1395 } ocs_cpuinfo_t;
1396
1397 extern int32_t ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo);
1398 extern uint32_t ocs_get_num_cpus(void);
1399
1400 #include "ocs_list.h"
1401 #include "ocs_utils.h"
1402 #include "ocs_mgmt.h"
1403 #include "ocs_common.h"
1404
1405 #endif /* !_OCS_OS_H */
Cache object: 4052fab323a0eb5e2c2bba3c1dc78a3e
|