aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTero Kristo2019-04-18 18:22:32 -0500
committerSuman Anna2019-04-28 15:59:44 -0500
commit7681b35943a16ee1097bdcf644957842111f95bc (patch)
tree08d04c3980e46673efeb2edde211353b72452f3b
parent6929520b166894ac807fe61d900dd9627eb9554b (diff)
downloadremoteproc-7681b35943a16ee1097bdcf644957842111f95bc.tar.gz
remoteproc-7681b35943a16ee1097bdcf644957842111f95bc.tar.xz
remoteproc-7681b35943a16ee1097bdcf644957842111f95bc.zip
TEMP: irqchip/irq-pruss-intc: Allow setting irq affinity for PRU events
The PRUSS INTC irqchip implementation provides a standard IRQ API for consumers to directly use the PRU System Events as interrupts and uses chained interrupts for connecting these to the main ARM GIC interrupt controller. Add support to the irqchip driver to set irq affinity for these consumer PRU interrupts. These consumer PRU interrupts are not directly connected to the ARM GIC, so it is not possible to directly set the affinity for these interrupts. The affinity is instead set on the real system irq or the actual chained interrupt that the PRU event is mapped to. The system irq is looked up using the programmed channel map and host map registers, and is validated against the configured channel and hosts as the channel map and host map registers are not reset in pruss_intc_unconfigure(). NOTE: 1. The affinity for a PRU event can only be set after its channel map and host map are configured. 2. The PRUSS INTC design allows multiple events on a single system irq, so the actual affinity on the corresponding chained interrupt will be set to the last programmed affinity on any of the connected PRU events. The IRQ affinity data for other events is not updated. Signed-off-by: Tero Kristo <t-kristo@ti.com> [s-anna@ti.com: add error checks, update affinity logic & patch description] Signed-off-by: Suman Anna <s-anna@ti.com>
-rw-r--r--drivers/irqchip/irq-pruss-intc.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index c02e5e9600c9..b3c63ea3d3b5 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -403,6 +403,65 @@ static void pruss_intc_irq_relres(struct irq_data *data)
403 module_put(THIS_MODULE); 403 module_put(THIS_MODULE);
404} 404}
405 405
406#ifdef CONFIG_SMP
407static int pruss_intc_irq_set_affinity(struct irq_data *data,
408 const struct cpumask *mask_val,
409 bool force)
410{
411 struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
412 u32 ch, host;
413 s8 sch, shost;
414 unsigned int pirq;
415 struct irq_chip *pchip;
416 struct irq_data *pdata;
417 struct cpumask *eff_mask;
418 int ret;
419
420 /* check for stored channel & host config for this event */
421 sch = intc->config_map.sysev_to_ch[data->hwirq];
422 shost = sch != -1 ? intc->config_map.ch_to_host[sch] : -1;
423 if (sch == -1 || shost == -1) {
424 pr_err("%s: event %lu not configured: ch = %d, host = %d\n",
425 __func__, data->hwirq, sch, shost);
426 return -EINVAL;
427 }
428
429 /* find programmed channel */
430 ch = pruss_intc_read_reg(intc, PRU_INTC_CMR(data->hwirq / 4));
431 ch >>= (data->hwirq % 4) * 8;
432 ch &= 0xf;
433
434 /* find programmed host interrupt */
435 host = pruss_intc_read_reg(intc, PRU_INTC_HMR(ch / 4));
436 host >>= (ch % 4) * 8;
437 host &= 0xf;
438
439 /* check programmed configuration for sanity */
440 if (ch != sch || host != shost) {
441 pr_err("%s: event %lu has mismatched configuration, ch = %d, host = %d\n",
442 __func__, data->hwirq, sch, shost);
443 return -EINVAL;
444 }
445
446 /* program affinity using parent GIC irqchip and irqdata */
447 pirq = intc->irqs[host - MIN_PRU_HOST_INT];
448 pchip = irq_get_chip(pirq);
449 pdata = irq_get_irq_data(pirq);
450
451 if (pchip && pchip->irq_set_affinity) {
452 ret = pchip->irq_set_affinity(pdata, mask_val, force);
453 if (ret >= 0) {
454 eff_mask = irq_data_get_effective_affinity_mask(pdata);
455 irq_data_update_effective_affinity(data, eff_mask);
456 }
457
458 return ret;
459 }
460
461 return -EINVAL;
462}
463#endif
464
406/** 465/**
407 * pruss_intc_trigger() - trigger a PRU system event 466 * pruss_intc_trigger() - trigger a PRU system event
408 * @irq: linux IRQ number associated with a PRU system event 467 * @irq: linux IRQ number associated with a PRU system event
@@ -549,6 +608,9 @@ static int pruss_intc_probe(struct platform_device *pdev)
549 irqchip->irq_retrigger = pruss_intc_irq_retrigger; 608 irqchip->irq_retrigger = pruss_intc_irq_retrigger;
550 irqchip->irq_request_resources = pruss_intc_irq_reqres; 609 irqchip->irq_request_resources = pruss_intc_irq_reqres;
551 irqchip->irq_release_resources = pruss_intc_irq_relres; 610 irqchip->irq_release_resources = pruss_intc_irq_relres;
611#ifdef CONFIG_SMP
612 irqchip->irq_set_affinity = pruss_intc_irq_set_affinity;
613#endif
552 irqchip->name = dev_name(dev); 614 irqchip->name = dev_name(dev);
553 intc->irqchip = irqchip; 615 intc->irqchip = irqchip;
554 616