linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Two improvements to Octeon irq handling.
@ 2009-10-13 15:51 David Daney
  2009-10-13 15:52 ` [PATCH 1/2] MIPS: Octeon: Use write_lock_irqsave/write_unlock_irqrestore when setting irq affinity David Daney
  2009-10-13 15:52 ` [PATCH 2/2] MIPS: Octeon: Use lockless interrupt controller operations when possible David Daney
  0 siblings, 2 replies; 7+ messages in thread
From: David Daney @ 2009-10-13 15:51 UTC (permalink / raw)
  To: Ralf Baechle, linux-mips

The first patch is a locking correctness issue, the second an optimization.

David Daney (2):
   MIPS: Octeon: Use write_lock_irqsave/write_unlock_irqrestore when
     setting irq affinity.
   MIPS: Octeon: Use lockless interrupt controller operations when
     possible.

  arch/mips/cavium-octeon/octeon-irq.c |  187 
++++++++++++++++++++++++++++++++--
  1 files changed, 178 insertions(+), 9 deletions(-)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] MIPS: Octeon: Use write_lock_irqsave/write_unlock_irqrestore when setting irq affinity.
  2009-10-13 15:51 [PATCH 0/2] Two improvements to Octeon irq handling David Daney
@ 2009-10-13 15:52 ` David Daney
  2009-10-13 16:17   ` Ralf Baechle
  2009-10-13 15:52 ` [PATCH 2/2] MIPS: Octeon: Use lockless interrupt controller operations when possible David Daney
  1 sibling, 1 reply; 7+ messages in thread
From: David Daney @ 2009-10-13 15:52 UTC (permalink / raw)
  To: linux-mips, ralf; +Cc: David Daney

Since the locks are used from interrupt context we need the
irqsave/irqrestore versions of the locking functions.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/cavium-octeon/octeon-irq.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 384f184..0bda5c5 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -182,9 +182,10 @@ static void octeon_irq_ciu0_disable(unsigned int irq)
 static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *dest)
 {
 	int cpu;
+	unsigned long flags;
 	int bit = irq - OCTEON_IRQ_WORKQ0;	/* Bit 0-63 of EN0 */
 
-	write_lock(&octeon_irq_ciu0_rwlock);
+	write_lock_irqsave(&octeon_irq_ciu0_rwlock, flags);
 	for_each_online_cpu(cpu) {
 		int coreid = cpu_logical_map(cpu);
 		uint64_t en0 =
@@ -200,7 +201,7 @@ static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *
 	 * of them are done.
 	 */
 	cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2));
-	write_unlock(&octeon_irq_ciu0_rwlock);
+	write_unlock_irqrestore(&octeon_irq_ciu0_rwlock, flags);
 
 	return 0;
 }
@@ -299,9 +300,10 @@ static void octeon_irq_ciu1_disable(unsigned int irq)
 static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *dest)
 {
 	int cpu;
+	unsigned long flags;
 	int bit = irq - OCTEON_IRQ_WDOG0;	/* Bit 0-63 of EN1 */
 
-	write_lock(&octeon_irq_ciu1_rwlock);
+	write_lock_irqsave(&octeon_irq_ciu1_rwlock, flags);
 	for_each_online_cpu(cpu) {
 		int coreid = cpu_logical_map(cpu);
 		uint64_t en1 =
@@ -318,7 +320,7 @@ static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *
 	 * of them are done.
 	 */
 	cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num() * 2 + 1));
-	write_unlock(&octeon_irq_ciu1_rwlock);
+	write_unlock_irqrestore(&octeon_irq_ciu1_rwlock, flags);
 
 	return 0;
 }
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] MIPS: Octeon: Use lockless interrupt controller operations when possible.
  2009-10-13 15:51 [PATCH 0/2] Two improvements to Octeon irq handling David Daney
  2009-10-13 15:52 ` [PATCH 1/2] MIPS: Octeon: Use write_lock_irqsave/write_unlock_irqrestore when setting irq affinity David Daney
@ 2009-10-13 15:52 ` David Daney
  2009-10-13 16:20   ` Ralf Baechle
  1 sibling, 1 reply; 7+ messages in thread
From: David Daney @ 2009-10-13 15:52 UTC (permalink / raw)
  To: linux-mips, ralf; +Cc: David Daney

