Просмотр исходного кода

Merge branch 'topic/4.19/pruss' of git://git.ti.com/rpmsg/remoteproc into topic/4.19/am65x

Merge in the PRUSS topic branch into the AM65x remoteproc topic branch
that pulls in the support for setting affinity for the PRU System Events
and a fix for deactivating the PRUSS INTC interrupts when the module is
removed.

* 'topic/4.19/pruss' of git://git.ti.com/rpmsg/remoteproc:
  TEMP: irqchip/irq-pruss-intc: Allow setting irq affinity for PRU events
  irqchip/irq-pruss-intc: Reset chained handlers during cleanup

Signed-off-by: Suman Anna <s-anna@ti.com>
Suman Anna 6 лет назад
Родитель
Сommit
9e787b7e20
1 измененных файлов с 74 добавлено и 0 удалено
  1. 74 0
      drivers/irqchip/irq-pruss-intc.c

+ 74 - 0
drivers/irqchip/irq-pruss-intc.c

@@ -444,6 +444,65 @@ static void pruss_intc_irq_relres(struct irq_data *data)
 	module_put(THIS_MODULE);
 }
 
+#ifdef CONFIG_SMP
+static int pruss_intc_irq_set_affinity(struct irq_data *data,
+				       const struct cpumask *mask_val,
+				       bool force)
+{
+	struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
+	u32 ch, host;
+	s8 sch, shost;
+	unsigned int pirq;
+	struct irq_chip *pchip;
+	struct irq_data *pdata;
+	struct cpumask *eff_mask;
+	int ret;
+
+	/* check for stored channel & host config for this event */
+	sch = intc->config_map.sysev_to_ch[data->hwirq];
+	shost = sch != -1 ? intc->config_map.ch_to_host[sch] : -1;
+	if (sch == -1 || shost == -1) {
+		pr_err("%s: event %lu not configured: ch = %d, host = %d\n",
+		       __func__, data->hwirq, sch, shost);
+		return -EINVAL;
+	}
+
+	/* find programmed channel */
+	ch = pruss_intc_read_reg(intc, PRU_INTC_CMR(data->hwirq / 4));
+	ch >>= (data->hwirq % 4) * 8;
+	ch &= 0xf;
+
+	/* find programmed host interrupt */
+	host = pruss_intc_read_reg(intc, PRU_INTC_HMR(ch / 4));
+	host >>= (ch % 4) * 8;
+	host &= 0xf;
+
+	/* check programmed configuration for sanity */
+	if (ch != sch || host != shost) {
+		pr_err("%s: event %lu has mismatched configuration, ch = %d, host = %d\n",
+		       __func__, data->hwirq, sch, shost);
+		return -EINVAL;
+	}
+
+	/* program affinity using parent GIC irqchip and irqdata */
+	pirq = intc->irqs[host - MIN_PRU_HOST_INT];
+	pchip = irq_get_chip(pirq);
+	pdata = irq_get_irq_data(pirq);
+
+	if (pchip && pchip->irq_set_affinity) {
+		ret = pchip->irq_set_affinity(pdata, mask_val, force);
+		if (ret >= 0) {
+			eff_mask = irq_data_get_effective_affinity_mask(pdata);
+			irq_data_update_effective_affinity(data, eff_mask);
+		}
+
+		return ret;
+	}
+
+	return -EINVAL;
+}
+#endif
+
 /**
  * pruss_intc_trigger() - trigger a PRU system event
  * @irq: linux IRQ number associated with a PRU system event
@@ -596,6 +655,9 @@ static int pruss_intc_probe(struct platform_device *pdev)
 	irqchip->irq_retrigger = pruss_intc_irq_retrigger;
 	irqchip->irq_request_resources = pruss_intc_irq_reqres;
 	irqchip->irq_release_resources = pruss_intc_irq_relres;
+#ifdef CONFIG_SMP
+	irqchip->irq_set_affinity = pruss_intc_irq_set_affinity;
+#endif
 	irqchip->name = dev_name(dev);
 	intc->irqchip = irqchip;
 
@@ -623,6 +685,11 @@ static int pruss_intc_probe(struct platform_device *pdev)
 	return 0;
 
 fail_irq:
+	while (--i >= 0) {
+		if (intc->irqs[i])
+			irq_set_chained_handler_and_data(intc->irqs[i], NULL,
+							 NULL);
+	}
 	irq_domain_remove(intc->domain);
 	return irq;
 }
@@ -632,6 +699,13 @@ static int pruss_intc_remove(struct platform_device *pdev)
 	struct pruss_intc *intc = platform_get_drvdata(pdev);
 	u8 max_system_events = intc->data->num_system_events;
 	unsigned int hwirq;
+	int i;
+
+	for (i = 0; i < MAX_HOST_NUM_IRQS; i++) {
+		if (intc->irqs[i])
+			irq_set_chained_handler_and_data(intc->irqs[i], NULL,
+							 NULL);
+	}
 
 	if (intc->domain) {
 		for (hwirq = 0; hwirq < max_system_events; hwirq++)