|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_FREE_COPYRIGHT@
24: */
25: /*
26: * HISTORY
27: *
28: * Revision 1.1.1.1 1998/09/22 21:05:38 wsanchez
29: * Import of Mac OS X kernel (~semeria)
30: *
31: * Revision 1.1.1.1 1998/03/07 02:25:39 wsanchez
32: * Import of OSF Mach kernel (~mburg)
33: *
34: * Revision 1.3.17.7 1995/08/21 20:33:13 devrcs
35: * ri-osc CR1547: Fix himem buffer translation to cope with non
36: * page-aligned addresses.
37: * [1995/08/08 16:51:58 bolinger]
38: *
39: * Revision 1.3.17.6 1995/02/24 15:51:12 alanl
40: * DIPC: Merge from nmk17b2 to nmk18b8.
41: * Notes: lock package cleanup.
42: * [95/01/23 alanl]
43: * [95/02/24 alanl]
44: *
45: * Revision 1.3.17.5 1995/01/26 22:14:52 ezf
46: * removed extraneous CMU CR
47: * [1995/01/26 20:24:45 ezf]
48: *
49: * Revision 1.3.17.4 1995/01/10 04:51:04 devrcs
50: * mk6 CR801 - merge up from nmk18b4 to nmk18b7
51: * * Rev 1.3.17.3 1994/10/21 18:41:39 joe
52: * Added ETAP support
53: * [1994/12/09 20:37:48 dwm]
54: *
55: * mk6 CR764 - s/spinlock/simple_lock/ (name change only)
56: * [1994/11/10 05:25:33 dwm]
57: *
58: * mk6 CR668 - 1.3b26 merge
59: * * Revision 1.3.5.8 1994/05/06 18:44:06 tmt
60: * Fix prototypes for new device signatures.
61: * * Revision 1.3.5.6 1993/12/10 18:08:15 jeffc
62: * CR10305 -- locking bug in himem_reserve(): change call to
63: * vm_page_free to VM_PAGE_FREE.
64: * * Revision 1.3.5.5 1993/11/19 17:56:58 jeffc
65: * CR10125 -- Uninitialized lock in himem_convert. Add himem_init
66: * CR9461 -- Locking bug in himem_convert - must retake lock after
67: * thread_sleep.
68: * * End1.3merge
69: * [1994/11/04 09:07:39 dwm]
70: *
71: * Revision 1.3.17.1 1994/06/14 03:04:20 toshi
72: * Merge MK6 and NMK17
73: * [1994/06/14 01:06:55 toshi]
74: *
75: * Revision 1.3.15.2 1994/06/08 21:14:24 dswartz
76: * Preemption merge.
77: * [1994/06/08 21:12:29 dswartz]
78: *
79: * Revision 1.3.15.1 1994/05/19 20:30:23 dwm
80: * mk6 CR 74. Locking bug in himem_reserve(): use VM_PAGE_FREE.
81: * mk6 CR 9461. Init hil_lock used by himem_convert();
82: * retake lock after sleeping.
83: * [1994/05/19 20:30:07 dwm]
84: *
85: * Revision 1.3.11.1 1994/02/09 07:27:07 bernadat
86: * Added himem_init() for module initialization.
87: * [93/08/12 paire]
88: *
89: * Take back hil_lock lock on return from thread_sleep()
90: * [93/07/16 bernadat]
91: *
92: * Add vm_page_gobble() calls where needed. (dwm bug #542)
93: * Change from NORMA_MK14.6 [1993/02/09 22:24:00 dwm]
94: * [93/07/16 bernadat]
95: * [94/02/08 bernadat]
96: *
97: * Revision 1.3.5.4 1993/08/09 19:37:19 dswartz
98: * Add ANSI prototypes - CR#9523
99: * [1993/08/06 17:50:02 dswartz]
100: *
101: * Revision 1.3.5.3 1993/08/03 22:21:26 bernard
102: * CR#9523 - ANSI prototype fixes.
103: * [1993/08/03 15:34:10 bernard]
104: *
105: * Revision 1.3.5.2 1993/06/09 02:25:18 gm
106: * CR9157 - Find himem.h in the right place.
107: * [1993/05/28 17:27:23 brezak]
108: *
109: * Revision 1.3 1993/04/19 16:09:46 devrcs
110: * make endif tags ansi compliant/include files
111: * [1993/02/20 21:46:44 david]
112: *
113: * Print an appropriate message when going out of HIMEM pages.
114: * [93/01/26 bernadat]
115: *
116: * Revision 1.2 1992/11/25 01:07:08 robert
117: * integrate changes below for norma_14
118: * [1992/11/13 19:28:44 robert]
119: *
120: * $EndLog$
121: */
122:
123: /*
124: * support of memory above 16 Megs for DMA limited to memory
125: * below 16 Megs. Copies high memory lo low memory before DMA
126: * write operations and does the reverse at completion time for
127: * DMA read operations
128: */
129:
130: #include <cpus.h>
131: #include <platforms.h>
132: #include <kern/lock.h>
133: #include <mach/vm_param.h>
134: #include <vm/vm_page.h>
135: #include <i386/AT386/himem.h>
136: #include <kern/kalloc.h>
137: #include <kern/spl.h>
138: #include <mach/boolean.h>
139: #include <kern/misc_protos.h>
140: #include <i386/AT386/misc_protos.h>
141:
142: hil_t hil_head;
143: decl_simple_lock_data(,hil_lock)
144:
145: #if HIMEM_STATS
146: int himem_request; /* number of requests */
147: int himem_used; /* number of times used */
148: #endif /* HIMEM_STATS */
149:
150: void
151: himem_init(
152: void)
153: {
154: simple_lock_init(&hil_lock, ETAP_VM_HIMEM);
155: }
156:
157: /*
158: * Called by drivers, this indicates himem that this driver might need
159: * to allocate as many as npages pages in a single I/O DMA transfer
160: */
161:
162: void
163: himem_reserve(
164: int npages)
165: {
166: register i = 0;
167: vm_page_t free_head = VM_PAGE_NULL;
168: vm_page_t low;
169: hil_t hil;
170: spl_t ipl;
171: extern vm_offset_t avail_end;
172:
173: if (avail_end <= HIGH_MEM)
174: return;
175: hil = (hil_t)kalloc(npages*sizeof(struct himem_link));
176: if (hil == (hil_t)0)
177: panic("himem_reserve: kalloc failed\n");
178:
179: for (i=0; i < npages-1; i++)
180: (hil+i)->next = hil+i+1;
181:
182: /*
183: * This is the only way of getting low physical pages
184: * wtithout changing VM internals
185: */
186: for (i=0; i != npages;) {
187: if ((low = vm_page_grab()) == VM_PAGE_NULL)
188: panic("No low memory pages for himem\n");
189: vm_page_gobble(low); /* mark as consumed internally */
190: if (_high_mem_page(low->phys_addr)) {
191: low->pageq.next = (queue_entry_t)free_head;
192: free_head = low;
193: } else {
194: (hil+i)->low_page = low->phys_addr;
195: i++;
196: }
197: }
198:
199: for (low = free_head; low; low = free_head) {
200: free_head = (vm_page_t) low->pageq.next;
201: VM_PAGE_FREE(low);
202: }
203:
204: ipl = splhi();
205: simple_lock(&hil_lock);
206: (hil+npages-1)->next = hil_head;
207: hil_head = hil;
208: simple_unlock(&hil_lock);
209: splx(ipl);
210: }
211:
212: /*
213: * Called by driver at DMA initialization time. Converts a high memory
214: * physical page to a low memory one. If operation is a write,
215: * [phys_addr, phys_addr+length-1] is copied to new page. Caller must
216: * provide a pointer to a pointer to a himem_list. This is used to store
217: * all the conversions and is use at completion time to revert the pages.
218: * This pointer must point to a null hil_t value for the call on the first
219: * page of a DMA transfer.
220: */
221:
222: vm_offset_t
223: himem_convert(
224: vm_offset_t phys_addr,
225: vm_size_t length,
226: int io_op,
227: hil_t *hil)
228: {
229: hil_t h;
230: spl_t ipl;
231: vm_offset_t offset = phys_addr & (I386_PGBYTES - 1);
232:
233: assert (offset + length <= I386_PGBYTES);
234:
235: ipl = splhi();
236: simple_lock(&hil_lock);
237: while (!(h = hil_head)) {
238: printf("WARNING: out of HIMEM pages\n");
239: thread_sleep_simple_lock((event_t)&hil_head,
240: simple_lock_addr(hil_lock), FALSE);
241: simple_lock (&hil_lock);
242: }
243: hil_head = hil_head->next;
244: simple_unlock(&hil_lock);
245: splx(ipl);
246:
247: h->high_addr = phys_addr;
248:
249: if (io_op == D_WRITE) {
250: bcopy((char *)phystokv(phys_addr), (char *)phystokv(h->low_page + offset),
251: length);
252: h->length = 0;
253: } else {
254: h->length = length;
255: }
256: h->offset = offset;
257:
258: assert(!*hil || (*hil)->high_addr);
259:
260: h->next = *hil;
261: *hil = h;
262: return(h->low_page + offset);
263: }
264:
265: /*
266: * Called by driver at DMA completion time. Converts a list of low memory
267: * physical page to the original high memory one. If operation was read,
268: * [phys_addr, phys_addr+lenght-1] is copied to original page
269: */
270:
271: void
272: himem_revert(
273: hil_t hil)
274: {
275: hil_t next;
276: boolean_t wakeup = FALSE;
277: spl_t ipl;
278:
279: while(hil) {
280: if (hil->length) {
281: bcopy((char *)phystokv(hil->low_page + hil->offset),
282: (char *)phystokv(hil->high_addr),
283: hil->length);
284: }
285: hil->high_addr = 0;
286: hil->length = 0;
287: hil->offset = 0;
288: next = hil->next;
289: ipl = splhi();
290: simple_lock(&hil_lock);
291: if (!(hil->next = hil_head))
292: wakeup = TRUE;
293: hil_head = hil;
294: simple_unlock(&hil_lock);
295: splx(ipl);
296: hil = next;
297: }
298: if (wakeup)
299: thread_wakeup((event_t)&hil_head);
300: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.