xref: /openbsd-src/sys/arch/arm64/dev/apldart.c (revision 0f9e9ec23bb2b65cc62a3d17df12827a45dae80c)
1*0f9e9ec2Sjsg /*	$OpenBSD: apldart.c,v 1.21 2024/05/13 01:15:50 jsg Exp $	*/
255f7f351Skettenis /*
355f7f351Skettenis  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
455f7f351Skettenis  *
555f7f351Skettenis  * Permission to use, copy, modify, and distribute this software for any
655f7f351Skettenis  * purpose with or without fee is hereby granted, provided that the above
755f7f351Skettenis  * copyright notice and this permission notice appear in all copies.
855f7f351Skettenis  *
955f7f351Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1055f7f351Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1155f7f351Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1255f7f351Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1355f7f351Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1455f7f351Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1555f7f351Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1655f7f351Skettenis  */
1755f7f351Skettenis 
1855f7f351Skettenis #include <sys/param.h>
1955f7f351Skettenis #include <sys/systm.h>
2055f7f351Skettenis #include <sys/device.h>
2155f7f351Skettenis #include <sys/extent.h>
2255f7f351Skettenis #include <sys/malloc.h>
239ced64eaSvisa #include <sys/mutex.h>
2455f7f351Skettenis 
2555f7f351Skettenis #include <machine/intr.h>
2655f7f351Skettenis #include <machine/bus.h>
2755f7f351Skettenis #include <machine/fdt.h>
2855f7f351Skettenis 
29494ba95aSkettenis #include <uvm/uvm_extern.h>
30494ba95aSkettenis 
3155f7f351Skettenis #include <dev/ofw/openfirm.h>
3255f7f351Skettenis #include <dev/ofw/ofw_misc.h>
33f2e6717fSkettenis #include <dev/ofw/ofw_power.h>
3455f7f351Skettenis #include <dev/ofw/fdt.h>
3555f7f351Skettenis 
3655f7f351Skettenis /*
3755f7f351Skettenis  * This driver largely ignores stream IDs and simply uses a single
3855f7f351Skettenis  * translation table for all the devices that it serves.  This is good
3955f7f351Skettenis  * enough for the PCIe host bridge that serves the on-board devices on
4055f7f351Skettenis  * the current generation Apple Silicon Macs as these only have a
4155f7f351Skettenis  * single PCIe device behind each DART.
4255f7f351Skettenis  */
4355f7f351Skettenis 
44c4e02adeSkettenis #define DART_PARAMS2			0x0004
45c4e02adeSkettenis #define  DART_PARAMS2_BYPASS_SUPPORT		(1 << 0)
4655f7f351Skettenis 
47bd26d413Skettenis #define DART_T8020_TLB_CMD		0x0020
48bd26d413Skettenis #define  DART_T8020_TLB_CMD_FLUSH		(1 << 20)
49bd26d413Skettenis #define  DART_T8020_TLB_CMD_BUSY		(1 << 2)
50bd26d413Skettenis #define DART_T8020_TLB_SIDMASK		0x0034
51bd26d413Skettenis #define DART_T8020_ERROR		0x0040
52bd26d413Skettenis #define DART_T8020_ERROR_ADDR_LO	0x0050
53bd26d413Skettenis #define DART_T8020_ERROR_ADDR_HI	0x0054
54bd26d413Skettenis #define DART_T8020_CONFIG		0x0060
55bd26d413Skettenis #define  DART_T8020_CONFIG_LOCK			(1 << 15)
56bd26d413Skettenis #define DART_T8020_SID_ENABLE		0x00fc
57bd26d413Skettenis #define DART_T8020_TCR_BASE		0x0100
58bd26d413Skettenis #define  DART_T8020_TCR_TRANSLATE_ENABLE	(1 << 7)
59bd26d413Skettenis #define  DART_T8020_TCR_BYPASS_DART		(1 << 8)
60bd26d413Skettenis #define  DART_T8020_TCR_BYPASS_DAPF		(1 << 12)
61bd26d413Skettenis #define DART_T8020_TTBR_BASE		0x0200
62bd26d413Skettenis #define  DART_T8020_TTBR_VALID			(1U << 31)
63bd26d413Skettenis 
64b4036ef4Skettenis #define DART_T8110_PARAMS3		0x0008
65b4036ef4Skettenis #define  DART_T8110_PARAMS3_REV_MIN(x)		(((x) >> 0) & 0xff)
66b4036ef4Skettenis #define  DART_T8110_PARAMS3_REV_MAJ(x)		(((x) >> 8) & 0xff)
67b4036ef4Skettenis #define  DART_T8110_PARAMS3_VA_WIDTH(x)		(((x) >> 16) & 0x3f)
68bd26d413Skettenis #define DART_T8110_PARAMS4		0x000c
69bd26d413Skettenis #define  DART_T8110_PARAMS4_NSID_MASK		(0x1ff << 0)
70bd26d413Skettenis #define DART_T8110_TLB_CMD		0x0080
71bd26d413Skettenis #define  DART_T8110_TLB_CMD_BUSY		(1U << 31)
72bd26d413Skettenis #define  DART_T8110_TLB_CMD_FLUSH_ALL		(0 << 8)
7388ef38baSkettenis #define  DART_T8110_TLB_CMD_FLUSH_SID		(1 << 8)
74bd26d413Skettenis #define DART_T8110_ERROR		0x0100
75bd26d413Skettenis #define DART_T8110_ERROR_MASK		0x0104
76bd26d413Skettenis #define DART_T8110_ERROR_ADDR_LO	0x0170
77bd26d413Skettenis #define DART_T8110_ERROR_ADDR_HI	0x0174
78bd26d413Skettenis #define DART_T8110_PROTECT		0x0200
79bd26d413Skettenis #define  DART_T8110_PROTECT_TTBR_TCR		(1 << 0)
80bd26d413Skettenis #define DART_T8110_SID_ENABLE_BASE	0x0c00
81bd26d413Skettenis #define DART_T8110_TCR_BASE		0x1000
82bd26d413Skettenis #define  DART_T8110_TCR_BYPASS_DAPF		(1 << 2)
83bd26d413Skettenis #define  DART_T8110_TCR_BYPASS_DART		(1 << 1)
84bd26d413Skettenis #define  DART_T8110_TCR_TRANSLATE_ENABLE	(1 << 0)
85bd26d413Skettenis #define DART_T8110_TTBR_BASE		0x1400
86bd26d413Skettenis #define  DART_T8110_TTBR_VALID			(1 << 0)
87c4e02adeSkettenis 
8855f7f351Skettenis #define DART_PAGE_SIZE		16384
8955f7f351Skettenis #define DART_PAGE_MASK		(DART_PAGE_SIZE - 1)
9055f7f351Skettenis 
91bd26d413Skettenis #define DART_SID_ENABLE(sc, idx) \
92bd26d413Skettenis     ((sc)->sc_sid_enable_base + 4 * (idx))
93bd26d413Skettenis #define DART_TCR(sc, sid)	((sc)->sc_tcr_base + 4 * (sid))
94bd26d413Skettenis #define DART_TTBR(sc, sid, idx)	\
95bd26d413Skettenis     ((sc)->sc_ttbr_base + 4 * (sc)->sc_nttbr * (sid) + 4 * (idx))
96bd26d413Skettenis #define  DART_TTBR_SHIFT	12
97bd26d413Skettenis 
98bd26d413Skettenis #define DART_ALL_STREAMS(sc)	((1U << (sc)->sc_nsid) - 1)
99bd26d413Skettenis 
1002c847e44Skettenis /*
1012c847e44Skettenis  * Some hardware (e.g. bge(4)) will always use (aligned) 64-bit memory
1022c847e44Skettenis  * access.  To make sure this doesn't fault, round the subpage limits
1032c847e44Skettenis  * down and up accordingly.
1042c847e44Skettenis  */
1052c847e44Skettenis #define DART_OFFSET_MASK	7
1062c847e44Skettenis 
107f809c1d0Skettenis #define DART_L1_TABLE		0x3
1082c847e44Skettenis #define DART_L2_INVAL		0
1092c847e44Skettenis #define DART_L2_VALID		(1 << 0)
1102c847e44Skettenis #define DART_L2_FULL_PAGE	(1 << 1)
1112c847e44Skettenis #define DART_L2_START(addr)	((((addr) & DART_PAGE_MASK) >> 2) << 52)
1122c847e44Skettenis #define DART_L2_END(addr)	((((addr) & DART_PAGE_MASK) >> 2) << 40)
11355f7f351Skettenis 
11430025dadSpatrick static inline paddr_t
apldart_round_page(paddr_t pa)11555f7f351Skettenis apldart_round_page(paddr_t pa)
11655f7f351Skettenis {
11755f7f351Skettenis 	return ((pa + DART_PAGE_MASK) & ~DART_PAGE_MASK);
11855f7f351Skettenis }
11955f7f351Skettenis 
1202c847e44Skettenis static inline paddr_t
apldart_trunc_page(paddr_t pa)1212c847e44Skettenis apldart_trunc_page(paddr_t pa)
12255f7f351Skettenis {
12355f7f351Skettenis 	return (pa & ~DART_PAGE_MASK);
12455f7f351Skettenis }
12555f7f351Skettenis 
1262c847e44Skettenis static inline psize_t
apldart_round_offset(psize_t off)1272c847e44Skettenis apldart_round_offset(psize_t off)
1282c847e44Skettenis {
1292c847e44Skettenis 	return ((off + DART_OFFSET_MASK) & ~DART_OFFSET_MASK);
1302c847e44Skettenis }
1312c847e44Skettenis 
1322c847e44Skettenis static inline psize_t
apldart_trunc_offset(psize_t off)1332c847e44Skettenis apldart_trunc_offset(psize_t off)
1342c847e44Skettenis {
1352c847e44Skettenis 	return (off & ~DART_OFFSET_MASK);
1362c847e44Skettenis }
1372c847e44Skettenis 
13855f7f351Skettenis #define HREAD4(sc, reg)							\
139c4e02adeSkettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
14055f7f351Skettenis #define HWRITE4(sc, reg, val)						\
141c4e02adeSkettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
14255f7f351Skettenis 
14388ef38baSkettenis struct apldart_stream {
14488ef38baSkettenis 	struct apldart_softc	*as_sc;
14588ef38baSkettenis 	int			as_sid;
14688ef38baSkettenis 
14788ef38baSkettenis 	struct extent		*as_dvamap;
14888ef38baSkettenis 	struct mutex		as_dvamap_mtx;
14988ef38baSkettenis 	struct apldart_dmamem	*as_l1;
15088ef38baSkettenis 	struct apldart_dmamem	**as_l2;
15188ef38baSkettenis 
15288ef38baSkettenis 	struct machine_bus_dma_tag as_dmat;
15388ef38baSkettenis };
15488ef38baSkettenis 
15555f7f351Skettenis struct apldart_softc {
15655f7f351Skettenis 	struct device		sc_dev;
15755f7f351Skettenis 	bus_space_tag_t		sc_iot;
158c4e02adeSkettenis 	bus_space_handle_t	sc_ioh;
15955f7f351Skettenis 	bus_dma_tag_t		sc_dmat;
160bd26d413Skettenis 	int			sc_node;
161bd26d413Skettenis 
162b4036ef4Skettenis 	int			sc_ias;
163bd26d413Skettenis 	int			sc_nsid;
164bd26d413Skettenis 	int			sc_nttbr;
16588ef38baSkettenis 	int			sc_shift;
166bd26d413Skettenis 	bus_addr_t		sc_sid_enable_base;
167bd26d413Skettenis 	bus_addr_t		sc_tcr_base;
168bd26d413Skettenis 	uint32_t		sc_tcr_translate_enable;
169bd26d413Skettenis 	uint32_t		sc_tcr_bypass;
170bd26d413Skettenis 	bus_addr_t		sc_ttbr_base;
171bd26d413Skettenis 	uint32_t		sc_ttbr_valid;
17288ef38baSkettenis 	void			(*sc_flush_tlb)(struct apldart_softc *, int);
17355f7f351Skettenis 
17455f7f351Skettenis 	bus_addr_t		sc_dvabase;
17555f7f351Skettenis 	bus_addr_t		sc_dvaend;
176b4036ef4Skettenis 	bus_addr_t		sc_dvamask;
17755f7f351Skettenis 
17888ef38baSkettenis 	struct apldart_stream	**sc_as;
17955f7f351Skettenis 	struct iommu_device	sc_id;
180f2e6717fSkettenis 
181494ba95aSkettenis 	int			sc_locked;
182494ba95aSkettenis 	int			sc_translating;
183f2e6717fSkettenis 	int			sc_do_suspend;
18455f7f351Skettenis };
18555f7f351Skettenis 
18655f7f351Skettenis struct apldart_map_state {
18755f7f351Skettenis 	struct extent_region	ams_er;
18855f7f351Skettenis 	bus_addr_t		ams_dva;
18955f7f351Skettenis 	bus_size_t		ams_len;
19055f7f351Skettenis };
19155f7f351Skettenis 
19255f7f351Skettenis struct apldart_dmamem {
19355f7f351Skettenis 	bus_dmamap_t		adm_map;
19455f7f351Skettenis 	bus_dma_segment_t	adm_seg;
19555f7f351Skettenis 	size_t			adm_size;
19655f7f351Skettenis 	caddr_t			adm_kva;
19755f7f351Skettenis };
19855f7f351Skettenis 
19955f7f351Skettenis #define APLDART_DMA_MAP(_adm)	((_adm)->adm_map)
20055f7f351Skettenis #define APLDART_DMA_LEN(_adm)	((_adm)->adm_size)
20155f7f351Skettenis #define APLDART_DMA_DVA(_adm)	((_adm)->adm_map->dm_segs[0].ds_addr)
20255f7f351Skettenis #define APLDART_DMA_KVA(_adm)	((void *)(_adm)->adm_kva)
20355f7f351Skettenis 
20455f7f351Skettenis struct apldart_dmamem *apldart_dmamem_alloc(bus_dma_tag_t, bus_size_t,
20555f7f351Skettenis 	    bus_size_t);
20655f7f351Skettenis void	apldart_dmamem_free(bus_dma_tag_t, struct apldart_dmamem *);
20755f7f351Skettenis 
20855f7f351Skettenis int	apldart_match(struct device *, void *, void *);
20955f7f351Skettenis void	apldart_attach(struct device *, struct device *, void *);
210f2e6717fSkettenis int	apldart_activate(struct device *, int);
21155f7f351Skettenis 
212471aeecfSnaddy const struct cfattach apldart_ca = {
213f2e6717fSkettenis 	sizeof (struct apldart_softc), apldart_match, apldart_attach, NULL,
214f2e6717fSkettenis 	apldart_activate
21555f7f351Skettenis };
21655f7f351Skettenis 
21755f7f351Skettenis struct cfdriver apldart_cd = {
21855f7f351Skettenis 	NULL, "apldart", DV_DULL
21955f7f351Skettenis };
22055f7f351Skettenis 
22155f7f351Skettenis bus_dma_tag_t apldart_map(void *, uint32_t *, bus_dma_tag_t);
222415019ceSpatrick void	apldart_reserve(void *, uint32_t *, bus_addr_t, bus_size_t);
223bd26d413Skettenis int	apldart_t8020_intr(void *);
224bd26d413Skettenis int	apldart_t8110_intr(void *);
22555f7f351Skettenis 
22688ef38baSkettenis void	apldart_t8020_flush_tlb(struct apldart_softc *, int);
22788ef38baSkettenis void	apldart_t8110_flush_tlb(struct apldart_softc *, int);
228b4036ef4Skettenis int	apldart_load_map(struct apldart_stream *, bus_dmamap_t, int);
22988ef38baSkettenis void	apldart_unload_map(struct apldart_stream *, bus_dmamap_t);
23055f7f351Skettenis 
23155f7f351Skettenis int	apldart_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
23255f7f351Skettenis 	    bus_size_t boundary, int, bus_dmamap_t *);
23355f7f351Skettenis void	apldart_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
23455f7f351Skettenis int	apldart_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
23555f7f351Skettenis 	    bus_size_t, struct proc *, int);
23655f7f351Skettenis int	apldart_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
23755f7f351Skettenis 	    struct mbuf *, int);
23855f7f351Skettenis int	apldart_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
23955f7f351Skettenis 	    struct uio *, int);
24055f7f351Skettenis int	apldart_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
24155f7f351Skettenis 	    bus_dma_segment_t *, int, bus_size_t, int);
24255f7f351Skettenis void	apldart_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
24355f7f351Skettenis 
24455f7f351Skettenis int
apldart_match(struct device * parent,void * match,void * aux)24555f7f351Skettenis apldart_match(struct device *parent, void *match, void *aux)
24655f7f351Skettenis {
24755f7f351Skettenis 	struct fdt_attach_args *faa = aux;
24855f7f351Skettenis 
249bd26d413Skettenis 	return OF_is_compatible(faa->fa_node, "apple,t6000-dart") ||
250bd26d413Skettenis 	    OF_is_compatible(faa->fa_node, "apple,t8103-dart") ||
251bd26d413Skettenis 	    OF_is_compatible(faa->fa_node, "apple,t8110-dart");
25255f7f351Skettenis }
25355f7f351Skettenis 
25455f7f351Skettenis void
apldart_attach(struct device * parent,struct device * self,void * aux)25555f7f351Skettenis apldart_attach(struct device *parent, struct device *self, void *aux)
25655f7f351Skettenis {
25755f7f351Skettenis 	struct apldart_softc *sc = (struct apldart_softc *)self;
25855f7f351Skettenis 	struct fdt_attach_args *faa = aux;
259b4036ef4Skettenis 	uint64_t dva_range[2];
260b4036ef4Skettenis 	uint32_t config, maj, min, params2, params3, params4, tcr, ttbr;
26155f7f351Skettenis 	int sid, idx;
26255f7f351Skettenis 
26355f7f351Skettenis 	if (faa->fa_nreg < 1) {
26455f7f351Skettenis 		printf(": no registers\n");
26555f7f351Skettenis 		return;
26655f7f351Skettenis 	}
26755f7f351Skettenis 
26855f7f351Skettenis 	sc->sc_iot = faa->fa_iot;
26955f7f351Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
270c4e02adeSkettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
27155f7f351Skettenis 		printf(": can't map registers\n");
27255f7f351Skettenis 		return;
27355f7f351Skettenis 	}
27455f7f351Skettenis 
27555f7f351Skettenis 	sc->sc_dmat = faa->fa_dmat;
276bd26d413Skettenis 	sc->sc_node = faa->fa_node;
277f2e6717fSkettenis 
278f2e6717fSkettenis 	power_domain_enable(sc->sc_node);
279f2e6717fSkettenis 
280bd26d413Skettenis 	if (OF_is_compatible(sc->sc_node, "apple,t8110-dart")) {
281b4036ef4Skettenis 		params3 = HREAD4(sc, DART_T8110_PARAMS3);
282bd26d413Skettenis 		params4 = HREAD4(sc, DART_T8110_PARAMS4);
283b4036ef4Skettenis 		sc->sc_ias = DART_T8110_PARAMS3_VA_WIDTH(params3);
284bd26d413Skettenis 		sc->sc_nsid = params4 & DART_T8110_PARAMS4_NSID_MASK;
285bd26d413Skettenis 		sc->sc_nttbr = 1;
286bd26d413Skettenis 		sc->sc_sid_enable_base = DART_T8110_SID_ENABLE_BASE;
287bd26d413Skettenis 		sc->sc_tcr_base = DART_T8110_TCR_BASE;
288bd26d413Skettenis 		sc->sc_tcr_translate_enable = DART_T8110_TCR_TRANSLATE_ENABLE;
289bd26d413Skettenis 		sc->sc_tcr_bypass =
290bd26d413Skettenis 		    DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART;
291bd26d413Skettenis 		sc->sc_ttbr_base = DART_T8110_TTBR_BASE;
292bd26d413Skettenis 		sc->sc_ttbr_valid = DART_T8110_TTBR_VALID;
293bd26d413Skettenis 		sc->sc_flush_tlb = apldart_t8110_flush_tlb;
294b4036ef4Skettenis 		maj = DART_T8110_PARAMS3_REV_MAJ(params3);
295b4036ef4Skettenis 		min = DART_T8110_PARAMS3_REV_MIN(params3);
296bd26d413Skettenis 	} else {
297b4036ef4Skettenis 		sc->sc_ias = 32;
298bd26d413Skettenis 		sc->sc_nsid = 16;
299bd26d413Skettenis 		sc->sc_nttbr = 4;
300bd26d413Skettenis 		sc->sc_sid_enable_base = DART_T8020_SID_ENABLE;
301bd26d413Skettenis 		sc->sc_tcr_base = DART_T8020_TCR_BASE;
302bd26d413Skettenis 		sc->sc_tcr_translate_enable = DART_T8020_TCR_TRANSLATE_ENABLE;
303bd26d413Skettenis 		sc->sc_tcr_bypass =
304bd26d413Skettenis 		    DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART;
305bd26d413Skettenis 		sc->sc_ttbr_base = DART_T8020_TTBR_BASE;
306bd26d413Skettenis 		sc->sc_ttbr_valid = DART_T8020_TTBR_VALID;
307bd26d413Skettenis 		sc->sc_flush_tlb = apldart_t8020_flush_tlb;
308b4036ef4Skettenis 		maj = min = 0;
309bd26d413Skettenis 	}
310bd26d413Skettenis 
311bd26d413Skettenis 	if (OF_is_compatible(sc->sc_node, "apple,t6000-dart") ||
312bd26d413Skettenis 	    OF_is_compatible(sc->sc_node, "apple,t8110-dart"))
313bd26d413Skettenis 		sc->sc_shift = 4;
314bd26d413Skettenis 
315f05e7979Skettenis 	/* Skip locked DARTs for now. */
316bd26d413Skettenis 	if (OF_is_compatible(sc->sc_node, "apple,t8110-dart")) {
317bd26d413Skettenis 		config = HREAD4(sc, DART_T8110_PROTECT);
318494ba95aSkettenis 		if (config & DART_T8110_PROTECT_TTBR_TCR)
319494ba95aSkettenis 			sc->sc_locked = 1;
320bd26d413Skettenis 	} else {
321bd26d413Skettenis 		config = HREAD4(sc, DART_T8020_CONFIG);
322494ba95aSkettenis 		if (config & DART_T8020_CONFIG_LOCK)
323494ba95aSkettenis 			sc->sc_locked = 1;
324bd26d413Skettenis 	}
32555f7f351Skettenis 
326b4036ef4Skettenis 	if (maj != 0 || min != 0)
327b4036ef4Skettenis 		printf(" rev %d.%d", maj, min);
328b4036ef4Skettenis 
329b4036ef4Skettenis 	printf(": %d bits", sc->sc_ias);
330b4036ef4Skettenis 
331b4036ef4Skettenis 	/*
332b4036ef4Skettenis 	 * Anything over 36 bits requires 4-level page tables which we
333b4036ef4Skettenis 	 * don't implement yet.  So limit to 36 bits.
334b4036ef4Skettenis 	 */
335b4036ef4Skettenis 	if (sc->sc_ias > 36)
336b4036ef4Skettenis 		sc->sc_ias = 36;
337b4036ef4Skettenis 	sc->sc_dvamask = (1ULL << sc->sc_ias) - 1;
338b4036ef4Skettenis 
339f05e7979Skettenis 	/*
34077431635Skettenis 	 * Resetting the DART used for the display controller will
34177431635Skettenis 	 * kill the framebuffer.  This should be the only DART that
34277431635Skettenis 	 * has translation enabled and a valid translation table
34377431635Skettenis 	 * installed.  Skip this DART for now.
34477431635Skettenis 	 */
345bd26d413Skettenis 	for (sid = 0; sid < sc->sc_nsid; sid++) {
346bd26d413Skettenis 		tcr = HREAD4(sc, DART_TCR(sc, sid));
347bd26d413Skettenis 		if ((tcr & sc->sc_tcr_translate_enable) == 0)
34877431635Skettenis 			continue;
34977431635Skettenis 
350bd26d413Skettenis 		for (idx = 0; idx < sc->sc_nttbr; idx++) {
351bd26d413Skettenis 			ttbr = HREAD4(sc, DART_TTBR(sc, sid, idx));
352494ba95aSkettenis 			if (ttbr & sc->sc_ttbr_valid)
353494ba95aSkettenis 				sc->sc_translating = 1;
35477431635Skettenis 		}
35577431635Skettenis 	}
35677431635Skettenis 
35777431635Skettenis 	/*
358494ba95aSkettenis 	 * If we have full control over this DART, do suspend it.
359f2e6717fSkettenis 	 */
360494ba95aSkettenis 	sc->sc_do_suspend = !sc->sc_locked && !sc->sc_translating;
361f2e6717fSkettenis 
362f2e6717fSkettenis 	/*
363f05e7979Skettenis 	 * Use bypass mode if supported.  This avoids an issue with
364f05e7979Skettenis 	 * the USB3 controllers which need mappings entered into two
365f05e7979Skettenis 	 * IOMMUs, which is somewhat difficult to implement with our
366f05e7979Skettenis 	 * current kernel interfaces.
367f05e7979Skettenis 	 */
368c4e02adeSkettenis 	params2 = HREAD4(sc, DART_PARAMS2);
369494ba95aSkettenis 	if ((params2 & DART_PARAMS2_BYPASS_SUPPORT) &&
370494ba95aSkettenis 	    !sc->sc_locked && !sc->sc_translating) {
371bd26d413Skettenis 		for (sid = 0; sid < sc->sc_nsid; sid++)
372bd26d413Skettenis 			HWRITE4(sc, DART_TCR(sc, sid), sc->sc_tcr_bypass);
373b4036ef4Skettenis 		printf(", bypass\n");
374c4e02adeSkettenis 		return;
375c4e02adeSkettenis 	}
37655f7f351Skettenis 
377494ba95aSkettenis 	if (sc->sc_locked)
378b4036ef4Skettenis 		printf(", locked\n");
379494ba95aSkettenis 	else if (sc->sc_translating)
380b4036ef4Skettenis 		printf(", translating\n");
381494ba95aSkettenis 	else
382f05e7979Skettenis 		printf("\n");
383f05e7979Skettenis 
384b4036ef4Skettenis 	if (OF_getpropint64array(sc->sc_node, "apple,dma-range",
385b4036ef4Skettenis 	    dva_range, sizeof(dva_range)) == sizeof(dva_range)) {
386b4036ef4Skettenis 		sc->sc_dvabase = dva_range[0];
387b4036ef4Skettenis 		sc->sc_dvaend = dva_range[0] + dva_range[1] - 1;
388b4036ef4Skettenis 	} else {
38914edd68eSkettenis 		/*
390b4036ef4Skettenis 		 * Restrict ourselves to 32-bit addresses to cater for
391b4036ef4Skettenis 		 * devices that don't do 64-bit DMA.  Skip the first
392b4036ef4Skettenis 		 * page to help catching bugs where a device is doing
393b4036ef4Skettenis 		 * DMA to/from address zero because we didn't properly
394b4036ef4Skettenis 		 * set up the DMA transfer.  Skip the last page to
395b4036ef4Skettenis 		 * avoid using the address reserved for MSIs.
39614edd68eSkettenis 		 */
39714edd68eSkettenis 		sc->sc_dvabase = DART_PAGE_SIZE;
39814edd68eSkettenis 		sc->sc_dvaend = 0xffffffff - DART_PAGE_SIZE;
399b4036ef4Skettenis 	}
40055f7f351Skettenis 
401494ba95aSkettenis 	if (!sc->sc_locked && !sc->sc_translating) {
40255f7f351Skettenis 		/* Disable translations. */
403bd26d413Skettenis 		for (sid = 0; sid < sc->sc_nsid; sid++)
404bd26d413Skettenis 			HWRITE4(sc, DART_TCR(sc, sid), 0);
40555f7f351Skettenis 
40655f7f351Skettenis 		/* Remove page tables. */
407bd26d413Skettenis 		for (sid = 0; sid < sc->sc_nsid; sid++) {
408bd26d413Skettenis 			for (idx = 0; idx < sc->sc_nttbr; idx++)
409bd26d413Skettenis 				HWRITE4(sc, DART_TTBR(sc, sid, idx), 0);
41055f7f351Skettenis 		}
41188ef38baSkettenis 		sc->sc_flush_tlb(sc, -1);
412494ba95aSkettenis 	}
41355f7f351Skettenis 
414bd26d413Skettenis 	if (OF_is_compatible(sc->sc_node, "apple,t8110-dart")) {
415bd26d413Skettenis 		HWRITE4(sc, DART_T8110_ERROR, HREAD4(sc, DART_T8110_ERROR));
416bd26d413Skettenis 		HWRITE4(sc, DART_T8110_ERROR_MASK, 0);
417bd26d413Skettenis 		fdt_intr_establish(faa->fa_node, IPL_NET, apldart_t8110_intr,
41855f7f351Skettenis 		    sc, sc->sc_dev.dv_xname);
419bd26d413Skettenis 	} else {
420bd26d413Skettenis 		HWRITE4(sc, DART_T8020_ERROR, HREAD4(sc, DART_T8020_ERROR));
421bd26d413Skettenis 		fdt_intr_establish(faa->fa_node, IPL_NET, apldart_t8020_intr,
422bd26d413Skettenis 		    sc, sc->sc_dev.dv_xname);
423bd26d413Skettenis 	}
42455f7f351Skettenis 
42588ef38baSkettenis 	sc->sc_as = mallocarray(sc->sc_nsid, sizeof(*sc->sc_as),
42688ef38baSkettenis 	    M_DEVBUF, M_WAITOK | M_ZERO);
42755f7f351Skettenis 
42855f7f351Skettenis 	sc->sc_id.id_node = faa->fa_node;
42955f7f351Skettenis 	sc->sc_id.id_cookie = sc;
43055f7f351Skettenis 	sc->sc_id.id_map = apldart_map;
431415019ceSpatrick 	sc->sc_id.id_reserve = apldart_reserve;
43255f7f351Skettenis 	iommu_device_register(&sc->sc_id);
43355f7f351Skettenis }
43455f7f351Skettenis 
435f2e6717fSkettenis void
apldart_suspend(struct apldart_softc * sc)436f2e6717fSkettenis apldart_suspend(struct apldart_softc *sc)
437f2e6717fSkettenis {
438f2e6717fSkettenis 	if (!sc->sc_do_suspend)
439f2e6717fSkettenis 		return;
440f2e6717fSkettenis 
441f2e6717fSkettenis 	power_domain_disable(sc->sc_node);
442f2e6717fSkettenis }
443f2e6717fSkettenis 
444f2e6717fSkettenis void
apldart_resume(struct apldart_softc * sc)445f2e6717fSkettenis apldart_resume(struct apldart_softc *sc)
446f2e6717fSkettenis {
447f2e6717fSkettenis 	paddr_t pa;
448f2e6717fSkettenis 	int ntte, nl1, nl2;
449f2e6717fSkettenis 	uint32_t params2;
45088ef38baSkettenis 	uint32_t mask;
451f2e6717fSkettenis 	int sid, idx;
452f2e6717fSkettenis 
453f2e6717fSkettenis 	if (!sc->sc_do_suspend)
454f2e6717fSkettenis 		return;
455f2e6717fSkettenis 
456f2e6717fSkettenis 	power_domain_enable(sc->sc_node);
457f2e6717fSkettenis 
458f2e6717fSkettenis 	params2 = HREAD4(sc, DART_PARAMS2);
459f2e6717fSkettenis 	if (params2 & DART_PARAMS2_BYPASS_SUPPORT) {
460f2e6717fSkettenis 		for (sid = 0; sid < sc->sc_nsid; sid++)
461f2e6717fSkettenis 			HWRITE4(sc, DART_TCR(sc, sid), sc->sc_tcr_bypass);
462f2e6717fSkettenis 		return;
463f2e6717fSkettenis 	}
464f2e6717fSkettenis 
465b4036ef4Skettenis 	ntte = howmany((sc->sc_dvaend & sc->sc_dvamask), DART_PAGE_SIZE);
466f2e6717fSkettenis 	nl2 = howmany(ntte, DART_PAGE_SIZE / sizeof(uint64_t));
467f2e6717fSkettenis 	nl1 = howmany(nl2, DART_PAGE_SIZE / sizeof(uint64_t));
468f2e6717fSkettenis 
469f2e6717fSkettenis 	/* Install page tables. */
470f2e6717fSkettenis 	for (sid = 0; sid < sc->sc_nsid; sid++) {
47188ef38baSkettenis 		if (sc->sc_as[sid] == NULL)
47288ef38baSkettenis 			continue;
47388ef38baSkettenis 		pa = APLDART_DMA_DVA(sc->sc_as[sid]->as_l1);
474f2e6717fSkettenis 		for (idx = 0; idx < nl1; idx++) {
475f2e6717fSkettenis 			HWRITE4(sc, DART_TTBR(sc, sid, idx),
476f2e6717fSkettenis 			    (pa >> DART_TTBR_SHIFT) | sc->sc_ttbr_valid);
477f2e6717fSkettenis 			pa += DART_PAGE_SIZE;
478f2e6717fSkettenis 		}
479f2e6717fSkettenis 	}
48088ef38baSkettenis 	sc->sc_flush_tlb(sc, -1);
481f2e6717fSkettenis 
48288ef38baSkettenis 	/* Enable all active streams. */
48388ef38baSkettenis 	for (sid = 0; sid < sc->sc_nsid; sid++) {
48488ef38baSkettenis 		if (sc->sc_as[sid] == NULL)
48588ef38baSkettenis 			continue;
48688ef38baSkettenis 		mask = HREAD4(sc, DART_SID_ENABLE(sc, sid / 32));
48788ef38baSkettenis 		mask |= (1U << (sid % 32));
48888ef38baSkettenis 		HWRITE4(sc, DART_SID_ENABLE(sc, sid / 32), mask);
48988ef38baSkettenis 	}
490f2e6717fSkettenis 
491f2e6717fSkettenis 	/* Enable translations. */
49288ef38baSkettenis 	for (sid = 0; sid < sc->sc_nsid; sid++) {
49388ef38baSkettenis 		if (sc->sc_as[sid] == NULL)
49488ef38baSkettenis 			continue;
495f2e6717fSkettenis 		HWRITE4(sc, DART_TCR(sc, sid), sc->sc_tcr_translate_enable);
49688ef38baSkettenis 	}
497f2e6717fSkettenis 
498f2e6717fSkettenis 	if (OF_is_compatible(sc->sc_node, "apple,t8110-dart")) {
499f2e6717fSkettenis 		HWRITE4(sc, DART_T8110_ERROR, HREAD4(sc, DART_T8110_ERROR));
500f2e6717fSkettenis 		HWRITE4(sc, DART_T8110_ERROR_MASK, 0);
501f2e6717fSkettenis 	} else {
502f2e6717fSkettenis 		HWRITE4(sc, DART_T8020_ERROR, HREAD4(sc, DART_T8020_ERROR));
503f2e6717fSkettenis 	}
504f2e6717fSkettenis }
505f2e6717fSkettenis 
506f2e6717fSkettenis int
apldart_activate(struct device * self,int act)507f2e6717fSkettenis apldart_activate(struct device *self, int act)
508f2e6717fSkettenis {
509f2e6717fSkettenis 	struct apldart_softc *sc = (struct apldart_softc *)self;
510f2e6717fSkettenis 
511f2e6717fSkettenis 	switch (act) {
512f2e6717fSkettenis 	case DVACT_SUSPEND:
513f2e6717fSkettenis 		apldart_suspend(sc);
514f2e6717fSkettenis 		break;
515f2e6717fSkettenis 	case DVACT_RESUME:
516f2e6717fSkettenis 		apldart_resume(sc);
517f2e6717fSkettenis 		break;
518f2e6717fSkettenis 	}
519f2e6717fSkettenis 
520f2e6717fSkettenis 	return 0;
521f2e6717fSkettenis }
522f2e6717fSkettenis 
523494ba95aSkettenis void
apldart_init_locked_stream(struct apldart_stream * as)524494ba95aSkettenis apldart_init_locked_stream(struct apldart_stream *as)
525494ba95aSkettenis {
526494ba95aSkettenis 	struct apldart_softc *sc = as->as_sc;
527494ba95aSkettenis 	uint32_t ttbr;
528494ba95aSkettenis 	vaddr_t startva, endva, va;
529494ba95aSkettenis 	paddr_t pa;
530b4036ef4Skettenis 	bus_addr_t dva, dvaend, dvabase;
531494ba95aSkettenis 	volatile uint64_t *l1;
532494ba95aSkettenis 	int nl1, nl2, ntte;
533494ba95aSkettenis 	int idx;
534494ba95aSkettenis 
535494ba95aSkettenis 	for (idx = 0; idx < sc->sc_nttbr; idx++) {
536494ba95aSkettenis 		ttbr = HREAD4(sc, DART_TTBR(sc, as->as_sid, idx));
537494ba95aSkettenis 		if ((ttbr & sc->sc_ttbr_valid) == 0)
538494ba95aSkettenis 			break;
539494ba95aSkettenis 	}
540494ba95aSkettenis 	KASSERT(idx > 0);
541494ba95aSkettenis 
542494ba95aSkettenis 	nl2 = idx * (DART_PAGE_SIZE / sizeof(uint64_t));
543494ba95aSkettenis 	ntte = nl2 * (DART_PAGE_SIZE / sizeof(uint64_t));
544494ba95aSkettenis 
545b4036ef4Skettenis 	dvabase = sc->sc_dvabase & ~sc->sc_dvamask;
546b4036ef4Skettenis 	dvaend = dvabase + (bus_addr_t)ntte * DART_PAGE_SIZE;
547494ba95aSkettenis 	if (dvaend < sc->sc_dvaend)
548494ba95aSkettenis 		sc->sc_dvaend = dvaend;
549494ba95aSkettenis 
550b4036ef4Skettenis 	as->as_dvamap = extent_create(sc->sc_dev.dv_xname, 0, ULONG_MAX,
551b4036ef4Skettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_NOCOALESCE);
552b4036ef4Skettenis 	if (sc->sc_dvabase > 0) {
553b4036ef4Skettenis 		extent_alloc_region(as->as_dvamap, 0, sc->sc_dvabase,
554b4036ef4Skettenis 		    EX_WAITOK);
555b4036ef4Skettenis 	}
556b4036ef4Skettenis 	if (sc->sc_dvaend < ULONG_MAX) {
557b4036ef4Skettenis 		extent_alloc_region(as->as_dvamap, sc->sc_dvaend + 1,
558b4036ef4Skettenis 		    ULONG_MAX - sc->sc_dvaend, EX_WAITOK);
559b4036ef4Skettenis 	}
560494ba95aSkettenis 
561b4036ef4Skettenis 	ntte = howmany((sc->sc_dvaend & sc->sc_dvamask), DART_PAGE_SIZE);
562494ba95aSkettenis 	nl2 = howmany(ntte, DART_PAGE_SIZE / sizeof(uint64_t));
563494ba95aSkettenis 	nl1 = howmany(nl2, DART_PAGE_SIZE / sizeof(uint64_t));
564494ba95aSkettenis 
565494ba95aSkettenis 	as->as_l2 = mallocarray(nl2, sizeof(*as->as_l2),
566494ba95aSkettenis 	    M_DEVBUF, M_WAITOK | M_ZERO);
567494ba95aSkettenis 
568494ba95aSkettenis 	l1 = km_alloc(nl1 * DART_PAGE_SIZE, &kv_any, &kp_none, &kd_waitok);
569494ba95aSkettenis 	KASSERT(l1);
570494ba95aSkettenis 
571494ba95aSkettenis 	for (idx = 0; idx < nl1; idx++) {
572494ba95aSkettenis 		startva = (vaddr_t)l1 + idx * DART_PAGE_SIZE;
573494ba95aSkettenis 		endva = startva + DART_PAGE_SIZE;
574494ba95aSkettenis 		ttbr = HREAD4(sc, DART_TTBR(sc, as->as_sid, idx));
575494ba95aSkettenis 		pa = (paddr_t)(ttbr & ~sc->sc_ttbr_valid) << DART_TTBR_SHIFT;
576494ba95aSkettenis 		for (va = startva; va < endva; va += PAGE_SIZE) {
577494ba95aSkettenis 			pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE,
578494ba95aSkettenis 			    PMAP_CACHE_CI);
579494ba95aSkettenis 			pa += PAGE_SIZE;
580494ba95aSkettenis 		}
581494ba95aSkettenis 	}
582494ba95aSkettenis 
583494ba95aSkettenis 	for (idx = 0; idx < nl2; idx++) {
584494ba95aSkettenis 		if (l1[idx] & DART_L1_TABLE) {
585494ba95aSkettenis 			dva = idx * (DART_PAGE_SIZE / sizeof(uint64_t)) *
586494ba95aSkettenis 			    DART_PAGE_SIZE;
587494ba95aSkettenis 			dvaend = dva + DART_PAGE_SIZE * DART_PAGE_SIZE - 1;
588b4036ef4Skettenis 			extent_alloc_region(as->as_dvamap, dvabase + dva,
589b4036ef4Skettenis 			    dvaend - dva + 1, EX_WAITOK | EX_CONFLICTOK);
590494ba95aSkettenis 		} else {
591494ba95aSkettenis 			as->as_l2[idx] = apldart_dmamem_alloc(sc->sc_dmat,
592494ba95aSkettenis 			    DART_PAGE_SIZE, DART_PAGE_SIZE);
593494ba95aSkettenis 			pa = APLDART_DMA_DVA(as->as_l2[idx]);
594494ba95aSkettenis 			l1[idx] = (pa >> sc->sc_shift) | DART_L1_TABLE;
595494ba95aSkettenis 		}
596494ba95aSkettenis 	}
597494ba95aSkettenis 	sc->sc_flush_tlb(sc, as->as_sid);
598494ba95aSkettenis 
599494ba95aSkettenis 	memcpy(&as->as_dmat, sc->sc_dmat, sizeof(*sc->sc_dmat));
600494ba95aSkettenis 	as->as_dmat._cookie = as;
601494ba95aSkettenis 	as->as_dmat._dmamap_create = apldart_dmamap_create;
602494ba95aSkettenis 	as->as_dmat._dmamap_destroy = apldart_dmamap_destroy;
603494ba95aSkettenis 	as->as_dmat._dmamap_load = apldart_dmamap_load;
604494ba95aSkettenis 	as->as_dmat._dmamap_load_mbuf = apldart_dmamap_load_mbuf;
605494ba95aSkettenis 	as->as_dmat._dmamap_load_uio = apldart_dmamap_load_uio;
606494ba95aSkettenis 	as->as_dmat._dmamap_load_raw = apldart_dmamap_load_raw;
607494ba95aSkettenis 	as->as_dmat._dmamap_unload = apldart_dmamap_unload;
608494ba95aSkettenis 	as->as_dmat._flags |= BUS_DMA_COHERENT;
609494ba95aSkettenis }
610494ba95aSkettenis 
61188ef38baSkettenis struct apldart_stream *
apldart_alloc_stream(struct apldart_softc * sc,int sid)61288ef38baSkettenis apldart_alloc_stream(struct apldart_softc *sc, int sid)
61388ef38baSkettenis {
61488ef38baSkettenis 	struct apldart_stream *as;
61588ef38baSkettenis 	paddr_t pa;
61688ef38baSkettenis 	volatile uint64_t *l1;
61788ef38baSkettenis 	int idx, ntte, nl1, nl2;
61888ef38baSkettenis 	uint32_t mask;
61988ef38baSkettenis 
62088ef38baSkettenis 	as = malloc(sizeof(*as), M_DEVBUF, M_WAITOK | M_ZERO);
62188ef38baSkettenis 
62288ef38baSkettenis 	as->as_sc = sc;
62388ef38baSkettenis 	as->as_sid = sid;
62488ef38baSkettenis 
625494ba95aSkettenis 	mtx_init(&as->as_dvamap_mtx, IPL_HIGH);
626494ba95aSkettenis 
627494ba95aSkettenis 	if (sc->sc_locked || sc->sc_translating) {
628494ba95aSkettenis 		apldart_init_locked_stream(as);
629494ba95aSkettenis 		return as;
630494ba95aSkettenis 	}
631494ba95aSkettenis 
632b4036ef4Skettenis 	as->as_dvamap = extent_create(sc->sc_dev.dv_xname, 0, ULONG_MAX,
633b4036ef4Skettenis 	    M_DEVBUF, NULL, 0, EX_WAITOK | EX_NOCOALESCE);
634b4036ef4Skettenis 	if (sc->sc_dvabase > 0) {
635b4036ef4Skettenis 		extent_alloc_region(as->as_dvamap, 0, sc->sc_dvabase,
636b4036ef4Skettenis 		    EX_WAITOK);
637b4036ef4Skettenis 	}
638b4036ef4Skettenis 	if (sc->sc_dvaend < ULONG_MAX) {
639b4036ef4Skettenis 		extent_alloc_region(as->as_dvamap, sc->sc_dvaend + 1,
640b4036ef4Skettenis 		    ULONG_MAX - sc->sc_dvaend, EX_WAITOK);
641b4036ef4Skettenis 	}
64288ef38baSkettenis 
64388ef38baSkettenis 	/*
64488ef38baSkettenis 	 * Build translation tables.  We pre-allocate the translation
64588ef38baSkettenis 	 * tables for the entire aperture such that we don't have to
64688ef38baSkettenis 	 * worry about growing them in an mpsafe manner later.
64788ef38baSkettenis 	 */
64888ef38baSkettenis 
649b4036ef4Skettenis 	ntte = howmany((sc->sc_dvaend & sc->sc_dvamask), DART_PAGE_SIZE);
65088ef38baSkettenis 	nl2 = howmany(ntte, DART_PAGE_SIZE / sizeof(uint64_t));
65188ef38baSkettenis 	nl1 = howmany(nl2, DART_PAGE_SIZE / sizeof(uint64_t));
65288ef38baSkettenis 
65388ef38baSkettenis 	as->as_l1 = apldart_dmamem_alloc(sc->sc_dmat,
65488ef38baSkettenis 	    nl1 * DART_PAGE_SIZE, DART_PAGE_SIZE);
65588ef38baSkettenis 	as->as_l2 = mallocarray(nl2, sizeof(*as->as_l2),
65688ef38baSkettenis 	    M_DEVBUF, M_WAITOK | M_ZERO);
65788ef38baSkettenis 
65888ef38baSkettenis 	l1 = APLDART_DMA_KVA(as->as_l1);
65988ef38baSkettenis 	for (idx = 0; idx < nl2; idx++) {
66088ef38baSkettenis 		as->as_l2[idx] = apldart_dmamem_alloc(sc->sc_dmat,
66188ef38baSkettenis 		    DART_PAGE_SIZE, DART_PAGE_SIZE);
66288ef38baSkettenis 		pa = APLDART_DMA_DVA(as->as_l2[idx]);
66388ef38baSkettenis 		l1[idx] = (pa >> sc->sc_shift) | DART_L1_TABLE;
66488ef38baSkettenis 	}
66588ef38baSkettenis 
66688ef38baSkettenis 	/* Install page tables. */
66788ef38baSkettenis 	pa = APLDART_DMA_DVA(as->as_l1);
66888ef38baSkettenis 	for (idx = 0; idx < nl1; idx++) {
66988ef38baSkettenis 		HWRITE4(sc, DART_TTBR(sc, sid, idx),
67088ef38baSkettenis 		    (pa >> DART_TTBR_SHIFT) | sc->sc_ttbr_valid);
67188ef38baSkettenis 		pa += DART_PAGE_SIZE;
67288ef38baSkettenis 	}
67388ef38baSkettenis 	sc->sc_flush_tlb(sc, sid);
67488ef38baSkettenis 
67588ef38baSkettenis 	/* Enable this stream. */
67688ef38baSkettenis 	mask = HREAD4(sc, DART_SID_ENABLE(sc, sid / 32));
67788ef38baSkettenis 	mask |= (1U << (sid % 32));
67888ef38baSkettenis 	HWRITE4(sc, DART_SID_ENABLE(sc, sid / 32), mask);
67988ef38baSkettenis 
68088ef38baSkettenis 	/* Enable translations. */
68188ef38baSkettenis 	HWRITE4(sc, DART_TCR(sc, sid), sc->sc_tcr_translate_enable);
68288ef38baSkettenis 
68388ef38baSkettenis 	memcpy(&as->as_dmat, sc->sc_dmat, sizeof(*sc->sc_dmat));
68488ef38baSkettenis 	as->as_dmat._cookie = as;
68588ef38baSkettenis 	as->as_dmat._dmamap_create = apldart_dmamap_create;
68688ef38baSkettenis 	as->as_dmat._dmamap_destroy = apldart_dmamap_destroy;
68788ef38baSkettenis 	as->as_dmat._dmamap_load = apldart_dmamap_load;
68888ef38baSkettenis 	as->as_dmat._dmamap_load_mbuf = apldart_dmamap_load_mbuf;
68988ef38baSkettenis 	as->as_dmat._dmamap_load_uio = apldart_dmamap_load_uio;
69088ef38baSkettenis 	as->as_dmat._dmamap_load_raw = apldart_dmamap_load_raw;
69188ef38baSkettenis 	as->as_dmat._dmamap_unload = apldart_dmamap_unload;
69288ef38baSkettenis 	as->as_dmat._flags |= BUS_DMA_COHERENT;
69388ef38baSkettenis 
69488ef38baSkettenis 	return as;
69588ef38baSkettenis }
69688ef38baSkettenis 
69755f7f351Skettenis bus_dma_tag_t
apldart_map(void * cookie,uint32_t * cells,bus_dma_tag_t dmat)69855f7f351Skettenis apldart_map(void *cookie, uint32_t *cells, bus_dma_tag_t dmat)
69955f7f351Skettenis {
70055f7f351Skettenis 	struct apldart_softc *sc = cookie;
70188ef38baSkettenis 	uint32_t sid = cells[0];
70255f7f351Skettenis 
70388ef38baSkettenis 	KASSERT(sid < sc->sc_nsid);
70488ef38baSkettenis 
70588ef38baSkettenis 	if (sc->sc_as[sid] == NULL)
70688ef38baSkettenis 		sc->sc_as[sid] = apldart_alloc_stream(sc, sid);
70788ef38baSkettenis 
70888ef38baSkettenis 	return &sc->sc_as[sid]->as_dmat;
70955f7f351Skettenis }
71055f7f351Skettenis 
711415019ceSpatrick void
apldart_reserve(void * cookie,uint32_t * cells,bus_addr_t addr,bus_size_t size)712415019ceSpatrick apldart_reserve(void *cookie, uint32_t *cells, bus_addr_t addr, bus_size_t size)
713415019ceSpatrick {
714415019ceSpatrick }
715415019ceSpatrick 
71655f7f351Skettenis int
apldart_t8020_intr(void * arg)717bd26d413Skettenis apldart_t8020_intr(void *arg)
71855f7f351Skettenis {
71955f7f351Skettenis 	struct apldart_softc *sc = arg;
72055f7f351Skettenis 
721bd26d413Skettenis 	panic("%s: error 0x%08x addr 0x%08x%08x\n",
722bd26d413Skettenis 	    sc->sc_dev.dv_xname, HREAD4(sc, DART_T8020_ERROR),
723bd26d413Skettenis 	    HREAD4(sc, DART_T8020_ERROR_ADDR_HI),
724bd26d413Skettenis 	    HREAD4(sc, DART_T8020_ERROR_ADDR_LO));
725bd26d413Skettenis }
726bd26d413Skettenis 
727bd26d413Skettenis int
apldart_t8110_intr(void * arg)728bd26d413Skettenis apldart_t8110_intr(void *arg)
729bd26d413Skettenis {
730bd26d413Skettenis 	struct apldart_softc *sc = arg;
731bd26d413Skettenis 
732bd26d413Skettenis 	panic("%s: error 0x%08x addr 0x%08x%08x\n",
733bd26d413Skettenis 	    sc->sc_dev.dv_xname, HREAD4(sc, DART_T8110_ERROR),
734bd26d413Skettenis 	    HREAD4(sc, DART_T8110_ERROR_ADDR_HI),
735bd26d413Skettenis 	    HREAD4(sc, DART_T8110_ERROR_ADDR_LO));
73655f7f351Skettenis }
73755f7f351Skettenis 
73855f7f351Skettenis void
apldart_t8020_flush_tlb(struct apldart_softc * sc,int sid)73988ef38baSkettenis apldart_t8020_flush_tlb(struct apldart_softc *sc, int sid)
74055f7f351Skettenis {
74188ef38baSkettenis 	uint32_t mask;
74288ef38baSkettenis 
74355f7f351Skettenis 	__asm volatile ("dsb sy" ::: "memory");
74455f7f351Skettenis 
74588ef38baSkettenis 	if (sid == -1)
74688ef38baSkettenis 		mask = DART_ALL_STREAMS(sc);
74788ef38baSkettenis 	else
74888ef38baSkettenis 		mask = (1U << sid);
74988ef38baSkettenis 
75088ef38baSkettenis 	HWRITE4(sc, DART_T8020_TLB_SIDMASK, mask);
751bd26d413Skettenis 	HWRITE4(sc, DART_T8020_TLB_CMD, DART_T8020_TLB_CMD_FLUSH);
752bd26d413Skettenis 	while (HREAD4(sc, DART_T8020_TLB_CMD) & DART_T8020_TLB_CMD_BUSY)
753bd26d413Skettenis 		CPU_BUSY_CYCLE();
754bd26d413Skettenis }
755bd26d413Skettenis 
756bd26d413Skettenis void
apldart_t8110_flush_tlb(struct apldart_softc * sc,int sid)75788ef38baSkettenis apldart_t8110_flush_tlb(struct apldart_softc *sc, int sid)
758bd26d413Skettenis {
75988ef38baSkettenis 	uint32_t cmd;
76088ef38baSkettenis 
761bd26d413Skettenis 	__asm volatile ("dsb sy" ::: "memory");
762bd26d413Skettenis 
76388ef38baSkettenis 	if (sid == -1)
76488ef38baSkettenis 		cmd = DART_T8110_TLB_CMD_FLUSH_ALL;
76588ef38baSkettenis 	else
76688ef38baSkettenis 		cmd = DART_T8110_TLB_CMD_FLUSH_SID | sid;
76788ef38baSkettenis 
76888ef38baSkettenis 	HWRITE4(sc, DART_T8110_TLB_CMD, cmd);
769bd26d413Skettenis 	while (HREAD4(sc, DART_T8110_TLB_CMD) & DART_T8110_TLB_CMD_BUSY)
77055f7f351Skettenis 		CPU_BUSY_CYCLE();
77155f7f351Skettenis }
77255f7f351Skettenis 
77355f7f351Skettenis volatile uint64_t *
apldart_lookup_tte(struct apldart_stream * as,bus_addr_t dva)77488ef38baSkettenis apldart_lookup_tte(struct apldart_stream *as, bus_addr_t dva)
77555f7f351Skettenis {
776b4036ef4Skettenis 	int idx = (dva & as->as_sc->sc_dvamask) / DART_PAGE_SIZE;
77755f7f351Skettenis 	int l2_idx = idx / (DART_PAGE_SIZE / sizeof(uint64_t));
77855f7f351Skettenis 	int tte_idx = idx % (DART_PAGE_SIZE / sizeof(uint64_t));
77955f7f351Skettenis 	volatile uint64_t *l2;
78055f7f351Skettenis 
78188ef38baSkettenis 	l2 = APLDART_DMA_KVA(as->as_l2[l2_idx]);
78255f7f351Skettenis 	return &l2[tte_idx];
78355f7f351Skettenis }
78455f7f351Skettenis 
78555f7f351Skettenis int
apldart_load_map(struct apldart_stream * as,bus_dmamap_t map,int flags)786b4036ef4Skettenis apldart_load_map(struct apldart_stream *as, bus_dmamap_t map, int flags)
78755f7f351Skettenis {
78888ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
78955f7f351Skettenis 	struct apldart_map_state *ams = map->_dm_cookie;
79055f7f351Skettenis 	volatile uint64_t *tte;
79155f7f351Skettenis 	int seg, error;
79255f7f351Skettenis 
79355f7f351Skettenis 	/* For each segment. */
79455f7f351Skettenis 	for (seg = 0; seg < map->dm_nsegs; seg++) {
79555f7f351Skettenis 		paddr_t pa = map->dm_segs[seg]._ds_paddr;
79655f7f351Skettenis 		psize_t off = pa - apldart_trunc_page(pa);
7972c847e44Skettenis 		psize_t start, end;
79855f7f351Skettenis 		u_long len, dva;
79955f7f351Skettenis 
80055f7f351Skettenis 		len = apldart_round_page(map->dm_segs[seg].ds_len + off);
80155f7f351Skettenis 
80288ef38baSkettenis 		mtx_enter(&as->as_dvamap_mtx);
803b4036ef4Skettenis 		if (flags & BUS_DMA_FIXED) {
804b4036ef4Skettenis 			dva = apldart_trunc_page(map->dm_segs[seg].ds_addr);
805b4036ef4Skettenis 			/* XXX truncate because "apple,dma-range" mismatch */
806b4036ef4Skettenis 			if (dva > sc->sc_dvaend)
807b4036ef4Skettenis 				dva &= sc->sc_dvamask;
808b4036ef4Skettenis 			error = extent_alloc_region_with_descr(as->as_dvamap,
809b4036ef4Skettenis 			    dva, len, EX_NOWAIT, &ams[seg].ams_er);
810b4036ef4Skettenis 		} else {
81188ef38baSkettenis 			error = extent_alloc_with_descr(as->as_dvamap, len,
812b4036ef4Skettenis 			    DART_PAGE_SIZE, 0, 0, EX_NOWAIT, &ams[seg].ams_er,
813b4036ef4Skettenis 			    &dva);
814b4036ef4Skettenis 		}
81588ef38baSkettenis 		mtx_leave(&as->as_dvamap_mtx);
81655f7f351Skettenis 		if (error) {
81788ef38baSkettenis 			apldart_unload_map(as, map);
81855f7f351Skettenis 			return error;
81955f7f351Skettenis 		}
82055f7f351Skettenis 
82155f7f351Skettenis 		ams[seg].ams_dva = dva;
82255f7f351Skettenis 		ams[seg].ams_len = len;
82355f7f351Skettenis 
82455f7f351Skettenis 		map->dm_segs[seg].ds_addr = dva + off;
82555f7f351Skettenis 
82655f7f351Skettenis 		pa = apldart_trunc_page(pa);
8272c847e44Skettenis 		start = apldart_trunc_offset(off);
8282c847e44Skettenis 		end = DART_PAGE_MASK;
82955f7f351Skettenis 		while (len > 0) {
8302c847e44Skettenis 			if (len < DART_PAGE_SIZE)
8312c847e44Skettenis 				end = apldart_round_offset(len) - 1;
8322c847e44Skettenis 
83388ef38baSkettenis 			tte = apldart_lookup_tte(as, dva);
8345d503355Skettenis 			*tte = (pa >> sc->sc_shift) | DART_L2_VALID |
8352c847e44Skettenis 			    DART_L2_START(start) | DART_L2_END(end);
83655f7f351Skettenis 
83755f7f351Skettenis 			pa += DART_PAGE_SIZE;
83855f7f351Skettenis 			dva += DART_PAGE_SIZE;
83955f7f351Skettenis 			len -= DART_PAGE_SIZE;
8402c847e44Skettenis 			start = 0;
84155f7f351Skettenis 		}
84255f7f351Skettenis 	}
84355f7f351Skettenis 
84488ef38baSkettenis 	sc->sc_flush_tlb(sc, as->as_sid);
84555f7f351Skettenis 
84655f7f351Skettenis 	return 0;
84755f7f351Skettenis }
84855f7f351Skettenis 
84955f7f351Skettenis void
apldart_unload_map(struct apldart_stream * as,bus_dmamap_t map)85088ef38baSkettenis apldart_unload_map(struct apldart_stream *as, bus_dmamap_t map)
85155f7f351Skettenis {
85288ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
85355f7f351Skettenis 	struct apldart_map_state *ams = map->_dm_cookie;
85455f7f351Skettenis 	volatile uint64_t *tte;
85555f7f351Skettenis 	int seg, error;
85655f7f351Skettenis 
85755f7f351Skettenis 	/* For each segment. */
85855f7f351Skettenis 	for (seg = 0; seg < map->dm_nsegs; seg++) {
85955f7f351Skettenis 		u_long len, dva;
86055f7f351Skettenis 
86155f7f351Skettenis 		if (ams[seg].ams_len == 0)
86255f7f351Skettenis 			continue;
86355f7f351Skettenis 
86455f7f351Skettenis 		dva = ams[seg].ams_dva;
86555f7f351Skettenis 		len = ams[seg].ams_len;
86655f7f351Skettenis 
86755f7f351Skettenis 		while (len > 0) {
86888ef38baSkettenis 			tte = apldart_lookup_tte(as, dva);
86955f7f351Skettenis 			*tte = DART_L2_INVAL;
87055f7f351Skettenis 
87155f7f351Skettenis 			dva += DART_PAGE_SIZE;
87255f7f351Skettenis 			len -= DART_PAGE_SIZE;
87355f7f351Skettenis 		}
87455f7f351Skettenis 
87588ef38baSkettenis 		mtx_enter(&as->as_dvamap_mtx);
87688ef38baSkettenis 		error = extent_free(as->as_dvamap, ams[seg].ams_dva,
87755f7f351Skettenis 		    ams[seg].ams_len, EX_NOWAIT);
87888ef38baSkettenis 		mtx_leave(&as->as_dvamap_mtx);
87955f7f351Skettenis 
88055f7f351Skettenis 		KASSERT(error == 0);
88155f7f351Skettenis 
88255f7f351Skettenis 		ams[seg].ams_dva = 0;
88355f7f351Skettenis 		ams[seg].ams_len = 0;
88455f7f351Skettenis 	}
88555f7f351Skettenis 
88688ef38baSkettenis 	sc->sc_flush_tlb(sc, as->as_sid);
88755f7f351Skettenis }
88855f7f351Skettenis 
88955f7f351Skettenis int
apldart_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)89055f7f351Skettenis apldart_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
89155f7f351Skettenis     bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamap)
89255f7f351Skettenis {
89388ef38baSkettenis 	struct apldart_stream *as = t->_cookie;
89488ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
89555f7f351Skettenis 	struct apldart_map_state *ams;
89655f7f351Skettenis 	bus_dmamap_t map;
89755f7f351Skettenis 	int error;
89855f7f351Skettenis 
89955f7f351Skettenis 	error = sc->sc_dmat->_dmamap_create(sc->sc_dmat, size, nsegments,
90055f7f351Skettenis 	    maxsegsz, boundary, flags, &map);
90155f7f351Skettenis 	if (error)
90255f7f351Skettenis 		return error;
90355f7f351Skettenis 
90455f7f351Skettenis 	ams = mallocarray(map->_dm_segcnt, sizeof(*ams), M_DEVBUF,
90555f7f351Skettenis 	    (flags & BUS_DMA_NOWAIT) ? (M_NOWAIT|M_ZERO) : (M_WAITOK|M_ZERO));
90655f7f351Skettenis 	if (ams == NULL) {
90755f7f351Skettenis 		sc->sc_dmat->_dmamap_destroy(sc->sc_dmat, map);
90855f7f351Skettenis 		return ENOMEM;
90955f7f351Skettenis 	}
91055f7f351Skettenis 
91155f7f351Skettenis 	map->_dm_cookie = ams;
91255f7f351Skettenis 	*dmamap = map;
91355f7f351Skettenis 	return 0;
91455f7f351Skettenis }
91555f7f351Skettenis 
91655f7f351Skettenis void
apldart_dmamap_destroy(bus_dma_tag_t t,bus_dmamap_t map)91755f7f351Skettenis apldart_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
91855f7f351Skettenis {
91988ef38baSkettenis 	struct apldart_stream *as = t->_cookie;
92088ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
92155f7f351Skettenis 	struct apldart_map_state *ams = map->_dm_cookie;
92255f7f351Skettenis 
923f1481cb2Skettenis 	if (map->dm_nsegs)
924f1481cb2Skettenis 		apldart_dmamap_unload(t, map);
925f1481cb2Skettenis 
92655f7f351Skettenis 	free(ams, M_DEVBUF, map->_dm_segcnt * sizeof(*ams));
92755f7f351Skettenis 	sc->sc_dmat->_dmamap_destroy(sc->sc_dmat, map);
92855f7f351Skettenis }
92955f7f351Skettenis 
93055f7f351Skettenis int
apldart_dmamap_load(bus_dma_tag_t t,bus_dmamap_t map,void * buf,size_t buflen,struct proc * p,int flags)93155f7f351Skettenis apldart_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
93255f7f351Skettenis     size_t buflen, struct proc *p, int flags)
93355f7f351Skettenis {
93488ef38baSkettenis 	struct apldart_stream *as = t->_cookie;
93588ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
93655f7f351Skettenis 	int error;
93755f7f351Skettenis 
93855f7f351Skettenis 	error = sc->sc_dmat->_dmamap_load(sc->sc_dmat, map,
93955f7f351Skettenis 	    buf, buflen, p, flags);
94055f7f351Skettenis 	if (error)
94155f7f351Skettenis 		return error;
94255f7f351Skettenis 
943b4036ef4Skettenis 	error = apldart_load_map(as, map, flags);
94455f7f351Skettenis 	if (error)
94555f7f351Skettenis 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
94655f7f351Skettenis 
94755f7f351Skettenis 	return error;
94855f7f351Skettenis }
94955f7f351Skettenis 
95055f7f351Skettenis int
apldart_dmamap_load_mbuf(bus_dma_tag_t t,bus_dmamap_t map,struct mbuf * m,int flags)95155f7f351Skettenis apldart_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
95255f7f351Skettenis     struct mbuf *m, int flags)
95355f7f351Skettenis {
95488ef38baSkettenis 	struct apldart_stream *as = t->_cookie;
95588ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
95655f7f351Skettenis 	int error;
95755f7f351Skettenis 
95855f7f351Skettenis 	error = sc->sc_dmat->_dmamap_load_mbuf(sc->sc_dmat, map,
95955f7f351Skettenis 	    m, flags);
96055f7f351Skettenis 	if (error)
96155f7f351Skettenis 		return error;
96255f7f351Skettenis 
963b4036ef4Skettenis 	error = apldart_load_map(as, map, flags);
96455f7f351Skettenis 	if (error)
96555f7f351Skettenis 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
96655f7f351Skettenis 
96755f7f351Skettenis 	return error;
96855f7f351Skettenis }
96955f7f351Skettenis 
97055f7f351Skettenis int
apldart_dmamap_load_uio(bus_dma_tag_t t,bus_dmamap_t map,struct uio * uio,int flags)97155f7f351Skettenis apldart_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map,
97255f7f351Skettenis     struct uio *uio, int flags)
97355f7f351Skettenis {
97488ef38baSkettenis 	struct apldart_stream *as = t->_cookie;
97588ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
97655f7f351Skettenis 	int error;
97755f7f351Skettenis 
97855f7f351Skettenis 	error = sc->sc_dmat->_dmamap_load_uio(sc->sc_dmat, map,
97955f7f351Skettenis 	    uio, flags);
98055f7f351Skettenis 	if (error)
98155f7f351Skettenis 		return error;
98255f7f351Skettenis 
983b4036ef4Skettenis 	error = apldart_load_map(as, map, flags);
98455f7f351Skettenis 	if (error)
98555f7f351Skettenis 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
98655f7f351Skettenis 
98755f7f351Skettenis 	return error;
98855f7f351Skettenis }
98955f7f351Skettenis 
99055f7f351Skettenis int
apldart_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)99155f7f351Skettenis apldart_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
99255f7f351Skettenis     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
99355f7f351Skettenis {
99488ef38baSkettenis 	struct apldart_stream *as = t->_cookie;
99588ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
996b4036ef4Skettenis 	int i, error;
99755f7f351Skettenis 
998b4036ef4Skettenis 	if (flags & BUS_DMA_FIXED) {
999b4036ef4Skettenis 		if (map->dm_nsegs != nsegs)
1000b4036ef4Skettenis 			return EINVAL;
1001b4036ef4Skettenis 		for (i = 0; i < nsegs; i++) {
1002b4036ef4Skettenis 			if (map->dm_segs[i].ds_len != segs[i].ds_len)
1003b4036ef4Skettenis 				return EINVAL;
1004b4036ef4Skettenis 			map->dm_segs[i]._ds_paddr = segs[i].ds_addr;
1005b4036ef4Skettenis 			map->dm_segs[i]._ds_vaddr = segs[i]._ds_vaddr;
1006b4036ef4Skettenis 		}
1007b4036ef4Skettenis 	} else {
100855f7f351Skettenis 		error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map,
100955f7f351Skettenis 		     segs, nsegs, size, flags);
101055f7f351Skettenis 		if (error)
101155f7f351Skettenis 			return error;
1012b4036ef4Skettenis 	}
101355f7f351Skettenis 
1014b4036ef4Skettenis 	error = apldart_load_map(as, map, flags);
101555f7f351Skettenis 	if (error)
101655f7f351Skettenis 		sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
101755f7f351Skettenis 
101855f7f351Skettenis 	return error;
101955f7f351Skettenis }
102055f7f351Skettenis 
102155f7f351Skettenis void
apldart_dmamap_unload(bus_dma_tag_t t,bus_dmamap_t map)102255f7f351Skettenis apldart_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
102355f7f351Skettenis {
102488ef38baSkettenis 	struct apldart_stream *as = t->_cookie;
102588ef38baSkettenis 	struct apldart_softc *sc = as->as_sc;
102655f7f351Skettenis 
102788ef38baSkettenis 	apldart_unload_map(as, map);
102855f7f351Skettenis 	sc->sc_dmat->_dmamap_unload(sc->sc_dmat, map);
102955f7f351Skettenis }
103055f7f351Skettenis 
103155f7f351Skettenis struct apldart_dmamem *
apldart_dmamem_alloc(bus_dma_tag_t dmat,bus_size_t size,bus_size_t align)103255f7f351Skettenis apldart_dmamem_alloc(bus_dma_tag_t dmat, bus_size_t size, bus_size_t align)
103355f7f351Skettenis {
103455f7f351Skettenis 	struct apldart_dmamem *adm;
103555f7f351Skettenis 	int nsegs;
103655f7f351Skettenis 
103755f7f351Skettenis 	adm = malloc(sizeof(*adm), M_DEVBUF, M_WAITOK | M_ZERO);
103855f7f351Skettenis 	adm->adm_size = size;
103955f7f351Skettenis 
104055f7f351Skettenis 	if (bus_dmamap_create(dmat, size, 1, size, 0,
104155f7f351Skettenis 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &adm->adm_map) != 0)
104255f7f351Skettenis 		goto admfree;
104355f7f351Skettenis 
104455f7f351Skettenis 	if (bus_dmamem_alloc(dmat, size, align, 0, &adm->adm_seg, 1,
104555f7f351Skettenis 	    &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
104655f7f351Skettenis 		goto destroy;
104755f7f351Skettenis 
104855f7f351Skettenis 	if (bus_dmamem_map(dmat, &adm->adm_seg, nsegs, size,
104955f7f351Skettenis 	    &adm->adm_kva, BUS_DMA_WAITOK | BUS_DMA_NOCACHE) != 0)
105055f7f351Skettenis 		goto free;
105155f7f351Skettenis 
105255f7f351Skettenis 	if (bus_dmamap_load_raw(dmat, adm->adm_map, &adm->adm_seg,
105355f7f351Skettenis 	    nsegs, size, BUS_DMA_WAITOK) != 0)
105455f7f351Skettenis 		goto unmap;
105555f7f351Skettenis 
105655f7f351Skettenis 	return adm;
105755f7f351Skettenis 
105855f7f351Skettenis unmap:
105955f7f351Skettenis 	bus_dmamem_unmap(dmat, adm->adm_kva, size);
106055f7f351Skettenis free:
106155f7f351Skettenis 	bus_dmamem_free(dmat, &adm->adm_seg, 1);
106255f7f351Skettenis destroy:
106355f7f351Skettenis 	bus_dmamap_destroy(dmat, adm->adm_map);
106455f7f351Skettenis admfree:
106555f7f351Skettenis 	free(adm, M_DEVBUF, sizeof(*adm));
106655f7f351Skettenis 
106755f7f351Skettenis 	return NULL;
106855f7f351Skettenis }
106955f7f351Skettenis 
107055f7f351Skettenis void
apldart_dmamem_free(bus_dma_tag_t dmat,struct apldart_dmamem * adm)107155f7f351Skettenis apldart_dmamem_free(bus_dma_tag_t dmat, struct apldart_dmamem *adm)
107255f7f351Skettenis {
107355f7f351Skettenis 	bus_dmamem_unmap(dmat, adm->adm_kva, adm->adm_size);
107455f7f351Skettenis 	bus_dmamem_free(dmat, &adm->adm_seg, 1);
107555f7f351Skettenis 	bus_dmamap_destroy(dmat, adm->adm_map);
107655f7f351Skettenis 	free(adm, M_DEVBUF, sizeof(*adm));
107755f7f351Skettenis }
1078