Skip to contentSkip to conversation

fix paca memory usage and NR_CPU loops, factor ipi and simplify irq code

PATCH In review Milton Miller 3 participants 51 messages May 11, 2011 – May 19, 2011

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover fix paca memory usage and NR_CPU loops, factor ipi and simplify irq code

This series represents a somewhat ordered, somewhat meandering series development series of patches I've been working on for the past few weeks.

It starts with memory corruption fixes that need to go back to stable relating to slave cpu searches and paca allocation. After refactoring and taking into consideration of patches merged upstream, I think this is just the first 4, but the next 3 are related.

powerpc: fix memory corruption from unallocated slaves
powerpc: don't search for paca in freed memory powerpc/kdump64: Don't reference freed memory as pacas powerpc/iseries: cleanup and fix secondary startup

powerpc: Respect nr_cpu_ids when calling set_cpu_possible and set_cpu_present
powerpc: use nr_cpu_ids in initial paca allocation
powerpc: call no-longer static setup_nr_cpu_ids instead of replicating it

A search for NR_CPUS found that MSG_ALL_BUT_SELF was only used to enter the debugger, but caused special code loops in all smp_ops, so I pulled that code for a bit more path length in the loop to enter the debugger or kexec. I then simplified the mpic code and factored
out common code in ipi interrupt multiplexing. That allowed an
easy change to remove a set of lwarx/stwcx. in the ipi send path.

powerpc: mpic: limit NR_CPUS loop to 32 bit
powerpc: mpic: break cpumask abstraction earlier
powerpc: remove call sites of MSG_ALL_BUT_SELF
powerpc: remove checks for MSG_ALL and MSG_ALL_BUT_SELF linux/smp.h: remove unused MSG_ flags
powerpc/mpic: simplify ipi cpu mask handling
powerpc: remove powermac/pic.h
powerpc: remove alloc_maybe_bootmem for zalloc version
powerpc: remove stubbed beat smp support
powerpc cell: use smp_request_message_ipi [ patchwork 3780 ]
powerpc: move smp_ops_t from machdep.h to smp.h
powerpc: consolidate ipi message mux and demux
powerpc: add kconfig for muxed smp ipi support
powerpc: use bytes instead of bitops in smp ipi multiplexing

I then got sidetracked with Grant's quest to create irq_domains from the irq_host code. I started going through the irq_host implementations in arch/powerpc, removing some code that was redundant or not called, tring to simplify the interfaces before we export them. Also standardizing the use of the per-irq chip data and handler data.

powerpc: xics: cleanup xics_host_map and ipi
powerpc: radix trees are available before init_IRQ
powerpc: return early if irq_host lookup type is wrong
powerpc: remove trival irq_host_ops.unmap
powerpc: remove i8259 irq_host_ops->unmap
powerpc fsl_msi: don't abuse platform_data for driver_data
powerpc: fsl_msi: use chip_data not handler_data
powerpc: mpc5121_ads_cpld: remove use of NO_IRQ_IGNORE
powerpc: mpc62xx_pic: fix get_irq handling of NO_IRQ
powerpc: psurge: create a irq_host for secondary cpus
powerpc: remove irq_host_ops->remap hook
powerpc: spider-pic: get pic from chip_data instead of irq_map
powerpc: axon_msi: validate msi irq via chip_data
powerpc: add virq_is_host to reduce virq_to_host usage
powerpc: remove virq_to_host
powerpc: make IRQ_NOREQUEST last to clear, first to set

My vision is irq_host (or irq_domain) becomes a small wrapper layer around the irq_desc layer. irq_host details are not needed beyond that layer; the irq_host is a opaque pointer.

Populating reverse mappings (hwirq to virq) will become part of the irq_host layer and happen at create_irq or irq_alloc_virt.

The return value of the reverse map functions will be the irqdesc and ppc_md.get_irq will return the irqdesc. There is no reason to follow up the radix tree lookup of hwirq to irq only to use that in another radix-tree lookup to get the irqdesc that we need. (The only remaining user of NO_IRQ_IGNORE is iSeries, and that special return is the only holdup.)

I already have patches that replace the irq_map.host pointer with a per-irq_host NR_IRQ bitmap (but they are entangled with Grant's series to switch to irq_alloc as the primary allocator). As long as you have fewer than BITS_PER_LONG irq_hosts that will be a win, and the only path that might be slower is searching for the irq_host at unmap time.

For small irq count controllers that want to map all interrupts to linux interrupts (including the legacy irq host), we can replace that bitmap with an irq range.

The irq_host.hostdata field will become a parameter to alloc_irq_host, and will be set as the irq's chip_data before calling ->map. The map routine is free to change this later (ps3 uses per-cpu data, xics now uses the ics sub-ops as chipdata). This allows a irq_host to have several irq_chips for different flows but a driver can have multiple irq_hosts for multiple instances of a given chip, distinguished by chip_data.

My current thinking is the device node pointer stored in the host will become generic match data, still used by the of wrapper to irq_domains as a device node for default matching. Both the match data and the chip data will be availible to the match routine. (This allows us to keep the default of device node = match data without standardizing a match struct inside each irq_hosts chipdata that we have to undo every irq).

After doing a bunch of grep's on arch/sh, I think the interesting parts of super8 interrupt handling that Thomas referred to are in drivers/sh/intc. For some reason they populate the radix tree first with a descriptor of their common interrupt controler abstraction then walk the tree, replacing the tagged elements with the pointer to their equivalent to irq_map. I do not yet understand the purpose of this two phase allocation.

All patches are being sent to linuxppc-dev, a few have additional cc's.

All patches were compiled for 3 configs: a smp 32 bit classic, a 32 bit book-e smp, and a 64 bit server, each had most platforms enabled.
I restricted many of my grep searches to arch/powerpc. I boot tested
using bml.

 arch/powerpc/include/asm/dbell.h                 |    3 +-
 arch/powerpc/include/asm/irq.h                   |    5 +-
 arch/powerpc/include/asm/machdep.h               |   21 ----
 arch/powerpc/include/asm/smp.h                   |   33 +++++-
 arch/powerpc/include/asm/system.h                |    2 -
 arch/powerpc/include/asm/xics.h                  |    2 +-
 arch/powerpc/kernel/crash.c                      |    2 +-
 arch/powerpc/kernel/dbell.c                      |   65 ++----------
 arch/powerpc/kernel/head_64.S                    |   13 ++-
 arch/powerpc/kernel/irq.c                        |  112 ++++----------------
 arch/powerpc/kernel/kgdb.c                       |    2 +-
 arch/powerpc/kernel/misc_64.S                    |   13 ++-
 arch/powerpc/kernel/paca.c                       |   17 +--
 arch/powerpc/kernel/pci_dn.c                     |    3 +-
 arch/powerpc/kernel/setup-common.c               |   14 ++--
 arch/powerpc/kernel/smp.c                        |  118 ++++++++++++++-------
 arch/powerpc/lib/alloc.c                         |    8 --
 arch/powerpc/platforms/512x/mpc5121_ads_cpld.c   |    6 +-
 arch/powerpc/platforms/52xx/mpc52xx_pic.c        |    4 +-
 arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    8 --
 arch/powerpc/platforms/85xx/smp.c                |    6 +-
 arch/powerpc/platforms/Kconfig                   |   11 ++-
 arch/powerpc/platforms/Kconfig.cputype           |    2 +
 arch/powerpc/platforms/cell/Makefile             |    1 -
 arch/powerpc/platforms/cell/axon_msi.c           |    3 +-
 arch/powerpc/platforms/cell/beat_interrupt.c     |   27 -----
 arch/powerpc/platforms/cell/beat_interrupt.h     |    3 -
 arch/powerpc/platforms/cell/beat_smp.c           |  123 ----------------------
 arch/powerpc/platforms/cell/celleb_pci.c         |    6 +-
 arch/powerpc/platforms/cell/celleb_setup.c       |    4 -
 arch/powerpc/platforms/cell/interrupt.c          |   27 ++----
 arch/powerpc/platforms/cell/smp.c                |   18 +---
 arch/powerpc/platforms/cell/spider-pic.c         |   13 ++-
 arch/powerpc/platforms/embedded6xx/flipper-pic.c |    7 --
 arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    7 --
 arch/powerpc/platforms/iseries/Kconfig           |    1 +
 arch/powerpc/platforms/iseries/exception.S       |   59 ++++++----
 arch/powerpc/platforms/iseries/irq.c             |    3 +-
 arch/powerpc/platforms/iseries/setup.c           |    5 +
 arch/powerpc/platforms/iseries/smp.c             |   39 +-------
 arch/powerpc/platforms/iseries/smp.h             |    6 -
 arch/powerpc/platforms/powermac/Kconfig          |   11 ++-
 arch/powerpc/platforms/powermac/pic.c            |   13 +--
 arch/powerpc/platforms/powermac/pic.h            |   11 --
 arch/powerpc/platforms/powermac/pmac.h           |    1 +
 arch/powerpc/platforms/powermac/smp.c            |   87 +++++++++-------
 arch/powerpc/platforms/ps3/interrupt.c           |    6 -
 arch/powerpc/platforms/ps3/smp.c                 |   22 +----
 arch/powerpc/platforms/pseries/smp.c             |    3 +-
 arch/powerpc/sysdev/fsl_msi.c                    |   10 +-
 arch/powerpc/sysdev/i8259.c                      |   13 ---
 arch/powerpc/sysdev/mpic.c                       |   52 +++-------
 arch/powerpc/sysdev/xics/icp-hv.c                |   26 +----
 arch/powerpc/sysdev/xics/icp-native.c            |   26 +----
 arch/powerpc/sysdev/xics/xics-common.c           |   42 ++------
 arch/powerpc/xmon/xmon.c                         |    2 +-
 include/linux/smp.h                              |   10 --
 57 files changed, 363 insertions(+), 794 deletions(-)
 delete mode 100644 arch/powerpc/platforms/cell/beat_smp.c
 delete mode 100644 arch/powerpc/platforms/iseries/smp.h
 delete mode 100644 arch/powerpc/platforms/powermac/pic.h
#1 lore raw

PATCH 1/37 powerpc: fix memory corruption from unallocated slaves

Commit 1fc711f7ffb01089efc58042cfdbac8573d1b59a (powerpc/kexec: Fix race in kexec shutdown) moved the write to signal the cpu had exited the kernel from before the transition to real mode in kexec_smp_wait to kexec_wait.

Unfornately it missed that kexec_wait is used both by cpus leaving the kernel and by secondary slave cpus that were not allocated a paca for what ever reason -- they could be beyond nr_cpus or not described in the current device tree for whatever reason (for example, kexec-load was not refreshed after a cpu hotplug operation). Cpus coming through that path they will write to paca[NR_CPUS] which is beyond the space allocated for the paca data and overwrite memory not allocated to pacas but very likely still real mode accessable).

Move the write back to kexec_smp_wait, which is used only by cpus that found their paca, but after the transition to real mode.

Cc <[email protected]> # (1fc711f was backported to 2.6.32)
---
 arch/powerpc/kernel/misc_64.S |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)
arch/powerpc/kernel/misc_64.S +8 -5
index 206a321..e89df59 100644
@@ -462,7 +462,8 @@ _GLOBAL(disable_kernel_fp)
  * wait for the flag to change, indicating this kernel is going away but
  * the slave code for the next one is at addresses 0 to 100.
  *
- * This is used by all slaves.
+ * This is used by all slaves, even those that did not find a matching
+ * paca in the secondary startup code.
  *
  * Physical (hardware) cpu id should be in r3.
  */
@@ -471,10 +472,6 @@ _GLOBAL(kexec_wait)
 1:	mflr	r5
 	addi	r5,r5,kexec_flag-1b
 
-	li	r4,KEXEC_STATE_REAL_MODE
-	stb	r4,PACAKEXECSTATE(r13)
-	SYNC
-
 99:	HMT_LOW
 #ifdef CONFIG_KEXEC		/* use no memory without kexec */
 	lwz	r4,0(r5)
@@ -499,11 +496,17 @@ kexec_flag:
  *
  * get phys id from paca
  * switch to real mode
+ * mark the paca as no longer used
  * join other cpus in kexec_wait(phys_id)
  */
 _GLOBAL(kexec_smp_wait)
 	lhz	r3,PACAHWCPUID(r13)
 	bl	real_mode
+
+	li	r4,KEXEC_STATE_REAL_MODE
+	stb	r4,PACAKEXECSTATE(r13)
+	SYNC
+
 	b	.kexec_wait
 
 /*
Signature · 1 line
1.7.0.4
#2 lore raw

PATCH 2/37 powerpc: don't search for paca in freed memory

In reply to Milton Miller

Starting with 1426d5a3bd07589534286375998c0c8c6fdc5260 (powerpc:
Dynamically allocate pacas) we free the memory for pacas beyond cpu_possible, but we failed to update the loop the secondary cpus use to find their paca. If the system has running cpu threads for which the kernel did not allocate a paca for they will search the memory that was freed. For instance this could happen when the device tree for a kdump kernel was not updated after a cpu hotplug, or the kernel is running with more cpus than the kernel was configured.

Since c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) we set nr_cpu_ids before telling the cpus to advance, so use that to limit the search.

We can't reference nr_cpu_ids without CONFIG_SMP because it is defined as 1 instead of a memory location, but any extra threads should be sent to kexec_wait in that case anyways, so make that explicit and remove the search loop for UP.

Note to stable: The fix also requires c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) to function. Also 9d07bc841c9779b4d7902e417f4e509996ce805d (Properly handshake CPUs going out of boot spin loop) affects the second chunk, specifically the branch target was 3b before and is 4b after that patch, and there was a blank line before the #ifdef CONFIG_SMP that was removed

Cc <[email protected]> # .34.x: c1854e0072 powerpc: Set nr_cpu_ids early
Cc <[email protected]> # .34.x
---
 arch/powerpc/kernel/head_64.S |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)
arch/powerpc/kernel/head_64.S +8 -5
index 73d6e9a..ba50409 100644
@@ -218,13 +218,19 @@ generic_secondary_common_init:
 	 */
 	LOAD_REG_ADDR(r13, paca)	/* Load paca pointer		 */
 	ld	r13,0(r13)		/* Get base vaddr of paca array	 */
+#ifndef CONFIG_SMP
+	addi	r13,r13,PACA_SIZE	/* know r13 if used accidentally */
+	b	.kexec_wait		/* wait for next kernel if !SMP	 */
+#else
+	LOAD_REG_ADDR(r7, nr_cpu_ids)	/* Load nr_cpu_ids address       */
+	lwz	r7,0(r7)		/* also the max paca allocated 	 */
 	li	r5,0			/* logical cpu id                */
 1:	lhz	r6,PACAHWCPUID(r13)	/* Load HW procid from paca      */
 	cmpw	r6,r24			/* Compare to our id             */
 	beq	2f
 	addi	r13,r13,PACA_SIZE	/* Loop to next PACA on miss     */
 	addi	r5,r5,1
-	cmpwi	r5,NR_CPUS
+	cmpw	r5,r7			/* Check if more pacas exist     */
 	blt	1b
 
 	mr	r3,r24			/* not found, copy phys to r3	 */
@@ -259,9 +265,6 @@ generic_secondary_common_init:
 4:	HMT_LOW
 	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor should */
 					/* start.			 */
-#ifndef CONFIG_SMP
-	b	4b			/* Never go on non-SMP		 */
-#else
 	cmpwi	0,r23,0
 	beq	4b			/* Loop until told to go	 */
 
@@ -273,7 +276,7 @@ generic_secondary_common_init:
 	subi	r1,r1,STACK_FRAME_OVERHEAD
 
 	b	__secondary_start
-#endif
+#endif /* SMP */
 
 /*
  * Turn the MMU off.
Signature · 1 line
1.7.0.4
#3 lore raw

PATCH 3/37 powerpc/kdump64: Don't reference freed memory as pacas

In reply to Milton Miller

Starting with 1426d5a3bd07589534286375998c0c8c6fdc5260 (powerpc:
Dynamically allocate pacas) the space for pacas beyond cpu_possible is freed, but we failed to update the loop in crash.c.

Since c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) the number of pacas allocated is always nr_cpu_ids.

---
This is the simplest fix, and quite sutiable for stable.

We can merge the crash waits with the normal kexec waits later, and fix the hole described in the other version.

---
 arch/powerpc/kernel/crash.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/powerpc/kernel/crash.c +1 -1
index 21f2c78..4e6ee94 100644
@@ -236,7 +236,7 @@ static void crash_kexec_wait_realmode(int cpu)
 	int i;
 
 	msecs = 10000;
-	for (i=0; i < NR_CPUS && msecs > 0; i++) {
+	for (i=0; i < nr_cpu_ids && msecs > 0; i++) {
 		if (i == cpu)
 			continue;
 
Signature · 1 line
1.7.0.4
#4 lore raw

PATCH 4/37 powerpc/iseries: cleanup and fix secondary startup

In reply to Milton Miller

9cb82f2f4692293a27c578c3038518ce4477de72 (Make iSeries spin on __secondary_hold_spinloop, like pSeries) added a load of current_set but this load was repeated later and we don't even have the paca yet. It also checked __secondary_hold_spinloop with a 32 bit compare instead of a 64 bit compare.

b6f6b98a4e91fcf31db7de54c3aa86252fc6fb5f (Don't spin on sync instruction at boot time) missed the copy of the startup code in iseries.

1426d5a3bd07589534286375998c0c8c6fdc5260 (Dynamically allocate pacas) doesn't allow for pacas to be less than lppacas and recalculated the paca location from the cpu id in r0 every time through the secondary loop.

Various revisions over time made the comments on conditional branches confusing with respect to being a hold loop or forward progress

Mostly in-order description of the changes:

Replicate the few lines of code saved by the ugly scoped ifdef CONFIG_SMP in the secondary loop between yielding on UP and marking time with the hypervisor on SMP. Always compile the iseries_secondary_yield loop and use it if the cpu id is above nr_cpu_ids. Change all forward progress paths to be forward branches to the next numerical label. Assign a label to all loops. Move all sync instructions from the loops to the forward progress path. Wait to load current_set until paca is set to go. Move the iseries_secondary_smp_loop label to cover the whole spin loop. Add HMT_MEDIUM when we make forward progress.

---
commpile tested only

---
 arch/powerpc/platforms/iseries/exception.S |   59 ++++++++++++++++-----------
 1 files changed, 35 insertions(+), 24 deletions(-)
arch/powerpc/platforms/iseries/exception.S +35 -24
index a67984c..29c02f3 100644
@@ -61,29 +61,31 @@ system_reset_iSeries:
 /* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
 /* In the UP case we'll yield() later, and we will not access the paca anyway */
 #ifdef CONFIG_SMP
-1:
+iSeries_secondary_wait_paca:
 	HMT_LOW
 	LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
 	ld	r23,0(r23)
-	sync
-	LOAD_REG_ADDR(r3,current_set)
-	sldi	r28,r24,3		/* get current_set[cpu#] */
-	ldx	r3,r3,r28
-	addi	r1,r3,THREAD_SIZE
-	subi	r1,r1,STACK_FRAME_OVERHEAD
 
-	cmpwi	0,r23,0			/* Keep poking the Hypervisor until */
-	bne	2f			/* we're released */
-	/* Let the Hypervisor know we are alive */
+	cmpdi	0,r23,0
+	bne	2f			/* go on when the master is ready */
+
+	/* Keep poking the Hypervisor until we're released */
 	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
 	lis	r3,0x8002
 	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
 	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
 	sc				/* Invoke the hypervisor via a system call */
-	b	1b
-#endif
+	b	iSeries_secondary_wait_paca
 
 2:
+	HMT_MEDIUM
+	sync
+
+	LOAD_REG_ADDR(r3, nr_cpu_ids)	/* get number of pacas allocated */
+	lwz	r3,0(r3)		/* nr_cpus= or NR_CPUS can limit */
+	cmpld	0,r24,r3		/* is our cpu number allocated? */
+	bge	iSeries_secondary_yield	/* no, yield forever */
+
 	/* Load our paca now that it's been allocated */
 	LOAD_REG_ADDR(r13, paca)
 	ld	r13,0(r13)
@@ -94,10 +96,24 @@ system_reset_iSeries:
 	ori	r23,r23,MSR_RI
 	mtmsrd	r23			/* RI on */
 
-	HMT_LOW
-#ifdef CONFIG_SMP
+iSeries_secondary_smp_loop:
 	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor
 					 * should start */