Some newer Octeon chips have registers that allow lockless operation
of the interrupt controller.  Take advantage of them.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/cavium-octeon/octeon-irq.c |  177 +++++++++++++++++++++++++++++++++-
 1 files changed, 172 insertions(+), 5 deletions(-)

diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 0bda5c5..865ff7b 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -178,6 +178,50 @@ static void octeon_irq_ciu0_disable(unsigned int irq)
 #endif
 }
 
+/*
+ * Enable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu0_enable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
+}
+
+/*
+ * Disable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu0_disable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+}
+
+/*
+ * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu0_disable_all_v2(unsigned int irq)
+{
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+	int index;
+#ifdef CONFIG_SMP
+	int cpu;
+	for_each_online_cpu(cpu) {
+		index = cpu_logical_map(cpu) * 2;
+		cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+	}
+#else
+	index = cvmx_get_core_num() * 2;
+	cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+#endif
+}
+
 #ifdef CONFIG_SMP
 static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *dest)
 {
@@ -205,8 +249,42 @@ static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *
 
 	return 0;
 }
+
+/*
+ * Set affinity for the irq for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static int octeon_irq_ciu0_set_affinity_v2(unsigned int irq,
+					   const struct cpumask *dest)
+{
+	int cpu;
+	int index;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+	for_each_online_cpu(cpu) {
+		index = cpu_logical_map(cpu) * 2;
+		if (cpumask_test_cpu(cpu, dest))
+			cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
+		else
+			cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+	}
+	return 0;
+}
 #endif
 
+/*
+ * Newer octeon chips have support for lockless CIU operation.
+ */
+static struct irq_chip octeon_irq_chip_ciu0_v2 = {
+	.name = "CIU0",
+	.enable = octeon_irq_ciu0_enable_v2,
+	.disable = octeon_irq_ciu0_disable_all_v2,
+	.ack = octeon_irq_ciu0_disable_v2,
+	.eoi = octeon_irq_ciu0_enable_v2,
+#ifdef CONFIG_SMP
+	.set_affinity = octeon_irq_ciu0_set_affinity_v2,
+#endif
+};
+
 static struct irq_chip octeon_irq_chip_ciu0 = {
 	.name = "CIU0",
 	.enable = octeon_irq_ciu0_enable,
@@ -296,8 +374,53 @@ static void octeon_irq_ciu1_disable(unsigned int irq)
 #endif
 }
 
