diff options
Diffstat (limited to 'arch/powerpc/sysdev/xive/common.c')
| -rw-r--r-- | arch/powerpc/sysdev/xive/common.c | 214 | 
1 files changed, 146 insertions, 68 deletions
| diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index 7b69299c2912..1ca5564bda9d 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -85,6 +85,16 @@ static DEFINE_PER_CPU(struct xive_cpu *, xive_cpu);  #define XIVE_INVALID_TARGET	(-1)  /* + * Global toggle to switch on/off StoreEOI + */ +static bool xive_store_eoi = true; + +static bool xive_is_store_eoi(struct xive_irq_data *xd) +{ +	return xd->flags & XIVE_IRQ_FLAG_STORE_EOI && xive_store_eoi; +} + +/*   * Read the next entry in a queue, return its content if it's valid   * or 0 if there is no new entry.   * @@ -208,7 +218,7 @@ static notrace u8 xive_esb_read(struct xive_irq_data *xd, u32 offset)  {  	u64 val; -	if (offset == XIVE_ESB_SET_PQ_10 && xd->flags & XIVE_IRQ_FLAG_STORE_EOI) +	if (offset == XIVE_ESB_SET_PQ_10 && xive_is_store_eoi(xd))  		offset |= XIVE_ESB_LD_ST_MO;  	if ((xd->flags & XIVE_IRQ_FLAG_H_INT_ESB) && xive_ops->esb_rw) @@ -227,6 +237,21 @@ static void xive_esb_write(struct xive_irq_data *xd, u32 offset, u64 data)  		out_be64(xd->eoi_mmio + offset, data);  } +#if defined(CONFIG_XMON) || defined(CONFIG_DEBUG_FS) +static void xive_irq_data_dump(struct xive_irq_data *xd, char *buffer, size_t size) +{ +	u64 val = xive_esb_read(xd, XIVE_ESB_GET); + +	snprintf(buffer, size, "flags=%c%c%c PQ=%c%c 0x%016llx 0x%016llx", +		 xive_is_store_eoi(xd) ? 'S' : ' ', +		 xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ', +		 xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ', +		 val & XIVE_ESB_VAL_P ? 'P' : '-', +		 val & XIVE_ESB_VAL_Q ? 'Q' : '-', +		 xd->trig_page, xd->eoi_page); +} +#endif +  #ifdef CONFIG_XMON  static notrace void xive_dump_eq(const char *name, struct xive_q *q)  { @@ -252,11 +277,10 @@ notrace void xmon_xive_do_dump(int cpu)  #ifdef CONFIG_SMP  		{ -			u64 val = xive_esb_read(&xc->ipi_data, XIVE_ESB_GET); +			char buffer[128]; -			xmon_printf("IPI=0x%08x PQ=%c%c ", xc->hw_ipi, -				    val & XIVE_ESB_VAL_P ? 'P' : '-', -				    val & XIVE_ESB_VAL_Q ? 'Q' : '-'); +			xive_irq_data_dump(&xc->ipi_data, buffer, sizeof(buffer)); +			xmon_printf("IPI=0x%08x %s", xc->hw_ipi, buffer);  		}  #endif  		xive_dump_eq("EQ", &xc->queue[xive_irq_priority]); @@ -291,15 +315,11 @@ int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d)  		d = xive_get_irq_data(hw_irq);  	if (d) { -		struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); -		u64 val = xive_esb_read(xd, XIVE_ESB_GET); - -		xmon_printf("flags=%c%c%c PQ=%c%c", -			    xd->flags & XIVE_IRQ_FLAG_STORE_EOI ? 'S' : ' ', -			    xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ', -			    xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ', -			    val & XIVE_ESB_VAL_P ? 'P' : '-', -			    val & XIVE_ESB_VAL_Q ? 'Q' : '-'); +		char buffer[128]; + +		xive_irq_data_dump(irq_data_get_irq_handler_data(d), +				   buffer, sizeof(buffer)); +		xmon_printf("%s", buffer);  	}  	xmon_printf("\n"); @@ -385,7 +405,7 @@ static void xive_do_source_eoi(struct xive_irq_data *xd)  	xd->stale_p = false;  	/* If the XIVE supports the new "store EOI facility, use it */ -	if (xd->flags & XIVE_IRQ_FLAG_STORE_EOI) { +	if (xive_is_store_eoi(xd)) {  		xive_esb_write(xd, XIVE_ESB_STORE_EOI, 0);  		return;  	} @@ -451,6 +471,8 @@ static void xive_do_source_set_mask(struct xive_irq_data *xd,  {  	u64 val; +	pr_debug("%s: HW 0x%x %smask\n", __func__, xd->hw_irq, mask ? "" : "un"); +  	/*  	 * If the interrupt had P set, it may be in a queue.  	 * @@ -612,8 +634,8 @@ static unsigned int xive_irq_startup(struct irq_data *d)  	xd->saved_p = false;  	xd->stale_p = false; -	pr_devel("xive_irq_startup: irq %d [0x%x] data @%p\n", -		 d->irq, hw_irq, d); + +	pr_debug("%s: irq %d [0x%x] data @%p\n", __func__, d->irq, hw_irq, d);  	/* Pick a target */  	target = xive_pick_irq_target(d, irq_data_get_affinity_mask(d)); @@ -654,8 +676,7 @@ static void xive_irq_shutdown(struct irq_data *d)  	struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);  	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); -	pr_devel("xive_irq_shutdown: irq %d [0x%x] data @%p\n", -		 d->irq, hw_irq, d); +	pr_debug("%s: irq %d [0x%x] data @%p\n", __func__, d->irq, hw_irq, d);  	if (WARN_ON(xd->target == XIVE_INVALID_TARGET))  		return; @@ -679,7 +700,7 @@ static void xive_irq_unmask(struct irq_data *d)  {  	struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); -	pr_devel("xive_irq_unmask: irq %d data @%p\n", d->irq, xd); +	pr_debug("%s: irq %d data @%p\n", __func__, d->irq, xd);  	xive_do_source_set_mask(xd, false);  } @@ -688,7 +709,7 @@ static void xive_irq_mask(struct irq_data *d)  {  	struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); -	pr_devel("xive_irq_mask: irq %d data @%p\n", d->irq, xd); +	pr_debug("%s: irq %d data @%p\n", __func__, d->irq, xd);  	xive_do_source_set_mask(xd, true);  } @@ -702,7 +723,7 @@ static int xive_irq_set_affinity(struct irq_data *d,  	u32 target, old_target;  	int rc = 0; -	pr_debug("%s: irq %d/%x\n", __func__, d->irq, hw_irq); +	pr_debug("%s: irq %d/0x%x\n", __func__, d->irq, hw_irq);  	/* Is this valid ? */  	if (cpumask_any_and(cpumask, cpu_online_mask) >= nr_cpu_ids) @@ -975,7 +996,7 @@ EXPORT_SYMBOL_GPL(is_xive_irq);  void xive_cleanup_irq_data(struct xive_irq_data *xd)  { -	pr_debug("%s for HW %x\n", __func__, xd->hw_irq); +	pr_debug("%s for HW 0x%x\n", __func__, xd->hw_irq);  	if (xd->eoi_mmio) {  		iounmap(xd->eoi_mmio); @@ -1211,8 +1232,8 @@ static int xive_setup_cpu_ipi(unsigned int cpu)  		pr_err("Failed to map IPI CPU %d\n", cpu);  		return -EIO;  	} -	pr_devel("CPU %d HW IPI %x, virq %d, trig_mmio=%p\n", cpu, -	    xc->hw_ipi, xive_ipi_irq, xc->ipi_data.trig_mmio); +	pr_debug("CPU %d HW IPI 0x%x, virq %d, trig_mmio=%p\n", cpu, +		 xc->hw_ipi, xive_ipi_irq, xc->ipi_data.trig_mmio);  	/* Unmask it */  	xive_do_source_set_mask(&xc->ipi_data, false); @@ -1390,7 +1411,7 @@ static int xive_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,  	if (rc)  		return rc; -	pr_debug("%s %d/%lx #%d\n", __func__, virq, hwirq, nr_irqs); +	pr_debug("%s %d/0x%lx #%d\n", __func__, virq, hwirq, nr_irqs);  	for (i = 0; i < nr_irqs; i++) {  		/* TODO: call xive_irq_domain_map() */ @@ -1504,7 +1525,7 @@ static void xive_setup_cpu(void)  #ifdef CONFIG_SMP  void xive_smp_setup_cpu(void)  { -	pr_devel("SMP setup CPU %d\n", smp_processor_id()); +	pr_debug("SMP setup CPU %d\n", smp_processor_id());  	/* This will have already been done on the boot CPU */  	if (smp_processor_id() != boot_cpuid) @@ -1650,10 +1671,10 @@ bool __init xive_core_init(struct device_node *np, const struct xive_ops *ops,  	ppc_md.get_irq = xive_get_irq;  	__xive_enabled = true; -	pr_devel("Initializing host..\n"); +	pr_debug("Initializing host..\n");  	xive_init_host(np); -	pr_devel("Initializing boot CPU..\n"); +	pr_debug("Initializing boot CPU..\n");  	/* Allocate per-CPU data and queues */  	xive_prepare_cpu(smp_processor_id()); @@ -1691,36 +1712,36 @@ static int __init xive_off(char *arg)  }  __setup("xive=off", xive_off); -static void xive_debug_show_cpu(struct seq_file *m, int cpu) +static int __init xive_store_eoi_cmdline(char *arg) +{ +	if (!arg) +		return -EINVAL; + +	if (strncmp(arg, "off", 3) == 0) { +		pr_info("StoreEOI disabled on kernel command line\n"); +		xive_store_eoi = false; +	} +	return 0; +} +__setup("xive.store-eoi=", xive_store_eoi_cmdline); + +#ifdef CONFIG_DEBUG_FS +static void xive_debug_show_ipi(struct seq_file *m, int cpu)  {  	struct xive_cpu *xc = per_cpu(xive_cpu, cpu); -	seq_printf(m, "CPU %d:", cpu); +	seq_printf(m, "CPU %d: ", cpu);  	if (xc) {  		seq_printf(m, "pp=%02x CPPR=%02x ", xc->pending_prio, xc->cppr);  #ifdef CONFIG_SMP  		{ -			u64 val = xive_esb_read(&xc->ipi_data, XIVE_ESB_GET); +			char buffer[128]; -			seq_printf(m, "IPI=0x%08x PQ=%c%c ", xc->hw_ipi, -				   val & XIVE_ESB_VAL_P ? 'P' : '-', -				   val & XIVE_ESB_VAL_Q ? 'Q' : '-'); +			xive_irq_data_dump(&xc->ipi_data, buffer, sizeof(buffer)); +			seq_printf(m, "IPI=0x%08x %s", xc->hw_ipi, buffer);  		}  #endif -		{ -			struct xive_q *q = &xc->queue[xive_irq_priority]; -			u32 i0, i1, idx; - -			if (q->qpage) { -				idx = q->idx; -				i0 = be32_to_cpup(q->qpage + idx); -				idx = (idx + 1) & q->msk; -				i1 = be32_to_cpup(q->qpage + idx); -				seq_printf(m, "EQ idx=%d T=%d %08x %08x ...", -					   q->idx, q->toggle, i0, i1); -			} -		}  	}  	seq_puts(m, "\n");  } @@ -1732,8 +1753,7 @@ static void xive_debug_show_irq(struct seq_file *m, struct irq_data *d)  	u32 target;  	u8 prio;  	u32 lirq; -	struct xive_irq_data *xd; -	u64 val; +	char buffer[128];  	rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq);  	if (rc) { @@ -1744,43 +1764,101 @@ static void xive_debug_show_irq(struct seq_file *m, struct irq_data *d)  	seq_printf(m, "IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ",  		   hw_irq, target, prio, lirq); -	xd = irq_data_get_irq_handler_data(d); -	val = xive_esb_read(xd, XIVE_ESB_GET); -	seq_printf(m, "flags=%c%c%c PQ=%c%c", -		   xd->flags & XIVE_IRQ_FLAG_STORE_EOI ? 'S' : ' ', -		   xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ', -		   xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ', -		   val & XIVE_ESB_VAL_P ? 'P' : '-', -		   val & XIVE_ESB_VAL_Q ? 'Q' : '-'); +	xive_irq_data_dump(irq_data_get_irq_handler_data(d), buffer, sizeof(buffer)); +	seq_puts(m, buffer);  	seq_puts(m, "\n");  } -static int xive_core_debug_show(struct seq_file *m, void *private) +static int xive_irq_debug_show(struct seq_file *m, void *private)  {  	unsigned int i;  	struct irq_desc *desc; + +	for_each_irq_desc(i, desc) { +		struct irq_data *d = irq_domain_get_irq_data(xive_irq_domain, i); + +		if (d) +			xive_debug_show_irq(m, d); +	} +	return 0; +} +DEFINE_SHOW_ATTRIBUTE(xive_irq_debug); + +static int xive_ipi_debug_show(struct seq_file *m, void *private) +{  	int cpu;  	if (xive_ops->debug_show)  		xive_ops->debug_show(m, private);  	for_each_possible_cpu(cpu) -		xive_debug_show_cpu(m, cpu); +		xive_debug_show_ipi(m, cpu); +	return 0; +} +DEFINE_SHOW_ATTRIBUTE(xive_ipi_debug); -	for_each_irq_desc(i, desc) { -		struct irq_data *d = irq_domain_get_irq_data(xive_irq_domain, i); +static void xive_eq_debug_show_one(struct seq_file *m, struct xive_q *q, u8 prio) +{ +	int i; -		if (d) -			xive_debug_show_irq(m, d); +	seq_printf(m, "EQ%d idx=%d T=%d\n", prio, q->idx, q->toggle); +	if (q->qpage) { +		for (i = 0; i < q->msk + 1; i++) { +			if (!(i % 8)) +				seq_printf(m, "%05d ", i); +			seq_printf(m, "%08x%s", be32_to_cpup(q->qpage + i), +				   (i + 1) % 8 ? " " : "\n"); +		}  	} +	seq_puts(m, "\n"); +} + +static int xive_eq_debug_show(struct seq_file *m, void *private) +{ +	int cpu = (long)m->private; +	struct xive_cpu *xc = per_cpu(xive_cpu, cpu); + +	if (xc) +		xive_eq_debug_show_one(m, &xc->queue[xive_irq_priority], +				       xive_irq_priority);  	return 0;  } -DEFINE_SHOW_ATTRIBUTE(xive_core_debug); +DEFINE_SHOW_ATTRIBUTE(xive_eq_debug); + +static void xive_core_debugfs_create(void) +{ +	struct dentry *xive_dir; +	struct dentry *xive_eq_dir; +	long cpu; +	char name[16]; + +	xive_dir = debugfs_create_dir("xive", arch_debugfs_dir); +	if (IS_ERR(xive_dir)) +		return; + +	debugfs_create_file("ipis", 0400, xive_dir, +			    NULL, &xive_ipi_debug_fops); +	debugfs_create_file("interrupts", 0400, xive_dir, +			    NULL, &xive_irq_debug_fops); +	xive_eq_dir = debugfs_create_dir("eqs", xive_dir); +	for_each_possible_cpu(cpu) { +		snprintf(name, sizeof(name), "cpu%ld", cpu); +		debugfs_create_file(name, 0400, xive_eq_dir, (void *)cpu, +				    &xive_eq_debug_fops); +	} +	debugfs_create_bool("store-eoi", 0600, xive_dir, &xive_store_eoi); + +	if (xive_ops->debug_create) +		xive_ops->debug_create(xive_dir); +} +#else +static inline void xive_core_debugfs_create(void) { } +#endif /* CONFIG_DEBUG_FS */  int xive_core_debug_init(void)  { -	if (xive_enabled()) -		debugfs_create_file("xive", 0400, arch_debugfs_dir, -				    NULL, &xive_core_debug_fops); +	if (xive_enabled() && IS_ENABLED(CONFIG_DEBUG_FS)) +		xive_core_debugfs_create(); +  	return 0;  } |