fix paca memory usage and NR_CPU loops, factor ipi and simplify irq code
Subsystems (6)
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
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.
--- arch/powerpc/kernel/misc_64.S | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-)
arch/powerpc/kernel/misc_64.S +8 -5
@@ -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
PATCH 2/37 powerpc: don't search for paca in freed memory
In reply to Milton MillerStarting 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
--- arch/powerpc/kernel/head_64.S | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-)
arch/powerpc/kernel/head_64.S +8 -5
@@ -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
PATCH 3/37 powerpc/kdump64: Don't reference freed memory as pacas
In reply to Milton MillerStarting 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
@@ -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
PATCH 4/37 powerpc/iseries: cleanup and fix secondary startup
In reply to Milton Miller9cb82f2f4692293a27c578c3038518ce4477de72 (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
@@ -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
PATCH 5/37 powerpc: Respect nr_cpu_ids when calling set_cpu_possible and set_cpu_present
In reply to Milton MillerWe 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
@@ -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
PATCH 6/37 powerpc: use nr_cpu_ids in initial paca allocation
In reply to Milton MillerNow 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
@@ -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
@@ -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
PATCH 7/37 powerpc: call no-longer static setup_nr_cpu_ids instead of replicating it
In reply to Milton Millerc1854e00727f50f7ac99e98d26ece04c087ef785 (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
@@ -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
PATCH 8/37 powerpc: mpic: limit NR_CPUS loop to 32 bit
In reply to Milton Millermpic_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
@@ -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
PATCH 9/37 powerpc: mpic: break cpumask abstraction earlier
In reply to Milton Millermpic_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
@@ -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
PATCH 10/37 powerpc: remove call sites of MSG_ALL_BUT_SELF
In reply to Milton MillerThe 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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 11/37 powerpc: remove checks for MSG_ALL and MSG_ALL_BUT_SELF
In reply to Milton MillerNow 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 12/37 linux/smp.h: remove unused MSG_ flags
In reply to Milton MillerNow 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
@@ -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
PATCH 13/37 powerpc/mpic: simplify ipi cpu mask handling
In reply to Milton MillerNow 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
@@ -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
PATCH 14/37 powerpc: remove powermac/pic.h
In reply to Milton MillerIts 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
@@ -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
PATCH 15/37 powerpc: remove alloc_maybe_bootmem for zalloc version
In reply to Milton MillerReplace all remaining callers of alloc_maybe_bootmem withzalloc_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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 16/37 powerpc: remove stubbed beat smp support
In reply to Milton MillerI 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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 17/37 powerpc cell: use smp_request_message_ipi
In reply to Milton MillerThis 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.
PATCH 18/37 powerpc: move smp_ops_t from machdep.h to smp.h
In reply to Milton MillerI 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
@@ -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
@@ -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
PATCH 19/37 powerpc: consolidate ipi message mux and demux
In reply to Milton MillerConsolidate 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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.cand call a newsmp_opscallback 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.
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.cand call a newsmp_opscallback 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.
PATCH 20/37 powerpc: add kconfig for muxed smp ipi support
In reply to Milton MillerCompile 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 21/37 powerpc: use bytes instead of bitops in smp ipi multiplexing
In reply to Milton MillerSince 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
@@ -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
PATCH 22/37 powerpc: xics: cleanup xics_host_map and ipi
In reply to Milton MillerSince 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
@@ -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
PATCH 23/37 powerpc: radix trees are available before init_IRQ
In reply to Milton MillerSince 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 thearch_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
@@ -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
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_initcallirq_late_init.Also, the kmem caches are allocated so we don't need to use
zalloc_maybe_bootmem.Signed-off-by Milton Miller <[email protected]>
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@@ -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=3DIRQ_HOST_MAP_LINEAR)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0size +=3Drevmap_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 =3Dkzalloc(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 =A0caseIRQ_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 =A0smp_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 returnirq_find_mapping(host, hwirq); -
- =A0 =A0 =A0 /* Now try to resolve */
- =A0 =A0 =A0 /*
=A0 =A0 =A0 =A0 * Norcu_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_maptabl=
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_th=
wirq)
Quoted 7 lines
=A0{
-
=A0 =A0 =A0 =A0WARN_ON(host->revmap_type !=3DIRQ_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 =A0smp_rmb();
- =A0 =A0 =A0 if (revmap_trees_allocated< 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
-
=A0 =A0 =A0 =A0if (virq !=3DNO_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 intvirq_debug_show(struct seq_file *m, void *private)=A0{
--
1.7.0.4
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
PATCH 24/37 powerpc: return early if irq_host lookup type is wrong
In reply to Milton MillerIf 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
@@ -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
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.Signed-off-by Milton Miller <[email protected]>
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@@ -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 * Norcu_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_th=
wirq)
arch/powerpc/kernel/irq.c unsigned int irq_linear_revmap(struct irq_host *host, · line 941
Quoted 13 lines
=A0{
- =A0 =A0 =A0WARN_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.
PATCH 25/37 powerpc: remove trival irq_host_ops.unmap
In reply to Milton MillerThese 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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 26/37 powerpc: remove i8259 irq_host_ops->unmap
In reply to Milton MillerIt 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
@@ -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
PATCH 27/37 powerpc fsl_msi: don't abuse platform_data for driver_data
In reply to Milton MillerThe 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
@@ -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
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_datais supposed to be for platforms to communicate to drivers parameters that are not otherwise discoverable. =A0Its lifetime matches theplatform_devicenot the platform device driver. =A0It is generally not needed for drivers that only support systems with device trees.Signed-off-by Milton Miller <[email protected]>
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 =A0dev->dev.platform_data=3D msi;
+ =A0 =A0 =A0platform_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.
PATCH 28/37 powerpc: fsl_msi: use chip_data not handler_data
In reply to Milton Millerhandler_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
@@ -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
PATCH 29/37 powerpc: mpc5121_ads_cpld: remove use of NO_IRQ_IGNORE
In reply to Milton MillerAs 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
@@ -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
Re: [PATCH 29/37] powerpc: mpc5121_ads_cpld: remove use of NO_IRQ_IGNORE
Quoted 1 line · Milton Miller
As
NO_IRQ_IGNOREis only used between the static function cpld_pic_get_ir=
q
Quoted 5 lines
and its caller
cpld_pic_cascade, andcpld_pic_cascadeonly uses it to suppress callinghandle_generic_irq, we can change these uses toNO_IRQand remove the extra tests and pathlength incpld_pic_cascade.Signed-off-by Milton Miller <[email protected]>
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 !=3DNO_IRQ&& irq !=3DNO_IRQ_IGNORE) {
+ =A0 =A0 =A0 if (irq !=3DNO_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 !=3DNO_IRQ&& irq !=3DNO_IRQ_IGNORE) {
+ =A0 =A0 =A0 if (irq !=3DNO_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.
PATCH 30/37 powerpc: mpc62xx_pic: fix get_irq handling of NO_IRQ
In reply to Milton MillerIf 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
@@ -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
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 passNO_IRQ_IGNORE(-1) toirq_linear_revmap, which does an unsigned compare and declares the interrupt above the linear map range. =A0It then punts toirq_find_mapping, which performs a linear search of all irqs, which will likely miss and only then returnNO_IRQ.If no status bit is set, then we should return
NO_IRQdirectly. The interrupt should not be suppressed from spurious counting, in fact that is the definition of supurious.Signed-off-by Milton Miller <[email protected]>
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 returnNO_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.
PATCH 31/37 powerpc: psurge: create a irq_host for secondary cpus
In reply to Milton MillerCreate 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
@@ -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
@@ -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
PATCH 32/37 powerpc: remove irq_host_ops->remap hook
In reply to Milton MillerIt 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
@@ -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
@@ -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
@@ -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
PATCH 33/37 powerpc: spider-pic: get pic from chip_data instead of irq_map
In reply to Milton MillerBuilding 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
@@ -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
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_maparray, this patch moves spider-pics use ofvirq_to_host()to useirq_data_get_chip_dataand 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
Signed-off-by Milton Miller <[email protected]>---
---
=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.
PATCH 34/37 powerpc: axon_msi: validate msi irq via chip_data
In reply to Milton MillerInstead 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
@@ -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
PATCH 35/37 powerpc: add virq_is_host to reduce virq_to_host usage
In reply to Milton MillerSome 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
@@ -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
@@ -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
@@ -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
Re: [PATCH 35/37] powerpc: add virq_is_host to reduce virq_to_host usage
Quoted 7 lines · Milton Miller
Some
irq_hostimplementations are usingvirq_to_hostto check if they are theirq_hostfor a virtual irq. =A0To allow us to make space versus time tradeoffs, replace this usage with an assertivevirq_is_hostthat confirms or denies the irq is associated with the givenirq_host.Signed-off-by Milton Miller <[email protected]>
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@@ -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)!=3Dxics_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.
PATCH 36/37 powerpc: remove virq_to_host
In reply to Milton MillerThe 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
@@ -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
@@ -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
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.cSigned-off-by Milton Miller <[email protected]>
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 newirq_hostdata structurearch/powerpc/kernel/irq.c +0
-0@@ -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 =A0returnh->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.
PATCH 37/37 powerpc: make IRQ_NOREQUEST last to clear, first to set
In reply to Milton MillerWhen 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
@@ -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
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_NOREQUESTflag until the host map hook has been called.When freeing irqs, set the
IRQ_NOREQUESTflag 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
Signed-off-by Milton Miller <[email protected]>---
=A0arch/powerpc/kernel/irq.c | =A0 14 +++++++------- =A01 files changed, 7 insertions(+), 7 deletions(-)arch/powerpc/kernel/irq.c +0
-0@@ -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 =A0caseIRQ_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.
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_NOREQUESTflag until the host map hook has been called.When freeing irqs, set the
IRQ_NOREQUESTflag 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
Signed-off-by Milton Miller <[email protected]>---
arch/powerpc/kernel/irq.c| 14 +++++++-------1 files changed, 7 insertions(+), 7 deletions(-)arch/powerpc/kernel/irq.c +5
-5@@ -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
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 indrivers/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 toirq_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.