diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 11:17:05 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 11:17:05 -0700 |
commit | 79c4581262e225a7c96d88b632b05ab3b5e9a52c (patch) | |
tree | 8ef030c74ab7e0d0df27cf86195f915efd2832f7 /arch/powerpc/sysdev | |
parent | 59534f7298c5e28aaa64e6ed550e247f64ee72ae (diff) | |
parent | 99ec28f183daa450faa7bdad6f932364ae325648 (diff) | |
download | linux-79c4581262e225a7c96d88b632b05ab3b5e9a52c.tar.gz linux-79c4581262e225a7c96d88b632b05ab3b5e9a52c.tar.bz2 linux-79c4581262e225a7c96d88b632b05ab3b5e9a52c.zip |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (92 commits)
powerpc: Remove unused 'protect4gb' boot parameter
powerpc: Build-in e1000e for pseries & ppc64_defconfig
powerpc/pseries: Make request_ras_irqs() available to other pseries code
powerpc/numa: Use ibm,architecture-vec-5 to detect form 1 affinity
powerpc/numa: Set a smaller value for RECLAIM_DISTANCE to enable zone reclaim
powerpc: Use smt_snooze_delay=-1 to always busy loop
powerpc: Remove check of ibm,smt-snooze-delay OF property
powerpc/kdump: Fix race in kdump shutdown
powerpc/kexec: Fix race in kexec shutdown
powerpc/kexec: Speedup kexec hash PTE tear down
powerpc/pseries: Add hcall to read 4 ptes at a time in real mode
powerpc: Use more accurate limit for first segment memory allocations
powerpc/kdump: Use chip->shutdown to disable IRQs
powerpc/kdump: CPUs assume the context of the oopsing CPU
powerpc/crashdump: Do not fail on NULL pointer dereferencing
powerpc/eeh: Fix oops when probing in early boot
powerpc/pci: Check devices status property when scanning OF tree
powerpc/vio: Switch VIO Bus PM to use generic helpers
powerpc: Avoid bad relocations in iSeries code
powerpc: Use common cpu_die (fixes SMP+SUSPEND build)
...
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r-- | arch/powerpc/sysdev/mpc8xxx_gpio.c | 147 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 72 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_soc.c | 24 |
3 files changed, 208 insertions, 35 deletions
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 6478eb10691a..83f519655fac 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -16,6 +16,7 @@ #include <linux/of_gpio.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/irq.h> #define MPC8XXX_GPIO_PINS 32 @@ -35,6 +36,7 @@ struct mpc8xxx_gpio_chip { * open drain mode safely */ u32 data; + struct irq_host *irq; }; static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) @@ -128,12 +130,136 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val return 0; } +static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + + if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS) + return irq_create_mapping(mpc8xxx_gc->irq, offset); + else + return -ENXIO; +} + +static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_desc_data(desc); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned int mask; + + mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR); + if (mask) + generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, + 32 - ffs(mask))); +} + +static void mpc8xxx_irq_unmask(unsigned int virq) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static void mpc8xxx_irq_mask(unsigned int virq) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static void mpc8xxx_irq_ack(unsigned int virq) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + + out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(virq))); +} + +static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + switch (flow_type) { + case IRQ_TYPE_EDGE_FALLING: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + setbits32(mm->regs + GPIO_ICR, + mpc8xxx_gpio2mask(virq_to_hw(virq))); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + case IRQ_TYPE_EDGE_BOTH: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + clrbits32(mm->regs + GPIO_ICR, + mpc8xxx_gpio2mask(virq_to_hw(virq))); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static struct irq_chip mpc8xxx_irq_chip = { + .name = "mpc8xxx-gpio", + .unmask = mpc8xxx_irq_unmask, + .mask = mpc8xxx_irq_mask, + .ack = mpc8xxx_irq_ack, + .set_type = mpc8xxx_irq_set_type, +}; + +static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + set_irq_chip_data(virq, h->host_data); + set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); + set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static int mpc8xxx_gpio_irq_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) + +{ + /* interrupt sense values coming from the device tree equal either + * EDGE_FALLING or EDGE_BOTH + */ + *out_hwirq = intspec[0]; + *out_flags = intspec[1]; + + return 0; +} + +static struct irq_host_ops mpc8xxx_gpio_irq_ops = { + .map = mpc8xxx_gpio_irq_map, + .xlate = mpc8xxx_gpio_irq_xlate, +}; + static void __init mpc8xxx_add_controller(struct device_node *np) { struct mpc8xxx_gpio_chip *mpc8xxx_gc; struct of_mm_gpio_chip *mm_gc; struct of_gpio_chip *of_gc; struct gpio_chip *gc; + unsigned hwirq; int ret; mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); @@ -158,11 +284,32 @@ static void __init mpc8xxx_add_controller(struct device_node *np) else gc->get = mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; + gc->to_irq = mpc8xxx_gpio_to_irq; ret = of_mm_gpiochip_add(np, mm_gc); if (ret) goto err; + hwirq = irq_of_parse_and_map(np, 0); + if (hwirq == NO_IRQ) + goto skip_irq; + + mpc8xxx_gc->irq = + irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, + &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); + if (!mpc8xxx_gc->irq) + goto skip_irq; + + mpc8xxx_gc->irq->host_data = mpc8xxx_gc; + + /* ack and mask all irqs */ + out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); + out_be32(mm_gc->regs + GPIO_IMR, 0); + + set_irq_data(hwirq, mpc8xxx_gc); + set_irq_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); + +skip_irq: return; err: diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 260295b10557..2102487612a4 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -568,12 +568,12 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) #endif /* CONFIG_MPIC_U3_HT_IRQS */ #ifdef CONFIG_SMP -static int irq_choose_cpu(const cpumask_t *mask) +static int irq_choose_cpu(const struct cpumask *mask) { int cpuid; if (cpumask_equal(mask, cpu_all_mask)) { - static int irq_rover; + static int irq_rover = 0; static DEFINE_RAW_SPINLOCK(irq_rover_lock); unsigned long flags; @@ -581,15 +581,11 @@ static int irq_choose_cpu(const cpumask_t *mask) do_round_robin: raw_spin_lock_irqsave(&irq_rover_lock, flags); - while (!cpu_online(irq_rover)) { - if (++irq_rover >= NR_CPUS) - irq_rover = 0; - } + irq_rover = cpumask_next(irq_rover, cpu_online_mask); + if (irq_rover >= nr_cpu_ids) + irq_rover = cpumask_first(cpu_online_mask); + cpuid = irq_rover; - do { - if (++irq_rover >= NR_CPUS) - irq_rover = 0; - } while (!cpu_online(irq_rover)); raw_spin_unlock_irqrestore(&irq_rover_lock, flags); } else { @@ -601,7 +597,7 @@ static int irq_choose_cpu(const cpumask_t *mask) return get_hard_smp_processor_id(cpuid); } #else -static int irq_choose_cpu(const cpumask_t *mask) +static int irq_choose_cpu(const struct cpumask *mask) { return hard_smp_processor_id(); } @@ -814,12 +810,16 @@ int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask) mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); } else { - cpumask_t tmp; + cpumask_var_t tmp; - cpumask_and(&tmp, cpumask, cpu_online_mask); + alloc_cpumask_var(&tmp, GFP_KERNEL); + + cpumask_and(tmp, cpumask, cpu_online_mask); mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), - mpic_physmask(cpus_addr(tmp)[0])); + mpic_physmask(cpumask_bits(tmp)[0])); + + free_cpumask_var(tmp); } return 0; @@ -1479,21 +1479,6 @@ void mpic_teardown_this_cpu(int secondary) } -void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) -{ - struct mpic *mpic = mpic_primary; - - 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(cpu_mask & cpus_addr(cpu_online_map)[0])); -} - static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) { u32 src; @@ -1589,8 +1574,25 @@ void mpic_request_ipis(void) } } +static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) +{ + struct mpic *mpic = mpic_primary; + + 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 target, 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", @@ -1599,13 +1601,17 @@ void smp_mpic_message_pass(int target, int msg) } switch (target) { case MSG_ALL: - mpic_send_ipi(msg, 0xffffffff); + mpic_send_ipi(msg, cpu_online_mask); break; case MSG_ALL_BUT_SELF: - mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); + 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, 1 << target); + mpic_send_ipi(msg, cpumask_of(target)); break; } } @@ -1616,7 +1622,7 @@ int __init smp_mpic_probe(void) DBG("smp_mpic_probe()...\n"); - nr_cpus = cpus_weight(cpu_possible_map); + nr_cpus = cpumask_weight(cpu_possible_mask); DBG("nr_cpus: %d\n", nr_cpus); diff --git a/arch/powerpc/sysdev/ppc4xx_soc.c b/arch/powerpc/sysdev/ppc4xx_soc.c index 5c014350bf16..d3d6ce3c33b4 100644 --- a/arch/powerpc/sysdev/ppc4xx_soc.c +++ b/arch/powerpc/sysdev/ppc4xx_soc.c @@ -191,11 +191,31 @@ static int __init ppc4xx_l2c_probe(void) arch_initcall(ppc4xx_l2c_probe); /* - * At present, this routine just applies a system reset. + * Apply a system reset. Alternatively a board specific value may be + * provided via the "reset-type" property in the cpu node. */ void ppc4xx_reset_system(char *cmd) { - mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_RST_SYSTEM); + struct device_node *np; + u32 reset_type = DBCR0_RST_SYSTEM; + const u32 *prop; + + np = of_find_node_by_type(NULL, "cpu"); + if (np) { + prop = of_get_property(np, "reset-type", NULL); + + /* + * Check if property exists and if it is in range: + * 1 - PPC4xx core reset + * 2 - PPC4xx chip reset + * 3 - PPC4xx system reset (default) + */ + if ((prop) && ((prop[0] >= 1) && (prop[0] <= 3))) + reset_type = prop[0] << 28; + } + + mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | reset_type); + while (1) ; /* Just in case the reset doesn't work */ } |