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