+/*
+ * Enable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu1_enable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2 + 1;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+}
+
+/*
+ * Disable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu1_disable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2 + 1;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+}
+
+/*
+ * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu1_disable_all_v2(unsigned int irq)
+{
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+	int index;
 #ifdef CONFIG_SMP
-static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *dest)
+	int cpu;
+	for_each_online_cpu(cpu) {
+		index = cpu_logical_map(cpu) * 2 + 1;
+		cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+	}
+#else
+	index = cvmx_get_core_num() * 2 + 1;
+	cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+#endif
+}
+
+#ifdef CONFIG_SMP
+static int octeon_irq_ciu1_set_affinity(unsigned int irq,
+					const struct cpumask *dest)
 {
 	int cpu;
 	unsigned long flags;
@@ -324,8 +447,42 @@ static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *
 
 	return 0;
 }
+
+/*
+ * Set affinity for the irq for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static int octeon_irq_ciu1_set_affinity_v2(unsigned int irq,
+					   const struct cpumask *dest)
+{
+	int cpu;
+	int index;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+	for_each_online_cpu(cpu) {
+		index = cpu_logical_map(cpu) * 2 + 1;
+		if (cpumask_test_cpu(cpu, dest))
+			cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+		else
+			cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+	}
+	return 0;
+}
 #endif
 
+/*
+ * Newer octeon chips have support for lockless CIU operation.
+ */
+static struct irq_chip octeon_irq_chip_ciu1_v2 = {
+	.name = "CIU0",
+	.enable = octeon_irq_ciu1_enable_v2,
+	.disable = octeon_irq_ciu1_disable_all_v2,
+	.ack = octeon_irq_ciu1_disable_v2,
+	.eoi = octeon_irq_ciu1_enable_v2,
+#ifdef CONFIG_SMP
+	.set_affinity = octeon_irq_ciu1_set_affinity_v2,
+#endif
+};
+
 static struct irq_chip octeon_irq_chip_ciu1 = {
 	.name = "CIU1",
 	.enable = octeon_irq_ciu1_enable,
@@ -422,6 +579,8 @@ static struct irq_chip octeon_irq_chip_msi = {
 void __init arch_init_irq(void)
 {
 	int irq;
+	struct irq_chip *chip0;
+	struct irq_chip *chip1;
 
 #ifdef CONFIG_SMP
 	/* Set the default affinity to the boot cpu. */
@@ -432,6 +591,16 @@ void __init arch_init_irq(void)
 	if (NR_IRQS < OCTEON_IRQ_LAST)
 		pr_err("octeon_irq_init: NR_IRQS is set too low\n");
 
+	if (OCTEON_IS_MODEL(OCTEON_CN58XX_PASS2_X) ||
+	    OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) ||
+	    OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X)) {
+		chip0 = &octeon_irq_chip_ciu0_v2;
+		chip1 = &octeon_irq_chip_ciu1_v2;
+	} else {
+		chip0 = &octeon_irq_chip_ciu0;
+		chip1 = &octeon_irq_chip_ciu1;
+	}
+
 	/* 0 - 15 reserved for i8259 master and slave controller. */
 
 	/* 17 - 23 Mips internal */
@@ -442,14 +611,12 @@ void __init arch_init_irq(void)
 
 	/* 24 - 87 CIU_INT_SUM0 */
 	for (irq = OCTEON_IRQ_WORKQ0; irq <= OCTEON_IRQ_BOOTDMA; irq++) {
-		set_irq_chip_and_handler(irq, &octeon_irq_chip_ciu0,
-					 handle_percpu_irq);
+		set_irq_chip_and_handler(irq, chip0, handle_percpu_irq);
 	}
 
 	/* 88 - 151 CIU_INT_SUM1 */
 	for (irq = OCTEON_IRQ_WDOG0; irq <= OCTEON_IRQ_RESERVED151; irq++) {
-		set_irq_chip_and_handler(irq, &octeon_irq_chip_ciu1,
-					 handle_percpu_irq);
+		set_irq_chip_and_handler(irq, chip1, handle_percpu_irq);
 	}
 
 #ifdef CONFIG_PCI_MSI
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] MIPS: Octeon: Use write_lock_irqsave/write_unlock_irqrestore when setting irq affinity.
  2009-10-13 15:52 ` [PATCH 1/2] MIPS: Octeon: Use write_lock_irqsave/write_unlock_irqrestore when setting irq affinity David Daney
@ 2009-10-13 16:17   ` Ralf Baechle
  0 siblings, 0 replies; 7+ messages in thread
From: Ralf Baechle @ 2009-10-13 16:17 UTC (permalink / raw)
  To: David Daney; +Cc: linux-mips

On Tue, Oct 13, 2009 at 08:52:28AM -0700, David Daney wrote:

> Since the locks are used from interrupt context we need the
> irqsave/irqrestore versions of the locking functions.
> 
> Signed-off-by: David Daney <ddaney@caviumnetworks.com>

Looks good, will apply.

  Ralf

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] MIPS: Octeon: Use lockless interrupt controller operations when possible.
  2009-10-13 15:52 ` [PATCH 2/2] MIPS: Octeon: Use lockless interrupt controller operations when possible David Daney
@ 2009-10-13 16:20   ` Ralf Baechle
  2009-10-13 18:26     ` [PATCH] " David Daney
  0 siblings, 1 reply; 7+ messages in thread
From: Ralf Baechle @ 2009-10-13 16:20 UTC (permalink / raw)
  To: David Daney; +Cc: linux-mips

On Tue, Oct 13, 2009 at 08:52:29AM -0700, David Daney wrote:

> Some newer Octeon chips have registers that allow lockless operation
> of the interrupt controller.  Take advantage of them.

Good stuff.

> +/*
> + * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
> + * registers.
> + */
> +static void octeon_irq_ciu0_disable_all_v2(unsigned int irq)
> +{
> +	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
> +	int index;
> +#ifdef CONFIG_SMP
> +	int cpu;
> +	for_each_online_cpu(cpu) {
> +		index = cpu_logical_map(cpu) * 2;
> +		cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
> +	}
> +#else
> +	index = cvmx_get_core_num() * 2;
> +	cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
> +#endif

This #ifdef should be unnecessary.  For NR_CPUS == 1 it is defined as

#define for_each_online_cpu(cpu)   for_each_cpu((cpu), cpu_online_mask)
And for NR_CPUS == 1:
#define for_each_cpu(cpu, mask)                 \
        for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)

Iow, the loop will go away for uniprocessor kernels.

Rest looks ok at a glance.

  Ralf

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] MIPS: Octeon: Use lockless interrupt controller operations when possible.
  2009-10-13 16:20   ` Ralf Baechle
