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