+	cmpwi	0,r23,0
+	bne	3f			/* go on when we are told */
+
+	HMT_LOW
+	/* Let the Hypervisor know we are alive */
+	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
+	lis	r3,0x8002
+	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
+	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
+	sc				/* Invoke the hypervisor via a system call */
+	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */
+	b	iSeries_secondary_smp_loop /* wait for signal to start */
+
+3:
+	HMT_MEDIUM
 	sync
 	LOAD_REG_ADDR(r3,current_set)
 	sldi	r28,r24,3		/* get current_set[cpu#] */
@@ -105,27 +121,22 @@ system_reset_iSeries:
 	addi	r1,r3,THREAD_SIZE
 	subi	r1,r1,STACK_FRAME_OVERHEAD
 
-	cmpwi	0,r23,0
-	beq	iSeries_secondary_smp_loop	/* Loop until told to go */
 	b	__secondary_start		/* Loop until told to go */
-iSeries_secondary_smp_loop:
-	/* Let the Hypervisor know we are alive */
-	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
-	lis	r3,0x8002
-	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
-#else /* CONFIG_SMP */
+#endif /* CONFIG_SMP */
+
+iSeries_secondary_yield:
 	/* Yield the processor.  This is required for non-SMP kernels
 		which are running on multi-threaded machines. */
+	HMT_LOW
 	lis	r3,0x8000
 	rldicr	r3,r3,32,15		/* r3 = (r3 << 32) & 0xffff000000000000 */
 	addi	r3,r3,18		/* r3 = 0x8000000000000012 which is "yield" */
 	li	r4,0			/* "yield timed" */
 	li	r5,-1			/* "yield forever" */
-#endif /* CONFIG_SMP */
 	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
 	sc				/* Invoke the hypervisor via a system call */
 	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */
-	b	2b			/* If SMP not configured, secondaries
+	b	iSeries_secondary_yield	/* If SMP not configured, secondaries
 					 * loop forever */
 
 /***  ISeries-LPAR interrupt handlers ***/
Signature · 1 line
1.7.0.4
#5 lore raw

PATCH 5/37 powerpc: Respect nr_cpu_ids when calling set_cpu_possible and set_cpu_present

In reply to Milton Miller

We should not set cpus above nr_cpu_ids to possible. While we will trigger a warning with CONFIG_CPUMASK_DEBUG, even then the mask initializers will set the bits beyond what the iterators check and cause nr_cpu_ids to increase.

Respecting nr_cpu_ids during setup will allow us to use it in our initial paca allocation. It can be reduced from NR_CPUS by the existing early param nr_cpus=, which was added in 2b633e3fac5efada088b57d31e65401f22bcc18f (smp:
Use nr_cpus= to set nr_cpu_ids early). We already call parse_early_parms between finding the command line and allocating the pacas.

---

Probably-not-worth-Cc: stable (2.6.34 and up)

---
 arch/powerpc/kernel/setup-common.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)
arch/powerpc/kernel/setup-common.c +6 -6
index 1475df6..fce759b 100644
@@ -404,7 +404,7 @@ static void __init cpu_init_thread_core_maps(int tpc)
  *                  cpu_present_mask
  *
  * Having the possible map set up early allows us to restrict allocations
- * of things like irqstacks to num_possible_cpus() rather than NR_CPUS.
+ * of things like irqstacks to nr_cpu_ids rather than NR_CPUS.
  *
  * We do not initialize the online map here; cpus set their own bits in
  * cpu_online_mask as they come up.
@@ -424,7 +424,7 @@ void __init smp_setup_cpu_maps(void)
 
 	DBG("smp_setup_cpu_maps()\n");
 
-	while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
+	while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < nr_cpu_ids) {
 		const int *intserv;
 		int j, len;
 
@@ -443,7 +443,7 @@ void __init smp_setup_cpu_maps(void)
 				intserv = &cpu;	/* assume logical == phys */
 		}
 
-		for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
+		for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
 			DBG("    thread %d -> cpu %d (hard id %d)\n",
 			    j, cpu, intserv[j]);
 			set_cpu_present(cpu, true);
@@ -483,12 +483,12 @@ void __init smp_setup_cpu_maps(void)
 		if (cpu_has_feature(CPU_FTR_SMT))
 			maxcpus *= nthreads;
 
-		if (maxcpus > NR_CPUS) {
+		if (maxcpus > nr_cpu_ids) {
 			printk(KERN_WARNING
 			       "Partition configured for %d cpus, "
 			       "operating system maximum is %d.\n",
-			       maxcpus, NR_CPUS);
-			maxcpus = NR_CPUS;
+			       maxcpus, nr_cpu_ids);
+			maxcpus = nr_cpu_ids;
 		} else
 			printk(KERN_INFO "Partition configured for %d cpus.\n",
 			       maxcpus);
Signature · 1 line
1.7.0.4
#6 lore raw

PATCH 6/37 powerpc: use nr_cpu_ids in initial paca allocation

In reply to Milton Miller

Now that we never set a cpu above nr_cpu_ids possible we can limit our initial paca allocation to nr_cpu_ids. We can then clamp the number of cpus in platforms/iseries/setup.c.

---

---
 arch/powerpc/kernel/paca.c             |   17 ++++++-----------
 arch/powerpc/platforms/iseries/setup.c |    5 +++++
 2 files changed, 11 insertions(+), 11 deletions(-)
arch/powerpc/kernel/paca.c +6 -11
index 102244e..efeb881 100644
@@ -7,7 +7,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/threads.h>
+#include <linux/smp.h>
 #include <linux/module.h>
 #include <linux/memblock.h>
 
@@ -178,7 +178,7 @@ static int __initdata paca_size;
 
 void __init allocate_pacas(void)
 {
-	int nr_cpus, cpu, limit;
+	int cpu, limit;
 
 	/*
 	 * We can't take SLB misses on the paca, and we want to access them
@@ -190,23 +190,18 @@ void __init allocate_pacas(void)
 	if (firmware_has_feature(FW_FEATURE_ISERIES))
 		limit = min(limit, HvPagesToMap * HVPAGESIZE);
 
-	nr_cpus = NR_CPUS;
-	/* On iSeries we know we can never have more than 64 cpus */
-	if (firmware_has_feature(FW_FEATURE_ISERIES))
-		nr_cpus = min(64, nr_cpus);
-
-	paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpus);
+	paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids);
 
 	paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit));
 	memset(paca, 0, paca_size);
 
 	printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
-		paca_size, nr_cpus, paca);
+		paca_size, nr_cpu_ids, paca);
 
-	allocate_lppacas(nr_cpus, limit);
+	allocate_lppacas(nr_cpu_ids, limit);
 
 	/* Can't use for_each_*_cpu, as they aren't functional yet */
-	for (cpu = 0; cpu < nr_cpus; cpu++)
+	for (cpu = 0; cpu < nr_cpu_ids; cpu++)
 		initialise_paca(&paca[cpu], cpu);
 }
 
arch/powerpc/platforms/iseries/setup.c +5 -0
index 81cb8d2..c25a081 100644
@@ -685,6 +685,11 @@ void * __init iSeries_early_setup(void)
 	powerpc_firmware_features |= FW_FEATURE_ISERIES;
 	powerpc_firmware_features |= FW_FEATURE_LPAR;
 
+#ifdef CONFIG_SMP
+	/* On iSeries we know we can never have more than 64 cpus */
+	nr_cpu_ids = max(nr_cpu_ids, 64);
+#endif
+
 	iSeries_fixup_klimit();
 
 	/*
Signature · 1 line
1.7.0.4
#7 lore raw

PATCH 7/37 powerpc: call no-longer static setup_nr_cpu_ids instead of replicating it

In reply to Milton Miller

c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) copied the formerly static setup_nr_cpu_ids from init/main.c but 34db18a054c600b6f81787165669dc572fe4de25 (smp:
move smp setup functions to kernel/smp.c) moved it to kernel/smp.c with a declaration in include/linux/smp.h, so we can call it instead of replicating it.

---
I found this cleanup while c1854e was being merged, but saved it from the end to ease backporting.

---
 arch/powerpc/kernel/setup-common.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/powerpc/kernel/setup-common.c +1 -1
index fce759b..ef33a08 100644
@@ -510,7 +510,7 @@ void __init smp_setup_cpu_maps(void)
 	cpu_init_thread_core_maps(nthreads);
 
 	/* Now that possible cpus are set, set nr_cpu_ids for later use */
-	nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
+	setup_nr_cpu_ids();
 
 	free_unused_pacas();
 }
Signature · 1 line
1.7.0.4
#8 lore raw

PATCH 8/37 powerpc: mpic: limit NR_CPUS loop to 32 bit

In reply to Milton Miller

mpic_physmask was looping NR_CPUS times over a mask that was passed as a u32. Since mpic is architecturaly limited to 32 physical cpus, clamp the logical cpus to 32 when compiling (we could also clamp at runtime to nr_cpu_ids).

---
 arch/powerpc/sysdev/mpic.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/powerpc/sysdev/mpic.c +1 -1
index 824a94f..a93da80 100644
@@ -631,7 +631,7 @@ static inline u32 mpic_physmask(u32 cpumask)
 	int i;
 	u32 mask = 0;
 
-	for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
+	for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1)
 		mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
 	return mask;
 }
Signature · 1 line
1.7.0.4
#9 lore raw

PATCH 9/37 powerpc: mpic: break cpumask abstraction earlier

In reply to Milton Miller

mpic_set_affinity is allocating and freeing a cpumask var even though it was breaking the cpumask abstraction when passing the mask to mpic_physmask. It also didn't have any check for allocatin failure.

Break the cpumask abstraction earlier and use simple bitwise and of the bits from the mask with the bits of cpu_online_mask.

---
 arch/powerpc/sysdev/mpic.c |   10 +++-------
 1 files changed, 3 insertions(+), 7 deletions(-)
arch/powerpc/sysdev/mpic.c +3 -7
index a93da80..116695b 100644
@@ -821,16 +821,12 @@ int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
 
 		mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
 	} else {
-		cpumask_var_t tmp;
+		u32 mask = cpumask_bits(cpumask)[0];
 
-		alloc_cpumask_var(&tmp, GFP_KERNEL);
-
-		cpumask_and(tmp, cpumask, cpu_online_mask);
+		mask &= cpumask_bits(cpu_online_mask)[0];
 
 		mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
-			       mpic_physmask(cpumask_bits(tmp)[0]));
-
-		free_cpumask_var(tmp);
+			       mpic_physmask(mask));
 	}
 
 	return 0;
Signature · 1 line
1.7.0.4
#10 lore raw

PATCH 10/37 powerpc: remove call sites of MSG_ALL_BUT_SELF

In reply to Milton Miller

The only user of MSG_ALL_BUT_SELF in the whole kernel tree is powerpc, and it only uses it to start the debugger. Both debuggers always call smp_send_debugger_break with MSG_ALL_BUT_SELF, and only mpic can do anything more optimal than a loop over all online cpus, but all message passing implementations have to code for this special delivery target.

Convert smp_send_debugger_break to take void and loop calling the smp_ops message_pass function for each of the other cpus in the online cpumask.

Use raw_smp_processor_id() because we are either entering the debugger or trying to start kdump and the additional warning it not useful were it to trigger.

---
 arch/powerpc/include/asm/smp.h |    2 +-
 arch/powerpc/kernel/kgdb.c     |    2 +-
 arch/powerpc/kernel/smp.c      |   19 +++++++++++++------
 arch/powerpc/xmon/xmon.c       |    2 +-
 4 files changed, 16 insertions(+), 9 deletions(-)
arch/powerpc/include/asm/smp.h +1 -1
index 5087349..91472c5 100644
@@ -35,7 +35,7 @@ extern void cpu_die(void);
 
 #ifdef CONFIG_SMP
 
-extern void smp_send_debugger_break(int cpu);
+extern void smp_send_debugger_break(void);
 extern void smp_message_recv(int);
 extern void start_secondary_resume(void);
 
arch/powerpc/kernel/kgdb.c +1 -1
index 42850ee..bd9d35f 100644
@@ -109,7 +109,7 @@ static int kgdb_call_nmi_hook(struct pt_regs *regs)
 #ifdef CONFIG_SMP
 void kgdb_roundup_cpus(unsigned long flags)
 {
-	smp_send_debugger_break(MSG_ALL_BUT_SELF);
+	smp_send_debugger_break();
 }
 #endif
 
arch/powerpc/kernel/smp.c +13 -6
index 87517ab..b744114 100644
@@ -218,11 +218,18 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 		smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
 }
 
-#ifdef CONFIG_DEBUGGER
-void smp_send_debugger_break(int cpu)
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+void smp_send_debugger_break(void)
 {
-	if (likely(smp_ops))
-		smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
+	int cpu;
+	int me = raw_smp_processor_id();
+
+	if (unlikely(!smp_ops))
+		return;
+
+	for_each_online_cpu(cpu)
+		if (cpu != me)
+			smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
 }
 #endif
 
@@ -230,9 +237,9 @@ void smp_send_debugger_break(int cpu)
 void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
 {
 	crash_ipi_function_ptr = crash_ipi_callback;
-	if (crash_ipi_callback && smp_ops) {
+	if (crash_ipi_callback) {
 		mb();
-		smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
+		smp_send_debugger_break();
 	}
 }
 #endif
arch/powerpc/xmon/xmon.c +1 -1
index 91309c5..42541bb 100644
@@ -437,7 +437,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
 		xmon_owner = cpu;
 		mb();
 		if (ncpus > 1) {
-			smp_send_debugger_break(MSG_ALL_BUT_SELF);
+			smp_send_debugger_break();
 			/* wait for other cpus to come in */
 			for (timeout = 100000000; timeout != 0; --timeout) {
 				if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Signature · 1 line
1.7.0.4
#11 lore raw

PATCH 11/37 powerpc: remove checks for MSG_ALL and MSG_ALL_BUT_SELF

In reply to Milton Miller

Now that smp_ops->smp_message_pass is always called with an (online) cpu number for the target remove the checks for MSG_ALL and MSG_ALL_BUT_SELF.

---
rediffed for ppc-next xics split

---
 arch/powerpc/include/asm/dbell.h       |    2 +-
 arch/powerpc/include/asm/machdep.h     |    2 +-
 arch/powerpc/include/asm/xics.h        |    2 +-
 arch/powerpc/kernel/dbell.c            |   29 +++++------------------------
 arch/powerpc/platforms/cell/beat_smp.c |   18 +-----------------
 arch/powerpc/platforms/cell/smp.c      |   18 +-----------------
 arch/powerpc/platforms/iseries/smp.c   |   18 +-----------------
 arch/powerpc/platforms/powermac/smp.c  |   17 +++--------------
 arch/powerpc/platforms/ps3/smp.c       |   22 +++-------------------
 arch/powerpc/sysdev/mpic.c             |   20 ++------------------
 arch/powerpc/sysdev/xics/icp-hv.c      |   18 +-----------------
 arch/powerpc/sysdev/xics/icp-native.c  |   18 +-----------------
 12 files changed, 21 insertions(+), 163 deletions(-)
arch/powerpc/include/asm/dbell.h +1 -1
index 0893ab9..3269eb4 100644
@@ -27,7 +27,7 @@ enum ppc_dbell {
 	PPC_G_DBELL_MC = 4,	/* guest mcheck doorbell */
 };
 
-extern void doorbell_message_pass(int target, int msg);
+extern void doorbell_message_pass(int cpu, int msg);
 extern void doorbell_exception(struct pt_regs *regs);
 extern void doorbell_check_self(void);
 extern void doorbell_setup_this_cpu(void);
arch/powerpc/include/asm/machdep.h +1 -1
index c6345ac..b0802a5 100644
@@ -31,7 +31,7 @@ struct kimage;
 
 #ifdef CONFIG_SMP
 struct smp_ops_t {
-	void  (*message_pass)(int target, int msg);
+	void  (*message_pass)(int cpu, int msg);
 	int   (*probe)(void);
 	int   (*kick_cpu)(int nr);
 	void  (*setup_cpu)(int nr);
arch/powerpc/include/asm/xics.h +1 -1
index 6c06306..1750c8d 100644
@@ -40,7 +40,7 @@ struct icp_ops {
 	void (*teardown_cpu)(void);
 	void (*flush_ipi)(void);
 #ifdef CONFIG_SMP
-	void (*message_pass)(int target, int msg);
+	void (*message_pass)(int cpu, int msg);
 	irq_handler_t ipi_action;
 #endif
 };
arch/powerpc/kernel/dbell.c +5 -24
index 3307a52..e49b24c 100644
@@ -34,32 +34,13 @@ void doorbell_setup_this_cpu(void)
 	info->tag = mfspr(SPRN_PIR) & 0x3fff;
 }
 
-void doorbell_message_pass(int target, int msg)
+void doorbell_message_pass(int cpu, int msg)
 {
 	struct doorbell_cpu_info *info;
-	int i;
-
-	if (target < NR_CPUS) {
-		info = &per_cpu(doorbell_cpu_info, target);
-		set_bit(msg, &info->messages);
-		ppc_msgsnd(PPC_DBELL, 0, info->tag);
-	}
-	else if (target == MSG_ALL_BUT_SELF) {
-		for_each_online_cpu(i) {
-			if (i == smp_processor_id())
-				continue;
-			info = &per_cpu(doorbell_cpu_info, i);
-			set_bit(msg, &info->messages);
-			ppc_msgsnd(PPC_DBELL, 0, info->tag);
-		}
-	}
-	else { /* target == MSG_ALL */
-		for_each_online_cpu(i) {
-			info = &per_cpu(doorbell_cpu_info, i);
-			set_bit(msg, &info->messages);
-		}
-		ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0);
-	}
+
+	info = &per_cpu(doorbell_cpu_info, cpu);
+	set_bit(msg, &info->messages);
+	ppc_msgsnd(PPC_DBELL, 0, info->tag);
 }
 
 void doorbell_exception(struct pt_regs *regs)
arch/powerpc/platforms/cell/beat_smp.c +1 -17
index 3e86acb..23bbe6e 100644
@@ -67,22 +67,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
 	return 0;
 }
 
-static void smp_beatic_message_pass(int target, int msg)
-{
-	unsigned int i;
-
-	if (target < NR_CPUS) {
-		beatic_cause_IPI(target, msg);
-	} else {
-		for_each_online_cpu(i) {
-			if (target == MSG_ALL_BUT_SELF
-			    && i == smp_processor_id())
-				continue;
-			beatic_cause_IPI(i, msg);
-		}
-	}
-}
-
 static int __init smp_beatic_probe(void)
 {
 	return cpumask_weight(cpu_possible_mask);
@@ -105,7 +89,7 @@ static int smp_celleb_cpu_bootable(unsigned int nr)
 	return 1;
 }
 static struct smp_ops_t bpa_beatic_smp_ops = {
-	.message_pass	= smp_beatic_message_pass,
+	.message_pass	= beatic_cause_IPI,
 	.probe		= smp_beatic_probe,
 	.kick_cpu	= smp_celleb_kick_cpu,
 	.setup_cpu	= smp_beatic_setup_cpu,
arch/powerpc/platforms/cell/smp.c +1 -17
index a2161b9..d176e61 100644
@@ -103,22 +103,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
 	return 1;
 }
 
-static void smp_iic_message_pass(int target, int msg)
-{
-	unsigned int i;
-
-	if (target < NR_CPUS) {
-		iic_cause_IPI(target, msg);
-	} else {
-		for_each_online_cpu(i) {
-			if (target == MSG_ALL_BUT_SELF
-			    && i == smp_processor_id())
-				continue;
-			iic_cause_IPI(i, msg);
-		}
-	}
-}
-
 static int __init smp_iic_probe(void)
 {
 	iic_request_IPIs();
@@ -168,7 +152,7 @@ static int smp_cell_cpu_bootable(unsigned int nr)
 	return 1;
 }
 static struct smp_ops_t bpa_iic_smp_ops = {
-	.message_pass	= smp_iic_message_pass,
+	.message_pass	= iic_cause_IPI,
 	.probe		= smp_iic_probe,
 	.kick_cpu	= smp_cell_kick_cpu,
 	.setup_cpu	= smp_cell_setup_cpu,
arch/powerpc/platforms/iseries/smp.c +1 -17
index 02a677a..dcdbc5d 100644
@@ -59,28 +59,12 @@ void iSeries_smp_message_recv(void)
 			smp_message_recv(msg);
 }
 
-static inline void smp_iSeries_do_message(int cpu, int msg)
+static void smp_iSeries_message_pass(int cpu, int msg)
 {
 	set_bit(msg, &iSeries_smp_message[cpu]);
 	HvCall_sendIPI(&(paca[cpu]));
 }
 
-static void smp_iSeries_message_pass(int target, int msg)
-{
-	int i;
-
-	if (target < NR_CPUS)
-		smp_iSeries_do_message(target, msg);
-	else {
-		for_each_online_cpu(i) {
-			if ((target == MSG_ALL_BUT_SELF) &&
-					(i == smp_processor_id()))
-				continue;
-			smp_iSeries_do_message(i, msg);
-		}
-	}
-}
-
 static int smp_iSeries_probe(void)
 {
 	return cpumask_weight(cpu_possible_mask);
arch/powerpc/platforms/powermac/smp.c +3 -14
index 621d4b7..c49e719 100644
@@ -186,21 +186,10 @@ irqreturn_t psurge_primary_intr(int irq, void *d)
 	return IRQ_HANDLED;
 }
 
-static void smp_psurge_message_pass(int target, int msg)
+static void smp_psurge_message_pass(int cpu, int msg)
 {
-	int i;
-
-	if (num_online_cpus() < 2)
-		return;
-
-	for_each_online_cpu(i) {
-		if (target == MSG_ALL
-		    || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
-		    || target == i) {
-			set_bit(msg, &psurge_smp_message[i]);
-			psurge_set_ipi(i);
-		}
-	}
+	set_bit(msg, &psurge_smp_message[cpu]);
+	psurge_set_ipi(cpu);
 }
 
 /*
arch/powerpc/platforms/ps3/smp.c +3 -19
index 51ffde4..4c44794 100644
@@ -39,7 +39,7 @@
 #define MSG_COUNT 4
 static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
 
-static void do_message_pass(int target, int msg)
+static void ps3_smp_message_pass(int cpu, int msg)
 {
 	int result;
 	unsigned int virq;
@@ -49,28 +49,12 @@ static void do_message_pass(int target, int msg)
 		return;
 	}
 
-	virq = per_cpu(ps3_ipi_virqs, target)[msg];
+	virq = per_cpu(ps3_ipi_virqs, cpu)[msg];
 	result = ps3_send_event_locally(virq);
 
 	if (result)
 		DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
-			" (%d)\n", __func__, __LINE__, target, msg, result);
-}
-
-static void ps3_smp_message_pass(int target, int msg)
-{
-	int cpu;
-
-	if (target < NR_CPUS)
-		do_message_pass(target, msg);
-	else if (target == MSG_ALL_BUT_SELF) {
-		for_each_online_cpu(cpu)
-			if (cpu != smp_processor_id())
-				do_message_pass(cpu, msg);
-	} else {
-		for_each_online_cpu(cpu)
-			do_message_pass(cpu, msg);
-	}
+			" (%d)\n", __func__, __LINE__, cpu, msg, result);
 }
 
 static int ps3_smp_probe(void)
arch/powerpc/sysdev/mpic.c +2 -18
index 116695b..68ea50c 100644
@@ -1628,31 +1628,15 @@ static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask)
 		       mpic_physmask(cpumask_bits(cpu_mask)[0]));
 }
 
-void smp_mpic_message_pass(int target, int msg)
+void smp_mpic_message_pass(int cpu, int msg)
 {
-	cpumask_var_t tmp;
-
 	/* make sure we're sending something that translates to an IPI */
 	if ((unsigned int)msg > 3) {
 		printk("SMP %d: smp_message_pass: unknown msg %d\n",
 		       smp_processor_id(), msg);
 		return;
 	}
-	switch (target) {
-	case MSG_ALL:
-		mpic_send_ipi(msg, cpu_online_mask);
-		break;
-	case MSG_ALL_BUT_SELF:
-		alloc_cpumask_var(&tmp, GFP_NOWAIT);
-		cpumask_andnot(tmp, cpu_online_mask,
-			       cpumask_of(smp_processor_id()));
-		mpic_send_ipi(msg, tmp);
-		free_cpumask_var(tmp);
-		break;
-	default:
-		mpic_send_ipi(msg, cpumask_of(target));
-		break;
-	}
+	mpic_send_ipi(msg, cpumask_of(cpu));
 }
 
 int __init smp_mpic_probe(void)
