xref: /netbsd-src/sys/arch/arm/apple/apple_dart.c (revision b5511178647c2b729885643786d61219695e9788)
1*b5511178Sjmcneill /* $NetBSD: apple_dart.c,v 1.5 2023/02/24 11:19:15 jmcneill Exp $ */
2f6a78933Sskrll /*	$OpenBSD: apldart.c,v 1.10 2022/02/27 17:36:52 kettenis Exp $	*/
3db7e12daSjmcneill 
4db7e12daSjmcneill /*-
5db7e12daSjmcneill  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
6db7e12daSjmcneill  * Copyright (c) 2021 Jared McNeill <jmcneill@invisible.ca>
7db7e12daSjmcneill  *
8db7e12daSjmcneill  * Permission to use, copy, modify, and distribute this software for any
9db7e12daSjmcneill  * purpose with or without fee is hereby granted, provided that the above
10db7e12daSjmcneill  * copyright notice and this permission notice appear in all copies.
11db7e12daSjmcneill  *
12db7e12daSjmcneill  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13db7e12daSjmcneill  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14db7e12daSjmcneill  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15db7e12daSjmcneill  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16db7e12daSjmcneill  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17db7e12daSjmcneill  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18db7e12daSjmcneill  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19db7e12daSjmcneill  */
20db7e12daSjmcneill 
21db7e12daSjmcneill //#define APPLE_DART_DEBUG
22db7e12daSjmcneill 
23db7e12daSjmcneill #include <sys/cdefs.h>
24*b5511178Sjmcneill __KERNEL_RCSID(0, "$NetBSD: apple_dart.c,v 1.5 2023/02/24 11:19:15 jmcneill Exp $");
25db7e12daSjmcneill 
26db7e12daSjmcneill #include <sys/param.h>
27db7e12daSjmcneill #include <sys/bus.h>
28db7e12daSjmcneill #include <sys/device.h>
29db7e12daSjmcneill #include <sys/intr.h>
30db7e12daSjmcneill #include <sys/kernel.h>
31db7e12daSjmcneill #include <sys/systm.h>
32db7e12daSjmcneill #include <sys/kmem.h>
33db7e12daSjmcneill #include <sys/vmem.h>
34db7e12daSjmcneill 
35db7e12daSjmcneill #include <arm/cpufunc.h>
36db7e12daSjmcneill 
37db7e12daSjmcneill #include <dev/fdt/fdtvar.h>
38f6a78933Sskrll /*
39f6a78933Sskrll  * This driver largely ignores stream IDs and simply uses a single
40f6a78933Sskrll  * translation table for all the devices that it serves.  This is good
41f6a78933Sskrll  * enough for the PCIe host bridge that serves the on-board devices on
42f6a78933Sskrll  * the current generation Apple Silicon Macs as these only have a
43f6a78933Sskrll  * single PCIe device behind each DART.
44f6a78933Sskrll  */
45db7e12daSjmcneill 
46db7e12daSjmcneill /*
47db7e12daSjmcneill  * DART registers
48db7e12daSjmcneill  */
49f6a78933Sskrll #define	DART_PARAMS2		0x0004
50f6a78933Sskrll #define	 DART_PARAMS2_BYPASS_SUPPORT	__BIT(0)
51db7e12daSjmcneill #define	DART_TLB_OP		0x0020
52db7e12daSjmcneill #define	 DART_TLB_OP_BUSY		__BIT(2)
53f6a78933Sskrll #define	 DART_TLB_OP_FLUSH		__BIT(20)
54db7e12daSjmcneill #define	DART_TLB_OP_SIDMASK	0x0034
55db7e12daSjmcneill #define	DART_ERR_STATUS		0x0040
56f6a78933Sskrll #define	 DART_ERR_FLAG		__BIT(31)
57f6a78933Sskrll #define	 DART_ERR_STREAM_MASK	__BITS(27, 24)
58f6a78933Sskrll #define	 DART_ERR_CODE_MASK	__BITS(11, 0)
59f6a78933Sskrll #define	 DART_ERR_READ_FAULT	__BIT(4)
60f6a78933Sskrll #define	 DART_ERR_WRITE_FAULT	__BIT(3)
61f6a78933Sskrll #define	 DART_ERR_NOPTE		__BIT(2)
62f6a78933Sskrll #define	 DART_ERR_NOPMD		__BIT(1)
63f6a78933Sskrll #define	 DART_ERR_NOTTBR	__BIT(0)
64db7e12daSjmcneill #define	DART_ERR_ADDRL		0x0050
65db7e12daSjmcneill #define	DART_ERR_ADDRH		0x0054
66f6a78933Sskrll #define	DART_CONFIG		0x0060
67f6a78933Sskrll #define	 DART_CONFIG_LOCK		__BIT(15)
68f6a78933Sskrll #define	DART_TCR(sid)		(0x0100 + (sid) * 0x4)
69f6a78933Sskrll #define	 DART_TCR_TRANSLATE_ENABLE	__BIT(7)
70f6a78933Sskrll #define	 DART_TCR_BYPASS_DART		__BIT(8)
71f6a78933Sskrll #define	 DART_TCR_BYPASS_DAPF		__BIT(12)
72db7e12daSjmcneill #define	DART_TTBR(sid, idx)	(0x0200 + (sid) * 0x10 + (idx) * 0x4)
73db7e12daSjmcneill #define	 DART_TTBR_VALID		__BIT(31)
74db7e12daSjmcneill #define	 DART_TTBR_SHIFT		12
75db7e12daSjmcneill 
76f6a78933Sskrll #define	DART_NUM_STREAMS	16
77f6a78933Sskrll #define	DART_ALL_STREAMS	((1 << DART_NUM_STREAMS) - 1)
78f6a78933Sskrll 
79db7e12daSjmcneill #define	DART_APERTURE_START	0x00100000
80db7e12daSjmcneill #define	DART_APERTURE_SIZE	0x3fe00000
81db7e12daSjmcneill #define	DART_PAGE_SIZE		16384
82db7e12daSjmcneill #define	DART_PAGE_MASK		(DART_PAGE_SIZE - 1)
83db7e12daSjmcneill 
84f6a78933Sskrll /*
85f6a78933Sskrll  * Some hardware (e.g. bge(4)) will always use (aligned) 64-bit memory
86f6a78933Sskrll  * access.  To make sure this doesn't fault, round the subpage limits
87f6a78933Sskrll  * down and up accordingly.
88f6a78933Sskrll  */
89f6a78933Sskrll #define	DART_OFFSET_MASK	7
90f6a78933Sskrll 
91f6a78933Sskrll #define	DART_L1_TABLE		0x3
92db7e12daSjmcneill #define	DART_L2_INVAL		0x0
93f6a78933Sskrll #define	DART_L2_VALID		__BIT(0)
94f6a78933Sskrll #define	DART_L2_FULL_PAGE	__BIT(1)
95f6a78933Sskrll 
96f6a78933Sskrll #define	DART_L2_START_MASK	__BITS(63, 52)
97f6a78933Sskrll #define	DART_L2_END_MASK	__BITS(51, 40)
98f6a78933Sskrll #define	DART_L2_SUBPAGE(addr)	__SHIFTOUT((addr), __BITS(13, 2))
99f6a78933Sskrll #define	DART_L2_START(addr)	__SHIFTIN(DART_L2_SUBPAGE(addr), DART_L2_START_MASK)
100f6a78933Sskrll #define	DART_L2_END(addr)	__SHIFTIN(DART_L2_SUBPAGE(addr), DART_L2_END_MASK)
101db7e12daSjmcneill 
102db7e12daSjmcneill #define	DART_ROUND_PAGE(pa)	(((pa) + DART_PAGE_MASK) & ~DART_PAGE_MASK)
103db7e12daSjmcneill #define	DART_TRUNC_PAGE(pa)	((pa) & ~DART_PAGE_MASK)
104f6a78933Sskrll #define	DART_ROUND_OFFSET(pa)	(((pa) + DART_OFFSET_MASK) & ~DART_OFFSET_MASK)
105f6a78933Sskrll #define	DART_TRUNC_OFFSET(pa)	((pa) & ~DART_OFFSET_MASK)
106db7e12daSjmcneill 
107db7e12daSjmcneill static const struct device_compatible_entry compat_data[] = {
108db7e12daSjmcneill 	{ .compat = "apple,dart-m1",		.value = 16 },
109f6a78933Sskrll 	{ .compat = "apple,t8103-dart",		.value = 16 },
110db7e12daSjmcneill 	DEVICE_COMPAT_EOL
111db7e12daSjmcneill };
112db7e12daSjmcneill 
113db7e12daSjmcneill static struct arm32_dma_range apple_dart_dma_ranges[] = {
114db7e12daSjmcneill 	[0] = {
115db7e12daSjmcneill 		.dr_sysbase = 0,
116db7e12daSjmcneill 		.dr_busbase = 0,
117db7e12daSjmcneill 		.dr_len = UINTPTR_MAX,
118db7e12daSjmcneill 		.dr_flags = _BUS_DMAMAP_COHERENT,
119db7e12daSjmcneill 	}
120db7e12daSjmcneill };
121db7e12daSjmcneill 
122db7e12daSjmcneill struct apple_dart_map_state {
123db7e12daSjmcneill 	bus_addr_t ams_dva;
124db7e12daSjmcneill 	bus_size_t ams_len;
125db7e12daSjmcneill };
126db7e12daSjmcneill 
127db7e12daSjmcneill struct apple_dart_dma {
128db7e12daSjmcneill 	bus_dmamap_t dma_map;
129db7e12daSjmcneill 	bus_dma_segment_t dma_seg;
130db7e12daSjmcneill 	bus_size_t dma_size;
131db7e12daSjmcneill 	void *dma_kva;
132db7e12daSjmcneill };
133db7e12daSjmcneill 
134db7e12daSjmcneill #define	DART_DMA_MAP(_dma)	((_dma)->dma_map)
135db7e12daSjmcneill #define	DART_DMA_LEN(_dma)	((_dma)->dma_size)
136db7e12daSjmcneill #define	DART_DMA_DVA(_dma)	((_dma)->dma_map->dm_segs[0].ds_addr)
137db7e12daSjmcneill #define	DART_DMA_KVA(_dma)	((_dma)->dma_kva)
138db7e12daSjmcneill 
139db7e12daSjmcneill struct apple_dart_softc {
140db7e12daSjmcneill 	device_t sc_dev;
141db7e12daSjmcneill 	int sc_phandle;
142db7e12daSjmcneill 	bus_space_tag_t sc_bst;
143db7e12daSjmcneill 	bus_space_handle_t sc_bsh;
144db7e12daSjmcneill 	bus_dma_tag_t sc_dmat;
145db7e12daSjmcneill 
146db7e12daSjmcneill 	uint64_t sc_sid_mask;
147db7e12daSjmcneill 	u_int sc_nsid;
148db7e12daSjmcneill 
149db7e12daSjmcneill 	vmem_t *sc_dvamap;
150db7e12daSjmcneill 
151db7e12daSjmcneill 	struct apple_dart_dma *sc_l1;
152db7e12daSjmcneill 	struct apple_dart_dma **sc_l2;
153db7e12daSjmcneill 	u_int sc_nl2;
154db7e12daSjmcneill 
155db7e12daSjmcneill 	struct arm32_bus_dma_tag sc_bus_dmat;
156db7e12daSjmcneill };
157db7e12daSjmcneill 
158db7e12daSjmcneill #define DART_READ(sc, reg) \
159db7e12daSjmcneill 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
160db7e12daSjmcneill #define	DART_WRITE(sc, reg, val) \
161db7e12daSjmcneill 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
162db7e12daSjmcneill 
163db7e12daSjmcneill static void
apple_dart_flush_tlb(struct apple_dart_softc * sc)164db7e12daSjmcneill apple_dart_flush_tlb(struct apple_dart_softc *sc)
165db7e12daSjmcneill {
166db7e12daSjmcneill 	dsb(sy);
167db7e12daSjmcneill 	isb();
168db7e12daSjmcneill 
169db7e12daSjmcneill 	DART_WRITE(sc, DART_TLB_OP_SIDMASK, sc->sc_sid_mask);
170db7e12daSjmcneill 	DART_WRITE(sc, DART_TLB_OP, DART_TLB_OP_FLUSH);
171db7e12daSjmcneill 	while ((DART_READ(sc, DART_TLB_OP) & DART_TLB_OP_BUSY) != 0) {
172db7e12daSjmcneill 		__asm volatile ("yield" ::: "memory");
173db7e12daSjmcneill 	}
174db7e12daSjmcneill }
175db7e12daSjmcneill 
176db7e12daSjmcneill static struct apple_dart_dma *
apple_dart_dma_alloc(bus_dma_tag_t dmat,bus_size_t size,bus_size_t align)177db7e12daSjmcneill apple_dart_dma_alloc(bus_dma_tag_t dmat, bus_size_t size, bus_size_t align)
178db7e12daSjmcneill {
179db7e12daSjmcneill 	struct apple_dart_dma *dma;
180db7e12daSjmcneill 	int nsegs, error;
181db7e12daSjmcneill 
182db7e12daSjmcneill 	dma = kmem_zalloc(sizeof(*dma), KM_SLEEP);
183db7e12daSjmcneill 	dma->dma_size = size;
184db7e12daSjmcneill 
185db7e12daSjmcneill 	error = bus_dmamem_alloc(dmat, size, align, 0, &dma->dma_seg, 1,
186db7e12daSjmcneill 	    &nsegs, BUS_DMA_WAITOK);
187db7e12daSjmcneill 	if (error != 0) {
188db7e12daSjmcneill 		goto destroy;
189db7e12daSjmcneill 	}
190db7e12daSjmcneill 
191db7e12daSjmcneill 	error = bus_dmamem_map(dmat, &dma->dma_seg, nsegs, size,
192db7e12daSjmcneill 	    &dma->dma_kva, BUS_DMA_WAITOK | BUS_DMA_NOCACHE);
193db7e12daSjmcneill 	if (error != 0) {
194db7e12daSjmcneill 		goto free;
195db7e12daSjmcneill 	}
196db7e12daSjmcneill 
197db7e12daSjmcneill 	error = bus_dmamap_create(dmat, size, 1, size, 0,
198db7e12daSjmcneill 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &dma->dma_map);
199db7e12daSjmcneill 	if (error != 0) {
200db7e12daSjmcneill 		goto dmafree;
201db7e12daSjmcneill 	}
202db7e12daSjmcneill 
203db7e12daSjmcneill 	error = bus_dmamap_load(dmat, dma->dma_map, dma->dma_kva, size,
204db7e12daSjmcneill 	    NULL, BUS_DMA_WAITOK);
205db7e12daSjmcneill 	if (error != 0) {
206db7e12daSjmcneill 		goto unmap;
207db7e12daSjmcneill 	}
208db7e12daSjmcneill 
209db7e12daSjmcneill 	memset(dma->dma_kva, 0, size);
210db7e12daSjmcneill 
211db7e12daSjmcneill 	return dma;
212db7e12daSjmcneill 
213db7e12daSjmcneill destroy:
214db7e12daSjmcneill 	bus_dmamap_destroy(dmat, dma->dma_map);
215db7e12daSjmcneill unmap:
216db7e12daSjmcneill 	bus_dmamem_unmap(dmat, dma->dma_kva, size);
217db7e12daSjmcneill free:
218db7e12daSjmcneill 	bus_dmamem_free(dmat, &dma->dma_seg, 1);
219db7e12daSjmcneill dmafree:
220db7e12daSjmcneill 	kmem_free(dma, sizeof(*dma));
221db7e12daSjmcneill 	return NULL;
222db7e12daSjmcneill }
223db7e12daSjmcneill 
224db7e12daSjmcneill static int
apple_dart_intr(void * priv)225db7e12daSjmcneill apple_dart_intr(void *priv)
226db7e12daSjmcneill {
227db7e12daSjmcneill 	struct apple_dart_softc * const sc = priv;
228db7e12daSjmcneill 	char fdt_path[128];
229db7e12daSjmcneill 	uint64_t addr;
230db7e12daSjmcneill 	uint32_t status;
231db7e12daSjmcneill 
232db7e12daSjmcneill 	status = DART_READ(sc, DART_ERR_STATUS);
233f6a78933Sskrll 	addr  = __SHIFTIN(DART_READ(sc, DART_ERR_ADDRL), __BITS(31, 0));
234f6a78933Sskrll 	addr |= __SHIFTIN(DART_READ(sc, DART_ERR_ADDRH), __BITS(63, 32));
235db7e12daSjmcneill 	DART_WRITE(sc, DART_ERR_STATUS, status);
236db7e12daSjmcneill 
237f6a78933Sskrll 	if ((status & DART_ERR_FLAG) == 0)
238f6a78933Sskrll 		return 1;
239f6a78933Sskrll 
240f6a78933Sskrll #ifdef APPLE_DART_DEBUG
241f6a78933Sskrll 	printf("%s: status %#"PRIx32"\n", __func__, status);
242f6a78933Sskrll 	printf("%s: addrl  %#"PRIx32"\n", __func__, DART_READ(sc, DART_ERR_ADDRL));
243f6a78933Sskrll 	printf("%s: addrh  %#"PRIx32"\n", __func__, DART_READ(sc, DART_ERR_ADDRH));
244f6a78933Sskrll #endif
245f6a78933Sskrll 
246f6a78933Sskrll 	const char *reason = NULL;
247f6a78933Sskrll 	int32_t code = __SHIFTOUT(status, DART_ERR_CODE_MASK);
248f6a78933Sskrll 	switch (code) {
249f6a78933Sskrll 	case DART_ERR_NOTTBR:
250f6a78933Sskrll 	    reason = "no ttbr for address";
251f6a78933Sskrll 	    break;
252f6a78933Sskrll 	case DART_ERR_NOPMD:
253f6a78933Sskrll 	    reason = "no pmd for address";
254f6a78933Sskrll 	    break;
255f6a78933Sskrll 	case DART_ERR_NOPTE:
256f6a78933Sskrll 	    reason = "no pte for address";
257f6a78933Sskrll 	    break;
258f6a78933Sskrll 	case DART_ERR_WRITE_FAULT:
259f6a78933Sskrll 	    reason = "write fault";
260f6a78933Sskrll 	    break;
261f6a78933Sskrll 	case DART_ERR_READ_FAULT:
262f6a78933Sskrll 	    reason = "read fault";
263f6a78933Sskrll 	    break;
264f6a78933Sskrll 	}
265db7e12daSjmcneill 	fdtbus_get_path(sc->sc_phandle, fdt_path, sizeof(fdt_path));
266db7e12daSjmcneill 
267f6a78933Sskrll 	printf("%s (%s): error addr 0x%016lx status 0x%08x: %s\n",
268f6a78933Sskrll 	    device_xname(sc->sc_dev), fdt_path, addr, status, reason);
269db7e12daSjmcneill 
270db7e12daSjmcneill 	return 1;
271db7e12daSjmcneill }
272db7e12daSjmcneill 
273db7e12daSjmcneill static volatile uint64_t *
apple_dart_lookup_tte(struct apple_dart_softc * sc,bus_addr_t dva)274db7e12daSjmcneill apple_dart_lookup_tte(struct apple_dart_softc *sc, bus_addr_t dva)
275db7e12daSjmcneill {
276db7e12daSjmcneill 	int idx = dva / DART_PAGE_SIZE;
277db7e12daSjmcneill 	int l2_idx = idx / (DART_PAGE_SIZE / sizeof(uint64_t));
278db7e12daSjmcneill 	int tte_idx = idx % (DART_PAGE_SIZE / sizeof(uint64_t));
279f6a78933Sskrll 	volatile uint64_t *l2 = DART_DMA_KVA(sc->sc_l2[l2_idx]);
280db7e12daSjmcneill 
281db7e12daSjmcneill 	return &l2[tte_idx];
282db7e12daSjmcneill }
283db7e12daSjmcneill 
284db7e12daSjmcneill static void
apple_dart_unload_map(struct apple_dart_softc * sc,bus_dmamap_t map)285db7e12daSjmcneill apple_dart_unload_map(struct apple_dart_softc *sc, bus_dmamap_t map)
286db7e12daSjmcneill {
287db7e12daSjmcneill 	struct apple_dart_map_state *ams = map->_dm_iommu;
288db7e12daSjmcneill 	volatile uint64_t *tte;
289db7e12daSjmcneill 	int seg;
290db7e12daSjmcneill 
291db7e12daSjmcneill 	/* For each segment */
292db7e12daSjmcneill 	for (seg = 0; seg < map->dm_nsegs; seg++) {
293db7e12daSjmcneill 		u_long len, dva;
294db7e12daSjmcneill 
295db7e12daSjmcneill 		if (ams[seg].ams_len == 0) {
296db7e12daSjmcneill 			continue;
297db7e12daSjmcneill 		}
298db7e12daSjmcneill 
299db7e12daSjmcneill 		dva = ams[seg].ams_dva;
300db7e12daSjmcneill 		len = ams[seg].ams_len;
301db7e12daSjmcneill 
302db7e12daSjmcneill 		while (len > 0) {
303db7e12daSjmcneill 			tte = apple_dart_lookup_tte(sc, dva);
304db7e12daSjmcneill 			*tte = DART_L2_INVAL;
305db7e12daSjmcneill 
306db7e12daSjmcneill 			dva += DART_PAGE_SIZE;
307db7e12daSjmcneill 			len -= DART_PAGE_SIZE;
308db7e12daSjmcneill 		}
309db7e12daSjmcneill 
310db7e12daSjmcneill 		vmem_xfree(sc->sc_dvamap, ams[seg].ams_dva, ams[seg].ams_len);
311db7e12daSjmcneill 
312db7e12daSjmcneill 		ams[seg].ams_dva = 0;
313db7e12daSjmcneill 		ams[seg].ams_len = 0;
314db7e12daSjmcneill 	}
315db7e12daSjmcneill 
316db7e12daSjmcneill 	apple_dart_flush_tlb(sc);
317db7e12daSjmcneill }
318db7e12daSjmcneill 
319db7e12daSjmcneill static int
apple_dart_load_map(struct apple_dart_softc * sc,bus_dmamap_t map)320db7e12daSjmcneill apple_dart_load_map(struct apple_dart_softc *sc, bus_dmamap_t map)
321db7e12daSjmcneill {
322db7e12daSjmcneill 	struct apple_dart_map_state *ams = map->_dm_iommu;
323db7e12daSjmcneill 	volatile uint64_t *tte;
324db7e12daSjmcneill 	int seg, error;
325db7e12daSjmcneill 
326db7e12daSjmcneill 	/* For each segment */
327db7e12daSjmcneill 	for (seg = 0; seg < map->dm_nsegs; seg++) {
328db7e12daSjmcneill 		paddr_t pa = map->dm_segs[seg]._ds_paddr;
329db7e12daSjmcneill 		psize_t off = pa - DART_TRUNC_PAGE(pa);
330db7e12daSjmcneill 		u_long len, dva;
331db7e12daSjmcneill 
332db7e12daSjmcneill 		len = DART_ROUND_PAGE(map->dm_segs[seg].ds_len + off);
333db7e12daSjmcneill 
334db7e12daSjmcneill #ifdef APPLE_DART_DEBUG
335db7e12daSjmcneill 		device_printf(sc->sc_dev, "load pa=%#lx off=%lu len=%lu ",
336db7e12daSjmcneill 		    pa, off, len);
337db7e12daSjmcneill #endif
338db7e12daSjmcneill 
339db7e12daSjmcneill 		error = vmem_xalloc(sc->sc_dvamap, len, DART_PAGE_SIZE, 0,
340db7e12daSjmcneill 		    0, VMEM_ADDR_MIN, VMEM_ADDR_MAX, VM_BESTFIT|VM_NOSLEEP,
341db7e12daSjmcneill 		    &dva);
342db7e12daSjmcneill 		if (error != 0) {
343db7e12daSjmcneill 			apple_dart_unload_map(sc, map);
344db7e12daSjmcneill #ifdef APPLE_DART_DEBUG
345db7e12daSjmcneill 			printf("error=%d\n", error);
346db7e12daSjmcneill #endif
347db7e12daSjmcneill 			return error;
348db7e12daSjmcneill 		}
349db7e12daSjmcneill 
350db7e12daSjmcneill #ifdef APPLE_DART_DEBUG
351db7e12daSjmcneill 		printf("dva=%#lx\n", dva);
352db7e12daSjmcneill #endif
353db7e12daSjmcneill 
354db7e12daSjmcneill 		ams[seg].ams_dva = dva;
355db7e12daSjmcneill 		ams[seg].ams_len = len;
356db7e12daSjmcneill 
357db7e12daSjmcneill 		map->dm_segs[seg].ds_addr = dva + off;
358db7e12daSjmcneill 
359db7e12daSjmcneill 		pa = DART_TRUNC_PAGE(pa);
360f6a78933Sskrll 		paddr_t start = DART_TRUNC_OFFSET(off);
361f6a78933Sskrll 		paddr_t end = DART_PAGE_MASK;
362db7e12daSjmcneill 		while (len > 0) {
363db7e12daSjmcneill 			tte = apple_dart_lookup_tte(sc, dva);
364f6a78933Sskrll 			if (len < DART_PAGE_SIZE)
365f6a78933Sskrll 				end = DART_ROUND_OFFSET(len) - 1;
366db7e12daSjmcneill 
367f6a78933Sskrll 			*tte = pa | DART_L2_VALID |
368f6a78933Sskrll 			    DART_L2_START(start) | DART_L2_END(end);
369f6a78933Sskrll #ifdef APPLE_DART_DEBUG
370f6a78933Sskrll 			printf("tte %p = %"PRIx64"\n", tte, *tte);
371f6a78933Sskrll #endif
372db7e12daSjmcneill 			pa += DART_PAGE_SIZE;
373db7e12daSjmcneill 			dva += DART_PAGE_SIZE;
374db7e12daSjmcneill 			len -= DART_PAGE_SIZE;
375f6a78933Sskrll 			start = 0;
376db7e12daSjmcneill 		}
377db7e12daSjmcneill 	}
378db7e12daSjmcneill 
379db7e12daSjmcneill 	apple_dart_flush_tlb(sc);
380db7e12daSjmcneill 
381db7e12daSjmcneill 	return 0;
382db7e12daSjmcneill }
383db7e12daSjmcneill 
384db7e12daSjmcneill static int
apple_dart_dmamap_create(bus_dma_tag_t t,bus_size_t size,int nsegments,bus_size_t maxsegsz,bus_size_t boundary,int flags,bus_dmamap_t * dmamap)385db7e12daSjmcneill apple_dart_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
386db7e12daSjmcneill     bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamap)
387db7e12daSjmcneill {
388db7e12daSjmcneill 	struct apple_dart_softc *sc = t->_cookie;
389db7e12daSjmcneill 	struct apple_dart_map_state *ams;
390db7e12daSjmcneill 	bus_dmamap_t map;
391db7e12daSjmcneill 	int error;
392db7e12daSjmcneill 
393db7e12daSjmcneill 	error = sc->sc_dmat->_dmamap_create(sc->sc_dmat, size, nsegments,
394db7e12daSjmcneill 	    maxsegsz, boundary, flags, &map);
395db7e12daSjmcneill 	if (error != 0) {
396db7e12daSjmcneill 		return error;
397db7e12daSjmcneill 	}
398db7e12daSjmcneill 
399db7e12daSjmcneill 	ams = kmem_zalloc(map->_dm_segcnt * sizeof(*ams),
400db7e12daSjmcneill 	    (flags & BUS_DMA_NOWAIT) != 0 ? KM_NOSLEEP : KM_SLEEP);
401db7e12daSjmcneill 	if (ams == NULL) {
402db7e12daSjmcneill 		sc->sc_dmat->_dmamap_destroy(sc->sc_dmat, map);
403db7e12daSjmcneill 		return ENOMEM;
404db7e12daSjmcneill 	}
405db7e12daSjmcneill 
406db7e12daSjmcneill 	map->_dm_iommu = ams;
407db7e12daSjmcneill 	*dmamap = map;
408db7e12daSjmcneill 	return 0;
409db7e12daSjmcneill }
410db7e12daSjmcneill 
411db7e12daSjmcneill static void
apple_dart_dmamap_destroy(bus_dma_tag_t t,bus_dmamap_t map)412db7e12daSjmcneill apple_dart_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
413db7e12daSjmcneill {
414db7e12daSjmcneill 	struct apple_dart_softc *sc = t->_cookie;
415db7e12daSjmcneill 	struct apple_dart_map_state *ams = map->_dm_iommu;
416db7e12daSjmcneill 
417db7e12daSjmcneill 	kmem_free(ams, map->_dm_segcnt * sizeof(*ams));
418db7e12daSjmcneill 	sc->sc_dmat->_dmamap_destroy(sc->sc_dmat, map);
419db7e12daSjmcneill }
420db7e12daSjmcneill 
421db7e12daSjmcneill static int
apple_dart_dmamap_load(bus_dma_tag_t t,bus_dmamap_t map,void * buf,size_t buflen,struct proc * p,int flags)422db7e12daSjmcneill apple_dart_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
423db7e12daSjmcneill     size_t buflen, struct proc *p, int flags)
424db7e12daSjmcneill {
425db7e12daSjmcneill 	struct apple_dart_softc *sc = t->_cookie;
426db7e12daSjmcneill 	int error;
427db7e12daSjmcneill 
428db7e12daSjmcneill 	error = sc->sc_dmat->_dmamap_load(sc->sc_dmat, map,
429db7e12daSjmcneill 	    buf, buflen, p, flags);
430db7e12daSjmcneill 	if (error != 0) {
431db7e12daSjmcneill 		return error;
432db7e12daSjmcneill 	}
433db7e12daSjmcneill 
434db7e12daSjmcneill 	error = apple_dart_load_map(sc, map);
435db7e12daSjmcneill 	if (error != 0) {
436db7e12daSjmcneill 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
437db7e12daSjmcneill 	}
438db7e12daSjmcneill 
439db7e12daSjmcneill 	return error;
440db7e12daSjmcneill }
441db7e12daSjmcneill 
442db7e12daSjmcneill static int
apple_dart_dmamap_load_mbuf(bus_dma_tag_t t,bus_dmamap_t map,struct mbuf * m,int flags)443db7e12daSjmcneill apple_dart_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
444db7e12daSjmcneill     struct mbuf *m, int flags)
445db7e12daSjmcneill {
446db7e12daSjmcneill 	struct apple_dart_softc *sc = t->_cookie;
447db7e12daSjmcneill 	int error;
448db7e12daSjmcneill 
449db7e12daSjmcneill 	error = sc->sc_dmat->_dmamap_load_mbuf(sc->sc_dmat, map,
450db7e12daSjmcneill 	    m, flags);
451db7e12daSjmcneill 	if (error != 0) {
452db7e12daSjmcneill 		return error;
453db7e12daSjmcneill 	}
454db7e12daSjmcneill 
455db7e12daSjmcneill 	error = apple_dart_load_map(sc, map);
456db7e12daSjmcneill 	if (error != 0) {
457db7e12daSjmcneill 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
458db7e12daSjmcneill 	}
459db7e12daSjmcneill 
460db7e12daSjmcneill 	return error;
461db7e12daSjmcneill }
462db7e12daSjmcneill 
463db7e12daSjmcneill static int
apple_dart_dmamap_load_uio(bus_dma_tag_t t,bus_dmamap_t map,struct uio * uio,int flags)464db7e12daSjmcneill apple_dart_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map,
465db7e12daSjmcneill     struct uio *uio, int flags)
466db7e12daSjmcneill {
467db7e12daSjmcneill 	struct apple_dart_softc *sc = t->_cookie;
468db7e12daSjmcneill 	int error;
469db7e12daSjmcneill 
470db7e12daSjmcneill 	error = sc->sc_dmat->_dmamap_load_uio(sc->sc_dmat, map,
471db7e12daSjmcneill 	    uio, flags);
472db7e12daSjmcneill 	if (error != 0) {
473db7e12daSjmcneill 		return error;
474db7e12daSjmcneill 	}
475db7e12daSjmcneill 
476db7e12daSjmcneill 	error = apple_dart_load_map(sc, map);
477db7e12daSjmcneill 	if (error != 0) {
478db7e12daSjmcneill 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
479db7e12daSjmcneill 	}
480db7e12daSjmcneill 
481db7e12daSjmcneill 	return error;
482db7e12daSjmcneill }
483db7e12daSjmcneill 
484db7e12daSjmcneill static int
apple_dart_dmamap_load_raw(bus_dma_tag_t t,bus_dmamap_t map,bus_dma_segment_t * segs,int nsegs,bus_size_t size,int flags)485db7e12daSjmcneill apple_dart_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
486db7e12daSjmcneill     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
487db7e12daSjmcneill {
488db7e12daSjmcneill 	struct apple_dart_softc *sc = t->_cookie;
489db7e12daSjmcneill 	int error;
490db7e12daSjmcneill 
491db7e12daSjmcneill 	error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map,
492db7e12daSjmcneill 	    segs, nsegs, size, flags);
493db7e12daSjmcneill 	if (error != 0) {
494db7e12daSjmcneill 		return error;
495db7e12daSjmcneill 	}
496db7e12daSjmcneill 
497db7e12daSjmcneill 	error = apple_dart_load_map(sc, map);
498db7e12daSjmcneill 	if (error != 0) {
499db7e12daSjmcneill 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
500db7e12daSjmcneill 	}
501db7e12daSjmcneill 
502db7e12daSjmcneill 	return error;
503db7e12daSjmcneill }
504db7e12daSjmcneill 
505db7e12daSjmcneill static void
apple_dart_dmamap_unload(bus_dma_tag_t t,bus_dmamap_t map)506db7e12daSjmcneill apple_dart_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
507db7e12daSjmcneill {
508db7e12daSjmcneill 	struct apple_dart_softc *sc = t->_cookie;
509db7e12daSjmcneill 
510db7e12daSjmcneill 	apple_dart_unload_map(sc, map);
511db7e12daSjmcneill 	sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
512db7e12daSjmcneill }
513db7e12daSjmcneill 
514a808ce0eSjmcneill static bus_dma_tag_t
apple_dart_iommu_map(device_t dev,const u_int * data,bus_dma_tag_t dmat)515a808ce0eSjmcneill apple_dart_iommu_map(device_t dev, const u_int *data, bus_dma_tag_t dmat)
516a808ce0eSjmcneill {
517a808ce0eSjmcneill 	struct apple_dart_softc * const sc = device_private(dev);
518a808ce0eSjmcneill 
519a808ce0eSjmcneill 	return &sc->sc_bus_dmat;
520a808ce0eSjmcneill }
521a808ce0eSjmcneill 
522a808ce0eSjmcneill const struct fdtbus_iommu_func apple_dart_iommu_funcs = {
523a808ce0eSjmcneill 	.map = apple_dart_iommu_map,
524a808ce0eSjmcneill };
525a808ce0eSjmcneill 
526db7e12daSjmcneill static int
apple_dart_match(device_t parent,cfdata_t cf,void * aux)527db7e12daSjmcneill apple_dart_match(device_t parent, cfdata_t cf, void *aux)
528db7e12daSjmcneill {
529db7e12daSjmcneill 	struct fdt_attach_args * const faa = aux;
530db7e12daSjmcneill 
531db7e12daSjmcneill 	return of_compatible_match(faa->faa_phandle, compat_data);
532db7e12daSjmcneill }
533db7e12daSjmcneill 
534db7e12daSjmcneill static void
apple_dart_attach(device_t parent,device_t self,void * aux)535db7e12daSjmcneill apple_dart_attach(device_t parent, device_t self, void *aux)
536db7e12daSjmcneill {
537db7e12daSjmcneill 	struct apple_dart_softc * const sc = device_private(self);
538db7e12daSjmcneill 	struct fdt_attach_args * const faa = aux;
539db7e12daSjmcneill 	const int phandle = faa->faa_phandle;
540db7e12daSjmcneill 	char intrstr[128];
541db7e12daSjmcneill 	volatile uint64_t *l1;
542db7e12daSjmcneill 	bus_addr_t addr;
543db7e12daSjmcneill 	bus_size_t size;
544db7e12daSjmcneill 	u_int sid, idx;
545db7e12daSjmcneill 	paddr_t pa;
546db7e12daSjmcneill 	void *ih;
547db7e12daSjmcneill 
548db7e12daSjmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
549db7e12daSjmcneill 		aprint_error(": couldn't get registers\n");
550db7e12daSjmcneill 		return;
551db7e12daSjmcneill 	}
552db7e12daSjmcneill 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
553db7e12daSjmcneill 		aprint_error(": couldn't decode interrupt\n");
554db7e12daSjmcneill 		return;
555db7e12daSjmcneill 	}
556db7e12daSjmcneill 
557db7e12daSjmcneill 	sc->sc_dev = self;
558db7e12daSjmcneill 	sc->sc_phandle = phandle;
559db7e12daSjmcneill 	sc->sc_dmat = faa->faa_dmat;
560db7e12daSjmcneill 	sc->sc_bst = faa->faa_bst;
56177a7b674Sjmcneill 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
562db7e12daSjmcneill 		aprint_error(": couldn't map registers\n");
563db7e12daSjmcneill 		return;
564db7e12daSjmcneill 	}
565db7e12daSjmcneill 
566f6a78933Sskrll 	/* Skip locked DARTs for now. */
567f6a78933Sskrll 	uint32_t config = DART_READ(sc, DART_CONFIG);
568f6a78933Sskrll 	if (config & DART_CONFIG_LOCK) {
569f6a78933Sskrll 		aprint_naive("\n");
570f6a78933Sskrll 		aprint_normal(": locked\n");
571f6a78933Sskrll 		return;
572db7e12daSjmcneill 	}
573db7e12daSjmcneill 
574f6a78933Sskrll 	/*
575f6a78933Sskrll 	 * Use bypass mode if supported.  This avoids an issue with
576f6a78933Sskrll 	 * the USB3 controllers which need mappings entered into two
577f6a78933Sskrll 	 * IOMMUs, which is somewhat difficult to implement with our
578f6a78933Sskrll 	 * current kernel interfaces.
579f6a78933Sskrll 	 */
580f6a78933Sskrll 	uint32_t params2 = DART_READ(sc, DART_PARAMS2);
581f6a78933Sskrll 	if (params2 & DART_PARAMS2_BYPASS_SUPPORT) {
582f6a78933Sskrll 		for (sid = 0; sid < DART_NUM_STREAMS; sid++) {
583f6a78933Sskrll 			DART_WRITE(sc, DART_TCR(sid),
584f6a78933Sskrll 			    DART_TCR_BYPASS_DART | DART_TCR_BYPASS_DAPF);
585f6a78933Sskrll 		}
586f6a78933Sskrll 		aprint_naive("\n");
587f6a78933Sskrll 		aprint_normal(": bypass\n");
588f6a78933Sskrll 		return;
589f6a78933Sskrll 	}
590f6a78933Sskrll 
591f6a78933Sskrll 	sc->sc_nsid = of_compatible_lookup(phandle, compat_data)->value;
592f6a78933Sskrll 	sc->sc_sid_mask = __MASK(sc->sc_nsid);
593f6a78933Sskrll 
594db7e12daSjmcneill 	aprint_naive("\n");
595db7e12daSjmcneill 	aprint_normal(": Apple DART @ %#lx/%#lx, %u SIDs (mask 0x%lx)\n",
596db7e12daSjmcneill 	    addr, size, sc->sc_nsid, sc->sc_sid_mask);
597db7e12daSjmcneill 
598db7e12daSjmcneill 	KASSERT(sc->sc_nsid == 16);
599db7e12daSjmcneill 	KASSERT(sc->sc_sid_mask == 0xffff);
600db7e12daSjmcneill 
601db7e12daSjmcneill 	sc->sc_dvamap = vmem_create(device_xname(self),
602db7e12daSjmcneill 	    DART_APERTURE_START, DART_APERTURE_SIZE, DART_PAGE_SIZE,
603db7e12daSjmcneill 	    NULL, NULL, NULL, 0, VM_SLEEP, IPL_HIGH);
604db7e12daSjmcneill 	if (sc->sc_dvamap == NULL) {
605db7e12daSjmcneill 		aprint_error_dev(self, "couldn't allocate DVA map\n");
606db7e12daSjmcneill 		return;
607db7e12daSjmcneill 	}
608db7e12daSjmcneill 
609db7e12daSjmcneill 	/* Disable translations */
610db7e12daSjmcneill 	for (sid = 0; sid < sc->sc_nsid; sid++) {
611f6a78933Sskrll 		DART_WRITE(sc, DART_TCR(sid), 0);
612db7e12daSjmcneill 	}
613db7e12daSjmcneill 
614db7e12daSjmcneill 	/* Remove page tables */
615db7e12daSjmcneill 	for (sid = 0; sid < sc->sc_nsid; sid++) {
616db7e12daSjmcneill 		for (idx = 0; idx < 4; idx++) {
617db7e12daSjmcneill 			DART_WRITE(sc, DART_TTBR(sid, idx), 0);
618db7e12daSjmcneill 		}
619db7e12daSjmcneill 	}
620db7e12daSjmcneill 	apple_dart_flush_tlb(sc);
621db7e12daSjmcneill 
622db7e12daSjmcneill 	/*
623db7e12daSjmcneill 	 * Build translation tables. We pre-allocate the translation
624db7e12daSjmcneill 	 * tables for the entire aperture such that we don't have to worry
625db7e12daSjmcneill 	 * about growing them in an mpsafe manner later.
626f6a78933Sskrll 	 *
627f6a78933Sskrll 	 * Cover the entire address space [0, ..._START + ..._SIZE) even if vmem
628f6a78933Sskrll 	 * only allocates from [..._START, ..._START + ...+SIZE)
629db7e12daSjmcneill 	 */
630db7e12daSjmcneill 
631db7e12daSjmcneill 	const u_int ntte = howmany(DART_APERTURE_START + DART_APERTURE_SIZE - 1,
632db7e12daSjmcneill 				   DART_PAGE_SIZE);
633db7e12daSjmcneill 	const u_int nl2 = howmany(ntte, DART_PAGE_SIZE / sizeof(uint64_t));
634db7e12daSjmcneill 	const u_int nl1 = howmany(nl2, DART_PAGE_SIZE / sizeof(uint64_t));
635db7e12daSjmcneill 
636db7e12daSjmcneill 	sc->sc_l1 = apple_dart_dma_alloc(sc->sc_dmat,
637db7e12daSjmcneill 	    nl1 * DART_PAGE_SIZE, DART_PAGE_SIZE);
638db7e12daSjmcneill 	if (sc->sc_l1 == NULL) {
639db7e12daSjmcneill 		aprint_error_dev(self, "couldn't allocate L1 tables\n");
640db7e12daSjmcneill 		return;
641db7e12daSjmcneill 	}
642db7e12daSjmcneill 	sc->sc_l2 = kmem_zalloc(nl2 * sizeof(*sc->sc_l2), KM_SLEEP);
643db7e12daSjmcneill 	sc->sc_nl2 = nl2;
644db7e12daSjmcneill 
645db7e12daSjmcneill 	l1 = DART_DMA_KVA(sc->sc_l1);
646db7e12daSjmcneill 	for (idx = 0; idx < nl2; idx++) {
647db7e12daSjmcneill 		sc->sc_l2[idx] = apple_dart_dma_alloc(sc->sc_dmat,
648db7e12daSjmcneill 		    DART_PAGE_SIZE, DART_PAGE_SIZE);
649db7e12daSjmcneill 		if (sc->sc_l2[idx] == NULL) {
650db7e12daSjmcneill 			aprint_error_dev(self,
651db7e12daSjmcneill 			    "couldn't allocate L2 tables\n");
652db7e12daSjmcneill 			return;
653db7e12daSjmcneill 		}
654f6a78933Sskrll 
655db7e12daSjmcneill 		l1[idx] = DART_DMA_DVA(sc->sc_l2[idx]) | DART_L1_TABLE;
656f6a78933Sskrll #ifdef APPLE_DART_DEBUG
657f6a78933Sskrll 		printf("l1[%d] (%p) = %"PRIx64"\n", idx, &l1[idx], l1[idx]);
658f6a78933Sskrll #endif
659db7e12daSjmcneill 	}
660db7e12daSjmcneill 
661db7e12daSjmcneill 	/* Install page tables */
662db7e12daSjmcneill 	for (sid = 0; sid < sc->sc_nsid; sid++) {
663db7e12daSjmcneill 		pa = DART_DMA_DVA(sc->sc_l1);
664db7e12daSjmcneill 		for (idx = 0; idx < nl1; idx++) {
665f6a78933Sskrll 			KASSERTMSG(__SHIFTOUT(pa, __BITS(DART_TTBR_SHIFT - 1, 0)) == 0,
666f6a78933Sskrll 			    "TTBR pa is not correctly aligned %" PRIxPADDR, pa);
667f6a78933Sskrll 
668db7e12daSjmcneill 			DART_WRITE(sc, DART_TTBR(sid, idx),
669db7e12daSjmcneill 			    (pa >> DART_TTBR_SHIFT) | DART_TTBR_VALID);
670db7e12daSjmcneill 			pa += DART_PAGE_SIZE;
671f6a78933Sskrll #ifdef APPLE_DART_DEBUG
672f6a78933Sskrll 			printf("writing %"PRIx64" to %"PRIx32"\n",
673f6a78933Sskrll 			    (pa >> DART_TTBR_SHIFT) | DART_TTBR_VALID,
674f6a78933Sskrll 			    DART_TTBR(sid, idx));
675f6a78933Sskrll #endif
676db7e12daSjmcneill 		}
677db7e12daSjmcneill 	}
678db7e12daSjmcneill 	apple_dart_flush_tlb(sc);
679db7e12daSjmcneill 
680db7e12daSjmcneill 	/* Enable translations */
681db7e12daSjmcneill 	for (sid = 0; sid < sc->sc_nsid; sid++) {
682f6a78933Sskrll 		DART_WRITE(sc, DART_TCR(sid), DART_TCR_TRANSLATE_ENABLE);
683db7e12daSjmcneill 	}
684db7e12daSjmcneill 
685db7e12daSjmcneill 	ih = fdtbus_intr_establish_xname(phandle, 0, IPL_HIGH, FDT_INTR_MPSAFE,
686db7e12daSjmcneill 	    apple_dart_intr, sc, device_xname(self));
687db7e12daSjmcneill 	if (ih == NULL) {
688db7e12daSjmcneill 		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
689db7e12daSjmcneill 		    intrstr);
690db7e12daSjmcneill 		return;
691db7e12daSjmcneill 	}
692db7e12daSjmcneill 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
693db7e12daSjmcneill 
694db7e12daSjmcneill 	/* Setup bus DMA tag */
695db7e12daSjmcneill 	sc->sc_bus_dmat = *sc->sc_dmat;
696db7e12daSjmcneill 	sc->sc_bus_dmat._ranges = apple_dart_dma_ranges;
697db7e12daSjmcneill 	sc->sc_bus_dmat._nranges = 1;
698db7e12daSjmcneill 	sc->sc_bus_dmat._cookie = sc;
699db7e12daSjmcneill 	sc->sc_bus_dmat._dmamap_create = apple_dart_dmamap_create;
700db7e12daSjmcneill 	sc->sc_bus_dmat._dmamap_destroy = apple_dart_dmamap_destroy;
701db7e12daSjmcneill 	sc->sc_bus_dmat._dmamap_load = apple_dart_dmamap_load;
702db7e12daSjmcneill 	sc->sc_bus_dmat._dmamap_load_mbuf = apple_dart_dmamap_load_mbuf;
703db7e12daSjmcneill 	sc->sc_bus_dmat._dmamap_load_uio = apple_dart_dmamap_load_uio;
704db7e12daSjmcneill 	sc->sc_bus_dmat._dmamap_load_raw = apple_dart_dmamap_load_raw;
705db7e12daSjmcneill 	sc->sc_bus_dmat._dmamap_unload = apple_dart_dmamap_unload;
706db7e12daSjmcneill 
707a808ce0eSjmcneill 	fdtbus_register_iommu(self, phandle, &apple_dart_iommu_funcs);
708db7e12daSjmcneill }
709db7e12daSjmcneill 
710db7e12daSjmcneill CFATTACH_DECL_NEW(apple_dart, sizeof(struct apple_dart_softc),
711db7e12daSjmcneill 	apple_dart_match, apple_dart_attach, NULL, NULL);
712