diff options
Diffstat (limited to 'arch/powerpc/platforms')
72 files changed, 1528 insertions, 742 deletions
diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index 546bbc2..2521d93 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -50,7 +50,7 @@ machine_device_initcall(ppc40x_simple, ppc40x_device_probe); * Again, if your board needs to do things differently then create a * board.c file for it rather than adding it to this list. */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "amcc,acadia", "amcc,haleakala", "amcc,kilauea", @@ -60,14 +60,9 @@ static char *board[] __initdata = { static int __init ppc40x_probe(void) { - unsigned long root = of_get_flat_dt_root(); - int i = 0; - - for (i = 0; i < ARRAY_SIZE(board); i++) { - if (of_flat_dt_is_compatible(root, board[i])) { - ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); - return 1; - } + if (of_flat_dt_match(of_get_flat_dt_root(), board)) { + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); + return 1; } return 0; diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 4ecf4cf..fde0ea5 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -59,9 +59,9 @@ irq_to_pic_bit(unsigned int irq) } static void -cpld_mask_irq(unsigned int irq) +cpld_mask_irq(struct irq_data *d) { - unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; + unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq; void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); out_8(pic_mask, @@ -69,9 +69,9 @@ cpld_mask_irq(unsigned int irq) } static void -cpld_unmask_irq(unsigned int irq) +cpld_unmask_irq(struct irq_data *d) { - unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; + unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq; void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); out_8(pic_mask, @@ -80,9 +80,9 @@ cpld_unmask_irq(unsigned int irq) static struct irq_chip cpld_pic = { .name = "CPLD PIC", - .mask = cpld_mask_irq, - .ack = cpld_mask_irq, - .unmask = cpld_unmask_irq, + .irq_mask = cpld_mask_irq, + .irq_ack = cpld_mask_irq, + .irq_unmask = cpld_unmask_irq, }; static int diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c index e487eb0..926731f 100644 --- a/arch/powerpc/platforms/512x/mpc5121_generic.c +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c @@ -26,7 +26,7 @@ /* * list of supported boards */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "prt,prtlvt", NULL }; @@ -36,16 +36,7 @@ static char *board[] __initdata = { */ static int __init mpc5121_generic_probe(void) { - unsigned long node = of_get_flat_dt_root(); - int i = 0; - - while (board[i]) { - if (of_flat_dt_is_compatible(node, board[i])) - break; - i++; - } - - return board[i] != NULL; + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(mpc5121_generic) { diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index de55bc0..01ffa64 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -172,20 +172,18 @@ static void __init lite5200_setup_arch(void) mpc52xx_setup_pci(); } +static const char *board[] __initdata = { + "fsl,lite5200", + "fsl,lite5200b", + NULL, +}; + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init lite5200_probe(void) { - unsigned long node = of_get_flat_dt_root(); - const char *model = of_get_flat_dt_prop(node, "model", NULL); - - if (!of_flat_dt_is_compatible(node, "fsl,lite5200") && - !of_flat_dt_is_compatible(node, "fsl,lite5200b")) - return 0; - pr_debug("%s board found\n", model ? model : "unknown"); - - return 1; + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(lite5200) { diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index 80234e5..eda0fc2 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -232,7 +232,7 @@ static void lite5200_pm_end(void) lite5200_pm_target_state = PM_SUSPEND_ON; } -static struct platform_suspend_ops lite5200_pm_ops = { +static const struct platform_suspend_ops lite5200_pm_ops = { .valid = lite5200_pm_valid, .begin = lite5200_pm_begin, .prepare = lite5200_pm_prepare, diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 0bac3a3..2bd1e6c 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -49,45 +49,46 @@ struct media5200_irq { }; struct media5200_irq media5200_irq; -static void media5200_irq_unmask(unsigned int virq) +static void media5200_irq_unmask(struct irq_data *d) { unsigned long flags; u32 val; spin_lock_irqsave(&media5200_irq.lock, flags); val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE); - val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq); + val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq); out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val); spin_unlock_irqrestore(&media5200_irq.lock, flags); } -static void media5200_irq_mask(unsigned int virq) +static void media5200_irq_mask(struct irq_data *d) { unsigned long flags; u32 val; spin_lock_irqsave(&media5200_irq.lock, flags); val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE); - val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq)); + val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq)); out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val); spin_unlock_irqrestore(&media5200_irq.lock, flags); } static struct irq_chip media5200_irq_chip = { .name = "Media5200 FPGA", - .unmask = media5200_irq_unmask, - .mask = media5200_irq_mask, - .mask_ack = media5200_irq_mask, + .irq_unmask = media5200_irq_unmask, + .irq_mask = media5200_irq_mask, + .irq_mask_ack = media5200_irq_mask, }; void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); int sub_virq, val; u32 status, enable; /* Mask off the cascaded IRQ */ raw_spin_lock(&desc->lock); - desc->chip->mask(virq); + chip->irq_mask(&desc->irq_data); raw_spin_unlock(&desc->lock); /* Ask the FPGA for IRQ status. If 'val' is 0, then no irqs @@ -105,9 +106,9 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc) /* Processing done; can reenable the cascade now */ raw_spin_lock(&desc->lock); - desc->chip->ack(virq); + chip->irq_ack(&desc->irq_data); if (!(desc->status & IRQ_DISABLED)) - desc->chip->unmask(virq); + chip->irq_unmask(&desc->irq_data); raw_spin_unlock(&desc->lock); } @@ -239,7 +240,7 @@ static void __init media5200_setup_arch(void) } /* list of the supported boards */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "fsl,media5200", NULL }; @@ -249,16 +250,7 @@ static char *board[] __initdata = { */ static int __init media5200_probe(void) { - unsigned long node = of_get_flat_dt_root(); - int i = 0; - - while (board[i]) { - if (of_flat_dt_is_compatible(node, board[i])) - break; - i++; - } - - return (board[i] != NULL); + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(media5200_platform) { diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index d45be5b..e36d6e2 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -49,7 +49,7 @@ static void __init mpc5200_simple_setup_arch(void) } /* list of the supported boards */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "intercontrol,digsy-mtc", "manroland,mucmc52", "manroland,uc101", @@ -66,16 +66,7 @@ static char *board[] __initdata = { */ static int __init mpc5200_simple_probe(void) { - unsigned long node = of_get_flat_dt_root(); - int i = 0; - - while (board[i]) { - if (of_flat_dt_is_compatible(node, board[i])) - break; - i++; - } - - return (board[i] != NULL); + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(mpc5200_simple_platform) { diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index e0d703c..c9290d8 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -135,9 +135,9 @@ DEFINE_MUTEX(mpc52xx_gpt_list_mutex); * Cascaded interrupt controller hooks */ -static void mpc52xx_gpt_irq_unmask(unsigned int virq) +static void mpc52xx_gpt_irq_unmask(struct irq_data *d) { - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); + struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d); unsigned long flags; spin_lock_irqsave(&gpt->lock, flags); @@ -145,9 +145,9 @@ static void mpc52xx_gpt_irq_unmask(unsigned int virq) spin_unlock_irqrestore(&gpt->lock, flags); } -static void mpc52xx_gpt_irq_mask(unsigned int virq) +static void mpc52xx_gpt_irq_mask(struct irq_data *d) { - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); + struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d); unsigned long flags; spin_lock_irqsave(&gpt->lock, flags); @@ -155,20 +155,20 @@ static void mpc52xx_gpt_irq_mask(unsigned int virq) spin_unlock_irqrestore(&gpt->lock, flags); } -static void mpc52xx_gpt_irq_ack(unsigned int virq) +static void mpc52xx_gpt_irq_ack(struct irq_data *d) { - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); + struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d); out_be32(&gpt->regs->status, MPC52xx_GPT_STATUS_IRQMASK); } -static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type) +static int mpc52xx_gpt_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); + struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d); unsigned long flags; u32 reg; - dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, virq, flow_type); + dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, d->irq, flow_type); spin_lock_irqsave(&gpt->lock, flags); reg = in_be32(&gpt->regs->mode) & ~MPC52xx_GPT_MODE_ICT_MASK; @@ -184,10 +184,10 @@ static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type) static struct irq_chip mpc52xx_gpt_irq_chip = { .name = "MPC52xx GPT", - .unmask = mpc52xx_gpt_irq_unmask, - .mask = mpc52xx_gpt_irq_mask, - .ack = mpc52xx_gpt_irq_ack, - .set_type = mpc52xx_gpt_irq_set_type, + .irq_unmask = mpc52xx_gpt_irq_unmask, + .irq_mask = mpc52xx_gpt_irq_mask, + .irq_ack = mpc52xx_gpt_irq_ack, + .irq_set_type = mpc52xx_gpt_irq_set_type, }; void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc) diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 4bf4bf7..9f3ed58 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -155,47 +155,47 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno) /* * IRQ[0-3] interrupt irq_chip */ -static void mpc52xx_extirq_mask(unsigned int virq) +static void mpc52xx_extirq_mask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->ctrl, 11 - l2irq); } -static void mpc52xx_extirq_unmask(unsigned int virq) +static void mpc52xx_extirq_unmask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->ctrl, 11 - l2irq); } -static void mpc52xx_extirq_ack(unsigned int virq) +static void mpc52xx_extirq_ack(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->ctrl, 27-l2irq); } -static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) +static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type) { u32 ctrl_reg, type; int irq; int l2irq; void *handler = handle_level_irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); @@ -214,44 +214,44 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) ctrl_reg |= (type << (22 - (l2irq * 2))); out_be32(&intr->ctrl, ctrl_reg); - __set_irq_handler_unlocked(virq, handler); + __set_irq_handler_unlocked(d->irq, handler); return 0; } static struct irq_chip mpc52xx_extirq_irqchip = { .name = "MPC52xx External", - .mask = mpc52xx_extirq_mask, - .unmask = mpc52xx_extirq_unmask, - .ack = mpc52xx_extirq_ack, - .set_type = mpc52xx_extirq_set_type, + .irq_mask = mpc52xx_extirq_mask, + .irq_unmask = mpc52xx_extirq_unmask, + .irq_ack = mpc52xx_extirq_ack, + .irq_set_type = mpc52xx_extirq_set_type, }; /* * Main interrupt irq_chip */ -static int mpc52xx_null_set_type(unsigned int virq, unsigned int flow_type) +static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type) { return 0; /* Do nothing so that the sense mask will get updated */ } -static void mpc52xx_main_mask(unsigned int virq) +static void mpc52xx_main_mask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->main_mask, 16 - l2irq); } -static void mpc52xx_main_unmask(unsigned int virq) +static void mpc52xx_main_unmask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->main_mask, 16 - l2irq); @@ -259,32 +259,32 @@ static void mpc52xx_main_unmask(unsigned int virq) static struct irq_chip mpc52xx_main_irqchip = { .name = "MPC52xx Main", - .mask = mpc52xx_main_mask, - .mask_ack = mpc52xx_main_mask, - .unmask = mpc52xx_main_unmask, - .set_type = mpc52xx_null_set_type, + .irq_mask = mpc52xx_main_mask, + .irq_mask_ack = mpc52xx_main_mask, + .irq_unmask = mpc52xx_main_unmask, + .irq_set_type = mpc52xx_null_set_type, }; /* * Peripherals interrupt irq_chip */ -static void mpc52xx_periph_mask(unsigned int virq) +static void mpc52xx_periph_mask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->per_mask, 31 - l2irq); } -static void mpc52xx_periph_unmask(unsigned int virq) +static void mpc52xx_periph_unmask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->per_mask, 31 - l2irq); @@ -292,43 +292,43 @@ static void mpc52xx_periph_unmask(unsigned int virq) static struct irq_chip mpc52xx_periph_irqchip = { .name = "MPC52xx Peripherals", - .mask = mpc52xx_periph_mask, - .mask_ack = mpc52xx_periph_mask, - .unmask = mpc52xx_periph_unmask, - .set_type = mpc52xx_null_set_type, + .irq_mask = mpc52xx_periph_mask, + .irq_mask_ack = mpc52xx_periph_mask, + .irq_unmask = mpc52xx_periph_unmask, + .irq_set_type = mpc52xx_null_set_type, }; /* * SDMA interrupt irq_chip */ -static void mpc52xx_sdma_mask(unsigned int virq) +static void mpc52xx_sdma_mask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_setbit(&sdma->IntMask, l2irq); } -static void mpc52xx_sdma_unmask(unsigned int virq) +static void mpc52xx_sdma_unmask(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&sdma->IntMask, l2irq); } -static void mpc52xx_sdma_ack(unsigned int virq) +static void mpc52xx_sdma_ack(struct irq_data *d) { int irq; int l2irq; - irq = irq_map[virq].hwirq; + irq = irq_map[d->irq].hwirq; l2irq = irq & MPC52xx_IRQ_L2_MASK; out_be32(&sdma->IntPend, 1 << l2irq); @@ -336,10 +336,10 @@ static void mpc52xx_sdma_ack(unsigned int virq) static struct irq_chip mpc52xx_sdma_irqchip = { .name = "MPC52xx SDMA", - .mask = mpc52xx_sdma_mask, - .unmask = mpc52xx_sdma_unmask, - .ack = mpc52xx_sdma_ack, - .set_type = mpc52xx_null_set_type, + .irq_mask = mpc52xx_sdma_mask, + .irq_unmask = mpc52xx_sdma_unmask, + .irq_ack = mpc52xx_sdma_ack, + .irq_set_type = mpc52xx_null_set_type, }; /** diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index 568cef6..8310e8b 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c @@ -186,7 +186,7 @@ void mpc52xx_pm_finish(void) iounmap(mbar); } -static struct platform_suspend_ops mpc52xx_pm_ops = { +static const struct platform_suspend_ops mpc52xx_pm_ops = { .valid = mpc52xx_pm_valid, .prepare = mpc52xx_pm_prepare, .enter = mpc52xx_pm_enter, diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index d982793..455fe21 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_CPM2) += pq2.o obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o obj-$(CONFIG_PQ2FADS) += pq2fads.o obj-$(CONFIG_EP8248E) += ep8248e.o -obj-$(CONFIG_MGCOGE) += mgcoge.o +obj-$(CONFIG_MGCOGE) += km82xx.o diff --git a/arch/powerpc/platforms/82xx/mgcoge.c b/arch/powerpc/platforms/82xx/km82xx.c index 7a5de9e..428c5e0 100644 --- a/arch/powerpc/platforms/82xx/mgcoge.c +++ b/arch/powerpc/platforms/82xx/km82xx.c @@ -1,6 +1,6 @@ /* - * Keymile mgcoge support - * Copyright 2008 DENX Software Engineering GmbH + * Keymile km82xx support + * Copyright 2008-2011 DENX Software Engineering GmbH * Author: Heiko Schocher <hs@denx.de> * * based on code from: @@ -31,9 +31,10 @@ #include "pq2.h" -static void __init mgcoge_pic_init(void) +static void __init km82xx_pic_init(void) { - struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); + struct device_node *np = of_find_compatible_node(NULL, NULL, + "fsl,pq2-pic"); if (!np) { printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); return; @@ -47,12 +48,18 @@ struct cpm_pin { int port, pin, flags; }; -static __initdata struct cpm_pin mgcoge_pins[] = { +static __initdata struct cpm_pin km82xx_pins[] = { /* SMC2 */ {0, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, {0, 9, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + /* SCC1 */ + {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + /* SCC4 */ {2, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, @@ -107,30 +114,49 @@ static __initdata struct cpm_pin mgcoge_pins[] = { {3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN}, {3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN}, #endif + + /* USB */ + {0, 10, CPM_PIN_OUTPUT | CPM_PIN_GPIO}, /* FULL_SPEED */ + {0, 11, CPM_PIN_OUTPUT | CPM_PIN_GPIO}, /*/SLAVE */ + {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXN */ + {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXP */ + {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, /* /OE */ + {2, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXCLK */ + {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, /* TXP */ + {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, /* TXN */ + {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXD */ }; static void __init init_ioports(void) { int i; - for (i = 0; i < ARRAY_SIZE(mgcoge_pins); i++) { - const struct cpm_pin *pin = &mgcoge_pins[i]; + for (i = 0; i < ARRAY_SIZE(km82xx_pins); i++) { + const struct cpm_pin *pin = &km82xx_pins[i]; cpm2_set_pin(pin->port, pin->pin, pin->flags); } cpm2_smc_clk_setup(CPM_CLK_SMC2, CPM_BRG8); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_CLK11, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_CLK11, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_RTX); cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK7, CPM_CLK_RX); cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK8, CPM_CLK_TX); cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_RX); cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK9, CPM_CLK_TX); cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); + + /* Force USB FULL SPEED bit to '1' */ + setbits32(&cpm2_immr->im_ioport.iop_pdata, 1 << (31 - 10)); + /* clear USB_SLAVE */ + clrbits32(&cpm2_immr->im_ioport.iop_pdata, 1 << (31 - 11)); } -static void __init mgcoge_setup_arch(void) +static void __init km82xx_setup_arch(void) { if (ppc_md.progress) - ppc_md.progress("mgcoge_setup_arch()", 0); + ppc_md.progress("km82xx_setup_arch()", 0); cpm2_reset(); @@ -142,7 +168,7 @@ static void __init mgcoge_setup_arch(void) init_ioports(); if (ppc_md.progress) - ppc_md.progress("mgcoge_setup_arch(), finish", 0); + ppc_md.progress("km82xx_setup_arch(), finish", 0); } static __initdata struct of_device_id of_bus_ids[] = { @@ -156,23 +182,23 @@ static int __init declare_of_platform_devices(void) return 0; } -machine_device_initcall(mgcoge, declare_of_platform_devices); +machine_device_initcall(km82xx, declare_of_platform_devices); /* * Called very early, device-tree isn't unflattened */ -static int __init mgcoge_probe(void) +static int __init km82xx_probe(void) { unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "keymile,mgcoge"); + return of_flat_dt_is_compatible(root, "keymile,km82xx"); } -define_machine(mgcoge) +define_machine(km82xx) { - .name = "Keymile MGCOGE", - .probe = mgcoge_probe, - .setup_arch = mgcoge_setup_arch, - .init_IRQ = mgcoge_pic_init, + .name = "Keymile km82xx", + .probe = km82xx_probe, + .setup_arch = km82xx_setup_arch, + .init_IRQ = km82xx_pic_init, .get_irq = cpm2_get_irq, .calibrate_decr = generic_calibrate_decr, .restart = pq2_restart, diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 5a55d87..926dfda 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -39,10 +39,10 @@ struct pq2ads_pci_pic { #define NUM_IRQS 32 -static void pq2ads_pci_mask_irq(unsigned int virq) +static void pq2ads_pci_mask_irq(struct irq_data *d) { - struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); - int irq = NUM_IRQS - virq_to_hw(virq) - 1; + struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); + int irq = NUM_IRQS - virq_to_hw(d->irq) - 1; if (irq != -1) { unsigned long flags; @@ -55,10 +55,10 @@ static void pq2ads_pci_mask_irq(unsigned int virq) } } -static void pq2ads_pci_unmask_irq(unsigned int virq) +static void pq2ads_pci_unmask_irq(struct irq_data *d) { - struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); - int irq = NUM_IRQS - virq_to_hw(virq) - 1; + struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); + int irq = NUM_IRQS - virq_to_hw(d->irq) - 1; if (irq != -1) { unsigned long flags; @@ -71,18 +71,17 @@ static void pq2ads_pci_unmask_irq(unsigned int virq) static struct irq_chip pq2ads_pci_ic = { .name = "PQ2 ADS PCI", - .end = pq2ads_pci_unmask_irq, - .mask = pq2ads_pci_mask_irq, - .mask_ack = pq2ads_pci_mask_irq, - .ack = pq2ads_pci_mask_irq, - .unmask = pq2ads_pci_unmask_irq, - .enable = pq2ads_pci_unmask_irq, - .disable = pq2ads_pci_mask_irq + .irq_mask = pq2ads_pci_mask_irq, + .irq_mask_ack = pq2ads_pci_mask_irq, + .irq_ack = pq2ads_pci_mask_irq, + .irq_unmask = pq2ads_pci_unmask_irq, + .irq_enable = pq2ads_pci_unmask_irq, + .irq_disable = pq2ads_pci_mask_irq }; static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct pq2ads_pci_pic *priv = desc->handler_data; + struct pq2ads_pci_pic *priv = get_irq_desc_data(desc); u32 stat, mask, pend; int bit; diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 6e8bbbb..ed95bfc 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -16,4 +16,4 @@ obj-$(CONFIG_MPC837x_MDS) += mpc837x_mds.o obj-$(CONFIG_SBC834x) += sbc834x.o obj-$(CONFIG_MPC837x_RDB) += mpc837x_rdb.o obj-$(CONFIG_ASP834x) += asp834x.o -obj-$(CONFIG_KMETER1) += kmeter1.o +obj-$(CONFIG_KMETER1) += km83xx.o diff --git a/arch/powerpc/platforms/83xx/kmeter1.c b/arch/powerpc/platforms/83xx/km83xx.c index 903acfd..a2b9b9e 100644 --- a/arch/powerpc/platforms/83xx/kmeter1.c +++ b/arch/powerpc/platforms/83xx/km83xx.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 DENX Software Engineering GmbH + * Copyright 2008-2011 DENX Software Engineering GmbH * Author: Heiko Schocher <hs@denx.de> * * Description: @@ -49,12 +49,12 @@ * Setup the architecture * */ -static void __init kmeter1_setup_arch(void) +static void __init mpc83xx_km_setup_arch(void) { struct device_node *np; if (ppc_md.progress) - ppc_md.progress("kmeter1_setup_arch()", 0); + ppc_md.progress("kmpbec83xx_setup_arch()", 0); #ifdef CONFIG_PCI for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") @@ -69,6 +69,9 @@ static void __init kmeter1_setup_arch(void) par_io_init(np); of_node_put(np); + for_each_node_by_name(np, "spi") + par_io_of_config(np); + for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;) par_io_of_config(np); } @@ -119,7 +122,7 @@ static void __init kmeter1_setup_arch(void) #endif /* CONFIG_QUICC_ENGINE */ } -static struct of_device_id kmeter_ids[] = { +static struct of_device_id kmpbec83xx_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .compatible = "simple-bus", }, @@ -131,13 +134,13 @@ static struct of_device_id kmeter_ids[] = { static int __init kmeter_declare_of_platform_devices(void) { /* Publish the QE devices */ - of_platform_bus_probe(NULL, kmeter_ids, NULL); + of_platform_bus_probe(NULL, kmpbec83xx_ids, NULL); return 0; } -machine_device_initcall(kmeter1, kmeter_declare_of_platform_devices); +machine_device_initcall(mpc83xx_km, kmeter_declare_of_platform_devices); -static void __init kmeter1_init_IRQ(void) +static void __init mpc83xx_km_init_IRQ(void) { struct device_node *np; @@ -168,21 +171,34 @@ static void __init kmeter1_init_IRQ(void) #endif /* CONFIG_QUICC_ENGINE */ } +/* list of the supported boards */ +static char *board[] __initdata = { + "Keymile,KMETER1", + "Keymile,kmpbec8321", + NULL +}; + /* * Called very early, MMU is off, device-tree isn't unflattened */ -static int __init kmeter1_probe(void) +static int __init mpc83xx_km_probe(void) { - unsigned long root = of_get_flat_dt_root(); + unsigned long node = of_get_flat_dt_root(); + int i = 0; - return of_flat_dt_is_compatible(root, "keymile,KMETER1"); + while (board[i]) { + if (of_flat_dt_is_compatible(node, board[i])) + break; + i++; + } + return (board[i] != NULL); } -define_machine(kmeter1) { - .name = "KMETER1", - .probe = kmeter1_probe, - .setup_arch = kmeter1_setup_arch, - .init_IRQ = kmeter1_init_IRQ, +define_machine(mpc83xx_km) { + .name = "mpc83xx-km-platform", + .probe = mpc83xx_km_probe, + .setup_arch = mpc83xx_km_setup_arch, + .init_IRQ = mpc83xx_km_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c index 846831d..d0c4e15 100644 --- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c @@ -57,16 +57,19 @@ static void __init mpc830x_rdb_init_IRQ(void) ipic_set_default_priority(); } +static const char *board[] __initdata = { + "MPC8308RDB", + "fsl,mpc8308rdb", + "denx,mpc8308_p1m", + NULL +}; + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init mpc830x_rdb_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "MPC8308RDB") || - of_flat_dt_is_compatible(root, "fsl,mpc8308rdb") || - of_flat_dt_is_compatible(root, "denx,mpc8308_p1m"); + return of_flat_dt_match(of_get_flat_dt_root(), board); } static struct of_device_id __initdata of_bus_ids[] = { diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index ae525e4..f859ead 100644 --- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c @@ -60,15 +60,18 @@ static void __init mpc831x_rdb_init_IRQ(void) ipic_set_default_priority(); } +static const char *board[] __initdata = { + "MPC8313ERDB", + "fsl,mpc8315erdb", + NULL +}; + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init mpc831x_rdb_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "MPC8313ERDB") || - of_flat_dt_is_compatible(root, "fsl,mpc8315erdb"); + return of_flat_dt_match(of_get_flat_dt_root(), board); } static struct of_device_id __initdata of_bus_ids[] = { diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 910caa6..7bafbf2 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -101,17 +101,20 @@ static void __init mpc837x_rdb_init_IRQ(void) ipic_set_default_priority(); } +static const char *board[] __initdata = { + "fsl,mpc8377rdb", + "fsl,mpc8378rdb", + "fsl,mpc8379rdb", + "fsl,mpc8377wlan", + NULL +}; + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init mpc837x_rdb_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "fsl,mpc8377rdb") || - of_flat_dt_is_compatible(root, "fsl,mpc8378rdb") || - of_flat_dt_is_compatible(root, "fsl,mpc8379rdb") || - of_flat_dt_is_compatible(root, "fsl,mpc8377wlan"); + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(mpc837x_rdb) { diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 0fea881..82a4345 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -35,6 +35,8 @@ /* system i/o configuration register high */ #define MPC83XX_SICRH_OFFS 0x118 +#define MPC8308_SICRH_USB_MASK 0x000c0000 +#define MPC8308_SICRH_USB_ULPI 0x00040000 #define MPC834X_SICRH_USB_UTMI 0x00020000 #define MPC831X_SICRH_USB_MASK 0x000000e0 #define MPC831X_SICRH_USB_ULPI 0x000000a0 diff --git a/arch/powerpc/platforms/83xx/suspend-asm.S b/arch/powerpc/platforms/83xx/suspend-asm.S index 1930543..3d1ecd2 100644 --- a/arch/powerpc/platforms/83xx/suspend-asm.S +++ b/arch/powerpc/platforms/83xx/suspend-asm.S @@ -231,7 +231,7 @@ _GLOBAL(mpc83xx_enter_deep_sleep) ori r4, r4, 0x002a mtspr SPRN_DBAT0L, r4 lis r8, TMP_VIRT_IMMR@h - ori r4, r8, 0x001e /* 1 MByte accessable from Kernel Space only */ + ori r4, r8, 0x001e /* 1 MByte accessible from Kernel Space only */ mtspr SPRN_DBAT0U, r4 isync @@ -241,7 +241,7 @@ _GLOBAL(mpc83xx_enter_deep_sleep) ori r4, r4, 0x002a mtspr SPRN_DBAT1L, r4 lis r9, (TMP_VIRT_IMMR + 0x01000000)@h - ori r4, r9, 0x001e /* 1 MByte accessable from Kernel Space only */ + ori r4, r9, 0x001e /* 1 MByte accessible from Kernel Space only */ mtspr SPRN_DBAT1U, r4 isync @@ -253,7 +253,7 @@ _GLOBAL(mpc83xx_enter_deep_sleep) li r4, 0x0002 mtspr SPRN_DBAT2L, r4 lis r4, KERNELBASE@h - ori r4, r4, 0x001e /* 1 MByte accessable from Kernel Space only */ + ori r4, r4, 0x001e /* 1 MByte accessible from Kernel Space only */ mtspr SPRN_DBAT2U, r4 isync diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 75ae77f..fd4f2f2 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -311,7 +311,7 @@ static int mpc83xx_is_pci_agent(void) return ret; } -static struct platform_suspend_ops mpc83xx_suspend_ops = { +static const struct platform_suspend_ops mpc83xx_suspend_ops = { .valid = mpc83xx_suspend_valid, .begin = mpc83xx_suspend_begin, .enter = mpc83xx_suspend_enter, diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index 3ba4bb7..2c64164 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c @@ -127,7 +127,8 @@ int mpc831x_usb_cfg(void) /* Configure clock */ immr_node = of_get_parent(np); - if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) + if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") || + of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))) clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, MPC8315_SCCR_USB_MASK, MPC8315_SCCR_USB_DRCM_01); @@ -138,7 +139,11 @@ int mpc831x_usb_cfg(void) /* Configure pin mux for ULPI. There is no pin mux for UTMI */ if (prop && !strcmp(prop, "ulpi")) { - if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) { + if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) { + clrsetbits_be32(immap + MPC83XX_SICRH_OFFS, + MPC8308_SICRH_USB_MASK, + MPC8308_SICRH_USB_ULPI); + } else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) { clrsetbits_be32(immap + MPC83XX_SICRL_OFFS, MPC8315_SICRL_USB_MASK, MPC8315_SICRL_USB_ULPI); @@ -173,6 +178,9 @@ int mpc831x_usb_cfg(void) !strcmp(prop, "utmi"))) { u32 refsel; + if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) + goto out; + if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) refsel = CONTROL_REFSEL_24MHZ; else @@ -186,9 +194,11 @@ int mpc831x_usb_cfg(void) temp = CONTROL_PHY_CLK_SEL_ULPI; #ifdef CONFIG_USB_OTG /* Set OTG_PORT */ - dr_mode = of_get_property(np, "dr_mode", NULL); - if (dr_mode && !strcmp(dr_mode, "otg")) - temp |= CONTROL_OTG_PORT; + if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) { + dr_mode = of_get_property(np, "dr_mode", NULL); + if (dr_mode && !strcmp(dr_mode, "otg")) + temp |= CONTROL_OTG_PORT; + } #endif /* CONFIG_USB_OTG */ out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp); } else { @@ -196,6 +206,7 @@ int mpc831x_usb_cfg(void) ret = -EINVAL; } +out: iounmap(usb_regs); of_node_put(np); return ret; diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index f4d36b5..64447e4 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c @@ -56,12 +56,13 @@ static void machine_restart(char *cmd) static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); int cascade_irq; while ((cascade_irq = cpm2_get_irq()) >= 0) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } static void __init ksi8560_pic_init(void) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 9438a89..1352d11 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -50,12 +50,13 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); int cascade_irq; while ((cascade_irq = cpm2_get_irq()) >= 0) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } #endif /* CONFIG_CPM2 */ diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 8190bc2..793ead7 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -47,12 +47,13 @@ #ifdef CONFIG_PPC_I8259 static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); unsigned int cascade_irq = i8259_irq(); if (cascade_irq != NO_IRQ) { generic_handle_irq(cascade_irq); } - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } #endif /* CONFIG_PPC_I8259 */ diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index aa34cac..747d1ee 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -309,7 +309,7 @@ static void __init mpc85xx_mds_qe_init(void) /* P1021 has pins muxed for QE and other functions. To * enable QE UEC mode, we need to set bit QE0 for UCC1 * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 - * and QE12 for QE MII management singals in PMUXCR + * and QE12 for QE MII management signals in PMUXCR * register. */ setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 | diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index a5ad1c7..d7e28ec 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c @@ -41,12 +41,13 @@ static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); int cascade_irq; while ((cascade_irq = cpm2_get_irq()) >= 0) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } #endif /* CONFIG_CPM2 */ diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 5c91a99..0d00ff9 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -91,10 +91,14 @@ smp_85xx_kick_cpu(int nr) while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) mdelay(1); #else + smp_generic_kick_cpu(nr); + out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER), __pa((u64)*((unsigned long long *) generic_secondary_smp_init))); - smp_generic_kick_cpu(nr); + if (!ioremappable) + flush_dcache_range((ulong)bptr_vaddr, + (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY)); #endif local_irq_restore(flags); diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index d48527f..79d85ac 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -93,6 +93,7 @@ static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq) void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); unsigned int cascade_irq; /* @@ -103,17 +104,16 @@ void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc) if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); - + chip->irq_eoi(&desc->irq_data); } -static void socrates_fpga_pic_ack(unsigned int virq) +static void socrates_fpga_pic_ack(struct irq_data *d) { unsigned long flags; unsigned int hwirq, irq_line; uint32_t mask; - hwirq = socrates_fpga_irq_to_hw(virq); + hwirq = socrates_fpga_irq_to_hw(d->irq); irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); @@ -124,14 +124,14 @@ static void socrates_fpga_pic_ack(unsigned int virq) raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); } -static void socrates_fpga_pic_mask(unsigned int virq) +static void socrates_fpga_pic_mask(struct irq_data *d) { unsigned long flags; unsigned int hwirq; int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(virq); + hwirq = socrates_fpga_irq_to_hw(d->irq); irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); @@ -142,14 +142,14 @@ static void socrates_fpga_pic_mask(unsigned int virq) raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); } -static void socrates_fpga_pic_mask_ack(unsigned int virq) +static void socrates_fpga_pic_mask_ack(struct irq_data *d) { unsigned long flags; unsigned int hwirq; int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(virq); + hwirq = socrates_fpga_irq_to_hw(d->irq); irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); @@ -161,14 +161,14 @@ static void socrates_fpga_pic_mask_ack(unsigned int virq) raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); } -static void socrates_fpga_pic_unmask(unsigned int virq) +static void socrates_fpga_pic_unmask(struct irq_data *d) { unsigned long flags; unsigned int hwirq; int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(virq); + hwirq = socrates_fpga_irq_to_hw(d->irq); irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); @@ -179,14 +179,14 @@ static void socrates_fpga_pic_unmask(unsigned int virq) raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); } -static void socrates_fpga_pic_eoi(unsigned int virq) +static void socrates_fpga_pic_eoi(struct irq_data *d) { unsigned long flags; unsigned int hwirq; int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(virq); + hwirq = socrates_fpga_irq_to_hw(d->irq); irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); @@ -197,7 +197,7 @@ static void socrates_fpga_pic_eoi(unsigned int virq) raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); } -static int socrates_fpga_pic_set_type(unsigned int virq, +static int socrates_fpga_pic_set_type(struct irq_data *d, unsigned int flow_type) { unsigned long flags; @@ -205,7 +205,7 @@ static int socrates_fpga_pic_set_type(unsigned int virq, int polarity; u32 mask; - hwirq = socrates_fpga_irq_to_hw(virq); + hwirq = socrates_fpga_irq_to_hw(d->irq); if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE) return -EINVAL; @@ -233,12 +233,12 @@ static int socrates_fpga_pic_set_type(unsigned int virq, static struct irq_chip socrates_fpga_pic_chip = { .name = "FPGA-PIC", - .ack = socrates_fpga_pic_ack, - .mask = socrates_fpga_pic_mask, - .mask_ack = socrates_fpga_pic_mask_ack, - .unmask = socrates_fpga_pic_unmask, - .eoi = socrates_fpga_pic_eoi, - .set_type = socrates_fpga_pic_set_type, + .irq_ack = socrates_fpga_pic_ack, + .irq_mask = socrates_fpga_pic_mask, + .irq_mask_ack = socrates_fpga_pic_mask_ack, + .irq_unmask = socrates_fpga_pic_unmask, + .irq_eoi = socrates_fpga_pic_eoi, + .irq_set_type = socrates_fpga_pic_set_type, }; static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index bc33d18..2b62b06 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -46,12 +46,13 @@ static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); int cascade_irq; while ((cascade_irq = cpm2_get_irq()) >= 0) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } #endif /* CONFIG_CPM2 */ diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index 8f29bbc..2265b68 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -44,12 +44,13 @@ static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); int cascade_irq; while ((cascade_irq = cpm2_get_irq()) >= 0) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } #endif /* CONFIG_CPM2 */ @@ -186,21 +187,21 @@ static int __init declare_of_platform_devices(void) } machine_device_initcall(tqm85xx, declare_of_platform_devices); +static const char *board[] __initdata = { + "tqc,tqm8540", + "tqc,tqm8541", + "tqc,tqm8548", + "tqc,tqm8555", + "tqc,tqm8560", + NULL +}; + /* * Called very early, device-tree isn't unflattened */ static int __init tqm85xx_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - if ((of_flat_dt_is_compatible(root, "tqc,tqm8540")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8541")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8548")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8555")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8560"))) - return 1; - - return 0; + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(tqm85xx) { diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 6df9e25..0adfe3b 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c @@ -95,6 +95,7 @@ static int gef_pic_cascade_irq; void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); unsigned int cascade_irq; /* @@ -106,17 +107,16 @@ void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); - + chip->irq_eoi(&desc->irq_data); } -static void gef_pic_mask(unsigned int virq) +static void gef_pic_mask(struct irq_data *d) { unsigned long flags; unsigned int hwirq; u32 mask; - hwirq = gef_irq_to_hw(virq); + hwirq = gef_irq_to_hw(d->irq); raw_spin_lock_irqsave(&gef_pic_lock, flags); mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); @@ -125,21 +125,21 @@ static void gef_pic_mask(unsigned int virq) raw_spin_unlock_irqrestore(&gef_pic_lock, flags); } -static void gef_pic_mask_ack(unsigned int virq) +static void gef_pic_mask_ack(struct irq_data *d) { /* Don't think we actually have to do anything to ack an interrupt, * we just need to clear down the devices interrupt and it will go away */ - gef_pic_mask(virq); + gef_pic_mask(d); } -static void gef_pic_unmask(unsigned int virq) +static void gef_pic_unmask(struct irq_data *d) { unsigned long flags; unsigned int hwirq; u32 mask; - hwirq = gef_irq_to_hw(virq); + hwirq = gef_irq_to_hw(d->irq); raw_spin_lock_irqsave(&gef_pic_lock, flags); mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); @@ -150,9 +150,9 @@ static void gef_pic_unmask(unsigned int virq) static struct irq_chip gef_pic_chip = { .name = "gefp", - .mask = gef_pic_mask, - .mask_ack = gef_pic_mask_ack, - .unmask = gef_pic_unmask, + .irq_mask = gef_pic_mask, + .irq_mask_ack = gef_pic_mask_ack, + .irq_unmask = gef_pic_unmask, }; diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c index 668275d..cbe3363 100644 --- a/arch/powerpc/platforms/86xx/pic.c +++ b/arch/powerpc/platforms/86xx/pic.c @@ -19,10 +19,13 @@ #ifdef CONFIG_PPC_I8259 static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); unsigned int cascade_irq = i8259_irq(); + if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + + chip->irq_eoi(&desc->irq_data); } #endif /* CONFIG_PPC_I8259 */ diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index dd35ce0..ee56a9e 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -49,12 +49,6 @@ config PPC_ADDER875 This enables support for the Analogue & Micro Adder 875 board. -config PPC_MGSUVD - bool "MGSUVD" - select CPM1 - help - This enables support for the Keymile MGSUVD board. - config TQM8XX bool "TQM8XX" select CPM1 diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile index a491fe6..76a81c3 100644 --- a/arch/powerpc/platforms/8xx/Makefile +++ b/arch/powerpc/platforms/8xx/Makefile @@ -6,5 +6,4 @@ obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o obj-$(CONFIG_PPC_EP88XC) += ep88xc.o obj-$(CONFIG_PPC_ADDER875) += adder875.o -obj-$(CONFIG_PPC_MGSUVD) += mgsuvd.o obj-$(CONFIG_TQM8XX) += tqm8xx_setup.o diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 60168c1..fabb108 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -218,15 +218,20 @@ void mpc8xx_restart(char *cmd) static void cpm_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip; int cascade_irq; if ((cascade_irq = cpm_get_irq()) >= 0) { struct irq_desc *cdesc = irq_to_desc(cascade_irq); generic_handle_irq(cascade_irq); - cdesc->chip->eoi(cascade_irq); + + chip = get_irq_desc_chip(cdesc); + chip->irq_eoi(&cdesc->irq_data); } - desc->chip->eoi(irq); + + chip = get_irq_desc_chip(desc); + chip->irq_eoi(&desc->irq_data); } /* Initialize the internal interrupt controllers. The number of diff --git a/arch/powerpc/platforms/8xx/mgsuvd.c b/arch/powerpc/platforms/8xx/mgsuvd.c deleted file mode 100644 index ca3cb07..0000000 --- a/arch/powerpc/platforms/8xx/mgsuvd.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * - * Platform setup for the Keymile mgsuvd board - * - * Heiko Schocher <hs@denx.de> - * - * Copyright 2008 DENX Software Engineering GmbH - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/ioport.h> -#include <linux/of_platform.h> - -#include <asm/io.h> -#include <asm/machdep.h> -#include <asm/processor.h> -#include <asm/cpm1.h> -#include <asm/prom.h> -#include <asm/fs_pd.h> - -#include "mpc8xx.h" - -struct cpm_pin { - int port, pin, flags; -}; - -static __initdata struct cpm_pin mgsuvd_pins[] = { - /* SMC1 */ - {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */ - {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ - - /* SCC3 */ - {CPM_PORTA, 10, CPM_PIN_INPUT}, - {CPM_PORTA, 11, CPM_PIN_INPUT}, - {CPM_PORTA, 3, CPM_PIN_INPUT}, - {CPM_PORTA, 2, CPM_PIN_INPUT}, - {CPM_PORTC, 13, CPM_PIN_INPUT}, -}; - -static void __init init_ioports(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mgsuvd_pins); i++) { - struct cpm_pin *pin = &mgsuvd_pins[i]; - cpm1_set_pin(pin->port, pin->pin, pin->flags); - } - - setbits16(&mpc8xx_immr->im_ioport.iop_pcso, 0x300); - cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_RX); - cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK6, CPM_CLK_TX); - cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); -} - -static void __init mgsuvd_setup_arch(void) -{ - cpm_reset(); - init_ioports(); -} - -static __initdata struct of_device_id of_bus_ids[] = { - { .compatible = "simple-bus" }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - return 0; -} -machine_device_initcall(mgsuvd, declare_of_platform_devices); - -static int __init mgsuvd_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "keymile,mgsuvd"); -} - -define_machine(mgsuvd) { - .name = "MGSUVD", - .probe = mgsuvd_probe, - .setup_arch = mgsuvd_setup_arch, - .init_IRQ = mpc8xx_pics_init, - .get_irq = mpc8xx_get_irq, - .restart = mpc8xx_restart, - .calibrate_decr = mpc8xx_calibrate_decr, - .set_rtc_time = mpc8xx_set_rtc_time, - .get_rtc_time = mpc8xx_get_rtc_time, -}; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index e3e379c..c07930f 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -93,6 +93,7 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val) static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); struct axon_msic *msic = get_irq_data(irq); u32 write_offset, msi; int idx; @@ -145,7 +146,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) msic->read_offset &= MSIC_FIFO_SIZE_MASK; } - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } static struct axon_msic *find_msi_translator(struct pci_dev *dev) diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 682af97..0b8f7d7 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -61,59 +61,59 @@ static inline void beatic_update_irq_mask(unsigned int irq_plug) panic("Failed to set mask IRQ!"); } -static void beatic_mask_irq(unsigned int irq_plug) +static void beatic_mask_irq(struct irq_data *d) { unsigned long flags; raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags); - beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64))); - beatic_update_irq_mask(irq_plug); + beatic_irq_mask_enable[d->irq/64] &= ~(1UL << (63 - (d->irq%64))); + beatic_update_irq_mask(d->irq); raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); } -static void beatic_unmask_irq(unsigned int irq_plug) +static void beatic_unmask_irq(struct irq_data *d) { unsigned long flags; raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags); - beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); - beatic_update_irq_mask(irq_plug); + beatic_irq_mask_enable[d->irq/64] |= 1UL << (63 - (d->irq%64)); + beatic_update_irq_mask(d->irq); raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); } -static void beatic_ack_irq(unsigned int irq_plug) +static void beatic_ack_irq(struct irq_data *d) { unsigned long flags; raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags); - beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64))); - beatic_update_irq_mask(irq_plug); + beatic_irq_mask_ack[d->irq/64] &= ~(1UL << (63 - (d->irq%64))); + beatic_update_irq_mask(d->irq); raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); } -static void beatic_end_irq(unsigned int irq_plug) +static void beatic_end_irq(struct irq_data *d) { s64 err; unsigned long flags; - err = beat_downcount_of_interrupt(irq_plug); + err = beat_downcount_of_interrupt(d->irq); if (err != 0) { if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */ panic("Failed to downcount IRQ! Error = %16llx", err); - printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug); + printk(KERN_ERR "IRQ over-downcounted, plug %d\n", d->irq); } raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags); - beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); - beatic_update_irq_mask(irq_plug); + beatic_irq_mask_ack[d->irq/64] |= 1UL << (63 - (d->irq%64)); + beatic_update_irq_mask(d->irq); raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); } static struct irq_chip beatic_pic = { .name = "CELL-BEAT", - .unmask = beatic_unmask_irq, - .mask = beatic_mask_irq, - .eoi = beatic_end_irq, + .irq_unmask = beatic_unmask_irq, + .irq_mask = beatic_mask_irq, + .irq_eoi = beatic_end_irq, }; /* @@ -232,7 +232,7 @@ unsigned int beatic_get_irq(void) ret = beatic_get_irq_plug(); if (ret != NO_IRQ) - beatic_ack_irq(ret); + beatic_ack_irq(irq_get_irq_data(ret)); return ret; } diff --git a/arch/powerpc/platforms/cell/cpufreq_spudemand.c b/arch/powerpc/platforms/cell/cpufreq_spudemand.c index 968c1c0..d809836 100644 --- a/arch/powerpc/platforms/cell/cpufreq_spudemand.c +++ b/arch/powerpc/platforms/cell/cpufreq_spudemand.c @@ -39,8 +39,6 @@ struct spu_gov_info_struct { }; static DEFINE_PER_CPU(struct spu_gov_info_struct, spu_gov_info); -static struct workqueue_struct *kspugov_wq; - static int calc_freq(struct spu_gov_info_struct *info) { int cpu; @@ -71,14 +69,14 @@ static void spu_gov_work(struct work_struct *work) __cpufreq_driver_target(info->policy, target_freq, CPUFREQ_RELATION_H); delay = usecs_to_jiffies(info->poll_int); - queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay); + schedule_delayed_work_on(info->policy->cpu, &info->work, delay); } static void spu_gov_init_work(struct spu_gov_info_struct *info) { int delay = usecs_to_jiffies(info->poll_int); INIT_DELAYED_WORK_DEFERRABLE(&info->work, spu_gov_work); - queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay); + schedule_delayed_work_on(info->policy->cpu, &info->work, delay); } static void spu_gov_cancel_work(struct spu_gov_info_struct *info) @@ -152,27 +150,15 @@ static int __init spu_gov_init(void) { int ret; - kspugov_wq = create_workqueue("kspugov"); - if (!kspugov_wq) { - printk(KERN_ERR "creation of kspugov failed\n"); - ret = -EFAULT; - goto out; - } - ret = cpufreq_register_governor(&spu_governor); - if (ret) { + if (ret) printk(KERN_ERR "registration of governor failed\n"); - destroy_workqueue(kspugov_wq); - goto out; - } -out: return ret; } static void __exit spu_gov_exit(void) { cpufreq_unregister_governor(&spu_governor); - destroy_workqueue(kspugov_wq); } diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 10eb1a4..624d26e 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -72,15 +72,15 @@ static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit; } -static void iic_mask(unsigned int irq) +static void iic_mask(struct irq_data *d) { } -static void iic_unmask(unsigned int irq) +static void iic_unmask(struct irq_data *d) { } -static void iic_eoi(unsigned int irq) +static void iic_eoi(struct irq_data *d) { struct iic *iic = &__get_cpu_var(cpu_iic); out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]); @@ -89,19 +89,21 @@ static void iic_eoi(unsigned int irq) static struct irq_chip iic_chip = { .name = "CELL-IIC", - .mask = iic_mask, - .unmask = iic_unmask, - .eoi = iic_eoi, + .irq_mask = iic_mask, + .irq_unmask = iic_unmask, + .irq_eoi = iic_eoi, }; -static void iic_ioexc_eoi(unsigned int irq) +static void iic_ioexc_eoi(struct irq_data *d) { } static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc) { - struct cbe_iic_regs __iomem *node_iic = (void __iomem *)desc->handler_data; + struct irq_chip *chip = get_irq_desc_chip(desc); + struct cbe_iic_regs __iomem *node_iic = + (void __iomem *)get_irq_desc_data(desc); unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC; unsigned long bits, ack; int cascade; @@ -128,15 +130,15 @@ static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc) if (ack) out_be64(&node_iic->iic_is, ack); } - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); } static struct irq_chip iic_ioexc_chip = { .name = "CELL-IOEX", - .mask = iic_mask, - .unmask = iic_unmask, - .eoi = iic_ioexc_eoi, + .irq_mask = iic_mask, + .irq_unmask = iic_unmask, + .irq_eoi = iic_ioexc_eoi, }; /* Get an IRQ number from the pending state register of the IIC */ @@ -237,6 +239,8 @@ extern int noirqdebug; static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); + raw_spin_lock(&desc->lock); desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); @@ -275,7 +279,7 @@ static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) desc->status &= ~IRQ_INPROGRESS; out_eoi: - desc->chip->eoi(irq); + chip->irq_eoi(&desc->irq_data); raw_spin_unlock(&desc->lock); } diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c index 1b57490..d31c594 100644 --- a/arch/powerpc/platforms/cell/qpace_setup.c +++ b/arch/powerpc/platforms/cell/qpace_setup.c @@ -145,9 +145,4 @@ define_machine(qpace) { .calibrate_decr = generic_calibrate_decr, .progress = qpace_progress, .init_IRQ = iic_init_IRQ, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 6919957..6a28d02 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -187,13 +187,15 @@ machine_subsys_initcall(cell, cell_publish_devices); static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc) { - struct mpic *mpic = desc->handler_data; + struct irq_chip *chip = get_irq_desc_chip(desc); + struct mpic *mpic = get_irq_desc_data(desc); unsigned int virq; virq = mpic_get_one_irq(mpic); if (virq != NO_IRQ) generic_handle_irq(virq); - desc->chip->eoi(irq); + + chip->irq_eoi(&desc->irq_data); } static void __init mpic_init_IRQ(void) diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 3f2e557..b38cdfc 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -79,30 +79,30 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic, return pic->regs + TIR_CFGA + 8 * src; } -static void spider_unmask_irq(unsigned int virq) +static void spider_unmask_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(virq); - void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq); + struct spider_pic *pic = spider_virq_to_pic(d->irq); + void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq); out_be32(cfg, in_be32(cfg) | 0x30000000u); } -static void spider_mask_irq(unsigned int virq) +static void spider_mask_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(virq); - void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq); + struct spider_pic *pic = spider_virq_to_pic(d->irq); + void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq); out_be32(cfg, in_be32(cfg) & ~0x30000000u); } -static void spider_ack_irq(unsigned int virq) +static void spider_ack_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(virq); - unsigned int src = irq_map[virq].hwirq; + struct spider_pic *pic = spider_virq_to_pic(d->irq); + unsigned int src = irq_map[d->irq].hwirq; /* Reset edge detection logic if necessary */ - if (irq_to_desc(virq)->status & IRQ_LEVEL) + if (irq_to_desc(d->irq)->status & IRQ_LEVEL) return; /* Only interrupts 47 to 50 can be set to edge */ @@ -113,13 +113,13 @@ static void spider_ack_irq(unsigned int virq) out_be32(pic->regs + TIR_EDC, 0x100 | (src & 0xf)); } -static int spider_set_irq_type(unsigned int virq, unsigned int type) +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(virq); - unsigned int hw = irq_map[virq].hwirq; + struct spider_pic *pic = spider_virq_to_pic(d->irq); + unsigned int hw = irq_map[d->irq].hwirq; void __iomem *cfg = spider_get_irq_config(pic, hw); - struct irq_desc *desc = irq_to_desc(virq); + struct irq_desc *desc = irq_to_desc(d->irq); u32 old_mask; u32 ic; @@ -169,10 +169,10 @@ static int spider_set_irq_type(unsigned int virq, unsigned int type) static struct irq_chip spider_pic = { .name = "SPIDER", - .unmask = spider_unmask_irq, - .mask = spider_mask_irq, - .ack = spider_ack_irq, - .set_type = spider_set_irq_type, + .irq_unmask = spider_unmask_irq, + .irq_mask = spider_mask_irq, + .irq_ack = spider_ack_irq, + .irq_set_type = spider_set_irq_type, }; static int spider_host_map(struct irq_host *h, unsigned int virq, @@ -207,7 +207,8 @@ static struct irq_host_ops spider_host_ops = { static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc) { - struct spider_pic *pic = desc->handler_data; + struct irq_chip *chip = get_irq_desc_chip(desc); + struct spider_pic *pic = get_irq_desc_data(desc); unsigned int cs, virq; cs = in_be32(pic->regs + TIR_CS) >> 24; @@ -215,9 +216,11 @@ static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc) virq = NO_IRQ; else virq = irq_linear_revmap(pic->host, cs); + if (virq != NO_IRQ) generic_handle_irq(virq); - desc->chip->eoi(irq); + + chip->irq_eoi(&desc->irq_data); } /* For hooking up the cascace we have a problem. Our device-tree is diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 8547e86..acfacce 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -37,6 +37,7 @@ #include <asm/spu_csa.h> #include <asm/xmon.h> #include <asm/prom.h> +#include <asm/kexec.h> const struct spu_management_ops *spu_management_ops; EXPORT_SYMBOL_GPL(spu_management_ops); @@ -727,6 +728,75 @@ static ssize_t spu_stat_show(struct sys_device *sysdev, static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL); +#ifdef CONFIG_KEXEC + +struct crash_spu_info { + struct spu *spu; + u32 saved_spu_runcntl_RW; + u32 saved_spu_status_R; + u32 saved_spu_npc_RW; + u64 saved_mfc_sr1_RW; + u64 saved_mfc_dar; + u64 saved_mfc_dsisr; +}; + +#define CRASH_NUM_SPUS 16 /* Enough for current hardware */ +static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS]; + +static void crash_kexec_stop_spus(void) +{ + struct spu *spu; + int i; + u64 tmp; + + for (i = 0; i < CRASH_NUM_SPUS; i++) { + if (!crash_spu_info[i].spu) + continue; + + spu = crash_spu_info[i].spu; + + crash_spu_info[i].saved_spu_runcntl_RW = + in_be32(&spu->problem->spu_runcntl_RW); + crash_spu_info[i].saved_spu_status_R = + in_be32(&spu->problem->spu_status_R); + crash_spu_info[i].saved_spu_npc_RW = + in_be32(&spu->problem->spu_npc_RW); + + crash_spu_info[i].saved_mfc_dar = spu_mfc_dar_get(spu); + crash_spu_info[i].saved_mfc_dsisr = spu_mfc_dsisr_get(spu); + tmp = spu_mfc_sr1_get(spu); + crash_spu_info[i].saved_mfc_sr1_RW = tmp; + + tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK; + spu_mfc_sr1_set(spu, tmp); + + __delay(200); + } +} + +static void crash_register_spus(struct list_head *list) +{ + struct spu *spu; + int ret; + + list_for_each_entry(spu, list, full_list) { + if (WARN_ON(spu->number >= CRASH_NUM_SPUS)) + continue; + + crash_spu_info[spu->number].spu = spu; + } + + ret = crash_shutdown_register(&crash_kexec_stop_spus); + if (ret) + printk(KERN_ERR "Could not register SPU crash handler"); +} + +#else +static inline void crash_register_spus(struct list_head *list) +{ +} +#endif + static int __init init_spu_base(void) { int i, ret = 0; diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 02f7b11..3c7c3f8 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -219,24 +219,17 @@ spufs_mem_write(struct file *file, const char __user *buffer, loff_t pos = *ppos; int ret; - if (pos < 0) - return -EINVAL; if (pos > LS_SIZE) return -EFBIG; - if (size > LS_SIZE - pos) - size = LS_SIZE - pos; ret = spu_acquire(ctx); if (ret) return ret; local_store = ctx->ops->get_ls(ctx); - ret = copy_from_user(local_store + pos, buffer, size); + size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size); spu_release(ctx); - if (ret) - return -EFAULT; - *ppos = pos + size; return size; } @@ -574,18 +567,15 @@ spufs_regs_write(struct file *file, const char __user *buffer, if (*pos >= sizeof(lscsa->gprs)) return -EFBIG; - size = min_t(ssize_t, sizeof(lscsa->gprs) - *pos, size); - *pos += size; - ret = spu_acquire_saved(ctx); if (ret) return ret; - ret = copy_from_user((char *)lscsa->gprs + *pos - size, - buffer, size) ? -EFAULT : size; + size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos, + buffer, size); spu_release_saved(ctx); - return ret; + return size; } static const struct file_operations spufs_regs_fops = { @@ -630,18 +620,15 @@ spufs_fpcr_write(struct file *file, const char __user * buffer, if (*pos >= sizeof(lscsa->fpcr)) return -EFBIG; - size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); - ret = spu_acquire_saved(ctx); if (ret) return ret; - *pos += size; - ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, - buffer, size) ? -EFAULT : size; + size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos, + buffer, size); spu_release_saved(ctx); - return ret; + return size; } static const struct file_operations spufs_fpcr_fops = { diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 3532b92..856e9c3 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -71,12 +71,18 @@ spufs_alloc_inode(struct super_block *sb) return &ei->vfs_inode; } -static void -spufs_destroy_inode(struct inode *inode) +static void spufs_i_callback(struct rcu_head *head) { + struct inode *inode = container_of(head, struct inode, i_rcu); + INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(spufs_inode_cache, SPUFS_I(inode)); } +static void spufs_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, spufs_i_callback); +} + static void spufs_init_once(void *p) { @@ -159,18 +165,18 @@ static void spufs_prune_dir(struct dentry *dir) mutex_lock(&dir->d_inode->i_mutex); list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { - spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (!(d_unhashed(dentry)) && dentry->d_inode) { - dget_locked(dentry); + dget_dlock(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); simple_unlink(dir->d_inode, dentry); - spin_unlock(&dcache_lock); + /* XXX: what was dcache_lock protecting here? Other + * filesystems (IB, configfs) release dcache_lock + * before unlink */ dput(dentry); } else { spin_unlock(&dentry->d_lock); - spin_unlock(&dcache_lock); } } shrink_dcache_parent(dir); diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 8553cc4..4c12884 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -365,10 +365,13 @@ void __init chrp_setup_arch(void) static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); unsigned int cascade_irq = i8259_irq(); + if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + + chip->irq_eoi(&desc->irq_data); } /* diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index c278bd3..0aca0e2 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -46,10 +46,10 @@ * */ -static void flipper_pic_mask_and_ack(unsigned int virq) +static void flipper_pic_mask_and_ack(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); u32 mask = 1 << irq; clrbits32(io_base + FLIPPER_IMR, mask); @@ -57,27 +57,27 @@ static void flipper_pic_mask_and_ack(unsigned int virq) out_be32(io_base + FLIPPER_ICR, mask); } -static void flipper_pic_ack(unsigned int virq) +static void flipper_pic_ack(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); /* this is at least needed for RSW */ out_be32(io_base + FLIPPER_ICR, 1 << irq); } -static void flipper_pic_mask(unsigned int virq) +static void flipper_pic_mask(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); clrbits32(io_base + FLIPPER_IMR, 1 << irq); } -static void flipper_pic_unmask(unsigned int virq) +static void flipper_pic_unmask(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + FLIPPER_IMR, 1 << irq); } @@ -85,10 +85,10 @@ static void flipper_pic_unmask(unsigned int virq) static struct irq_chip flipper_pic = { .name = "flipper-pic", - .ack = flipper_pic_ack, - .mask_ack = flipper_pic_mask_and_ack, - .mask = flipper_pic_mask, - .unmask = flipper_pic_unmask, + .irq_ack = flipper_pic_ack, + .irq_mask_ack = flipper_pic_mask_and_ack, + .irq_mask = flipper_pic_mask, + .irq_unmask = flipper_pic_unmask, }; /* diff --git a/arch/powerpc/platforms/embedded6xx/gamecube.c b/arch/powerpc/platforms/embedded6xx/gamecube.c index 1106fd9..a138e14 100644 --- a/arch/powerpc/platforms/embedded6xx/gamecube.c +++ b/arch/powerpc/platforms/embedded6xx/gamecube.c @@ -75,14 +75,6 @@ static void gamecube_shutdown(void) flipper_quiesce(); } -#ifdef CONFIG_KEXEC -static int gamecube_kexec_prepare(struct kimage *image) -{ - return 0; -} -#endif /* CONFIG_KEXEC */ - - define_machine(gamecube) { .name = "gamecube", .probe = gamecube_probe, @@ -95,9 +87,6 @@ define_machine(gamecube) { .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, .machine_shutdown = gamecube_shutdown, -#ifdef CONFIG_KEXEC - .machine_kexec_prepare = gamecube_kexec_prepare, -#endif }; diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index a771f91..35e448b 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -41,36 +41,36 @@ * */ -static void hlwd_pic_mask_and_ack(unsigned int virq) +static void hlwd_pic_mask_and_ack(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); u32 mask = 1 << irq; clrbits32(io_base + HW_BROADWAY_IMR, mask); out_be32(io_base + HW_BROADWAY_ICR, mask); } -static void hlwd_pic_ack(unsigned int virq) +static void hlwd_pic_ack(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); out_be32(io_base + HW_BROADWAY_ICR, 1 << irq); } -static void hlwd_pic_mask(unsigned int virq) +static void hlwd_pic_mask(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq); } -static void hlwd_pic_unmask(unsigned int virq) +static void hlwd_pic_unmask(struct irq_data *d) { - int irq = virq_to_hw(virq); - void __iomem *io_base = get_irq_chip_data(virq); + int irq = virq_to_hw(d->irq); + void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); } @@ -78,10 +78,10 @@ static void hlwd_pic_unmask(unsigned int virq) static struct irq_chip hlwd_pic = { .name = "hlwd-pic", - .ack = hlwd_pic_ack, - .mask_ack = hlwd_pic_mask_and_ack, - .mask = hlwd_pic_mask, - .unmask = hlwd_pic_unmask, + .irq_ack = hlwd_pic_ack, + .irq_mask_ack = hlwd_pic_mask_and_ack, + .irq_mask = hlwd_pic_mask, + .irq_unmask = hlwd_pic_unmask, }; /* @@ -129,11 +129,12 @@ static unsigned int __hlwd_pic_get_irq(struct irq_host *h) static void hlwd_pic_irq_cascade(unsigned int cascade_virq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); struct irq_host *irq_host = get_irq_data(cascade_virq); unsigned int virq; raw_spin_lock(&desc->lock); - desc->chip->mask(cascade_virq); /* IRQ_LEVEL */ + chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */ raw_spin_unlock(&desc->lock); virq = __hlwd_pic_get_irq(irq_host); @@ -143,9 +144,9 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq, pr_err("spurious interrupt!\n"); raw_spin_lock(&desc->lock); - desc->chip->ack(cascade_virq); /* IRQ_LEVEL */ - if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) - desc->chip->unmask(cascade_virq); + chip->irq_ack(&desc->irq_data); /* IRQ_LEVEL */ + if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask) + chip->irq_unmask(&desc->irq_data); raw_spin_unlock(&desc->lock); } diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c index 649473a..1b5dc1a 100644 --- a/arch/powerpc/platforms/embedded6xx/wii.c +++ b/arch/powerpc/platforms/embedded6xx/wii.c @@ -18,7 +18,6 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/seq_file.h> -#include <linux/kexec.h> #include <linux/of_platform.h> #include <linux/memblock.h> #include <mm/mmu_decl.h> @@ -226,13 +225,6 @@ static void wii_shutdown(void) flipper_quiesce(); } -#ifdef CONFIG_KEXEC -static int wii_machine_kexec_prepare(struct kimage *image) -{ - return 0; -} -#endif /* CONFIG_KEXEC */ - define_machine(wii) { .name = "wii", .probe = wii_probe, @@ -246,9 +238,6 @@ define_machine(wii) { .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, .machine_shutdown = wii_shutdown, -#ifdef CONFIG_KEXEC - .machine_kexec_prepare = wii_machine_kexec_prepare, -#endif }; static struct of_device_id wii_of_bus[] = { diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index 47a20cf..e5bc9f7 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -2,7 +2,7 @@ config PPC_ISERIES bool "IBM Legacy iSeries" depends on PPC64 && PPC_BOOK3S select PPC_INDIRECT_IO - select PPC_PCI_CHOICE if EMBEDDED + select PPC_PCI_CHOICE if EXPERT menu "iSeries device drivers" depends on PPC_ISERIES diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index ba446bf..4fb96f0 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -167,11 +167,11 @@ static void pci_event_handler(struct HvLpEvent *event) * This will be called by device drivers (via enable_IRQ) * to enable INTA in the bridge interrupt status register. */ -static void iseries_enable_IRQ(unsigned int irq) +static void iseries_enable_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[irq].hwirq; + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -184,23 +184,23 @@ static void iseries_enable_IRQ(unsigned int irq) } /* This is called by iseries_activate_IRQs */ -static unsigned int iseries_startup_IRQ(unsigned int irq) +static unsigned int iseries_startup_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[irq].hwirq; + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; bus = REAL_IRQ_TO_BUS(rirq); function = REAL_IRQ_TO_FUNC(rirq); dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; /* Link the IRQ number to the bridge */ - HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq); + HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq); /* Unmask bridge interrupts in the FISR */ mask = 0x01010000 << function; HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask); - iseries_enable_IRQ(irq); + iseries_enable_IRQ(d); return 0; } @@ -215,21 +215,26 @@ void __init iSeries_activate_IRQs() for_each_irq (irq) { struct irq_desc *desc = irq_to_desc(irq); + struct irq_chip *chip; - if (desc && desc->chip && desc->chip->startup) { + if (!desc) + continue; + + chip = get_irq_desc_chip(desc); + if (chip && chip->irq_startup) { raw_spin_lock_irqsave(&desc->lock, flags); - desc->chip->startup(irq); + chip->irq_startup(&desc->irq_data); raw_spin_unlock_irqrestore(&desc->lock, flags); } } } /* this is not called anywhere currently */ -static void iseries_shutdown_IRQ(unsigned int irq) +static void iseries_shutdown_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[irq].hwirq; + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; /* irq should be locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -248,11 +253,11 @@ static void iseries_shutdown_IRQ(unsigned int irq) * This will be called by device drivers (via disable_IRQ) * to disable INTA in the bridge interrupt status register. */ -static void iseries_disable_IRQ(unsigned int irq) +static void iseries_disable_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[irq].hwirq; + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -264,9 +269,9 @@ static void iseries_disable_IRQ(unsigned int irq) HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); } -static void iseries_end_IRQ(unsigned int irq) +static void iseries_end_IRQ(struct irq_data *d) { - unsigned int rirq = (unsigned int)irq_map[irq].hwirq; + unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); @@ -274,11 +279,11 @@ static void iseries_end_IRQ(unsigned int irq) static struct irq_chip iseries_pic = { .name = "iSeries", - .startup = iseries_startup_IRQ, - .shutdown = iseries_shutdown_IRQ, - .unmask = iseries_enable_IRQ, - .mask = iseries_disable_IRQ, - .eoi = iseries_end_IRQ + .irq_startup = iseries_startup_IRQ, + .irq_shutdown = iseries_shutdown_IRQ, + .irq_unmask = iseries_enable_IRQ, + .irq_mask = iseries_disable_IRQ, + .irq_eoi = iseries_end_IRQ }; /* diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index f372ec1..a6067b3 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -240,7 +240,7 @@ static __init void pas_init_IRQ(void) nmi_virq = irq_create_mapping(NULL, *nmiprop); mpic_irq_set_priority(nmi_virq, 15); set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING); - mpic_unmask_irq(nmi_virq); + mpic_unmask_irq(irq_get_irq_data(nmi_virq)); } of_node_put(mpic_node); @@ -266,7 +266,7 @@ static int pas_machine_check_handler(struct pt_regs *regs) if (nmi_virq != NO_IRQ && mpic_get_mcirq() == nmi_virq) { printk(KERN_ERR "NMI delivered\n"); debugger(regs); - mpic_end_irq(nmi_virq); + mpic_end_irq(irq_get_irq_data(nmi_virq)); goto out; } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 890d5f7..c55812b 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -82,9 +82,9 @@ static void __pmac_retrigger(unsigned int irq_nr) } } -static void pmac_mask_and_ack_irq(unsigned int virq) +static void pmac_mask_and_ack_irq(struct irq_data *d) { - unsigned int src = irq_map[virq].hwirq; + unsigned int src = irq_map[d->irq].hwirq; unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; unsigned long flags; @@ -104,9 +104,9 @@ static void pmac_mask_and_ack_irq(unsigned int virq) raw_spin_unlock_irqrestore(&pmac_pic_lock, flags); } -static void pmac_ack_irq(unsigned int virq) +static void pmac_ack_irq(struct irq_data *d) { - unsigned int src = irq_map[virq].hwirq; + unsigned int src = irq_map[d->irq].hwirq; unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; unsigned long flags; @@ -149,15 +149,15 @@ static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) /* When an irq gets requested for the first client, if it's an * edge interrupt, we clear any previous one on the controller */ -static unsigned int pmac_startup_irq(unsigned int virq) +static unsigned int pmac_startup_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[virq].hwirq; + unsigned int src = irq_map[d->irq].hwirq; unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; raw_spin_lock_irqsave(&pmac_pic_lock, flags); - if ((irq_to_desc(virq)->status & IRQ_LEVEL) == 0) + if ((irq_to_desc(d->irq)->status & IRQ_LEVEL) == 0) out_le32(&pmac_irq_hw[i]->ack, bit); __set_bit(src, ppc_cached_irq_mask); __pmac_set_irq_mask(src, 0); @@ -166,10 +166,10 @@ static unsigned int pmac_startup_irq(unsigned int virq) return 0; } -static void pmac_mask_irq(unsigned int virq) +static void pmac_mask_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[virq].hwirq; + unsigned int src = irq_map[d->irq].hwirq; raw_spin_lock_irqsave(&pmac_pic_lock, flags); __clear_bit(src, ppc_cached_irq_mask); @@ -177,10 +177,10 @@ static void pmac_mask_irq(unsigned int virq) raw_spin_unlock_irqrestore(&pmac_pic_lock, flags); } -static void pmac_unmask_irq(unsigned int virq) +static void pmac_unmask_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[virq].hwirq; + unsigned int src = irq_map[d->irq].hwirq; raw_spin_lock_irqsave(&pmac_pic_lock, flags); __set_bit(src, ppc_cached_irq_mask); @@ -188,24 +188,24 @@ static void pmac_unmask_irq(unsigned int virq) raw_spin_unlock_irqrestore(&pmac_pic_lock, flags); } -static int pmac_retrigger(unsigned int virq) +static int pmac_retrigger(struct irq_data *d) { unsigned long flags; raw_spin_lock_irqsave(&pmac_pic_lock, flags); - __pmac_retrigger(irq_map[virq].hwirq); + __pmac_retrigger(irq_map[d->irq].hwirq); raw_spin_unlock_irqrestore(&pmac_pic_lock, flags); return 1; } static struct irq_chip pmac_pic = { .name = "PMAC-PIC", - .startup = pmac_startup_irq, - .mask = pmac_mask_irq, - .ack = pmac_ack_irq, - .mask_ack = pmac_mask_and_ack_irq, - .unmask = pmac_unmask_irq, - .retrigger = pmac_retrigger, + .irq_startup = pmac_startup_irq, + .irq_mask = pmac_mask_irq, + .irq_ack = pmac_ack_irq, + .irq_mask_ack = pmac_mask_and_ack_irq, + .irq_unmask = pmac_unmask_irq, + .irq_retrigger = pmac_retrigger, }; static irqreturn_t gatwick_action(int cpl, void *dev_id) @@ -472,12 +472,14 @@ int of_irq_map_oldworld(struct device_node *device, int index, static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc) { - struct mpic *mpic = desc->handler_data; - + struct irq_chip *chip = get_irq_desc_chip(desc); + struct mpic *mpic = get_irq_desc_data(desc); unsigned int cascade_irq = mpic_get_one_irq(mpic); + if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + + chip->irq_eoi(&desc->irq_data); } static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) @@ -707,7 +709,7 @@ static int pmacpic_resume(struct sys_device *sysdev) mb(); for (i = 0; i < max_real_irqs; ++i) if (test_bit(i, sleep_save_mask)) - pmac_unmask_irq(i); + pmac_unmask_irq(irq_get_irq_data(i)); return 0; } diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index b341018..6c4b583 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -566,10 +566,10 @@ static int ps3_setup_dynamic_device(const struct ps3_repository_device *repo) case PS3_DEV_TYPE_STOR_DISK: result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK); - /* Some devices are not accessable from the Other OS lpar. */ + /* Some devices are not accessible from the Other OS lpar. */ if (result == -ENODEV) { result = 0; - pr_debug("%s:%u: not accessable\n", __func__, + pr_debug("%s:%u: not accessible\n", __func__, __LINE__); } diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 59d9712..3988c86 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -44,7 +44,7 @@ * @lock: * @ipi_debug_brk_mask: * - * The HV mantains per SMT thread mappings of HV outlet to HV plug on + * The HV maintains per SMT thread mappings of HV outlet to HV plug on * behalf of the guest. These mappings are implemented as 256 bit guest * supplied bitmaps indexed by plug number. The addresses of the bitmaps * are registered with the HV through lv1_configure_irq_state_bitmap(). @@ -99,16 +99,16 @@ static DEFINE_PER_CPU(struct ps3_private, ps3_private); * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). */ -static void ps3_chip_mask(unsigned int virq) +static void ps3_chip_mask(struct irq_data *d) { - struct ps3_private *pd = get_irq_chip_data(virq); + struct ps3_private *pd = irq_data_get_irq_chip_data(d); unsigned long flags; pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, - pd->thread_id, virq); + pd->thread_id, d->irq); local_irq_save(flags); - clear_bit(63 - virq, &pd->bmp.mask); + clear_bit(63 - d->irq, &pd->bmp.mask); lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); local_irq_restore(flags); } @@ -120,16 +120,16 @@ static void ps3_chip_mask(unsigned int virq) * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). */ -static void ps3_chip_unmask(unsigned int virq) +static void ps3_chip_unmask(struct irq_data *d) { - struct ps3_private *pd = get_irq_chip_data(virq); + struct ps3_private *pd = irq_data_get_irq_chip_data(d); unsigned long flags; pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, - pd->thread_id, virq); + pd->thread_id, d->irq); local_irq_save(flags); - set_bit(63 - virq, &pd->bmp.mask); + set_bit(63 - d->irq, &pd->bmp.mask); lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); local_irq_restore(flags); } @@ -141,10 +141,10 @@ static void ps3_chip_unmask(unsigned int virq) * Calls lv1_end_of_interrupt_ext(). */ -static void ps3_chip_eoi(unsigned int virq) +static void ps3_chip_eoi(struct irq_data *d) { - const struct ps3_private *pd = get_irq_chip_data(virq); - lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq); + const struct ps3_private *pd = irq_data_get_irq_chip_data(d); + lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq); } /** @@ -153,9 +153,9 @@ static void ps3_chip_eoi(unsigned int virq) static struct irq_chip ps3_irq_chip = { .name = "ps3", - .mask = ps3_chip_mask, - .unmask = ps3_chip_unmask, - .eoi = ps3_chip_eoi, + .irq_mask = ps3_chip_mask, + .irq_unmask = ps3_chip_unmask, + .irq_eoi = ps3_chip_eoi, }; /** @@ -202,7 +202,7 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, goto fail_set; } - ps3_chip_mask(*virq); + ps3_chip_mask(irq_get_irq_data(*virq)); return result; @@ -296,7 +296,7 @@ int ps3_irq_plug_destroy(unsigned int virq) pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, __LINE__, pd->ppe_id, pd->thread_id, virq); - ps3_chip_mask(virq); + ps3_chip_mask(irq_get_irq_data(virq)); result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq); @@ -357,7 +357,7 @@ int ps3_event_receive_port_destroy(unsigned int virq) pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq); - ps3_chip_mask(virq); + ps3_chip_mask(irq_get_irq_data(virq)); result = lv1_destruct_event_receive_port(virq_to_hw(virq)); @@ -492,7 +492,7 @@ int ps3_io_irq_destroy(unsigned int virq) int result; unsigned long outlet = virq_to_hw(virq); - ps3_chip_mask(virq); + ps3_chip_mask(irq_get_irq_data(virq)); /* * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, @@ -553,7 +553,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) { int result; - ps3_chip_mask(virq); + ps3_chip_mask(irq_get_irq_data(virq)); result = lv1_deconfigure_virtual_uart_irq(); if (result) { @@ -605,7 +605,7 @@ int ps3_spe_irq_destroy(unsigned int virq) { int result; - ps3_chip_mask(virq); + ps3_chip_mask(irq_get_irq_data(virq)); result = ps3_irq_plug_destroy(virq); BUG_ON(result); diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 5d1b743..5b3da4b 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -10,7 +10,7 @@ config PPC_PSERIES select RTAS_ERROR_LOGGING select PPC_UDBG_16550 select PPC_NATIVE - select PPC_PCI_CHOICE if EMBEDDED + select PPC_PCI_CHOICE if EXPERT default y config PPC_SPLPAR @@ -24,9 +24,9 @@ config PPC_SPLPAR two or more partitions. config EEH - bool "PCI Extended Error Handling (EEH)" if EMBEDDED + bool "PCI Extended Error Handling (EEH)" if EXPERT depends on PPC_PSERIES && PCI - default y if !EMBEDDED + default y if !EXPERT config PSERIES_MSI bool diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index f480386..3cafc30 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -508,12 +508,7 @@ static int cmm_memory_isolate_cb(struct notifier_block *self, if (action == MEM_ISOLATE_COUNT) ret = cmm_count_pages(arg); - if (ret) - ret = notifier_from_errno(ret); - else - ret = NOTIFY_OK; - - return ret; + return notifier_from_errno(ret); } static struct notifier_block cmm_mem_isolate_nb = { @@ -635,12 +630,7 @@ static int cmm_memory_cb(struct notifier_block *self, break; } - if (ret) - ret = notifier_from_errno(ret); - else - ret = NOTIFY_OK; - - return ret; + return notifier_from_errno(ret); } static struct notifier_block cmm_mem_nb = { diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 17a11c8..3cc4d10 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -876,7 +876,7 @@ void eeh_restore_bars(struct pci_dn *pdn) * * Save the values of the device bars. Unlike the restore * routine, this routine is *not* recursive. This is because - * PCI devices are added individuallly; but, for the restore, + * PCI devices are added individually; but, for the restore, * an entire slot is reset at a time. */ static void eeh_save_bars(struct pci_dn *pdn) diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index 15e13b5..23982c7 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -25,7 +25,6 @@ #include <linux/pci.h> #include <asm/ppc-pci.h> #include <asm/pci-bridge.h> -#include <linux/kobject.h> /** * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index e19ff02..f106662 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -55,7 +55,7 @@ static void hc_stop(struct seq_file *m, void *p) static int hc_show(struct seq_file *m, void *p) { unsigned long h_num = (unsigned long)p; - struct hcall_stats *hs = (struct hcall_stats *)m->private; + struct hcall_stats *hs = m->private; if (hs[h_num].num_calls) { if (cpu_has_feature(CPU_FTR_PURR)) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index edea60b..154c464 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -33,6 +33,7 @@ #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/crash_dump.h> +#include <linux/memory.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/rtas.h> @@ -45,6 +46,7 @@ #include <asm/tce.h> #include <asm/ppc-pci.h> #include <asm/udbg.h> +#include <asm/mmzone.h> #include "plpar_wrappers.h" @@ -270,6 +272,152 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum) return tce_ret; } +/* this is compatable with cells for the device tree property */ +struct dynamic_dma_window_prop { + __be32 liobn; /* tce table number */ + __be64 dma_base; /* address hi,lo */ + __be32 tce_shift; /* ilog2(tce_page_size) */ + __be32 window_shift; /* ilog2(tce_window_size) */ +}; + +struct direct_window { + struct device_node *device; + const struct dynamic_dma_window_prop *prop; + struct list_head list; +}; + +/* Dynamic DMA Window support */ +struct ddw_query_response { + u32 windows_available; + u32 largest_available_block; + u32 page_size; + u32 migration_capable; +}; + +struct ddw_create_response { + u32 liobn; + u32 addr_hi; + u32 addr_lo; +}; + +static LIST_HEAD(direct_window_list); +/* prevents races between memory on/offline and window creation */ +static DEFINE_SPINLOCK(direct_window_list_lock); +/* protects initializing window twice for same device */ +static DEFINE_MUTEX(direct_window_init_mutex); +#define DIRECT64_PROPNAME "linux,direct64-ddr-window-info" + +static int tce_clearrange_multi_pSeriesLP(unsigned long start_pfn, + unsigned long num_pfn, const void *arg) +{ + const struct dynamic_dma_window_prop *maprange = arg; + int rc; + u64 tce_size, num_tce, dma_offset, next; + u32 tce_shift; + long limit; + + tce_shift = be32_to_cpu(maprange->tce_shift); + tce_size = 1ULL << tce_shift; + next = start_pfn << PAGE_SHIFT; + num_tce = num_pfn << PAGE_SHIFT; + + /* round back to the beginning of the tce page size */ + num_tce += next & (tce_size - 1); + next &= ~(tce_size - 1); + + /* covert to number of tces */ + num_tce |= tce_size - 1; + num_tce >>= tce_shift; + + do { + /* + * Set up the page with TCE data, looping through and setting + * the values. + */ + limit = min_t(long, num_tce, 512); + dma_offset = next + be64_to_cpu(maprange->dma_base); + + rc = plpar_tce_stuff((u64)be32_to_cpu(maprange->liobn), + dma_offset, + 0, limit); + num_tce -= limit; + } while (num_tce > 0 && !rc); + + return rc; +} + +static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, + unsigned long num_pfn, const void *arg) +{ + const struct dynamic_dma_window_prop *maprange = arg; + u64 *tcep, tce_size, num_tce, dma_offset, next, proto_tce, liobn; + u32 tce_shift; + u64 rc = 0; + long l, limit; + + local_irq_disable(); /* to protect tcep and the page behind it */ + tcep = __get_cpu_var(tce_page); + + if (!tcep) { + tcep = (u64 *)__get_free_page(GFP_ATOMIC); + if (!tcep) { + local_irq_enable(); + return -ENOMEM; + } + __get_cpu_var(tce_page) = tcep; + } + + proto_tce = TCE_PCI_READ | TCE_PCI_WRITE; + + liobn = (u64)be32_to_cpu(maprange->liobn); + tce_shift = be32_to_cpu(maprange->tce_shift); + tce_size = 1ULL << tce_shift; + next = start_pfn << PAGE_SHIFT; + num_tce = num_pfn << PAGE_SHIFT; + + /* round back to the beginning of the tce page size */ + num_tce += next & (tce_size - 1); + next &= ~(tce_size - 1); + + /* covert to number of tces */ + num_tce |= tce_size - 1; + num_tce >>= tce_shift; + + /* We can map max one pageful of TCEs at a time */ + do { + /* + * Set up the page with TCE data, looping through and setting + * the values. + */ + limit = min_t(long, num_tce, 4096/TCE_ENTRY_SIZE); + dma_offset = next + be64_to_cpu(maprange->dma_base); + + for (l = 0; l < limit; l++) { + tcep[l] = proto_tce | next; + next += tce_size; + } + + rc = plpar_tce_put_indirect(liobn, + dma_offset, + (u64)virt_to_abs(tcep), + limit); + + num_tce -= limit; + } while (num_tce > 0 && !rc); + + /* error cleanup: caller will clear whole range */ + + local_irq_enable(); + return rc; +} + +static int tce_setrange_multi_pSeriesLP_walk(unsigned long start_pfn, + unsigned long num_pfn, void *arg) +{ + return tce_setrange_multi_pSeriesLP(start_pfn, num_pfn, arg); +} + + #ifdef CONFIG_PCI static void iommu_table_setparms(struct pci_controller *phb, struct device_node *dn, @@ -495,6 +643,329 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) pci_name(dev)); } +static int __read_mostly disable_ddw; + +static int __init disable_ddw_setup(char *str) +{ + disable_ddw = 1; + printk(KERN_INFO "ppc iommu: disabling ddw.\n"); + + return 0; +} + +early_param("disable_ddw", disable_ddw_setup); + +static void remove_ddw(struct device_node *np) +{ + struct dynamic_dma_window_prop *dwp; + struct property *win64; + const u32 *ddr_avail; + u64 liobn; + int len, ret; + + ddr_avail = of_get_property(np, "ibm,ddw-applicable", &len); + win64 = of_find_property(np, DIRECT64_PROPNAME, NULL); + if (!win64 || !ddr_avail || len < 3 * sizeof(u32)) + return; + + dwp = win64->value; + liobn = (u64)be32_to_cpu(dwp->liobn); + + /* clear the whole window, note the arg is in kernel pages */ + ret = tce_clearrange_multi_pSeriesLP(0, + 1ULL << (be32_to_cpu(dwp->window_shift) - PAGE_SHIFT), dwp); + if (ret) + pr_warning("%s failed to clear tces in window.\n", + np->full_name); + else + pr_debug("%s successfully cleared tces in window.\n", + np->full_name); + + ret = rtas_call(ddr_avail[2], 1, 1, NULL, liobn); + if (ret) + pr_warning("%s: failed to remove direct window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddr_avail[2], liobn); + else + pr_debug("%s: successfully removed direct window: rtas returned " + "%d to ibm,remove-pe-dma-window(%x) %llx\n", + np->full_name, ret, ddr_avail[2], liobn); +} + + +static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn) +{ + struct device_node *dn; + struct pci_dn *pcidn; + struct direct_window *window; + const struct dynamic_dma_window_prop *direct64; + u64 dma_addr = 0; + + dn = pci_device_to_OF_node(dev); + pcidn = PCI_DN(dn); + spin_lock(&direct_window_list_lock); + /* check if we already created a window and dupe that config if so */ + list_for_each_entry(window, &direct_window_list, list) { + if (window->device == pdn) { + direct64 = window->prop; + dma_addr = direct64->dma_base; + break; + } + } + spin_unlock(&direct_window_list_lock); + + return dma_addr; +} + +static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn) +{ + struct device_node *dn; + struct pci_dn *pcidn; + int len; + struct direct_window *window; + const struct dynamic_dma_window_prop *direct64; + u64 dma_addr = 0; + + dn = pci_device_to_OF_node(dev); + pcidn = PCI_DN(dn); + direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); + if (direct64) { + window = kzalloc(sizeof(*window), GFP_KERNEL); + if (!window) { + remove_ddw(pdn); + } else { + window->device = pdn; + window->prop = direct64; + spin_lock(&direct_window_list_lock); + list_add(&window->list, &direct_window_list); + spin_unlock(&direct_window_list_lock); + dma_addr = direct64->dma_base; + } + } + + return dma_addr; +} + +static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, + struct ddw_query_response *query) +{ + struct device_node *dn; + struct pci_dn *pcidn; + u32 cfg_addr; + u64 buid; + int ret; + + /* + * Get the config address and phb buid of the PE window. + * Rely on eeh to retrieve this for us. + * Retrieve them from the pci device, not the node with the + * dma-window property + */ + dn = pci_device_to_OF_node(dev); + pcidn = PCI_DN(dn); + cfg_addr = pcidn->eeh_config_addr; + if (pcidn->eeh_pe_config_addr) + cfg_addr = pcidn->eeh_pe_config_addr; + buid = pcidn->phb->buid; + ret = rtas_call(ddr_avail[0], 3, 5, (u32 *)query, + cfg_addr, BUID_HI(buid), BUID_LO(buid)); + dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x" + " returned %d\n", ddr_avail[0], cfg_addr, BUID_HI(buid), + BUID_LO(buid), ret); + return ret; +} + +static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, + struct ddw_create_response *create, int page_shift, + int window_shift) +{ + struct device_node *dn; + struct pci_dn *pcidn; + u32 cfg_addr; + u64 buid; + int ret; + + /* + * Get the config address and phb buid of the PE window. + * Rely on eeh to retrieve this for us. + * Retrieve them from the pci device, not the node with the + * dma-window property + */ + dn = pci_device_to_OF_node(dev); + pcidn = PCI_DN(dn); + cfg_addr = pcidn->eeh_config_addr; + if (pcidn->eeh_pe_config_addr) + cfg_addr = pcidn->eeh_pe_config_addr; + buid = pcidn->phb->buid; + + do { + /* extra outputs are LIOBN and dma-addr (hi, lo) */ + ret = rtas_call(ddr_avail[1], 5, 4, (u32 *)create, cfg_addr, + BUID_HI(buid), BUID_LO(buid), page_shift, window_shift); + } while (rtas_busy_delay(ret)); + dev_info(&dev->dev, + "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d " + "(liobn = 0x%x starting addr = %x %x)\n", ddr_avail[1], + cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift, + window_shift, ret, create->liobn, create->addr_hi, create->addr_lo); + + return ret; +} + +/* + * If the PE supports dynamic dma windows, and there is space for a table + * that can map all pages in a linear offset, then setup such a table, + * and record the dma-offset in the struct device. + * + * dev: the pci device we are checking + * pdn: the parent pe node with the ibm,dma_window property + * Future: also check if we can remap the base window for our base page size + * + * returns the dma offset for use by dma_set_mask + */ +static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) +{ + int len, ret; + struct ddw_query_response query; + struct ddw_create_response create; + int page_shift; + u64 dma_addr, max_addr; + struct device_node *dn; + const u32 *uninitialized_var(ddr_avail); + struct direct_window *window; + struct property *uninitialized_var(win64); + struct dynamic_dma_window_prop *ddwprop; + + mutex_lock(&direct_window_init_mutex); + + dma_addr = dupe_ddw_if_already_created(dev, pdn); + if (dma_addr != 0) + goto out_unlock; + + dma_addr = dupe_ddw_if_kexec(dev, pdn); + if (dma_addr != 0) + goto out_unlock; + + /* + * the ibm,ddw-applicable property holds the tokens for: + * ibm,query-pe-dma-window + * ibm,create-pe-dma-window + * ibm,remove-pe-dma-window + * for the given node in that order. + * the property is actually in the parent, not the PE + */ + ddr_avail = of_get_property(pdn, "ibm,ddw-applicable", &len); + if (!ddr_avail || len < 3 * sizeof(u32)) + goto out_unlock; + + /* + * Query if there is a second window of size to map the + * whole partition. Query returns number of windows, largest + * block assigned to PE (partition endpoint), and two bitmasks + * of page sizes: supported and supported for migrate-dma. + */ + dn = pci_device_to_OF_node(dev); + ret = query_ddw(dev, ddr_avail, &query); + if (ret != 0) + goto out_unlock; + + if (query.windows_available == 0) { + /* + * no additional windows are available for this device. + * We might be able to reallocate the existing window, + * trading in for a larger page size. + */ + dev_dbg(&dev->dev, "no free dynamic windows"); + goto out_unlock; + } + if (query.page_size & 4) { + page_shift = 24; /* 16MB */ + } else if (query.page_size & 2) { + page_shift = 16; /* 64kB */ + } else if (query.page_size & 1) { + page_shift = 12; /* 4kB */ + } else { + dev_dbg(&dev->dev, "no supported direct page size in mask %x", + query.page_size); + goto out_unlock; + } + /* verify the window * number of ptes will map the partition */ + /* check largest block * page size > max memory hotplug addr */ + max_addr = memory_hotplug_max(); + if (query.largest_available_block < (max_addr >> page_shift)) { + dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u " + "%llu-sized pages\n", max_addr, query.largest_available_block, + 1ULL << page_shift); + goto out_unlock; + } + len = order_base_2(max_addr); + win64 = kzalloc(sizeof(struct property), GFP_KERNEL); + if (!win64) { + dev_info(&dev->dev, + "couldn't allocate property for 64bit dma window\n"); + goto out_unlock; + } + win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL); + win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL); + if (!win64->name || !win64->value) { + dev_info(&dev->dev, + "couldn't allocate property name and value\n"); + goto out_free_prop; + } + + ret = create_ddw(dev, ddr_avail, &create, page_shift, len); + if (ret != 0) + goto out_free_prop; + + ddwprop->liobn = cpu_to_be32(create.liobn); + ddwprop->dma_base = cpu_to_be64(of_read_number(&create.addr_hi, 2)); + ddwprop->tce_shift = cpu_to_be32(page_shift); + ddwprop->window_shift = cpu_to_be32(len); + + dev_dbg(&dev->dev, "created tce table LIOBN 0x%x for %s\n", + create.liobn, dn->full_name); + + window = kzalloc(sizeof(*window), GFP_KERNEL); + if (!window) + goto out_clear_window; + + ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT, + win64->value, tce_setrange_multi_pSeriesLP_walk); + if (ret) { + dev_info(&dev->dev, "failed to map direct window for %s: %d\n", + dn->full_name, ret); + goto out_clear_window; + } + + ret = prom_add_property(pdn, win64); + if (ret) { + dev_err(&dev->dev, "unable to add dma window property for %s: %d", + pdn->full_name, ret); + goto out_clear_window; + } + + window->device = pdn; + window->prop = ddwprop; + spin_lock(&direct_window_list_lock); + list_add(&window->list, &direct_window_list); + spin_unlock(&direct_window_list_lock); + + dma_addr = of_read_number(&create.addr_hi, 2); + goto out_unlock; + +out_clear_window: + remove_ddw(pdn); + +out_free_prop: + kfree(win64->name); + kfree(win64->value); + kfree(win64); + +out_unlock: + mutex_unlock(&direct_window_init_mutex); + return dma_addr; +} + static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) { struct device_node *pdn, *dn; @@ -541,23 +1012,137 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) set_iommu_table_base(&dev->dev, pci->iommu_table); } + +static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) +{ + bool ddw_enabled = false; + struct device_node *pdn, *dn; + struct pci_dev *pdev; + const void *dma_window = NULL; + u64 dma_offset; + + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + + /* only attempt to use a new window if 64-bit DMA is requested */ + if (!disable_ddw && dma_mask == DMA_BIT_MASK(64)) { + pdev = to_pci_dev(dev); + + dn = pci_device_to_OF_node(pdev); + dev_dbg(dev, "node is %s\n", dn->full_name); + + /* + * the device tree might contain the dma-window properties + * per-device and not neccesarily for the bus. So we need to + * search upwards in the tree until we either hit a dma-window + * property, OR find a parent with a table already allocated. + */ + for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table; + pdn = pdn->parent) { + dma_window = of_get_property(pdn, "ibm,dma-window", NULL); + if (dma_window) + break; + } + if (pdn && PCI_DN(pdn)) { + dma_offset = enable_ddw(pdev, pdn); + if (dma_offset != 0) { + dev_info(dev, "Using 64-bit direct DMA at offset %llx\n", dma_offset); + set_dma_offset(dev, dma_offset); + set_dma_ops(dev, &dma_direct_ops); + ddw_enabled = true; + } + } + } + + /* fall-through to iommu ops */ + if (!ddw_enabled) { + dev_info(dev, "Using 32-bit DMA via iommu\n"); + set_dma_ops(dev, &dma_iommu_ops); + } + + *dev->dma_mask = dma_mask; + return 0; +} + #else /* CONFIG_PCI */ #define pci_dma_bus_setup_pSeries NULL #define pci_dma_dev_setup_pSeries NULL #define pci_dma_bus_setup_pSeriesLP NULL #define pci_dma_dev_setup_pSeriesLP NULL +#define dma_set_mask_pSeriesLP NULL #endif /* !CONFIG_PCI */ +static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct direct_window *window; + struct memory_notify *arg = data; + int ret = 0; + + switch (action) { + case MEM_GOING_ONLINE: + spin_lock(&direct_window_list_lock); + list_for_each_entry(window, &direct_window_list, list) { + ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn, + arg->nr_pages, window->prop); + /* XXX log error */ + } + spin_unlock(&direct_window_list_lock); + break; + case MEM_CANCEL_ONLINE: + case MEM_OFFLINE: + spin_lock(&direct_window_list_lock); + list_for_each_entry(window, &direct_window_list, list) { + ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn, + arg->nr_pages, window->prop); + /* XXX log error */ + } + spin_unlock(&direct_window_list_lock); + break; + default: + break; + } + if (ret && action != MEM_CANCEL_ONLINE) + return NOTIFY_BAD; + + return NOTIFY_OK; +} + +static struct notifier_block iommu_mem_nb = { + .notifier_call = iommu_mem_notifier, +}; + static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node) { int err = NOTIFY_OK; struct device_node *np = node; struct pci_dn *pci = PCI_DN(np); + struct direct_window *window; switch (action) { case PSERIES_RECONFIG_REMOVE: if (pci && pci->iommu_table) iommu_free_table(pci->iommu_table, np->full_name); + + spin_lock(&direct_window_list_lock); + list_for_each_entry(window, &direct_window_list, list) { + if (window->device == np) { + list_del(&window->list); + kfree(window); + break; + } + } + spin_unlock(&direct_window_list_lock); + + /* + * Because the notifier runs after isolation of the + * slot, we are guaranteed any DMA window has already + * been revoked and the TCEs have been marked invalid, + * so we don't need a call to remove_ddw(np). However, + * if an additional notifier action is added before the + * isolate call, we should update this code for + * completeness with such a call. + */ break; default: err = NOTIFY_DONE; @@ -587,6 +1172,7 @@ void iommu_init_early_pSeries(void) ppc_md.tce_get = tce_get_pSeriesLP; ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP; ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP; + ppc_md.dma_set_mask = dma_set_mask_pSeriesLP; } else { ppc_md.tce_build = tce_build_pSeries; ppc_md.tce_free = tce_free_pSeries; @@ -597,6 +1183,7 @@ void iommu_init_early_pSeries(void) pSeries_reconfig_notifier_register(&iommu_reconfig_nb); + register_memory_notifier(&iommu_mem_nb); set_pci_dma_ops(&dma_iommu_ops); } diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 53cbd53..77d38a5 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -61,13 +61,3 @@ void __init setup_kexec_cpu_down_xics(void) { ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; } - -static int __init pseries_kexec_setup(void) -{ - ppc_md.machine_kexec = default_machine_kexec; - ppc_md.machine_kexec_prepare = default_machine_kexec_prepare; - ppc_md.machine_crash_shutdown = default_machine_crash_shutdown; - - return 0; -} -machine_device_initcall(pseries, pseries_kexec_setup); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 5d3ea9f..ca5d589 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -713,6 +713,13 @@ EXPORT_SYMBOL(arch_free_page); /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ extern long hcall_tracepoint_refcount; +/* + * Since the tracing code might execute hcalls we need to guard against + * recursion. One example of this are spinlocks calling H_YIELD on + * shared processor partitions. + */ +static DEFINE_PER_CPU(unsigned int, hcall_trace_depth); + void hcall_tracepoint_regfunc(void) { hcall_tracepoint_refcount++; @@ -725,12 +732,42 @@ void hcall_tracepoint_unregfunc(void) void __trace_hcall_entry(unsigned long opcode, unsigned long *args) { + unsigned long flags; + unsigned int *depth; + + local_irq_save(flags); + + depth = &__get_cpu_var(hcall_trace_depth); + + if (*depth) + goto out; + + (*depth)++; trace_hcall_entry(opcode, args); + (*depth)--; + +out: + local_irq_restore(flags); } void __trace_hcall_exit(long opcode, unsigned long retval, unsigned long *retbuf) { + unsigned long flags; + unsigned int *depth; + + local_irq_save(flags); + + depth = &__get_cpu_var(hcall_trace_depth); + + if (*depth) + goto out; + + (*depth)++; trace_hcall_exit(opcode, retval, retbuf); + (*depth)--; + +out: + local_irq_restore(flags); } #endif diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 1164c34..18ac801 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -93,8 +93,18 @@ static void rtas_disable_msi(struct pci_dev *pdev) if (!pdn) return; - if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0) - pr_debug("rtas_msi: Setting MSIs to 0 failed!\n"); + /* + * disabling MSI with the explicit interface also disables MSI-X + */ + if (rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, 0) != 0) { + /* + * may have failed because explicit interface is not + * present + */ + if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0) { + pr_debug("rtas_msi: Setting MSIs to 0 failed!\n"); + } + } } static int rtas_query_irq_number(struct pci_dn *pdn, int offset) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 7e828ba..419707b 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -16,6 +16,8 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/kmsg_dump.h> #include <asm/uaccess.h> #include <asm/nvram.h> #include <asm/rtas.h> @@ -30,17 +32,54 @@ static int nvram_fetch, nvram_store; static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ static DEFINE_SPINLOCK(nvram_lock); -static long nvram_error_log_index = -1; -static long nvram_error_log_size = 0; - struct err_log_info { int error_type; unsigned int seq_num; }; -#define NVRAM_MAX_REQ 2079 -#define NVRAM_MIN_REQ 1055 -#define NVRAM_LOG_PART_NAME "ibm,rtas-log" +struct nvram_os_partition { + const char *name; + int req_size; /* desired size, in bytes */ + int min_size; /* minimum acceptable size (0 means req_size) */ + long size; /* size of data portion (excluding err_log_info) */ + long index; /* offset of data portion of partition */ +}; + +static struct nvram_os_partition rtas_log_partition = { + .name = "ibm,rtas-log", + .req_size = 2079, + .min_size = 1055, + .index = -1 +}; + +static struct nvram_os_partition oops_log_partition = { + .name = "lnx,oops-log", + .req_size = 4000, + .min_size = 2000, + .index = -1 +}; + +static const char *pseries_nvram_os_partitions[] = { + "ibm,rtas-log", + "lnx,oops-log", + NULL +}; + +static void oops_to_nvram(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason, + const char *old_msgs, unsigned long old_len, + const char *new_msgs, unsigned long new_len); + +static struct kmsg_dumper nvram_kmsg_dumper = { + .dump = oops_to_nvram +}; + +/* See clobbering_unread_rtas_event() */ +#define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */ +static unsigned long last_unread_rtas_event; /* timestamp */ + +/* We preallocate oops_buf during init to avoid kmalloc during oops/panic. */ +static char *oops_buf; static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) { @@ -134,7 +173,7 @@ static ssize_t pSeries_nvram_get_size(void) } -/* nvram_write_error_log +/* nvram_write_os_partition, nvram_write_error_log * * We need to buffer the error logs into nvram to ensure that we have * the failure information to decode. If we have a severe error there @@ -156,48 +195,58 @@ static ssize_t pSeries_nvram_get_size(void) * The 'data' section would look like (in bytes): * +--------------+------------+-----------------------------------+ * | event_logged | sequence # | error log | - * |0 3|4 7|8 nvram_error_log_size-1| + * |0 3|4 7|8 error_log_size-1| * +--------------+------------+-----------------------------------+ * * event_logged: 0 if event has not been logged to syslog, 1 if it has * sequence #: The unique sequence # for each event. (until it wraps) * error log: The error log from event_scan */ -int nvram_write_error_log(char * buff, int length, - unsigned int err_type, unsigned int error_log_cnt) +int nvram_write_os_partition(struct nvram_os_partition *part, char * buff, + int length, unsigned int err_type, unsigned int error_log_cnt) { int rc; loff_t tmp_index; struct err_log_info info; - if (nvram_error_log_index == -1) { + if (part->index == -1) { return -ESPIPE; } - if (length > nvram_error_log_size) { - length = nvram_error_log_size; + if (length > part->size) { + length = part->size; } info.error_type = err_type; info.seq_num = error_log_cnt; - tmp_index = nvram_error_log_index; + tmp_index = part->index; rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index); if (rc <= 0) { - printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); + pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc); return rc; } rc = ppc_md.nvram_write(buff, length, &tmp_index); if (rc <= 0) { - printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); + pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc); return rc; } return 0; } +int nvram_write_error_log(char * buff, int length, + unsigned int err_type, unsigned int error_log_cnt) +{ + int rc = nvram_write_os_partition(&rtas_log_partition, buff, length, + err_type, error_log_cnt); + if (!rc) + last_unread_rtas_event = get_seconds(); + return rc; +} + /* nvram_read_error_log * * Reads nvram for error log for at most 'length' @@ -209,13 +258,13 @@ int nvram_read_error_log(char * buff, int length, loff_t tmp_index; struct err_log_info info; - if (nvram_error_log_index == -1) + if (rtas_log_partition.index == -1) return -1; - if (length > nvram_error_log_size) - length = nvram_error_log_size; + if (length > rtas_log_partition.size) + length = rtas_log_partition.size; - tmp_index = nvram_error_log_index; + tmp_index = rtas_log_partition.index; rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index); if (rc <= 0) { @@ -244,37 +293,40 @@ int nvram_clear_error_log(void) int clear_word = ERR_FLAG_ALREADY_LOGGED; int rc; - if (nvram_error_log_index == -1) + if (rtas_log_partition.index == -1) return -1; - tmp_index = nvram_error_log_index; + tmp_index = rtas_log_partition.index; rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); if (rc <= 0) { printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc); return rc; } + last_unread_rtas_event = 0; return 0; } -/* pseries_nvram_init_log_partition +/* pseries_nvram_init_os_partition * - * This will setup the partition we need for buffering the - * error logs and cleanup partitions if needed. + * This sets up a partition with an "OS" signature. * * The general strategy is the following: - * 1.) If there is log partition large enough then use it. - * 2.) If there is none large enough, search - * for a free partition that is large enough. - * 3.) If there is not a free partition large enough remove - * _all_ OS partitions and consolidate the space. - * 4.) Will first try getting a chunk that will satisfy the maximum - * error log size (NVRAM_MAX_REQ). - * 5.) If the max chunk cannot be allocated then try finding a chunk - * that will satisfy the minum needed (NVRAM_MIN_REQ). + * 1.) If a partition with the indicated name already exists... + * - If it's large enough, use it. + * - Otherwise, recycle it and keep going. + * 2.) Search for a free partition that is large enough. + * 3.) If there's not a free partition large enough, recycle any obsolete + * OS partitions and try again. + * 4.) Will first try getting a chunk that will satisfy the requested size. + * 5.) If a chunk of the requested size cannot be allocated, then try finding + * a chunk that will satisfy the minum needed. + * + * Returns 0 on success, else -1. */ -static int __init pseries_nvram_init_log_partition(void) +static int __init pseries_nvram_init_os_partition(struct nvram_os_partition + *part) { loff_t p; int size; @@ -282,47 +334,76 @@ static int __init pseries_nvram_init_log_partition(void) /* Scan nvram for partitions */ nvram_scan_partitions(); - /* Lookg for ours */ - p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size); + /* Look for ours */ + p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size); /* Found one but too small, remove it */ - if (p && size < NVRAM_MIN_REQ) { - pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition" - ",removing it..."); - nvram_remove_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS); + if (p && size < part->min_size) { + pr_info("nvram: Found too small %s partition," + " removing it...\n", part->name); + nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL); p = 0; } /* Create one if we didn't find */ if (!p) { - p = nvram_create_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, - NVRAM_MAX_REQ, NVRAM_MIN_REQ); - /* No room for it, try to get rid of any OS partition - * and try again - */ + p = nvram_create_partition(part->name, NVRAM_SIG_OS, + part->req_size, part->min_size); if (p == -ENOSPC) { - pr_info("nvram: No room to create "NVRAM_LOG_PART_NAME - " partition, deleting all OS partitions..."); - nvram_remove_partition(NULL, NVRAM_SIG_OS); - p = nvram_create_partition(NVRAM_LOG_PART_NAME, - NVRAM_SIG_OS, NVRAM_MAX_REQ, - NVRAM_MIN_REQ); + pr_info("nvram: No room to create %s partition, " + "deleting any obsolete OS partitions...\n", + part->name); + nvram_remove_partition(NULL, NVRAM_SIG_OS, + pseries_nvram_os_partitions); + p = nvram_create_partition(part->name, NVRAM_SIG_OS, + part->req_size, part->min_size); } } if (p <= 0) { - pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME - " partition, err %d\n", (int)p); - return 0; + pr_err("nvram: Failed to find or create %s" + " partition, err %d\n", part->name, (int)p); + return -1; } - nvram_error_log_index = p; - nvram_error_log_size = nvram_get_partition_size(p) - - sizeof(struct err_log_info); + part->index = p; + part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info); return 0; } -machine_arch_initcall(pseries, pseries_nvram_init_log_partition); + +static void __init nvram_init_oops_partition(int rtas_partition_exists) +{ + int rc; + + rc = pseries_nvram_init_os_partition(&oops_log_partition); + if (rc != 0) { + if (!rtas_partition_exists) + return; + pr_notice("nvram: Using %s partition to log both" + " RTAS errors and oops/panic reports\n", + rtas_log_partition.name); + memcpy(&oops_log_partition, &rtas_log_partition, + sizeof(rtas_log_partition)); + } + oops_buf = kmalloc(oops_log_partition.size, GFP_KERNEL); + rc = kmsg_dump_register(&nvram_kmsg_dumper); + if (rc != 0) { + pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc); + kfree(oops_buf); + return; + } +} + +static int __init pseries_nvram_init_log_partitions(void) +{ + int rc; + + rc = pseries_nvram_init_os_partition(&rtas_log_partition); + nvram_init_oops_partition(rc == 0); + return 0; +} +machine_arch_initcall(pseries, pseries_nvram_init_log_partitions); int __init pSeries_nvram_init(void) { @@ -353,3 +434,59 @@ int __init pSeries_nvram_init(void) return 0; } + +/* + * Try to capture the last capture_len bytes of the printk buffer. Return + * the amount actually captured. + */ +static size_t capture_last_msgs(const char *old_msgs, size_t old_len, + const char *new_msgs, size_t new_len, + char *captured, size_t capture_len) +{ + if (new_len >= capture_len) { + memcpy(captured, new_msgs + (new_len - capture_len), + capture_len); + return capture_len; + } else { + /* Grab the end of old_msgs. */ + size_t old_tail_len = min(old_len, capture_len - new_len); + memcpy(captured, old_msgs + (old_len - old_tail_len), + old_tail_len); + memcpy(captured + old_tail_len, new_msgs, new_len); + return old_tail_len + new_len; + } +} + +/* + * Are we using the ibm,rtas-log for oops/panic reports? And if so, + * would logging this oops/panic overwrite an RTAS event that rtas_errd + * hasn't had a chance to read and process? Return 1 if so, else 0. + * + * We assume that if rtas_errd hasn't read the RTAS event in + * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to. + */ +static int clobbering_unread_rtas_event(void) +{ + return (oops_log_partition.index == rtas_log_partition.index + && last_unread_rtas_event + && get_seconds() - last_unread_rtas_event <= + NVRAM_RTAS_READ_TIMEOUT); +} + +/* our kmsg_dump callback */ +static void oops_to_nvram(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason, + const char *old_msgs, unsigned long old_len, + const char *new_msgs, unsigned long new_len) +{ + static unsigned int oops_count = 0; + size_t text_len; + + if (clobbering_unread_rtas_event()) + return; + + text_len = capture_last_msgs(old_msgs, old_len, new_msgs, new_len, + oops_buf, oops_log_partition.size); + (void) nvram_write_os_partition(&oops_log_partition, oops_buf, + (int) text_len, ERR_TYPE_KERNEL_PANIC, ++oops_count); +} diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index a4fc6da..c55d7ad 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -54,7 +54,8 @@ static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; static DEFINE_SPINLOCK(ras_log_buf_lock); -static char mce_data_buf[RTAS_ERROR_LOG_MAX]; +static char global_mce_data_buf[RTAS_ERROR_LOG_MAX]; +static DEFINE_PER_CPU(__u64, mce_data_buf); static int ras_get_sensor_state_token; static int ras_check_exception_token; @@ -196,12 +197,24 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* Get the error information for errors coming through the +/* + * Some versions of FWNMI place the buffer inside the 4kB page starting at + * 0x7000. Other versions place it inside the rtas buffer. We check both. + */ +#define VALID_FWNMI_BUFFER(A) \ + ((((A) >= 0x7000) && ((A) < 0x7ff0)) || \ + (((A) >= rtas.base) && ((A) < (rtas.base + rtas.size - 16)))) + +/* + * Get the error information for errors coming through the * FWNMI vectors. The pt_regs' r3 will be updated to reflect * the actual r3 if possible, and a ptr to the error log entry * will be returned if found. * - * The mce_data_buf does not have any locks or protection around it, + * If the RTAS error is not of the extended type, then we put it in a per + * cpu 64bit buffer. If it is the extended type we use global_mce_data_buf. + * + * The global_mce_data_buf does not have any locks or protection around it, * if a second machine check comes in, or a system reset is done * before we have logged the error, then we will get corruption in the * error log. This is preferable over holding off on calling @@ -210,20 +223,31 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) */ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) { - unsigned long errdata = regs->gpr[3]; - struct rtas_error_log *errhdr = NULL; unsigned long *savep; + struct rtas_error_log *h, *errhdr = NULL; + + if (!VALID_FWNMI_BUFFER(regs->gpr[3])) { + printk(KERN_ERR "FWNMI: corrupt r3\n"); + return NULL; + } - if ((errdata >= 0x7000 && errdata < 0x7fff0) || - (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) { - savep = __va(errdata); - regs->gpr[3] = savep[0]; /* restore original r3 */ - memset(mce_data_buf, 0, RTAS_ERROR_LOG_MAX); - memcpy(mce_data_buf, (char *)(savep + 1), RTAS_ERROR_LOG_MAX); - errhdr = (struct rtas_error_log *)mce_data_buf; + savep = __va(regs->gpr[3]); + regs->gpr[3] = savep[0]; /* restore original r3 */ + + /* If it isn't an extended log we can use the per cpu 64bit buffer */ + h = (struct rtas_error_log *)&savep[1]; + if (!h->extended) { + memcpy(&__get_cpu_var(mce_data_buf), h, sizeof(__u64)); + errhdr = (struct rtas_error_log *)&__get_cpu_var(mce_data_buf); } else { - printk("FWNMI: corrupt r3\n"); + int len; + + len = max_t(int, 8+h->extended_log_length, RTAS_ERROR_LOG_MAX); + memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX); + memcpy(global_mce_data_buf, h, len); + errhdr = (struct rtas_error_log *)global_mce_data_buf; } + return errhdr; } @@ -235,7 +259,7 @@ static void fwnmi_release_errinfo(void) { int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL); if (ret != 0) - printk("FWNMI: nmi-interlock failed: %d\n", ret); + printk(KERN_ERR "FWNMI: nmi-interlock failed: %d\n", ret); } int pSeries_system_reset_exception(struct pt_regs *regs) @@ -259,31 +283,43 @@ int pSeries_system_reset_exception(struct pt_regs *regs) * Return 1 if corrected (or delivered a signal). * Return 0 if there is nothing we can do. */ -static int recover_mce(struct pt_regs *regs, struct rtas_error_log * err) +static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err) { - int nonfatal = 0; + int recovered = 0; - if (err->disposition == RTAS_DISP_FULLY_RECOVERED) { + if (!(regs->msr & MSR_RI)) { + /* If MSR_RI isn't set, we cannot recover */ + recovered = 0; + + } else if (err->disposition == RTAS_DISP_FULLY_RECOVERED) { /* Platform corrected itself */ - nonfatal = 1; - } else if ((regs->msr & MSR_RI) && - user_mode(regs) && - err->severity == RTAS_SEVERITY_ERROR_SYNC && - err->disposition == RTAS_DISP_NOT_RECOVERED && - err->target == RTAS_TARGET_MEMORY && - err->type == RTAS_TYPE_ECC_UNCORR && - !(current->pid == 0 || is_global_init(current))) { - /* Kill off a user process with an ECC error */ - printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n", - current->pid); - /* XXX something better for ECC error? */ - _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); - nonfatal = 1; + recovered = 1; + + } else if (err->disposition == RTAS_DISP_LIMITED_RECOVERY) { + /* Platform corrected itself but could be degraded */ + printk(KERN_ERR "MCE: limited recovery, system may " + "be degraded\n"); + recovered = 1; + + } else if (user_mode(regs) && !is_global_init(current) && + err->severity == RTAS_SEVERITY_ERROR_SYNC) { + + /* + * If we received a synchronous error when in userspace + * kill the task. Firmware may report details of the fail + * asynchronously, so we can't rely on the target and type + * fields being valid here. + */ + printk(KERN_ERR "MCE: uncorrectable error, killing task " + "%s:%d\n", current->comm, current->pid); + + _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); + recovered = 1; } - log_error((char *)err, ERR_TYPE_RTAS_LOG, !nonfatal); + log_error((char *)err, ERR_TYPE_RTAS_LOG, 0); - return nonfatal; + return recovered; } /* diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index d345bfd..2a0089a 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -114,10 +114,13 @@ static void __init fwnmi_init(void) static void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = get_irq_desc_chip(desc); unsigned int cascade_irq = i8259_irq(); + if (cascade_irq != NO_IRQ) generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); + + chip->irq_eoi(&desc->irq_data); } static void __init pseries_setup_i8259_cascade(void) diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c index ed72098..a8ca289 100644 --- a/arch/powerpc/platforms/pseries/suspend.c +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -153,7 +153,7 @@ static struct sysdev_class suspend_sysdev_class = { .name = "power", }; -static struct platform_suspend_ops pseries_suspend_ops = { +static const struct platform_suspend_ops pseries_suspend_ops = { .valid = suspend_valid_only_mem, .begin = pseries_suspend_begin, .prepare_late = pseries_prepare_late, diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 7b96e5a..01fea46 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -202,20 +202,20 @@ static int get_irq_server(unsigned int virq, const struct cpumask *cpumask, #define get_irq_server(virq, cpumask, strict_check) (default_server) #endif -static void xics_unmask_irq(unsigned int virq) +static void xics_unmask_irq(struct irq_data *d) { unsigned int irq; int call_status; int server; - pr_devel("xics: unmask virq %d\n", virq); + pr_devel("xics: unmask virq %d\n", d->irq); - irq = (unsigned int)irq_map[virq].hwirq; + irq = (unsigned int)irq_map[d->irq].hwirq; pr_devel(" -> map to hwirq 0x%x\n", irq); if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) return; - server = get_irq_server(virq, irq_to_desc(virq)->affinity, 0); + server = get_irq_server(d->irq, d->affinity, 0); call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, DEFAULT_PRIORITY); @@ -235,61 +235,61 @@ static void xics_unmask_irq(unsigned int virq) } } -static unsigned int xics_startup(unsigned int virq) +static unsigned int xics_startup(struct irq_data *d) { /* * The generic MSI code returns with the interrupt disabled on the * card, using the MSI mask bits. Firmware doesn't appear to unmask * at that level, so we do it here by hand. */ - if (irq_to_desc(virq)->msi_desc) - unmask_msi_irq(irq_get_irq_data(virq)); + if (d->msi_desc) + unmask_msi_irq(d); /* unmask it */ - xics_unmask_irq(virq); + xics_unmask_irq(d); return 0; } -static void xics_mask_real_irq(unsigned int irq) +static void xics_mask_real_irq(struct irq_data *d) { int call_status; - if (irq == XICS_IPI) + if (d->irq == XICS_IPI) return; - call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); + call_status = rtas_call(ibm_int_off, 1, 1, NULL, d->irq); if (call_status != 0) { printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", - __func__, irq, call_status); + __func__, d->irq, call_status); return; } /* Have to set XIVE to 0xff to be able to remove a slot */ - call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, + call_status = rtas_call(ibm_set_xive, 3, 1, NULL, d->irq, default_server, 0xff); if (call_status != 0) { printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", - __func__, irq, call_status); + __func__, d->irq, call_status); return; } } -static void xics_mask_irq(unsigned int virq) +static void xics_mask_irq(struct irq_data *d) { unsigned int irq; - pr_devel("xics: mask virq %d\n", virq); + pr_devel("xics: mask virq %d\n", d->irq); - irq = (unsigned int)irq_map[virq].hwirq; + irq = (unsigned int)irq_map[d->irq].hwirq; if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) return; - xics_mask_real_irq(irq); + xics_mask_real_irq(d); } static void xics_mask_unknown_vec(unsigned int vec) { printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); - xics_mask_real_irq(vec); + xics_mask_real_irq(irq_get_irq_data(vec)); } static inline unsigned int xics_xirr_vector(unsigned int xirr) @@ -371,30 +371,31 @@ static unsigned char pop_cppr(void) return os_cppr->stack[--os_cppr->index]; } -static void xics_eoi_direct(unsigned int virq) +static void xics_eoi_direct(struct irq_data *d) { - unsigned int irq = (unsigned int)irq_map[virq].hwirq; + unsigned int irq = (unsigned int)irq_map[d->irq].hwirq; iosync(); direct_xirr_info_set((pop_cppr() << 24) | irq); } -static void xics_eoi_lpar(unsigned int virq) +static void xics_eoi_lpar(struct irq_data *d) { - unsigned int irq = (unsigned int)irq_map[virq].hwirq; + unsigned int irq = (unsigned int)irq_map[d->irq].hwirq; iosync(); lpar_xirr_info_set((pop_cppr() << 24) | irq); } -static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) +static int +xics_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) { unsigned int irq; int status; int xics_status[2]; int irq_server; - irq = (unsigned int)irq_map[virq].hwirq; + irq = (unsigned int)irq_map[d->irq].hwirq; if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) return -1; @@ -406,13 +407,13 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) return -1; } - irq_server = get_irq_server(virq, cpumask, 1); + irq_server = get_irq_server(d->irq, cpumask, 1); if (irq_server == -1) { char cpulist[128]; cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); printk(KERN_WARNING "%s: No online cpus in the mask %s for irq %d\n", - __func__, cpulist, virq); + __func__, cpulist, d->irq); return -1; } @@ -430,20 +431,20 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) static struct irq_chip xics_pic_direct = { .name = "XICS", - .startup = xics_startup, - .mask = xics_mask_irq, - .unmask = xics_unmask_irq, - .eoi = xics_eoi_direct, - .set_affinity = xics_set_affinity + .irq_startup = xics_startup, + .irq_mask = xics_mask_irq, + .irq_unmask = xics_unmask_irq, + .irq_eoi = xics_eoi_direct, + .irq_set_affinity = xics_set_affinity }; static struct irq_chip xics_pic_lpar = { .name = "XICS", - .startup = xics_startup, - .mask = xics_mask_irq, - .unmask = xics_unmask_irq, - .eoi = xics_eoi_lpar, - .set_affinity = xics_set_affinity + .irq_startup = xics_startup, + .irq_mask = xics_mask_irq, + .irq_unmask = xics_unmask_irq, + .irq_eoi = xics_eoi_lpar, + .irq_set_affinity = xics_set_affinity }; @@ -890,6 +891,7 @@ void xics_migrate_irqs_away(void) for_each_irq(virq) { struct irq_desc *desc; + struct irq_chip *chip; int xics_status[2]; int status; unsigned long flags; @@ -903,12 +905,15 @@ void xics_migrate_irqs_away(void) /* We need to get IPIs still. */ if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) continue; + desc = irq_to_desc(virq); /* We only need to migrate enabled IRQS */ - if (desc == NULL || desc->chip == NULL - || desc->action == NULL - || desc->chip->set_affinity == NULL) + if (desc == NULL || desc->action == NULL) + continue; + + chip = get_irq_desc_chip(desc); + if (chip == NULL || chip->irq_set_affinity == NULL) continue; raw_spin_lock_irqsave(&desc->lock, flags); @@ -934,8 +939,8 @@ void xics_migrate_irqs_away(void) virq, cpu); /* Reset affinity to all cpus */ - cpumask_setall(irq_to_desc(virq)->affinity); - desc->chip->set_affinity(virq, cpu_all_mask); + cpumask_setall(desc->irq_data.affinity); + chip->irq_set_affinity(&desc->irq_data, cpu_all_mask, true); unlock: raw_spin_unlock_irqrestore(&desc->lock, flags); } |