@ 2009-10-13 18:26     ` David Daney
  2009-10-13 19:41       ` Ralf Baechle
  0 siblings, 1 reply; 7+ messages in thread
From: David Daney @ 2009-10-13 18:26 UTC (permalink / raw)
  To: linux-mips, ralf; +Cc: David Daney

Some newer Octeon chips have registers that allow lockless operation
of the interrupt controller.  Take advantage of them.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---

This version gets rid of some redundant CONFIG_SMP code as noticed by Ralf.

 arch/mips/cavium-octeon/octeon-irq.c |  214 ++++++++++++++++++++++++++++------
 1 files changed, 178 insertions(+), 36 deletions(-)

diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 0bda5c5..6f2acf0 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -17,6 +17,15 @@ DEFINE_RWLOCK(octeon_irq_ciu0_rwlock);
 DEFINE_RWLOCK(octeon_irq_ciu1_rwlock);
 DEFINE_SPINLOCK(octeon_irq_msi_lock);
 
+static int octeon_coreid_for_cpu(int cpu)
+{
+#ifdef CONFIG_SMP
+	return cpu_logical_map(cpu);
+#else
+	return cvmx_get_core_num();
+#endif
+}
+
 static void octeon_irq_core_ack(unsigned int irq)
 {
 	unsigned int bit = irq - OCTEON_IRQ_SW0;
@@ -152,11 +161,10 @@ static void octeon_irq_ciu0_disable(unsigned int irq)
 	int bit = irq - OCTEON_IRQ_WORKQ0;	/* Bit 0-63 of EN0 */
 	unsigned long flags;
 	uint64_t en0;
-#ifdef CONFIG_SMP
 	int cpu;
 	write_lock_irqsave(&octeon_irq_ciu0_rwlock, flags);
 	for_each_online_cpu(cpu) {
-		int coreid = cpu_logical_map(cpu);
+		int coreid = octeon_coreid_for_cpu(cpu);
 		en0 = cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2));
 		en0 &= ~(1ull << bit);
 		cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), en0);
@@ -167,15 +175,45 @@ static void octeon_irq_ciu0_disable(unsigned int irq)
 	 */
 	cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2));
 	write_unlock_irqrestore(&octeon_irq_ciu0_rwlock, flags);
-#else
-	int coreid = cvmx_get_core_num();
-	local_irq_save(flags);
-	en0 = cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2));
-	en0 &= ~(1ull << bit);
-	cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), en0);
-	cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2));
-	local_irq_restore(flags);
-#endif
+}
+
+/*
+ * Enable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu0_enable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
+}
+
+/*
+ * Disable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu0_disable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+}
+
+/*
+ * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu0_disable_all_v2(unsigned int irq)
+{
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+	int index;
+	int cpu;
+	for_each_online_cpu(cpu) {
+		index = octeon_coreid_for_cpu(cpu) * 2;
+		cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+	}
 }
 
 #ifdef CONFIG_SMP
@@ -187,7 +225,7 @@ static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *
 
 	write_lock_irqsave(&octeon_irq_ciu0_rwlock, flags);
 	for_each_online_cpu(cpu) {
-		int coreid = cpu_logical_map(cpu);
+		int coreid = octeon_coreid_for_cpu(cpu);
 		uint64_t en0 =
 			cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2));
 		if (cpumask_test_cpu(cpu, dest))
@@ -205,8 +243,42 @@ static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *
 
 	return 0;
 }
+
+/*
+ * Set affinity for the irq for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static int octeon_irq_ciu0_set_affinity_v2(unsigned int irq,
+					   const struct cpumask *dest)
+{
+	int cpu;
+	int index;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+	for_each_online_cpu(cpu) {
+		index = octeon_coreid_for_cpu(cpu) * 2;
+		if (cpumask_test_cpu(cpu, dest))
+			cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
+		else
+			cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+	}
+	return 0;
+}
 #endif
 
+/*
+ * Newer octeon chips have support for lockless CIU operation.
+ */
+static struct irq_chip octeon_irq_chip_ciu0_v2 = {
+	.name = "CIU0",
+	.enable = octeon_irq_ciu0_enable_v2,
+	.disable = octeon_irq_ciu0_disable_all_v2,
+	.ack = octeon_irq_ciu0_disable_v2,
+	.eoi = octeon_irq_ciu0_enable_v2,
+#ifdef CONFIG_SMP
+	.set_affinity = octeon_irq_ciu0_set_affinity_v2,
+#endif
+};
+
 static struct irq_chip octeon_irq_chip_ciu0 = {
 	.name = "CIU0",
 	.enable = octeon_irq_ciu0_enable,
@@ -270,11 +342,10 @@ static void octeon_irq_ciu1_disable(unsigned int irq)
 	int bit = irq - OCTEON_IRQ_WDOG0;	/* Bit 0-63 of EN1 */
 	unsigned long flags;
 	uint64_t en1;
-#ifdef CONFIG_SMP
 	int cpu;
 	write_lock_irqsave(&octeon_irq_ciu1_rwlock, flags);
 	for_each_online_cpu(cpu) {
-		int coreid = cpu_logical_map(cpu);
+		int coreid = octeon_coreid_for_cpu(cpu);
 		en1 = cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1));
 		en1 &= ~(1ull << bit);
 		cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), en1);
