ARM: Fix build after memfd_create syscall
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / drivers / iommu / exynos7-iommu.c
CommitLineData
3c2a0909
S
1/* linux/drivers/iommu/exynos7_iommu.c
2 *
3 * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifdef CONFIG_EXYNOS_IOMMU_DEBUG
12#define DEBUG
13#endif
14
15#include <linux/kernel.h>
16#include <linux/io.h>
17#include <linux/interrupt.h>
18#include <linux/clk.h>
19#include <linux/err.h>
20#include <linux/errno.h>
21#include <linux/device.h>
22#include <linux/sched.h>
23#include <linux/smc.h>
24
25#include <asm/pgtable.h>
26
27#include "exynos-iommu.h"
28
29#define CFG_MASK 0x01101FBC /* Selecting bit 24, 20, 12-7, 5-2 */
30
31#define PB_INFO_NUM(reg) ((reg) & 0xFF)
32#define L1TLB_ATTR_IM (1 << 16)
33
34#define REG_PT_BASE_PPN 0x00C
35#define REG_MMU_FLUSH 0x010
36#define REG_MMU_FLUSH_ENTRY 0x014
37#define REG_MMU_FLUSH_RANGE 0x018
38#define REG_FLUSH_RANGE_START 0x020
39#define REG_FLUSH_RANGE_END 0x024
40#define REG_MMU_CAPA 0x030
41#define REG_INT_STATUS 0x060
42#define REG_INT_CLEAR 0x064
43#define REG_FAULT_AR_ADDR 0x070
44#define REG_FAULT_AR_TRANS_INFO 0x078
45#define REG_FAULT_AW_ADDR 0x080
46#define REG_FAULT_AW_TRANS_INFO 0x088
47#define REG_L1TLB_CFG 0x100 /* sysmmu v5.1 only */
48#define REG_L1TLB_CTRL 0x108 /* sysmmu v5.1 only */
49#define REG_L2TLB_CFG 0x200 /* sysmmu that has L2TLB only*/
50#define REG_PB_LMM 0x300
51#define REG_PB_INDICATE 0x308
52#define REG_PB_CFG 0x310
53#define REG_PB_START_ADDR 0x320
54#define REG_PB_END_ADDR 0x328
55#define REG_PB_INFO 0x350
56#define REG_SW_DF_VPN 0x400 /* sysmmu v5.1 only */
57#define REG_SW_DF_VPN_CMD_NUM 0x408 /* sysmmu v5.1 only */
58#define REG_L1TLB_READ_ENTRY 0x750
59#define REG_L1TLB_ENTRY_VPN 0x754
60#define REG_L1TLB_ENTRY_PPN 0x75C
61#define REG_L1TLB_ENTRY_ATTR 0x764
62
63/* 'reg' argument must be the value of REG_MMU_CAPA register */
64#define MMU_NUM_L1TLB_ENTRIES(reg) (reg & 0xFF)
65#define MMU_HAVE_PB(reg) (!!((reg >> 20) & 0xF))
66#define MMU_HAVE_L2TLB(reg) (!!((reg >> 8) & 0xFFF))
67
68#define MMU_MAX_DF_CMD 8
69
70#define SYSMMU_FAULTS_NUM (SYSMMU_FAULT_UNKNOWN + 1)
71
72static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
73 "PTW ACCESS FAULT",
74 "PAGE FAULT",
75 "L1TLB MULTI-HIT FAULT",
76 "ACCESS FAULT",
77 "SECURITY FAULT",
78 "UNKNOWN FAULT"
79};
80
81static bool has_sysmmu_capable_pbuf(void __iomem *sfrbase)
82{
83 unsigned long cfg = __raw_readl(sfrbase + REG_MMU_CAPA);
84
85 return MMU_HAVE_PB(cfg) ? true : false;
86}
87
88void __sysmmu_tlb_invalidate_flpdcache(void __iomem *sfrbase, dma_addr_t iova)
89{
90 if (has_sysmmu_capable_pbuf(sfrbase))
91 __raw_writel(iova | 0x1, sfrbase + REG_MMU_FLUSH_ENTRY);
92}
93
94void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase, dma_addr_t iova)
95{
96 __raw_writel(iova | 0x1, sfrbase + REG_MMU_FLUSH_ENTRY);
97}
98
99void __sysmmu_tlb_invalidate(struct sysmmu_drvdata *drvdata,
100 dma_addr_t iova, size_t size)
101{
102 void * __iomem sfrbase = drvdata->sfrbase;
103
104 if (__raw_sysmmu_version(sfrbase) >= MAKE_MMU_VER(5, 1)) {
105 __raw_writel(iova, sfrbase + REG_FLUSH_RANGE_START);
106 __raw_writel(size - 1 + iova, sfrbase + REG_FLUSH_RANGE_END);
107 __raw_writel(0x1, sfrbase + REG_MMU_FLUSH_RANGE);
108 SYSMMU_EVENT_LOG_TLB_INV_RANGE(SYSMMU_DRVDATA_TO_LOG(drvdata),
109 iova, iova + size);
110 } else {
111 if (sysmmu_block(sfrbase)) {
112 __raw_writel(0x1, sfrbase + REG_MMU_FLUSH);
113 SYSMMU_EVENT_LOG_TLB_INV_ALL(
114 SYSMMU_DRVDATA_TO_LOG(drvdata));
115 }
116 sysmmu_unblock(sfrbase);
117 }
118}
119
120void __sysmmu_set_ptbase(void __iomem *sfrbase, phys_addr_t pfn_pgtable)
121{
122 __raw_writel(pfn_pgtable, sfrbase + REG_PT_BASE_PPN);
123
124 __raw_writel(0x1, sfrbase + REG_MMU_FLUSH);
125}
126
127static unsigned int find_lmm_preset(unsigned int num_pb, unsigned int num_bufs)
128{
129 static char lmm_preset[4][6] = { /* [num of PB][num of buffers] */
130 /* 1, 2, 3, 4, 5, 6 */
131 { 1, 1, 0, -1, -1, -1}, /* num of pb: 3 */
132 { 3, 2, 1, 0, -1, -1}, /* num of pb: 4 */
133 {-1, -1, -1, -1, -1, -1},
134 { 5, 5, 4, 2, 1, 0}, /* num of pb: 6 */
135 };
136 unsigned int lmm;
137
138 BUG_ON(num_bufs > 6);
139 lmm = lmm_preset[num_pb - 3][num_bufs - 1];
140 BUG_ON(lmm == -1);
141 return lmm;
142}
143
144static unsigned int find_num_pb(unsigned int num_pb, unsigned int lmm)
145{
146 static char lmm_preset[6][6] = { /* [pb_num - 1][pb_lmm] */
147 {0, 0, 0, 0, 0, 0},
148 {0, 0, 0, 0, 0, 0},
149 {3, 2, 0, 0, 0, 0},
150 {4, 3, 2, 1, 0, 0},
151 {0, 0, 0, 0, 0, 0},
152 {6, 5, 4, 3, 3, 2},
153 };
154
155 num_pb = lmm_preset[num_pb - 1][lmm];
156 BUG_ON(num_pb == 0);
157 return num_pb;
158}
159
160static void __sysmmu_init_pb(void __iomem *sfrbase, unsigned int num_pb)
161{
162 unsigned int i = 0;
163
164 for (i = 0; i < num_pb; i++) {
165 __raw_writel(i, sfrbase + REG_PB_INDICATE);
166 __raw_writel(0, sfrbase + REG_PB_CFG);
167 }
168
169 __raw_writel(0x1, sfrbase + REG_MMU_FLUSH);
170}
171
172static void __sysmmu_set_pbuf(struct sysmmu_drvdata *drvdata,
173 struct sysmmu_prefbuf prefbuf[], int num_bufs)
174{
175 unsigned int i, num_pb, lmm;
176
177 num_pb = PB_INFO_NUM(__raw_readl(drvdata->sfrbase + REG_PB_INFO));
178
179 __sysmmu_init_pb(drvdata->sfrbase,
180 find_num_pb(num_pb,
181 __raw_readl(drvdata->sfrbase + REG_PB_LMM)));
182
183 lmm = find_lmm_preset(num_pb, (unsigned int)num_bufs);
184 num_pb = find_num_pb(num_pb, lmm);
185
186 __raw_writel(lmm, drvdata->sfrbase + REG_PB_LMM);
187
188 SYSMMU_EVENT_LOG_PBLMM(SYSMMU_DRVDATA_TO_LOG(drvdata), lmm, num_bufs);
189
190 for (i = 0; i < num_pb; i++) {
191 __raw_writel(i, drvdata->sfrbase + REG_PB_INDICATE);
192 if ((prefbuf[i].size > 0) && (i < num_bufs)) {
193 __raw_writel(prefbuf[i].base,
194 drvdata->sfrbase + REG_PB_START_ADDR);
195 __raw_writel(prefbuf[i].size - 1 + prefbuf[i].base,
196 drvdata->sfrbase + REG_PB_END_ADDR);
197 __raw_writel(prefbuf[i].config | 1,
198 drvdata->sfrbase + REG_PB_CFG);
199 SYSMMU_EVENT_LOG_PBSET(SYSMMU_DRVDATA_TO_LOG(drvdata),
200 prefbuf[i].config | 1, prefbuf[i].base,
201 prefbuf[i].size - 1 + prefbuf[i].base);
202 } else {
203 if (prefbuf[i].size == 0) {
204 dev_err(drvdata->sysmmu,
205 "%s: Trying to init PB[%d/%d]with zero-size\n",
206 __func__, i, num_bufs);
207 }
208
209 SYSMMU_EVENT_LOG_PBSET(SYSMMU_DRVDATA_TO_LOG(drvdata),
210 0, 0, 0);
211 }
212 }
213}
214
215static void __sysmmu_disable_pbuf(struct sysmmu_drvdata *drvdata)
216{
217 unsigned int i, num_pb;
218
219 num_pb = PB_INFO_NUM(__raw_readl(drvdata->sfrbase + REG_PB_INFO));
220
221 __sysmmu_init_pb(drvdata->sfrbase,
222 find_num_pb(num_pb,
223 __raw_readl(drvdata->sfrbase + REG_PB_LMM)));
224
225 __raw_writel(0, drvdata->sfrbase + REG_PB_LMM);
226
227 SYSMMU_EVENT_LOG_PBLMM(SYSMMU_DRVDATA_TO_LOG(drvdata), 0, 0);
228
229 for (i = 0; i < num_pb; i++) {
230 __raw_writel(i, drvdata->sfrbase + REG_PB_INDICATE);
231 __raw_writel(0, drvdata->sfrbase + REG_PB_CFG);
232 SYSMMU_EVENT_LOG_PBSET(SYSMMU_DRVDATA_TO_LOG(drvdata), 0, 0, 0);
233 }
234}
235
236void __exynos_sysmmu_set_prefbuf_by_region(struct sysmmu_drvdata *drvdata,
237 struct sysmmu_prefbuf pb_reg[], unsigned int num_reg)
238{
239 unsigned int i;
240 int num_bufs = 0;
241 struct sysmmu_prefbuf prefbuf[6];
242
243 if (!has_sysmmu_capable_pbuf(drvdata->sfrbase))
244 return;
245
246 if ((num_reg == 0) || (pb_reg == NULL)) {
247 /* Disabling prefetch buffers */
248 __sysmmu_disable_pbuf(drvdata);
249 return;
250 }
251
252 for (i = 0; i < num_reg; i++) {
253 if (((pb_reg[i].config & SYSMMU_PBUFCFG_WRITE) &&
254 (drvdata->prop & SYSMMU_PROP_WRITE)) ||
255 (!(pb_reg[i].config & SYSMMU_PBUFCFG_WRITE) &&
256 (drvdata->prop & SYSMMU_PROP_READ)))
257 prefbuf[num_bufs++] = pb_reg[i];
258 }
259
260 __sysmmu_set_pbuf(drvdata, prefbuf, num_bufs);
261}
262
263void __exynos_sysmmu_set_prefbuf_by_plane(struct sysmmu_drvdata *drvdata,
264 unsigned int inplanes, unsigned int onplanes,
265 unsigned int ipoption, unsigned int opoption)
266{
267 unsigned int num_pb;
268 int num_bufs;
269 struct sysmmu_prefbuf prefbuf[6];
270
271 if (!has_sysmmu_capable_pbuf(drvdata->sfrbase))
272 return;
273
274 num_pb = PB_INFO_NUM(__raw_readl(drvdata->sfrbase + REG_PB_INFO));
275 if ((num_pb != 3) && (num_pb != 4) && (num_pb != 6)) {
276 dev_err(drvdata->master,
277 "%s: Read invalid PB information from %s\n",
278 __func__, dev_name(drvdata->sysmmu));
279 return;
280 }
281
282 num_bufs = __prepare_prefetch_buffers_by_plane(drvdata,
283 prefbuf, num_pb, inplanes, onplanes,
284 ipoption, opoption);
285
286 if (num_bufs == 0)
287 __sysmmu_disable_pbuf(drvdata);
288 else
289 __sysmmu_set_pbuf(drvdata, prefbuf, num_bufs);
290}
291
292static void __sysmmu_set_df(void __iomem *sfrbase,
293 dma_addr_t iova)
294{
295 __raw_writel(iova, sfrbase + REG_SW_DF_VPN);
296}
297
298void __exynos_sysmmu_set_df(struct sysmmu_drvdata *drvdata, dma_addr_t iova)
299{
300#ifdef CONFIG_EXYNOS7_IOMMU_CHECK_DF
301 int i, num_l1tlb, df_cnt = 0;
302#endif
303 u32 cfg;
304
305 if (MAKE_MMU_VER(5, 1) > __raw_sysmmu_version(drvdata->sfrbase)) {
306 dev_err(drvdata->sysmmu, "%s: SW direct fetch not supported\n",
307 __func__);
308 return;
309 }
310
311#ifdef CONFIG_EXYNOS7_IOMMU_CHECK_DF
312 num_l1tlb = MMU_NUM_L1TLB_ENTRIES(__raw_readl(drvdata->sfrbase +
313 REG_MMU_CAPA));
314 for (i = 0; i < num_l1tlb; i++) {
315 __raw_writel(i, drvdata->sfrbase + REG_L1TLB_READ_ENTRY);
316 cfg = __raw_readl(drvdata->sfrbase + REG_L1TLB_ENTRY_ATTR);
317 if (cfg & L1TLB_ATTR_IM)
318 df_cnt++;
319 }
320
321 if (df_cnt == num_l1tlb) {
322 dev_err(drvdata->sysmmu, "%s: All TLBs are special slots", __func__);
323 return;
324 }
325
326 cfg = __raw_readl(drvdata->sfrbase + REG_SW_DF_VPN_CMD_NUM);
327
328 if ((cfg & 0xFF) > 9) {
329 dev_info(drvdata->sysmmu,
330 "%s: DF command queue is full\n", __func__);
331 return;
332 } else
333#endif
334 {
335 __sysmmu_set_df(drvdata->sfrbase, iova);
336 SYSMMU_EVENT_LOG_DF(SYSMMU_DRVDATA_TO_LOG(drvdata), iova);
337 }
338}
339
340void __exynos_sysmmu_release_df(struct sysmmu_drvdata *drvdata)
341{
342 if (__raw_sysmmu_version(drvdata->sfrbase) >= MAKE_MMU_VER(5, 1)) {
343 __raw_writel(0x1, drvdata->sfrbase + REG_L1TLB_CTRL);
344 SYSMMU_EVENT_LOG_DF_UNLOCK_ALL(SYSMMU_DRVDATA_TO_LOG(drvdata));
345 } else {
346 dev_err(drvdata->sysmmu, "DF is not supported");
347 }
348}
349
350void dump_sysmmu_tlb_pb(void __iomem *sfrbase)
351{
352 unsigned int i, capa, lmm;
353 pgd_t *pgd;
354 pud_t *pud;
355 pmd_t *pmd;
356 pte_t *pte;
357 phys_addr_t phys;
358
359 pr_crit("---------- System MMU Status -----------------------------\n");
360
361 pgd = pgd_offset_k((unsigned long)sfrbase);
362 if (!pgd) {
363 pr_crit("Invalid virtual address %pK\n", sfrbase);
364 return;
365 }
366
367 pud = pud_offset(pgd, (unsigned long)sfrbase);
368 if (!pud) {
369 pr_crit("Invalid virtual address %pK\n", sfrbase);
370 return;
371 }
372
373 pmd = pmd_offset(pud, (unsigned long)sfrbase);
374 if (!pmd) {
375 pr_crit("Invalid virtual address %pK\n", sfrbase);
376 return;
377 }
378
379 pte = pte_offset_kernel(pmd, (unsigned long)sfrbase);
380 if (!pte) {
381 pr_crit("Invalid virtual address %pK\n", sfrbase);
382 return;
383 }
384
385 capa = __raw_readl(sfrbase + REG_MMU_CAPA);
386 lmm = MMU_RAW_VER(__raw_readl(sfrbase + REG_MMU_VERSION));
387
388 phys = pte_pfn(*pte) << PAGE_SHIFT;
389 pr_crit("ADDR: 0x%pa(VA: 0x%pK), MMU_CTRL: %#010x, PT_BASE: %#010x\n",
390 &phys, sfrbase,
391 __raw_readl(sfrbase + REG_MMU_CTRL),
392 __raw_readl(sfrbase + REG_PT_BASE_PPN));
393 pr_crit("VERSION %d.%d, MMU_CFG: %#010x, MMU_STATUS: %#010x\n",
394 MMU_MAJ_VER(lmm), MMU_MIN_VER(lmm),
395 __raw_readl(sfrbase + REG_MMU_CFG),
396 __raw_readl(sfrbase + REG_MMU_STATUS));
397
398 if (lmm == MAKE_MMU_VER(5, 1))
399 pr_crit("TLB hit notify : %s\n",
400 (__raw_readl(sfrbase + REG_L1TLB_CFG) == 2) ?
401 "on" : "off");
402
403 if (MMU_HAVE_L2TLB(capa))
404 pr_crit("Level 2 TLB: %s\n",
405 (__raw_readl(sfrbase + REG_L2TLB_CFG) == 1) ?
406 "on" : "off");
407
408 pr_crit("---------- Level 1 TLB -----------------------------------\n");
409
410 for (i = 0; i < MMU_NUM_L1TLB_ENTRIES(capa); i++) {
411 __raw_writel(i, sfrbase + REG_L1TLB_READ_ENTRY);
412 pr_crit("[%02d] VPN: %#010x, PPN: %#010x, ATTR: %#010x\n",
413 i, __raw_readl(sfrbase + REG_L1TLB_ENTRY_VPN),
414 __raw_readl(sfrbase + REG_L1TLB_ENTRY_PPN),
415 __raw_readl(sfrbase + REG_L1TLB_ENTRY_ATTR));
416 }
417
418 if (!MMU_HAVE_PB(capa))
419 return;
420
421 capa = __raw_readl(sfrbase + REG_PB_INFO);
422 lmm = __raw_readl(sfrbase + REG_PB_LMM);
423
424 pr_crit("---------- Prefetch Buffers ------------------------------\n");
425 pr_crit("PB_INFO: %#010x, PB_LMM: %#010x\n", capa, lmm);
426
427 capa = find_num_pb(capa & 0xFF, lmm);
428
429 for (i = 0; i < capa; i++) {
430 __raw_writel(i, sfrbase + REG_PB_INDICATE);
431 pr_crit("PB[%d] = CFG: %#010x, START: %#010x, END: %#010x\n", i,
432 __raw_readl(sfrbase + REG_PB_CFG),
433 __raw_readl(sfrbase + REG_PB_START_ADDR),
434 __raw_readl(sfrbase + REG_PB_END_ADDR));
435 }
436
437 /* Reading L2TLB is not provided by H/W */
438}
439
440static void show_fault_information(struct sysmmu_drvdata *drvdata,
441 int flags, unsigned long fault_addr)
442{
443 unsigned int info;
444 phys_addr_t pgtable;
445 int fault_id = SYSMMU_FAULT_ID(flags);
446
447 pgtable = __raw_readl(drvdata->sfrbase + REG_PT_BASE_PPN);
448 pgtable <<= PAGE_SHIFT;
449
450 pr_crit("----------------------------------------------------------\n");
451 pr_crit("%s %s %s at %#010lx by %s (page table @ %pa)\n",
452 dev_name(drvdata->sysmmu),
453 (flags & IOMMU_FAULT_WRITE) ? "WRITE" : "READ",
454 sysmmu_fault_name[fault_id], fault_addr,
455 dev_name(drvdata->master), &pgtable);
456
457 if (fault_id == SYSMMU_FAULT_UNKNOWN) {
458 pr_crit("The fault is not caused by this System MMU.\n");
459 pr_crit("Please check IRQ and SFR base address.\n");
460 goto finish;
461 }
462
463 info = __raw_readl(drvdata->sfrbase +
464 ((flags & IOMMU_FAULT_WRITE) ?
465 REG_FAULT_AW_TRANS_INFO : REG_FAULT_AR_TRANS_INFO));
466 pr_crit("AxID: %#x, AxLEN: %#x\n", info & 0xFFFF, (info >> 16) & 0xF);
467
468 if (pgtable != drvdata->pgtable)
469 pr_crit("Page table base of driver: %pa\n",
470 &drvdata->pgtable);
471
472 if (fault_id == SYSMMU_FAULT_PTW_ACCESS) {
473 pr_crit("System MMU has failed to access page table\n");
474 goto finish;
475 }
476
477 if (!pfn_valid(pgtable >> PAGE_SHIFT)) {
478 pr_crit("Page table base is not in a valid memory region\n");
479 } else {
480 sysmmu_pte_t *ent;
481 ent = section_entry(phys_to_virt(pgtable), fault_addr);
482 pr_crit("Lv1 entry: %#010x\n", *ent);
483
484 if (lv1ent_page(ent)) {
485 ent = page_entry(ent, fault_addr);
486 pr_crit("Lv2 entry: %#010x\n", *ent);
487 }
488 }
489
490 dump_sysmmu_tlb_pb(drvdata->sfrbase);
491
492finish:
493 pr_crit("----------------------------------------------------------\n");
494}
495
496#define REG_INT_STATUS_WRITE_BIT 16
497
498irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
499{
500 /* SYSMMU is in blocked when interrupt occurred. */
501 struct sysmmu_drvdata *drvdata = dev_id;
502 unsigned int itype;
503 unsigned long addr = -1;
504 int ret = -ENOSYS;
505 int flags = 0;
506
507 if (!is_sysmmu_active(drvdata)) {
508 /* HACK for MFC fault handling */
509 if(!strncmp("15200000.sysmmu", dev_name(drvdata->sysmmu), 15) ||
510 !strncmp("15210000.sysmmu", dev_name(drvdata->sysmmu), 15))
511 exynos_smc(0x810000DD, 0, 0, 0);
512 else if(!strncmp("15300000.sysmmu", dev_name(drvdata->sysmmu), 15) ||
513 !strncmp("15310000.sysmmu", dev_name(drvdata->sysmmu), 15))
514 exynos_smc(0x810000DD, 0, 0, 1);
515 /*----------------------------*/
516
517 WARN(!is_sysmmu_active(drvdata),
518 "Fault occurred while System MMU %s is not enabled!\n",
519 dev_name(drvdata->sysmmu));
520 }
521
522 itype = __ffs(__raw_readl(drvdata->sfrbase + REG_INT_STATUS));
523 if (itype >= REG_INT_STATUS_WRITE_BIT) {
524 itype -= REG_INT_STATUS_WRITE_BIT;
525 flags = IOMMU_FAULT_WRITE;
526 }
527
528 if (WARN_ON(!(itype < SYSMMU_FAULT_UNKNOWN)))
529 itype = SYSMMU_FAULT_UNKNOWN;
530 else
531 addr = __raw_readl(drvdata->sfrbase +
532 ((flags & IOMMU_FAULT_WRITE) ?
533 REG_FAULT_AW_ADDR : REG_FAULT_AR_ADDR));
534 flags |= SYSMMU_FAULT_FLAG(itype);
535
536 show_fault_information(drvdata, flags, addr);
537
538 if (drvdata->domain) /* master is set if drvdata->domain exists */
539 ret = report_iommu_fault(drvdata->domain,
540 drvdata->master, addr, flags);
541
542#if 0 /* Recovering System MMU fault is available from System MMU v6 */
543 if ((ret == 0) &&
544 ((itype == SYSMMU_FAULT_PAGE_FAULT) ||
545 (itype == SYSMMU_FAULT_ACCESS))) {
546 if (flags & IOMMU_FAULT_WRITE)
547 itype += REG_INT_STATUS_WRITE_BIT;
548 __raw_writel(1 << itype, drvdata->sfrbase + REG_INT_CLEAR);
549
550 sysmmu_unblock(drvdata->sfrbase);
551 } else
552#endif
553
554 panic("Unrecoverable System MMU Fault!!");
555
556 return IRQ_HANDLED;
557}
558
559void __sysmmu_init_config(struct sysmmu_drvdata *drvdata)
560{
561 unsigned long cfg;
562
563 __raw_writel(0, drvdata->sfrbase + REG_MMU_CTRL);
564
565 cfg = CFG_FLPDCACHE | CFG_ACGEN;
566 if (!(drvdata->qos < 0))
567 cfg |= CFG_QOS_OVRRIDE | CFG_QOS(drvdata->qos);
568
569 if (has_sysmmu_capable_pbuf(drvdata->sfrbase))
570 __exynos_sysmmu_set_prefbuf_by_plane(drvdata, 0, 0,
571 SYSMMU_PBUFCFG_DEFAULT_INPUT,
572 SYSMMU_PBUFCFG_DEFAULT_OUTPUT);
573
574 cfg |= __raw_readl(drvdata->sfrbase + REG_MMU_CFG) & ~CFG_MASK;
575 __raw_writel(cfg, drvdata->sfrbase + REG_MMU_CFG);
576}
577
578void dump_sysmmu_ppc_cnt(struct sysmmu_drvdata *drvdata)
579{
580 unsigned int cfg;
581 int i;
582
583 pr_crit("------------- System MMU PPC Status --------------\n");
584 for (i = 0; i < drvdata->event_cnt; i++) {
585 cfg = __raw_readl(drvdata->sfrbase +
586 REG_PPC_EVENT_SEL(i));
587 pr_crit("%s %s %s CNT : %d", dev_name(drvdata->sysmmu),
588 cfg & 0x10 ? "WRITE" : "READ",
589 ppc_event_name[cfg & 0x7],
590 __raw_readl(drvdata->sfrbase + REG_PPC_PMCNT(i)));
591 }
592 pr_crit("--------------------------------------------------\n");
593}
594
595int sysmmu_set_ppc_event(struct sysmmu_drvdata *drvdata, int event)
596{
597 unsigned int cfg;
598
599 if (event < 0 || event > TOTAL_ID_NUM ||
600 event == READ_TLB_MISS || event == WRITE_TLB_MISS ||
601 event == READ_FLPD_MISS_PREFETCH ||
602 event == WRITE_FLPD_MISS_PREFETCH)
603 return -EINVAL;
604
605 if (!drvdata->event_cnt)
606 __raw_writel(0x1, drvdata->sfrbase + REG_PPC_PMNC);
607
608 __raw_writel(event, drvdata->sfrbase +
609 REG_PPC_EVENT_SEL(drvdata->event_cnt));
610 cfg = __raw_readl(drvdata->sfrbase +
611 REG_PPC_CNTENS);
612 __raw_writel(cfg | 0x1 << drvdata->event_cnt,
613 drvdata->sfrbase + REG_PPC_CNTENS);
614 return 0;
615}