diff options
Diffstat (limited to 'arch/powerpc/platforms')
28 files changed, 1772 insertions, 113 deletions
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index bcc69e1f77c1..45c0cb9b67e6 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/utsrelease.h> | 13 | #include <generated/utsrelease.h> |
14 | #include <linux/pci.h> | 14 | #include <linux/pci.h> |
15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
16 | #include <asm/prom.h> | 16 | #include <asm/prom.h> |
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index d306f07b9aa1..43805348b81e 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #define PMCCR1_NEXT_STATE 0x0C /* Next state for power management */ | 32 | #define PMCCR1_NEXT_STATE 0x0C /* Next state for power management */ |
33 | #define PMCCR1_NEXT_STATE_SHIFT 2 | 33 | #define PMCCR1_NEXT_STATE_SHIFT 2 |
34 | #define PMCCR1_CURR_STATE 0x03 /* Current state for power management*/ | 34 | #define PMCCR1_CURR_STATE 0x03 /* Current state for power management*/ |
35 | #define IMMR_SYSCR_OFFSET 0x100 | ||
35 | #define IMMR_RCW_OFFSET 0x900 | 36 | #define IMMR_RCW_OFFSET 0x900 |
36 | #define RCW_PCI_HOST 0x80000000 | 37 | #define RCW_PCI_HOST 0x80000000 |
37 | 38 | ||
@@ -78,6 +79,22 @@ struct mpc83xx_clock { | |||
78 | u32 sccr; | 79 | u32 sccr; |
79 | }; | 80 | }; |
80 | 81 | ||
82 | struct mpc83xx_syscr { | ||
83 | __be32 sgprl; | ||
84 | __be32 sgprh; | ||
85 | __be32 spridr; | ||
86 | __be32 :32; | ||
87 | __be32 spcr; | ||
88 | __be32 sicrl; | ||
89 | __be32 sicrh; | ||
90 | }; | ||
91 | |||
92 | struct mpc83xx_saved { | ||
93 | u32 sicrl; | ||
94 | u32 sicrh; | ||
95 | u32 sccr; | ||
96 | }; | ||
97 | |||
81 | struct pmc_type { | 98 | struct pmc_type { |
82 | int has_deep_sleep; | 99 | int has_deep_sleep; |
83 | }; | 100 | }; |
@@ -87,6 +104,8 @@ static int has_deep_sleep, deep_sleeping; | |||
87 | static int pmc_irq; | 104 | static int pmc_irq; |
88 | static struct mpc83xx_pmc __iomem *pmc_regs; | 105 | static struct mpc83xx_pmc __iomem *pmc_regs; |
89 | static struct mpc83xx_clock __iomem *clock_regs; | 106 | static struct mpc83xx_clock __iomem *clock_regs; |
107 | static struct mpc83xx_syscr __iomem *syscr_regs; | ||
108 | static struct mpc83xx_saved saved_regs; | ||
90 | static int is_pci_agent, wake_from_pci; | 109 | static int is_pci_agent, wake_from_pci; |
91 | static phys_addr_t immrbase; | 110 | static phys_addr_t immrbase; |
92 | static int pci_pm_state; | 111 | static int pci_pm_state; |
@@ -137,6 +156,20 @@ static irqreturn_t pmc_irq_handler(int irq, void *dev_id) | |||
137 | return ret; | 156 | return ret; |
138 | } | 157 | } |
139 | 158 | ||
159 | static void mpc83xx_suspend_restore_regs(void) | ||
160 | { | ||
161 | out_be32(&syscr_regs->sicrl, saved_regs.sicrl); | ||
162 | out_be32(&syscr_regs->sicrh, saved_regs.sicrh); | ||
163 | out_be32(&clock_regs->sccr, saved_regs.sccr); | ||
164 | } | ||
165 | |||
166 | static void mpc83xx_suspend_save_regs(void) | ||
167 | { | ||
168 | saved_regs.sicrl = in_be32(&syscr_regs->sicrl); | ||
169 | saved_regs.sicrh = in_be32(&syscr_regs->sicrh); | ||
170 | saved_regs.sccr = in_be32(&clock_regs->sccr); | ||
171 | } | ||
172 | |||
140 | static int mpc83xx_suspend_enter(suspend_state_t state) | 173 | static int mpc83xx_suspend_enter(suspend_state_t state) |
141 | { | 174 | { |
142 | int ret = -EAGAIN; | 175 | int ret = -EAGAIN; |
@@ -166,6 +199,8 @@ static int mpc83xx_suspend_enter(suspend_state_t state) | |||
166 | */ | 199 | */ |
167 | 200 | ||
168 | if (deep_sleeping) { | 201 | if (deep_sleeping) { |
202 | mpc83xx_suspend_save_regs(); | ||
203 | |||
169 | out_be32(&pmc_regs->mask, PMCER_ALL); | 204 | out_be32(&pmc_regs->mask, PMCER_ALL); |
170 | 205 | ||
171 | out_be32(&pmc_regs->config1, | 206 | out_be32(&pmc_regs->config1, |
@@ -179,6 +214,8 @@ static int mpc83xx_suspend_enter(suspend_state_t state) | |||
179 | in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF); | 214 | in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF); |
180 | 215 | ||
181 | out_be32(&pmc_regs->mask, PMCER_PMCI); | 216 | out_be32(&pmc_regs->mask, PMCER_PMCI); |
217 | |||
218 | mpc83xx_suspend_restore_regs(); | ||
182 | } else { | 219 | } else { |
183 | out_be32(&pmc_regs->mask, PMCER_PMCI); | 220 | out_be32(&pmc_regs->mask, PMCER_PMCI); |
184 | 221 | ||
@@ -194,7 +231,7 @@ out: | |||
194 | return ret; | 231 | return ret; |
195 | } | 232 | } |
196 | 233 | ||
197 | static void mpc83xx_suspend_finish(void) | 234 | static void mpc83xx_suspend_end(void) |
198 | { | 235 | { |
199 | deep_sleeping = 0; | 236 | deep_sleeping = 0; |
200 | } | 237 | } |
@@ -278,7 +315,7 @@ static struct platform_suspend_ops mpc83xx_suspend_ops = { | |||
278 | .valid = mpc83xx_suspend_valid, | 315 | .valid = mpc83xx_suspend_valid, |
279 | .begin = mpc83xx_suspend_begin, | 316 | .begin = mpc83xx_suspend_begin, |
280 | .enter = mpc83xx_suspend_enter, | 317 | .enter = mpc83xx_suspend_enter, |
281 | .finish = mpc83xx_suspend_finish, | 318 | .end = mpc83xx_suspend_end, |
282 | }; | 319 | }; |
283 | 320 | ||
284 | static int pmc_probe(struct of_device *ofdev, | 321 | static int pmc_probe(struct of_device *ofdev, |
@@ -333,12 +370,23 @@ static int pmc_probe(struct of_device *ofdev, | |||
333 | goto out_pmc; | 370 | goto out_pmc; |
334 | } | 371 | } |
335 | 372 | ||
373 | if (has_deep_sleep) { | ||
374 | syscr_regs = ioremap(immrbase + IMMR_SYSCR_OFFSET, | ||
375 | sizeof(*syscr_regs)); | ||
376 | if (!syscr_regs) { | ||
377 | ret = -ENOMEM; | ||
378 | goto out_syscr; | ||
379 | } | ||
380 | } | ||
381 | |||
336 | if (is_pci_agent) | 382 | if (is_pci_agent) |
337 | mpc83xx_set_agent(); | 383 | mpc83xx_set_agent(); |
338 | 384 | ||
339 | suspend_set_ops(&mpc83xx_suspend_ops); | 385 | suspend_set_ops(&mpc83xx_suspend_ops); |
340 | return 0; | 386 | return 0; |
341 | 387 | ||
388 | out_syscr: | ||
389 | iounmap(clock_regs); | ||
342 | out_pmc: | 390 | out_pmc: |
343 | iounmap(pmc_regs); | 391 | iounmap(pmc_regs); |
344 | out: | 392 | out: |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index c5028a2e5a58..cc29c0f5300d 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
@@ -86,7 +86,7 @@ static int mpc8568_fixup_125_clock(struct phy_device *phydev) | |||
86 | scr = phy_read(phydev, MV88E1111_SCR); | 86 | scr = phy_read(phydev, MV88E1111_SCR); |
87 | 87 | ||
88 | if (scr < 0) | 88 | if (scr < 0) |
89 | return err; | 89 | return scr; |
90 | 90 | ||
91 | err = phy_write(phydev, MV88E1111_SCR, scr | 0x0008); | 91 | err = phy_write(phydev, MV88E1111_SCR, scr | 0x0008); |
92 | 92 | ||
@@ -338,7 +338,8 @@ static void __init mpc85xx_mds_pic_init(void) | |||
338 | } | 338 | } |
339 | 339 | ||
340 | mpic = mpic_alloc(np, r.start, | 340 | mpic = mpic_alloc(np, r.start, |
341 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | 341 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | |
342 | MPIC_BROKEN_FRR_NIRQS, | ||
342 | 0, 256, " OpenPIC "); | 343 | 0, 256, " OpenPIC "); |
343 | BUG_ON(mpic == NULL); | 344 | BUG_ON(mpic == NULL); |
344 | of_node_put(np); | 345 | of_node_put(np); |
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 04160a4cc699..a15f582300d8 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c | |||
@@ -46,6 +46,7 @@ smp_85xx_kick_cpu(int nr) | |||
46 | __iomem u32 *bptr_vaddr; | 46 | __iomem u32 *bptr_vaddr; |
47 | struct device_node *np; | 47 | struct device_node *np; |
48 | int n = 0; | 48 | int n = 0; |
49 | int ioremappable; | ||
49 | 50 | ||
50 | WARN_ON (nr < 0 || nr >= NR_CPUS); | 51 | WARN_ON (nr < 0 || nr >= NR_CPUS); |
51 | 52 | ||
@@ -59,21 +60,37 @@ smp_85xx_kick_cpu(int nr) | |||
59 | return; | 60 | return; |
60 | } | 61 | } |
61 | 62 | ||
63 | /* | ||
64 | * A secondary core could be in a spinloop in the bootpage | ||
65 | * (0xfffff000), somewhere in highmem, or somewhere in lowmem. | ||
66 | * The bootpage and highmem can be accessed via ioremap(), but | ||
67 | * we need to directly access the spinloop if its in lowmem. | ||
68 | */ | ||
69 | ioremappable = *cpu_rel_addr > virt_to_phys(high_memory); | ||
70 | |||
62 | /* Map the spin table */ | 71 | /* Map the spin table */ |
63 | bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY); | 72 | if (ioremappable) |
73 | bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY); | ||
74 | else | ||
75 | bptr_vaddr = phys_to_virt(*cpu_rel_addr); | ||
64 | 76 | ||
65 | local_irq_save(flags); | 77 | local_irq_save(flags); |
66 | 78 | ||
67 | out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr); | 79 | out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr); |
68 | out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); | 80 | out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); |
69 | 81 | ||
82 | if (!ioremappable) | ||
83 | flush_dcache_range((ulong)bptr_vaddr, | ||
84 | (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY)); | ||
85 | |||
70 | /* Wait a bit for the CPU to ack. */ | 86 | /* Wait a bit for the CPU to ack. */ |
71 | while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) | 87 | while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) |
72 | mdelay(1); | 88 | mdelay(1); |
73 | 89 | ||
74 | local_irq_restore(flags); | 90 | local_irq_restore(flags); |
75 | 91 | ||
76 | iounmap(bptr_vaddr); | 92 | if (ioremappable) |
93 | iounmap(bptr_vaddr); | ||
77 | 94 | ||
78 | pr_debug("waited %d msecs for CPU #%d.\n", n, nr); | 95 | pr_debug("waited %d msecs for CPU #%d.\n", n, nr); |
79 | } | 96 | } |
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 2eab27a94cc9..fa0f690d3867 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype | |||
@@ -311,7 +311,7 @@ config NR_CPUS | |||
311 | 311 | ||
312 | config NOT_COHERENT_CACHE | 312 | config NOT_COHERENT_CACHE |
313 | bool | 313 | bool |
314 | depends on 4xx || 8xx || E200 || PPC_MPC512x | 314 | depends on 4xx || 8xx || E200 || PPC_MPC512x || GAMECUBE_COMMON |
315 | default y | 315 | default y |
316 | 316 | ||
317 | config CHECK_CACHE_COHERENCY | 317 | config CHECK_CACHE_COHERENCY |
diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c index 9290a7a442d0..fb4eb0df054c 100644 --- a/arch/powerpc/platforms/amigaone/setup.c +++ b/arch/powerpc/platforms/amigaone/setup.c | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/seq_file.h> | 16 | #include <linux/seq_file.h> |
17 | #include <linux/utsrelease.h> | 17 | #include <generated/utsrelease.h> |
18 | 18 | ||
19 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
20 | #include <asm/cputable.h> | 20 | #include <asm/cputable.h> |
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index b93f877ba504..b9d5d678aa44 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile | |||
@@ -13,10 +13,8 @@ SPU_CC := $(SPU_CROSS)gcc | |||
13 | SPU_AS := $(SPU_CROSS)gcc | 13 | SPU_AS := $(SPU_CROSS)gcc |
14 | SPU_LD := $(SPU_CROSS)ld | 14 | SPU_LD := $(SPU_CROSS)ld |
15 | SPU_OBJCOPY := $(SPU_CROSS)objcopy | 15 | SPU_OBJCOPY := $(SPU_CROSS)objcopy |
16 | SPU_CFLAGS := -O2 -Wall -I$(srctree)/include \ | 16 | SPU_CFLAGS := -O2 -Wall -I$(srctree)/include -D__KERNEL__ |
17 | -I$(objtree)/include2 -D__KERNEL__ | 17 | SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include -D__KERNEL__ |
18 | SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include \ | ||
19 | -I$(objtree)/include2 -D__KERNEL__ | ||
20 | SPU_LDFLAGS := -N -Ttext=0x0 | 18 | SPU_LDFLAGS := -N -Ttext=0x0 |
21 | 19 | ||
22 | $(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h | 20 | $(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h |
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index c4d4a19235e0..eea120229cdb 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c | |||
@@ -54,7 +54,7 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer, | |||
54 | */ | 54 | */ |
55 | static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset) | 55 | static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset) |
56 | { | 56 | { |
57 | unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 57 | unsigned long limit = rlimit(RLIMIT_CORE); |
58 | ssize_t written; | 58 | ssize_t written; |
59 | 59 | ||
60 | if (*foffset + nr > limit) | 60 | if (*foffset + nr > limit) |
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 52f3df3b4ca0..8f41685d8f42 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/reboot.h> | 23 | #include <linux/reboot.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/utsrelease.h> | 26 | #include <generated/utsrelease.h> |
27 | #include <linux/adb.h> | 27 | #include <linux/adb.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 291ac9d8cbee..524d971a1478 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig | |||
@@ -90,3 +90,36 @@ config MPC10X_OPENPIC | |||
90 | config MPC10X_STORE_GATHERING | 90 | config MPC10X_STORE_GATHERING |
91 | bool "Enable MPC10x store gathering" | 91 | bool "Enable MPC10x store gathering" |
92 | depends on MPC10X_BRIDGE | 92 | depends on MPC10X_BRIDGE |
93 | |||
94 | config GAMECUBE_COMMON | ||
95 | bool | ||
96 | |||
97 | config USBGECKO_UDBG | ||
98 | bool "USB Gecko udbg console for the Nintendo GameCube/Wii" | ||
99 | depends on GAMECUBE_COMMON | ||
100 | help | ||
101 | If you say yes to this option, support will be included for the | ||
102 | USB Gecko adapter as an udbg console. | ||
103 | The USB Gecko is a EXI to USB Serial converter that can be plugged | ||
104 | into a memcard slot in the Nintendo GameCube/Wii. | ||
105 | |||
106 | This driver bypasses the EXI layer completely. | ||
107 | |||
108 | If in doubt, say N here. | ||
109 | |||
110 | config GAMECUBE | ||
111 | bool "Nintendo-GameCube" | ||
112 | depends on EMBEDDED6xx | ||
113 | select GAMECUBE_COMMON | ||
114 | help | ||
115 | Select GAMECUBE if configuring for the Nintendo GameCube. | ||
116 | More information at: <http://gc-linux.sourceforge.net/> | ||
117 | |||
118 | config WII | ||
119 | bool "Nintendo-Wii" | ||
120 | depends on EMBEDDED6xx | ||
121 | select GAMECUBE_COMMON | ||
122 | help | ||
123 | Select WII if configuring for the Nintendo Wii. | ||
124 | More information at: <http://gc-linux.sourceforge.net/> | ||
125 | |||
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile index 0773c08bd444..66c23e423f40 100644 --- a/arch/powerpc/platforms/embedded6xx/Makefile +++ b/arch/powerpc/platforms/embedded6xx/Makefile | |||
@@ -7,3 +7,7 @@ obj-$(CONFIG_STORCENTER) += storcenter.o | |||
7 | obj-$(CONFIG_PPC_HOLLY) += holly.o | 7 | obj-$(CONFIG_PPC_HOLLY) += holly.o |
8 | obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o | 8 | obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o |
9 | obj-$(CONFIG_PPC_C2K) += c2k.o | 9 | obj-$(CONFIG_PPC_C2K) += c2k.o |
10 | obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o | ||
11 | obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o | ||
12 | obj-$(CONFIG_GAMECUBE) += gamecube.o | ||
13 | obj-$(CONFIG_WII) += wii.o hlwd-pic.o | ||
diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c new file mode 100644 index 000000000000..c278bd3a8fec --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c | |||
@@ -0,0 +1,263 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/flipper-pic.c | ||
3 | * | ||
4 | * Nintendo GameCube/Wii "Flipper" interrupt controller support. | ||
5 | * Copyright (C) 2004-2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2007,2008,2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | #define DRV_MODULE_NAME "flipper-pic" | ||
15 | #define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | #include "flipper-pic.h" | ||
24 | |||
25 | #define FLIPPER_NR_IRQS 32 | ||
26 | |||
27 | /* | ||
28 | * Each interrupt has a corresponding bit in both | ||
29 | * the Interrupt Cause (ICR) and Interrupt Mask (IMR) registers. | ||
30 | * | ||
31 | * Enabling/disabling an interrupt line involves setting/clearing | ||
32 | * the corresponding bit in IMR. | ||
33 | * Except for the RSW interrupt, all interrupts get deasserted automatically | ||
34 | * when the source deasserts the interrupt. | ||
35 | */ | ||
36 | #define FLIPPER_ICR 0x00 | ||
37 | #define FLIPPER_ICR_RSS (1<<16) /* reset switch state */ | ||
38 | |||
39 | #define FLIPPER_IMR 0x04 | ||
40 | |||
41 | #define FLIPPER_RESET 0x24 | ||
42 | |||
43 | |||
44 | /* | ||
45 | * IRQ chip hooks. | ||
46 | * | ||
47 | */ | ||
48 | |||
49 | static void flipper_pic_mask_and_ack(unsigned int virq) | ||
50 | { | ||
51 | int irq = virq_to_hw(virq); | ||
52 | void __iomem *io_base = get_irq_chip_data(virq); | ||
53 | u32 mask = 1 << irq; | ||
54 | |||
55 | clrbits32(io_base + FLIPPER_IMR, mask); | ||
56 | /* this is at least needed for RSW */ | ||
57 | out_be32(io_base + FLIPPER_ICR, mask); | ||
58 | } | ||
59 | |||
60 | static void flipper_pic_ack(unsigned int virq) | ||
61 | { | ||
62 | int irq = virq_to_hw(virq); | ||
63 | void __iomem *io_base = get_irq_chip_data(virq); | ||
64 | |||
65 | /* this is at least needed for RSW */ | ||
66 | out_be32(io_base + FLIPPER_ICR, 1 << irq); | ||
67 | } | ||
68 | |||
69 | static void flipper_pic_mask(unsigned int virq) | ||
70 | { | ||
71 | int irq = virq_to_hw(virq); | ||
72 | void __iomem *io_base = get_irq_chip_data(virq); | ||
73 | |||
74 | clrbits32(io_base + FLIPPER_IMR, 1 << irq); | ||
75 | } | ||
76 | |||
77 | static void flipper_pic_unmask(unsigned int virq) | ||
78 | { | ||
79 | int irq = virq_to_hw(virq); | ||
80 | void __iomem *io_base = get_irq_chip_data(virq); | ||
81 | |||
82 | setbits32(io_base + FLIPPER_IMR, 1 << irq); | ||
83 | } | ||
84 | |||
85 | |||
86 | static struct irq_chip flipper_pic = { | ||
87 | .name = "flipper-pic", | ||
88 | .ack = flipper_pic_ack, | ||
89 | .mask_ack = flipper_pic_mask_and_ack, | ||
90 | .mask = flipper_pic_mask, | ||
91 | .unmask = flipper_pic_unmask, | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * IRQ host hooks. | ||
96 | * | ||
97 | */ | ||
98 | |||
99 | static struct irq_host *flipper_irq_host; | ||
100 | |||
101 | static int flipper_pic_map(struct irq_host *h, unsigned int virq, | ||
102 | irq_hw_number_t hwirq) | ||
103 | { | ||
104 | set_irq_chip_data(virq, h->host_data); | ||
105 | irq_to_desc(virq)->status |= IRQ_LEVEL; | ||
106 | set_irq_chip_and_handler(virq, &flipper_pic, handle_level_irq); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static void flipper_pic_unmap(struct irq_host *h, unsigned int irq) | ||
111 | { | ||
112 | set_irq_chip_data(irq, NULL); | ||
113 | set_irq_chip(irq, NULL); | ||
114 | } | ||
115 | |||
116 | static int flipper_pic_match(struct irq_host *h, struct device_node *np) | ||
117 | { | ||
118 | return 1; | ||
119 | } | ||
120 | |||
121 | |||
122 | static struct irq_host_ops flipper_irq_host_ops = { | ||
123 | .map = flipper_pic_map, | ||
124 | .unmap = flipper_pic_unmap, | ||
125 | .match = flipper_pic_match, | ||
126 | }; | ||
127 | |||
128 | /* | ||
129 | * Platform hooks. | ||
130 | * | ||
131 | */ | ||
132 | |||
133 | static void __flipper_quiesce(void __iomem *io_base) | ||
134 | { | ||
135 | /* mask and ack all IRQs */ | ||
136 | out_be32(io_base + FLIPPER_IMR, 0x00000000); | ||
137 | out_be32(io_base + FLIPPER_ICR, 0xffffffff); | ||
138 | } | ||
139 | |||
140 | struct irq_host * __init flipper_pic_init(struct device_node *np) | ||
141 | { | ||
142 | struct device_node *pi; | ||
143 | struct irq_host *irq_host = NULL; | ||
144 | struct resource res; | ||
145 | void __iomem *io_base; | ||
146 | int retval; | ||
147 | |||
148 | pi = of_get_parent(np); | ||
149 | if (!pi) { | ||
150 | pr_err("no parent found\n"); | ||
151 | goto out; | ||
152 | } | ||
153 | if (!of_device_is_compatible(pi, "nintendo,flipper-pi")) { | ||
154 | pr_err("unexpected parent compatible\n"); | ||
155 | goto out; | ||
156 | } | ||
157 | |||
158 | retval = of_address_to_resource(pi, 0, &res); | ||
159 | if (retval) { | ||
160 | pr_err("no io memory range found\n"); | ||
161 | goto out; | ||
162 | } | ||
163 | io_base = ioremap(res.start, resource_size(&res)); | ||
164 | |||
165 | pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base); | ||
166 | |||
167 | __flipper_quiesce(io_base); | ||
168 | |||
169 | irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS, | ||
170 | &flipper_irq_host_ops, -1); | ||
171 | if (!irq_host) { | ||
172 | pr_err("failed to allocate irq_host\n"); | ||
173 | return NULL; | ||
174 | } | ||
175 | |||
176 | irq_host->host_data = io_base; | ||
177 | |||
178 | out: | ||
179 | return irq_host; | ||
180 | } | ||
181 | |||
182 | unsigned int flipper_pic_get_irq(void) | ||
183 | { | ||
184 | void __iomem *io_base = flipper_irq_host->host_data; | ||
185 | int irq; | ||
186 | u32 irq_status; | ||
187 | |||
188 | irq_status = in_be32(io_base + FLIPPER_ICR) & | ||
189 | in_be32(io_base + FLIPPER_IMR); | ||
190 | if (irq_status == 0) | ||
191 | return NO_IRQ; /* no more IRQs pending */ | ||
192 | |||
193 | irq = __ffs(irq_status); | ||
194 | return irq_linear_revmap(flipper_irq_host, irq); | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Probe function. | ||
199 | * | ||
200 | */ | ||
201 | |||
202 | void __init flipper_pic_probe(void) | ||
203 | { | ||
204 | struct device_node *np; | ||
205 | |||
206 | np = of_find_compatible_node(NULL, NULL, "nintendo,flipper-pic"); | ||
207 | BUG_ON(!np); | ||
208 | |||
209 | flipper_irq_host = flipper_pic_init(np); | ||
210 | BUG_ON(!flipper_irq_host); | ||
211 | |||
212 | irq_set_default_host(flipper_irq_host); | ||
213 | |||
214 | of_node_put(np); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Misc functions related to the flipper chipset. | ||
219 | * | ||
220 | */ | ||
221 | |||
222 | /** | ||
223 | * flipper_quiesce() - quiesce flipper irq controller | ||
224 | * | ||
225 | * Mask and ack all interrupt sources. | ||
226 | * | ||
227 | */ | ||
228 | void flipper_quiesce(void) | ||
229 | { | ||
230 | void __iomem *io_base = flipper_irq_host->host_data; | ||
231 | |||
232 | __flipper_quiesce(io_base); | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Resets the platform. | ||
237 | */ | ||
238 | void flipper_platform_reset(void) | ||
239 | { | ||
240 | void __iomem *io_base; | ||
241 | |||
242 | if (flipper_irq_host && flipper_irq_host->host_data) { | ||
243 | io_base = flipper_irq_host->host_data; | ||
244 | out_8(io_base + FLIPPER_RESET, 0x00); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * Returns non-zero if the reset button is pressed. | ||
250 | */ | ||
251 | int flipper_is_reset_button_pressed(void) | ||
252 | { | ||
253 | void __iomem *io_base; | ||
254 | u32 icr; | ||
255 | |||
256 | if (flipper_irq_host && flipper_irq_host->host_data) { | ||
257 | io_base = flipper_irq_host->host_data; | ||
258 | icr = in_be32(io_base + FLIPPER_ICR); | ||
259 | return !(icr & FLIPPER_ICR_RSS); | ||
260 | } | ||
261 | return 0; | ||
262 | } | ||
263 | |||
diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.h b/arch/powerpc/platforms/embedded6xx/flipper-pic.h new file mode 100644 index 000000000000..e339186b5663 --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/flipper-pic.h | ||
3 | * | ||
4 | * Nintendo GameCube/Wii "Flipper" interrupt controller support. | ||
5 | * Copyright (C) 2004-2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2007,2008,2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __FLIPPER_PIC_H | ||
16 | #define __FLIPPER_PIC_H | ||
17 | |||
18 | unsigned int flipper_pic_get_irq(void); | ||
19 | void __init flipper_pic_probe(void); | ||
20 | |||
21 | void flipper_quiesce(void); | ||
22 | void flipper_platform_reset(void); | ||
23 | int flipper_is_reset_button_pressed(void); | ||
24 | |||
25 | #endif | ||
diff --git a/arch/powerpc/platforms/embedded6xx/gamecube.c b/arch/powerpc/platforms/embedded6xx/gamecube.c new file mode 100644 index 000000000000..1106fd99627f --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/gamecube.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/gamecube.c | ||
3 | * | ||
4 | * Nintendo GameCube board-specific support | ||
5 | * Copyright (C) 2004-2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2007,2008,2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/kexec.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/prom.h> | ||
25 | #include <asm/time.h> | ||
26 | #include <asm/udbg.h> | ||
27 | |||
28 | #include "flipper-pic.h" | ||
29 | #include "usbgecko_udbg.h" | ||
30 | |||
31 | |||
32 | static void gamecube_spin(void) | ||
33 | { | ||
34 | /* spin until power button pressed */ | ||
35 | for (;;) | ||
36 | cpu_relax(); | ||
37 | } | ||
38 | |||
39 | static void gamecube_restart(char *cmd) | ||
40 | { | ||
41 | local_irq_disable(); | ||
42 | flipper_platform_reset(); | ||
43 | gamecube_spin(); | ||
44 | } | ||
45 | |||
46 | static void gamecube_power_off(void) | ||
47 | { | ||
48 | local_irq_disable(); | ||
49 | gamecube_spin(); | ||
50 | } | ||
51 | |||
52 | static void gamecube_halt(void) | ||
53 | { | ||
54 | gamecube_restart(NULL); | ||
55 | } | ||
56 | |||
57 | static void __init gamecube_init_early(void) | ||
58 | { | ||
59 | ug_udbg_init(); | ||
60 | } | ||
61 | |||
62 | static int __init gamecube_probe(void) | ||
63 | { | ||
64 | unsigned long dt_root; | ||
65 | |||
66 | dt_root = of_get_flat_dt_root(); | ||
67 | if (!of_flat_dt_is_compatible(dt_root, "nintendo,gamecube")) | ||
68 | return 0; | ||
69 | |||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | static void gamecube_shutdown(void) | ||
74 | { | ||
75 | flipper_quiesce(); | ||
76 | } | ||
77 | |||
78 | #ifdef CONFIG_KEXEC | ||
79 | static int gamecube_kexec_prepare(struct kimage *image) | ||
80 | { | ||
81 | return 0; | ||
82 | } | ||
83 | #endif /* CONFIG_KEXEC */ | ||
84 | |||
85 | |||
86 | define_machine(gamecube) { | ||
87 | .name = "gamecube", | ||
88 | .probe = gamecube_probe, | ||
89 | .init_early = gamecube_init_early, | ||
90 | .restart = gamecube_restart, | ||
91 | .power_off = gamecube_power_off, | ||
92 | .halt = gamecube_halt, | ||
93 | .init_IRQ = flipper_pic_probe, | ||
94 | .get_irq = flipper_pic_get_irq, | ||
95 | .calibrate_decr = generic_calibrate_decr, | ||
96 | .progress = udbg_progress, | ||
97 | .machine_shutdown = gamecube_shutdown, | ||
98 | #ifdef CONFIG_KEXEC | ||
99 | .machine_kexec_prepare = gamecube_kexec_prepare, | ||
100 | #endif | ||
101 | }; | ||
102 | |||
103 | |||
104 | static struct of_device_id gamecube_of_bus[] = { | ||
105 | { .compatible = "nintendo,flipper", }, | ||
106 | { }, | ||
107 | }; | ||
108 | |||
109 | static int __init gamecube_device_probe(void) | ||
110 | { | ||
111 | if (!machine_is(gamecube)) | ||
112 | return 0; | ||
113 | |||
114 | of_platform_bus_probe(NULL, gamecube_of_bus, NULL); | ||
115 | return 0; | ||
116 | } | ||
117 | device_initcall(gamecube_device_probe); | ||
118 | |||
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c new file mode 100644 index 000000000000..a771f91e215b --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/hlwd-pic.c | ||
3 | * | ||
4 | * Nintendo Wii "Hollywood" interrupt controller support. | ||
5 | * Copyright (C) 2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | #define DRV_MODULE_NAME "hlwd-pic" | ||
15 | #define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | #include "hlwd-pic.h" | ||
24 | |||
25 | #define HLWD_NR_IRQS 32 | ||
26 | |||
27 | /* | ||
28 | * Each interrupt has a corresponding bit in both | ||
29 | * the Interrupt Cause (ICR) and Interrupt Mask (IMR) registers. | ||
30 | * | ||
31 | * Enabling/disabling an interrupt line involves asserting/clearing | ||
32 | * the corresponding bit in IMR. ACK'ing a request simply involves | ||
33 | * asserting the corresponding bit in ICR. | ||
34 | */ | ||
35 | #define HW_BROADWAY_ICR 0x00 | ||
36 | #define HW_BROADWAY_IMR 0x04 | ||
37 | |||
38 | |||
39 | /* | ||
40 | * IRQ chip hooks. | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | static void hlwd_pic_mask_and_ack(unsigned int virq) | ||
45 | { | ||
46 | int irq = virq_to_hw(virq); | ||
47 | void __iomem *io_base = get_irq_chip_data(virq); | ||
48 | u32 mask = 1 << irq; | ||
49 | |||
50 | clrbits32(io_base + HW_BROADWAY_IMR, mask); | ||
51 | out_be32(io_base + HW_BROADWAY_ICR, mask); | ||
52 | } | ||
53 | |||
54 | static void hlwd_pic_ack(unsigned int virq) | ||
55 | { | ||
56 | int irq = virq_to_hw(virq); | ||
57 | void __iomem *io_base = get_irq_chip_data(virq); | ||
58 | |||
59 | out_be32(io_base + HW_BROADWAY_ICR, 1 << irq); | ||
60 | } | ||
61 | |||
62 | static void hlwd_pic_mask(unsigned int virq) | ||
63 | { | ||
64 | int irq = virq_to_hw(virq); | ||
65 | void __iomem *io_base = get_irq_chip_data(virq); | ||
66 | |||
67 | clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq); | ||
68 | } | ||
69 | |||
70 | static void hlwd_pic_unmask(unsigned int virq) | ||
71 | { | ||
72 | int irq = virq_to_hw(virq); | ||
73 | void __iomem *io_base = get_irq_chip_data(virq); | ||
74 | |||
75 | setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); | ||
76 | } | ||
77 | |||
78 | |||
79 | static struct irq_chip hlwd_pic = { | ||
80 | .name = "hlwd-pic", | ||
81 | .ack = hlwd_pic_ack, | ||
82 | .mask_ack = hlwd_pic_mask_and_ack, | ||
83 | .mask = hlwd_pic_mask, | ||
84 | .unmask = hlwd_pic_unmask, | ||
85 | }; | ||
86 | |||
87 | /* | ||
88 | * IRQ host hooks. | ||
89 | * | ||
90 | */ | ||
91 | |||
92 | static struct irq_host *hlwd_irq_host; | ||
93 | |||
94 | static int hlwd_pic_map(struct irq_host *h, unsigned int virq, | ||
95 | irq_hw_number_t hwirq) | ||
96 | { | ||
97 | set_irq_chip_data(virq, h->host_data); | ||
98 | irq_to_desc(virq)->status |= IRQ_LEVEL; | ||
99 | set_irq_chip_and_handler(virq, &hlwd_pic, handle_level_irq); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static void hlwd_pic_unmap(struct irq_host *h, unsigned int irq) | ||
104 | { | ||
105 | set_irq_chip_data(irq, NULL); | ||
106 | set_irq_chip(irq, NULL); | ||
107 | } | ||
108 | |||
109 | static struct irq_host_ops hlwd_irq_host_ops = { | ||
110 | .map = hlwd_pic_map, | ||
111 | .unmap = hlwd_pic_unmap, | ||
112 | }; | ||
113 | |||
114 | static unsigned int __hlwd_pic_get_irq(struct irq_host *h) | ||
115 | { | ||
116 | void __iomem *io_base = h->host_data; | ||
117 | int irq; | ||
118 | u32 irq_status; | ||
119 | |||
120 | irq_status = in_be32(io_base + HW_BROADWAY_ICR) & | ||
121 | in_be32(io_base + HW_BROADWAY_IMR); | ||
122 | if (irq_status == 0) | ||
123 | return NO_IRQ; /* no more IRQs pending */ | ||
124 | |||
125 | irq = __ffs(irq_status); | ||
126 | return irq_linear_revmap(h, irq); | ||
127 | } | ||
128 | |||
129 | static void hlwd_pic_irq_cascade(unsigned int cascade_virq, | ||
130 | struct irq_desc *desc) | ||
131 | { | ||
132 | struct irq_host *irq_host = get_irq_data(cascade_virq); | ||
133 | unsigned int virq; | ||
134 | |||
135 | raw_spin_lock(&desc->lock); | ||
136 | desc->chip->mask(cascade_virq); /* IRQ_LEVEL */ | ||
137 | raw_spin_unlock(&desc->lock); | ||
138 | |||
139 | virq = __hlwd_pic_get_irq(irq_host); | ||
140 | if (virq != NO_IRQ) | ||
141 | generic_handle_irq(virq); | ||
142 | else | ||
143 | pr_err("spurious interrupt!\n"); | ||
144 | |||
145 | raw_spin_lock(&desc->lock); | ||
146 | desc->chip->ack(cascade_virq); /* IRQ_LEVEL */ | ||
147 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | ||
148 | desc->chip->unmask(cascade_virq); | ||
149 | raw_spin_unlock(&desc->lock); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Platform hooks. | ||
154 | * | ||
155 | */ | ||
156 | |||
157 | static void __hlwd_quiesce(void __iomem *io_base) | ||
158 | { | ||
159 | /* mask and ack all IRQs */ | ||
160 | out_be32(io_base + HW_BROADWAY_IMR, 0); | ||
161 | out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff); | ||
162 | } | ||
163 | |||
164 | struct irq_host *hlwd_pic_init(struct device_node *np) | ||
165 | { | ||
166 | struct irq_host *irq_host; | ||
167 | struct resource res; | ||
168 | void __iomem *io_base; | ||
169 | int retval; | ||
170 | |||
171 | retval = of_address_to_resource(np, 0, &res); | ||
172 | if (retval) { | ||
173 | pr_err("no io memory range found\n"); | ||
174 | return NULL; | ||
175 | } | ||
176 | io_base = ioremap(res.start, resource_size(&res)); | ||
177 | if (!io_base) { | ||
178 | pr_err("ioremap failed\n"); | ||
179 | return NULL; | ||
180 | } | ||
181 | |||
182 | pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base); | ||
183 | |||
184 | __hlwd_quiesce(io_base); | ||
185 | |||
186 | irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, HLWD_NR_IRQS, | ||
187 | &hlwd_irq_host_ops, -1); | ||
188 | if (!irq_host) { | ||
189 | pr_err("failed to allocate irq_host\n"); | ||
190 | return NULL; | ||
191 | } | ||
192 | irq_host->host_data = io_base; | ||
193 | |||
194 | return irq_host; | ||
195 | } | ||
196 | |||
197 | unsigned int hlwd_pic_get_irq(void) | ||
198 | { | ||
199 | return __hlwd_pic_get_irq(hlwd_irq_host); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Probe function. | ||
204 | * | ||
205 | */ | ||
206 | |||
207 | void hlwd_pic_probe(void) | ||
208 | { | ||
209 | struct irq_host *host; | ||
210 | struct device_node *np; | ||
211 | const u32 *interrupts; | ||
212 | int cascade_virq; | ||
213 | |||
214 | for_each_compatible_node(np, NULL, "nintendo,hollywood-pic") { | ||
215 | interrupts = of_get_property(np, "interrupts", NULL); | ||
216 | if (interrupts) { | ||
217 | host = hlwd_pic_init(np); | ||
218 | BUG_ON(!host); | ||
219 | cascade_virq = irq_of_parse_and_map(np, 0); | ||
220 | set_irq_data(cascade_virq, host); | ||
221 | set_irq_chained_handler(cascade_virq, | ||
222 | hlwd_pic_irq_cascade); | ||
223 | hlwd_irq_host = host; | ||
224 | break; | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * hlwd_quiesce() - quiesce hollywood irq controller | ||
231 | * | ||
232 | * Mask and ack all interrupt sources. | ||
233 | * | ||
234 | */ | ||
235 | void hlwd_quiesce(void) | ||
236 | { | ||
237 | void __iomem *io_base = hlwd_irq_host->host_data; | ||
238 | |||
239 | __hlwd_quiesce(io_base); | ||
240 | } | ||
241 | |||
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.h b/arch/powerpc/platforms/embedded6xx/hlwd-pic.h new file mode 100644 index 000000000000..d2e5a092761e --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/hlwd-pic.h | ||
3 | * | ||
4 | * Nintendo Wii "Hollywood" interrupt controller support. | ||
5 | * Copyright (C) 2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __HLWD_PIC_H | ||
16 | #define __HLWD_PIC_H | ||
17 | |||
18 | extern unsigned int hlwd_pic_get_irq(void); | ||
19 | extern void hlwd_pic_probe(void); | ||
20 | extern void hlwd_quiesce(void); | ||
21 | |||
22 | #endif | ||
diff --git a/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c b/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c new file mode 100644 index 000000000000..20a8ed91962e --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c | ||
3 | * | ||
4 | * udbg serial input/output routines for the USB Gecko adapter. | ||
5 | * Copyright (C) 2008-2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2008,2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <mm/mmu_decl.h> | ||
16 | |||
17 | #include <asm/io.h> | ||
18 | #include <asm/prom.h> | ||
19 | #include <asm/udbg.h> | ||
20 | #include <asm/fixmap.h> | ||
21 | |||
22 | #include "usbgecko_udbg.h" | ||
23 | |||
24 | |||
25 | #define EXI_CLK_32MHZ 5 | ||
26 | |||
27 | #define EXI_CSR 0x00 | ||
28 | #define EXI_CSR_CLKMASK (0x7<<4) | ||
29 | #define EXI_CSR_CLK_32MHZ (EXI_CLK_32MHZ<<4) | ||
30 | #define EXI_CSR_CSMASK (0x7<<7) | ||
31 | #define EXI_CSR_CS_0 (0x1<<7) /* Chip Select 001 */ | ||
32 | |||
33 | #define EXI_CR 0x0c | ||
34 | #define EXI_CR_TSTART (1<<0) | ||
35 | #define EXI_CR_WRITE (1<<2) | ||
36 | #define EXI_CR_READ_WRITE (2<<2) | ||
37 | #define EXI_CR_TLEN(len) (((len)-1)<<4) | ||
38 | |||
39 | #define EXI_DATA 0x10 | ||
40 | |||
41 | #define UG_READ_ATTEMPTS 100 | ||
42 | #define UG_WRITE_ATTEMPTS 100 | ||
43 | |||
44 | |||
45 | static void __iomem *ug_io_base; | ||
46 | |||
47 | /* | ||
48 | * Performs one input/output transaction between the exi host and the usbgecko. | ||
49 | */ | ||
50 | static u32 ug_io_transaction(u32 in) | ||
51 | { | ||
52 | u32 __iomem *csr_reg = ug_io_base + EXI_CSR; | ||
53 | u32 __iomem *data_reg = ug_io_base + EXI_DATA; | ||
54 | u32 __iomem *cr_reg = ug_io_base + EXI_CR; | ||
55 | u32 csr, data, cr; | ||
56 | |||
57 | /* select */ | ||
58 | csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0; | ||
59 | out_be32(csr_reg, csr); | ||
60 | |||
61 | /* read/write */ | ||
62 | data = in; | ||
63 | out_be32(data_reg, data); | ||
64 | cr = EXI_CR_TLEN(2) | EXI_CR_READ_WRITE | EXI_CR_TSTART; | ||
65 | out_be32(cr_reg, cr); | ||
66 | |||
67 | while (in_be32(cr_reg) & EXI_CR_TSTART) | ||
68 | barrier(); | ||
69 | |||
70 | /* deselect */ | ||
71 | out_be32(csr_reg, 0); | ||
72 | |||
73 | /* result */ | ||
74 | data = in_be32(data_reg); | ||
75 | |||
76 | return data; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Returns true if an usbgecko adapter is found. | ||
81 | */ | ||
82 | static int ug_is_adapter_present(void) | ||
83 | { | ||
84 | if (!ug_io_base) | ||
85 | return 0; | ||
86 | |||
87 | return ug_io_transaction(0x90000000) == 0x04700000; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Returns true if the TX fifo is ready for transmission. | ||
92 | */ | ||
93 | static int ug_is_txfifo_ready(void) | ||
94 | { | ||
95 | return ug_io_transaction(0xc0000000) & 0x04000000; | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Tries to transmit a character. | ||
100 | * If the TX fifo is not ready the result is undefined. | ||
101 | */ | ||
102 | static void ug_raw_putc(char ch) | ||
103 | { | ||
104 | ug_io_transaction(0xb0000000 | (ch << 20)); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Transmits a character. | ||
109 | * It silently fails if the TX fifo is not ready after a number of retries. | ||
110 | */ | ||
111 | static void ug_putc(char ch) | ||
112 | { | ||
113 | int count = UG_WRITE_ATTEMPTS; | ||
114 | |||
115 | if (!ug_io_base) | ||
116 | return; | ||
117 | |||
118 | if (ch == '\n') | ||
119 | ug_putc('\r'); | ||
120 | |||
121 | while (!ug_is_txfifo_ready() && count--) | ||
122 | barrier(); | ||
123 | if (count >= 0) | ||
124 | ug_raw_putc(ch); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Returns true if the RX fifo is ready for transmission. | ||
129 | */ | ||
130 | static int ug_is_rxfifo_ready(void) | ||
131 | { | ||
132 | return ug_io_transaction(0xd0000000) & 0x04000000; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Tries to receive a character. | ||
137 | * If a character is unavailable the function returns -1. | ||
138 | */ | ||
139 | static int ug_raw_getc(void) | ||
140 | { | ||
141 | u32 data = ug_io_transaction(0xa0000000); | ||
142 | if (data & 0x08000000) | ||
143 | return (data >> 16) & 0xff; | ||
144 | else | ||
145 | return -1; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Receives a character. | ||
150 | * It fails if the RX fifo is not ready after a number of retries. | ||
151 | */ | ||
152 | static int ug_getc(void) | ||
153 | { | ||
154 | int count = UG_READ_ATTEMPTS; | ||
155 | |||
156 | if (!ug_io_base) | ||
157 | return -1; | ||
158 | |||
159 | while (!ug_is_rxfifo_ready() && count--) | ||
160 | barrier(); | ||
161 | return ug_raw_getc(); | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * udbg functions. | ||
166 | * | ||
167 | */ | ||
168 | |||
169 | /* | ||
170 | * Transmits a character. | ||
171 | */ | ||
172 | void ug_udbg_putc(char ch) | ||
173 | { | ||
174 | ug_putc(ch); | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Receives a character. Waits until a character is available. | ||
179 | */ | ||
180 | static int ug_udbg_getc(void) | ||
181 | { | ||
182 | int ch; | ||
183 | |||
184 | while ((ch = ug_getc()) == -1) | ||
185 | barrier(); | ||
186 | return ch; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Receives a character. If a character is not available, returns -1. | ||
191 | */ | ||
192 | static int ug_udbg_getc_poll(void) | ||
193 | { | ||
194 | if (!ug_is_rxfifo_ready()) | ||
195 | return -1; | ||
196 | return ug_getc(); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Retrieves and prepares the virtual address needed to access the hardware. | ||
201 | */ | ||
202 | static void __iomem *ug_udbg_setup_exi_io_base(struct device_node *np) | ||
203 | { | ||
204 | void __iomem *exi_io_base = NULL; | ||
205 | phys_addr_t paddr; | ||
206 | const unsigned int *reg; | ||
207 | |||
208 | reg = of_get_property(np, "reg", NULL); | ||
209 | if (reg) { | ||
210 | paddr = of_translate_address(np, reg); | ||
211 | if (paddr) | ||
212 | exi_io_base = ioremap(paddr, reg[1]); | ||
213 | } | ||
214 | return exi_io_base; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Checks if a USB Gecko adapter is inserted in any memory card slot. | ||
219 | */ | ||
220 | static void __iomem *ug_udbg_probe(void __iomem *exi_io_base) | ||
221 | { | ||
222 | int i; | ||
223 | |||
224 | /* look for a usbgecko on memcard slots A and B */ | ||
225 | for (i = 0; i < 2; i++) { | ||
226 | ug_io_base = exi_io_base + 0x14 * i; | ||
227 | if (ug_is_adapter_present()) | ||
228 | break; | ||
229 | } | ||
230 | if (i == 2) | ||
231 | ug_io_base = NULL; | ||
232 | return ug_io_base; | ||
233 | |||
234 | } | ||
235 | |||
236 | /* | ||
237 | * USB Gecko udbg support initialization. | ||
238 | */ | ||
239 | void __init ug_udbg_init(void) | ||
240 | { | ||
241 | struct device_node *np; | ||
242 | void __iomem *exi_io_base; | ||
243 | |||
244 | if (ug_io_base) | ||
245 | udbg_printf("%s: early -> final\n", __func__); | ||
246 | |||
247 | np = of_find_compatible_node(NULL, NULL, "nintendo,flipper-exi"); | ||
248 | if (!np) { | ||
249 | udbg_printf("%s: EXI node not found\n", __func__); | ||
250 | goto done; | ||
251 | } | ||
252 | |||
253 | exi_io_base = ug_udbg_setup_exi_io_base(np); | ||
254 | if (!exi_io_base) { | ||
255 | udbg_printf("%s: failed to setup EXI io base\n", __func__); | ||
256 | goto done; | ||
257 | } | ||
258 | |||
259 | if (!ug_udbg_probe(exi_io_base)) { | ||
260 | udbg_printf("usbgecko_udbg: not found\n"); | ||
261 | iounmap(exi_io_base); | ||
262 | } else { | ||
263 | udbg_putc = ug_udbg_putc; | ||
264 | udbg_getc = ug_udbg_getc; | ||
265 | udbg_getc_poll = ug_udbg_getc_poll; | ||
266 | udbg_printf("usbgecko_udbg: ready\n"); | ||
267 | } | ||
268 | |||
269 | done: | ||
270 | if (np) | ||
271 | of_node_put(np); | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | #ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO | ||
276 | |||
277 | static phys_addr_t __init ug_early_grab_io_addr(void) | ||
278 | { | ||
279 | #if defined(CONFIG_GAMECUBE) | ||
280 | return 0x0c000000; | ||
281 | #elif defined(CONFIG_WII) | ||
282 | return 0x0d000000; | ||
283 | #else | ||
284 | #error Invalid platform for USB Gecko based early debugging. | ||
285 | #endif | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * USB Gecko early debug support initialization for udbg. | ||
290 | */ | ||
291 | void __init udbg_init_usbgecko(void) | ||
292 | { | ||
293 | void __iomem *early_debug_area; | ||
294 | void __iomem *exi_io_base; | ||
295 | |||
296 | /* | ||
297 | * At this point we have a BAT already setup that enables I/O | ||
298 | * to the EXI hardware. | ||
299 | * | ||
300 | * The BAT uses a virtual address range reserved at the fixmap. | ||
301 | * This must match the virtual address configured in | ||
302 | * head_32.S:setup_usbgecko_bat(). | ||
303 | */ | ||
304 | early_debug_area = (void __iomem *)__fix_to_virt(FIX_EARLY_DEBUG_BASE); | ||
305 | exi_io_base = early_debug_area + 0x00006800; | ||
306 | |||
307 | /* try to detect a USB Gecko */ | ||
308 | if (!ug_udbg_probe(exi_io_base)) | ||
309 | return; | ||
310 | |||
311 | /* we found a USB Gecko, load udbg hooks */ | ||
312 | udbg_putc = ug_udbg_putc; | ||
313 | udbg_getc = ug_udbg_getc; | ||
314 | udbg_getc_poll = ug_udbg_getc_poll; | ||
315 | |||
316 | /* | ||
317 | * Prepare again the same BAT for MMU_init. | ||
318 | * This allows udbg I/O to continue working after the MMU is | ||
319 | * turned on for real. | ||
320 | * It is safe to continue using the same virtual address as it is | ||
321 | * a reserved fixmap area. | ||
322 | */ | ||
323 | setbat(1, (unsigned long)early_debug_area, | ||
324 | ug_early_grab_io_addr(), 128*1024, PAGE_KERNEL_NCG); | ||
325 | } | ||
326 | |||
327 | #endif /* CONFIG_PPC_EARLY_DEBUG_USBGECKO */ | ||
328 | |||
diff --git a/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.h b/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.h new file mode 100644 index 000000000000..bb6cde4ad764 --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/usbgecko_udbg.h | ||
3 | * | ||
4 | * udbg serial input/output routines for the USB Gecko adapter. | ||
5 | * Copyright (C) 2008-2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2008,2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __USBGECKO_UDBG_H | ||
16 | #define __USBGECKO_UDBG_H | ||
17 | |||
18 | #ifdef CONFIG_USBGECKO_UDBG | ||
19 | |||
20 | extern void __init ug_udbg_init(void); | ||
21 | |||
22 | #else | ||
23 | |||
24 | static inline void __init ug_udbg_init(void) | ||
25 | { | ||
26 | } | ||
27 | |||
28 | #endif /* CONFIG_USBGECKO_UDBG */ | ||
29 | |||
30 | void __init udbg_init_usbgecko(void); | ||
31 | |||
32 | #endif /* __USBGECKO_UDBG_H */ | ||
diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c new file mode 100644 index 000000000000..57e5b608fa1a --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/wii.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/embedded6xx/wii.c | ||
3 | * | ||
4 | * Nintendo Wii board-specific support | ||
5 | * Copyright (C) 2008-2009 The GameCube Linux Team | ||
6 | * Copyright (C) 2008,2009 Albert Herranz | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | #define DRV_MODULE_NAME "wii" | ||
15 | #define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <linux/kexec.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/lmb.h> | ||
24 | #include <mm/mmu_decl.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/prom.h> | ||
29 | #include <asm/time.h> | ||
30 | #include <asm/udbg.h> | ||
31 | |||
32 | #include "flipper-pic.h" | ||
33 | #include "hlwd-pic.h" | ||
34 | #include "usbgecko_udbg.h" | ||
35 | |||
36 | /* control block */ | ||
37 | #define HW_CTRL_COMPATIBLE "nintendo,hollywood-control" | ||
38 | |||
39 | #define HW_CTRL_RESETS 0x94 | ||
40 | #define HW_CTRL_RESETS_SYS (1<<0) | ||
41 | |||
42 | /* gpio */ | ||
43 | #define HW_GPIO_COMPATIBLE "nintendo,hollywood-gpio" | ||
44 | |||
45 | #define HW_GPIO_BASE(idx) (idx * 0x20) | ||
46 | #define HW_GPIO_OUT(idx) (HW_GPIO_BASE(idx) + 0) | ||
47 | #define HW_GPIO_DIR(idx) (HW_GPIO_BASE(idx) + 4) | ||
48 | |||
49 | #define HW_GPIO_SHUTDOWN (1<<1) | ||
50 | #define HW_GPIO_SLOT_LED (1<<5) | ||
51 | #define HW_GPIO_SENSOR_BAR (1<<8) | ||
52 | |||
53 | |||
54 | static void __iomem *hw_ctrl; | ||
55 | static void __iomem *hw_gpio; | ||
56 | |||
57 | unsigned long wii_hole_start; | ||
58 | unsigned long wii_hole_size; | ||
59 | |||
60 | |||
61 | static int __init page_aligned(unsigned long x) | ||
62 | { | ||
63 | return !(x & (PAGE_SIZE-1)); | ||
64 | } | ||
65 | |||
66 | void __init wii_memory_fixups(void) | ||
67 | { | ||
68 | struct lmb_property *p = lmb.memory.region; | ||
69 | |||
70 | /* | ||
71 | * This is part of a workaround to allow the use of two | ||
72 | * discontiguous RAM ranges on the Wii, even if this is | ||
73 | * currently unsupported on 32-bit PowerPC Linux. | ||
74 | * | ||
75 | * We coealesce the two memory ranges of the Wii into a | ||
76 | * single range, then create a reservation for the "hole" | ||
77 | * between both ranges. | ||
78 | */ | ||
79 | |||
80 | BUG_ON(lmb.memory.cnt != 2); | ||
81 | BUG_ON(!page_aligned(p[0].base) || !page_aligned(p[1].base)); | ||
82 | |||
83 | p[0].size = _ALIGN_DOWN(p[0].size, PAGE_SIZE); | ||
84 | p[1].size = _ALIGN_DOWN(p[1].size, PAGE_SIZE); | ||
85 | |||
86 | wii_hole_start = p[0].base + p[0].size; | ||
87 | wii_hole_size = p[1].base - wii_hole_start; | ||
88 | |||
89 | pr_info("MEM1: <%08llx %08llx>\n", p[0].base, p[0].size); | ||
90 | pr_info("HOLE: <%08lx %08lx>\n", wii_hole_start, wii_hole_size); | ||
91 | pr_info("MEM2: <%08llx %08llx>\n", p[1].base, p[1].size); | ||
92 | |||
93 | p[0].size += wii_hole_size + p[1].size; | ||
94 | |||
95 | lmb.memory.cnt = 1; | ||
96 | lmb_analyze(); | ||
97 | |||
98 | /* reserve the hole */ | ||
99 | lmb_reserve(wii_hole_start, wii_hole_size); | ||
100 | |||
101 | /* allow ioremapping the address space in the hole */ | ||
102 | __allow_ioremap_reserved = 1; | ||
103 | } | ||
104 | |||
105 | unsigned long __init wii_mmu_mapin_mem2(unsigned long top) | ||
106 | { | ||
107 | unsigned long delta, size, bl; | ||
108 | unsigned long max_size = (256<<20); | ||
109 | |||
110 | /* MEM2 64MB@0x10000000 */ | ||
111 | delta = wii_hole_start + wii_hole_size; | ||
112 | size = top - delta; | ||
113 | for (bl = 128<<10; bl < max_size; bl <<= 1) { | ||
114 | if (bl * 2 > size) | ||
115 | break; | ||
116 | } | ||
117 | setbat(4, PAGE_OFFSET+delta, delta, bl, PAGE_KERNEL_X); | ||
118 | return delta + bl; | ||
119 | } | ||
120 | |||
121 | static void wii_spin(void) | ||
122 | { | ||
123 | local_irq_disable(); | ||
124 | for (;;) | ||
125 | cpu_relax(); | ||
126 | } | ||
127 | |||
128 | static void __iomem *wii_ioremap_hw_regs(char *name, char *compatible) | ||
129 | { | ||
130 | void __iomem *hw_regs = NULL; | ||
131 | struct device_node *np; | ||
132 | struct resource res; | ||
133 | int error = -ENODEV; | ||
134 | |||
135 | np = of_find_compatible_node(NULL, NULL, compatible); | ||
136 | if (!np) { | ||
137 | pr_err("no compatible node found for %s\n", compatible); | ||
138 | goto out; | ||
139 | } | ||
140 | error = of_address_to_resource(np, 0, &res); | ||
141 | if (error) { | ||
142 | pr_err("no valid reg found for %s\n", np->name); | ||
143 | goto out_put; | ||
144 | } | ||
145 | |||
146 | hw_regs = ioremap(res.start, resource_size(&res)); | ||
147 | if (hw_regs) { | ||
148 | pr_info("%s at 0x%08x mapped to 0x%p\n", name, | ||
149 | res.start, hw_regs); | ||
150 | } | ||
151 | |||
152 | out_put: | ||
153 | of_node_put(np); | ||
154 | out: | ||
155 | return hw_regs; | ||
156 | } | ||
157 | |||
158 | static void __init wii_setup_arch(void) | ||
159 | { | ||
160 | hw_ctrl = wii_ioremap_hw_regs("hw_ctrl", HW_CTRL_COMPATIBLE); | ||
161 | hw_gpio = wii_ioremap_hw_regs("hw_gpio", HW_GPIO_COMPATIBLE); | ||
162 | if (hw_gpio) { | ||
163 | /* turn off the front blue led and IR light */ | ||
164 | clrbits32(hw_gpio + HW_GPIO_OUT(0), | ||
165 | HW_GPIO_SLOT_LED | HW_GPIO_SENSOR_BAR); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static void wii_restart(char *cmd) | ||
170 | { | ||
171 | local_irq_disable(); | ||
172 | |||
173 | if (hw_ctrl) { | ||
174 | /* clear the system reset pin to cause a reset */ | ||
175 | clrbits32(hw_ctrl + HW_CTRL_RESETS, HW_CTRL_RESETS_SYS); | ||
176 | } | ||
177 | wii_spin(); | ||
178 | } | ||
179 | |||
180 | static void wii_power_off(void) | ||
181 | { | ||
182 | local_irq_disable(); | ||
183 | |||
184 | if (hw_gpio) { | ||
185 | /* make sure that the poweroff GPIO is configured as output */ | ||
186 | setbits32(hw_gpio + HW_GPIO_DIR(1), HW_GPIO_SHUTDOWN); | ||
187 | |||
188 | /* drive the poweroff GPIO high */ | ||
189 | setbits32(hw_gpio + HW_GPIO_OUT(1), HW_GPIO_SHUTDOWN); | ||
190 | } | ||
191 | wii_spin(); | ||
192 | } | ||
193 | |||
194 | static void wii_halt(void) | ||
195 | { | ||
196 | if (ppc_md.restart) | ||
197 | ppc_md.restart(NULL); | ||
198 | wii_spin(); | ||
199 | } | ||
200 | |||
201 | static void __init wii_init_early(void) | ||
202 | { | ||
203 | ug_udbg_init(); | ||
204 | } | ||
205 | |||
206 | static void __init wii_pic_probe(void) | ||
207 | { | ||
208 | flipper_pic_probe(); | ||
209 | hlwd_pic_probe(); | ||
210 | } | ||
211 | |||
212 | static int __init wii_probe(void) | ||
213 | { | ||
214 | unsigned long dt_root; | ||
215 | |||
216 | dt_root = of_get_flat_dt_root(); | ||
217 | if (!of_flat_dt_is_compatible(dt_root, "nintendo,wii")) | ||
218 | return 0; | ||
219 | |||
220 | return 1; | ||
221 | } | ||
222 | |||
223 | static void wii_shutdown(void) | ||
224 | { | ||
225 | hlwd_quiesce(); | ||
226 | flipper_quiesce(); | ||
227 | } | ||
228 | |||
229 | #ifdef CONFIG_KEXEC | ||
230 | static int wii_machine_kexec_prepare(struct kimage *image) | ||
231 | { | ||
232 | return 0; | ||
233 | } | ||
234 | #endif /* CONFIG_KEXEC */ | ||
235 | |||
236 | define_machine(wii) { | ||
237 | .name = "wii", | ||
238 | .probe = wii_probe, | ||
239 | .init_early = wii_init_early, | ||
240 | .setup_arch = wii_setup_arch, | ||
241 | .restart = wii_restart, | ||
242 | .power_off = wii_power_off, | ||
243 | .halt = wii_halt, | ||
244 | .init_IRQ = wii_pic_probe, | ||
245 | .get_irq = flipper_pic_get_irq, | ||
246 | .calibrate_decr = generic_calibrate_decr, | ||
247 | .progress = udbg_progress, | ||
248 | .machine_shutdown = wii_shutdown, | ||
249 | #ifdef CONFIG_KEXEC | ||
250 | .machine_kexec_prepare = wii_machine_kexec_prepare, | ||
251 | #endif | ||
252 | }; | ||
253 | |||
254 | static struct of_device_id wii_of_bus[] = { | ||
255 | { .compatible = "nintendo,hollywood", }, | ||
256 | { }, | ||
257 | }; | ||
258 | |||
259 | static int __init wii_device_probe(void) | ||
260 | { | ||
261 | if (!machine_is(wii)) | ||
262 | return 0; | ||
263 | |||
264 | of_platform_bus_probe(NULL, wii_of_bus, NULL); | ||
265 | return 0; | ||
266 | } | ||
267 | device_initcall(wii_device_probe); | ||
268 | |||
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 0d9343df35bc..6617915bcb1a 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c | |||
@@ -855,59 +855,58 @@ static int mf_get_boot_rtc(struct rtc_time *tm) | |||
855 | } | 855 | } |
856 | 856 | ||
857 | #ifdef CONFIG_PROC_FS | 857 | #ifdef CONFIG_PROC_FS |
858 | 858 | static int mf_cmdline_proc_show(struct seq_file *m, void *v) | |
859 | static int proc_mf_dump_cmdline(char *page, char **start, off_t off, | ||
860 | int count, int *eof, void *data) | ||
861 | { | 859 | { |
862 | int len; | 860 | char *page, *p; |
863 | char *p; | ||
864 | struct vsp_cmd_data vsp_cmd; | 861 | struct vsp_cmd_data vsp_cmd; |
865 | int rc; | 862 | int rc; |
866 | dma_addr_t dma_addr; | 863 | dma_addr_t dma_addr; |
867 | 864 | ||
868 | /* The HV appears to return no more than 256 bytes of command line */ | 865 | /* The HV appears to return no more than 256 bytes of command line */ |
869 | if (off >= 256) | 866 | page = kmalloc(256, GFP_KERNEL); |
870 | return 0; | 867 | if (!page) |
871 | if ((off + count) > 256) | 868 | return -ENOMEM; |
872 | count = 256 - off; | ||
873 | 869 | ||
874 | dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE); | 870 | dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE); |
875 | if (dma_addr == DMA_ERROR_CODE) | 871 | if (dma_addr == DMA_ERROR_CODE) { |
872 | kfree(page); | ||
876 | return -ENOMEM; | 873 | return -ENOMEM; |
877 | memset(page, 0, off + count); | 874 | } |
875 | memset(page, 0, 256); | ||
878 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); | 876 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); |
879 | vsp_cmd.cmd = 33; | 877 | vsp_cmd.cmd = 33; |
880 | vsp_cmd.sub_data.kern.token = dma_addr; | 878 | vsp_cmd.sub_data.kern.token = dma_addr; |
881 | vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; | 879 | vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; |
882 | vsp_cmd.sub_data.kern.side = (u64)data; | 880 | vsp_cmd.sub_data.kern.side = (u64)m->private; |
883 | vsp_cmd.sub_data.kern.length = off + count; | 881 | vsp_cmd.sub_data.kern.length = 256; |
884 | mb(); | 882 | mb(); |
885 | rc = signal_vsp_instruction(&vsp_cmd); | 883 | rc = signal_vsp_instruction(&vsp_cmd); |
886 | iseries_hv_unmap(dma_addr, off + count, DMA_FROM_DEVICE); | 884 | iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE); |
887 | if (rc) | 885 | if (rc) { |
886 | kfree(page); | ||
888 | return rc; | 887 | return rc; |
889 | if (vsp_cmd.result_code != 0) | 888 | } |
889 | if (vsp_cmd.result_code != 0) { | ||
890 | kfree(page); | ||
890 | return -ENOMEM; | 891 | return -ENOMEM; |
892 | } | ||
891 | p = page; | 893 | p = page; |
892 | len = 0; | 894 | while (p - page < 256) { |
893 | while (len < (off + count)) { | 895 | if (*p == '\0' || *p == '\n') { |
894 | if ((*p == '\0') || (*p == '\n')) { | 896 | *p = '\n'; |
895 | if (*p == '\0') | ||
896 | *p = '\n'; | ||
897 | p++; | ||
898 | len++; | ||
899 | *eof = 1; | ||
900 | break; | 897 | break; |
901 | } | 898 | } |
902 | p++; | 899 | p++; |
903 | len++; | ||
904 | } | ||
905 | 900 | ||
906 | if (len < off) { | ||
907 | *eof = 1; | ||
908 | len = 0; | ||
909 | } | 901 | } |
910 | return len; | 902 | seq_write(m, page, p - page); |
903 | kfree(page); | ||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | static int mf_cmdline_proc_open(struct inode *inode, struct file *file) | ||
908 | { | ||
909 | return single_open(file, mf_cmdline_proc_show, PDE(inode)->data); | ||
911 | } | 910 | } |
912 | 911 | ||
913 | #if 0 | 912 | #if 0 |
@@ -962,10 +961,8 @@ static int proc_mf_dump_vmlinux(char *page, char **start, off_t off, | |||
962 | } | 961 | } |
963 | #endif | 962 | #endif |
964 | 963 | ||
965 | static int proc_mf_dump_side(char *page, char **start, off_t off, | 964 | static int mf_side_proc_show(struct seq_file *m, void *v) |
966 | int count, int *eof, void *data) | ||
967 | { | 965 | { |
968 | int len; | ||
969 | char mf_current_side = ' '; | 966 | char mf_current_side = ' '; |
970 | struct vsp_cmd_data vsp_cmd; | 967 | struct vsp_cmd_data vsp_cmd; |
971 | 968 | ||
@@ -989,21 +986,17 @@ static int proc_mf_dump_side(char *page, char **start, off_t off, | |||
989 | } | 986 | } |
990 | } | 987 | } |
991 | 988 | ||
992 | len = sprintf(page, "%c\n", mf_current_side); | 989 | seq_printf(m, "%c\n", mf_current_side); |
990 | return 0; | ||
991 | } | ||
993 | 992 | ||
994 | if (len <= (off + count)) | 993 | static int mf_side_proc_open(struct inode *inode, struct file *file) |
995 | *eof = 1; | 994 | { |
996 | *start = page + off; | 995 | return single_open(file, mf_side_proc_show, NULL); |
997 | len -= off; | ||
998 | if (len > count) | ||
999 | len = count; | ||
1000 | if (len < 0) | ||
1001 | len = 0; | ||
1002 | return len; | ||
1003 | } | 996 | } |
1004 | 997 | ||
1005 | static int proc_mf_change_side(struct file *file, const char __user *buffer, | 998 | static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer, |
1006 | unsigned long count, void *data) | 999 | size_t count, loff_t *pos) |
1007 | { | 1000 | { |
1008 | char side; | 1001 | char side; |
1009 | u64 newSide; | 1002 | u64 newSide; |
@@ -1041,6 +1034,15 @@ static int proc_mf_change_side(struct file *file, const char __user *buffer, | |||
1041 | return count; | 1034 | return count; |
1042 | } | 1035 | } |
1043 | 1036 | ||
1037 | static const struct file_operations mf_side_proc_fops = { | ||
1038 | .owner = THIS_MODULE, | ||
1039 | .open = mf_side_proc_open, | ||
1040 | .read = seq_read, | ||
1041 | .llseek = seq_lseek, | ||
1042 | .release = single_release, | ||
1043 | .write = mf_side_proc_write, | ||
1044 | }; | ||
1045 | |||
1044 | #if 0 | 1046 | #if 0 |
1045 | static void mf_getSrcHistory(char *buffer, int size) | 1047 | static void mf_getSrcHistory(char *buffer, int size) |
1046 | { | 1048 | { |
@@ -1087,8 +1089,7 @@ static void mf_getSrcHistory(char *buffer, int size) | |||
1087 | } | 1089 | } |
1088 | #endif | 1090 | #endif |
1089 | 1091 | ||
1090 | static int proc_mf_dump_src(char *page, char **start, off_t off, | 1092 | static int mf_src_proc_show(struct seq_file *m, void *v) |
1091 | int count, int *eof, void *data) | ||
1092 | { | 1093 | { |
1093 | #if 0 | 1094 | #if 0 |
1094 | int len; | 1095 | int len; |
@@ -1109,8 +1110,13 @@ static int proc_mf_dump_src(char *page, char **start, off_t off, | |||
1109 | #endif | 1110 | #endif |
1110 | } | 1111 | } |
1111 | 1112 | ||
1112 | static int proc_mf_change_src(struct file *file, const char __user *buffer, | 1113 | static int mf_src_proc_open(struct inode *inode, struct file *file) |
1113 | unsigned long count, void *data) | 1114 | { |
1115 | return single_open(file, mf_src_proc_show, NULL); | ||
1116 | } | ||
1117 | |||
1118 | static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer, | ||
1119 | size_t count, loff_t *pos) | ||
1114 | { | 1120 | { |
1115 | char stkbuf[10]; | 1121 | char stkbuf[10]; |
1116 | 1122 | ||
@@ -1135,9 +1141,19 @@ static int proc_mf_change_src(struct file *file, const char __user *buffer, | |||
1135 | return count; | 1141 | return count; |
1136 | } | 1142 | } |
1137 | 1143 | ||
1138 | static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, | 1144 | static const struct file_operations mf_src_proc_fops = { |
1139 | unsigned long count, void *data) | 1145 | .owner = THIS_MODULE, |
1146 | .open = mf_src_proc_open, | ||
1147 | .read = seq_read, | ||
1148 | .llseek = seq_lseek, | ||
1149 | .release = single_release, | ||
1150 | .write = mf_src_proc_write, | ||
1151 | }; | ||
1152 | |||
1153 | static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer, | ||
1154 | size_t count, loff_t *pos) | ||
1140 | { | 1155 | { |
1156 | void *data = PDE(file->f_path.dentry->d_inode)->data; | ||
1141 | struct vsp_cmd_data vsp_cmd; | 1157 | struct vsp_cmd_data vsp_cmd; |
1142 | dma_addr_t dma_addr; | 1158 | dma_addr_t dma_addr; |
1143 | char *page; | 1159 | char *page; |
@@ -1172,6 +1188,15 @@ out: | |||
1172 | return ret; | 1188 | return ret; |
1173 | } | 1189 | } |
1174 | 1190 | ||
1191 | static const struct file_operations mf_cmdline_proc_fops = { | ||
1192 | .owner = THIS_MODULE, | ||
1193 | .open = mf_cmdline_proc_open, | ||
1194 | .read = seq_read, | ||
1195 | .llseek = seq_lseek, | ||
1196 | .release = single_release, | ||
1197 | .write = mf_cmdline_proc_write, | ||
1198 | }; | ||
1199 | |||
1175 | static ssize_t proc_mf_change_vmlinux(struct file *file, | 1200 | static ssize_t proc_mf_change_vmlinux(struct file *file, |
1176 | const char __user *buf, | 1201 | const char __user *buf, |
1177 | size_t count, loff_t *ppos) | 1202 | size_t count, loff_t *ppos) |
@@ -1246,12 +1271,10 @@ static int __init mf_proc_init(void) | |||
1246 | if (!mf) | 1271 | if (!mf) |
1247 | return 1; | 1272 | return 1; |
1248 | 1273 | ||
1249 | ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf); | 1274 | ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf, |
1275 | &mf_cmdline_proc_fops, (void *)(long)i); | ||
1250 | if (!ent) | 1276 | if (!ent) |
1251 | return 1; | 1277 | return 1; |
1252 | ent->data = (void *)(long)i; | ||
1253 | ent->read_proc = proc_mf_dump_cmdline; | ||
1254 | ent->write_proc = proc_mf_change_cmdline; | ||
1255 | 1278 | ||
1256 | if (i == 3) /* no vmlinux entry for 'D' */ | 1279 | if (i == 3) /* no vmlinux entry for 'D' */ |
1257 | continue; | 1280 | continue; |
@@ -1263,19 +1286,15 @@ static int __init mf_proc_init(void) | |||
1263 | return 1; | 1286 | return 1; |
1264 | } | 1287 | } |
1265 | 1288 | ||
1266 | ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); | 1289 | ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, |
1290 | &mf_side_proc_fops); | ||
1267 | if (!ent) | 1291 | if (!ent) |
1268 | return 1; | 1292 | return 1; |
1269 | ent->data = (void *)0; | ||
1270 | ent->read_proc = proc_mf_dump_side; | ||
1271 | ent->write_proc = proc_mf_change_side; | ||
1272 | 1293 | ||
1273 | ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); | 1294 | ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, |
1295 | &mf_src_proc_fops); | ||
1274 | if (!ent) | 1296 | if (!ent) |
1275 | return 1; | 1297 | return 1; |
1276 | ent->data = (void *)0; | ||
1277 | ent->read_proc = proc_mf_dump_src; | ||
1278 | ent->write_proc = proc_mf_change_src; | ||
1279 | 1298 | ||
1280 | return 0; | 1299 | return 0; |
1281 | } | 1300 | } |
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index 657b72f68493..2aa8b5631beb 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c | |||
@@ -474,6 +474,8 @@ static void __init get_viotape_info(struct device_node *vio_root) | |||
474 | struct vio_waitevent we; | 474 | struct vio_waitevent we; |
475 | int ret; | 475 | int ret; |
476 | 476 | ||
477 | init_completion(&we.com); | ||
478 | |||
477 | ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); | 479 | ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); |
478 | if (ret) { | 480 | if (ret) { |
479 | printk(KERN_WARNING "get_viotape_info: " | 481 | printk(KERN_WARNING "get_viotape_info: " |
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index 49ff4dc422b7..5aea94f30836 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c | |||
@@ -116,7 +116,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) | |||
116 | u16 vlanMap; | 116 | u16 vlanMap; |
117 | dma_addr_t handle; | 117 | dma_addr_t handle; |
118 | HvLpEvent_Rc hvrc; | 118 | HvLpEvent_Rc hvrc; |
119 | DECLARE_COMPLETION(done); | 119 | DECLARE_COMPLETION_ONSTACK(done); |
120 | struct device_node *node; | 120 | struct device_node *node; |
121 | const char *sysid; | 121 | const char *sysid; |
122 | 122 | ||
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index cf660916ae0b..9dd789a7370d 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/string.h> | 13 | #include <linux/string.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/utsrelease.h> | 15 | #include <generated/utsrelease.h> |
16 | #include <asm/sections.h> | 16 | #include <asm/sections.h> |
17 | #include <asm/prom.h> | 17 | #include <asm/prom.h> |
18 | #include <asm/page.h> | 18 | #include <asm/page.h> |
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 27554c807fd5..c667f0f02c34 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig | |||
@@ -2,6 +2,8 @@ config PPC_PSERIES | |||
2 | depends on PPC64 && PPC_BOOK3S | 2 | depends on PPC64 && PPC_BOOK3S |
3 | bool "IBM pSeries & new (POWER5-based) iSeries" | 3 | bool "IBM pSeries & new (POWER5-based) iSeries" |
4 | select MPIC | 4 | select MPIC |
5 | select PCI_MSI | ||
6 | select XICS | ||
5 | select PPC_I8259 | 7 | select PPC_I8259 |
6 | select PPC_RTAS | 8 | select PPC_RTAS |
7 | select PPC_RTAS_DAEMON | 9 | select PPC_RTAS_DAEMON |
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index bcdcf0ccc8d7..a277f2e28dbc 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c | |||
@@ -38,19 +38,28 @@ | |||
38 | #include <asm/mmu.h> | 38 | #include <asm/mmu.h> |
39 | #include <asm/pgalloc.h> | 39 | #include <asm/pgalloc.h> |
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | #include <linux/memory.h> | ||
41 | 42 | ||
42 | #include "plpar_wrappers.h" | 43 | #include "plpar_wrappers.h" |
43 | 44 | ||
44 | #define CMM_DRIVER_VERSION "1.0.0" | 45 | #define CMM_DRIVER_VERSION "1.0.0" |
45 | #define CMM_DEFAULT_DELAY 1 | 46 | #define CMM_DEFAULT_DELAY 1 |
47 | #define CMM_HOTPLUG_DELAY 5 | ||
46 | #define CMM_DEBUG 0 | 48 | #define CMM_DEBUG 0 |
47 | #define CMM_DISABLE 0 | 49 | #define CMM_DISABLE 0 |
48 | #define CMM_OOM_KB 1024 | 50 | #define CMM_OOM_KB 1024 |
49 | #define CMM_MIN_MEM_MB 256 | 51 | #define CMM_MIN_MEM_MB 256 |
50 | #define KB2PAGES(_p) ((_p)>>(PAGE_SHIFT-10)) | 52 | #define KB2PAGES(_p) ((_p)>>(PAGE_SHIFT-10)) |
51 | #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) | 53 | #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) |
54 | /* | ||
55 | * The priority level tries to ensure that this notifier is called as | ||
56 | * late as possible to reduce thrashing in the shared memory pool. | ||
57 | */ | ||
58 | #define CMM_MEM_HOTPLUG_PRI 1 | ||
59 | #define CMM_MEM_ISOLATE_PRI 15 | ||
52 | 60 | ||
53 | static unsigned int delay = CMM_DEFAULT_DELAY; | 61 | static unsigned int delay = CMM_DEFAULT_DELAY; |
62 | static unsigned int hotplug_delay = CMM_HOTPLUG_DELAY; | ||
54 | static unsigned int oom_kb = CMM_OOM_KB; | 63 | static unsigned int oom_kb = CMM_OOM_KB; |
55 | static unsigned int cmm_debug = CMM_DEBUG; | 64 | static unsigned int cmm_debug = CMM_DEBUG; |
56 | static unsigned int cmm_disabled = CMM_DISABLE; | 65 | static unsigned int cmm_disabled = CMM_DISABLE; |
@@ -65,6 +74,10 @@ MODULE_VERSION(CMM_DRIVER_VERSION); | |||
65 | module_param_named(delay, delay, uint, S_IRUGO | S_IWUSR); | 74 | module_param_named(delay, delay, uint, S_IRUGO | S_IWUSR); |
66 | MODULE_PARM_DESC(delay, "Delay (in seconds) between polls to query hypervisor paging requests. " | 75 | MODULE_PARM_DESC(delay, "Delay (in seconds) between polls to query hypervisor paging requests. " |
67 | "[Default=" __stringify(CMM_DEFAULT_DELAY) "]"); | 76 | "[Default=" __stringify(CMM_DEFAULT_DELAY) "]"); |
77 | module_param_named(hotplug_delay, hotplug_delay, uint, S_IRUGO | S_IWUSR); | ||
78 | MODULE_PARM_DESC(delay, "Delay (in seconds) after memory hotplug remove " | ||
79 | "before loaning resumes. " | ||
80 | "[Default=" __stringify(CMM_HOTPLUG_DELAY) "]"); | ||
68 | module_param_named(oom_kb, oom_kb, uint, S_IRUGO | S_IWUSR); | 81 | module_param_named(oom_kb, oom_kb, uint, S_IRUGO | S_IWUSR); |
69 | MODULE_PARM_DESC(oom_kb, "Amount of memory in kb to free on OOM. " | 82 | MODULE_PARM_DESC(oom_kb, "Amount of memory in kb to free on OOM. " |
70 | "[Default=" __stringify(CMM_OOM_KB) "]"); | 83 | "[Default=" __stringify(CMM_OOM_KB) "]"); |
@@ -92,6 +105,9 @@ static unsigned long oom_freed_pages; | |||
92 | static struct cmm_page_array *cmm_page_list; | 105 | static struct cmm_page_array *cmm_page_list; |
93 | static DEFINE_SPINLOCK(cmm_lock); | 106 | static DEFINE_SPINLOCK(cmm_lock); |
94 | 107 | ||
108 | static DEFINE_MUTEX(hotplug_mutex); | ||
109 | static int hotplug_occurred; /* protected by the hotplug mutex */ | ||
110 | |||
95 | static struct task_struct *cmm_thread_ptr; | 111 | static struct task_struct *cmm_thread_ptr; |
96 | 112 | ||
97 | /** | 113 | /** |
@@ -110,6 +126,17 @@ static long cmm_alloc_pages(long nr) | |||
110 | cmm_dbg("Begin request for %ld pages\n", nr); | 126 | cmm_dbg("Begin request for %ld pages\n", nr); |
111 | 127 | ||
112 | while (nr) { | 128 | while (nr) { |
129 | /* Exit if a hotplug operation is in progress or occurred */ | ||
130 | if (mutex_trylock(&hotplug_mutex)) { | ||
131 | if (hotplug_occurred) { | ||
132 | mutex_unlock(&hotplug_mutex); | ||
133 | break; | ||
134 | } | ||
135 | mutex_unlock(&hotplug_mutex); | ||
136 | } else { | ||
137 | break; | ||
138 | } | ||
139 | |||
113 | addr = __get_free_page(GFP_NOIO | __GFP_NOWARN | | 140 | addr = __get_free_page(GFP_NOIO | __GFP_NOWARN | |
114 | __GFP_NORETRY | __GFP_NOMEMALLOC); | 141 | __GFP_NORETRY | __GFP_NOMEMALLOC); |
115 | if (!addr) | 142 | if (!addr) |
@@ -119,8 +146,9 @@ static long cmm_alloc_pages(long nr) | |||
119 | if (!pa || pa->index >= CMM_NR_PAGES) { | 146 | if (!pa || pa->index >= CMM_NR_PAGES) { |
120 | /* Need a new page for the page list. */ | 147 | /* Need a new page for the page list. */ |
121 | spin_unlock(&cmm_lock); | 148 | spin_unlock(&cmm_lock); |
122 | npa = (struct cmm_page_array *)__get_free_page(GFP_NOIO | __GFP_NOWARN | | 149 | npa = (struct cmm_page_array *)__get_free_page( |
123 | __GFP_NORETRY | __GFP_NOMEMALLOC); | 150 | GFP_NOIO | __GFP_NOWARN | |
151 | __GFP_NORETRY | __GFP_NOMEMALLOC); | ||
124 | if (!npa) { | 152 | if (!npa) { |
125 | pr_info("%s: Can not allocate new page list\n", __func__); | 153 | pr_info("%s: Can not allocate new page list\n", __func__); |
126 | free_page(addr); | 154 | free_page(addr); |
@@ -282,9 +310,28 @@ static int cmm_thread(void *dummy) | |||
282 | while (1) { | 310 | while (1) { |
283 | timeleft = msleep_interruptible(delay * 1000); | 311 | timeleft = msleep_interruptible(delay * 1000); |
284 | 312 | ||
285 | if (kthread_should_stop() || timeleft) { | 313 | if (kthread_should_stop() || timeleft) |
286 | loaned_pages_target = loaned_pages; | ||
287 | break; | 314 | break; |
315 | |||
316 | if (mutex_trylock(&hotplug_mutex)) { | ||
317 | if (hotplug_occurred) { | ||
318 | hotplug_occurred = 0; | ||
319 | mutex_unlock(&hotplug_mutex); | ||
320 | cmm_dbg("Hotplug operation has occurred, " | ||
321 | "loaning activity suspended " | ||
322 | "for %d seconds.\n", | ||
323 | hotplug_delay); | ||
324 | timeleft = msleep_interruptible(hotplug_delay * | ||
325 | 1000); | ||
326 | if (kthread_should_stop() || timeleft) | ||
327 | break; | ||
328 | continue; | ||
329 | } | ||
330 | mutex_unlock(&hotplug_mutex); | ||
331 | } else { | ||
332 | cmm_dbg("Hotplug operation in progress, activity " | ||
333 | "suspended\n"); | ||
334 | continue; | ||
288 | } | 335 | } |
289 | 336 | ||
290 | cmm_get_mpp(); | 337 | cmm_get_mpp(); |
@@ -414,6 +461,193 @@ static struct notifier_block cmm_reboot_nb = { | |||
414 | }; | 461 | }; |
415 | 462 | ||
416 | /** | 463 | /** |
464 | * cmm_count_pages - Count the number of pages loaned in a particular range. | ||
465 | * | ||
466 | * @arg: memory_isolate_notify structure with address range and count | ||
467 | * | ||
468 | * Return value: | ||
469 | * 0 on success | ||
470 | **/ | ||
471 | static unsigned long cmm_count_pages(void *arg) | ||
472 | { | ||
473 | struct memory_isolate_notify *marg = arg; | ||
474 | struct cmm_page_array *pa; | ||
475 | unsigned long start = (unsigned long)pfn_to_kaddr(marg->start_pfn); | ||
476 | unsigned long end = start + (marg->nr_pages << PAGE_SHIFT); | ||
477 | unsigned long idx; | ||
478 | |||
479 | spin_lock(&cmm_lock); | ||
480 | pa = cmm_page_list; | ||
481 | while (pa) { | ||
482 | if ((unsigned long)pa >= start && (unsigned long)pa < end) | ||
483 | marg->pages_found++; | ||
484 | for (idx = 0; idx < pa->index; idx++) | ||
485 | if (pa->page[idx] >= start && pa->page[idx] < end) | ||
486 | marg->pages_found++; | ||
487 | pa = pa->next; | ||
488 | } | ||
489 | spin_unlock(&cmm_lock); | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * cmm_memory_isolate_cb - Handle memory isolation notifier calls | ||
495 | * @self: notifier block struct | ||
496 | * @action: action to take | ||
497 | * @arg: struct memory_isolate_notify data for handler | ||
498 | * | ||
499 | * Return value: | ||
500 | * NOTIFY_OK or notifier error based on subfunction return value | ||
501 | **/ | ||
502 | static int cmm_memory_isolate_cb(struct notifier_block *self, | ||
503 | unsigned long action, void *arg) | ||
504 | { | ||
505 | int ret = 0; | ||
506 | |||
507 | if (action == MEM_ISOLATE_COUNT) | ||
508 | ret = cmm_count_pages(arg); | ||
509 | |||
510 | if (ret) | ||
511 | ret = notifier_from_errno(ret); | ||
512 | else | ||
513 | ret = NOTIFY_OK; | ||
514 | |||
515 | return ret; | ||
516 | } | ||
517 | |||
518 | static struct notifier_block cmm_mem_isolate_nb = { | ||
519 | .notifier_call = cmm_memory_isolate_cb, | ||
520 | .priority = CMM_MEM_ISOLATE_PRI | ||
521 | }; | ||
522 | |||
523 | /** | ||
524 | * cmm_mem_going_offline - Unloan pages where memory is to be removed | ||
525 | * @arg: memory_notify structure with page range to be offlined | ||
526 | * | ||
527 | * Return value: | ||
528 | * 0 on success | ||
529 | **/ | ||
530 | static int cmm_mem_going_offline(void *arg) | ||
531 | { | ||
532 | struct memory_notify *marg = arg; | ||
533 | unsigned long start_page = (unsigned long)pfn_to_kaddr(marg->start_pfn); | ||
534 | unsigned long end_page = start_page + (marg->nr_pages << PAGE_SHIFT); | ||
535 | struct cmm_page_array *pa_curr, *pa_last, *npa; | ||
536 | unsigned long idx; | ||
537 | unsigned long freed = 0; | ||
538 | |||
539 | cmm_dbg("Memory going offline, searching 0x%lx (%ld pages).\n", | ||
540 | start_page, marg->nr_pages); | ||
541 | spin_lock(&cmm_lock); | ||
542 | |||
543 | /* Search the page list for pages in the range to be offlined */ | ||
544 | pa_last = pa_curr = cmm_page_list; | ||
545 | while (pa_curr) { | ||
546 | for (idx = (pa_curr->index - 1); (idx + 1) > 0; idx--) { | ||
547 | if ((pa_curr->page[idx] < start_page) || | ||
548 | (pa_curr->page[idx] >= end_page)) | ||
549 | continue; | ||
550 | |||
551 | plpar_page_set_active(__pa(pa_curr->page[idx])); | ||
552 | free_page(pa_curr->page[idx]); | ||
553 | freed++; | ||
554 | loaned_pages--; | ||
555 | totalram_pages++; | ||
556 | pa_curr->page[idx] = pa_last->page[--pa_last->index]; | ||
557 | if (pa_last->index == 0) { | ||
558 | if (pa_curr == pa_last) | ||
559 | pa_curr = pa_last->next; | ||
560 | pa_last = pa_last->next; | ||
561 | free_page((unsigned long)cmm_page_list); | ||
562 | cmm_page_list = pa_last; | ||
563 | continue; | ||
564 | } | ||
565 | } | ||
566 | pa_curr = pa_curr->next; | ||
567 | } | ||
568 | |||
569 | /* Search for page list structures in the range to be offlined */ | ||
570 | pa_last = NULL; | ||
571 | pa_curr = cmm_page_list; | ||
572 | while (pa_curr) { | ||
573 | if (((unsigned long)pa_curr >= start_page) && | ||
574 | ((unsigned long)pa_curr < end_page)) { | ||
575 | npa = (struct cmm_page_array *)__get_free_page( | ||
576 | GFP_NOIO | __GFP_NOWARN | | ||
577 | __GFP_NORETRY | __GFP_NOMEMALLOC); | ||
578 | if (!npa) { | ||
579 | spin_unlock(&cmm_lock); | ||
580 | cmm_dbg("Failed to allocate memory for list " | ||
581 | "management. Memory hotplug " | ||
582 | "failed.\n"); | ||
583 | return ENOMEM; | ||
584 | } | ||
585 | memcpy(npa, pa_curr, PAGE_SIZE); | ||
586 | if (pa_curr == cmm_page_list) | ||
587 | cmm_page_list = npa; | ||
588 | if (pa_last) | ||
589 | pa_last->next = npa; | ||
590 | free_page((unsigned long) pa_curr); | ||
591 | freed++; | ||
592 | pa_curr = npa; | ||
593 | } | ||
594 | |||
595 | pa_last = pa_curr; | ||
596 | pa_curr = pa_curr->next; | ||
597 | } | ||
598 | |||
599 | spin_unlock(&cmm_lock); | ||
600 | cmm_dbg("Released %ld pages in the search range.\n", freed); | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | /** | ||
606 | * cmm_memory_cb - Handle memory hotplug notifier calls | ||
607 | * @self: notifier block struct | ||
608 | * @action: action to take | ||
609 | * @arg: struct memory_notify data for handler | ||
610 | * | ||
611 | * Return value: | ||
612 | * NOTIFY_OK or notifier error based on subfunction return value | ||
613 | * | ||
614 | **/ | ||
615 | static int cmm_memory_cb(struct notifier_block *self, | ||
616 | unsigned long action, void *arg) | ||
617 | { | ||
618 | int ret = 0; | ||
619 | |||
620 | switch (action) { | ||
621 | case MEM_GOING_OFFLINE: | ||
622 | mutex_lock(&hotplug_mutex); | ||
623 | hotplug_occurred = 1; | ||
624 | ret = cmm_mem_going_offline(arg); | ||
625 | break; | ||
626 | case MEM_OFFLINE: | ||
627 | case MEM_CANCEL_OFFLINE: | ||
628 | mutex_unlock(&hotplug_mutex); | ||
629 | cmm_dbg("Memory offline operation complete.\n"); | ||
630 | break; | ||
631 | case MEM_GOING_ONLINE: | ||
632 | case MEM_ONLINE: | ||
633 | case MEM_CANCEL_ONLINE: | ||
634 | break; | ||
635 | } | ||
636 | |||
637 | if (ret) | ||
638 | ret = notifier_from_errno(ret); | ||
639 | else | ||
640 | ret = NOTIFY_OK; | ||
641 | |||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | static struct notifier_block cmm_mem_nb = { | ||
646 | .notifier_call = cmm_memory_cb, | ||
647 | .priority = CMM_MEM_HOTPLUG_PRI | ||
648 | }; | ||
649 | |||
650 | /** | ||
417 | * cmm_init - Module initialization | 651 | * cmm_init - Module initialization |
418 | * | 652 | * |
419 | * Return value: | 653 | * Return value: |
@@ -435,18 +669,24 @@ static int cmm_init(void) | |||
435 | if ((rc = cmm_sysfs_register(&cmm_sysdev))) | 669 | if ((rc = cmm_sysfs_register(&cmm_sysdev))) |
436 | goto out_reboot_notifier; | 670 | goto out_reboot_notifier; |
437 | 671 | ||
672 | if (register_memory_notifier(&cmm_mem_nb) || | ||
673 | register_memory_isolate_notifier(&cmm_mem_isolate_nb)) | ||
674 | goto out_unregister_notifier; | ||
675 | |||
438 | if (cmm_disabled) | 676 | if (cmm_disabled) |
439 | return rc; | 677 | return rc; |
440 | 678 | ||
441 | cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); | 679 | cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); |
442 | if (IS_ERR(cmm_thread_ptr)) { | 680 | if (IS_ERR(cmm_thread_ptr)) { |
443 | rc = PTR_ERR(cmm_thread_ptr); | 681 | rc = PTR_ERR(cmm_thread_ptr); |
444 | goto out_unregister_sysfs; | 682 | goto out_unregister_notifier; |
445 | } | 683 | } |
446 | 684 | ||
447 | return rc; | 685 | return rc; |
448 | 686 | ||
449 | out_unregister_sysfs: | 687 | out_unregister_notifier: |
688 | unregister_memory_notifier(&cmm_mem_nb); | ||
689 | unregister_memory_isolate_notifier(&cmm_mem_isolate_nb); | ||
450 | cmm_unregister_sysfs(&cmm_sysdev); | 690 | cmm_unregister_sysfs(&cmm_sysdev); |
451 | out_reboot_notifier: | 691 | out_reboot_notifier: |
452 | unregister_reboot_notifier(&cmm_reboot_nb); | 692 | unregister_reboot_notifier(&cmm_reboot_nb); |
@@ -467,6 +707,8 @@ static void cmm_exit(void) | |||
467 | kthread_stop(cmm_thread_ptr); | 707 | kthread_stop(cmm_thread_ptr); |
468 | unregister_oom_notifier(&cmm_oom_nb); | 708 | unregister_oom_notifier(&cmm_oom_nb); |
469 | unregister_reboot_notifier(&cmm_reboot_nb); | 709 | unregister_reboot_notifier(&cmm_reboot_nb); |
710 | unregister_memory_notifier(&cmm_mem_nb); | ||
711 | unregister_memory_isolate_notifier(&cmm_mem_isolate_nb); | ||
470 | cmm_free_pages(loaned_pages); | 712 | cmm_free_pages(loaned_pages); |
471 | cmm_unregister_sysfs(&cmm_sysdev); | 713 | cmm_unregister_sysfs(&cmm_sysdev); |
472 | } | 714 | } |
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 12df9e8812a9..37bce52526da 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
@@ -236,7 +236,9 @@ static struct device_node *derive_parent(const char *path) | |||
236 | 236 | ||
237 | int dlpar_attach_node(struct device_node *dn) | 237 | int dlpar_attach_node(struct device_node *dn) |
238 | { | 238 | { |
239 | #ifdef CONFIG_PROC_DEVICETREE | ||
239 | struct proc_dir_entry *ent; | 240 | struct proc_dir_entry *ent; |
241 | #endif | ||
240 | int rc; | 242 | int rc; |
241 | 243 | ||
242 | of_node_set_flag(dn, OF_DYNAMIC); | 244 | of_node_set_flag(dn, OF_DYNAMIC); |
@@ -267,10 +269,10 @@ int dlpar_attach_node(struct device_node *dn) | |||
267 | 269 | ||
268 | int dlpar_detach_node(struct device_node *dn) | 270 | int dlpar_detach_node(struct device_node *dn) |
269 | { | 271 | { |
272 | #ifdef CONFIG_PROC_DEVICETREE | ||
270 | struct device_node *parent = dn->parent; | 273 | struct device_node *parent = dn->parent; |
271 | struct property *prop = dn->properties; | 274 | struct property *prop = dn->properties; |
272 | 275 | ||
273 | #ifdef CONFIG_PROC_DEVICETREE | ||
274 | while (prop) { | 276 | while (prop) { |
275 | remove_proc_entry(prop->name, dn->pde); | 277 | remove_proc_entry(prop->name, dn->pde); |
276 | prop = prop->next; | 278 | prop = prop->next; |
@@ -344,18 +346,6 @@ int dlpar_release_drc(u32 drc_index) | |||
344 | 346 | ||
345 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | 347 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE |
346 | 348 | ||
347 | static DEFINE_MUTEX(pseries_cpu_hotplug_mutex); | ||
348 | |||
349 | void cpu_hotplug_driver_lock() | ||
350 | { | ||
351 | mutex_lock(&pseries_cpu_hotplug_mutex); | ||
352 | } | ||
353 | |||
354 | void cpu_hotplug_driver_unlock() | ||
355 | { | ||
356 | mutex_unlock(&pseries_cpu_hotplug_mutex); | ||
357 | } | ||
358 | |||
359 | static int dlpar_online_cpu(struct device_node *dn) | 349 | static int dlpar_online_cpu(struct device_node *dn) |
360 | { | 350 | { |
361 | int rc = 0; | 351 | int rc = 0; |
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 8868c012268a..b4886635972c 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c | |||
@@ -144,8 +144,8 @@ static void __devinit smp_pSeries_kick_cpu(int nr) | |||
144 | hcpuid = get_hard_smp_processor_id(nr); | 144 | hcpuid = get_hard_smp_processor_id(nr); |
145 | rc = plpar_hcall_norets(H_PROD, hcpuid); | 145 | rc = plpar_hcall_norets(H_PROD, hcpuid); |
146 | if (rc != H_SUCCESS) | 146 | if (rc != H_SUCCESS) |
147 | panic("Error: Prod to wake up processor %d Ret= %ld\n", | 147 | printk(KERN_ERR "Error: Prod to wake up processor %d\ |
148 | nr, rc); | 148 | Ret= %ld\n", nr, rc); |
149 | } | 149 | } |
150 | } | 150 | } |
151 | 151 | ||
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index b9b9e11609ec..f5f79196721c 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -163,14 +163,13 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) | |||
163 | /* Interface to generic irq subsystem */ | 163 | /* Interface to generic irq subsystem */ |
164 | 164 | ||
165 | #ifdef CONFIG_SMP | 165 | #ifdef CONFIG_SMP |
166 | static int get_irq_server(unsigned int virq, unsigned int strict_check) | 166 | static int get_irq_server(unsigned int virq, cpumask_t cpumask, |
167 | unsigned int strict_check) | ||
167 | { | 168 | { |
168 | int server; | 169 | int server; |
169 | /* For the moment only implement delivery to all cpus or one cpu */ | 170 | /* For the moment only implement delivery to all cpus or one cpu */ |
170 | cpumask_t cpumask; | ||
171 | cpumask_t tmp = CPU_MASK_NONE; | 171 | cpumask_t tmp = CPU_MASK_NONE; |
172 | 172 | ||
173 | cpumask_copy(&cpumask, irq_to_desc(virq)->affinity); | ||
174 | if (!distribute_irqs) | 173 | if (!distribute_irqs) |
175 | return default_server; | 174 | return default_server; |
176 | 175 | ||
@@ -192,10 +191,7 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) | |||
192 | return default_server; | 191 | return default_server; |
193 | } | 192 | } |
194 | #else | 193 | #else |
195 | static int get_irq_server(unsigned int virq, unsigned int strict_check) | 194 | #define get_irq_server(virq, cpumask, strict_check) (default_server) |
196 | { | ||
197 | return default_server; | ||
198 | } | ||
199 | #endif | 195 | #endif |
200 | 196 | ||
201 | static void xics_unmask_irq(unsigned int virq) | 197 | static void xics_unmask_irq(unsigned int virq) |
@@ -211,7 +207,7 @@ static void xics_unmask_irq(unsigned int virq) | |||
211 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) | 207 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) |
212 | return; | 208 | return; |
213 | 209 | ||
214 | server = get_irq_server(virq, 0); | 210 | server = get_irq_server(virq, *(irq_to_desc(virq)->affinity), 0); |
215 | 211 | ||
216 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, | 212 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, |
217 | DEFAULT_PRIORITY); | 213 | DEFAULT_PRIORITY); |
@@ -405,7 +401,7 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) | |||
405 | * For the moment only implement delivery to all cpus or one cpu. | 401 | * For the moment only implement delivery to all cpus or one cpu. |
406 | * Get current irq_server for the given irq | 402 | * Get current irq_server for the given irq |
407 | */ | 403 | */ |
408 | irq_server = get_irq_server(virq, 1); | 404 | irq_server = get_irq_server(virq, *cpumask, 1); |
409 | if (irq_server == -1) { | 405 | if (irq_server == -1) { |
410 | char cpulist[128]; | 406 | char cpulist[128]; |
411 | cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); | 407 | cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); |
@@ -788,9 +784,13 @@ static void xics_set_cpu_priority(unsigned char cppr) | |||
788 | { | 784 | { |
789 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | 785 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); |
790 | 786 | ||
791 | BUG_ON(os_cppr->index != 0); | 787 | /* |
788 | * we only really want to set the priority when there's | ||
789 | * just one cppr value on the stack | ||
790 | */ | ||
791 | WARN_ON(os_cppr->index != 0); | ||
792 | 792 | ||
793 | os_cppr->stack[os_cppr->index] = cppr; | 793 | os_cppr->stack[0] = cppr; |
794 | 794 | ||
795 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 795 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
796 | lpar_cppr_info(cppr); | 796 | lpar_cppr_info(cppr); |
@@ -825,8 +825,14 @@ void xics_setup_cpu(void) | |||
825 | 825 | ||
826 | void xics_teardown_cpu(void) | 826 | void xics_teardown_cpu(void) |
827 | { | 827 | { |
828 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | ||
828 | int cpu = smp_processor_id(); | 829 | int cpu = smp_processor_id(); |
829 | 830 | ||
831 | /* | ||
832 | * we have to reset the cppr index to 0 because we're | ||
833 | * not going to return from the IPI | ||
834 | */ | ||
835 | os_cppr->index = 0; | ||
830 | xics_set_cpu_priority(0); | 836 | xics_set_cpu_priority(0); |
831 | 837 | ||
832 | /* Clear any pending IPI request */ | 838 | /* Clear any pending IPI request */ |