@@ -285,19 +356,50 @@ static void octeon_irq_ciu1_disable(unsigned int irq)
 	 */
 	cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num() * 2 + 1));
 	write_unlock_irqrestore(&octeon_irq_ciu1_rwlock, flags);
-#else
-	int coreid = cvmx_get_core_num();
-	local_irq_save(flags);
-	en1 = cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1));
-	en1 &= ~(1ull << bit);
-	cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), en1);
-	cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1));
-	local_irq_restore(flags);
-#endif
+}
+
+/*
+ * Enable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu1_enable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2 + 1;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+}
+
+/*
+ * Disable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu1_disable_v2(unsigned int irq)
+{
+	int index = cvmx_get_core_num() * 2 + 1;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+
+	cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+}
+
+/*
+ * Disable the irq on the all cores for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static void octeon_irq_ciu1_disable_all_v2(unsigned int irq)
+{
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+	int index;
+	int cpu;
+	for_each_online_cpu(cpu) {
+		index = octeon_coreid_for_cpu(cpu) * 2 + 1;
+		cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+	}
 }
 
 #ifdef CONFIG_SMP
-static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *dest)
+static int octeon_irq_ciu1_set_affinity(unsigned int irq,
+					const struct cpumask *dest)
 {
 	int cpu;
 	unsigned long flags;
@@ -305,7 +407,7 @@ static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *
 
 	write_lock_irqsave(&octeon_irq_ciu1_rwlock, flags);
 	for_each_online_cpu(cpu) {
-		int coreid = cpu_logical_map(cpu);
+		int coreid = octeon_coreid_for_cpu(cpu);
 		uint64_t en1 =
 			cvmx_read_csr(CVMX_CIU_INTX_EN1
 				(coreid * 2 + 1));
@@ -324,8 +426,42 @@ static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *
 
 	return 0;
 }
+
+/*
+ * Set affinity for the irq for chips that have the EN*_W1{S,C}
+ * registers.
+ */
+static int octeon_irq_ciu1_set_affinity_v2(unsigned int irq,
+					   const struct cpumask *dest)
+{
+	int cpu;
+	int index;
+	u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+	for_each_online_cpu(cpu) {
+		index = octeon_coreid_for_cpu(cpu) * 2 + 1;
+		if (cpumask_test_cpu(cpu, dest))
+			cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+		else
+			cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+	}
+	return 0;
+}
 #endif
 
