ocs_os.h revision 331766
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: head/sys/dev/ocs_fc/ocs_os.h 331766 2018-03-30 15:28:25Z ken $ 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 42typedef struct ocs_softc ocs_t; 43 44/*************************************************************************** 45 * OS specific includes 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/* 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) /* maxium 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/** 156 * @ingroup os 157 * @typedef ocs_os_handle_t 158 * @brief OS specific handle or driver context 159 * 160 * This can be anything from a void * to some other OS specific type. The lower 161 * layers make no assumption about its value and pass it back as the first 162 * parameter to most OS functions. 163 */ 164typedef ocs_t * ocs_os_handle_t; 165 166/** 167 * @ingroup os 168 * @brief return the lower 32-bits of a bus address 169 * 170 * @param addr Physical or bus address to convert 171 * @return lower 32-bits of a bus address 172 * 173 * @note this may be a good cadidate for an inline or macro 174 */ 175static inline uint32_t ocs_addr32_lo(uintptr_t addr) 176{ 177#if defined(__LP64__) 178 return (uint32_t)(addr & 0xffffffffUL); 179#else 180 return addr; 181#endif 182} 183 184/** 185 * @ingroup os 186 * @brief return the upper 32-bits of a bus address 187 * 188 * @param addr Physical or bus address to convert 189 * @return upper 32-bits of a bus address 190 * 191 * @note this may be a good cadidate for an inline or macro 192 */ 193static inline uint32_t ocs_addr32_hi(uintptr_t addr) 194{ 195#if defined(__LP64__) 196 return (uint32_t)(addr >> 32); 197#else 198 return 0; 199#endif 200} 201 202/** 203 * @ingroup os 204 * @brief return the log2(val) 205 * 206 * @param val number to use (assumed to be exact power of 2) 207 * 208 * @return log base 2 of val 209 */ 210static inline uint32_t ocs_lg2(uint32_t val) 211{ 212#if defined(__GNUC__) 213 /* 214 * clz = "count leading zero's" 215 * 216 * Assuming val is an exact power of 2, the most significant bit 217 * will be the log base 2 of val 218 */ 219 return 31 - __builtin_clz(val); 220#else 221#error You need to provide a non-GCC version of this function 222#endif 223} 224 225/** 226 * @ingroup os 227 * @brief optimization barrier 228 * 229 * Optimization barrier. Prevents compiler re-ordering 230 * instructions across barrier. 231 * 232 * @return none 233 */ 234#define ocs_barrier() __asm __volatile("" : : : "memory"); 235 236/** 237 * @ingroup os 238 * @brief convert a big endian 32 bit value to the host's native format 239 * 240 * @param val 32 bit big endian value 241 * 242 * @return value converted to the host's native endianness 243 */ 244#define ocs_be32toh(val) be32toh(val) 245 246/** 247 * @ingroup os 248 * @brief convert a 32 bit value from the host's native format to big endian 249 * 250 * @param val 32 bit native endian value 251 * 252 * @return value converted to big endian 253 */ 254#define ocs_htobe32(val) htobe32(val) 255 256/** 257 * @ingroup os 258 * @brief convert a 16 bit value from the host's native format to big endian 259 * 260 * @param v 16 bit native endian value 261 * 262 * @return value converted to big endian 263 */ 264#define ocs_htobe16(v) htobe16(v) 265#define ocs_be16toh(v) be16toh(v) 266 267 268#define ocs_htobe64(v) htobe64(v) 269#define ocs_be64toh(v) be64toh(v) 270 271/** 272 * @ingroup os 273 * @brief Delay execution by the given number of micro-seconds 274 * 275 * @param usec number of micro-seconds to "busy-wait" 276 * 277 * @note The value of usec may be greater than 1,000,000 278 */ 279#define ocs_udelay(usec) DELAY(usec) 280 281/** 282 * @ingroup os 283 * @brief Delay execution by the given number of milli-seconds 284 * 285 * @param msec number of milli-seconds to "busy-wait" 286 * 287 * @note The value of usec may be greater than 1,000,000 288 */ 289#define ocs_msleep(msec) ocs_udelay((msec)*1000) 290 291/** 292 * @ingroup os 293 * @brief Get time of day in msec 294 * 295 * @return time of day in msec 296 */ 297static inline time_t 298ocs_msectime(void) 299{ 300 struct timeval tv; 301 302 getmicrotime(&tv); 303 return (tv.tv_sec*1000) + (tv.tv_usec / 1000); 304} 305 306/** 307 * @ingroup os 308 * @brief Copy length number of bytes from the source to destination address 309 * 310 * @param d pointer to the destination memory 311 * @param s pointer to the source memory 312 * @param l number of bytes to copy 313 * 314 * @return original value of dst pointer 315 */ 316#define ocs_memcpy(d, s, l) memcpy(d, s, l) 317 318#define ocs_strlen(s) strlen(s) 319#define ocs_strcpy(d,s) strcpy(d, s) 320#define ocs_strncpy(d,s, n) strncpy(d, s, n) 321#define ocs_strcat(d, s) strcat(d, s) 322#define ocs_strtoul(s,ep,b) strtoul(s,ep,b) 323#define ocs_strtoull(s,ep,b) ((uint64_t)strtouq(s,ep,b)) 324#define ocs_atoi(s) strtol(s, 0, 0) 325#define ocs_strcmp(d,s) strcmp(d,s) 326#define ocs_strcasecmp(d,s) strcasecmp(d,s) 327#define ocs_strncmp(d,s,n) strncmp(d,s,n) 328#define ocs_strstr(h,n) strstr(h,n) 329#define ocs_strsep(h, n) strsep(h, n) 330#define ocs_strchr(s,c) strchr(s,c) 331#define ocs_copy_from_user(dst, src, n) copyin(src, dst, n) 332#define ocs_copy_to_user(dst, src, n) copyout(src, dst, n) 333#define ocs_snprintf(buf, n, fmt, ...) snprintf(buf, n, fmt, ##__VA_ARGS__) 334#define ocs_vsnprintf(buf, n, fmt, ap) vsnprintf((char*)buf, n, fmt, ap) 335#define ocs_sscanf(buf,fmt, ...) sscanf(buf, fmt, ##__VA_ARGS__) 336#define ocs_printf printf 337#define ocs_isspace(c) isspace(c) 338#define ocs_isdigit(c) isdigit(c) 339#define ocs_isxdigit(c) isxdigit(c) 340 341extern uint64_t ocs_get_tsc(void); 342extern void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size); 343extern int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size); 344extern void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size); 345extern char *ocs_strdup(const char *s); 346 347/** 348 * @ingroup os 349 * @brief Set the value of each byte in memory 350 * 351 * @param b pointer to the memory 352 * @param c value used to set memory 353 * @param l number of bytes to set 354 * 355 * @return original value of mem pointer 356 */ 357#define ocs_memset(b, c, l) memset(b, c, l) 358 359#define LOG_CRIT 0 360#define LOG_ERR 1 361#define LOG_WARN 2 362#define LOG_INFO 3 363#define LOG_TEST 4 364#define LOG_DEBUG 5 365 366extern int loglevel; 367 368extern void _ocs_log(ocs_t *ocs, const char *func, int line, const char *fmt, ...); 369 370#define ocs_log_crit(os, fmt, ...) ocs_log(os, LOG_CRIT, fmt, ##__VA_ARGS__); 371#define ocs_log_err(os, fmt, ...) ocs_log(os, LOG_ERR, fmt, ##__VA_ARGS__); 372#define ocs_log_warn(os, fmt, ...) ocs_log(os, LOG_WARN, fmt, ##__VA_ARGS__); 373#define ocs_log_info(os, fmt, ...) ocs_log(os, LOG_INFO, fmt, ##__VA_ARGS__); 374#define ocs_log_test(os, fmt, ...) ocs_log(os, LOG_TEST, fmt, ##__VA_ARGS__); 375#define ocs_log_debug(os, fmt, ...) ocs_log(os, LOG_DEBUG, fmt, ##__VA_ARGS__); 376 377#define ocs_log(os, level, fmt, ...) \ 378 do { \ 379 if (level <= loglevel) { \ 380 _ocs_log(os, __func__, __LINE__, fmt, ##__VA_ARGS__); \ 381 } \ 382 } while (0) 383 384static inline uint32_t ocs_roundup(uint32_t x, uint32_t y) 385{ 386 return (((x + y - 1) / y) * y); 387} 388 389static inline uint32_t ocs_rounddown(uint32_t x, uint32_t y) 390{ 391 return ((x / y) * y); 392} 393 394/*************************************************************************** 395 * Memory allocation interfaces 396 */ 397 398#define OCS_M_ZERO M_ZERO 399#define OCS_M_NOWAIT M_NOWAIT 400 401/** 402 * @ingroup os 403 * @brief Allocate host memory 404 * 405 * @param os OS handle 406 * @param size number of bytes to allocate 407 * @param flags additional options 408 * 409 * Flags include 410 * - OCS_M_ZERO zero memory after allocating 411 * - OCS_M_NOWAIT do not block/sleep waiting for an allocation request 412 * 413 * @return pointer to allocated memory, NULL otherwise 414 */ 415extern void *ocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags); 416 417/** 418 * @ingroup os 419 * @brief Free host memory 420 * 421 * @param os OS handle 422 * @param addr pointer to memory 423 * @param size bytes to free 424 */ 425extern void ocs_free(ocs_os_handle_t os, void *addr, size_t size); 426 427/** 428 * @ingroup os 429 * @brief generic DMA memory descriptor for driver allocations 430 * 431 * Memory regions ultimately used by the hardware are described using 432 * this structure. All implementations must include the structure members 433 * defined in the first section, and they may also add their own structure 434 * members in the second section. 435 * 436 * Note that each region described by ocs_dma_s is assumed to be physically 437 * contiguous. 438 */ 439typedef struct ocs_dma_s { 440 /* 441 * OCS layer requires the following members 442 */ 443 void *virt; /**< virtual address of the memory used by the CPU */ 444 void *alloc; /**< originally allocated virtual address used to restore virt if modified */ 445 uintptr_t phys; /**< physical or bus address of the memory used by the hardware */ 446 size_t size; /**< size in bytes of the memory */ 447 /* 448 * Implementation specific fields allowed here 449 */ 450 size_t len; /**< application specific length */ 451 bus_dma_tag_t tag; 452 bus_dmamap_t map; 453} ocs_dma_t; 454 455/** 456 * @ingroup os 457 * @brief Returns maximum supported DMA allocation size 458 * 459 * @param os OS specific handle or driver context 460 * @param align alignment requirement for DMA allocation 461 * 462 * Return maximum supported DMA allocation size, given alignment 463 * requirement. 464 * 465 * @return maxiumum supported DMA allocation size 466 */ 467static inline uint32_t ocs_max_dma_alloc(ocs_os_handle_t os, size_t align) 468{ 469 return ~((uint32_t)0); /* no max */ 470} 471 472/** 473 * @ingroup os 474 * @brief Allocate a DMA capable block of memory 475 * 476 * @param os OS specific handle or driver context 477 * @param dma DMA descriptor containing results of memory allocation 478 * @param size Size in bytes of desired allocation 479 * @param align Alignment in bytes of the requested allocation 480 * 481 * @return 0 on success, non-zero otherwise 482 */ 483extern int32_t ocs_dma_alloc(ocs_os_handle_t, ocs_dma_t *, size_t, size_t); 484 485/** 486 * @ingroup os 487 * @brief Free a DMA capable block of memory 488 * 489 * @param os OS specific handle or driver context 490 * @param dma DMA descriptor for memory to be freed 491 * 492 * @return 0 if memory is de-allocated, non-zero otherwise 493 */ 494extern int32_t ocs_dma_free(ocs_os_handle_t, ocs_dma_t *); 495extern int32_t ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length); 496extern int32_t ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length); 497 498static inline int32_t ocs_dma_valid(ocs_dma_t *dma) 499{ 500 return (dma->size != 0); 501} 502 503/** 504 * @ingroup os 505 * @brief Synchronize the DMA buffer memory 506 * 507 * Ensures memory coherency between the CPU and device 508 * 509 * @param dma DMA descriptor of memory to synchronize 510 * @param flags Describes direction of synchronization 511 * - OCS_DMASYNC_PREREAD sync needed before hardware updates host memory 512 * - OCS_DMASYNC_PREWRITE sync needed after CPU updates host memory but before hardware can access 513 * - OCS_DMASYNC_POSTREAD sync needed after hardware updates host memory but before CPU can access 514 * - OCS_DMASYNC_POSTWRITE sync needed after hardware updates host memory 515 */ 516extern void ocs_dma_sync(ocs_dma_t *, uint32_t); 517 518#define OCS_DMASYNC_PREWRITE BUS_DMASYNC_PREWRITE 519#define OCS_DMASYNC_POSTREAD BUS_DMASYNC_POSTREAD 520 521 522/*************************************************************************** 523 * Locking 524 */ 525 526/** 527 * @ingroup os 528 * @typedef ocs_lock_t 529 * @brief Define the type used implement locking 530 */ 531#define MAX_LOCK_DESC_LEN 64 532typedef struct ocs_lock_s { 533 struct mtx lock; 534 char name[MAX_LOCK_DESC_LEN]; 535} ocs_lock_t; 536 537/** 538 * @ingroup os 539 * @brief Initialize a lock 540 * 541 * @param lock lock to initialize 542 * @param name string identifier for the lock 543 */ 544extern void ocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...); 545 546/** 547 * @ingroup os 548 * @brief Free a previously allocated lock 549 * 550 * @param lock lock to free 551 */ 552static inline void 553ocs_lock_free(ocs_lock_t *lock) 554{ 555 556 if (mtx_initialized(&(lock)->lock)) { 557 mtx_assert(&(lock)->lock, MA_NOTOWNED); 558 mtx_destroy(&(lock)->lock); 559 } else { 560 panic("XXX trying to free with un-initialized mtx!?!?\n"); 561 } 562} 563 564/** 565 * @ingroup os 566 * @brief Acquire a lock 567 * 568 * @param lock lock to obtain 569 */ 570static inline void 571ocs_lock(ocs_lock_t *lock) 572{ 573 574 if (mtx_initialized(&(lock)->lock)) { 575 mtx_assert(&(lock)->lock, MA_NOTOWNED); 576 mtx_lock(&(lock)->lock); 577 } else { 578 panic("XXX trying to lock with un-initialized mtx!?!?\n"); 579 } 580} 581 582/** 583 * @ingroup os 584 * @brief Release a lock 585 * 586 * @param lock lock to release 587 */ 588static inline void 589ocs_unlock(ocs_lock_t *lock) 590{ 591 592 if (mtx_initialized(&(lock)->lock)) { 593 mtx_assert(&(lock)->lock, MA_OWNED | MA_NOTRECURSED); 594 mtx_unlock(&(lock)->lock); 595 } else { 596 panic("XXX trying to unlock with un-initialized mtx!?!?\n"); 597 } 598} 599 600/** 601 * @ingroup os 602 * @typedef ocs_lock_t 603 * @brief Define the type used implement recursive locking 604 */ 605typedef struct ocs_lock_s ocs_rlock_t; 606 607/** 608 * @ingroup os 609 * @brief Initialize a recursive lock 610 * 611 * @param ocs pointer to ocs structure 612 * @param lock lock to initialize 613 * @param name string identifier for the lock 614 */ 615static inline void 616ocs_rlock_init(ocs_t *ocs, ocs_rlock_t *lock, const char *name) 617{ 618 ocs_strncpy(lock->name, name, MAX_LOCK_DESC_LEN); 619 mtx_init(&(lock)->lock, lock->name, NULL, MTX_DEF | MTX_RECURSE | MTX_DUPOK); 620} 621 622/** 623 * @ingroup os 624 * @brief Free a previously allocated recursive lock 625 * 626 * @param lock lock to free 627 */ 628static inline void 629ocs_rlock_free(ocs_rlock_t *lock) 630{ 631 if (mtx_initialized(&(lock)->lock)) { 632 mtx_destroy(&(lock)->lock); 633 } else { 634 panic("XXX trying to free with un-initialized mtx!?!?\n"); 635 } 636} 637 638/** 639 * @brief try to acquire a recursive lock 640 * 641 * Attempt to acquire a recursive lock, return TRUE if successful 642 * 643 * @param lock pointer to recursive lock 644 * 645 * @return TRUE if lock was acquired, FALSE if not 646 */ 647static inline int32_t 648ocs_rlock_try(ocs_rlock_t *lock) 649{ 650 int rc = mtx_trylock(&(lock)->lock); 651 652 return rc != 0; 653} 654 655/** 656 * @ingroup os 657 * @brief Acquire a recursive lock 658 * 659 * @param lock lock to obtain 660 */ 661static inline void 662ocs_rlock_acquire(ocs_rlock_t *lock) 663{ 664 if (mtx_initialized(&(lock)->lock)) { 665 mtx_lock(&(lock)->lock); 666 } else { 667 panic("XXX trying to lock with un-initialized mtx!?!?\n"); 668 } 669} 670 671/** 672 * @ingroup os 673 * @brief Release a recursive lock 674 * 675 * @param lock lock to release 676 */ 677static inline void 678ocs_rlock_release(ocs_rlock_t *lock) 679{ 680 if (mtx_initialized(&(lock)->lock)) { 681 mtx_assert(&(lock)->lock, MA_OWNED); 682 mtx_unlock(&(lock)->lock); 683 } else { 684 panic("XXX trying to unlock with un-initialized mtx!?!?\n"); 685 } 686} 687 688/** 689 * @brief counting semaphore 690 * 691 * Declaration of the counting semaphore object 692 * 693 */ 694typedef struct { 695 char name[32]; 696 struct sema sem; /**< OS counting semaphore structure */ 697} ocs_sem_t; 698 699#define OCS_SEM_FOREVER (-1) 700#define OCS_SEM_TRY (0) 701 702/** 703 * @brief Initialize a counting semaphore 704 * 705 * The semaphore is initiatlized to the value 706 * 707 * @param sem pointer to semaphore 708 * @param val initial value 709 * @param name label for the semaphore 710 * 711 * @return returns 0 for success, a negative error code value for failure. 712 */ 713 714extern int ocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...) __attribute__((format(printf, 3, 4))); 715 716/** 717 * @brief execute a P (decrement) operation 718 * 719 * A P (decrement and block if negative) operation is performed on the semaphore. 720 * 721 * If timeout_usec is zero, the semaphore attempts one time and returns 0 if acquired. 722 * If timeout_usec is greater than zero, then the call will block until the semaphore 723 * is acquired, or a timeout occurred. If timeout_usec is less than zero, then 724 * the call will block until the semaphore is acquired. 725 * 726 * @param sem pointer to semaphore 727 * @param timeout_usec timeout in microseconds 728 * 729 * @return returns 0 for success, negative value if the semaphore was not acquired. 730 */ 731 732static inline int 733ocs_sem_p(ocs_sem_t *sem, int timeout_usec) 734{ 735 int32_t rc = 0; 736 737 if (timeout_usec == 0) { 738 rc = sema_trywait(&sem->sem); 739 if (rc == 0) { 740 rc = -1; 741 } 742 } else if (timeout_usec > 0) { 743 struct timeval tv; 744 uint32_t ticks; 745 746 tv.tv_sec = timeout_usec / 1000000; 747 tv.tv_usec = timeout_usec % 1000000; 748 ticks = tvtohz(&tv); 749 if (ticks == 0) { 750 ticks ++; 751 } 752 rc = sema_timedwait(&sem->sem, ticks); 753 if (rc != 0) { 754 rc = -1; 755 } 756 } else { 757 sema_wait(&sem->sem); 758 } 759 if (rc) 760 rc = -1; 761 762 return rc; 763} 764 765/** 766 * @brief perform a V (increment) operation on a counting semaphore 767 * 768 * The semaphore is incremented, unblocking one thread that is waiting on the 769 * sempahore 770 * 771 * @param sem pointer to the semaphore 772 * 773 * @return none 774 */ 775 776static inline void 777ocs_sem_v(ocs_sem_t *sem) 778{ 779 sema_post(&sem->sem); 780} 781 782/*************************************************************************** 783 * Bitmap 784 */ 785 786/** 787 * @ingroup os 788 * @typedef ocs_bitmap_t 789 * @brief Define the type used implement bit-maps 790 */ 791typedef bitstr_t ocs_bitmap_t; 792 793/** 794 * @ingroup os 795 * @brief Allocate a bitmap 796 * 797 * @param n_bits Minimum number of entries in the bit-map 798 * 799 * @return pointer to the bit-map or NULL on error 800 */ 801extern ocs_bitmap_t *ocs_bitmap_alloc(uint32_t n_bits); 802 803/** 804 * @ingroup os 805 * @brief Free a bit-map 806 * 807 * @param bitmap Bit-map to free 808 */ 809extern void ocs_bitmap_free(ocs_bitmap_t *bitmap); 810 811/** 812 * @ingroup os 813 * @brief Find next unset bit and set it 814 * 815 * @param bitmap bit map to search 816 * @param n_bits number of bits in map 817 * 818 * @return bit position or -1 if map is full 819 */ 820extern int32_t ocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits); 821 822/** 823 * @ingroup os 824 * @brief search for next (un)set bit 825 * 826 * @param bitmap bit map to search 827 * @param set search for a set or unset bit 828 * @param n_bits number of bits in map 829 * 830 * @return bit position or -1 831 */ 832extern int32_t ocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits); 833 834/** 835 * @ingroup os 836 * @brief clear the specified bit 837 * 838 * @param bitmap pointer to bit map 839 * @param bit bit number to clear 840 */ 841extern void ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit); 842 843extern int32_t ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len); 844 845/*************************************************************************** 846 * Timer Routines 847 * 848 * Functions for setting, querying and canceling timers. 849 */ 850typedef struct { 851 struct callout callout; 852 struct mtx lock; 853 854 void (*func)(void *); 855 void *data; 856} ocs_timer_t; 857 858/** 859 * @ingroup os 860 * @brief Initialize and set a timer 861 * 862 * @param os OS handle 863 * @param timer pointer to the structure allocated for this timer 864 * @param func the function to call when the timer expires 865 * @param data Data to pass to the provided timer function when the timer 866 * expires. 867 * @param timeout_ms the timeout in milliseconds 868 */ 869extern int32_t ocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg), 870 void *data, uint32_t timeout_ms); 871 872/** 873 * @ingroup os 874 * @brief Modify a timer's expiration 875 * 876 * @param timer pointer to the structure allocated for this timer 877 * @param timeout_ms the timeout in milliseconds 878 */ 879extern int32_t ocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms); 880 881/** 882 * @ingroup os 883 * @brief Queries to see if a timer is pending. 884 * 885 * @param timer pointer to the structure allocated for this timer 886 * 887 * @return non-zero if the timer is pending 888 */ 889extern int32_t ocs_timer_pending(ocs_timer_t *timer); 890 891/** 892 * @ingroup os 893 * @brief Remove a pending timer 894 * 895 * @param timer pointer to the structure allocated for this timer 896 * expires. 897 */ 898extern int32_t ocs_del_timer(ocs_timer_t *timer); 899 900/*************************************************************************** 901 * Atomics 902 * 903 */ 904 905typedef uint32_t ocs_atomic_t; 906 907/** 908 * @ingroup os 909 * @brief initialize an atomic 910 * 911 * @param a pointer to the atomic object 912 * @param v initial value 913 * 914 * @return none 915 */ 916#define ocs_atomic_init(a, v) ocs_atomic_set(a, v) 917 918/** 919 * @ingroup os 920 * @brief adds an integer to an atomic value 921 * 922 * @param a pointer to the atomic object 923 * @param v value to increment 924 * 925 * @return the value of the atomic before incrementing. 926 */ 927#define ocs_atomic_add_return(a, v) atomic_fetchadd_32(a, v) 928 929/** 930 * @ingroup os 931 * @brief subtracts an integer to an atomic value 932 * 933 * @param a pointer to the atomic object 934 * @param v value to increment 935 * 936 * @return the value of the atomic before subtracting. 937 */ 938#define ocs_atomic_sub_return(a, v) atomic_fetchadd_32(a, (-(v))) 939 940/** 941 * @ingroup os 942 * @brief returns the current value of an atomic object 943 * 944 * @param a pointer to the atomic object 945 * 946 * @return the value of the atomic. 947 */ 948#define ocs_atomic_read(a) atomic_load_acq_32(a) 949 950/** 951 * @ingroup os 952 * @brief sets the current value of an atomic object 953 * 954 * @param a pointer to the atomic object 955 */ 956#define ocs_atomic_set(a, v) atomic_store_rel_32(a, v) 957 958/** 959 * @ingroup os 960 * @brief Sets atomic to 0, returns previous value 961 * 962 * @param a pointer to the atomic object 963 * 964 * @return the value of the atomic before the operation. 965 */ 966#define ocs_atomic_read_and_clear atomic_readandclear_32(a) 967 968/** 969 * @brief OCS thread structure 970 * 971 */ 972 973typedef struct ocs_thread_s ocs_thread_t; 974 975typedef int32_t (*ocs_thread_fctn)(ocs_thread_t *mythread); 976 977struct ocs_thread_s { 978 struct thread *tcb; /*<< thread control block */ 979 ocs_thread_fctn fctn; /*<< thread function */ 980 char *name; /*<< name of thread */ 981 void *arg; /*<< pointer to thread argument */ 982 ocs_atomic_t terminate; /*<< terminate request */ 983 int32_t retval; /*<< return value */ 984 uint32_t cpu_affinity; /*<< cpu affinity */ 985}; 986#define OCS_THREAD_DEFAULT_STACK_SIZE_PAGES 8 987 988/** 989 * @brief OCS thread start options 990 * 991 */ 992 993typedef enum { 994 OCS_THREAD_RUN, /*<< run immediately */ 995 OCS_THREAD_CREATE, /*<< create and wait for start request */ 996} ocs_thread_start_e; 997 998 999extern int32_t ocs_thread_create(ocs_os_handle_t os, ocs_thread_t *thread, ocs_thread_fctn fctn, 1000 const char *name, void *arg, ocs_thread_start_e start_option); 1001extern int32_t ocs_thread_start(ocs_thread_t *thread); 1002extern void *ocs_thread_get_arg(ocs_thread_t *mythread); 1003extern int32_t ocs_thread_terminate(ocs_thread_t *thread); 1004extern int32_t ocs_thread_terminate_requested(ocs_thread_t *thread); 1005extern int32_t ocs_thread_get_retval(ocs_thread_t *thread); 1006extern void ocs_thread_yield(ocs_thread_t *thread); 1007extern ocs_thread_t *ocs_thread_self(void); 1008extern int32_t ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu); 1009extern int32_t ocs_thread_getcpu(void); 1010 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 */ 1024typedef 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 */ 1055extern int32_t 1056ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func); 1057 1058extern ocs_t *ocs_get_instance(uint32_t index); 1059extern uint32_t ocs_instance(void *os); 1060 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 */ 1071extern 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 */ 1083extern 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 */ 1095extern 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 */ 1108extern 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 */ 1121extern 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 */ 1134extern 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 */ 1146extern 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 */ 1158extern 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 */ 1170extern 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 */ 1181extern 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 */ 1192extern 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 */ 1203extern 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 */ 1211extern 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 */ 1219extern 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 */ 1227extern const char *ocs_pci_model(uint16_t vendor, uint16_t device); 1228 1229extern void ocs_print_stack(void); 1230 1231extern void ocs_abort(void) __attribute__((noreturn)); 1232 1233/*************************************************************************** 1234 * Reference counting 1235 * 1236 */ 1237 1238/** 1239 * @ingroup os 1240 * @brief reference counter object 1241 */ 1242typedef void (*ocs_ref_release_t)(void *arg); 1243typedef 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 */ 1257static inline void 1258ocs_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 */ 1273static inline uint32_t 1274ocs_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 */ 1286static inline void 1287ocs_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 */ 1308static inline void 1309ocs_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 */ 1327static inline uint32_t 1328ocs_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 */ 1352static inline uint32_t 1353ocs_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 */ 1370static inline uint64_t 1371ocs_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 */ 1382static inline uint32_t 1383ocs_get_os_tick_freq(void) 1384{ 1385 return hz; 1386} 1387 1388/***************************************************************************** 1389 * 1390 * CPU topology API 1391 */ 1392 1393typedef struct { 1394 uint32_t num_cpus; /* Number of CPU cores */ 1395 uint8_t hyper; /* TRUE if threaded CPUs */ 1396} ocs_cpuinfo_t; 1397 1398extern int32_t ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo); 1399extern 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 */ 1407