arch/powerpc/sysdev/xics/icp-hv.c +1 -17
index 76e8724..234764c 100644
@@ -118,7 +118,7 @@ static void icp_hv_set_cpu_priority(unsigned char cppr)
 
 #ifdef CONFIG_SMP
 
-static inline void icp_hv_do_message(int cpu, int msg)
+static void icp_hv_message_pass(int cpu, int msg)
 {
 	unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
 
@@ -127,22 +127,6 @@ static inline void icp_hv_do_message(int cpu, int msg)
 	icp_hv_set_qirr(cpu, IPI_PRIORITY);
 }
 
-static void icp_hv_message_pass(int target, int msg)
-{
-	unsigned int i;
-
-	if (target < NR_CPUS) {
-		icp_hv_do_message(target, msg);
-	} else {
-		for_each_online_cpu(i) {
-			if (target == MSG_ALL_BUT_SELF
-			    && i == smp_processor_id())
-				continue;
-			icp_hv_do_message(i, msg);
-		}
-	}
-}
-
 static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id)
 {
 	int cpu = smp_processor_id();
arch/powerpc/sysdev/xics/icp-native.c +1 -17
index 3508321..246500e 100644
@@ -134,7 +134,7 @@ static unsigned int icp_native_get_irq(void)
 
 #ifdef CONFIG_SMP
 
-static inline void icp_native_do_message(int cpu, int msg)
+static void icp_native_message_pass(int cpu, int msg)
 {
 	unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
 
@@ -143,22 +143,6 @@ static inline void icp_native_do_message(int cpu, int msg)
 	icp_native_set_qirr(cpu, IPI_PRIORITY);
 }
 
-static void icp_native_message_pass(int target, int msg)
-{
-	unsigned int i;
-
-	if (target < NR_CPUS) {
-		icp_native_do_message(target, msg);
-	} else {
-		for_each_online_cpu(i) {
-			if (target == MSG_ALL_BUT_SELF
-			    && i == smp_processor_id())
-				continue;
-			icp_native_do_message(i, msg);
-		}
-	}
-}
-
 static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
 {
 	int cpu = smp_processor_id();
Signature · 1 line
1.7.0.4
#12 lore raw

PATCH 12/37 linux/smp.h: remove unused MSG_ flags

In reply to Milton Miller

Now that powerpc has removed its use of MSG_ALL_BUT_SELF and MSG_ALL all these MSG_ flags are unused.

---
To be merged by powerpc with the series posted to linuxppc-dev

After the previous 2 patches, grep shows the following false hits (from partial symbol matches):

find . -name .git -prune -o -name .pc -prune -o -name patches -prune -o -type f|
xargs grep -E 'MSG_(ALL|RESCHEDULE|CALL_FUNCTION|INVALIDATE_TLB|STOP_CPU)'

XFRM_MSG_ALLOCSPI (include/linux/xfrm.h, net/xfrm/xfrm_user.c) CHANNELMSG_ALLOFFERS_DELIVERED (drivers/staging/hv/) PPC_MSG_CALL_FUNCTION, PPC_MSG_RESCHEDULE (arch/powerpc/) SMP_MSG_RESCHEDULE (arch/sh/)

---
 include/linux/smp.h |   10 ----------
 1 files changed, 0 insertions(+), 10 deletions(-)
include/linux/smp.h +0 -10
index 74243c8..7ad824d 100644
@@ -98,16 +98,6 @@ void ipi_call_unlock_irq(void);
  */
 int on_each_cpu(smp_call_func_t func, void *info, int wait);
 
-#define MSG_ALL_BUT_SELF	0x8000	/* Assume <32768 CPU's */
-#define MSG_ALL			0x8001
-
-#define MSG_INVALIDATE_TLB	0x0001	/* Remote processor TLB invalidate */
-#define MSG_STOP_CPU		0x0002	/* Sent to shut down slave CPU's
-					 * when rebooting
-					 */
-#define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
-#define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
-
 /*
  * Mark the boot cpu "online" so that it can call console drivers in
  * printk() and can access its per-cpu storage.
Signature · 1 line
1.7.0.4
#13 lore raw

PATCH 13/37 powerpc/mpic: simplify ipi cpu mask handling

In reply to Milton Miller

Now that MSG_ALL and MSG_ALL_BUT_SELF have been eliminated, smp_mpic_mesage_pass no longer needs to lookup the cpumask just to have mpic_send_ipi extract part of it and recode it in a NR_CPUS loop by mpic_physmask.

---
I chose stepwise refinement but this could be merged into the ALL_BUT_SELF removal patch.

---
 arch/powerpc/sysdev/mpic.c |   24 +++++++++++-------------
 1 files changed, 11 insertions(+), 13 deletions(-)
arch/powerpc/sysdev/mpic.c +11 -13
index 68ea50c..53121f6 100644
@@ -1613,30 +1613,28 @@ void mpic_request_ipis(void)
 	}
 }
 
-static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask)
+void smp_mpic_message_pass(int cpu, int msg)
 {
 	struct mpic *mpic = mpic_primary;
+	u32 physmask;
 
 	BUG_ON(mpic == NULL);
 
-#ifdef DEBUG_IPI
-	DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
-#endif
-
-	mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
-		       ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE),
-		       mpic_physmask(cpumask_bits(cpu_mask)[0]));
-}
-
-void smp_mpic_message_pass(int cpu, int msg)
-{
 	/* make sure we're sending something that translates to an IPI */
 	if ((unsigned int)msg > 3) {
 		printk("SMP %d: smp_message_pass: unknown msg %d\n",
 		       smp_processor_id(), msg);
 		return;
 	}
-	mpic_send_ipi(msg, cpumask_of(cpu));
+
+#ifdef DEBUG_IPI
+	DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg);
+#endif
+
+	physmask = 1 << get_hard_smp_processor_id(cpu);
+
+	mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
+		       msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask);
 }
 
 int __init smp_mpic_probe(void)
Signature · 1 line
1.7.0.4
#14 lore raw

PATCH 14/37 powerpc: remove powermac/pic.h

In reply to Milton Miller

Its unused, and of the three declarations, one is duplicated in pmac.h, the second is static and the third is renamed and static.

---

---
 arch/powerpc/platforms/powermac/pic.h |   11 -----------
 1 files changed, 0 insertions(+), 11 deletions(-)
 delete mode 100644 arch/powerpc/platforms/powermac/pic.h
arch/powerpc/platforms/powermac/pic.h deleted +0 -11
deleted file mode 100644
index d622a83..0000000
@@ -1,11 +0,0 @@
-#ifndef __PPC_PLATFORMS_PMAC_PIC_H
-#define __PPC_PLATFORMS_PMAC_PIC_H
-
-#include <linux/irq.h>
-
-extern struct irq_chip pmac_pic;
-
-extern void pmac_pic_init(void);
-extern int pmac_get_irq(void);
-
-#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
Signature · 1 line
1.7.0.4
#15 lore raw

PATCH 15/37 powerpc: remove alloc_maybe_bootmem for zalloc version

In reply to Milton Miller

Replace all remaining callers of alloc_maybe_bootmem with
zalloc_maybe_bootmem. The callsite in pci_dn is followed with a
memset to clear the memory, and not zeroing at the other callsites in the celleb fake pci code could lead to following uninitialized memory as pointers or even freeing said pointers on error paths.

---
 arch/powerpc/include/asm/system.h        |    2 --
 arch/powerpc/kernel/pci_dn.c             |    3 +--
 arch/powerpc/lib/alloc.c                 |    8 --------
 arch/powerpc/platforms/cell/celleb_pci.c |    6 +++---
 4 files changed, 4 insertions(+), 15 deletions(-)
arch/powerpc/include/asm/system.h +0 -2
index 5e474dd..2dc595d 100644
@@ -219,8 +219,6 @@ extern int mem_init_done;	/* set on boot once kmalloc can be called */
 extern int init_bootmem_done;	/* set once bootmem is available */
 extern phys_addr_t memory_limit;
 extern unsigned long klimit;
-
-extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
 extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
 
 extern int powersave_nap;	/* set if nap mode can be used in idle loop */
arch/powerpc/kernel/pci_dn.c +1 -2
index d225d99..6baabc1 100644
@@ -43,10 +43,9 @@ void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
 	const u32 *regs;
 	struct pci_dn *pdn;
 
-	pdn = alloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
+	pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
 	if (pdn == NULL)
 		return NULL;
-	memset(pdn, 0, sizeof(*pdn));
 	dn->data = pdn;
 	pdn->node = dn;
 	pdn->phb = phb;
arch/powerpc/lib/alloc.c +0 -8
index f53e09c..13b676c 100644
@@ -6,14 +6,6 @@
 
 #include <asm/system.h>
 