+/*
+ * Newer octeon chips have support for lockless CIU operation.
+ */
+static struct irq_chip octeon_irq_chip_ciu1_v2 = {
+	.name = "CIU0",
+	.enable = octeon_irq_ciu1_enable_v2,
+	.disable = octeon_irq_ciu1_disable_all_v2,
+	.ack = octeon_irq_ciu1_disable_v2,
+	.eoi = octeon_irq_ciu1_enable_v2,
+#ifdef CONFIG_SMP
+	.set_affinity = octeon_irq_ciu1_set_affinity_v2,
+#endif
+};
+
 static struct irq_chip octeon_irq_chip_ciu1 = {
 	.name = "CIU1",
 	.enable = octeon_irq_ciu1_enable,
@@ -422,6 +558,8 @@ static struct irq_chip octeon_irq_chip_msi = {
 void __init arch_init_irq(void)
 {
 	int irq;
+	struct irq_chip *chip0;
+	struct irq_chip *chip1;
 
 #ifdef CONFIG_SMP
 	/* Set the default affinity to the boot cpu. */
@@ -432,6 +570,16 @@ void __init arch_init_irq(void)
 	if (NR_IRQS < OCTEON_IRQ_LAST)
 		pr_err("octeon_irq_init: NR_IRQS is set too low\n");
 
+	if (OCTEON_IS_MODEL(OCTEON_CN58XX_PASS2_X) ||
+	    OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) ||
+	    OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X)) {
+		chip0 = &octeon_irq_chip_ciu0_v2;
+		chip1 = &octeon_irq_chip_ciu1_v2;
+	} else {
+		chip0 = &octeon_irq_chip_ciu0;
+		chip1 = &octeon_irq_chip_ciu1;
+	}
+
 	/* 0 - 15 reserved for i8259 master and slave controller. */
 
 	/* 17 - 23 Mips internal */
@@ -442,14 +590,12 @@ void __init arch_init_irq(void)
 
 	/* 24 - 87 CIU_INT_SUM0 */
 	for (irq = OCTEON_IRQ_WORKQ0; irq <= OCTEON_IRQ_BOOTDMA; irq++) {
-		set_irq_chip_and_handler(irq, &octeon_irq_chip_ciu0,
-					 handle_percpu_irq);
+		set_irq_chip_and_handler(irq, chip0, handle_percpu_irq);
 	}
 
 	/* 88 - 151 CIU_INT_SUM1 */
 	for (irq = OCTEON_IRQ_WDOG0; irq <= OCTEON_IRQ_RESERVED151; irq++) {
-		set_irq_chip_and_handler(irq, &octeon_irq_chip_ciu1,
-					 handle_percpu_irq);
+		set_irq_chip_and_handler(irq, chip1, handle_percpu_irq);
 	}
 
 #ifdef CONFIG_PCI_MSI
@@ -507,14 +653,10 @@ asmlinkage void plat_irq_dispatch(void)
 #ifdef CONFIG_HOTPLUG_CPU
 static int is_irq_enabled_on_cpu(unsigned int irq, unsigned int cpu)
 {
-       unsigned int isset;
-#ifdef CONFIG_SMP
-       int coreid = cpu_logical_map(cpu);
-#else
-	int coreid = cvmx_get_core_num();
-#endif
+	unsigned int isset;
+	int coreid = octeon_coreid_for_cpu(cpu);
 	int bit = (irq < OCTEON_IRQ_WDOG0) ?
-		irq - OCTEON_IRQ_WORKQ0 : irq - OCTEON_IRQ_WDOG0;
+		   irq - OCTEON_IRQ_WORKQ0 : irq - OCTEON_IRQ_WDOG0;
        if (irq < 64) {
 		isset = (cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)) &
 			(1ull << bit)) >> bit;
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] MIPS: Octeon: Use lockless interrupt controller operations when possible.
  2009-10-13 18:26     ` [PATCH] " David Daney
@ 2009-10-13 19:41       ` Ralf Baechle
  0 siblings, 0 replies; 7+ messages in thread
From: Ralf Baechle @ 2009-10-13 19:41 UTC (permalink / raw)
  To: David Daney; +Cc: linux-mips

On Tue, Oct 13, 2009 at 11:26:03AM -0700, David Daney wrote:

> Some newer Octeon chips have registers that allow lockless operation
> of the interrupt controller.  Take advantage of them.

Thanks, applied.

  Ralf

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-10-13 19:40 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-13 15:51 [PATCH 0/2] Two improvements to Octeon irq handling David Daney
2009-10-13 15:52 ` [PATCH 1/2] MIPS: Octeon: Use write_lock_irqsave/write_unlock_irqrestore when setting irq affinity David Daney
2009-10-13 16:17   ` Ralf Baechle
2009-10-13 15:52 ` [PATCH 2/2] MIPS: Octeon: Use lockless interrupt controller operations when possible David Daney
2009-10-13 16:20   ` Ralf Baechle
2009-10-13 18:26     ` [PATCH] " David Daney
2009-10-13 19:41       ` Ralf Baechle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).