// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2021 MediaTek Inc. */ #include #include #include #include #include #include #include static unsigned int gic_irq(struct irq_data *d) { return d->hwirq; } static int virq_to_hwirq(unsigned int virq) { struct irq_desc *desc; unsigned int hwirq = 0; desc = irq_to_desc(virq); if (desc) hwirq = gic_irq(&desc->irq_data); else WARN_ON(!desc); return hwirq; } static int mt_irq_dump_status_buf(unsigned int irq, char *buf) { unsigned int result; unsigned int hwirq; int num = 0; char *ptr = buf; struct arm_smccc_res res; if (!ptr) return 0; hwirq = virq_to_hwirq(irq); if (!hwirq) return 0; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] hwirq = %d, virq: %d\n", hwirq, irq); if (num == PAGE_SIZE) goto OUT; arm_smccc_smc(MTK_SIP_KERNEL_GIC_DUMP, 0, hwirq, 0, 0, 0, 0, 0, &res); if (res.a0 == 0) { num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] not allowed to dump!\n"); if (num == PAGE_SIZE) goto OUT; return num; } /* get mask */ result = res.a0 & 0x1; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] enable = %d\n", result); if (num == PAGE_SIZE) goto OUT; /* get group */ result = (res.a0 >> 1) & 0x1; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] group = %d\n", result); if (num == PAGE_SIZE) goto OUT; /* get group modifier */ result = (res.a0 >> 2) & 0x1; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] group modifier = %d\n", result); if (num == PAGE_SIZE) goto OUT; /* get priority */ result = (res.a0 >> 3) & 0xff; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] priority = %d\n", result); if (num == PAGE_SIZE) goto OUT; /* get sensitivity */ result = (res.a0 >> 0xb) & 0x1; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] sensitivity = %x ", result); num += snprintf(ptr + num, PAGE_SIZE - num, "(edge:0x1, level:0x0)\n"); if (num == PAGE_SIZE) goto OUT; /* get pending status */ result = (res.a0 >> 0xc) & 0x1; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] pending = %x\n", result); if (num == PAGE_SIZE) goto OUT; /* get active status */ result = (res.a0 >> 0xd) & 0x1; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] active status = %x\n", result); if (num == PAGE_SIZE) goto OUT; /* get target cpu mask */ result = (res.a0 >> 0xe) & 0xffff; num += snprintf(ptr + num, PAGE_SIZE - num, "[mt gic dump] tartget cpu mask = 0x%x\n", result); if (num == PAGE_SIZE) goto OUT; return num; OUT: pr_info("[mt gic dump] buffer is full\n"); return num; } void mt_irq_dump_status(unsigned int irq) { char *buf = kmalloc(PAGE_SIZE, GFP_ATOMIC); if (!buf) return; /* support GIC PPI/SPI only */ if (mt_irq_dump_status_buf(irq, buf) > 0) pr_info("%s", buf); kfree(buf); } EXPORT_SYMBOL(mt_irq_dump_status); static int __init irq_dbg_init(void) { return 0; } static __exit void irq_dbg_exit(void) { } module_init(irq_dbg_init); module_exit(irq_dbg_exit); MODULE_DESCRIPTION("MediaTek IRQ dbg Driver"); MODULE_LICENSE("GPL v2");