-void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask)
-{
-	if (mem_init_done)
-		return kmalloc(size, mask);
-	else
-		return alloc_bootmem(size);
-}
-
 void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask)
 {
 	void *p;
arch/powerpc/platforms/cell/celleb_pci.c +3 -3
index 2904b0a..5822141 100644
@@ -319,7 +319,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
 
 	size = 256;
 	config = &private->fake_config[devno][fn];
-	*config = alloc_maybe_bootmem(size, GFP_KERNEL);
+	*config = zalloc_maybe_bootmem(size, GFP_KERNEL);
 	if (*config == NULL) {
 		printk(KERN_ERR "PCI: "
 		       "not enough memory for fake configuration space\n");
@@ -330,7 +330,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
 
 	size = sizeof(struct celleb_pci_resource);
 	res = &private->res[devno][fn];
-	*res = alloc_maybe_bootmem(size, GFP_KERNEL);
+	*res = zalloc_maybe_bootmem(size, GFP_KERNEL);
 	if (*res == NULL) {
 		printk(KERN_ERR
 		       "PCI: not enough memory for resource data space\n");
@@ -431,7 +431,7 @@ static int __init phb_set_bus_ranges(struct device_node *dev,
 static void __init celleb_alloc_private_mem(struct pci_controller *hose)
 {
 	hose->private_data =
-		alloc_maybe_bootmem(sizeof(struct celleb_pci_private),
+		zalloc_maybe_bootmem(sizeof(struct celleb_pci_private),
 			GFP_KERNEL);
 }
 
Signature · 1 line
1.7.0.4
#16 lore raw

PATCH 16/37 powerpc: remove stubbed beat smp support

In reply to Milton Miller

I have no idea if the beat hypervisor supports multiple cpus in a partition, but the code has not been touched since these stubs were added in February of 2007 except to move them in April of 2008. These are stubs: start_cpu always returns fail (which is dropped), the message passing and reciving are empty functions, and the top of file comment says "Incomplete".

---
 arch/powerpc/platforms/cell/Makefile         |    1 -
 arch/powerpc/platforms/cell/beat_interrupt.c |   16 ----
 arch/powerpc/platforms/cell/beat_interrupt.h |    3 -
 arch/powerpc/platforms/cell/beat_smp.c       |  107 --------------------------
 arch/powerpc/platforms/cell/celleb_setup.c   |    4 -
 5 files changed, 0 insertions(+), 131 deletions(-)
 delete mode 100644 arch/powerpc/platforms/cell/beat_smp.c
arch/powerpc/platforms/cell/Makefile +0 -1
index 8839ef6..a4a8935 100644
@@ -43,7 +43,6 @@ obj-y					+= celleb_setup.o \
 					   beat_hvCall.o beat_interrupt.o \
 					   beat_iommu.o
 
-obj-$(CONFIG_SMP)			+= beat_smp.o
 obj-$(CONFIG_PPC_UDBG_BEAT)		+= beat_udbg.o
 obj-$(CONFIG_SERIAL_TXX9)		+= celleb_scc_sio.o
 obj-$(CONFIG_SPU_BASE)			+= beat_spu_priv1.o
arch/powerpc/platforms/cell/beat_interrupt.c +0 -16
index 4cb9e14..d46f7e4 100644
@@ -257,22 +257,6 @@ void __init beatic_init_IRQ(void)
 	irq_set_default_host(beatic_host);
 }
 
-#ifdef CONFIG_SMP
-
-/* Nullified to compile with SMP mode */
-void beatic_setup_cpu(int cpu)
-{
-}
-
-void beatic_cause_IPI(int cpu, int mesg)
-{
-}
-
-void beatic_request_IPIs(void)
-{
-}
-#endif /* CONFIG_SMP */
-
 void beatic_deinit_IRQ(void)
 {
 	int	i;
arch/powerpc/platforms/cell/beat_interrupt.h +0 -3
index b470fd0..a7e52f9 100644
@@ -24,9 +24,6 @@
 
 extern void beatic_init_IRQ(void);
 extern unsigned int beatic_get_irq(void);
-extern void beatic_cause_IPI(int cpu, int mesg);
-extern void beatic_request_IPIs(void);
-extern void beatic_setup_cpu(int);
 extern void beatic_deinit_IRQ(void);
 
 #endif
arch/powerpc/platforms/cell/beat_smp.c deleted +0 -107

107 lines not on this page · raw message

arch/powerpc/platforms/cell/celleb_setup.c +0 -4
index e538455..d58d9ba 100644
@@ -128,10 +128,6 @@ static void __init celleb_setup_arch_beat(void)
 	spu_management_ops	= &spu_management_of_ops;
 #endif
 
-#ifdef CONFIG_SMP
-	smp_init_celleb();
-#endif
-
 	celleb_setup_arch_common();
 }
 
Signature · 1 line
1.7.0.4
#17 lore raw

PATCH 17/37 powerpc cell: use smp_request_message_ipi

In reply to Milton Miller

This is a request to merge patchwork id 3780 with the same subject. I believe it was marked "changes requested" because it depended on a patch that had requested changes, but those were resolved and this one got overlooked. The next patch will remove smp_msg_recv.

thanks,
milton

Here is the original change log:

Subject: [PATCH 15/16] powerpc cell: use smp_request_message_ipi

cell native has 4 interrupts for ipis, so use the new smp_request_message_ipi to save pathlength and the data-dependent branch.

This has the side effects of enabling the debugger ipi for kdump and setting IRQF_PERCPU for the ipi interrupts. It doesn't undo the virq mapping if it turns out the ipi is not used.

#18 lore raw

PATCH 18/37 powerpc: move smp_ops_t from machdep.h to smp.h

In reply to Milton Miller

I can't see any reason these functions are needed by machdep.h and they are all hidden by CONFIG_SMP with no UP alternative.

Also move the declarations for the fallback timebase ops, which are used to fill in the smp ops.

---
 arch/powerpc/include/asm/machdep.h |   21 ---------------------
 arch/powerpc/include/asm/smp.h     |   15 +++++++++++++++
 2 files changed, 15 insertions(+), 21 deletions(-)
arch/powerpc/include/asm/machdep.h +0 -21
index b0802a5..47cacdd 100644
@@ -29,21 +29,6 @@ struct file;
 struct pci_controller;
 struct kimage;
 
-#ifdef CONFIG_SMP
-struct smp_ops_t {
-	void  (*message_pass)(int cpu, int msg);
-	int   (*probe)(void);
-	int   (*kick_cpu)(int nr);
-	void  (*setup_cpu)(int nr);
-	void  (*bringup_done)(void);
-	void  (*take_timebase)(void);
-	void  (*give_timebase)(void);
-	int   (*cpu_disable)(void);
-	void  (*cpu_die)(unsigned int nr);
-	int   (*cpu_bootable)(unsigned int nr);
-};
-#endif
-
 struct machdep_calls {
 	char		*name;
 #ifdef CONFIG_PPC64
@@ -312,12 +297,6 @@ extern sys_ctrler_t sys_ctrler;
 
 #endif /* CONFIG_PPC_PMAC */
 
-#ifdef CONFIG_SMP
-/* Poor default implementations */
-extern void __devinit smp_generic_give_timebase(void);
-extern void __devinit smp_generic_take_timebase(void);
-#endif /* CONFIG_SMP */
-
 
 /* Functions to produce codes on the leds.
  * The SRC code should be unique for the message category and should
arch/powerpc/include/asm/smp.h +15 -0
index 91472c5..6f7c95c 100644
@@ -35,9 +35,24 @@ extern void cpu_die(void);
 
 #ifdef CONFIG_SMP
 
+struct smp_ops_t {
+	void  (*message_pass)(int cpu, int msg);
+	int   (*probe)(void);
+	int   (*kick_cpu)(int nr);
+	void  (*setup_cpu)(int nr);
+	void  (*bringup_done)(void);
+	void  (*take_timebase)(void);
+	void  (*give_timebase)(void);
+	int   (*cpu_disable)(void);
+	void  (*cpu_die)(unsigned int nr);
+	int   (*cpu_bootable)(unsigned int nr);
+};
+
 extern void smp_send_debugger_break(void);
 extern void smp_message_recv(int);
 extern void start_secondary_resume(void);
+extern void __devinit smp_generic_give_timebase(void);
+extern void __devinit smp_generic_take_timebase(void);
 
 DECLARE_PER_CPU(unsigned int, cpu_pvr);
 
Signature · 1 line
1.7.0.4
#19 lore raw

PATCH 19/37 powerpc: consolidate ipi message mux and demux

In reply to Milton Miller

Consolidate the mux and demux of ipi messages into smp.c and call a new smp_ops callback to actually trigger the ipi.

The powerpc architecture code is optimised for having 4 distinct ipi triggers, which are mapped to 4 distinct messages (ipi many, ipi single, scheduler ipi, and enter debugger). However, several interrupt controllers only provide a single software triggered interrupt that can be delivered to each cpu. To resolve this limitation, each smp_ops implementation created a per-cpu variable that is manipulated with atomic bitops. Since these lines will be contended they are optimialy marked as shared_aligned and take a full cache line for each cpu. Distro kernels may have 2 or 3 of these in their config, each taking per-cpu space even though at most one will be in use.

This consolidation removes smp_message_recv and replaces the single call actions cases with direct calls from the common message recognition loop. The complicated debugger ipi case with its muxed crash handling code is moved to debug_ipi_action which is now called from the demux code (instead of the multi-message action calling smp_message_recv).

I put a call to reschedule_action to increase the likelyhood of correctly merging the anticipated scheduler_ipi() hook coming from the scheduler tree; that single required call can be inlined later.

The actual message decode is a copy of the old pseries xics code with its memory barriers and cache line spacing, augmented with a per-cpu unsigned long based on the book-e doorbell code. The optional data is set via a callback from the implementation and is passed to the new cause-ipi hook along with the logical cpu number. While currently only the doorbell implemntation uses this data it should be almost zero cost to retrieve and pass it -- it adds a single register load for the argument from the same cache line to which we just completed a store and the register is dead on return from the call. I extended the data element from unsigned int to unsigned long in case some other code wanted to associate a pointer.

The doorbell check_self is replaced by a call to smp_muxed_ipi_resend, conditioned on the CPU_DBELL feature. The ifdef guard could be relaxed to CONFIG_SMP but I left it with BOOKE for now.

Also, the doorbell interrupt vector for book-e was not calling irq_enter and irq_exit, which throws off cpu accounting and causes code to not realize it is running in interrupt context. Add the missing calls.

---

This requires patch 3780 be applied first for cell to compile.

---
 arch/powerpc/include/asm/dbell.h       |    3 +-
 arch/powerpc/include/asm/smp.h         |   14 +++--
 arch/powerpc/include/asm/xics.h        |    2 +-
 arch/powerpc/kernel/dbell.c            |   46 +++-------------
 arch/powerpc/kernel/irq.c              |    4 +-
 arch/powerpc/kernel/smp.c              |   92 +++++++++++++++++++++----------
 arch/powerpc/platforms/85xx/smp.c      |    6 ++-
 arch/powerpc/platforms/iseries/irq.c   |    3 +-
 arch/powerpc/platforms/iseries/smp.c   |   23 +-------
 arch/powerpc/platforms/iseries/smp.h   |    6 --
 arch/powerpc/platforms/powermac/smp.c  |   27 ++-------
 arch/powerpc/platforms/pseries/smp.c   |    3 +-
 arch/powerpc/sysdev/xics/icp-hv.c      |   10 +---
 arch/powerpc/sysdev/xics/icp-native.c  |   10 +---
 arch/powerpc/sysdev/xics/xics-common.c |   30 +----------
 15 files changed, 107 insertions(+), 172 deletions(-)
 delete mode 100644 arch/powerpc/platforms/iseries/smp.h
arch/powerpc/include/asm/dbell.h +1 -2
index 3269eb4..9c70d0c 100644
@@ -27,9 +27,8 @@ enum ppc_dbell {
 	PPC_G_DBELL_MC = 4,	/* guest mcheck doorbell */
 };
 
-extern void doorbell_message_pass(int cpu, int msg);
+extern void doorbell_cause_ipi(int cpu, unsigned long data);
 extern void doorbell_exception(struct pt_regs *regs);
-extern void doorbell_check_self(void);
 extern void doorbell_setup_this_cpu(void);
 
 static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
arch/powerpc/include/asm/smp.h +9 -5
index 6f7c95c..9ae64bf 100644
@@ -20,6 +20,7 @@
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/kernel.h>
+#include <linux/irqreturn.h>
 
 #ifndef __ASSEMBLY__
 
@@ -37,6 +38,7 @@ extern void cpu_die(void);
 
 struct smp_ops_t {
 	void  (*message_pass)(int cpu, int msg);
+	void  (*cause_ipi)(int cpu, unsigned long data);
 	int   (*probe)(void);
 	int   (*kick_cpu)(int nr);
 	void  (*setup_cpu)(int nr);
@@ -49,7 +51,6 @@ struct smp_ops_t {
 };
 
 extern void smp_send_debugger_break(void);
-extern void smp_message_recv(int);
 extern void start_secondary_resume(void);
 extern void __devinit smp_generic_give_timebase(void);
 extern void __devinit smp_generic_take_timebase(void);
@@ -109,13 +110,16 @@ extern int cpu_to_core_id(int cpu);
 #define PPC_MSG_CALL_FUNC_SINGLE	2
 #define PPC_MSG_DEBUGGER_BREAK  3
 
-/*
- * irq controllers that have dedicated ipis per message and don't
- * need additional code in the action handler may use this
- */
+/* for irq controllers that have dedicated ipis per message (4) */
 extern int smp_request_message_ipi(int virq, int message);
 extern const char *smp_ipi_name[];
 
+/* for irq controllers with only a single ipi */
+extern void smp_muxed_ipi_set_data(int cpu, unsigned long data);
+extern void smp_muxed_ipi_message_pass(int cpu, int msg);
+extern void smp_muxed_ipi_resend(void);
+extern irqreturn_t smp_ipi_demux(void);
+
 void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
arch/powerpc/include/asm/xics.h +1 -1
index 1750c8d..b183a40 100644
@@ -40,7 +40,7 @@ struct icp_ops {
 	void (*teardown_cpu)(void);
 	void (*flush_ipi)(void);
 #ifdef CONFIG_SMP
-	void (*message_pass)(int cpu, int msg);
+	void (*cause_ipi)(int cpu, unsigned long data);
 	irq_handler_t ipi_action;
 #endif
 };
arch/powerpc/kernel/dbell.c +8 -38

73 lines not on this page · raw message

arch/powerpc/kernel/irq.c +2 -2
index a81dd74..826552c 100644
@@ -66,7 +66,6 @@
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
 #include <asm/udbg.h>
-#include <asm/dbell.h>
 #include <asm/smp.h>
 
 #ifdef CONFIG_PPC64
@@ -160,7 +159,8 @@ notrace void arch_local_irq_restore(unsigned long en)
 
 #if defined(CONFIG_BOOKE) && defined(CONFIG_SMP)
 	/* Check for pending doorbell interrupts and resend to ourself */
-	doorbell_check_self();
+	if (cpu_has_feature(CPU_FTR_DBELL))
+		smp_muxed_ipi_resend();
 #endif
 
 	/*
arch/powerpc/kernel/smp.c +62 -30

110 lines not on this page · raw message

arch/powerpc/platforms/85xx/smp.c +4 -2
index fe3f6a3..d6a93a1 100644
@@ -235,8 +235,10 @@ void __init mpc85xx_smp_init(void)
 		smp_85xx_ops.message_pass = smp_mpic_message_pass;
 	}
 
-	if (cpu_has_feature(CPU_FTR_DBELL))
-		smp_85xx_ops.message_pass = doorbell_message_pass;
+	if (cpu_has_feature(CPU_FTR_DBELL)) {
+		smp_85xx_ops.message_pass = smp_muxed_ipi_message_pass;
+		smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
+	}
 
 	BUG_ON(!smp_85xx_ops.message_pass);
 
arch/powerpc/platforms/iseries/irq.c +1 -2
index 375c21c..b210345 100644
@@ -42,7 +42,6 @@
 #include "irq.h"
 #include "pci.h"
 #include "call_pci.h"
-#include "smp.h"
 
 #ifdef CONFIG_PCI
 
@@ -316,7 +315,7 @@ unsigned int iSeries_get_irq(void)
 #ifdef CONFIG_SMP
 	if (get_lppaca()->int_dword.fields.ipi_cnt) {
 		get_lppaca()->int_dword.fields.ipi_cnt = 0;
-		iSeries_smp_message_recv();
+		smp_ipi_demux();
 	}
 #endif /* CONFIG_SMP */
 	if (hvlpevent_is_pending())
arch/powerpc/platforms/iseries/smp.c +3 -20
index dcdbc5d..e3265ad 100644
@@ -42,26 +42,8 @@
 #include <asm/cputable.h>
 #include <asm/system.h>
 
-#include "smp.h"
-
-static unsigned long iSeries_smp_message[NR_CPUS];
-
-void iSeries_smp_message_recv(void)
-{
-	int cpu = smp_processor_id();
-	int msg;
-
-	if (num_online_cpus() < 2)
-		return;
-
-	for (msg = 0; msg < 4; msg++)
-		if (test_and_clear_bit(msg, &iSeries_smp_message[cpu]))
-			smp_message_recv(msg);
-}
-
-static void smp_iSeries_message_pass(int cpu, int msg)
+static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
 {
-	set_bit(msg, &iSeries_smp_message[cpu]);
 	HvCall_sendIPI(&(paca[cpu]));
 }
 
@@ -93,7 +75,8 @@ static void __devinit smp_iSeries_setup_cpu(int nr)
 }
 
 static struct smp_ops_t iSeries_smp_ops = {
-	.message_pass = smp_iSeries_message_pass,
+	.message_pass = smp_muxed_ipi_message_pass,
+	.cause_ipi    = smp_iSeries_cause_ipi,
 	.probe        = smp_iSeries_probe,
 	.kick_cpu     = smp_iSeries_kick_cpu,
 	.setup_cpu    = smp_iSeries_setup_cpu,
arch/powerpc/platforms/iseries/smp.h deleted +0 -6
deleted file mode 100644
index d501f7d..0000000
@@ -1,6 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_SMP_H
-#define _PLATFORMS_ISERIES_SMP_H
-
-extern void iSeries_smp_message_recv(void);
-
-#endif	/* _PLATFORMS_ISERIES_SMP_H */
arch/powerpc/platforms/powermac/smp.c +6 -21
index c49e719..a340107 100644
@@ -156,28 +156,13 @@ static inline void psurge_clr_ipi(int cpu)
 /*
  * On powersurge (old SMP powermac architecture) we don't have
  * separate IPIs for separate messages like openpic does.  Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
+ * use the generic demux helpers
  *  -- paulus.
  */
-static unsigned long psurge_smp_message[NR_CPUS];
-
 void psurge_smp_message_recv(void)
 {
-	int cpu = smp_processor_id();
-	int msg;
-
-	/* clear interrupt */
-	psurge_clr_ipi(cpu);
-
-	if (num_online_cpus() < 2)
-		return;
-
-	/* make sure there is a message there */
-	for (msg = 0; msg < 4; msg++)
-		if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
-			smp_message_recv(msg);
+	psurge_clr_ipi(smp_processor_id());
+	smp_ipi_demux();
 }
 
 irqreturn_t psurge_primary_intr(int irq, void *d)
@@ -186,9 +171,8 @@ irqreturn_t psurge_primary_intr(int irq, void *d)
 	return IRQ_HANDLED;
 }
 
-static void smp_psurge_message_pass(int cpu, int msg)
+static void smp_psurge_cause_ipi(int cpu, unsigned long data)
 {
-	set_bit(msg, &psurge_smp_message[cpu]);
 	psurge_set_ipi(cpu);
 }
 
@@ -428,7 +412,8 @@ void __init smp_psurge_give_timebase(void)
 
 /* PowerSurge-style Macs */
 struct smp_ops_t psurge_smp_ops = {
-	.message_pass	= smp_psurge_message_pass,
+	.message_pass	= smp_muxed_ipi_message_pass,
+	.cause_ipi	= smp_psurge_cause_ipi,
 	.probe		= smp_psurge_probe,
 	.kick_cpu	= smp_psurge_kick_cpu,
 	.setup_cpu	= smp_psurge_setup_cpu,
arch/powerpc/platforms/pseries/smp.c +2 -1
index 95f5781..fbffd7e 100644
@@ -207,7 +207,8 @@ static struct smp_ops_t pSeries_mpic_smp_ops = {
 };
 
 static struct smp_ops_t pSeries_xics_smp_ops = {
-	.message_pass	= NULL,	/* Filled at runtime by xics_smp_probe() */
+	.message_pass	= smp_muxed_ipi_message_pass,
+	.cause_ipi	= NULL,	/* Filled at runtime by xics_smp_probe() */
 	.probe		= xics_smp_probe,
 	.kick_cpu	= smp_pSeries_kick_cpu,
 	.setup_cpu	= smp_xics_setup_cpu,
arch/powerpc/sysdev/xics/icp-hv.c +3 -7
index 234764c..9518d36 100644
@@ -118,12 +118,8 @@ static void icp_hv_set_cpu_priority(unsigned char cppr)
 
 #ifdef CONFIG_SMP
 
-static void icp_hv_message_pass(int cpu, int msg)
+static void icp_hv_cause_ipi(int cpu, unsigned long data)
 {
-	unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
-	set_bit(msg, tgt);
-	mb();
 	icp_hv_set_qirr(cpu, IPI_PRIORITY);
 }
 
@@ -133,7 +129,7 @@ static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id)
 
 	icp_hv_set_qirr(cpu, 0xff);
 
-	return xics_ipi_dispatch(cpu);
+	return smp_ipi_demux();
 }
 
 #endif /* CONFIG_SMP */
@@ -146,7 +142,7 @@ static const struct icp_ops icp_hv_ops = {
 	.flush_ipi	= icp_hv_flush_ipi,
 #ifdef CONFIG_SMP
 	.ipi_action	= icp_hv_ipi_action,
-	.message_pass	= icp_hv_message_pass,
+	.cause_ipi	= icp_hv_cause_ipi,
 #endif
 };
 
arch/powerpc/sysdev/xics/icp-native.c +3 -7
index 246500e..1f15ad4 100644
@@ -134,12 +134,8 @@ static unsigned int icp_native_get_irq(void)
 
 #ifdef CONFIG_SMP
 
-static void icp_native_message_pass(int cpu, int msg)
+static void icp_native_cause_ipi(int cpu, unsigned long data)
 {
-	unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
-	set_bit(msg, tgt);
-	mb();
 	icp_native_set_qirr(cpu, IPI_PRIORITY);
 }
 
@@ -149,7 +145,7 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
 
 	icp_native_set_qirr(cpu, 0xff);
 
-	return xics_ipi_dispatch(cpu);
+	return smp_ipi_demux();
 }
 
 #endif /* CONFIG_SMP */
@@ -267,7 +263,7 @@ static const struct icp_ops icp_native_ops = {
 	.flush_ipi	= icp_native_flush_ipi,
 #ifdef CONFIG_SMP
 	.ipi_action	= icp_native_ipi_action,
-	.message_pass	= icp_native_message_pass,
+	.cause_ipi	= icp_native_cause_ipi,
 #endif
 };
 
arch/powerpc/sysdev/xics/xics-common.c +2 -28
index a0576b7..a31a710 100644
@@ -126,32 +126,6 @@ void xics_mask_unknown_vec(unsigned int vec)
 
 #ifdef CONFIG_SMP
 
-DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
-
-irqreturn_t xics_ipi_dispatch(int cpu)
-{
-	unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
-	mb();	/* order mmio clearing qirr */
-	while (*tgt) {
-		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) {
-			smp_message_recv(PPC_MSG_CALL_FUNCTION);
-		}
-		if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) {
-			smp_message_recv(PPC_MSG_RESCHEDULE);
-		}
-		if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) {
-			smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
-		}
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
-		if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) {
-			smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
-		}
-#endif
-	}
-	return IRQ_HANDLED;
-}
-
 static void xics_request_ipi(void)
 {
 	unsigned int ipi;
@@ -170,8 +144,8 @@ static void xics_request_ipi(void)
 
 int __init xics_smp_probe(void)
 {
-	/* Setup message_pass callback  based on which ICP is used */
-	smp_ops->message_pass = icp_ops->message_pass;
+	/* Setup cause_ipi callback  based on which ICP is used */
+	smp_ops->cause_ipi = icp_ops->cause_ipi;
 
 	/* Register all the IPIs */
 	xics_request_ipi();
Signature · 1 line
1.7.0.4
#20 lore raw

Re: [PATCH 19/37] powerpc: consolidate ipi message mux and demux

Quoted 2 lines · Milton Miller

Consolidate the mux and demux of ipi messages into smp.c and call a new smp_ops callback to actually trigger the ipi.

.../...

I'm merging the whole series. I had to do some fixups to this one and the one adding the CONFIG option, missing cell & wsp bits among others, but mostly trivial.

Cheers,
Ben.

#21 lore raw

Re: [PATCH 19/37] powerpc: consolidate ipi message mux and demux

Quoted 9 lines · Benjamin Herrenschmidt
Quoted 2 lines · Milton Miller

Consolidate the mux and demux of ipi messages into smp.c and call a new smp_ops callback to actually trigger the ipi.

.../...

I'm merging the whole series. I had to do some fixups to this one and the one adding the CONFIG option, missing cell & wsp bits among others, but mostly trivial.

I forgot to mention... I dropped the change to include/linux/smp.h to remove the unused MSG_ flags for now. It will not have been in -next long enough to hit Linus via my tree, just in case somebody started using the flags while we were not looking :-)

I suggest you send it to Linus directly after he pulls my tree during the merge window.

Cheers,
Ben.

#22 lore raw

PATCH 20/37 powerpc: add kconfig for muxed smp ipi support

In reply to Milton Miller

Compile the new smp ipi mux and demux code only if a platform will make use of it. The new config is selected as required.

The new cause_ipi smp op is only available conditionally to point out configs where the select is required; this makes setting the op an immediate fail instead of a deferred unresolved symbol at link.

This also creates a new config for power surge powermac upgrade support that can be disabled in expert mode but is default on.

I also removed the depends / default y on CONFIG_XICS since it is selected by PSERIES.

---
I kept this seperate mostly because of the addition of the PSURGE kconfig and to focus the discussion on the seperate concepts but it can be merged into the previous patch if desireed.

---
 arch/powerpc/include/asm/smp.h          |    2 ++
 arch/powerpc/kernel/smp.c               |    2 ++
 arch/powerpc/platforms/Kconfig          |   11 +++++++++--
 arch/powerpc/platforms/Kconfig.cputype  |    2 ++
 arch/powerpc/platforms/iseries/Kconfig  |    1 +
 arch/powerpc/platforms/powermac/Kconfig |   11 ++++++++++-
 arch/powerpc/platforms/powermac/pic.c   |    4 ++--
 arch/powerpc/platforms/powermac/smp.c   |    8 ++++----
 8 files changed, 32 insertions(+), 9 deletions(-)
arch/powerpc/include/asm/smp.h +2 -0
index 9ae64bf..11eb404 100644
@@ -38,7 +38,9 @@ extern void cpu_die(void);
 
 struct smp_ops_t {
 	void  (*message_pass)(int cpu, int msg);
+#ifdef CONFIG_PPC_SMP_MUXED_IPI
 	void  (*cause_ipi)(int cpu, unsigned long data);
+#endif
 	int   (*probe)(void);
 	int   (*kick_cpu)(int nr);
 	void  (*setup_cpu)(int nr);
arch/powerpc/kernel/smp.c +2 -0
index 72717e1..a28e945 100644
@@ -178,6 +178,7 @@ int smp_request_message_ipi(int virq, int msg)
 	return err;
 }
 
+#ifdef CONFIG_PPC_SMP_MUXED_IPI
 struct cpu_messages {
 	unsigned long messages;		/* current messages bits */
 	unsigned long data;		/* data for cause ipi */
@@ -230,6 +231,7 @@ irqreturn_t smp_ipi_demux(void)
 	}
 	return IRQ_HANDLED;
 }
