diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-22 16:16:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-22 16:16:01 -0400 |
commit | 06b8147c5dbd385b5b97ca74e19f6f3951ebc1cb (patch) | |
tree | 6ed9de7ca0ab3a65af6a189a89deb0a36ab35f6b /arch/powerpc/platforms/cell | |
parent | 53baaaa9682c230410a057263d1ce2922f43ddc4 (diff) | |
parent | 8725f25acc656c1522d48a6746055099efdaca4c (diff) |
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (49 commits)
powerpc: Fix build bug with binutils < 2.18 and GCC < 4.2
powerpc/eeh: Don't panic when EEH_MAX_FAILS is exceeded
fbdev: Teaches offb about palette on radeon r5xx/r6xx
powerpc/cell/edac: Log a syndrome code in case of correctable error
powerpc/cell: Add DMA_ATTR_WEAK_ORDERING dma attribute and use in Cell IOMMU code
powerpc: Indicate which oprofile counters to use while in compat mode
powerpc/boot: Change spaces to tabs
powerpc: Remove duplicate 6xx option in Kconfig
powerpc: Use PPC_LONG and PPC_LONG_ALIGN in lib/string.S
powerpc: Use PPC_LONG_ALIGN in uaccess.h
powerpc: Add a #define for aligning to a long-sized boundary
powerpc: Fix OF parsing of 64 bits PCI addresses
powerpc: Use WARN_ON(1) instead of __WARN()
powerpc: Fix support for latencytop
powerpc/ps3: Update ps3_defconfig
powerpc/ps3: Add a sub-match id to ps3_system_bus
powerpc: Add a 6xx defconfig
powerpc/dma: Use the struct dma_attrs in iommu code
powerpc/cell: Add support for power button of future IBM cell blades
powerpc/cell: Cleanup sysreset_hack for IBM cell blades
...
Diffstat (limited to 'arch/powerpc/platforms/cell')
-rw-r--r-- | arch/powerpc/platforms/cell/Kconfig | 25 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/Makefile | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/cbe_powerbutton.c | 117 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/cpufreq_spudemand.c | 184 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/iommu.c | 118 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/pervasive.c | 27 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/pervasive.h | 9 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/ras.c | 46 |
8 files changed, 496 insertions, 33 deletions
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 3959fcfe731c..c14d7d8d96c8 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig | |||
@@ -83,6 +83,22 @@ config CBE_RAS | |||
83 | depends on PPC_CELL_NATIVE | 83 | depends on PPC_CELL_NATIVE |
84 | default y | 84 | default y |
85 | 85 | ||
86 | config PPC_IBM_CELL_RESETBUTTON | ||
87 | bool "IBM Cell Blade Pinhole reset button" | ||
88 | depends on CBE_RAS && PPC_IBM_CELL_BLADE | ||
89 | default y | ||
90 | help | ||
91 | Support Pinhole Resetbutton on IBM Cell blades. | ||
92 | This adds a method to trigger system reset via front panel pinhole button. | ||
93 | |||
94 | config PPC_IBM_CELL_POWERBUTTON | ||
95 | tristate "IBM Cell Blade power button" | ||
96 | depends on PPC_IBM_CELL_BLADE && PPC_PMI && INPUT_EVDEV | ||
97 | default y | ||
98 | help | ||
99 | Support Powerbutton on IBM Cell blades. | ||
100 | This will enable the powerbutton as an input device. | ||
101 | |||
86 | config CBE_THERM | 102 | config CBE_THERM |
87 | tristate "CBE thermal support" | 103 | tristate "CBE thermal support" |
88 | default m | 104 | default m |
@@ -107,6 +123,15 @@ config CBE_CPUFREQ_PMI | |||
107 | processor will not only be able to run at lower speed, | 123 | processor will not only be able to run at lower speed, |
108 | but also at lower core voltage. | 124 | but also at lower core voltage. |
109 | 125 | ||
126 | config CBE_CPUFREQ_SPU_GOVERNOR | ||
127 | tristate "CBE frequency scaling based on SPU usage" | ||
128 | depends on SPU_FS && CPU_FREQ | ||
129 | default m | ||
130 | help | ||
131 | This governor checks for spu usage to adjust the cpu frequency. | ||
132 | If no spu is running on a given cpu, that cpu will be throttled to | ||
133 | the minimal possible frequency. | ||
134 | |||
110 | endmenu | 135 | endmenu |
111 | 136 | ||
112 | config OPROFILE_CELL | 137 | config OPROFILE_CELL |
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index c2a7e4e5ddf9..7fd830872c43 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile | |||
@@ -8,6 +8,9 @@ obj-$(CONFIG_CBE_THERM) += cbe_thermal.o | |||
8 | obj-$(CONFIG_CBE_CPUFREQ_PMI) += cbe_cpufreq_pmi.o | 8 | obj-$(CONFIG_CBE_CPUFREQ_PMI) += cbe_cpufreq_pmi.o |
9 | obj-$(CONFIG_CBE_CPUFREQ) += cbe-cpufreq.o | 9 | obj-$(CONFIG_CBE_CPUFREQ) += cbe-cpufreq.o |
10 | cbe-cpufreq-y += cbe_cpufreq_pervasive.o cbe_cpufreq.o | 10 | cbe-cpufreq-y += cbe_cpufreq_pervasive.o cbe_cpufreq.o |
11 | obj-$(CONFIG_CBE_CPUFREQ_SPU_GOVERNOR) += cpufreq_spudemand.o | ||
12 | |||
13 | obj-$(CONFIG_PPC_IBM_CELL_POWERBUTTON) += cbe_powerbutton.o | ||
11 | 14 | ||
12 | ifeq ($(CONFIG_SMP),y) | 15 | ifeq ($(CONFIG_SMP),y) |
13 | obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o | 16 | obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o |
diff --git a/arch/powerpc/platforms/cell/cbe_powerbutton.c b/arch/powerpc/platforms/cell/cbe_powerbutton.c new file mode 100644 index 000000000000..dcddaa5fcb66 --- /dev/null +++ b/arch/powerpc/platforms/cell/cbe_powerbutton.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * driver for powerbutton on IBM cell blades | ||
3 | * | ||
4 | * (C) Copyright IBM Corp. 2005-2008 | ||
5 | * | ||
6 | * Author: Christian Krafft <krafft@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/input.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <asm/pmi.h> | ||
26 | #include <asm/prom.h> | ||
27 | |||
28 | static struct input_dev *button_dev; | ||
29 | static struct platform_device *button_pdev; | ||
30 | |||
31 | static void cbe_powerbutton_handle_pmi(pmi_message_t pmi_msg) | ||
32 | { | ||
33 | BUG_ON(pmi_msg.type != PMI_TYPE_POWER_BUTTON); | ||
34 | |||
35 | input_report_key(button_dev, KEY_POWER, 1); | ||
36 | input_sync(button_dev); | ||
37 | input_report_key(button_dev, KEY_POWER, 0); | ||
38 | input_sync(button_dev); | ||
39 | } | ||
40 | |||
41 | static struct pmi_handler cbe_pmi_handler = { | ||
42 | .type = PMI_TYPE_POWER_BUTTON, | ||
43 | .handle_pmi_message = cbe_powerbutton_handle_pmi, | ||
44 | }; | ||
45 | |||
46 | static int __init cbe_powerbutton_init(void) | ||
47 | { | ||
48 | int ret = 0; | ||
49 | struct input_dev *dev; | ||
50 | |||
51 | if (!machine_is_compatible("IBM,CBPLUS-1.0")) { | ||
52 | printk(KERN_ERR "%s: Not a cell blade.\n", __func__); | ||
53 | ret = -ENODEV; | ||
54 | goto out; | ||
55 | } | ||
56 | |||
57 | dev = input_allocate_device(); | ||
58 | if (!dev) { | ||
59 | ret = -ENOMEM; | ||
60 | printk(KERN_ERR "%s: Not enough memory.\n", __func__); | ||
61 | goto out; | ||
62 | } | ||
63 | |||
64 | set_bit(EV_KEY, dev->evbit); | ||
65 | set_bit(KEY_POWER, dev->keybit); | ||
66 | |||
67 | dev->name = "Power Button"; | ||
68 | dev->id.bustype = BUS_HOST; | ||
69 | |||
70 | /* this makes the button look like an acpi power button | ||
71 | * no clue whether anyone relies on that though */ | ||
72 | dev->id.product = 0x02; | ||
73 | dev->phys = "LNXPWRBN/button/input0"; | ||
74 | |||
75 | button_pdev = platform_device_register_simple("power_button", 0, NULL, 0); | ||
76 | if (IS_ERR(button_pdev)) { | ||
77 | ret = PTR_ERR(button_pdev); | ||
78 | goto out_free_input; | ||
79 | } | ||
80 | |||
81 | dev->dev.parent = &button_pdev->dev; | ||
82 | ret = input_register_device(dev); | ||
83 | if (ret) { | ||
84 | printk(KERN_ERR "%s: Failed to register device\n", __func__); | ||
85 | goto out_free_pdev; | ||
86 | } | ||
87 | |||
88 | button_dev = dev; | ||
89 | |||
90 | ret = pmi_register_handler(&cbe_pmi_handler); | ||
91 | if (ret) { | ||
92 | printk(KERN_ERR "%s: Failed to register with pmi.\n", __func__); | ||
93 | goto out_free_pdev; | ||
94 | } | ||
95 | |||
96 | goto out; | ||
97 | |||
98 | out_free_pdev: | ||
99 | platform_device_unregister(button_pdev); | ||
100 | out_free_input: | ||
101 | input_free_device(dev); | ||
102 | out: | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static void __exit cbe_powerbutton_exit(void) | ||
107 | { | ||
108 | pmi_unregister_handler(&cbe_pmi_handler); | ||
109 | platform_device_unregister(button_pdev); | ||
110 | input_free_device(button_dev); | ||
111 | } | ||
112 | |||
113 | module_init(cbe_powerbutton_init); | ||
114 | module_exit(cbe_powerbutton_exit); | ||
115 | |||
116 | MODULE_LICENSE("GPL"); | ||
117 | MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); | ||
diff --git a/arch/powerpc/platforms/cell/cpufreq_spudemand.c b/arch/powerpc/platforms/cell/cpufreq_spudemand.c new file mode 100644 index 000000000000..a3c6c01bd6db --- /dev/null +++ b/arch/powerpc/platforms/cell/cpufreq_spudemand.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * spu aware cpufreq governor for the cell processor | ||
3 | * | ||
4 | * © Copyright IBM Corporation 2006-2008 | ||
5 | * | ||
6 | * Author: Christian Krafft <krafft@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/cpufreq.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/timer.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <asm/atomic.h> | ||
28 | #include <asm/machdep.h> | ||
29 | #include <asm/spu.h> | ||
30 | |||
31 | #define POLL_TIME 100000 /* in µs */ | ||
32 | #define EXP 753 /* exp(-1) in fixed-point */ | ||
33 | |||
34 | struct spu_gov_info_struct { | ||
35 | unsigned long busy_spus; /* fixed-point */ | ||
36 | struct cpufreq_policy *policy; | ||
37 | struct delayed_work work; | ||
38 | unsigned int poll_int; /* µs */ | ||
39 | }; | ||
40 | static DEFINE_PER_CPU(struct spu_gov_info_struct, spu_gov_info); | ||
41 | |||
42 | static struct workqueue_struct *kspugov_wq; | ||
43 | |||
44 | static int calc_freq(struct spu_gov_info_struct *info) | ||
45 | { | ||
46 | int cpu; | ||
47 | int busy_spus; | ||
48 | |||
49 | cpu = info->policy->cpu; | ||
50 | busy_spus = atomic_read(&cbe_spu_info[cpu_to_node(cpu)].busy_spus); | ||
51 | |||
52 | CALC_LOAD(info->busy_spus, EXP, busy_spus * FIXED_1); | ||
53 | pr_debug("cpu %d: busy_spus=%d, info->busy_spus=%ld\n", | ||
54 | cpu, busy_spus, info->busy_spus); | ||
55 | |||
56 | return info->policy->max * info->busy_spus / FIXED_1; | ||
57 | } | ||
58 | |||
59 | static void spu_gov_work(struct work_struct *work) | ||
60 | { | ||
61 | struct spu_gov_info_struct *info; | ||
62 | int delay; | ||
63 | unsigned long target_freq; | ||
64 | |||
65 | info = container_of(work, struct spu_gov_info_struct, work.work); | ||
66 | |||
67 | /* after cancel_delayed_work_sync we unset info->policy */ | ||
68 | BUG_ON(info->policy == NULL); | ||
69 | |||
70 | target_freq = calc_freq(info); | ||
71 | __cpufreq_driver_target(info->policy, target_freq, CPUFREQ_RELATION_H); | ||
72 | |||
73 | delay = usecs_to_jiffies(info->poll_int); | ||
74 | queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay); | ||
75 | } | ||
76 | |||
77 | static void spu_gov_init_work(struct spu_gov_info_struct *info) | ||
78 | { | ||
79 | int delay = usecs_to_jiffies(info->poll_int); | ||
80 | INIT_DELAYED_WORK_DEFERRABLE(&info->work, spu_gov_work); | ||
81 | queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay); | ||
82 | } | ||
83 | |||
84 | static void spu_gov_cancel_work(struct spu_gov_info_struct *info) | ||
85 | { | ||
86 | cancel_delayed_work_sync(&info->work); | ||
87 | } | ||
88 | |||
89 | static int spu_gov_govern(struct cpufreq_policy *policy, unsigned int event) | ||
90 | { | ||
91 | unsigned int cpu = policy->cpu; | ||
92 | struct spu_gov_info_struct *info, *affected_info; | ||
93 | int i; | ||
94 | int ret = 0; | ||
95 | |||
96 | info = &per_cpu(spu_gov_info, cpu); | ||
97 | |||
98 | switch (event) { | ||
99 | case CPUFREQ_GOV_START: | ||
100 | if (!cpu_online(cpu)) { | ||
101 | printk(KERN_ERR "cpu %d is not online\n", cpu); | ||
102 | ret = -EINVAL; | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | if (!policy->cur) { | ||
107 | printk(KERN_ERR "no cpu specified in policy\n"); | ||
108 | ret = -EINVAL; | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | /* initialize spu_gov_info for all affected cpus */ | ||
113 | for_each_cpu_mask(i, policy->cpus) { | ||
114 | affected_info = &per_cpu(spu_gov_info, i); | ||
115 | affected_info->policy = policy; | ||
116 | } | ||
117 | |||
118 | info->poll_int = POLL_TIME; | ||
119 | |||
120 | /* setup timer */ | ||
121 | spu_gov_init_work(info); | ||
122 | |||
123 | break; | ||
124 | |||
125 | case CPUFREQ_GOV_STOP: | ||
126 | /* cancel timer */ | ||
127 | spu_gov_cancel_work(info); | ||
128 | |||
129 | /* clean spu_gov_info for all affected cpus */ | ||
130 | for_each_cpu_mask (i, policy->cpus) { | ||
131 | info = &per_cpu(spu_gov_info, i); | ||
132 | info->policy = NULL; | ||
133 | } | ||
134 | |||
135 | break; | ||
136 | } | ||
137 | |||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static struct cpufreq_governor spu_governor = { | ||
142 | .name = "spudemand", | ||
143 | .governor = spu_gov_govern, | ||
144 | .owner = THIS_MODULE, | ||
145 | }; | ||
146 | |||
147 | /* | ||
148 | * module init and destoy | ||
149 | */ | ||
150 | |||
151 | static int __init spu_gov_init(void) | ||
152 | { | ||
153 | int ret; | ||
154 | |||
155 | kspugov_wq = create_workqueue("kspugov"); | ||
156 | if (!kspugov_wq) { | ||
157 | printk(KERN_ERR "creation of kspugov failed\n"); | ||
158 | ret = -EFAULT; | ||
159 | goto out; | ||
160 | } | ||
161 | |||
162 | ret = cpufreq_register_governor(&spu_governor); | ||
163 | if (ret) { | ||
164 | printk(KERN_ERR "registration of governor failed\n"); | ||
165 | destroy_workqueue(kspugov_wq); | ||
166 | goto out; | ||
167 | } | ||
168 | out: | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static void __exit spu_gov_exit(void) | ||
173 | { | ||
174 | cpufreq_unregister_governor(&spu_governor); | ||
175 | destroy_workqueue(kspugov_wq); | ||
176 | } | ||
177 | |||
178 | |||
179 | module_init(spu_gov_init); | ||
180 | module_exit(spu_gov_exit); | ||
181 | |||
182 | MODULE_LICENSE("GPL"); | ||
183 | MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); | ||
184 | |||
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index eeacb3a52ca1..208005ca262c 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c | |||
@@ -173,7 +173,8 @@ static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte, | |||
173 | } | 173 | } |
174 | 174 | ||
175 | static void tce_build_cell(struct iommu_table *tbl, long index, long npages, | 175 | static void tce_build_cell(struct iommu_table *tbl, long index, long npages, |
176 | unsigned long uaddr, enum dma_data_direction direction) | 176 | unsigned long uaddr, enum dma_data_direction direction, |
177 | struct dma_attrs *attrs) | ||
177 | { | 178 | { |
178 | int i; | 179 | int i; |
179 | unsigned long *io_pte, base_pte; | 180 | unsigned long *io_pte, base_pte; |
@@ -198,6 +199,8 @@ static void tce_build_cell(struct iommu_table *tbl, long index, long npages, | |||
198 | base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | | 199 | base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | |
199 | (window->ioid & IOPTE_IOID_Mask); | 200 | (window->ioid & IOPTE_IOID_Mask); |
200 | #endif | 201 | #endif |
202 | if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))) | ||
203 | base_pte &= ~IOPTE_SO_RW; | ||
201 | 204 | ||
202 | io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); | 205 | io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset); |
203 | 206 | ||
@@ -519,7 +522,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, | |||
519 | 522 | ||
520 | __set_bit(0, window->table.it_map); | 523 | __set_bit(0, window->table.it_map); |
521 | tce_build_cell(&window->table, window->table.it_offset, 1, | 524 | tce_build_cell(&window->table, window->table.it_offset, 1, |
522 | (unsigned long)iommu->pad_page, DMA_TO_DEVICE); | 525 | (unsigned long)iommu->pad_page, DMA_TO_DEVICE, NULL); |
523 | window->table.it_hint = window->table.it_blocksize; | 526 | window->table.it_hint = window->table.it_blocksize; |
524 | 527 | ||
525 | return window; | 528 | return window; |
@@ -538,7 +541,9 @@ static struct cbe_iommu *cell_iommu_for_node(int nid) | |||
538 | static unsigned long cell_dma_direct_offset; | 541 | static unsigned long cell_dma_direct_offset; |
539 | 542 | ||
540 | static unsigned long dma_iommu_fixed_base; | 543 | static unsigned long dma_iommu_fixed_base; |
541 | struct dma_mapping_ops dma_iommu_fixed_ops; | 544 | |
545 | /* iommu_fixed_is_weak is set if booted with iommu_fixed=weak */ | ||
546 | static int iommu_fixed_is_weak; | ||
542 | 547 | ||
543 | static struct iommu_table *cell_get_iommu_table(struct device *dev) | 548 | static struct iommu_table *cell_get_iommu_table(struct device *dev) |
544 | { | 549 | { |
@@ -562,6 +567,98 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev) | |||
562 | return &window->table; | 567 | return &window->table; |
563 | } | 568 | } |
564 | 569 | ||
570 | /* A coherent allocation implies strong ordering */ | ||
571 | |||
572 | static void *dma_fixed_alloc_coherent(struct device *dev, size_t size, | ||
573 | dma_addr_t *dma_handle, gfp_t flag) | ||
574 | { | ||
575 | if (iommu_fixed_is_weak) | ||
576 | return iommu_alloc_coherent(dev, cell_get_iommu_table(dev), | ||
577 | size, dma_handle, | ||
578 | device_to_mask(dev), flag, | ||
579 | dev->archdata.numa_node); | ||
580 | else | ||
581 | return dma_direct_ops.alloc_coherent(dev, size, dma_handle, | ||
582 | flag); | ||
583 | } | ||
584 | |||
585 | static void dma_fixed_free_coherent(struct device *dev, size_t size, | ||
586 | void *vaddr, dma_addr_t dma_handle) | ||
587 | { | ||
588 | if (iommu_fixed_is_weak) | ||
589 | iommu_free_coherent(cell_get_iommu_table(dev), size, vaddr, | ||
590 | dma_handle); | ||
591 | else | ||
592 | dma_direct_ops.free_coherent(dev, size, vaddr, dma_handle); | ||
593 | } | ||
594 | |||
595 | static dma_addr_t dma_fixed_map_single(struct device *dev, void *ptr, | ||
596 | size_t size, | ||
597 | enum dma_data_direction direction, | ||
598 | struct dma_attrs *attrs) | ||
599 | { | ||
600 | if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) | ||
601 | return dma_direct_ops.map_single(dev, ptr, size, direction, | ||
602 | attrs); | ||
603 | else | ||
604 | return iommu_map_single(dev, cell_get_iommu_table(dev), ptr, | ||
605 | size, device_to_mask(dev), direction, | ||
606 | attrs); | ||
607 | } | ||
608 | |||
609 | static void dma_fixed_unmap_single(struct device *dev, dma_addr_t dma_addr, | ||
610 | size_t size, | ||
611 | enum dma_data_direction direction, | ||
612 | struct dma_attrs *attrs) | ||
613 | { | ||
614 | if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) | ||
615 | dma_direct_ops.unmap_single(dev, dma_addr, size, direction, | ||
616 | attrs); | ||
617 | else | ||
618 | iommu_unmap_single(cell_get_iommu_table(dev), dma_addr, size, | ||
619 | direction, attrs); | ||
620 | } | ||
621 | |||
622 | static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg, | ||
623 | int nents, enum dma_data_direction direction, | ||
624 | struct dma_attrs *attrs) | ||
625 | { | ||
626 | if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) | ||
627 | return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs); | ||
628 | else | ||
629 | return iommu_map_sg(dev, cell_get_iommu_table(dev), sg, nents, | ||
630 | device_to_mask(dev), direction, attrs); | ||
631 | } | ||
632 | |||
633 | static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg, | ||
634 | int nents, enum dma_data_direction direction, | ||
635 | struct dma_attrs *attrs) | ||
636 | { | ||
637 | if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) | ||
638 | dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs); | ||
639 | else | ||
640 | iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents, direction, | ||
641 | attrs); | ||
642 | } | ||
643 | |||
644 | static int dma_fixed_dma_supported(struct device *dev, u64 mask) | ||
645 | { | ||
646 | return mask == DMA_64BIT_MASK; | ||
647 | } | ||
648 | |||
649 | static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask); | ||
650 | |||
651 | struct dma_mapping_ops dma_iommu_fixed_ops = { | ||
652 | .alloc_coherent = dma_fixed_alloc_coherent, | ||
653 | .free_coherent = dma_fixed_free_coherent, | ||
654 | .map_single = dma_fixed_map_single, | ||
655 | .unmap_single = dma_fixed_unmap_single, | ||
656 | .map_sg = dma_fixed_map_sg, | ||
657 | .unmap_sg = dma_fixed_unmap_sg, | ||
658 | .dma_supported = dma_fixed_dma_supported, | ||
659 | .set_dma_mask = dma_set_mask_and_switch, | ||
660 | }; | ||
661 | |||
565 | static void cell_dma_dev_setup_fixed(struct device *dev); | 662 | static void cell_dma_dev_setup_fixed(struct device *dev); |
566 | 663 | ||
567 | static void cell_dma_dev_setup(struct device *dev) | 664 | static void cell_dma_dev_setup(struct device *dev) |
@@ -918,9 +1015,16 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu, | |||
918 | 1015 | ||
919 | pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase); | 1016 | pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase); |
920 | 1017 | ||
921 | base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | 1018 | base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M |
922 | | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask); | 1019 | | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask); |
923 | 1020 | ||
1021 | if (iommu_fixed_is_weak) | ||
1022 | pr_info("IOMMU: Using weak ordering for fixed mapping\n"); | ||
1023 | else { | ||
1024 | pr_info("IOMMU: Using strong ordering for fixed mapping\n"); | ||
1025 | base_pte |= IOPTE_SO_RW; | ||
1026 | } | ||
1027 | |||
924 | for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) { | 1028 | for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) { |
925 | /* Don't touch the dynamic region */ | 1029 | /* Don't touch the dynamic region */ |
926 | ioaddr = uaddr + fbase; | 1030 | ioaddr = uaddr + fbase; |
@@ -1036,9 +1140,6 @@ static int __init cell_iommu_fixed_mapping_init(void) | |||
1036 | cell_iommu_setup_window(iommu, np, dbase, dsize, 0); | 1140 | cell_iommu_setup_window(iommu, np, dbase, dsize, 0); |
1037 | } | 1141 | } |
1038 | 1142 | ||
1039 | dma_iommu_fixed_ops = dma_direct_ops; | ||
1040 | dma_iommu_fixed_ops.set_dma_mask = dma_set_mask_and_switch; | ||
1041 | |||
1042 | dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch; | 1143 | dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch; |
1043 | set_pci_dma_ops(&dma_iommu_ops); | 1144 | set_pci_dma_ops(&dma_iommu_ops); |
1044 | 1145 | ||
@@ -1052,6 +1153,9 @@ static int __init setup_iommu_fixed(char *str) | |||
1052 | if (strcmp(str, "off") == 0) | 1153 | if (strcmp(str, "off") == 0) |
1053 | iommu_fixed_disabled = 1; | 1154 | iommu_fixed_disabled = 1; |
1054 | 1155 | ||
1156 | else if (strcmp(str, "weak") == 0) | ||
1157 | iommu_fixed_is_weak = 1; | ||
1158 | |||
1055 | return 1; | 1159 | return 1; |
1056 | } | 1160 | } |
1057 | __setup("iommu_fixed=", setup_iommu_fixed); | 1161 | __setup("iommu_fixed=", setup_iommu_fixed); |
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 8a3631ce912b..efdacc829576 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c | |||
@@ -38,8 +38,6 @@ | |||
38 | 38 | ||
39 | #include "pervasive.h" | 39 | #include "pervasive.h" |
40 | 40 | ||
41 | static int sysreset_hack; | ||
42 | |||
43 | static void cbe_power_save(void) | 41 | static void cbe_power_save(void) |
44 | { | 42 | { |
45 | unsigned long ctrl, thread_switch_control; | 43 | unsigned long ctrl, thread_switch_control; |
@@ -87,9 +85,6 @@ static void cbe_power_save(void) | |||
87 | 85 | ||
88 | static int cbe_system_reset_exception(struct pt_regs *regs) | 86 | static int cbe_system_reset_exception(struct pt_regs *regs) |
89 | { | 87 | { |
90 | int cpu; | ||
91 | struct cbe_pmd_regs __iomem *pmd; | ||
92 | |||
93 | switch (regs->msr & SRR1_WAKEMASK) { | 88 | switch (regs->msr & SRR1_WAKEMASK) { |
94 | case SRR1_WAKEEE: | 89 | case SRR1_WAKEEE: |
95 | do_IRQ(regs); | 90 | do_IRQ(regs); |
@@ -98,19 +93,7 @@ static int cbe_system_reset_exception(struct pt_regs *regs) | |||
98 | timer_interrupt(regs); | 93 | timer_interrupt(regs); |
99 | break; | 94 | break; |
100 | case SRR1_WAKEMT: | 95 | case SRR1_WAKEMT: |
101 | /* | 96 | return cbe_sysreset_hack(); |
102 | * The BMC can inject user triggered system reset exceptions, | ||
103 | * but cannot set the system reset reason in srr1, | ||
104 | * so check an extra register here. | ||
105 | */ | ||
106 | if (sysreset_hack && (cpu = smp_processor_id()) == 0) { | ||
107 | pmd = cbe_get_cpu_pmd_regs(cpu); | ||
108 | if (in_be64(&pmd->ras_esc_0) & 0xffff) { | ||
109 | out_be64(&pmd->ras_esc_0, 0); | ||
110 | return 0; | ||
111 | } | ||
112 | } | ||
113 | break; | ||
114 | #ifdef CONFIG_CBE_RAS | 97 | #ifdef CONFIG_CBE_RAS |
115 | case SRR1_WAKESYSERR: | 98 | case SRR1_WAKESYSERR: |
116 | cbe_system_error_exception(regs); | 99 | cbe_system_error_exception(regs); |
@@ -134,8 +117,6 @@ void __init cbe_pervasive_init(void) | |||
134 | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) | 117 | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) |
135 | return; | 118 | return; |
136 | 119 | ||
137 | sysreset_hack = machine_is_compatible("IBM,CBPLUS-1.0"); | ||
138 | |||
139 | for_each_possible_cpu(cpu) { | 120 | for_each_possible_cpu(cpu) { |
140 | struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); | 121 | struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); |
141 | if (!regs) | 122 | if (!regs) |
@@ -144,12 +125,6 @@ void __init cbe_pervasive_init(void) | |||
144 | /* Enable Pause(0) control bit */ | 125 | /* Enable Pause(0) control bit */ |
145 | out_be64(®s->pmcr, in_be64(®s->pmcr) | | 126 | out_be64(®s->pmcr, in_be64(®s->pmcr) | |
146 | CBE_PMD_PAUSE_ZERO_CONTROL); | 127 | CBE_PMD_PAUSE_ZERO_CONTROL); |
147 | |||
148 | /* Enable JTAG system-reset hack */ | ||
149 | if (sysreset_hack) | ||
150 | out_be32(®s->fir_mode_reg, | ||
151 | in_be32(®s->fir_mode_reg) | | ||
152 | CBE_PMD_FIR_MODE_M8); | ||
153 | } | 128 | } |
154 | 129 | ||
155 | ppc_md.power_save = cbe_power_save; | 130 | ppc_md.power_save = cbe_power_save; |
diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h index 7b50947f8044..fd4d7b7092b4 100644 --- a/arch/powerpc/platforms/cell/pervasive.h +++ b/arch/powerpc/platforms/cell/pervasive.h | |||
@@ -30,4 +30,13 @@ extern void cbe_system_error_exception(struct pt_regs *regs); | |||
30 | extern void cbe_maintenance_exception(struct pt_regs *regs); | 30 | extern void cbe_maintenance_exception(struct pt_regs *regs); |
31 | extern void cbe_thermal_exception(struct pt_regs *regs); | 31 | extern void cbe_thermal_exception(struct pt_regs *regs); |
32 | 32 | ||
33 | #ifdef CONFIG_PPC_IBM_CELL_RESETBUTTON | ||
34 | extern int cbe_sysreset_hack(void); | ||
35 | #else | ||
36 | static inline int cbe_sysreset_hack(void) | ||
37 | { | ||
38 | return 1; | ||
39 | } | ||
40 | #endif /* CONFIG_PPC_IBM_CELL_RESETBUTTON */ | ||
41 | |||
33 | #endif | 42 | #endif |
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index 505f9b9bdf0c..2a14b052abcd 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c | |||
@@ -236,6 +236,52 @@ static struct notifier_block cbe_ptcal_reboot_notifier = { | |||
236 | .notifier_call = cbe_ptcal_notify_reboot | 236 | .notifier_call = cbe_ptcal_notify_reboot |
237 | }; | 237 | }; |
238 | 238 | ||
239 | #ifdef CONFIG_PPC_IBM_CELL_RESETBUTTON | ||
240 | static int sysreset_hack; | ||
241 | |||
242 | static int __init cbe_sysreset_init(void) | ||
243 | { | ||
244 | struct cbe_pmd_regs __iomem *regs; | ||
245 | |||
246 | sysreset_hack = machine_is_compatible("IBM,CBPLUS-1.0"); | ||
247 | if (!sysreset_hack) | ||
248 | return 0; | ||
249 | |||
250 | regs = cbe_get_cpu_pmd_regs(0); | ||
251 | if (!regs) | ||
252 | return 0; | ||
253 | |||
254 | /* Enable JTAG system-reset hack */ | ||
255 | out_be32(®s->fir_mode_reg, | ||
256 | in_be32(®s->fir_mode_reg) | | ||
257 | CBE_PMD_FIR_MODE_M8); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | device_initcall(cbe_sysreset_init); | ||
262 | |||
263 | int cbe_sysreset_hack(void) | ||
264 | { | ||
265 | struct cbe_pmd_regs __iomem *regs; | ||
266 | |||
267 | /* | ||
268 | * The BMC can inject user triggered system reset exceptions, | ||
269 | * but cannot set the system reset reason in srr1, | ||
270 | * so check an extra register here. | ||
271 | */ | ||
272 | if (sysreset_hack && (smp_processor_id() == 0)) { | ||
273 | regs = cbe_get_cpu_pmd_regs(0); | ||
274 | if (!regs) | ||
275 | return 0; | ||
276 | if (in_be64(®s->ras_esc_0) & 0x0000ffff) { | ||
277 | out_be64(®s->ras_esc_0, 0); | ||
278 | return 0; | ||
279 | } | ||
280 | } | ||
281 | return 1; | ||
282 | } | ||
283 | #endif /* CONFIG_PPC_IBM_CELL_RESETBUTTON */ | ||
284 | |||
239 | int __init cbe_ptcal_init(void) | 285 | int __init cbe_ptcal_init(void) |
240 | { | 286 | { |
241 | int ret; | 287 | int ret; |