|
|
1.1 ! root 1: #define _DDI_DKI 1 ! 2: #define _DDI_DKI_IMPL 1 ! 3: #define _SYSV4 1 ! 4: ! 5: /* ! 6: * Definition for the DDI/DKI linkable version of ddi_proc () ! 7: */ ! 8: ! 9: /* ! 10: *-IMPORTS: ! 11: * <common/ccompat.h> ! 12: * __USE_PROTO__ ! 13: * __ARGS () ! 14: * <kernel/x86lock.h> ! 15: * ATOMIC_STORE_UCHAR () ! 16: * <kernel/ddi_lock.h> ! 17: * INTERNAL_LOCK ! 18: * poll_global_hierarchy ! 19: * poll_global_priority ! 20: * defer_hierarchy ! 21: * defer_priority ! 22: * proc_global_hierarchy ! 23: * proc_global_priority ! 24: * <sys/types.h> ! 25: * inb () ! 26: * outb () ! 27: * <sys/ksynch.h> ! 28: * lkinfo_t ! 29: * LOCK_ALLOC () ! 30: * <sys/kmem.h> ! 31: * KM_NOSLEEP ! 32: * kmem_alloc () ! 33: * <stddef.h> ! 34: * NULL ! 35: * <string.h> ! 36: * memset () ! 37: */ ! 38: ! 39: #include <common/ccompat.h> ! 40: #include <kernel/x86lock.h> ! 41: #include <kernel/ddi_lock.h> ! 42: #include <sys/types.h> ! 43: #include <sys/ksynch.h> ! 44: #include <sys/kmem.h> ! 45: #include <stddef.h> ! 46: #include <string.h> ! 47: ! 48: #include <kernel/ddi_base.h> ! 49: #include <kernel/ddi_proc.h> ! 50: #include <kernel/ddi_cpu.h> ! 51: #include <kernel/ddi_glob.h> ! 52: ! 53: ! 54: /* ! 55: * Here we have the actal static data declarations for the uniprocessor ! 56: * implementation of the DDI/DKI per-CPU data. Note that under a "real" ! 57: * system, the dynamic area would be the space left over by the fixed data up ! 58: * to the size of a page, because that seems the best (read fastest and most ! 59: * secure) way of doing it (by mapping each processor's private data into the ! 60: * same address across all processors). Of course, it's questionable whether ! 61: * any drivers *will* actually use the binary-compatible function-versions of ! 62: * the accessors, but that's not our problem. ! 63: * ! 64: * Don't forget that if we *do* use the paging system for per-CPU data that ! 65: * those pages will have to be mapped somewhere else as well, because there is ! 66: * data like the deferred function table that the world may want controlled ! 67: * access to. ! 68: */ ! 69: ! 70: dcdata_t __ddi_cpu_data [1]; ! 71: dgdata_t __ddi_global_data; ! 72: __LOCAL__ char ddi_cpu_dynarea [512]; ! 73: ! 74: ! 75: /* ! 76: * Lock information structures. ! 77: */ ! 78: ! 79: __LOCAL__ lkinfo_t poll_global_lkinfo = { ! 80: "polling global lock", INTERNAL_LOCK ! 81: }; ! 82: ! 83: __LOCAL__ lkinfo_t defer_lkinfo = { ! 84: "defer write lock", INTERNAL_LOCK ! 85: }; ! 86: ! 87: __LOCAL__ lkinfo_t proc_global_lkinfo = { ! 88: "process global lock", INTERNAL_LOCK ! 89: }; ! 90: ! 91: ! 92: /* ! 93: *-STATUS: ! 94: * Local DDI/DKI extension ! 95: * ! 96: *-NAME: ! 97: * ddi_base_data Get per-process DDI/DKI base data. ! 98: * ! 99: *-SYNOPSIS: ! 100: * #include <kernel/ddi_base.h> ! 101: * ! 102: * dbdata_t * ddi_base_data (void); ! 103: * ! 104: *-DESCRIPTION: ! 105: * This function returns a base pointer to a table of information that ! 106: * the DDI/DKI needs to associate with a process but will not need to ! 107: * access outside that process context. ! 108: * ! 109: *-RETURN VALUE: ! 110: * The base address of a per-process DDI/DKI data table entry. The ! 111: * value returned may be considered "constant" and memoized within a ! 112: * context provided that no rescheduling may occur. ! 113: * ! 114: *-LEVEL: ! 115: * Base only. ! 116: * ! 117: *-NOTES: ! 118: * This function does not sleep. ! 119: */ ! 120: ! 121: ! 122: #if __USE_PROTO__ ! 123: dbdata_t * (ddi_base_data) (void) ! 124: #else ! 125: dbdata_t * ! 126: ddi_base_data __ARGS (()) ! 127: #endif ! 128: { ! 129: ASSERT_BASE_LEVEL (); ! 130: ! 131: return ddi_base_data (); ! 132: } ! 133: ! 134: ! 135: /* ! 136: *-STATUS: ! 137: * Local DDI/DKI extension ! 138: * ! 139: *-NAME: ! 140: * ddi_proc_data Get per-process DDI/DKI global data. ! 141: * ! 142: *-SYNOPSIS: ! 143: * #include <kernel/ddi_proc.h> ! 144: * ! 145: * dpdata_t * ddi_proc_data (void); ! 146: * ! 147: *-DESCRIPTION: ! 148: * This function returns a base pointer to a table of information that ! 149: * the DDI/DKI needs to associate with a process but may need to access ! 150: * outside the process context. ! 151: * ! 152: *-RETURN VALUE: ! 153: * The base address of a per-process DDI/DKI data table entry. The ! 154: * value returned may be considered "constant" and memoized within a ! 155: * context provided that no rescheduling may occur. ! 156: * ! 157: *-LEVEL: ! 158: * Base or interrupt. ! 159: * ! 160: *-NOTES: ! 161: * This function does not sleep. ! 162: */ ! 163: ! 164: ! 165: #if __USE_PROTO__ ! 166: dpdata_t * (ddi_proc_data) (void) ! 167: #else ! 168: dpdata_t * ! 169: ddi_proc_data __ARGS (()) ! 170: #endif ! 171: { ! 172: return ddi_proc_data (); ! 173: } ! 174: ! 175: ! 176: /* ! 177: *-STATUS: ! 178: * Local DDI/DKI extension ! 179: * ! 180: *-NAME: ! 181: * ddi_cpu_data Get per-CPU DDI/DKI global data. ! 182: * ! 183: *-SYNOPSIS: ! 184: * #include <kernel/ddi_cpu.h> ! 185: * ! 186: * dcdata_t * ddi_cpu_data (void); ! 187: * ! 188: *-DESCRIPTION: ! 189: * This function returns a base pointer to a table of information that ! 190: * can be considered per-CPU DDI/DKI static data. The value returned ! 191: * may be considered "constant" and memoized within a context provided ! 192: * that no rescheduling could occur. ! 193: * ! 194: *-RETURN VALUE: ! 195: * The base address of a per-CPU DDI/DKI data table entry. ! 196: * ! 197: *-LEVEL: ! 198: * Base or interrupt. ! 199: * ! 200: *-NOTES: ! 201: * This function does not sleep. ! 202: */ ! 203: ! 204: #if __USE_PROTO__ ! 205: dcdata_t * (ddi_cpu_data) (void) ! 206: #else ! 207: dcdata_t * ! 208: ddi_cpu_data __ARGS (()) ! 209: #endif ! 210: { ! 211: return ddi_cpu_data (); ! 212: } ! 213: ! 214: ! 215: /* ! 216: *-STATUS: ! 217: * Local DDI/DKI extension ! 218: * ! 219: *-NAME: ! 220: * ddi_global_data Get DDI/DKI global data. ! 221: * ! 222: *-SYNOPSIS: ! 223: * #include <kernel/ddi_glob.h> ! 224: * ! 225: * dgdata_t * ddi_global_data (void); ! 226: * ! 227: *-DESCRIPTION: ! 228: * This function returns a base pointer to a table of information that ! 229: * represents the global state of the DDI/DKI subsystem, with the ! 230: * possible exception of the STREAMS global state. ! 231: * ! 232: *-RETURN VALUE: ! 233: * The base address of the global DDI/DKI data table. The value returned ! 234: * may be considered "constant" and memoized within a context provided ! 235: * that no rescheduling may occur. ! 236: * ! 237: *-LEVEL: ! 238: * Base or interrupt. ! 239: * ! 240: *-NOTES: ! 241: * This function does not sleep. ! 242: */ ! 243: ! 244: ! 245: #if __USE_PROTO__ ! 246: dgdata_t * (ddi_global_data) (void) ! 247: #else ! 248: dgdata_t * ! 249: ddi_global_data __ARGS (()) ! 250: #endif ! 251: { ! 252: return ddi_global_data (); ! 253: } ! 254: ! 255: ! 256: /* ! 257: *-STATUS: ! 258: * For the Implementors only. ! 259: * ! 260: *-NAME: ! 261: * ddi_cpu_id Determine the current CPU id. ! 262: * ! 263: *-SYNOPSIS: ! 264: * #include <kernel/ddi_cpu.h> ! 265: * ! 266: * processorid_t ddi_cpu_id (void); ! 267: * ! 268: *-DESCRIPTION: ! 269: * ddi_cpu_id () allows DDI/DKI code a way of accessing the current CPU ! 270: * id for passing to functions such as dtimeout () or defer_int_cpu (). ! 271: * ! 272: *-RETURN VALUE: ! 273: * The id code of the CPU that the caller is executing on. ! 274: * ! 275: *-LEVEL: ! 276: * Base or interrupt. ! 277: * ! 278: *-NOTES: ! 279: * Does not sleep. ! 280: */ ! 281: ! 282: #if __USE_PROTO__ ! 283: processorid_t (ddi_cpu_id) (void) ! 284: #else ! 285: processorid_t ! 286: ddi_cpu_id __ARGS (()) ! 287: #endif ! 288: { ! 289: return ddi_cpu_data ()->dc_cpuid; ! 290: } ! 291: ! 292: ! 293: /* ! 294: *-STATUS: ! 295: * For the Implementors only. ! 296: * ! 297: *-NAME: ! 298: * ddi_cpu_alloc Dynamically allocates per-CPU data. ! 299: * ! 300: *-SYNOPSIS: ! 301: * #include <kernel/ddi_cpu.h> ! 302: * ! 303: * void * ddi_cpu_alloc (size_t size); ! 304: * ! 305: *-ARGUMENTS: ! 306: * size The size in bytes to allocate. This value will always ! 307: * be rounded up to the size of an integer to ensure the ! 308: * alignment of the returned space. A value of 0 is not ! 309: * legal and will result in the function returning NULL. ! 310: * ! 311: *-DESCRIPTION: ! 312: * ddi_cpu_alloc () is for use in the DDI/DKI implementation to request ! 313: * per-CPU data in a flexible way. Facilities that require tables of per- ! 314: * CPU data should request it at startup time to allow the table sizes to ! 315: * be flexibly administered and also to avoid polluting the "dcdata_t" ! 316: * structure with information whose size cannot easily be fixed. Using ! 317: * this facility should allow for greater levels of internal binary ! 318: * compatibility by restricting the amount of change the "dcdata_t" ! 319: * structure can undergo between (minor) releases of the operation ! 320: * system. ! 321: * ! 322: *-RETURN VALUE: ! 323: * On failure, NULL is returned. On success, a pointer to the requested ! 324: * data is returned. The pointer returned will be aligned to the size of ! 325: * an integer on the target machine architecture. ! 326: * ! 327: *-LEVEL: ! 328: * Base only. ! 329: * ! 330: *-NOTES: ! 331: * Does not sleep. ! 332: */ ! 333: ! 334: #if __USE_PROTO__ ! 335: __VOID__ * (ddi_cpu_alloc) (size_t size) ! 336: #else ! 337: __VOID__ * ! 338: ddi_cpu_alloc __ARGS ((size)) ! 339: size_t size; ! 340: #endif ! 341: { ! 342: dcdata_t * dcdatap = ddi_cpu_data (); ! 343: __VOID__ * alloc; ! 344: ! 345: ASSERT_BASE_LEVEL (); ! 346: ! 347: size = (size + sizeof (int) - 1) & ~ sizeof (int); ! 348: ! 349: if (size == 0 || dcdatap->dc_dynalloc + size > dcdatap->dc_dynend) ! 350: return NULL; ! 351: ! 352: alloc = dcdatap->dc_dynalloc; ! 353: dcdatap->dc_dynalloc += size; ! 354: ! 355: memset (alloc, 0, size); ! 356: return alloc; ! 357: } ! 358: ! 359: ! 360: /* ! 361: *-STATUS: ! 362: * For the Implementors only. ! 363: * ! 364: *-NAME: ! 365: * ddi_cpu_other Return per-CPU data for other CPUs ! 366: * ! 367: *-SYNOPSIS: ! 368: * #include <kernel/ddi_cpu.h> ! 369: * ! 370: * dcdata_t * ddi_cpu_ref (processorid_t cpu); ! 371: * ! 372: *-ARGUMENTS: ! 373: * cpu ID code for processor whose data needs to be accessed. ! 374: * ! 375: *-DESCRIPTION: ! 376: * The implementations of DDI/DKI facilities may wish to write into the ! 377: * private data areas of other CPUs. This function provides a way of ! 378: * accessing that information. ! 379: * ! 380: * Note that the per-CPU data area provides many conveniences to the ! 381: * implementor, not the least of which is latitude with synchronization, ! 382: * which has a data space cost if not a run-time cost, and also makes ! 383: * many operations considerably simpler. Access by other CPUs to per-CPU ! 384: * data bypasses most of the assumptions that can be conveniently made ! 385: * about access to this area, so users of this function are especially ! 386: * cautioned to use all the appropriate interlock mechanisms when writing ! 387: * data via the pointer this function provides. ! 388: * ! 389: * There must be exactly one call to ddi_cpu_unref () for each call to ! 390: * ddi_cpu_ref (). This should be done as soon as possible after the ! 391: * call to ddi_cpu_ref () since on some architectures making this memory ! 392: * shared may have a serious impact on performance. ! 393: * ! 394: *-RETURN VALUE: ! 395: * NULL is returned if the cpu ID is not valid for the machine ! 396: * configuration. Otherwise, a pointer to the per-process data for the ! 397: * indicated CPU is returned. ! 398: * ! 399: *-LEVEL: ! 400: * Base or interrupt. ! 401: * ! 402: *-NOTES: ! 403: * Does not sleep. ! 404: * ! 405: * It is as yet uspecified whether recursive calls to ddi_cpu_ref () are ! 406: * permitted. ! 407: */ ! 408: ! 409: #if __USE_PROTO__ ! 410: dcdata_t * (ddi_cpu_ref) (processorid_t cpu) ! 411: #else ! 412: dcdata_t * ! 413: ddi_cpu_ref __ARGS ((cpu)) ! 414: processorid_t cpu; ! 415: #endif ! 416: { ! 417: /* ! 418: * Only one processor, as yet. ! 419: */ ! 420: ! 421: return cpu == 0 ? ddi_cpu_data () : NULL; ! 422: } ! 423: ! 424: ! 425: /* ! 426: *-STATUS: ! 427: * For the Implementors only. ! 428: * ! 429: *-NAME: ! 430: * ddi_cpu_other Return per-CPU data for other CPUs ! 431: * ! 432: *-SYNOPSIS: ! 433: * #include <kernel/ddi_cpu.h> ! 434: * ! 435: * void ddi_cpu_unref (dcdata_t * data); ! 436: * ! 437: *-ARGUMENTS: ! 438: * data A pointer to per-CPU data obtained via the ! 439: * ddi_cpu_ref () function. ! 440: * ! 441: *-DESCRIPTION: ! 442: * This function is used to release a reference to per-CPU data for some ! 443: * CPU that was obtained by ddi_cpu_ref (). This function may perform ! 444: * various actions to undo any work necessary to ensure that the memory ! 445: * in question can be accessed by the calling CPU, such as unmapping it ! 446: * from the calling CPU's address space to provide maximum protection ! 447: * against accidental damage. ! 448: * ! 449: * There must be exactly one call to ddi_cpu_unref () for each call to ! 450: * ddi_cpu_ref (). ! 451: * ! 452: *-RETURN VALUE: ! 453: * None. ! 454: * ! 455: *-LEVEL: ! 456: * Base or interrupt. ! 457: * ! 458: *-NOTES: ! 459: * Does not sleep. ! 460: */ ! 461: ! 462: #if __USE_PROTO__ ! 463: void (ddi_cpu_unref) (dcdata_t * data) ! 464: #else ! 465: void ! 466: ddi_cpu_unref __ARGS ((data)) ! 467: dcdata_t * data; ! 468: #endif ! 469: { ! 470: ASSERT (data != NULL && data == ddi_cpu_data ()); ! 471: } ! 472: ! 473: ! 474: /* ! 475: * Do what we need to do to ensure that the spl... () functions work. ! 476: */ ! 477: ! 478: #include <sys/inline.h> ! 479: ! 480: __EXTERN_C__ ! 481: #if __USE_PROTO__ ! 482: int (INTR_INIT) (void) ! 483: #else ! 484: int ! 485: INTR_INIT __ARGS (()) ! 486: #endif ! 487: { ! 488: dcdata_t * dcdatap; ! 489: ! 490: /* ! 491: * This implementation statically allocates the per-CPU data, since ! 492: * deep down we really "know" that we are working on a uniprocessor. ! 493: * This also means we don't have to zero-fill anything. ! 494: */ ! 495: ! 496: dcdatap = ddi_cpu_data (); ! 497: dcdatap->dc_base_mask = (inb (__SPICM__) << 8) | inb (__PICM__); ! 498: ! 499: ! 500: /* ! 501: * We start at interrupt level 1 so we can trap attempts to go to ! 502: * sleep before we are ready for that. ! 503: */ ! 504: ! 505: dcdatap->dc_int_level = 0; ! 506: dcdatap->dc_ipl = plbase; ! 507: ! 508: ! 509: /* ! 510: * Set up the "dynamic" part of the structures. ! 511: */ ! 512: ! 513: dcdatap->dc_dynalloc = ddi_cpu_dynarea; ! 514: dcdatap->dc_dynend = ddi_cpu_dynarea + sizeof (ddi_cpu_dynarea); ! 515: ! 516: ! 517: /* ! 518: * Carve off some of the "dynamic" space for the heirarchy-test stuff. ! 519: * This is done with the dynamic stuff because it seems like a really ! 520: * bad idea putting a table in space we want to form the basis of an ! 521: * internal binary standard (even though this is a very well-defined ! 522: * array). ! 523: */ ! 524: ! 525: dcdatap->dc_hierarchy_cnt = (__lkhier_t *) ! 526: ddi_cpu_alloc (sizeof (__lkhier_t) * ! 527: (__MAX_HIERARCHY__ - __MIN_HIERARCHY__ + 1)); ! 528: ! 529: return dcdatap->dc_hierarchy_cnt == NULL; ! 530: } ! 531: ! 532: ! 533: /* ! 534: * Set up one of the deferred-function tables. ! 535: */ ! 536: ! 537: #if __USE_PROTO__ ! 538: __LOCAL__ int (DEFER_INIT) (defer_t * deferp, int local, int max) ! 539: #else ! 540: __LOCAL__ int ! 541: DEFER_INIT __ARGS ((deferp, local, max)) ! 542: defer_t * deferp; ! 543: int local; ! 544: int max; ! 545: #endif ! 546: { ! 547: deferp->df_tab = (__deffuncp_t *) (local == 0 ? ! 548: kmem_alloc (sizeof (__deffuncp_t) * max, KM_NOSLEEP) : ! 549: ddi_cpu_alloc (sizeof (__deffuncp_t) * max)); ! 550: ! 551: deferp->df_wlock = LOCK_ALLOC (defer_hierarchy, defer_priority, ! 552: & defer_lkinfo, KM_NOSLEEP); ! 553: ! 554: if (deferp->df_tab == NULL || deferp->df_wlock == NULL) ! 555: return 1; ! 556: ! 557: ATOMIC_STORE_UCHAR (deferp->df_max, max); ! 558: return 0; ! 559: } ! 560: ! 561: ! 562: /* ! 563: * Set up the global and per-CPU DDI/DKI data, locks and other whatnot. ! 564: */ ! 565: ! 566: __EXTERN_C__ ! 567: #if __USE_PROTO__ ! 568: int (DDI_GLOB_INIT) (void) ! 569: #else ! 570: int ! 571: DDI_GLOB_INIT __ARGS (()) ! 572: #endif ! 573: { ! 574: dgdata_t * dgdatap = ddi_global_data (); ! 575: dcdata_t * dcdatap = ddi_cpu_data (); ! 576: ! 577: /* ! 578: * Set up the global data table. We assume here that our global data ! 579: * is zeroed by default. ! 580: */ ! 581: ! 582: if (DEFER_INIT (& dgdatap->dg_defint, 0, 25) != 0 || ! 583: DEFER_INIT (& dgdatap->dg_defproc, 0, 25) != 0 || ! 584: DEFER_INIT (& dcdatap->dc_defint, 1, 25) != 0 || ! 585: DEFER_INIT (& dcdatap->dc_defproc, 1, 25) != 0) ! 586: return 1; ! 587: ! 588: dgdatap->dg_polllock = LOCK_ALLOC (poll_global_hierarchy, ! 589: poll_global_priority, ! 590: & poll_global_lkinfo, KM_NOSLEEP); ! 591: ! 592: dgdatap->dg_proclock = LOCK_ALLOC (proc_global_hierarchy, ! 593: proc_global_priority, ! 594: & proc_global_lkinfo, KM_NOSLEEP); ! 595: ! 596: if (dgdatap->dg_polllock == NULL || dgdatap->dg_proclock == NULL) ! 597: return 1; ! 598: ! 599: return 0; ! 600: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.