+#endif /* CONFIG_PPC_SMP_MUXED_IPI */
 
 void smp_send_reschedule(int cpu)
 {
arch/powerpc/platforms/Kconfig +9 -2
index 6059053..ac95735 100644
@@ -57,15 +57,22 @@ config UDBG_RTAS_CONSOLE
 	depends on PPC_RTAS
 	default n
 
+config PPC_SMP_MUXED_IPI
+	bool
+	help
+	  Select this opton if your platform supports SMP and your
+	  interrupt controller provides less than 4 interrupts to each
+	  cpu.	This will enable the generic code to multiplex the 4
+	  messages on to one ipi.
+
 config PPC_UDBG_BEAT
 	bool "BEAT based debug console"
 	depends on PPC_CELLEB
 	default n
 
 config XICS
-	depends on PPC_PSERIES
 	bool
-	default y
+	select PPC_SMP_MUXED_IPI
 
 config IPIC
 	bool
arch/powerpc/platforms/Kconfig.cputype +2 -0
index a1e6238..2165b65 100644
@@ -73,6 +73,7 @@ config PPC_BOOK3S_64
 config PPC_BOOK3E_64
 	bool "Embedded processors"
 	select PPC_FPU # Make it a choice ?
+	select PPC_SMP_MUXED_IPI
 
 endchoice
 
@@ -178,6 +179,7 @@ config FSL_BOOKE
 config PPC_FSL_BOOK3E
 	bool
 	select FSL_EMB_PERFMON
+	select PPC_SMP_MUXED_IPI
 	default y if FSL_BOOKE
 
 config PTE_64BIT
arch/powerpc/platforms/iseries/Kconfig +1 -0
index ea1d362..b57cda3 100644
@@ -1,6 +1,7 @@
 config PPC_ISERIES
 	bool "IBM Legacy iSeries"
 	depends on PPC64 && PPC_BOOK3S
+	select PPC_SMP_MUXED_IPI
 	select PPC_INDIRECT_PIO
 	select PPC_INDIRECT_MMIO
 	select PPC_PCI_CHOICE if EXPERT
arch/powerpc/platforms/powermac/Kconfig +10 -1
index 1e1a087..1afd10f 100644
@@ -18,4 +18,13 @@ config PPC_PMAC64
 	select PPC_970_NAP
 	default y
 
-
+config PPC_PMAC32_PSURGE
+	bool "Support for powersurge upgrade cards" if EXPERT
+	depends on SMP && PPC32 && PPC_PMAC
+	select PPC_SMP_MUXED_IPI
+	default y
+	help
+	  The powersurge cpu boards can be used in the generation
+	  of powermacs that have a socket for an upgradeable cpu card,
+	  including the 7500, 8500, 9500, 9600.  Support exists for
+	  both dual and quad socket upgrade cards.
arch/powerpc/platforms/powermac/pic.c +2 -2
index 2f34ad0..b706cb3 100644
@@ -239,7 +239,7 @@ static unsigned int pmac_pic_get_irq(void)
 	unsigned long bits = 0;
 	unsigned long flags;
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_PPC_PMAC32_PSURGE
 	void psurge_smp_message_recv(void);
 
        	/* IPI's are a hack on the powersurge -- Cort */
@@ -247,7 +247,7 @@ static unsigned int pmac_pic_get_irq(void)
 		psurge_smp_message_recv();
 		return NO_IRQ_IGNORE;	/* ignore, already handled */
         }
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
 	raw_spin_lock_irqsave(&pmac_pic_lock, flags);
 	for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
 		int i = irq >> 5;
arch/powerpc/platforms/powermac/smp.c +4 -4
index a340107..67b6e14 100644
@@ -70,7 +70,7 @@ static void (*pmac_tb_freeze)(int freeze);
 static u64 timebase;
 static int tb_req;
 
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC_PMAC32_PSURGE
 
 /*
  * Powersurge (old powermac SMP) support.
@@ -420,7 +420,7 @@ struct smp_ops_t psurge_smp_ops = {
 	.give_timebase	= smp_psurge_give_timebase,
 	.take_timebase	= smp_psurge_take_timebase,
 };
-#endif /* CONFIG_PPC32 - actually powersurge support */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
 
 /*
  * Core 99 and later support
@@ -980,7 +980,7 @@ void __init pmac_setup_smp(void)
 		of_node_put(np);
 		smp_ops = &core99_smp_ops;
 	}
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC_PMAC32_PSURGE
 	else {
 		/* We have to set bits in cpu_possible_mask here since the
 		 * secondary CPU(s) aren't in the device tree. Various
@@ -993,7 +993,7 @@ void __init pmac_setup_smp(void)
 			set_cpu_possible(cpu, true);
 		smp_ops = &psurge_smp_ops;
 	}
-#endif /* CONFIG_PPC32 */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
 
 #ifdef CONFIG_HOTPLUG_CPU
 	ppc_md.cpu_die = pmac_cpu_die;
Signature · 1 line
1.7.0.4
#23 lore raw

PATCH 21/37 powerpc: use bytes instead of bitops in smp ipi multiplexing

In reply to Milton Miller

Since there are only 4 messages, we can replace the atomic bit set (which uses atomic load reserve and store conditional sequence) with a byte stores to seperate bytes. We still have to perform a load reserve and store conditional sequence to avoid loosing messages on reception but we can do that with a single call to xchg.

The do {} while and __BIG_ENDIAN specific mask testing was chosen by looking at the generated asm code. On gcc-4.4, the bit masking becomes a simple bit mask and test of the register returned from xchg without storing and loading the value to the stack like attempts with a union of bytes and an int (or worse, loading single bit constants from the constant pool into non-voliatle registers that had to be preseved on the stack). The do {} while avoids an unconditional branch to the end of the loop to test the entry / repeat condition of a while loop and instead optimises for the expected single iteration of the loop.

We have a full mb() at the beginning to cover ordering between send, ipi, and receive so we can use xchg_local and forgo the further acquire and release barriers of xchg.

---
v4: cast int to char ptr in msg send instead of char[] to int* for xchg/test
v3a: add resend to replace dorbell_check_self
v3: settle on casting from char message[4] __aligned(4) to int ptr
v2: try initialized messages
(ended up with globals for each check value, increased reg pressure)
v1: initial version, check bytes though pointer to result of xchg
(resulted in store to stack then byte load / compare / branch)

---
 arch/powerpc/kernel/smp.c |   31 ++++++++++++++++++-------------
 1 files changed, 18 insertions(+), 13 deletions(-)
arch/powerpc/kernel/smp.c +18 -13
index a28e945..8321b0a 100644
@@ -180,7 +180,7 @@ int smp_request_message_ipi(int virq, int msg)
 
 #ifdef CONFIG_PPC_SMP_MUXED_IPI
 struct cpu_messages {
-	unsigned long messages;		/* current messages bits */
+	int messages;			/* current messages */
 	unsigned long data;		/* data for cause ipi */
 };
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message);
@@ -195,9 +195,9 @@ void smp_muxed_ipi_set_data(int cpu, unsigned long data)
 void smp_muxed_ipi_message_pass(int cpu, int msg)
 {
 	struct cpu_messages *info = &per_cpu(ipi_message, cpu);
-	unsigned long *tgt = &info->messages;
+	char *message = (char *)&info->messages;
 
-	set_bit(msg, tgt);
+	message[msg] = 1;
 	mb();
 	smp_ops->cause_ipi(cpu, info->data);
 }
@@ -205,30 +205,35 @@ void smp_muxed_ipi_message_pass(int cpu, int msg)
 void smp_muxed_ipi_resend(void)
 {
 	struct cpu_messages *info = &__get_cpu_var(ipi_message);
-	unsigned long *tgt = &info->messages;
 
-	if (*tgt)
+	if (info->messages)
 		smp_ops->cause_ipi(smp_processor_id(), info->data);
 }
 
 irqreturn_t smp_ipi_demux(void)
 {
 	struct cpu_messages *info = &__get_cpu_var(ipi_message);
-	unsigned long *tgt = &info->messages;
+	unsigned int all;
 
 	mb();	/* order any irq clear */
-	while (*tgt) {
-		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt))
+
+	do {
+		all = xchg_local(&info->messages, 0);
+
+#ifdef __BIG_ENDIAN
+		if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION)))
 			generic_smp_call_function_interrupt();
-		if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt))
+		if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE)))
 			reschedule_action(0, NULL); /* upcoming sched hook */
-		if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt))
+		if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE)))
 			generic_smp_call_function_single_interrupt();
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
-		if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt))
+		if (all & (1 << (24 - 8 * PPC_MSG_DEBUGGER_BREAK)))
 			debug_ipi_action(0, NULL);
+#else
+#error Unsupported ENDIAN
 #endif
-	}
+	} while (info->messages);
+
 	return IRQ_HANDLED;
 }
 #endif /* CONFIG_PPC_SMP_MUXED_IPI */
Signature · 1 line
1.7.0.4
#24 lore raw

PATCH 22/37 powerpc: xics: cleanup xics_host_map and ipi

In reply to Milton Miller

Since we already have a special case in map to set the ipi handler, use the desired flow.

If we don't find an ics to handle the interrupt complain instead of returning 0 without having set a chip or handler.

---
 arch/powerpc/sysdev/xics/xics-common.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)
arch/powerpc/sysdev/xics/xics-common.c +5 -5
index a31a710..43b2a79 100644
@@ -135,9 +135,8 @@ static void xics_request_ipi(void)
 
 	/*
 	 * IPIs are marked IRQF_DISABLED as they must run with irqs
-	 * disabled
+	 * disabled, and PERCPU.  The handler was set in map.
 	 */
-	irq_set_handler(ipi, handle_percpu_irq);
 	BUG_ON(request_irq(ipi, icp_ops->ipi_action,
 			   IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL));
 }
@@ -341,15 +340,16 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
 	/* Don't call into ICS for IPIs */
 	if (hw == XICS_IPI) {
 		irq_set_chip_and_handler(virq, &xics_ipi_chip,
-					 handle_fasteoi_irq);
+					 handle_percpu_irq);
 		return 0;
 	}
 
 	/* Let the ICS setup the chip data */
 	list_for_each_entry(ics, &ics_list, link)
 		if (ics->map(ics, virq) == 0)
-			break;
-	return 0;
+			return 0;
+
+	return -EINVAL;
 }
 
 static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
Signature · 1 line
1.7.0.4
#25 lore raw

PATCH 23/37 powerpc: radix trees are available before init_IRQ

In reply to Milton Miller

Since the generic irq code uses a radix tree for sparse interrupts, the initcall ordering has been changed to initialize radix trees before
irqs. We no longer need to defer creating revmap radix trees to the
arch_initcall irq_late_init.

Also, the kmem caches are allocated so we don't need to use zalloc_maybe_bootmem.

---
 arch/powerpc/kernel/irq.c |   78 ++------------------------------------------
 1 files changed, 4 insertions(+), 74 deletions(-)
arch/powerpc/kernel/irq.c +4 -74
index 826552c..f42e869 100644
@@ -493,7 +493,6 @@ struct irq_map_entry {
 
 static LIST_HEAD(irq_hosts);
 static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static unsigned int revmap_trees_allocated;
 static DEFINE_MUTEX(revmap_trees_mutex);
 static struct irq_map_entry irq_map[NR_IRQS];
 static unsigned int irq_virq_count = NR_IRQS;
@@ -537,7 +536,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
 	/* Allocate structure and revmap table if using linear mapping */
 	if (revmap_type == IRQ_HOST_MAP_LINEAR)
 		size += revmap_arg * sizeof(unsigned int);
-	host = zalloc_maybe_bootmem(size, GFP_KERNEL);
+	host = kzalloc(size, GFP_KERNEL);
 	if (host == NULL)
 		return NULL;
 
@@ -605,6 +604,9 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
 		smp_wmb();
 		host->revmap_data.linear.revmap = rmap;
 		break;
+	case IRQ_HOST_MAP_TREE:
+		INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
+		break;
 	default:
 		break;
 	}
@@ -839,13 +841,6 @@ void irq_dispose_mapping(unsigned int virq)
 			host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
 		break;
 	case IRQ_HOST_MAP_TREE:
-		/*
-		 * Check if radix tree allocated yet, if not then nothing to
-		 * remove.
-		 */
-		smp_rmb();
-		if (revmap_trees_allocated < 1)
-			break;
 		mutex_lock(&revmap_trees_mutex);
 		radix_tree_delete(&host->revmap_data.tree, hwirq);
 		mutex_unlock(&revmap_trees_mutex);
@@ -906,14 +901,6 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
 	WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
 
 	/*
-	 * Check if the radix tree exists and has bee initialized.
-	 * If not, we fallback to slow mode
-	 */
-	if (revmap_trees_allocated < 2)
-		return irq_find_mapping(host, hwirq);
-
-	/* Now try to resolve */
-	/*
 	 * No rcu_read_lock(ing) needed, the ptr returned can't go under us
 	 * as it's referencing an entry in the static irq_map table.
 	 */
