1/*
2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
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>
33
34__BEGIN_DECLS
35extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
36__END_DECLS
37
38#define super IOService
39OSDefineMetaClassAndAbstractStructors(IOMapper, IOService);
40
41OSMetaClassDefineReservedUsed(IOMapper, 0);
42OSMetaClassDefineReservedUsed(IOMapper, 1);
43OSMetaClassDefineReservedUsed(IOMapper, 2);
44OSMetaClassDefineReservedUsed(IOMapper, 3);
45OSMetaClassDefineReservedUnused(IOMapper, 4);
46OSMetaClassDefineReservedUnused(IOMapper, 5);
47OSMetaClassDefineReservedUnused(IOMapper, 6);
48OSMetaClassDefineReservedUnused(IOMapper, 7);
49OSMetaClassDefineReservedUnused(IOMapper, 8);
50OSMetaClassDefineReservedUnused(IOMapper, 9);
51OSMetaClassDefineReservedUnused(IOMapper, 10);
52OSMetaClassDefineReservedUnused(IOMapper, 11);
53OSMetaClassDefineReservedUnused(IOMapper, 12);
54OSMetaClassDefineReservedUnused(IOMapper, 13);
55OSMetaClassDefineReservedUnused(IOMapper, 14);
56OSMetaClassDefineReservedUnused(IOMapper, 15);
57
58IOMapper * IOMapper::gSystem = (IOMapper *) IOMapper::kUnknown;
59
60class IOMapperLock {
61    IOLock *fWaitLock;
62public:
63    IOMapperLock() { fWaitLock = IOLockAlloc(); };
64    ~IOMapperLock() { IOLockFree(fWaitLock); };
65
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); };
70};
71
72static IOMapperLock sMapperLock;
73
74bool IOMapper::start(IOService *provider)
75{
76    OSObject * obj;
77    if (!super::start(provider))
78        return false;
79
80    if (!initHardware(provider))
81        return false;
82
83    if (fIsSystem) {
84        sMapperLock.lock();
85        IOMapper::gSystem = this;
86        sMapperLock.wakeup(&IOMapper::gSystem);
87        sMapperLock.unlock();
88    }
89
90    if (provider)
91    {
92    	obj = provider->getProperty("iommu-id");
93	if (!obj)
94	    obj = provider->getProperty("AAPL,phandle");
95	if (obj)
96	    setProperty(gIOMapperIDKey, obj);
97    }
98    return true;
99}
100
101bool IOMapper::allocTable(IOByteCount size)
102{
103    assert(!fTable);
104
105    fTableSize = size;
106    fTableHandle = NewARTTable(size, &fTable, &fTablePhys);
107    return fTableHandle != 0;
108}
109
110void IOMapper::free()
111{
112    if (fTableHandle) {
113        FreeARTTable(fTableHandle, fTableSize);
114        fTableHandle = 0;
115    }
116
117    super::free();
118}
119
120void IOMapper::setMapperRequired(bool hasMapper)
121{
122    if (hasMapper)
123        IOMapper::gSystem = (IOMapper *) kHasMapper;
124    else {
125        sMapperLock.lock();
126        IOMapper::gSystem = (IOMapper *) kNoMapper;
127        sMapperLock.unlock();
128        sMapperLock.wakeup(&IOMapper::gSystem);
129    }
130}
131
132void IOMapper::waitForSystemMapper()
133{
134    sMapperLock.lock();
135    while ((uintptr_t) IOMapper::gSystem & kWaitMask)
136    {
137		OSReportWithBacktrace("waitForSystemMapper");
138        sMapperLock.sleep(&IOMapper::gSystem);
139    }
140    sMapperLock.unlock();
141}
142
143IOMapper * IOMapper::copyMapperForDevice(IOService * device)
144{
145    OSObject * obj;
146    IOMapper * mapper;
147    OSDictionary * matching;
148
149    obj = device->copyProperty("iommu-parent");
150    if (!obj)
151	return (NULL);
152
153    if ((mapper = OSDynamicCast(IOMapper, obj)))
154	return (mapper);
155
156    matching = IOService::propertyMatching(gIOMapperIDKey, obj);
157    if (matching)
158    {
159	mapper = OSDynamicCast(IOMapper, IOService::waitForMatchingService(matching));
160    	matching->release();
161    }
162    if (mapper)
163	device->setProperty("iommu-parent", mapper);
164    else
165	obj->release();
166
167    return (mapper);
168}
169
170ppnum_t IOMapper::iovmAllocDMACommand(IODMACommand * command, IOItemCount pageCount)
171{
172    return (0);
173}
174
175void IOMapper::iovmFreeDMACommand(IODMACommand * command,
176				  ppnum_t addr, IOItemCount pageCount)
177{
178}
179
180ppnum_t IOMapper::iovmMapMemory(
181    			  OSObject                    * memory,   // dma command or iomd
182			  ppnum_t                       offsetPage,
183			  ppnum_t                       pageCount,
184			  uint32_t                      options,
185			  upl_page_info_t             * pageList,
186			  const IODMAMapSpecification * mapSpecification)
187{
188    return (0);
189}
190
191void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
192                            ppnum_t *pageList, IOItemCount pageCount)
193{
194    while (pageCount--)
195        iovmInsert(addr, offset++, *pageList++);
196}
197
198void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
199                            upl_page_info_t *pageList, IOItemCount pageCount)
200{
201    for (IOItemCount i = 0; i < pageCount; i++)
202        iovmInsert(addr, offset + i, pageList[i].phys_addr);
203}
204
205OSData * IOMapper::
206NewARTTable(IOByteCount size, void ** virtAddrP, ppnum_t *physAddrP)
207{
208    if (!virtAddrP || !physAddrP)
209	return 0;
210
211    kern_return_t kr;
212    vm_address_t address;
213
214    size = round_page(size);
215    kr = kmem_alloc_contig(kernel_map, &address, size, PAGE_MASK, 0 /*max_pnum*/, 0 /*pnum_mask*/, false);
216    if (kr)
217        return 0;
218
219    ppnum_t pagenum = pmap_find_phys(kernel_pmap, (addr64_t) address);
220    if (pagenum)
221	*physAddrP = pagenum;
222    else {
223	FreeARTTable((OSData *) address, size);
224	address = 0;
225    }
226
227    *virtAddrP = (void *) address;
228
229    return (OSData *) address;
230}
231
232void IOMapper::FreeARTTable(OSData *artHandle, IOByteCount size)
233{
234    vm_address_t address = (vm_address_t) artHandle;
235
236    size = round_page(size);
237    kmem_free(kernel_map, address, size);	// Just panic if address is 0
238}
239
240bool IOMapper::getBypassMask(addr64_t *maskP) const
241{
242    return false;
243}
244
245__BEGIN_DECLS
246
247// These are C accessors to the system mapper for non-IOKit clients
248ppnum_t IOMapperIOVMAlloc(unsigned pages)
249{
250    IOMapper::checkForSystemMapper();
251
252    if (IOMapper::gSystem)
253        return IOMapper::gSystem->iovmAlloc((IOItemCount) pages);
254    else
255        return 0;
256}
257
258void IOMapperIOVMFree(ppnum_t addr, unsigned pages)
259{
260    if (IOMapper::gSystem)
261        IOMapper::gSystem->iovmFree(addr, (IOItemCount) pages);
262}
263
264ppnum_t IOMapperInsertPage(ppnum_t addr, unsigned offset, ppnum_t page)
265{
266    if (IOMapper::gSystem) {
267		if (!addr) panic("!addr");
268        IOMapper::gSystem->iovmInsert(addr, (IOItemCount) offset, page);
269        return addr + offset;
270    }
271    else
272        return page;
273}
274
275void IOMapperInsertPPNPages(ppnum_t addr, unsigned offset,
276                            ppnum_t *pageList, unsigned pageCount)
277{
278    if (!IOMapper::gSystem)
279        panic("IOMapperInsertPPNPages no system mapper");
280    else
281        assert(!((vm_address_t) IOMapper::gSystem & 3));
282
283    IOMapper::gSystem->
284        iovmInsert(addr, (IOItemCount) offset, pageList, pageCount);
285}
286
287void IOMapperInsertUPLPages(ppnum_t addr, unsigned offset,
288                            upl_page_info_t *pageList, unsigned pageCount)
289{
290    if (!IOMapper::gSystem)
291        panic("IOMapperInsertUPLPages no system mapper");
292    else
293        assert(!((vm_address_t) IOMapper::gSystem & 3));
294
295    IOMapper::gSystem->iovmInsert(addr,
296                                 (IOItemCount) offset,
297                                  pageList,
298                                  (IOItemCount) pageCount);
299}
300
301/////////////////////////////////////////////////////////////////////////////
302//
303//
304//	IOLib.h APIs
305//
306//
307/////////////////////////////////////////////////////////////////////////////
308
309#include <machine/machine_routines.h>
310
311UInt8 IOMappedRead8(IOPhysicalAddress address)
312{
313    IOMapper::checkForSystemMapper();
314
315    if (IOMapper::gSystem) {
316        addr64_t addr = IOMapper::gSystem->mapAddr(address);
317        return (UInt8) ml_phys_read_byte_64(addr);
318    }
319    else
320        return (UInt8) ml_phys_read_byte((vm_offset_t) address);
321}
322
323UInt16 IOMappedRead16(IOPhysicalAddress address)
324{
325    IOMapper::checkForSystemMapper();
326
327    if (IOMapper::gSystem) {
328        addr64_t addr = IOMapper::gSystem->mapAddr(address);
329        return (UInt16) ml_phys_read_half_64(addr);
330    }
331    else
332        return (UInt16) ml_phys_read_half((vm_offset_t) address);
333}
334
335UInt32 IOMappedRead32(IOPhysicalAddress address)
336{
337    IOMapper::checkForSystemMapper();
338
339    if (IOMapper::gSystem) {
340        addr64_t addr = IOMapper::gSystem->mapAddr(address);
341	return (UInt32) ml_phys_read_word_64(addr);
342    }
343    else
344        return (UInt32) ml_phys_read_word((vm_offset_t) address);
345}
346
347UInt64 IOMappedRead64(IOPhysicalAddress address)
348{
349    IOMapper::checkForSystemMapper();
350
351    if (IOMapper::gSystem) {
352        addr64_t addr = IOMapper::gSystem->mapAddr(address);
353        return (UInt64) ml_phys_read_double_64(addr);
354    }
355    else
356        return (UInt64) ml_phys_read_double((vm_offset_t) address);
357}
358
359void IOMappedWrite8(IOPhysicalAddress address, UInt8 value)
360{
361    IOMapper::checkForSystemMapper();
362
363    if (IOMapper::gSystem) {
364        addr64_t addr = IOMapper::gSystem->mapAddr(address);
365        ml_phys_write_byte_64(addr, value);
366    }
367    else
368        ml_phys_write_byte((vm_offset_t) address, value);
369}
370
371void IOMappedWrite16(IOPhysicalAddress address, UInt16 value)
372{
373    IOMapper::checkForSystemMapper();
374
375    if (IOMapper::gSystem) {
376        addr64_t addr = IOMapper::gSystem->mapAddr(address);
377        ml_phys_write_half_64(addr, value);
378    }
379    else
380        ml_phys_write_half((vm_offset_t) address, value);
381}
382
383void IOMappedWrite32(IOPhysicalAddress address, UInt32 value)
384{
385    IOMapper::checkForSystemMapper();
386
387    if (IOMapper::gSystem) {
388        addr64_t addr = IOMapper::gSystem->mapAddr(address);
389        ml_phys_write_word_64(addr, value);
390    }
391    else
392        ml_phys_write_word((vm_offset_t) address, value);
393}
394
395void IOMappedWrite64(IOPhysicalAddress address, UInt64 value)
396{
397    IOMapper::checkForSystemMapper();
398
399    if (IOMapper::gSystem) {
400        addr64_t addr = IOMapper::gSystem->mapAddr(address);
401        ml_phys_write_double_64(addr, value);
402    }
403    else
404        ml_phys_write_double((vm_offset_t) address, value);
405}
406
407__END_DECLS
408