|
|
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.