@@ -935,18 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
 void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
 			     irq_hw_number_t hwirq)
 {
-
 	WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
 
-	/*
-	 * Check if the radix tree exists yet.
-	 * If not, then the irq will be inserted into the tree when it gets
-	 * initialized.
-	 */
-	smp_rmb();
-	if (revmap_trees_allocated < 1)
-		return;
-
 	if (virq != NO_IRQ) {
 		mutex_lock(&revmap_trees_mutex);
 		radix_tree_insert(&host->revmap_data.tree, hwirq,
@@ -1054,53 +1031,6 @@ int arch_early_irq_init(void)
 	return 0;
 }
 
-/* We need to create the radix trees late */
-static int irq_late_init(void)
-{
-	struct irq_host *h;
-	unsigned int i;
-
-	/*
-	 * No mutual exclusion with respect to accessors of the tree is needed
-	 * here as the synchronization is done via the state variable
-	 * revmap_trees_allocated.
-	 */
-	list_for_each_entry(h, &irq_hosts, link) {
-		if (h->revmap_type == IRQ_HOST_MAP_TREE)
-			INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL);
-	}
-
-	/*
-	 * Make sure the radix trees inits are visible before setting
-	 * the flag
-	 */
-	smp_wmb();
-	revmap_trees_allocated = 1;
-
-	/*
-	 * Insert the reverse mapping for those interrupts already present
-	 * in irq_map[].
-	 */
-	mutex_lock(&revmap_trees_mutex);
-	for (i = 0; i < irq_virq_count; i++) {
-		if (irq_map[i].host &&
-		    (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE))
-			radix_tree_insert(&irq_map[i].host->revmap_data.tree,
-					  irq_map[i].hwirq, &irq_map[i]);
-	}
-	mutex_unlock(&revmap_trees_mutex);
-
-	/*
-	 * Make sure the radix trees insertions are visible before setting
-	 * the flag
-	 */
-	smp_wmb();
-	revmap_trees_allocated = 2;
-
-	return 0;
-}
-arch_initcall(irq_late_init);
-
 #ifdef CONFIG_VIRQ_DEBUG
 static int virq_debug_show(struct seq_file *m, void *private)
 {
Signature · 1 line
1.7.0.4
Reviewed-by on v1 23/37
#26 lore raw

Re: [PATCH 23/37] powerpc: radix trees are available before init_IRQ

Quoted 9 lines · Milton Miller

Since the generic irq code uses a radix tree for sparse interrupts, the initcall ordering has been changed to initialize radix trees before irqs. =A0 We no longer need to defer creating revmap radix trees to the arch_initcall irq_late_init.

Also, the kmem caches are allocated so we don't need to use zalloc_maybe_bootmem.

w00t. Looks right to me.

Quoted 2 lines

---
=A0arch/powerpc/kernel/irq.c | =A0 78 ++---------------------------------=

---------

arch/powerpc/kernel/irq.c struct irq_host *irq_alloc_host(struct device_node *o=

Quoted 15 lines

=A01 files changed, 4 insertions(+), 74 deletions(-)

arch/powerpc/kernel/irq.c +0 -1
index 826552c..f42e869 100644
@@ -493,7 +493,6 @@ struct irq_map_entry {
 
 =A0static LIST_HEAD(irq_hosts);
 =A0static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static unsigned int revmap_trees_allocated;
 =A0static DEFINE_MUTEX(revmap_trees_mutex);
 =A0static struct irq_map_entry irq_map[NR_IRQS];
 =A0static unsigned int irq_virq_count =3D NR_IRQS;
@@ -537,7 +536,7 @@ struct irq_host *irq_alloc_host(struct device_node *o=

f_node,

Quoted 1 line

=A0 =A0 =A0 =A0/* Allocate structure and revmap table if using linear map=

ping */

Quoted 2 lines

=A0 =A0 =A0 =A0if (revmap_type =3D=3D IRQ_HOST_MAP_LINEAR)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0size +=3D revmap_arg * sizeof(unsigned int=

);

arch/powerpc/kernel/irq.c struct irq_host *irq_alloc_host(struct device_node *o=

Quoted 6 lines

- =A0 =A0 =A0 host =3D zalloc_maybe_bootmem(size, GFP_KERNEL);
+ =A0 =A0 =A0 host =3D kzalloc(size, GFP_KERNEL); =A0 =A0 =A0 =A0if (host =3D=3D NULL)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return NULL;

arch/powerpc/kernel/irq.c +0 -0
@@ -605,6 +604,9 @@ struct irq_host *irq_alloc_host(struct device_node *o=

f_node,

arch/powerpc/kernel/irq.c struct irq_host *irq_alloc_host(struct device_node *o= · line 608

Quoted 5 lines
arch/powerpc/kernel/irq.c +2 -0
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0smp_wmb();
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0host->revmap_data.linear.revmap =3D rmap;
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 case IRQ_HOST_MAP_TREE:
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 INIT_RADIX_TREE(&host->revmap_data.tree, GF=

P_KERNEL);

Quoted 6 lines
arch/powerpc/kernel/irq.c +1 -0
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;

=A0 =A0 =A0 =A0default:
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
=A0 =A0 =A0 =A0}

arch/powerpc/kernel/irq.c +0 -0
@@ -839,13 +841,6 @@ void irq_dispose_mapping(unsigned int virq)

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0host->revmap_data.linear.r=

evmap[hwirq] =3D NO_IRQ;

Quoted 4 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
=A0 =A0 =A0 =A0case IRQ_HOST_MAP_TREE:
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Check if radix tree allocated yet, if =

not then nothing to

Quoted 7 lines

- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* remove.
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 smp_rmb();
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (revmap_trees_allocated < 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mutex_lock(&revmap_trees_mutex); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0radix_tree_delete(&host->revmap_data.tree,=

hwirq);

arch/powerpc/kernel/irq.c unsigned int irq_radix_revmap_lookup(struct irq_host=

Quoted 2 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mutex_unlock(&revmap_trees_mutex);

arch/powerpc/kernel/irq.c +0 -0
@@ -906,14 +901,6 @@ unsigned int irq_radix_revmap_lookup(struct irq_host=

*host,

Quoted 4 lines
arch/powerpc/kernel/irq.c +0 -0
 =A0 =A0 =A0 =A0WARN_ON(host->revmap_type !=3D IRQ_HOST_MAP_TREE);
 

=A0 =A0 =A0 =A0/*
- =A0 =A0 =A0 =A0* Check if the radix tree exists and has bee initialized=

.

Quoted 8 lines

- =A0 =A0 =A0 =A0* If not, we fallback to slow mode
- =A0 =A0 =A0 =A0*/
- =A0 =A0 =A0 if (revmap_trees_allocated < 2)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 return irq_find_mapping(host, hwirq); -
- =A0 =A0 =A0 /* Now try to resolve */
- =A0 =A0 =A0 /*
=A0 =A0 =A0 =A0 * No rcu_read_lock(ing) needed, the ptr returned can't go=

under us

Quoted 1 line

=A0 =A0 =A0 =A0 * as it's referencing an entry in the static irq_map tabl=

e.

arch/powerpc/kernel/irq.c unsigned int irq_radix_revmap_lookup(struct irq_host=

Quoted 2 lines

=A0 =A0 =A0 =A0 */

arch/powerpc/kernel/irq.c +0 -0
@@ -935,18 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host=

*host,

Quoted 2 lines
arch/powerpc/kernel/irq.c +0 -0
 =A0void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq_hw_number_t h=

wirq)

Quoted 7 lines

=A0{
-
=A0 =A0 =A0 =A0WARN_ON(host->revmap_type !=3D IRQ_HOST_MAP_TREE);

- =A0 =A0 =A0 /*
- =A0 =A0 =A0 =A0* Check if the radix tree exists yet.
- =A0 =A0 =A0 =A0* If not, then the irq will be inserted into the tree wh=

en it gets

Quoted 9 lines

- =A0 =A0 =A0 =A0* initialized.
- =A0 =A0 =A0 =A0*/
- =A0 =A0 =A0 smp_rmb();
- =A0 =A0 =A0 if (revmap_trees_allocated < 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
-
=A0 =A0 =A0 =A0if (virq !=3D NO_IRQ) {
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mutex_lock(&revmap_trees_mutex); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0radix_tree_insert(&host->revmap_data.tree,=

hwirq,

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1064

Quoted 12 lines
arch/powerpc/kernel/irq.c +0 -8
@@ -1054,53 +1031,6 @@ int arch_early_irq_init(void)
 =A0 =A0 =A0 =A0return 0;
 =A0}
 
-/* We need to create the radix trees late */
-static int irq_late_init(void)
-{
- =A0 =A0 =A0 struct irq_host *h;
- =A0 =A0 =A0 unsigned int i;
-
- =A0 =A0 =A0 /*
- =A0 =A0 =A0 =A0* No mutual exclusion with respect to accessors of the t=

ree is needed

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1065

Quoted 1 line
arch/powerpc/kernel/irq.c +0 -1
- =A0 =A0 =A0 =A0* here as the synchronization is done via the state vari=

able

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1069

Quoted 4 lines
arch/powerpc/kernel/irq.c +0 -4
- =A0 =A0 =A0 =A0* revmap_trees_allocated.
- =A0 =A0 =A0 =A0*/
- =A0 =A0 =A0 list_for_each_entry(h, &irq_hosts, link) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (h->revmap_type =3D=3D IRQ_HOST_MAP_TREE=

)

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1070

Quoted 1 line
arch/powerpc/kernel/irq.c +0 -1
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 INIT_RADIX_TREE(&h->revmap_=

data.tree, GFP_KERNEL);

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1074

Quoted 4 lines
arch/powerpc/kernel/irq.c +0 -4
- =A0 =A0 =A0 }
-
- =A0 =A0 =A0 /*
- =A0 =A0 =A0 =A0* Make sure the radix trees inits are visible before set=

ting

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1081

Quoted 7 lines
arch/powerpc/kernel/irq.c +0 -7
- =A0 =A0 =A0 =A0* the flag
- =A0 =A0 =A0 =A0*/
- =A0 =A0 =A0 smp_wmb();
- =A0 =A0 =A0 revmap_trees_allocated =3D 1;
-
- =A0 =A0 =A0 /*
- =A0 =A0 =A0 =A0* Insert the reverse mapping for those interrupts alread=

y present

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1087

Quoted 6 lines
arch/powerpc/kernel/irq.c +0 -6
- =A0 =A0 =A0 =A0* in irq_map[].
- =A0 =A0 =A0 =A0*/
- =A0 =A0 =A0 mutex_lock(&revmap_trees_mutex);
- =A0 =A0 =A0 for (i =3D 0; i < irq_virq_count; i++) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (irq_map[i].host &&
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (irq_map[i].host->revmap_type =3D=

=3D IRQ_HOST_MAP_TREE))

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1088

Quoted 1 line
arch/powerpc/kernel/irq.c +0 -1
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 radix_tree_insert(&irq_map[=

i].host->revmap_data.tree,

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1089

Quoted 1 line
arch/powerpc/kernel/irq.c +0 -1
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=

=A0 =A0 irq_map[i].hwirq, &irq_map[i]);

arch/powerpc/kernel/irq.c int arch_early_irq_init(void) · line 1094

Quoted 5 lines
arch/powerpc/kernel/irq.c +0 -5
- =A0 =A0 =A0 }
- =A0 =A0 =A0 mutex_unlock(&revmap_trees_mutex);
-
- =A0 =A0 =A0 /*
- =A0 =A0 =A0 =A0* Make sure the radix trees insertions are visible befor=

e setting

Quoted 9 lines
arch/powerpc/kernel/irq.c +0 -9
- =A0 =A0 =A0 =A0* the flag
- =A0 =A0 =A0 =A0*/
- =A0 =A0 =A0 smp_wmb();
- =A0 =A0 =A0 revmap_trees_allocated =3D 2;
-
- =A0 =A0 =A0 return 0;
-}
-arch_initcall(irq_late_init);
-
Quoted 7 lines

=A0#ifdef CONFIG_VIRQ_DEBUG
=A0static int virq_debug_show(struct seq_file *m, void *private) =A0{
--
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#27 lore raw

PATCH 24/37 powerpc: return early if irq_host lookup type is wrong

In reply to Milton Miller

If for some reason the code incrorectly calls the wrong function to manage the revmap, not only should we warn, we should take action. However, in the paths we expect to be taken every delivered interrupt change to WARN_ON_ONCE. Use the if (WARN_ON(x)) format to get the unlikely for free.

---
 arch/powerpc/kernel/irq.c |   12 +++++++-----
 1 files changed, 7 insertions(+), 5 deletions(-)
arch/powerpc/kernel/irq.c +7 -5
index f42e869..4a5aa8c 100644
@@ -814,8 +814,7 @@ void irq_dispose_mapping(unsigned int virq)
 		return;
 
 	host = irq_map[virq].host;
-	WARN_ON (host == NULL);
-	if (host == NULL)
+	if (WARN_ON(host == NULL))
 		return;
 
 	/* Never unmap legacy interrupts */
@@ -898,7 +897,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
 	struct irq_map_entry *ptr;
 	unsigned int virq;
 
-	WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
+	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
+		return irq_find_mapping(host, hwirq);
 
 	/*
 	 * No rcu_read_lock(ing) needed, the ptr returned can't go under us
@@ -922,7 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
 void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
 			     irq_hw_number_t hwirq)
 {
-	WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
+	if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
+		return;
 
 	if (virq != NO_IRQ) {
 		mutex_lock(&revmap_trees_mutex);
@@ -937,7 +938,8 @@ unsigned int irq_linear_revmap(struct irq_host *host,
 {
 	unsigned int *revmap;
 
-	WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR);
+	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
+		return irq_find_mapping(host, hwirq);
 
 	/* Check revmap bounds */
 	if (unlikely(hwirq >= host->revmap_data.linear.size))
Signature · 1 line
1.7.0.4
Reviewed-by on v1 24/37
#28 lore raw

Re: [PATCH 24/37] powerpc: return early if irq_host lookup type is wrong

Quoted 7 lines · Milton Miller

If for some reason the code incrorectly calls the wrong function to manage the revmap, not only should we warn, we should take action. However, in the paths we expect to be taken every delivered interrupt change to WARN_ON_ONCE. =A0Use the if (WARN_ON(x)) format to get the unlikely for free.

Looks right.

arch/powerpc/kernel/irq.c unsigned int irq_radix_revmap_lookup(struct irq_host =

Quoted 19 lines

---
=A0arch/powerpc/kernel/irq.c | =A0 12 +++++++----- =A01 files changed, 7 insertions(+), 5 deletions(-)

arch/powerpc/kernel/irq.c +1 -2
index f42e869..4a5aa8c 100644
@@ -814,8 +814,7 @@ void irq_dispose_mapping(unsigned int virq)
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return;
 
 =A0 =A0 =A0 =A0host =3D irq_map[virq].host;
- =A0 =A0 =A0 WARN_ON (host =3D=3D NULL);
- =A0 =A0 =A0 if (host =3D=3D NULL)
+ =A0 =A0 =A0 if (WARN_ON(host =3D=3D NULL))
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return;
 

=A0 =A0 =A0 =A0/* Never unmap legacy interrupts */

arch/powerpc/kernel/irq.c +0 -0
@@ -898,7 +897,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host =

*host,

Quoted 9 lines
arch/powerpc/kernel/irq.c +2 -1
 =A0 =A0 =A0 =A0struct irq_map_entry *ptr;
 =A0 =A0 =A0 =A0unsigned int virq;
 
- =A0 =A0 =A0 WARN_ON(host->revmap_type !=3D IRQ_HOST_MAP_TREE);
+ =A0 =A0 =A0 if (WARN_ON_ONCE(host->revmap_type !=3D IRQ_HOST_MAP_TREE))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return irq_find_mapping(host, hwirq);
 

=A0 =A0 =A0 =A0/*
=A0 =A0 =A0 =A0 * No rcu_read_lock(ing) needed, the ptr returned can't go=

under us

arch/powerpc/kernel/irq.c unsigned int irq_radix_revmap_lookup(struct irq_host =

Quoted 1 line
arch/powerpc/kernel/irq.c +0 -0
@@ -922,7 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host =

*host,

Quoted 2 lines
arch/powerpc/kernel/irq.c +0 -0
 =A0void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq_hw_number_t h=

wirq)

arch/powerpc/kernel/irq.c unsigned int irq_linear_revmap(struct irq_host *host, · line 941

Quoted 13 lines

=A0{
- =A0 =A0 =A0 WARN_ON(host->revmap_type !=3D IRQ_HOST_MAP_TREE);
+ =A0 =A0 =A0 if (WARN_ON(host->revmap_type !=3D IRQ_HOST_MAP_TREE))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;

=A0 =A0 =A0 =A0if (virq !=3D NO_IRQ) {
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mutex_lock(&revmap_trees_mutex);

arch/powerpc/kernel/irq.c +1 -1
@@ -937,7 +938,8 @@ unsigned int irq_linear_revmap(struct irq_host *host,
 =A0{
 =A0 =A0 =A0 =A0unsigned int *revmap;
 
- =A0 =A0 =A0 WARN_ON(host->revmap_type !=3D IRQ_HOST_MAP_LINEAR);
+ =A0 =A0 =A0 if (WARN_ON_ONCE(host->revmap_type !=3D IRQ_HOST_MAP_LINEAR=

))

Quoted 8 lines
arch/powerpc/kernel/irq.c +1 -0
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return irq_find_mapping(host, hwirq);
 

=A0 =A0 =A0 =A0/* Check revmap bounds */
=A0 =A0 =A0 =A0if (unlikely(hwirq >=3D host->revmap_data.linear.size)) --
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#29 lore raw

PATCH 25/37 powerpc: remove trival irq_host_ops.unmap

In reply to Milton Miller

These all just clear chip or chipdata fields, which will be done by the generic code when we call irq_free_descs.

---
 arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    8 --------
 arch/powerpc/platforms/embedded6xx/flipper-pic.c |    7 -------
 arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    7 -------
 arch/powerpc/platforms/ps3/interrupt.c           |    6 ------
 4 files changed, 0 insertions(+), 28 deletions(-)
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +0 -8
index 5d6c34c..8ccf9ed 100644
@@ -112,16 +112,8 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
 	return 0;
 }
 
-static void pci_host_unmap(struct irq_host *h, unsigned int virq)
-{
-	/* remove chip and handler */
-	irq_set_chip_data(virq, NULL);
-	irq_set_chip(virq, NULL);
-}
-
 static struct irq_host_ops pci_pic_host_ops = {
 	.map = pci_pic_host_map,
-	.unmap = pci_host_unmap,
 };
 
 int __init pq2ads_pci_init_irq(void)
arch/powerpc/platforms/embedded6xx/flipper-pic.c +0 -7
index 77cbe4c..f61a2dd 100644
@@ -107,12 +107,6 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,
 	return 0;
 }
 
-static void flipper_pic_unmap(struct irq_host *h, unsigned int irq)
-{
-	irq_set_chip_data(irq, NULL);
-	irq_set_chip(irq, NULL);
-}
-
 static int flipper_pic_match(struct irq_host *h, struct device_node *np)
 {
 	return 1;
@@ -121,7 +115,6 @@ static int flipper_pic_match(struct irq_host *h, struct device_node *np)
 
 static struct irq_host_ops flipper_irq_host_ops = {
 	.map = flipper_pic_map,
-	.unmap = flipper_pic_unmap,
 	.match = flipper_pic_match,
 };
 
arch/powerpc/platforms/embedded6xx/hlwd-pic.c +0 -7
index 44b398b..e491917 100644
@@ -100,15 +100,8 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
 	return 0;
 }
 
-static void hlwd_pic_unmap(struct irq_host *h, unsigned int irq)
-{
-	irq_set_chip_data(irq, NULL);
-	irq_set_chip(irq, NULL);
-}
-
 static struct irq_host_ops hlwd_irq_host_ops = {
 	.map = hlwd_pic_map,
-	.unmap = hlwd_pic_unmap,
 };
 
 static unsigned int __hlwd_pic_get_irq(struct irq_host *h)
arch/powerpc/platforms/ps3/interrupt.c +0 -6
index 523bd0d..600ed2c 100644
@@ -659,11 +659,6 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,
 static void dump_bmp(struct ps3_private* pd) {};
 #endif /* defined(DEBUG) */
 
-static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
-{
-	irq_set_chip_data(virq, NULL);
-}
-
 static int ps3_host_map(struct irq_host *h, unsigned int virq,
 	irq_hw_number_t hwirq)
 {
@@ -683,7 +678,6 @@ static int ps3_host_match(struct irq_host *h, struct device_node *np)
 
 static struct irq_host_ops ps3_host_ops = {
 	.map = ps3_host_map,
-	.unmap = ps3_host_unmap,
 	.match = ps3_host_match,
 };
 
Signature · 1 line
1.7.0.4
#30 lore raw

PATCH 26/37 powerpc: remove i8259 irq_host_ops->unmap

In reply to Milton Miller

It was never called because the host is always IRQ_HOST_MAP_LEGACY.

And what it purported to do was mask the interrupt (which will already have happend if we shutdown the interrupt), then synchronise_irq and clear the chip pointer, both of which will have been be done by the caller were we to call unmap on a legacy irq.

---

---
 arch/powerpc/sysdev/i8259.c |   13 -------------
 1 files changed, 0 insertions(+), 13 deletions(-)
arch/powerpc/sysdev/i8259.c +0 -13
index 142770c..d18bb27 100644
@@ -185,18 +185,6 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,
 	return 0;
 }
 
-static void i8259_host_unmap(struct irq_host *h, unsigned int virq)
-{
-	/* Make sure irq is masked in hardware */
-	i8259_mask_irq(irq_get_irq_data(virq));
-
-	/* remove chip and handler */
-	irq_set_chip_and_handler(virq, NULL, NULL);
-
-	/* Make sure it's completed */
-	synchronize_irq(virq);
-}
-
 static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
 			    const u32 *intspec, unsigned int intsize,
 			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)
@@ -220,7 +208,6 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
 static struct irq_host_ops i8259_host_ops = {
 	.match = i8259_host_match,
 	.map = i8259_host_map,
-	.unmap = i8259_host_unmap,
 	.xlate = i8259_host_xlate,
 };
 
Signature · 1 line
1.7.0.4
#31 lore raw

PATCH 27/37 powerpc fsl_msi: don't abuse platform_data for driver_data

In reply to Milton Miller

The msi platform device driver was abusing dev.platform_data for its platform_driver_data. Use the correct pointer for storage.

Platform_data is supposed to be for platforms to communicate to drivers parameters that are not otherwise discoverable. Its lifetime matches the platform_device not the platform device driver. It is generally not needed for drivers that only support systems with device trees.

---

---
 arch/powerpc/sysdev/fsl_msi.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
arch/powerpc/sysdev/fsl_msi.c +2 -2
index d5679dc..077776c 100644
@@ -253,7 +253,7 @@ unlock:
 
 static int fsl_of_msi_remove(struct platform_device *ofdev)
 {
-	struct fsl_msi *msi = ofdev->dev.platform_data;
+	struct fsl_msi *msi = platform_get_drvdata(ofdev);
 	int virq, i;
 	struct fsl_msi_cascade_data *cascade_data;
 
@@ -327,7 +327,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
 		dev_err(&dev->dev, "No memory for MSI structure\n");
 		return -ENOMEM;
 	}
-	dev->dev.platform_data = msi;
+	platform_set_drvdata(dev, msi);
 
 	msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
 				      NR_MSI_IRQS, &fsl_msi_host_ops, 0);
Signature · 1 line
1.7.0.4
Acked-by on v1 27/37
#32 lore raw

Re: [PATCH 27/37] powerpc fsl_msi: don't abuse platform_data for driver_data

Quoted 9 lines · Milton Miller

The msi platform device driver was abusing dev.platform_data for its platform_driver_data. =A0Use the correct pointer for storage.

Platform_data is supposed to be for platforms to communicate to drivers parameters that are not otherwise discoverable. =A0Its lifetime matches the platform_device not the platform device driver. =A0It is generally not needed for drivers that only support systems with device trees.

arch/powerpc/sysdev/fsl_msi.=

Quoted 6 lines

---
---
=A0arch/powerpc/sysdev/fsl_msi.c | =A0 =A04 ++-- =A01 files changed, 2 insertions(+), 2 deletions(-)

arch/powerpc/sysdev/fsl_msi.= renamed from arch/powerpc/sysdev/fsl_msi.c +0 -0

c

arch/powerpc/sysdev/fsl_msi.c static int __devinit fsl_of_msi_probe(struct platform=

Quoted 13 lines

index d5679dc..077776c 100644

arch/powerpc/sysdev/fsl_msi.c +1 -1
@@ -253,7 +253,7 @@ unlock:
 
 =A0static int fsl_of_msi_remove(struct platform_device *ofdev)
 =A0{
- =A0 =A0 =A0 struct fsl_msi *msi =3D ofdev->dev.platform_data;
+ =A0 =A0 =A0 struct fsl_msi *msi =3D platform_get_drvdata(ofdev);
 =A0 =A0 =A0 =A0int virq, i;
 =A0 =A0 =A0 =A0struct fsl_msi_cascade_data *cascade_data;
 
@@ -327,7 +327,7 @@ static int __devinit fsl_of_msi_probe(struct platform=

_device *dev)

Quoted 1 line

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_err(&dev->dev, "No memory for MSI stru=

cture\n");

Quoted 6 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -ENOMEM;
=A0 =A0 =A0 =A0}
- =A0 =A0 =A0 dev->dev.platform_data =3D msi;
+ =A0 =A0 =A0 platform_set_drvdata(dev, msi);

=A0 =A0 =A0 =A0msi->irqhost =3D irq_alloc_host(dev->dev.of_node, IRQ_HOST=

_MAP_LINEAR,

Quoted 1 line

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =

=A0NR_MSI_IRQS, &fsl_msi_host_ops, 0);

Quoted 4 lines

--
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#33 lore raw

PATCH 28/37 powerpc: fsl_msi: use chip_data not handler_data

In reply to Milton Miller

handler_data should be reserved for flow handlers on the dependent irq, not consumed by the parent irq code that is part of the irq_chip code. The msi_data pointer was already set in msidesc->irqhost->hostdata and being copied to irq_data->chipdata in the msidesc->irqhost->map() method called via create_irq_mapping, so we can obtain the pointer from there and free the instance it in teardown_msi_irqs.

Also remove the unnecessary cast of irq_get_handler_data in the cascade handler, which is the demux flow handler of the parent msi interrupt. (This is the expected usage for handler_data).

---

---
 arch/powerpc/sysdev/fsl_msi.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
arch/powerpc/sysdev/fsl_msi.c +3 -3
index 077776c..067cc88 100644
@@ -110,7 +110,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
 	list_for_each_entry(entry, &pdev->msi_list, list) {
 		if (entry->irq == NO_IRQ)
 			continue;
-		msi_data = irq_get_handler_data(entry->irq);
+		msi_data = irq_get_chip_data(entry->irq);
 		irq_set_msi_desc(entry->irq, NULL);
 		msi_bitmap_free_hwirqs(&msi_data->bitmap,
 				       virq_to_hw(entry->irq), 1);
@@ -168,7 +168,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 			rc = -ENOSPC;
 			goto out_free;
 		}
-		irq_set_handler_data(virq, msi_data);
+		/* chip_data is msi_data via host->hostdata in host->map() */
 		irq_set_msi_desc(virq, entry);
 
 		fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
@@ -193,7 +193,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
 	u32 have_shift = 0;
 	struct fsl_msi_cascade_data *cascade_data;
 
-	cascade_data = (struct fsl_msi_cascade_data *)irq_get_handler_data(irq);
+	cascade_data = irq_get_handler_data(irq);
 	msi_data = cascade_data->msi_data;
 
 	raw_spin_lock(&desc->lock);
Signature · 1 line
1.7.0.4
#34 lore raw

PATCH 29/37 powerpc: mpc5121_ads_cpld: remove use of NO_IRQ_IGNORE

In reply to Milton Miller

As NO_IRQ_IGNORE is only used between the static function cpld_pic_get_irq and its caller cpld_pic_cascade, and cpld_pic_cascade only uses it to suppress calling handle_generic_irq, we can change these uses to NO_IRQ and remove the extra tests and pathlength in cpld_pic_cascade.

---

---
 arch/powerpc/platforms/512x/mpc5121_ads_cpld.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +3 -3
index a8bc0d4..9f09319 100644
@@ -97,7 +97,7 @@ cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,
 	status |= (ignore | mask);
 
 	if (status == 0xff)
-		return NO_IRQ_IGNORE;
+		return NO_IRQ;
 
 	cpld_irq = ffz(status) + offset;
 
@@ -109,14 +109,14 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)
 {
 	irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,
 		&cpld_regs->pci_mask);
-	if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
+	if (irq != NO_IRQ) {
 		generic_handle_irq(irq);
 		return;
 	}
 
 	irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,
 		&cpld_regs->misc_mask);
-	if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
+	if (irq != NO_IRQ) {
 		generic_handle_irq(irq);
 		return;
 	}
Signature · 1 line
1.7.0.4
Acked-by on v1 29/37
#35 lore raw

Re: [PATCH 29/37] powerpc: mpc5121_ads_cpld: remove use of NO_IRQ_IGNORE

Quoted 1 line · Milton Miller

As NO_IRQ_IGNORE is only used between the static function cpld_pic_get_ir=

q

Quoted 5 lines

and its caller cpld_pic_cascade, and cpld_pic_cascade only uses it to suppress calling handle_generic_irq, we can change these uses to NO_IRQ and remove the extra tests and pathlength in cpld_pic_cascade.

arch/powerp=

Quoted 6 lines

---
---
=A0arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | =A0 =A06 +++--- =A01 files changed, 3 insertions(+), 3 deletions(-)

arch/powerp= renamed from arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +0 -0

c/platforms/512x/mpc5121_ads_cpld.c

arch/powerpc/platforms/512x/mpc5121_ads_cpld.c cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *sta=

Quoted 4 lines

index a8bc0d4..9f09319 100644

arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +0 -0
@@ -97,7 +97,7 @@ cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *sta=

tusp,

arch/powerpc/platforms/512x/mpc5121_ads_cpld.c cpld_pic_cascade(unsigned int irq, struct irq_desc =

Quoted 9 lines
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +1 -1
 =A0 =A0 =A0 =A0status |=3D (ignore | mask);
 
 =A0 =A0 =A0 =A0if (status =3D=3D 0xff)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NO_IRQ_IGNORE;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NO_IRQ;
 
 =A0 =A0 =A0 =A0cpld_irq =3D ffz(status) + offset;
 
@@ -109,14 +109,14 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc =

*desc)

Quoted 2 lines
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +0 -0
 =A0{

=A0 =A0 =A0 =A0irq =3D cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_st=

atus,

Quoted 8 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&cpld_regs->pci_mask);
- =A0 =A0 =A0 if (irq !=3D NO_IRQ && irq !=3D NO_IRQ_IGNORE) {
+ =A0 =A0 =A0 if (irq !=3D NO_IRQ) {
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0generic_handle_irq(irq); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return;
=A0 =A0 =A0 =A0}

=A0 =A0 =A0 =A0irq =3D cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_=

status,

Quoted 10 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&cpld_regs->misc_mask);
- =A0 =A0 =A0 if (irq !=3D NO_IRQ && irq !=3D NO_IRQ_IGNORE) {
+ =A0 =A0 =A0 if (irq !=3D NO_IRQ) {
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0generic_handle_irq(irq); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return;
=A0 =A0 =A0 =A0}
--
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#36 lore raw

PATCH 30/37 powerpc: mpc62xx_pic: fix get_irq handling of NO_IRQ

In reply to Milton Miller

If none of irq category bits were set mpc52xx_get_irq() would pass NO_IRQ_IGNORE (-1) to irq_linear_revmap, which does an unsigned compare and declares the interrupt above the linear map range. It then punts to irq_find_mapping, which performs a linear search of all irqs, which will likely miss and only then return NO_IRQ.

If no status bit is set, then we should return NO_IRQ directly. The interrupt should not be suppressed from spurious counting, in fact that is the definition of supurious.

---

---
 arch/powerpc/platforms/52xx/mpc52xx_pic.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
arch/powerpc/platforms/52xx/mpc52xx_pic.c +3 -1
index bb61181..1a9a495 100644
@@ -486,7 +486,7 @@ void __init mpc52xx_init_irq(void)
 unsigned int mpc52xx_get_irq(void)
 {
 	u32 status;
-	int irq = NO_IRQ_IGNORE;
+	int irq;
 
 	status = in_be32(&intr->enc_status);
 	if (status & 0x00000400) {	/* critical */
@@ -509,6 +509,8 @@ unsigned int mpc52xx_get_irq(void)
 		} else {
 			irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
 		}
+	} else {
+		return NO_IRQ;
 	}
 
 	return irq_linear_revmap(mpc52xx_irqhost, irq);
Signature · 1 line
1.7.0.4
Acked-by on v1 30/37
#37 lore raw

Re: [PATCH 30/37] powerpc: mpc62xx_pic: fix get_irq handling of NO_IRQ

Quoted 11 lines · Milton Miller

If none of irq category bits were set mpc52xx_get_irq() would pass NO_IRQ_IGNORE (-1) to irq_linear_revmap, which does an unsigned compare and declares the interrupt above the linear map range. =A0It then punts to irq_find_mapping, which performs a linear search of all irqs, which will likely miss and only then return NO_IRQ.

If no status bit is set, then we should return NO_IRQ directly. The interrupt should not be suppressed from spurious counting, in fact that is the definition of supurious.

arch/powerpc/pla=

Quoted 6 lines

---
---
=A0arch/powerpc/platforms/52xx/mpc52xx_pic.c | =A0 =A04 +++- =A01 files changed, 3 insertions(+), 1 deletions(-)

arch/powerpc/pla= renamed from arch/powerpc/platforms/52xx/mpc52xx_pic.c +0 -0

tforms/52xx/mpc52xx_pic.c

Quoted 14 lines

index bb61181..1a9a495 100644

arch/powerpc/platforms/52xx/mpc52xx_pic.c +1 -1
@@ -486,7 +486,7 @@ void __init mpc52xx_init_irq(void)
 =A0unsigned int mpc52xx_get_irq(void)
 =A0{
 =A0 =A0 =A0 =A0u32 status;
- =A0 =A0 =A0 int irq =3D NO_IRQ_IGNORE;
+ =A0 =A0 =A0 int irq;
 
 =A0 =A0 =A0 =A0status =3D in_be32(&intr->enc_status);

=A0 =A0 =A0 =A0if (status & 0x00000400) { =A0 =A0 =A0/* critical */

arch/powerpc/platforms/52xx/mpc52xx_pic.c +0 -0
@@ -509,6 +509,8 @@ unsigned int mpc52xx_get_irq(void)
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} else {
Quoted 1 line

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0irq |=3D (MPC52xx_IRQ_L1_P=

ERP << MPC52xx_IRQ_L1_OFFSET);

Quoted 10 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 } else {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NO_IRQ;
=A0 =A0 =A0 =A0}

=A0 =A0 =A0 =A0return irq_linear_revmap(mpc52xx_irqhost, irq); --
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#38 lore raw

PATCH 31/37 powerpc: psurge: create a irq_host for secondary cpus

In reply to Milton Miller

Create a dummy irq_host using the generic dummy irq chip for the secondary cpus to use. Create a direct irq mapping for the ipi and register the ipi action handler against it. If for some unlikely reason part of this fails then don't detect the secondary cpus.

This removes another instance of NO_IRQ_IGNORE, records the ipi stats for the secondary cpus, and runs the ipi on the interrupt stack.

---

---
 arch/powerpc/platforms/powermac/pic.c  |    9 ++----
 arch/powerpc/platforms/powermac/pmac.h |    1 +
 arch/powerpc/platforms/powermac/smp.c  |   49 +++++++++++++++++++++++++++----
 3 files changed, 46 insertions(+), 13 deletions(-)
arch/powerpc/platforms/powermac/pic.c +3 -6
index b706cb3..360260d 100644
@@ -240,12 +240,9 @@ static unsigned int pmac_pic_get_irq(void)
 	unsigned long flags;
 
 #ifdef CONFIG_PPC_PMAC32_PSURGE
-	void psurge_smp_message_recv(void);
-
-       	/* IPI's are a hack on the powersurge -- Cort */
-       	if ( smp_processor_id() != 0 ) {
-		psurge_smp_message_recv();
-		return NO_IRQ_IGNORE;	/* ignore, already handled */
+	/* IPI's are a hack on the powersurge -- Cort */
+	if (smp_processor_id() != 0) {
+		return  psurge_secondary_virq;
         }
 #endif /* CONFIG_PPC_PMAC32_PSURGE */
 	raw_spin_lock_irqsave(&pmac_pic_lock, flags);
arch/powerpc/platforms/powermac/pmac.h +1 -0
index 20468f4..8327cce 100644
@@ -33,6 +33,7 @@ extern void pmac_setup_pci_dma(void);
 extern void pmac_check_ht_link(void);
 
 extern void pmac_setup_smp(void);
+extern int psurge_secondary_virq;
 extern void low_cpu_die(void) __attribute__((noreturn));
 
 extern int pmac_nvram_init(void);
arch/powerpc/platforms/powermac/smp.c +42 -7

83 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#39 lore raw

PATCH 32/37 powerpc: remove irq_host_ops->remap hook

In reply to Milton Miller

It was called from irq_create_mapping if that was called for a host and hwirq that was previously mapped, "to update the flags". But the only implementation was in beat_interrupt and all it did was repeat a hypervisor call without error checking that was performed with error checking at the beginning of the map hook. In addition, the comment on the beat remap hook says it will only called once for a given mapping, which would apply to map not remap.

All flags should be known by the time the match hook is called, before we call the map hook. Removing this mostly unused hook will simpify the requirements of irq_domain concept.

---
 arch/powerpc/include/asm/irq.h               |    3 ---
 arch/powerpc/kernel/irq.c                    |    2 --
 arch/powerpc/platforms/cell/beat_interrupt.c |   11 -----------
 3 files changed, 0 insertions(+), 16 deletions(-)
arch/powerpc/include/asm/irq.h +0 -3
index e1983d5..6f4a3ef 100644
@@ -88,9 +88,6 @@ struct irq_host_ops {
 	/* Dispose of such a mapping */
 	void (*unmap)(struct irq_host *h, unsigned int virq);
 
-	/* Update of such a mapping  */
-	void (*remap)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
-
 	/* Translate device-tree interrupt specifier from raw format coming
 	 * from the firmware to a irq_hw_number_t (interrupt line number) and
 	 * type (sense) that can be passed to set_irq_type(). In the absence
arch/powerpc/kernel/irq.c +0 -2
index 4a5aa8c..0715a09 100644
@@ -732,8 +732,6 @@ unsigned int irq_create_mapping(struct irq_host *host,
 	 */
 	virq = irq_find_mapping(host, hwirq);
 	if (virq != NO_IRQ) {
-		if (host->ops->remap)
-			host->ops->remap(host, virq, hwirq);
 		pr_debug("irq: -> existing mapping on virq %d\n", virq);
 		return virq;
 	}
arch/powerpc/platforms/cell/beat_interrupt.c +0 -11
index d46f7e4..55015e1 100644
@@ -148,16 +148,6 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
 }
 
 /*
- * Update binding hardware IRQ number (hw) and Virtuql
- * IRQ number (virq). This is called only once for a given mapping.
- */
-static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq,
-			       irq_hw_number_t hw)
-{
-	beat_construct_and_connect_irq_plug(virq, hw);
-}
-
-/*
  * Translate device-tree interrupt spec to irq_hw_number_t style (ulong),
  * to pass away to irq_create_mapping().
  *
@@ -184,7 +174,6 @@ static int beatic_pic_host_match(struct irq_host *h, struct device_node *np)
 
 static struct irq_host_ops beatic_pic_host_ops = {
 	.map = beatic_pic_host_map,
-	.remap = beatic_pic_host_remap,
 	.unmap = beatic_pic_host_unmap,
 	.xlate = beatic_pic_host_xlate,
 	.match = beatic_pic_host_match,
Signature · 1 line
1.7.0.4
#40 lore raw

PATCH 33/37 powerpc: spider-pic: get pic from chip_data instead of irq_map

In reply to Milton Miller

Building on Grant's efforts to remove the irq_map array, this patch moves spider-pics use of virq_to_host() to use irq_data_get_chip_data and sets the irq chip data in the map call, like most other interrupt controllers in powerpc.

---

---
 arch/powerpc/platforms/cell/spider-pic.c |   13 +++++++------
 1 files changed, 7 insertions(+), 6 deletions(-)
arch/powerpc/platforms/cell/spider-pic.c +7 -6
index 34d2b99..442c28c 100644
@@ -68,9 +68,9 @@ struct spider_pic {
 };
 static struct spider_pic spider_pics[SPIDER_CHIP_COUNT];
 
-static struct spider_pic *spider_virq_to_pic(unsigned int virq)
+static struct spider_pic *spider_irq_data_to_pic(struct irq_data *d)
 {
-	return virq_to_host(virq)->host_data;
+	return irq_data_get_irq_chip_data(d);
 }
 
 static void __iomem *spider_get_irq_config(struct spider_pic *pic,
@@ -81,7 +81,7 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic,
 
 static void spider_unmask_irq(struct irq_data *d)
 {
-	struct spider_pic *pic = spider_virq_to_pic(d->irq);
+	struct spider_pic *pic = spider_irq_data_to_pic(d);
 	void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d));
 
 	out_be32(cfg, in_be32(cfg) | 0x30000000u);
@@ -89,7 +89,7 @@ static void spider_unmask_irq(struct irq_data *d)
 
 static void spider_mask_irq(struct irq_data *d)
 {
-	struct spider_pic *pic = spider_virq_to_pic(d->irq);
+	struct spider_pic *pic = spider_irq_data_to_pic(d);
 	void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d));
 
 	out_be32(cfg, in_be32(cfg) & ~0x30000000u);
@@ -97,7 +97,7 @@ static void spider_mask_irq(struct irq_data *d)
 
 static void spider_ack_irq(struct irq_data *d)
 {
-	struct spider_pic *pic = spider_virq_to_pic(d->irq);
+	struct spider_pic *pic = spider_irq_data_to_pic(d);
 	unsigned int src = irqd_to_hwirq(d);
 
 	/* Reset edge detection logic if necessary
@@ -116,7 +116,7 @@ static void spider_ack_irq(struct irq_data *d)
 static int spider_set_irq_type(struct irq_data *d, unsigned int type)
 {
 	unsigned int sense = type & IRQ_TYPE_SENSE_MASK;
-	struct spider_pic *pic = spider_virq_to_pic(d->irq);
+	struct spider_pic *pic = spider_irq_data_to_pic(d);
 	unsigned int hw = irqd_to_hwirq(d);
 	void __iomem *cfg = spider_get_irq_config(pic, hw);
 	u32 old_mask;
@@ -171,6 +171,7 @@ static struct irq_chip spider_pic = {
 static int spider_host_map(struct irq_host *h, unsigned int virq,
 			irq_hw_number_t hw)
 {
+	irq_set_chip_data(virq, h->host_data);
 	irq_set_chip_and_handler(virq, &spider_pic, handle_level_irq);
 
 	/* Set default irq type */
Signature · 1 line
1.7.0.4
#41 lore raw

Re: [PATCH 33/37] powerpc: spider-pic: get pic from chip_data instead of irq_map

Quoted 4 lines · Milton Miller

Building on Grant's efforts to remove the irq_map array, this patch moves spider-pics use of virq_to_host() to use irq_data_get_chip_data and sets the irq chip data in the map call, like most other interrupt controllers in powerpc.

Looks good to me.

g.

arch/powerpc/plat=

Quoted 8 lines

---
---
=A0arch/powerpc/platforms/cell/spider-pic.c | =A0 13 +++++++------ =A01 files changed, 7 insertions(+), 6 deletions(-)

arch/powerpc/plat= renamed from arch/powerpc/platforms/cell/spider-pic.c +0 -0

forms/cell/spider-pic.c

arch/powerpc/platforms/cell/spider-pic.c static void __iomem *spider_get_irq_config(struct spide=

Quoted 16 lines

index 34d2b99..442c28c 100644

arch/powerpc/platforms/cell/spider-pic.c +2 -2
@@ -68,9 +68,9 @@ struct spider_pic {
 =A0};
 =A0static struct spider_pic spider_pics[SPIDER_CHIP_COUNT];
 
-static struct spider_pic *spider_virq_to_pic(unsigned int virq)
+static struct spider_pic *spider_irq_data_to_pic(struct irq_data *d)
 =A0{
- =A0 =A0 =A0 return virq_to_host(virq)->host_data;
+ =A0 =A0 =A0 return irq_data_get_irq_chip_data(d);
 =A0}
 
 =A0static void __iomem *spider_get_irq_config(struct spider_pic *pic,
@@ -81,7 +81,7 @@ static void __iomem *spider_get_irq_config(struct spide=

r_pic *pic,

Quoted 6 lines
arch/powerpc/platforms/cell/spider-pic.c +1 -1
 =A0static void spider_unmask_irq(struct irq_data *d)
 =A0{
- =A0 =A0 =A0 struct spider_pic *pic =3D spider_virq_to_pic(d->irq);
+ =A0 =A0 =A0 struct spider_pic *pic =3D spider_irq_data_to_pic(d);

=A0 =A0 =A0 =A0void __iomem *cfg =3D spider_get_irq_config(pic, irqd_to_h=

wirq(d));

Quoted 9 lines

=A0 =A0 =A0 =A0out_be32(cfg, in_be32(cfg) | 0x30000000u);

arch/powerpc/platforms/cell/spider-pic.c +1 -1
@@ -89,7 +89,7 @@ static void spider_unmask_irq(struct irq_data *d)
 
 =A0static void spider_mask_irq(struct irq_data *d)
 =A0{
- =A0 =A0 =A0 struct spider_pic *pic =3D spider_virq_to_pic(d->irq);
+ =A0 =A0 =A0 struct spider_pic *pic =3D spider_irq_data_to_pic(d);

=A0 =A0 =A0 =A0void __iomem *cfg =3D spider_get_irq_config(pic, irqd_to_h=

wirq(d));

Quoted 25 lines

=A0 =A0 =A0 =A0out_be32(cfg, in_be32(cfg) & ~0x30000000u);

arch/powerpc/platforms/cell/spider-pic.c +1 -1
@@ -97,7 +97,7 @@ static void spider_mask_irq(struct irq_data *d)
 
 =A0static void spider_ack_irq(struct irq_data *d)
 =A0{
- =A0 =A0 =A0 struct spider_pic *pic =3D spider_virq_to_pic(d->irq);
+ =A0 =A0 =A0 struct spider_pic *pic =3D spider_irq_data_to_pic(d);
 =A0 =A0 =A0 =A0unsigned int src =3D irqd_to_hwirq(d);
 

=A0 =A0 =A0 =A0/* Reset edge detection logic if necessary

arch/powerpc/platforms/cell/spider-pic.c +2 -1
@@ -116,7 +116,7 @@ static void spider_ack_irq(struct irq_data *d)
 =A0static int spider_set_irq_type(struct irq_data *d, unsigned int type)
 =A0{
 =A0 =A0 =A0 =A0unsigned int sense =3D type & IRQ_TYPE_SENSE_MASK;
- =A0 =A0 =A0 struct spider_pic *pic =3D spider_virq_to_pic(d->irq);
+ =A0 =A0 =A0 struct spider_pic *pic =3D spider_irq_data_to_pic(d);
 =A0 =A0 =A0 =A0unsigned int hw =3D irqd_to_hwirq(d);
 =A0 =A0 =A0 =A0void __iomem *cfg =3D spider_get_irq_config(pic, hw);
 =A0 =A0 =A0 =A0u32 old_mask;
@@ -171,6 +171,7 @@ static struct irq_chip spider_pic =3D {
 =A0static int spider_host_map(struct irq_host *h, unsigned int virq,
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0irq_hw_number_t hw)
 =A0{
+ =A0 =A0 =A0 irq_set_chip_data(virq, h->host_data);
Quoted 1 line

=A0 =A0 =A0 =A0irq_set_chip_and_handler(virq, &spider_pic, handle_level_i=

rq);

Quoted 6 lines

=A0 =A0 =A0 =A0/* Set default irq type */
--
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#42 lore raw

PATCH 34/37 powerpc: axon_msi: validate msi irq via chip_data

In reply to Milton Miller

Instead of checking for rogue msi numbers via the irq_map host field set the chip_data to h.host_data (which is the msic struct pointer) at map and compare it in get_irq.

---

---
 arch/powerpc/platforms/cell/axon_msi.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
arch/powerpc/platforms/cell/axon_msi.c +2 -1
index 1e3329e..ac06903 100644
@@ -113,7 +113,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
 		pr_devel("axon_msi: woff %x roff %x msi %x\n",
 			  write_offset, msic->read_offset, msi);
 
-		if (msi < NR_IRQS && virq_to_host(msi) == msic->irq_host) {
+		if (msi < NR_IRQS && irq_get_chip_data(msi) == msic) {
 			generic_handle_irq(msi);
 			msic->fifo_virt[idx] = cpu_to_le32(0xffffffff);
 		} else {
@@ -320,6 +320,7 @@ static struct irq_chip msic_irq_chip = {
 static int msic_host_map(struct irq_host *h, unsigned int virq,
 			 irq_hw_number_t hw)
 {
+	irq_set_chip_data(virq, h->host_data);
 	irq_set_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq);
 
 	return 0;
Signature · 1 line
1.7.0.4
#43 lore raw

PATCH 35/37 powerpc: add virq_is_host to reduce virq_to_host usage

In reply to Milton Miller

Some irq_host implementations are using virq_to_host to check if they are the irq_host for a virtual irq. To allow us to make space versus time tradeoffs, replace this usage with an assertive virq_is_host that confirms or denies the irq is associated with the given irq_host.

---
 arch/powerpc/include/asm/irq.h         |    1 +
 arch/powerpc/kernel/irq.c              |    6 ++++++
 arch/powerpc/sysdev/xics/xics-common.c |    2 +-
 3 files changed, 8 insertions(+), 1 deletions(-)
arch/powerpc/include/asm/irq.h +1 -0
index 6f4a3ef..a65d170 100644
@@ -128,6 +128,7 @@ struct irq_host {
 struct irq_data;
 extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
 extern irq_hw_number_t virq_to_hw(unsigned int virq);
+extern bool virq_is_host(unsigned int virq, struct irq_host *host);
 extern struct irq_host *virq_to_host(unsigned int virq);
 
 /**
arch/powerpc/kernel/irq.c +6 -0
index 0715a09..73cf290 100644
@@ -510,6 +510,12 @@ irq_hw_number_t virq_to_hw(unsigned int virq)
 }
 EXPORT_SYMBOL_GPL(virq_to_hw);
 
+bool virq_is_host(unsigned int virq, struct irq_host *host)
+{
+	return irq_map[virq].host == host;
+}
+EXPORT_SYMBOL_GPL(virq_is_host);
+
 struct irq_host *virq_to_host(unsigned int virq)
 {
 	return irq_map[virq].host;
arch/powerpc/sysdev/xics/xics-common.c +1 -1
index 43b2a79..445c5a0 100644
@@ -213,7 +213,7 @@ void xics_migrate_irqs_away(void)
 		/* We can't set affinity on ISA interrupts */
 		if (virq < NUM_ISA_INTERRUPTS)
 			continue;
-		if (virq_to_host(virq) != xics_host)
+		if (!virq_is_host(virq, xics_host))
 			continue;
 		irq = (unsigned int)virq_to_hw(virq);
 		/* We need to get IPIs still. */
Signature · 1 line
1.7.0.4
Acked-by on v1 35/37
#44 lore raw

Re: [PATCH 35/37] powerpc: add virq_is_host to reduce virq_to_host usage

Quoted 7 lines · Milton Miller

Some irq_host implementations are using virq_to_host to check if they are the irq_host for a virtual irq. =A0To allow us to make space versus time tradeoffs, replace this usage with an assertive virq_is_host that confirms or denies the irq is associated with the given irq_host.

arch/powerpc/include/asm/ir=

Quoted 7 lines

---
=A0arch/powerpc/include/asm/irq.h =A0 =A0 =A0 =A0 | =A0 =A01 + =A0arch/powerpc/kernel/irq.c =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 =A06 ++++++ =A0arch/powerpc/sysdev/xics/xics-common.c | =A0 =A02 +-
=A03 files changed, 8 insertions(+), 1 deletions(-)

arch/powerpc/include/asm/ir= renamed from arch/powerpc/include/asm/irq.h +0 -0

q.h

arch/powerpc/sysdev=

Quoted 29 lines

index 6f4a3ef..a65d170 100644

arch/powerpc/include/asm/irq.h +1 -0
@@ -128,6 +128,7 @@ struct irq_host {
 =A0struct irq_data;
 =A0extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
 =A0extern irq_hw_number_t virq_to_hw(unsigned int virq);
+extern bool virq_is_host(unsigned int virq, struct irq_host *host);
 =A0extern struct irq_host *virq_to_host(unsigned int virq);
 

=A0/**

arch/powerpc/kernel/irq.c +6 -0
index 0715a09..73cf290 100644
@@ -510,6 +510,12 @@ irq_hw_number_t virq_to_hw(unsigned int virq)
 =A0}
 =A0EXPORT_SYMBOL_GPL(virq_to_hw);
 
+bool virq_is_host(unsigned int virq, struct irq_host *host)
+{
+ =A0 =A0 =A0 return irq_map[virq].host =3D=3D host;
+}
+EXPORT_SYMBOL_GPL(virq_is_host);
+
 =A0struct irq_host *virq_to_host(unsigned int virq)
 =A0{
 =A0 =A0 =A0 =A0return irq_map[virq].host;
arch/powerpc/sysdev= renamed from arch/powerpc/sysdev/xics/xics-common.c +0 -0

/xics/xics-common.c

Quoted 5 lines

index 43b2a79..445c5a0 100644

arch/powerpc/sysdev/xics/xics-common.c +0 -0
@@ -213,7 +213,7 @@ void xics_migrate_irqs_away(void)

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* We can't set affinity on ISA interrupts=

*/

Quoted 11 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (virq < NUM_ISA_INTERRUPTS) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0continue;
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (virq_to_host(virq) !=3D xics_host)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!virq_is_host(virq, xics_host)) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0continue; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0irq =3D (unsigned int)virq_to_hw(virq); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* We need to get IPIs still. */ --
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#45 lore raw

PATCH 36/37 powerpc: remove virq_to_host

In reply to Milton Miller

The only references to the irq_map[].host field are internal to arch/powerpc/kernel/irq.c

---

---
 arch/powerpc/include/asm/irq.h |    1 -
 arch/powerpc/kernel/irq.c      |    6 ------
 2 files changed, 0 insertions(+), 7 deletions(-)
arch/powerpc/include/asm/irq.h +0 -1
index a65d170..1bff591 100644
@@ -129,7 +129,6 @@ struct irq_data;
 extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
 extern irq_hw_number_t virq_to_hw(unsigned int virq);
 extern bool virq_is_host(unsigned int virq, struct irq_host *host);
-extern struct irq_host *virq_to_host(unsigned int virq);
 
 /**
  * irq_alloc_host - Allocate a new irq_host data structure
arch/powerpc/kernel/irq.c +0 -6
index 73cf290..4368b5e 100644
@@ -516,12 +516,6 @@ bool virq_is_host(unsigned int virq, struct irq_host *host)
 }
 EXPORT_SYMBOL_GPL(virq_is_host);
 
-struct irq_host *virq_to_host(unsigned int virq)
-{
-	return irq_map[virq].host;
-}
-EXPORT_SYMBOL_GPL(virq_to_host);
-
 static int default_irq_host_match(struct irq_host *h, struct device_node *np)
 {
 	return h->of_node != NULL && h->of_node == np;
Signature · 1 line
1.7.0.4
Acked-by on v1 36/37
#46 lore raw

Re: [PATCH 36/37] powerpc: remove virq_to_host

Quoted 4 lines · Milton Miller

The only references to the irq_map[].host field are internal to arch/powerpc/kernel/irq.c

arch/powerpc/include/asm/ir=

Quoted 7 lines

---
---
=A0arch/powerpc/include/asm/irq.h | =A0 =A01 - =A0arch/powerpc/kernel/irq.c =A0 =A0 =A0| =A0 =A06 ------ =A02 files changed, 0 insertions(+), 7 deletions(-)

arch/powerpc/include/asm/ir= renamed from arch/powerpc/include/asm/irq.h +0 -0

q.h

arch/powerpc/kernel/irq.c bool virq_is_host(unsigned int virq, struct irq_host=

Quoted 16 lines

index a65d170..1bff591 100644

arch/powerpc/include/asm/irq.h +0 -1
@@ -129,7 +129,6 @@ struct irq_data;
 =A0extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
 =A0extern irq_hw_number_t virq_to_hw(unsigned int virq);
 =A0extern bool virq_is_host(unsigned int virq, struct irq_host *host);
-extern struct irq_host *virq_to_host(unsigned int virq);
 

=A0/**
=A0* irq_alloc_host - Allocate a new irq_host data structure

arch/powerpc/kernel/irq.c +0 -0
index 73cf290..4368b5e 100644
@@ -516,12 +516,6 @@ bool virq_is_host(unsigned int virq, struct irq_host=

*host)

Quoted 10 lines
arch/powerpc/kernel/irq.c +0 -6
 =A0}
 =A0EXPORT_SYMBOL_GPL(virq_is_host);
 
-struct irq_host *virq_to_host(unsigned int virq)
-{
- =A0 =A0 =A0 return irq_map[virq].host;
-}
-EXPORT_SYMBOL_GPL(virq_to_host);
-

=A0static int default_irq_host_match(struct irq_host *h, struct device_no=

de *np)

Quoted 6 lines

=A0{
=A0 =A0 =A0 =A0return h->of_node !=3D NULL && h->of_node =3D=3D np; --
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#47 lore raw

PATCH 37/37 powerpc: make IRQ_NOREQUEST last to clear, first to set

In reply to Milton Miller

When allocating irqs, wait to clear the IRQ_NOREQUEST flag until the host map hook has been called.

When freeing irqs, set the IRQ_NOREQUEST flag before calling the host unmap hook.

---
 arch/powerpc/kernel/irq.c |   14 +++++++-------
 1 files changed, 7 insertions(+), 7 deletions(-)
arch/powerpc/kernel/irq.c +7 -7
index 4368b5e..a24d37d 100644
@@ -586,14 +586,14 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
 			irq_map[i].host = host;
 			smp_wmb();
 
-			/* Clear norequest flags */
-			irq_clear_status_flags(i, IRQ_NOREQUEST);
-
 			/* Legacy flags are left to default at this point,
 			 * one can then use irq_create_mapping() to
 			 * explicitly change them
 			 */
 			ops->map(host, i, i);
+
+			/* Clear norequest flags */
+			irq_clear_status_flags(i, IRQ_NOREQUEST);
 		}
 		break;
 	case IRQ_HOST_MAP_LINEAR:
@@ -664,8 +664,6 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
 		goto error;
 	}
 
-	irq_clear_status_flags(virq, IRQ_NOREQUEST);
-
 	/* map it */
 	smp_wmb();
 	irq_map[virq].hwirq = hwirq;
@@ -676,6 +674,8 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
 		goto errdesc;
 	}
 
+	irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
 	return 0;
 
 errdesc:
@@ -819,6 +819,8 @@ void irq_dispose_mapping(unsigned int virq)
 	if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
 		return;
 
+	irq_set_status_flags(virq, IRQ_NOREQUEST);
+
 	/* remove chip and handler */
 	irq_set_chip_and_handler(virq, NULL, NULL);
 
@@ -848,8 +850,6 @@ void irq_dispose_mapping(unsigned int virq)
 	smp_mb();
 	irq_map[virq].hwirq = host->inval_irq;
 
-	irq_set_status_flags(virq, IRQ_NOREQUEST);
-
 	irq_free_descs(virq, 1);
 	/* Free it */
 	irq_free_virt(virq, 1);
Signature · 1 line
1.7.0.4
#48 lore raw

Re: [PATCH 37/37] powerpc: make IRQ_NOREQUEST last to clear, first to set

Quoted 5 lines · Milton Miller

When allocating irqs, wait to clear the IRQ_NOREQUEST flag until the host map hook has been called.

When freeing irqs, set the IRQ_NOREQUEST flag before calling the host unmap hook.

A description describing why this change is being made would be appreciated here.

g.

arch/powerpc/kernel/irq.c struct irq_host *irq_alloc_host(struct device_node =

Quoted 11 lines

---
=A0arch/powerpc/kernel/irq.c | =A0 14 +++++++------- =A01 files changed, 7 insertions(+), 7 deletions(-)

arch/powerpc/kernel/irq.c +0 -0
index 4368b5e..a24d37d 100644
@@ -586,14 +586,14 @@ struct irq_host *irq_alloc_host(struct device_node =

*of_node,

arch/powerpc/kernel/irq.c struct irq_host *irq_alloc_host(struct device_node = · line 590

Quoted 5 lines
arch/powerpc/kernel/irq.c +0 -2
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0irq_map[i].host =3D host;
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0smp_wmb();
 
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Clear norequest flags */
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq_clear_status_flags(i, I=

RQ_NOREQUEST);

Quoted 2 lines
arch/powerpc/kernel/irq.c +0 -1
-

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Legacy flags are left t=

o default at this point,

Quoted 1 line

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * one can then use irq_cr=

eate_mapping() to

Quoted 6 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * explicitly change them =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 */
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ops->map(host, i, i); +
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Clear norequest flags */
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq_clear_status_flags(i, I=

RQ_NOREQUEST);

arch/powerpc/kernel/irq.c static int irq_setup_virq(struct irq_host *host, unsi=

Quoted 4 lines

=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
=A0 =A0 =A0 =A0case IRQ_HOST_MAP_LINEAR:

arch/powerpc/kernel/irq.c +0 -0
@@ -664,8 +664,6 @@ static int irq_setup_virq(struct irq_host *host, unsi=

gned int virq,

arch/powerpc/kernel/irq.c static int irq_setup_virq(struct irq_host *host, unsi=

Quoted 9 lines
arch/powerpc/kernel/irq.c +0 -2
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto error;
 =A0 =A0 =A0 =A0}
 
- =A0 =A0 =A0 irq_clear_status_flags(virq, IRQ_NOREQUEST);
-

=A0 =A0 =A0 =A0/* map it */
=A0 =A0 =A0 =A0smp_wmb();
=A0 =A0 =A0 =A0irq_map[virq].hwirq =3D hwirq;

arch/powerpc/kernel/irq.c +0 -0
@@ -676,6 +674,8 @@ static int irq_setup_virq(struct irq_host *host, unsi=

gned int virq,

Quoted 24 lines
arch/powerpc/kernel/irq.c +2 -0
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto errdesc;
 =A0 =A0 =A0 =A0}
 
+ =A0 =A0 =A0 irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
 =A0 =A0 =A0 =A0return 0;
 

=A0errdesc:

arch/powerpc/kernel/irq.c +2 -0
@@ -819,6 +819,8 @@ void irq_dispose_mapping(unsigned int virq)
 =A0 =A0 =A0 =A0if (host->revmap_type =3D=3D IRQ_HOST_MAP_LEGACY)
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return;
 
+ =A0 =A0 =A0 irq_set_status_flags(virq, IRQ_NOREQUEST);
+

=A0 =A0 =A0 =A0/* remove chip and handler */
=A0 =A0 =A0 =A0irq_set_chip_and_handler(virq, NULL, NULL);

arch/powerpc/kernel/irq.c +0 -2
@@ -848,8 +850,6 @@ void irq_dispose_mapping(unsigned int virq)
 =A0 =A0 =A0 =A0smp_mb();
 =A0 =A0 =A0 =A0irq_map[virq].hwirq =3D host->inval_irq;
 
- =A0 =A0 =A0 irq_set_status_flags(virq, IRQ_NOREQUEST);
-
 =A0 =A0 =A0 =A0irq_free_descs(virq, 1);
Quoted 6 lines

=A0 =A0 =A0 =A0/* Free it */
=A0 =A0 =A0 =A0irq_free_virt(virq, 1);
--
1.7.0.4

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

#49 lore raw

Re: [PATCH 37/37] powerpc: make IRQ_NOREQUEST last to clear, first to set

Quoted 11 lines · Grant Likely
Quoted 5 lines · Milton Miller

When allocating irqs, wait to clear the IRQ_NOREQUEST flag until the host map hook has been called.

When freeing irqs, set the IRQ_NOREQUEST flag before calling the host unmap hook.

A description describing why this change is being made would be appreciated here.

g.

You are right. #insert <late addition to series but made cut>

When creating an irq, don't allow a concurent driver request until we have caled map, which will likley call set_chip_and_handler to change the irq_chip and its operations.

Similarly, when tearing down an IRQ, make sure no new uses come along while we change the irq back to the nop chip and then reset the descriptor to freed status.

If this is acceptable I'll let Ben update the changelog unless he asks me to resend.

milton

Quoted 69 lines
Quoted 69 lines

---
arch/powerpc/kernel/irq.c | 14 +++++++-------

1 files changed, 7 insertions(+), 7 deletions(-)
arch/powerpc/kernel/irq.c +5 -5
index 4368b5e..a24d37d 100644
@@ -586,14 +586,14 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
           irq_map[i].host = host;
           smp_wmb();
 
-            /* Clear norequest flags */
-            irq_clear_status_flags(i, IRQ_NOREQUEST);
-
           /* Legacy flags are left to default at this point,
            * one can then use irq_create_mapping() to
            * explicitly change them
            */
           ops->map(host, i, i);
+
+            /* Clear norequest flags */
+            irq_clear_status_flags(i, IRQ_NOREQUEST);
       }
       break;
   case IRQ_HOST_MAP_LINEAR:
@@ -664,8 +664,6 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
       goto error;
   }
 
-    irq_clear_status_flags(virq, IRQ_NOREQUEST);
-
   /* map it */
   smp_wmb();
   irq_map[virq].hwirq = hwirq;
@@ -676,6 +674,8 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
       goto errdesc;
   }
 
+    irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
   return 0;
 

errdesc:

arch/powerpc/kernel/irq.c +2 -3
@@ -819,6 +819,8 @@ void irq_dispose_mapping(unsigned int virq)
   if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
       return;
 
+    irq_set_status_flags(virq, IRQ_NOREQUEST);
+
   /* remove chip and handler */
   irq_set_chip_and_handler(virq, NULL, NULL);
 
@@ -848,8 +850,6 @@ void irq_dispose_mapping(unsigned int virq)
   smp_mb();
   irq_map[virq].hwirq = host->inval_irq;
 
-    irq_set_status_flags(virq, IRQ_NOREQUEST);
-
   irq_free_descs(virq, 1);
   /* Free it */
   irq_free_virt(virq, 1);
--

1.7.0.4

#50 lore raw
In reply to Milton Miller

On Wed, May 11, 2011 at 7:43 AM, Milton Miller <[email protected]> wrote:
[...]

Quoted 7 lines

After doing a bunch of grep's on arch/sh, I think the interesting parts of super8 interrupt handling that Thomas referred to are in drivers/sh/intc. =A0For some reason they populate the radix tree first with a descriptor of their common interrupt controler abstraction then walk the tree, replacing the tagged elements with the pointer to their equivalent to irq_map. =A0I do not yet understand the purpose of this two phase allocation.

BTW, you can also write a patch now that eliminates irq_map entirely. I just talked to tglx today and we agree in principle to move the hwirq value and irq_domain pointer directly into irq_data (and hence directly accessible from the irq_desc). The final form of irq_domain is still up in the air, but you could do an initial patch that leaves it as platform defined, and it can be followed up with a patch series that creates a common irq_domain definition.

g.