2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <IOKit/IOLib.h>
29 #include <IOKit/IOMapper.h>
30 #include <IOKit/IODMACommand.h>
31 #include <libkern/c++/OSData.h>
32 #include <libkern/OSDebug.h>
35 extern ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
38 #define super IOService
39 OSDefineMetaClassAndAbstractStructors(IOMapper
, IOService
);
41 OSMetaClassDefineReservedUsed(IOMapper
, 0);
42 OSMetaClassDefineReservedUsed(IOMapper
, 1);
43 OSMetaClassDefineReservedUsed(IOMapper
, 2);
44 OSMetaClassDefineReservedUsed(IOMapper
, 3);
45 OSMetaClassDefineReservedUnused(IOMapper
, 4);
46 OSMetaClassDefineReservedUnused(IOMapper
, 5);
47 OSMetaClassDefineReservedUnused(IOMapper
, 6);
48 OSMetaClassDefineReservedUnused(IOMapper
, 7);
49 OSMetaClassDefineReservedUnused(IOMapper
, 8);
50 OSMetaClassDefineReservedUnused(IOMapper
, 9);
51 OSMetaClassDefineReservedUnused(IOMapper
, 10);
52 OSMetaClassDefineReservedUnused(IOMapper
, 11);
53 OSMetaClassDefineReservedUnused(IOMapper
, 12);
54 OSMetaClassDefineReservedUnused(IOMapper
, 13);
55 OSMetaClassDefineReservedUnused(IOMapper
, 14);
56 OSMetaClassDefineReservedUnused(IOMapper
, 15);
58 IOMapper
* IOMapper::gSystem
= (IOMapper
*) IOMapper::kUnknown
;
63 IOMapperLock() { fWaitLock
= IOLockAlloc(); };
64 ~IOMapperLock() { IOLockFree(fWaitLock
); };
66 void lock() { IOLockLock(fWaitLock
); };
67 void unlock() { IOLockUnlock(fWaitLock
); };
68 void sleep(void *event
) { IOLockSleep(fWaitLock
, event
, THREAD_UNINT
); };
69 void wakeup(void *event
) { IOLockWakeup(fWaitLock
, event
, false); };
72 static IOMapperLock sMapperLock
;
74 bool IOMapper::start(IOService
*provider
)
77 if (!super::start(provider
))
80 if (!initHardware(provider
))
85 IOMapper::gSystem
= this;
86 sMapperLock
.wakeup(&IOMapper::gSystem
);
92 obj
= provider
->getProperty("iommu-id");
94 obj
= provider
->getProperty("AAPL,phandle");
96 setProperty(gIOMapperIDKey
, obj
);
101 bool IOMapper::allocTable(IOByteCount size
)
106 fTableHandle
= NewARTTable(size
, &fTable
, &fTablePhys
);
107 return fTableHandle
!= 0;
110 void IOMapper::free()
113 FreeARTTable(fTableHandle
, fTableSize
);
120 void IOMapper::setMapperRequired(bool hasMapper
)
123 IOMapper::gSystem
= (IOMapper
*) kHasMapper
;
126 IOMapper::gSystem
= (IOMapper
*) kNoMapper
;
127 sMapperLock
.unlock();
128 sMapperLock
.wakeup(&IOMapper::gSystem
);
132 void IOMapper::waitForSystemMapper()
135 while ((uintptr_t) IOMapper::gSystem
& kWaitMask
)
137 OSReportWithBacktrace("waitForSystemMapper");
138 sMapperLock
.sleep(&IOMapper::gSystem
);
140 sMapperLock
.unlock();
143 IOMapper
* IOMapper::copyMapperForDevice(IOService
* device
)
145 return copyMapperForDeviceWithIndex(device
, 0);
148 IOMapper
* IOMapper::copyMapperForDeviceWithIndex(IOService
* device
, unsigned int index
)
152 IOMapper
* mapper
= NULL
;
153 OSDictionary
* matching
;
155 obj
= device
->copyProperty("iommu-parent");
159 if ((mapper
= OSDynamicCast(IOMapper
, obj
)))
162 if ((data
= OSDynamicCast(OSData
, obj
)))
164 if (index
>= data
->getLength() / sizeof(UInt32
))
167 data
= OSData::withBytesNoCopy((UInt32
*)data
->getBytesNoCopy() + index
, sizeof(UInt32
));
171 matching
= IOService::propertyMatching(gIOMapperIDKey
, data
);
175 matching
= IOService::propertyMatching(gIOMapperIDKey
, obj
);
179 mapper
= OSDynamicCast(IOMapper
, IOService::waitForMatchingService(matching
));
189 ppnum_t
IOMapper::iovmAllocDMACommand(IODMACommand
* command
, IOItemCount pageCount
)
194 void IOMapper::iovmFreeDMACommand(IODMACommand
* command
,
195 ppnum_t addr
, IOItemCount pageCount
)
199 ppnum_t
IOMapper::iovmMapMemory(
200 OSObject
* memory
, // dma command or iomd
204 upl_page_info_t
* pageList
,
205 const IODMAMapSpecification
* mapSpecification
)
210 void IOMapper::iovmInsert(ppnum_t addr
, IOItemCount offset
,
211 ppnum_t
*pageList
, IOItemCount pageCount
)
214 iovmInsert(addr
, offset
++, *pageList
++);
217 void IOMapper::iovmInsert(ppnum_t addr
, IOItemCount offset
,
218 upl_page_info_t
*pageList
, IOItemCount pageCount
)
220 for (IOItemCount i
= 0; i
< pageCount
; i
++)
221 iovmInsert(addr
, offset
+ i
, pageList
[i
].phys_addr
);
225 NewARTTable(IOByteCount size
, void ** virtAddrP
, ppnum_t
*physAddrP
)
227 if (!virtAddrP
|| !physAddrP
)
231 vm_address_t address
;
233 size
= round_page(size
);
234 kr
= kmem_alloc_contig(kernel_map
, &address
, size
, PAGE_MASK
, 0 /*max_pnum*/, 0 /*pnum_mask*/, false);
238 ppnum_t pagenum
= pmap_find_phys(kernel_pmap
, (addr64_t
) address
);
240 *physAddrP
= pagenum
;
242 FreeARTTable((OSData
*) address
, size
);
246 *virtAddrP
= (void *) address
;
248 return (OSData
*) address
;
251 void IOMapper::FreeARTTable(OSData
*artHandle
, IOByteCount size
)
253 vm_address_t address
= (vm_address_t
) artHandle
;
255 size
= round_page(size
);
256 kmem_free(kernel_map
, address
, size
); // Just panic if address is 0
259 bool IOMapper::getBypassMask(addr64_t
*maskP
) const
266 // These are C accessors to the system mapper for non-IOKit clients
267 ppnum_t
IOMapperIOVMAlloc(unsigned pages
)
269 IOMapper::checkForSystemMapper();
271 if (IOMapper::gSystem
)
272 return IOMapper::gSystem
->iovmAlloc((IOItemCount
) pages
);
277 void IOMapperIOVMFree(ppnum_t addr
, unsigned pages
)
279 if (IOMapper::gSystem
)
280 IOMapper::gSystem
->iovmFree(addr
, (IOItemCount
) pages
);
283 ppnum_t
IOMapperInsertPage(ppnum_t addr
, unsigned offset
, ppnum_t page
)
285 if (IOMapper::gSystem
) {
286 if (!addr
) panic("!addr");
287 IOMapper::gSystem
->iovmInsert(addr
, (IOItemCount
) offset
, page
);
288 return addr
+ offset
;
294 void IOMapperInsertPPNPages(ppnum_t addr
, unsigned offset
,
295 ppnum_t
*pageList
, unsigned pageCount
)
297 if (!IOMapper::gSystem
)
298 panic("IOMapperInsertPPNPages no system mapper");
300 assert(!((vm_address_t
) IOMapper::gSystem
& 3));
303 iovmInsert(addr
, (IOItemCount
) offset
, pageList
, pageCount
);
306 void IOMapperInsertUPLPages(ppnum_t addr
, unsigned offset
,
307 upl_page_info_t
*pageList
, unsigned pageCount
)
309 if (!IOMapper::gSystem
)
310 panic("IOMapperInsertUPLPages no system mapper");
312 assert(!((vm_address_t
) IOMapper::gSystem
& 3));
314 IOMapper::gSystem
->iovmInsert(addr
,
315 (IOItemCount
) offset
,
317 (IOItemCount
) pageCount
);
320 /////////////////////////////////////////////////////////////////////////////
326 /////////////////////////////////////////////////////////////////////////////
328 #include <machine/machine_routines.h>
330 UInt8
IOMappedRead8(IOPhysicalAddress address
)
332 IOMapper::checkForSystemMapper();
334 if (IOMapper::gSystem
) {
335 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
336 return (UInt8
) ml_phys_read_byte_64(addr
);
339 return (UInt8
) ml_phys_read_byte((vm_offset_t
) address
);
342 UInt16
IOMappedRead16(IOPhysicalAddress address
)
344 IOMapper::checkForSystemMapper();
346 if (IOMapper::gSystem
) {
347 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
348 return (UInt16
) ml_phys_read_half_64(addr
);
351 return (UInt16
) ml_phys_read_half((vm_offset_t
) address
);
354 UInt32
IOMappedRead32(IOPhysicalAddress address
)
356 IOMapper::checkForSystemMapper();
358 if (IOMapper::gSystem
) {
359 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
360 return (UInt32
) ml_phys_read_word_64(addr
);
363 return (UInt32
) ml_phys_read_word((vm_offset_t
) address
);
366 UInt64
IOMappedRead64(IOPhysicalAddress address
)
368 IOMapper::checkForSystemMapper();
370 if (IOMapper::gSystem
) {
371 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
372 return (UInt64
) ml_phys_read_double_64(addr
);
375 return (UInt64
) ml_phys_read_double((vm_offset_t
) address
);
378 void IOMappedWrite8(IOPhysicalAddress address
, UInt8 value
)
380 IOMapper::checkForSystemMapper();
382 if (IOMapper::gSystem
) {
383 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
384 ml_phys_write_byte_64(addr
, value
);
387 ml_phys_write_byte((vm_offset_t
) address
, value
);
390 void IOMappedWrite16(IOPhysicalAddress address
, UInt16 value
)
392 IOMapper::checkForSystemMapper();
394 if (IOMapper::gSystem
) {
395 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
396 ml_phys_write_half_64(addr
, value
);
399 ml_phys_write_half((vm_offset_t
) address
, value
);
402 void IOMappedWrite32(IOPhysicalAddress address
, UInt32 value
)
404 IOMapper::checkForSystemMapper();
406 if (IOMapper::gSystem
) {
407 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
408 ml_phys_write_word_64(addr
, value
);
411 ml_phys_write_word((vm_offset_t
) address
, value
);
414 void IOMappedWrite64(IOPhysicalAddress address
, UInt64 value
)
416 IOMapper::checkForSystemMapper();
418 if (IOMapper::gSystem
) {
419 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
420 ml_phys_write_double_64(addr
, value
);
423 ml_phys_write_double((vm_offset_t
) address
, value
);