1f3ba9122SRob Herring // SPDX-License-Identifier:	GPL-2.0
2f3ba9122SRob Herring /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
37fdc48ccSBoris Brezillon 
47fdc48ccSBoris Brezillon #include <drm/panfrost_drm.h>
57fdc48ccSBoris Brezillon 
67282f764SRob Herring #include <linux/atomic.h>
7f3ba9122SRob Herring #include <linux/bitfield.h>
8f3ba9122SRob Herring #include <linux/delay.h>
9187d2929SRob Herring #include <linux/dma-mapping.h>
10f3ba9122SRob Herring #include <linux/interrupt.h>
11f3ba9122SRob Herring #include <linux/io.h>
12f3ba9122SRob Herring #include <linux/iopoll.h>
13f3ba9122SRob Herring #include <linux/io-pgtable.h>
14f3ba9122SRob Herring #include <linux/iommu.h>
15f3ba9122SRob Herring #include <linux/platform_device.h>
16f3ba9122SRob Herring #include <linux/pm_runtime.h>
17187d2929SRob Herring #include <linux/shmem_fs.h>
18f3ba9122SRob Herring #include <linux/sizes.h>
19f3ba9122SRob Herring 
20f3ba9122SRob Herring #include "panfrost_device.h"
21f3ba9122SRob Herring #include "panfrost_mmu.h"
22f3ba9122SRob Herring #include "panfrost_gem.h"
23f3ba9122SRob Herring #include "panfrost_features.h"
24f3ba9122SRob Herring #include "panfrost_regs.h"
25f3ba9122SRob Herring 
26f3ba9122SRob Herring #define mmu_write(dev, reg, data) writel(data, dev->iomem + reg)
27f3ba9122SRob Herring #define mmu_read(dev, reg) readl(dev->iomem + reg)
28f3ba9122SRob Herring 
29f3ba9122SRob Herring static int wait_ready(struct panfrost_device *pfdev, u32 as_nr)
30f3ba9122SRob Herring {
31f3ba9122SRob Herring 	int ret;
32f3ba9122SRob Herring 	u32 val;
33f3ba9122SRob Herring 
34f3ba9122SRob Herring 	/* Wait for the MMU status to indicate there is no active command, in
35f3ba9122SRob Herring 	 * case one is pending. */
36f3ba9122SRob Herring 	ret = readl_relaxed_poll_timeout_atomic(pfdev->iomem + AS_STATUS(as_nr),
37*0ec187f6SBoris Brezillon 		val, !(val & AS_STATUS_AS_ACTIVE), 10, 100000);
38f3ba9122SRob Herring 
39f9ab9c66SBoris Brezillon 	if (ret) {
40f9ab9c66SBoris Brezillon 		/* The GPU hung, let's trigger a reset */
41f9ab9c66SBoris Brezillon 		panfrost_device_schedule_reset(pfdev);
42f3ba9122SRob Herring 		dev_err(pfdev->dev, "AS_ACTIVE bit stuck\n");
43f9ab9c66SBoris Brezillon 	}
44f3ba9122SRob Herring 
45f3ba9122SRob Herring 	return ret;
46f3ba9122SRob Herring }
47f3ba9122SRob Herring 
48f3ba9122SRob Herring static int write_cmd(struct panfrost_device *pfdev, u32 as_nr, u32 cmd)
49f3ba9122SRob Herring {
50f3ba9122SRob Herring 	int status;
51f3ba9122SRob Herring 
52f3ba9122SRob Herring 	/* write AS_COMMAND when MMU is ready to accept another command */
53f3ba9122SRob Herring 	status = wait_ready(pfdev, as_nr);
54f3ba9122SRob Herring 	if (!status)
55f3ba9122SRob Herring 		mmu_write(pfdev, AS_COMMAND(as_nr), cmd);
56f3ba9122SRob Herring 
57f3ba9122SRob Herring 	return status;
58f3ba9122SRob Herring }
59f3ba9122SRob Herring 
60f3ba9122SRob Herring static void lock_region(struct panfrost_device *pfdev, u32 as_nr,
61f3ba9122SRob Herring 			u64 iova, size_t size)
62f3ba9122SRob Herring {
63f3ba9122SRob Herring 	u8 region_width;
64f3ba9122SRob Herring 	u64 region = iova & PAGE_MASK;
65f3ba9122SRob Herring 	/*
66f3ba9122SRob Herring 	 * fls returns:
67f3ba9122SRob Herring 	 * 1 .. 32
68f3ba9122SRob Herring 	 *
69f3ba9122SRob Herring 	 * 10 + fls(num_pages)
70f3ba9122SRob Herring 	 * results in the range (11 .. 42)
71f3ba9122SRob Herring 	 */
72f3ba9122SRob Herring 
73f3ba9122SRob Herring 	size = round_up(size, PAGE_SIZE);
74f3ba9122SRob Herring 
75f3ba9122SRob Herring 	region_width = 10 + fls(size >> PAGE_SHIFT);
76f3ba9122SRob Herring 	if ((size >> PAGE_SHIFT) != (1ul << (region_width - 11))) {
77f3ba9122SRob Herring 		/* not pow2, so must go up to the next pow2 */
78f3ba9122SRob Herring 		region_width += 1;
79f3ba9122SRob Herring 	}
80f3ba9122SRob Herring 	region |= region_width;
81f3ba9122SRob Herring 
82f3ba9122SRob Herring 	/* Lock the region that needs to be updated */
83f3ba9122SRob Herring 	mmu_write(pfdev, AS_LOCKADDR_LO(as_nr), region & 0xFFFFFFFFUL);
84f3ba9122SRob Herring 	mmu_write(pfdev, AS_LOCKADDR_HI(as_nr), (region >> 32) & 0xFFFFFFFFUL);
85f3ba9122SRob Herring 	write_cmd(pfdev, as_nr, AS_COMMAND_LOCK);
86f3ba9122SRob Herring }
87f3ba9122SRob Herring 
88f3ba9122SRob Herring 
8986df65f3SRob Herring static int mmu_hw_do_operation_locked(struct panfrost_device *pfdev, int as_nr,
90f3ba9122SRob Herring 				      u64 iova, size_t size, u32 op)
91f3ba9122SRob Herring {
9286df65f3SRob Herring 	if (as_nr < 0)
937282f764SRob Herring 		return 0;
94f3ba9122SRob Herring 
95f3ba9122SRob Herring 	if (op != AS_COMMAND_UNLOCK)
96f3ba9122SRob Herring 		lock_region(pfdev, as_nr, iova, size);
97f3ba9122SRob Herring 
98f3ba9122SRob Herring 	/* Run the MMU operation */
99f3ba9122SRob Herring 	write_cmd(pfdev, as_nr, op);
100f3ba9122SRob Herring 
101f3ba9122SRob Herring 	/* Wait for the flush to complete */
10286df65f3SRob Herring 	return wait_ready(pfdev, as_nr);
10386df65f3SRob Herring }
104f3ba9122SRob Herring 
10586df65f3SRob Herring static int mmu_hw_do_operation(struct panfrost_device *pfdev,
10686df65f3SRob Herring 			       struct panfrost_mmu *mmu,
10786df65f3SRob Herring 			       u64 iova, size_t size, u32 op)
10886df65f3SRob Herring {
10986df65f3SRob Herring 	int ret;
110f3ba9122SRob Herring 
11186df65f3SRob Herring 	spin_lock(&pfdev->as_lock);
11286df65f3SRob Herring 	ret = mmu_hw_do_operation_locked(pfdev, mmu->as, iova, size, op);
1137282f764SRob Herring 	spin_unlock(&pfdev->as_lock);
114f3ba9122SRob Herring 	return ret;
115f3ba9122SRob Herring }
116f3ba9122SRob Herring 
1177282f764SRob Herring static void panfrost_mmu_enable(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
118f3ba9122SRob Herring {
1197282f764SRob Herring 	int as_nr = mmu->as;
1207282f764SRob Herring 	struct io_pgtable_cfg *cfg = &mmu->pgtbl_cfg;
121f3ba9122SRob Herring 	u64 transtab = cfg->arm_mali_lpae_cfg.transtab;
122f3ba9122SRob Herring 	u64 memattr = cfg->arm_mali_lpae_cfg.memattr;
123f3ba9122SRob Herring 
1245924d409SRob Herring 	mmu_hw_do_operation_locked(pfdev, as_nr, 0, ~0UL, AS_COMMAND_FLUSH_MEM);
125f3ba9122SRob Herring 
126f3ba9122SRob Herring 	mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), transtab & 0xffffffffUL);
127f3ba9122SRob Herring 	mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), transtab >> 32);
128f3ba9122SRob Herring 
129f3ba9122SRob Herring 	/* Need to revisit mem attrs.
130f3ba9122SRob Herring 	 * NC is the default, Mali driver is inner WT.
131f3ba9122SRob Herring 	 */
132f3ba9122SRob Herring 	mmu_write(pfdev, AS_MEMATTR_LO(as_nr), memattr & 0xffffffffUL);
133f3ba9122SRob Herring 	mmu_write(pfdev, AS_MEMATTR_HI(as_nr), memattr >> 32);
134f3ba9122SRob Herring 
135f3ba9122SRob Herring 	write_cmd(pfdev, as_nr, AS_COMMAND_UPDATE);
136f3ba9122SRob Herring }
137f3ba9122SRob Herring 
13862f1089fSRob Herring static void panfrost_mmu_disable(struct panfrost_device *pfdev, u32 as_nr)
139f3ba9122SRob Herring {
14062f1089fSRob Herring 	mmu_hw_do_operation_locked(pfdev, as_nr, 0, ~0UL, AS_COMMAND_FLUSH_MEM);
14162f1089fSRob Herring 
142f3ba9122SRob Herring 	mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), 0);
143f3ba9122SRob Herring 	mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), 0);
144f3ba9122SRob Herring 
145f3ba9122SRob Herring 	mmu_write(pfdev, AS_MEMATTR_LO(as_nr), 0);
146f3ba9122SRob Herring 	mmu_write(pfdev, AS_MEMATTR_HI(as_nr), 0);
147f3ba9122SRob Herring 
148f3ba9122SRob Herring 	write_cmd(pfdev, as_nr, AS_COMMAND_UPDATE);
149f3ba9122SRob Herring }
150f3ba9122SRob Herring 
1517282f764SRob Herring u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
1527282f764SRob Herring {
1537282f764SRob Herring 	int as;
1547282f764SRob Herring 
1557282f764SRob Herring 	spin_lock(&pfdev->as_lock);
1567282f764SRob Herring 
1577282f764SRob Herring 	as = mmu->as;
1587282f764SRob Herring 	if (as >= 0) {
1597282f764SRob Herring 		int en = atomic_inc_return(&mmu->as_count);
160ed7a34c5SBoris Brezillon 		u32 mask = BIT(as) | BIT(16 + as);
161dde2bb2dSBoris Brezillon 
162dde2bb2dSBoris Brezillon 		/*
163dde2bb2dSBoris Brezillon 		 * AS can be retained by active jobs or a perfcnt context,
164dde2bb2dSBoris Brezillon 		 * hence the '+ 1' here.
165dde2bb2dSBoris Brezillon 		 */
166dde2bb2dSBoris Brezillon 		WARN_ON(en >= (NUM_JOB_SLOTS + 1));
1677282f764SRob Herring 
1687282f764SRob Herring 		list_move(&mmu->list, &pfdev->as_lru_list);
169ed7a34c5SBoris Brezillon 
170ed7a34c5SBoris Brezillon 		if (pfdev->as_faulty_mask & mask) {
171ed7a34c5SBoris Brezillon 			/* Unhandled pagefault on this AS, the MMU was
172ed7a34c5SBoris Brezillon 			 * disabled. We need to re-enable the MMU after
173ed7a34c5SBoris Brezillon 			 * clearing+unmasking the AS interrupts.
174ed7a34c5SBoris Brezillon 			 */
175ed7a34c5SBoris Brezillon 			mmu_write(pfdev, MMU_INT_CLEAR, mask);
176ed7a34c5SBoris Brezillon 			mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
177ed7a34c5SBoris Brezillon 			pfdev->as_faulty_mask &= ~mask;
178ed7a34c5SBoris Brezillon 			panfrost_mmu_enable(pfdev, mmu);
179ed7a34c5SBoris Brezillon 		}
180ed7a34c5SBoris Brezillon 
1817282f764SRob Herring 		goto out;
1827282f764SRob Herring 	}
1837282f764SRob Herring 
1847282f764SRob Herring 	/* Check for a free AS */
1857282f764SRob Herring 	as = ffz(pfdev->as_alloc_mask);
1867282f764SRob Herring 	if (!(BIT(as) & pfdev->features.as_present)) {
1877282f764SRob Herring 		struct panfrost_mmu *lru_mmu;
1887282f764SRob Herring 
1897282f764SRob Herring 		list_for_each_entry_reverse(lru_mmu, &pfdev->as_lru_list, list) {
1907282f764SRob Herring 			if (!atomic_read(&lru_mmu->as_count))
1917282f764SRob Herring 				break;
1927282f764SRob Herring 		}
1937282f764SRob Herring 		WARN_ON(&lru_mmu->list == &pfdev->as_lru_list);
1947282f764SRob Herring 
1957282f764SRob Herring 		list_del_init(&lru_mmu->list);
1967282f764SRob Herring 		as = lru_mmu->as;
1977282f764SRob Herring 
1987282f764SRob Herring 		WARN_ON(as < 0);
1997282f764SRob Herring 		lru_mmu->as = -1;
2007282f764SRob Herring 	}
2017282f764SRob Herring 
2027282f764SRob Herring 	/* Assign the free or reclaimed AS to the FD */
2037282f764SRob Herring 	mmu->as = as;
2047282f764SRob Herring 	set_bit(as, &pfdev->as_alloc_mask);
2057282f764SRob Herring 	atomic_set(&mmu->as_count, 1);
2067282f764SRob Herring 	list_add(&mmu->list, &pfdev->as_lru_list);
2077282f764SRob Herring 
2087282f764SRob Herring 	dev_dbg(pfdev->dev, "Assigned AS%d to mmu %p, alloc_mask=%lx", as, mmu, pfdev->as_alloc_mask);
2097282f764SRob Herring 
2107282f764SRob Herring 	panfrost_mmu_enable(pfdev, mmu);
2117282f764SRob Herring 
2127282f764SRob Herring out:
2137282f764SRob Herring 	spin_unlock(&pfdev->as_lock);
2147282f764SRob Herring 	return as;
2157282f764SRob Herring }
2167282f764SRob Herring 
2177282f764SRob Herring void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
2187282f764SRob Herring {
2197282f764SRob Herring 	atomic_dec(&mmu->as_count);
2207282f764SRob Herring 	WARN_ON(atomic_read(&mmu->as_count) < 0);
2217282f764SRob Herring }
2227282f764SRob Herring 
22373e467f6SRob Herring void panfrost_mmu_reset(struct panfrost_device *pfdev)
22473e467f6SRob Herring {
2257282f764SRob Herring 	struct panfrost_mmu *mmu, *mmu_tmp;
2267282f764SRob Herring 
2277282f764SRob Herring 	spin_lock(&pfdev->as_lock);
2287282f764SRob Herring 
2297282f764SRob Herring 	pfdev->as_alloc_mask = 0;
230ed7a34c5SBoris Brezillon 	pfdev->as_faulty_mask = 0;
2317282f764SRob Herring 
2327282f764SRob Herring 	list_for_each_entry_safe(mmu, mmu_tmp, &pfdev->as_lru_list, list) {
2337282f764SRob Herring 		mmu->as = -1;
2347282f764SRob Herring 		atomic_set(&mmu->as_count, 0);
2357282f764SRob Herring 		list_del_init(&mmu->list);
2367282f764SRob Herring 	}
2377282f764SRob Herring 
2387282f764SRob Herring 	spin_unlock(&pfdev->as_lock);
23973e467f6SRob Herring 
24073e467f6SRob Herring 	mmu_write(pfdev, MMU_INT_CLEAR, ~0);
24173e467f6SRob Herring 	mmu_write(pfdev, MMU_INT_MASK, ~0);
24273e467f6SRob Herring }
24373e467f6SRob Herring 
2444dff47c7SRob Herring static size_t get_pgsize(u64 addr, size_t size)
2454dff47c7SRob Herring {
2464dff47c7SRob Herring 	if (addr & (SZ_2M - 1) || size < SZ_2M)
2474dff47c7SRob Herring 		return SZ_4K;
2484dff47c7SRob Herring 
2494dff47c7SRob Herring 	return SZ_2M;
2504dff47c7SRob Herring }
2514dff47c7SRob Herring 
2526f39188cSYi Wang static void panfrost_mmu_flush_range(struct panfrost_device *pfdev,
253ec7eba47SRob Herring 				     struct panfrost_mmu *mmu,
254ec7eba47SRob Herring 				     u64 iova, size_t size)
255f3ba9122SRob Herring {
256ec7eba47SRob Herring 	if (mmu->as < 0)
257ec7eba47SRob Herring 		return;
258ec7eba47SRob Herring 
259ec7eba47SRob Herring 	pm_runtime_get_noresume(pfdev->dev);
260ec7eba47SRob Herring 
261ec7eba47SRob Herring 	/* Flush the PTs only if we're already awake */
262ec7eba47SRob Herring 	if (pm_runtime_active(pfdev->dev))
263ec7eba47SRob Herring 		mmu_hw_do_operation(pfdev, mmu, iova, size, AS_COMMAND_FLUSH_PT);
264ec7eba47SRob Herring 
265ec7eba47SRob Herring 	pm_runtime_put_sync_autosuspend(pfdev->dev);
266ec7eba47SRob Herring }
267ec7eba47SRob Herring 
2687282f764SRob Herring static int mmu_map_sg(struct panfrost_device *pfdev, struct panfrost_mmu *mmu,
2697282f764SRob Herring 		      u64 iova, int prot, struct sg_table *sgt)
270f3ba9122SRob Herring {
271f3ba9122SRob Herring 	unsigned int count;
272f3ba9122SRob Herring 	struct scatterlist *sgl;
2737282f764SRob Herring 	struct io_pgtable_ops *ops = mmu->pgtbl_ops;
274eecbb3cdSRob Herring 	u64 start_iova = iova;
275f3ba9122SRob Herring 
27634a4e66fSMarek Szyprowski 	for_each_sgtable_dma_sg(sgt, sgl, count) {
277f3ba9122SRob Herring 		unsigned long paddr = sg_dma_address(sgl);
278f3ba9122SRob Herring 		size_t len = sg_dma_len(sgl);
279f3ba9122SRob Herring 
2807282f764SRob Herring 		dev_dbg(pfdev->dev, "map: as=%d, iova=%llx, paddr=%lx, len=%zx", mmu->as, iova, paddr, len);
281f3ba9122SRob Herring 
282f3ba9122SRob Herring 		while (len) {
2834dff47c7SRob Herring 			size_t pgsize = get_pgsize(iova | paddr, len);
2844dff47c7SRob Herring 
285f34ce7a7SBaolin Wang 			ops->map(ops, iova, paddr, pgsize, prot, GFP_KERNEL);
2864dff47c7SRob Herring 			iova += pgsize;
2874dff47c7SRob Herring 			paddr += pgsize;
2884dff47c7SRob Herring 			len -= pgsize;
289f3ba9122SRob Herring 		}
290f3ba9122SRob Herring 	}
291f3ba9122SRob Herring 
292ec7eba47SRob Herring 	panfrost_mmu_flush_range(pfdev, mmu, start_iova, iova - start_iova);
293f3ba9122SRob Herring 
294eecbb3cdSRob Herring 	return 0;
295eecbb3cdSRob Herring }
296f3ba9122SRob Herring 
297bdefca2dSBoris Brezillon int panfrost_mmu_map(struct panfrost_gem_mapping *mapping)
298eecbb3cdSRob Herring {
299bdefca2dSBoris Brezillon 	struct panfrost_gem_object *bo = mapping->obj;
300eecbb3cdSRob Herring 	struct drm_gem_object *obj = &bo->base.base;
301eecbb3cdSRob Herring 	struct panfrost_device *pfdev = to_panfrost_device(obj->dev);
302eecbb3cdSRob Herring 	struct sg_table *sgt;
303eecbb3cdSRob Herring 	int prot = IOMMU_READ | IOMMU_WRITE;
304eecbb3cdSRob Herring 
305bdefca2dSBoris Brezillon 	if (WARN_ON(mapping->active))
306eecbb3cdSRob Herring 		return 0;
307eecbb3cdSRob Herring 
308203270c0SRob Herring 	if (bo->noexec)
309203270c0SRob Herring 		prot |= IOMMU_NOEXEC;
310203270c0SRob Herring 
311eecbb3cdSRob Herring 	sgt = drm_gem_shmem_get_pages_sgt(obj);
312eecbb3cdSRob Herring 	if (WARN_ON(IS_ERR(sgt)))
313eecbb3cdSRob Herring 		return PTR_ERR(sgt);
314eecbb3cdSRob Herring 
315bdefca2dSBoris Brezillon 	mmu_map_sg(pfdev, mapping->mmu, mapping->mmnode.start << PAGE_SHIFT,
316bdefca2dSBoris Brezillon 		   prot, sgt);
317bdefca2dSBoris Brezillon 	mapping->active = true;
318f3ba9122SRob Herring 
319f3ba9122SRob Herring 	return 0;
320f3ba9122SRob Herring }
321f3ba9122SRob Herring 
322bdefca2dSBoris Brezillon void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping)
323f3ba9122SRob Herring {
324bdefca2dSBoris Brezillon 	struct panfrost_gem_object *bo = mapping->obj;
325f3ba9122SRob Herring 	struct drm_gem_object *obj = &bo->base.base;
326f3ba9122SRob Herring 	struct panfrost_device *pfdev = to_panfrost_device(obj->dev);
327bdefca2dSBoris Brezillon 	struct io_pgtable_ops *ops = mapping->mmu->pgtbl_ops;
328bdefca2dSBoris Brezillon 	u64 iova = mapping->mmnode.start << PAGE_SHIFT;
329bdefca2dSBoris Brezillon 	size_t len = mapping->mmnode.size << PAGE_SHIFT;
330f3ba9122SRob Herring 	size_t unmapped_len = 0;
331f3ba9122SRob Herring 
332bdefca2dSBoris Brezillon 	if (WARN_ON(!mapping->active))
3339870dc39SBoris Brezillon 		return;
3349870dc39SBoris Brezillon 
335bdefca2dSBoris Brezillon 	dev_dbg(pfdev->dev, "unmap: as=%d, iova=%llx, len=%zx",
336bdefca2dSBoris Brezillon 		mapping->mmu->as, iova, len);
337f3ba9122SRob Herring 
338f3ba9122SRob Herring 	while (unmapped_len < len) {
3394dff47c7SRob Herring 		size_t unmapped_page;
3404dff47c7SRob Herring 		size_t pgsize = get_pgsize(iova, len - unmapped_len);
3414dff47c7SRob Herring 
342187d2929SRob Herring 		if (ops->iova_to_phys(ops, iova)) {
343a2d3a382SWill Deacon 			unmapped_page = ops->unmap(ops, iova, pgsize, NULL);
344187d2929SRob Herring 			WARN_ON(unmapped_page != pgsize);
345187d2929SRob Herring 		}
346187d2929SRob Herring 		iova += pgsize;
347187d2929SRob Herring 		unmapped_len += pgsize;
348f3ba9122SRob Herring 	}
349f3ba9122SRob Herring 
350bdefca2dSBoris Brezillon 	panfrost_mmu_flush_range(pfdev, mapping->mmu,
351bdefca2dSBoris Brezillon 				 mapping->mmnode.start << PAGE_SHIFT, len);
352bdefca2dSBoris Brezillon 	mapping->active = false;
353f3ba9122SRob Herring }
354f3ba9122SRob Herring 
355f3ba9122SRob Herring static void mmu_tlb_inv_context_s1(void *cookie)
35662f1089fSRob Herring {}
357f3ba9122SRob Herring 
358f3ba9122SRob Herring static void mmu_tlb_sync_context(void *cookie)
359f3ba9122SRob Herring {
3607fdc48ccSBoris Brezillon 	//struct panfrost_mmu *mmu = cookie;
361f3ba9122SRob Herring 	// TODO: Wait 1000 GPU cycles for HW_ISSUE_6367/T60X
362f3ba9122SRob Herring }
363f3ba9122SRob Herring 
36405aed941SWill Deacon static void mmu_tlb_flush_walk(unsigned long iova, size_t size, size_t granule,
36505aed941SWill Deacon 			       void *cookie)
36605aed941SWill Deacon {
36705aed941SWill Deacon 	mmu_tlb_sync_context(cookie);
36805aed941SWill Deacon }
36905aed941SWill Deacon 
370298f7889SWill Deacon static const struct iommu_flush_ops mmu_tlb_ops = {
371f3ba9122SRob Herring 	.tlb_flush_all	= mmu_tlb_inv_context_s1,
37205aed941SWill Deacon 	.tlb_flush_walk = mmu_tlb_flush_walk,
373f3ba9122SRob Herring };
374f3ba9122SRob Herring 
375bdefca2dSBoris Brezillon static struct panfrost_gem_mapping *
376bdefca2dSBoris Brezillon addr_to_mapping(struct panfrost_device *pfdev, int as, u64 addr)
377187d2929SRob Herring {
378bdefca2dSBoris Brezillon 	struct panfrost_gem_mapping *mapping = NULL;
37965e51e30SSteven Price 	struct drm_mm_node *node;
380187d2929SRob Herring 	u64 offset = addr >> PAGE_SHIFT;
3817282f764SRob Herring 	struct panfrost_mmu *mmu;
382187d2929SRob Herring 
3837282f764SRob Herring 	spin_lock(&pfdev->as_lock);
3847282f764SRob Herring 	list_for_each_entry(mmu, &pfdev->as_lru_list, list) {
38565e51e30SSteven Price 		if (as == mmu->as)
386f70744c6SRobin Murphy 			goto found_mmu;
38765e51e30SSteven Price 	}
38865e51e30SSteven Price 	goto out;
3897282f764SRob Herring 
390f70744c6SRobin Murphy found_mmu:
39165e51e30SSteven Price 
3927fdc48ccSBoris Brezillon 	spin_lock(&mmu->mm_lock);
39365e51e30SSteven Price 
3947fdc48ccSBoris Brezillon 	drm_mm_for_each_node(node, &mmu->mm) {
39565e51e30SSteven Price 		if (offset >= node->start &&
39665e51e30SSteven Price 		    offset < (node->start + node->size)) {
397bdefca2dSBoris Brezillon 			mapping = drm_mm_node_to_panfrost_mapping(node);
398bdefca2dSBoris Brezillon 
399bdefca2dSBoris Brezillon 			kref_get(&mapping->refcount);
40065e51e30SSteven Price 			break;
401187d2929SRob Herring 		}
4027282f764SRob Herring 	}
4037282f764SRob Herring 
4047fdc48ccSBoris Brezillon 	spin_unlock(&mmu->mm_lock);
4057282f764SRob Herring out:
4067282f764SRob Herring 	spin_unlock(&pfdev->as_lock);
407bdefca2dSBoris Brezillon 	return mapping;
408187d2929SRob Herring }
409187d2929SRob Herring 
410187d2929SRob Herring #define NUM_FAULT_PAGES (SZ_2M / PAGE_SIZE)
411187d2929SRob Herring 
4126f39188cSYi Wang static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
4136f39188cSYi Wang 				       u64 addr)
414187d2929SRob Herring {
415187d2929SRob Herring 	int ret, i;
416bdefca2dSBoris Brezillon 	struct panfrost_gem_mapping *bomapping;
417187d2929SRob Herring 	struct panfrost_gem_object *bo;
418187d2929SRob Herring 	struct address_space *mapping;
419187d2929SRob Herring 	pgoff_t page_offset;
420187d2929SRob Herring 	struct sg_table *sgt;
421187d2929SRob Herring 	struct page **pages;
422187d2929SRob Herring 
423bdefca2dSBoris Brezillon 	bomapping = addr_to_mapping(pfdev, as, addr);
424bdefca2dSBoris Brezillon 	if (!bomapping)
425187d2929SRob Herring 		return -ENOENT;
426187d2929SRob Herring 
427bdefca2dSBoris Brezillon 	bo = bomapping->obj;
428187d2929SRob Herring 	if (!bo->is_heap) {
429187d2929SRob Herring 		dev_WARN(pfdev->dev, "matching BO is not heap type (GPU VA = %llx)",
430bdefca2dSBoris Brezillon 			 bomapping->mmnode.start << PAGE_SHIFT);
43165e51e30SSteven Price 		ret = -EINVAL;
43265e51e30SSteven Price 		goto err_bo;
433187d2929SRob Herring 	}
434bdefca2dSBoris Brezillon 	WARN_ON(bomapping->mmu->as != as);
4357282f764SRob Herring 
436187d2929SRob Herring 	/* Assume 2MB alignment and size multiple */
437187d2929SRob Herring 	addr &= ~((u64)SZ_2M - 1);
438187d2929SRob Herring 	page_offset = addr >> PAGE_SHIFT;
439bdefca2dSBoris Brezillon 	page_offset -= bomapping->mmnode.start;
440187d2929SRob Herring 
441187d2929SRob Herring 	mutex_lock(&bo->base.pages_lock);
442187d2929SRob Herring 
443187d2929SRob Herring 	if (!bo->base.pages) {
444187d2929SRob Herring 		bo->sgts = kvmalloc_array(bo->base.base.size / SZ_2M,
445187d2929SRob Herring 				     sizeof(struct sg_table), GFP_KERNEL | __GFP_ZERO);
4463efdf83cSWei Yongjun 		if (!bo->sgts) {
4473efdf83cSWei Yongjun 			mutex_unlock(&bo->base.pages_lock);
44865e51e30SSteven Price 			ret = -ENOMEM;
44965e51e30SSteven Price 			goto err_bo;
4503efdf83cSWei Yongjun 		}
451187d2929SRob Herring 
452187d2929SRob Herring 		pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT,
453187d2929SRob Herring 				       sizeof(struct page *), GFP_KERNEL | __GFP_ZERO);
454187d2929SRob Herring 		if (!pages) {
455114427b8SDenis Efremov 			kvfree(bo->sgts);
456187d2929SRob Herring 			bo->sgts = NULL;
4573efdf83cSWei Yongjun 			mutex_unlock(&bo->base.pages_lock);
45865e51e30SSteven Price 			ret = -ENOMEM;
45965e51e30SSteven Price 			goto err_bo;
460187d2929SRob Herring 		}
461187d2929SRob Herring 		bo->base.pages = pages;
462187d2929SRob Herring 		bo->base.pages_use_count = 1;
463f45da820SBoris Brezillon 	} else {
464187d2929SRob Herring 		pages = bo->base.pages;
465f45da820SBoris Brezillon 		if (pages[page_offset]) {
466f45da820SBoris Brezillon 			/* Pages are already mapped, bail out. */
467f45da820SBoris Brezillon 			mutex_unlock(&bo->base.pages_lock);
468f45da820SBoris Brezillon 			goto out;
469f45da820SBoris Brezillon 		}
470f45da820SBoris Brezillon 	}
471187d2929SRob Herring 
472187d2929SRob Herring 	mapping = bo->base.base.filp->f_mapping;
473187d2929SRob Herring 	mapping_set_unevictable(mapping);
474187d2929SRob Herring 
475187d2929SRob Herring 	for (i = page_offset; i < page_offset + NUM_FAULT_PAGES; i++) {
476187d2929SRob Herring 		pages[i] = shmem_read_mapping_page(mapping, i);
477187d2929SRob Herring 		if (IS_ERR(pages[i])) {
478187d2929SRob Herring 			mutex_unlock(&bo->base.pages_lock);
479187d2929SRob Herring 			ret = PTR_ERR(pages[i]);
480187d2929SRob Herring 			goto err_pages;
481187d2929SRob Herring 		}
482187d2929SRob Herring 	}
483187d2929SRob Herring 
484187d2929SRob Herring 	mutex_unlock(&bo->base.pages_lock);
485187d2929SRob Herring 
486187d2929SRob Herring 	sgt = &bo->sgts[page_offset / (SZ_2M / PAGE_SIZE)];
487187d2929SRob Herring 	ret = sg_alloc_table_from_pages(sgt, pages + page_offset,
488187d2929SRob Herring 					NUM_FAULT_PAGES, 0, SZ_2M, GFP_KERNEL);
489187d2929SRob Herring 	if (ret)
490187d2929SRob Herring 		goto err_pages;
491187d2929SRob Herring 
49234a4e66fSMarek Szyprowski 	ret = dma_map_sgtable(pfdev->dev, sgt, DMA_BIDIRECTIONAL, 0);
49334a4e66fSMarek Szyprowski 	if (ret)
494187d2929SRob Herring 		goto err_map;
495187d2929SRob Herring 
496bdefca2dSBoris Brezillon 	mmu_map_sg(pfdev, bomapping->mmu, addr,
497bdefca2dSBoris Brezillon 		   IOMMU_WRITE | IOMMU_READ | IOMMU_NOEXEC, sgt);
498187d2929SRob Herring 
499bdefca2dSBoris Brezillon 	bomapping->active = true;
500187d2929SRob Herring 
5017282f764SRob Herring 	dev_dbg(pfdev->dev, "mapped page fault @ AS%d %llx", as, addr);
502187d2929SRob Herring 
503f45da820SBoris Brezillon out:
504bdefca2dSBoris Brezillon 	panfrost_gem_mapping_put(bomapping);
50565e51e30SSteven Price 
506187d2929SRob Herring 	return 0;
507187d2929SRob Herring 
508187d2929SRob Herring err_map:
509187d2929SRob Herring 	sg_free_table(sgt);
510187d2929SRob Herring err_pages:
511187d2929SRob Herring 	drm_gem_shmem_put_pages(&bo->base);
51265e51e30SSteven Price err_bo:
513496d0cc6SEmil Velikov 	drm_gem_object_put(&bo->base.base);
514187d2929SRob Herring 	return ret;
515187d2929SRob Herring }
516187d2929SRob Herring 
5177fdc48ccSBoris Brezillon static void panfrost_mmu_release_ctx(struct kref *kref)
5187fdc48ccSBoris Brezillon {
5197fdc48ccSBoris Brezillon 	struct panfrost_mmu *mmu = container_of(kref, struct panfrost_mmu,
5207fdc48ccSBoris Brezillon 						refcount);
5217fdc48ccSBoris Brezillon 	struct panfrost_device *pfdev = mmu->pfdev;
5227fdc48ccSBoris Brezillon 
5237fdc48ccSBoris Brezillon 	spin_lock(&pfdev->as_lock);
5247fdc48ccSBoris Brezillon 	if (mmu->as >= 0) {
5257fdc48ccSBoris Brezillon 		pm_runtime_get_noresume(pfdev->dev);
5267fdc48ccSBoris Brezillon 		if (pm_runtime_active(pfdev->dev))
5277fdc48ccSBoris Brezillon 			panfrost_mmu_disable(pfdev, mmu->as);
5287fdc48ccSBoris Brezillon 		pm_runtime_put_autosuspend(pfdev->dev);
5297fdc48ccSBoris Brezillon 
5307fdc48ccSBoris Brezillon 		clear_bit(mmu->as, &pfdev->as_alloc_mask);
5317fdc48ccSBoris Brezillon 		clear_bit(mmu->as, &pfdev->as_in_use_mask);
5327fdc48ccSBoris Brezillon 		list_del(&mmu->list);
5337fdc48ccSBoris Brezillon 	}
5347fdc48ccSBoris Brezillon 	spin_unlock(&pfdev->as_lock);
5357fdc48ccSBoris Brezillon 
5367fdc48ccSBoris Brezillon 	free_io_pgtable_ops(mmu->pgtbl_ops);
5377fdc48ccSBoris Brezillon 	drm_mm_takedown(&mmu->mm);
5387fdc48ccSBoris Brezillon 	kfree(mmu);
5397fdc48ccSBoris Brezillon }
5407fdc48ccSBoris Brezillon 
5417fdc48ccSBoris Brezillon void panfrost_mmu_ctx_put(struct panfrost_mmu *mmu)
5427fdc48ccSBoris Brezillon {
5437fdc48ccSBoris Brezillon 	kref_put(&mmu->refcount, panfrost_mmu_release_ctx);
5447fdc48ccSBoris Brezillon }
5457fdc48ccSBoris Brezillon 
5467fdc48ccSBoris Brezillon struct panfrost_mmu *panfrost_mmu_ctx_get(struct panfrost_mmu *mmu)
5477fdc48ccSBoris Brezillon {
5487fdc48ccSBoris Brezillon 	kref_get(&mmu->refcount);
5497fdc48ccSBoris Brezillon 
5507fdc48ccSBoris Brezillon 	return mmu;
5517fdc48ccSBoris Brezillon }
5527fdc48ccSBoris Brezillon 
5537fdc48ccSBoris Brezillon #define PFN_4G		(SZ_4G >> PAGE_SHIFT)
5547fdc48ccSBoris Brezillon #define PFN_4G_MASK	(PFN_4G - 1)
5557fdc48ccSBoris Brezillon #define PFN_16M		(SZ_16M >> PAGE_SHIFT)
5567fdc48ccSBoris Brezillon 
5577fdc48ccSBoris Brezillon static void panfrost_drm_mm_color_adjust(const struct drm_mm_node *node,
5587fdc48ccSBoris Brezillon 					 unsigned long color,
5597fdc48ccSBoris Brezillon 					 u64 *start, u64 *end)
5607fdc48ccSBoris Brezillon {
5617fdc48ccSBoris Brezillon 	/* Executable buffers can't start or end on a 4GB boundary */
5627fdc48ccSBoris Brezillon 	if (!(color & PANFROST_BO_NOEXEC)) {
5637fdc48ccSBoris Brezillon 		u64 next_seg;
5647fdc48ccSBoris Brezillon 
5657fdc48ccSBoris Brezillon 		if ((*start & PFN_4G_MASK) == 0)
5667fdc48ccSBoris Brezillon 			(*start)++;
5677fdc48ccSBoris Brezillon 
5687fdc48ccSBoris Brezillon 		if ((*end & PFN_4G_MASK) == 0)
5697fdc48ccSBoris Brezillon 			(*end)--;
5707fdc48ccSBoris Brezillon 
5717fdc48ccSBoris Brezillon 		next_seg = ALIGN(*start, PFN_4G);
5727fdc48ccSBoris Brezillon 		if (next_seg - *start <= PFN_16M)
5737fdc48ccSBoris Brezillon 			*start = next_seg + 1;
5747fdc48ccSBoris Brezillon 
5757fdc48ccSBoris Brezillon 		*end = min(*end, ALIGN(*start, PFN_4G) - 1);
5767fdc48ccSBoris Brezillon 	}
5777fdc48ccSBoris Brezillon }
5787fdc48ccSBoris Brezillon 
5797fdc48ccSBoris Brezillon struct panfrost_mmu *panfrost_mmu_ctx_create(struct panfrost_device *pfdev)
5807fdc48ccSBoris Brezillon {
5817fdc48ccSBoris Brezillon 	struct panfrost_mmu *mmu;
5827fdc48ccSBoris Brezillon 
5837fdc48ccSBoris Brezillon 	mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
5847fdc48ccSBoris Brezillon 	if (!mmu)
5857fdc48ccSBoris Brezillon 		return ERR_PTR(-ENOMEM);
5867fdc48ccSBoris Brezillon 
5877fdc48ccSBoris Brezillon 	mmu->pfdev = pfdev;
5887fdc48ccSBoris Brezillon 	spin_lock_init(&mmu->mm_lock);
5897fdc48ccSBoris Brezillon 
5907fdc48ccSBoris Brezillon 	/* 4G enough for now. can be 48-bit */
5917fdc48ccSBoris Brezillon 	drm_mm_init(&mmu->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT);
5927fdc48ccSBoris Brezillon 	mmu->mm.color_adjust = panfrost_drm_mm_color_adjust;
5937fdc48ccSBoris Brezillon 
5947fdc48ccSBoris Brezillon 	INIT_LIST_HEAD(&mmu->list);
5957fdc48ccSBoris Brezillon 	mmu->as = -1;
5967fdc48ccSBoris Brezillon 
5977fdc48ccSBoris Brezillon 	mmu->pgtbl_cfg = (struct io_pgtable_cfg) {
5987fdc48ccSBoris Brezillon 		.pgsize_bitmap	= SZ_4K | SZ_2M,
5997fdc48ccSBoris Brezillon 		.ias		= FIELD_GET(0xff, pfdev->features.mmu_features),
6007fdc48ccSBoris Brezillon 		.oas		= FIELD_GET(0xff00, pfdev->features.mmu_features),
6017fdc48ccSBoris Brezillon 		.coherent_walk	= pfdev->coherent,
6027fdc48ccSBoris Brezillon 		.tlb		= &mmu_tlb_ops,
6037fdc48ccSBoris Brezillon 		.iommu_dev	= pfdev->dev,
6047fdc48ccSBoris Brezillon 	};
6057fdc48ccSBoris Brezillon 
6067fdc48ccSBoris Brezillon 	mmu->pgtbl_ops = alloc_io_pgtable_ops(ARM_MALI_LPAE, &mmu->pgtbl_cfg,
6077fdc48ccSBoris Brezillon 					      mmu);
6087fdc48ccSBoris Brezillon 	if (!mmu->pgtbl_ops) {
6097fdc48ccSBoris Brezillon 		kfree(mmu);
6107fdc48ccSBoris Brezillon 		return ERR_PTR(-EINVAL);
6117fdc48ccSBoris Brezillon 	}
6127fdc48ccSBoris Brezillon 
6137fdc48ccSBoris Brezillon 	kref_init(&mmu->refcount);
6147fdc48ccSBoris Brezillon 
6157fdc48ccSBoris Brezillon 	return mmu;
6167fdc48ccSBoris Brezillon }
6177fdc48ccSBoris Brezillon 
618f3ba9122SRob Herring static const char *access_type_name(struct panfrost_device *pfdev,
619f3ba9122SRob Herring 		u32 fault_status)
620f3ba9122SRob Herring {
621f3ba9122SRob Herring 	switch (fault_status & AS_FAULTSTATUS_ACCESS_TYPE_MASK) {
622f3ba9122SRob Herring 	case AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC:
623f3ba9122SRob Herring 		if (panfrost_has_hw_feature(pfdev, HW_FEATURE_AARCH64_MMU))
624f3ba9122SRob Herring 			return "ATOMIC";
625f3ba9122SRob Herring 		else
626f3ba9122SRob Herring 			return "UNKNOWN";
627f3ba9122SRob Herring 	case AS_FAULTSTATUS_ACCESS_TYPE_READ:
628f3ba9122SRob Herring 		return "READ";
629f3ba9122SRob Herring 	case AS_FAULTSTATUS_ACCESS_TYPE_WRITE:
630f3ba9122SRob Herring 		return "WRITE";
631f3ba9122SRob Herring 	case AS_FAULTSTATUS_ACCESS_TYPE_EX:
632f3ba9122SRob Herring 		return "EXECUTE";
633f3ba9122SRob Herring 	default:
634f3ba9122SRob Herring 		WARN_ON(1);
635f3ba9122SRob Herring 		return NULL;
636f3ba9122SRob Herring 	}
637f3ba9122SRob Herring }
638f3ba9122SRob Herring 
639f3ba9122SRob Herring static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data)
640f3ba9122SRob Herring {
641f3ba9122SRob Herring 	struct panfrost_device *pfdev = data;
642f3ba9122SRob Herring 
643b31bdd13SRob Herring 	if (!mmu_read(pfdev, MMU_INT_STAT))
644f3ba9122SRob Herring 		return IRQ_NONE;
645f3ba9122SRob Herring 
646b31bdd13SRob Herring 	mmu_write(pfdev, MMU_INT_MASK, 0);
647b31bdd13SRob Herring 	return IRQ_WAKE_THREAD;
648b31bdd13SRob Herring }
649b31bdd13SRob Herring 
650b31bdd13SRob Herring static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
651b31bdd13SRob Herring {
652b31bdd13SRob Herring 	struct panfrost_device *pfdev = data;
653b31bdd13SRob Herring 	u32 status = mmu_read(pfdev, MMU_INT_RAWSTAT);
6540eae01beSBoris Brezillon 	int ret;
655f3ba9122SRob Herring 
6560eae01beSBoris Brezillon 	while (status) {
6570eae01beSBoris Brezillon 		u32 as = ffs(status | (status >> 16)) - 1;
6580eae01beSBoris Brezillon 		u32 mask = BIT(as) | BIT(as + 16);
659f3ba9122SRob Herring 		u64 addr;
660f3ba9122SRob Herring 		u32 fault_status;
661f3ba9122SRob Herring 		u32 exception_type;
662f3ba9122SRob Herring 		u32 access_type;
663f3ba9122SRob Herring 		u32 source_id;
664f3ba9122SRob Herring 
6650eae01beSBoris Brezillon 		fault_status = mmu_read(pfdev, AS_FAULTSTATUS(as));
6660eae01beSBoris Brezillon 		addr = mmu_read(pfdev, AS_FAULTADDRESS_LO(as));
6670eae01beSBoris Brezillon 		addr |= (u64)mmu_read(pfdev, AS_FAULTADDRESS_HI(as)) << 32;
668f3ba9122SRob Herring 
669f3ba9122SRob Herring 		/* decode the fault status */
670f3ba9122SRob Herring 		exception_type = fault_status & 0xFF;
671f3ba9122SRob Herring 		access_type = (fault_status >> 8) & 0x3;
672f3ba9122SRob Herring 		source_id = (fault_status >> 16);
673f3ba9122SRob Herring 
6743aa0a80fSBoris Brezillon 		mmu_write(pfdev, MMU_INT_CLEAR, mask);
6753aa0a80fSBoris Brezillon 
676187d2929SRob Herring 		/* Page fault only */
677eb9d8ddbSTomeu Vizoso 		ret = -1;
6780eae01beSBoris Brezillon 		if ((status & mask) == BIT(as) && (exception_type & 0xF8) == 0xC0)
6790eae01beSBoris Brezillon 			ret = panfrost_mmu_map_fault_addr(pfdev, as, addr);
680187d2929SRob Herring 
681ed7a34c5SBoris Brezillon 		if (ret) {
682f3ba9122SRob Herring 			/* terminal fault, print info about the fault */
683f3ba9122SRob Herring 			dev_err(pfdev->dev,
684f3ba9122SRob Herring 				"Unhandled Page fault in AS%d at VA 0x%016llX\n"
685f3ba9122SRob Herring 				"Reason: %s\n"
686f3ba9122SRob Herring 				"raw fault status: 0x%X\n"
687f3ba9122SRob Herring 				"decoded fault status: %s\n"
688f3ba9122SRob Herring 				"exception type 0x%X: %s\n"
689f3ba9122SRob Herring 				"access type 0x%X: %s\n"
690f3ba9122SRob Herring 				"source id 0x%X\n",
6910eae01beSBoris Brezillon 				as, addr,
692f3ba9122SRob Herring 				"TODO",
693f3ba9122SRob Herring 				fault_status,
694f3ba9122SRob Herring 				(fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
6956ef2f37fSBoris Brezillon 				exception_type, panfrost_exception_name(exception_type),
696f3ba9122SRob Herring 				access_type, access_type_name(pfdev, fault_status),
697f3ba9122SRob Herring 				source_id);
698f3ba9122SRob Herring 
699ed7a34c5SBoris Brezillon 			spin_lock(&pfdev->as_lock);
700ed7a34c5SBoris Brezillon 			/* Ignore MMU interrupts on this AS until it's been
701ed7a34c5SBoris Brezillon 			 * re-enabled.
702ed7a34c5SBoris Brezillon 			 */
703ed7a34c5SBoris Brezillon 			pfdev->as_faulty_mask |= mask;
704ed7a34c5SBoris Brezillon 
705ed7a34c5SBoris Brezillon 			/* Disable the MMU to kill jobs on this AS. */
706ed7a34c5SBoris Brezillon 			panfrost_mmu_disable(pfdev, as);
707ed7a34c5SBoris Brezillon 			spin_unlock(&pfdev->as_lock);
708ed7a34c5SBoris Brezillon 		}
709ed7a34c5SBoris Brezillon 
710f3ba9122SRob Herring 		status &= ~mask;
7110eae01beSBoris Brezillon 
7120eae01beSBoris Brezillon 		/* If we received new MMU interrupts, process them before returning. */
7130eae01beSBoris Brezillon 		if (!status)
714ed7a34c5SBoris Brezillon 			status = mmu_read(pfdev, MMU_INT_RAWSTAT) & ~pfdev->as_faulty_mask;
715f3ba9122SRob Herring 	}
716f3ba9122SRob Herring 
717ed7a34c5SBoris Brezillon 	spin_lock(&pfdev->as_lock);
718ed7a34c5SBoris Brezillon 	mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
719ed7a34c5SBoris Brezillon 	spin_unlock(&pfdev->as_lock);
720ed7a34c5SBoris Brezillon 
721f3ba9122SRob Herring 	return IRQ_HANDLED;
722f3ba9122SRob Herring };
723f3ba9122SRob Herring 
724f3ba9122SRob Herring int panfrost_mmu_init(struct panfrost_device *pfdev)
725f3ba9122SRob Herring {
726f3ba9122SRob Herring 	int err, irq;
727f3ba9122SRob Herring 
728f3ba9122SRob Herring 	irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu");
729f3ba9122SRob Herring 	if (irq <= 0)
730f3ba9122SRob Herring 		return -ENODEV;
731f3ba9122SRob Herring 
73273896f60SEzequiel Garcia 	err = devm_request_threaded_irq(pfdev->dev, irq,
73373896f60SEzequiel Garcia 					panfrost_mmu_irq_handler,
734b31bdd13SRob Herring 					panfrost_mmu_irq_handler_thread,
73573896f60SEzequiel Garcia 					IRQF_SHARED, KBUILD_MODNAME "-mmu",
73673896f60SEzequiel Garcia 					pfdev);
737f3ba9122SRob Herring 
738f3ba9122SRob Herring 	if (err) {
739f3ba9122SRob Herring 		dev_err(pfdev->dev, "failed to request mmu irq");
740f3ba9122SRob Herring 		return err;
741f3ba9122SRob Herring 	}
742f3ba9122SRob Herring 
743f3ba9122SRob Herring 	return 0;
744f3ba9122SRob Herring }
745f3ba9122SRob Herring 
746f3ba9122SRob Herring void panfrost_mmu_fini(struct panfrost_device *pfdev)
747f3ba9122SRob Herring {
748f3ba9122SRob Herring 	mmu_write(pfdev, MMU_INT_MASK, 0);
749f3ba9122SRob Herring }
750