diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-01-30 18:20:27 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-02-06 22:03:19 -0500 |
commit | 2a08ea69a3e448a5cc94e5da9eccc40cf13f9532 (patch) | |
tree | 76fe2d0788c533b1d5fc1a89a34606d84b79961a /arch/powerpc | |
parent | 63c2f782e8f6aafbc11b14b2cb291b3dc9fc217d (diff) |
[POWERPC] PS3: Move system bus to platform directory
Move the PS3 system bus routines from drivers/ps3 to
arch/powerpc/platforms/ps3.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/platforms/ps3/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/htab.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/interrupt.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/mm.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/os-area.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/platform.h | 151 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/repository.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/setup.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/smp.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/spu.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/system-bus.c | 363 |
11 files changed, 519 insertions, 8 deletions
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index 1994904f580f..a0048fcf0866 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o | 1 | obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o |
2 | obj-y += interrupt.o exports.o os-area.o | 2 | obj-y += interrupt.o exports.o os-area.o |
3 | obj-y += system-bus.o | ||
3 | 4 | ||
4 | obj-$(CONFIG_SMP) += smp.o | 5 | obj-$(CONFIG_SMP) += smp.o |
5 | obj-$(CONFIG_SPU_BASE) += spu.o | 6 | obj-$(CONFIG_SPU_BASE) += spu.o |
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 8fe1769655a3..a4b5a1bc60f4 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <asm/machdep.h> | 23 | #include <asm/machdep.h> |
24 | #include <asm/lmb.h> | 24 | #include <asm/lmb.h> |
25 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
26 | #include <asm/ps3.h> | ||
27 | #include <asm/lv1call.h> | 26 | #include <asm/lv1call.h> |
28 | 27 | ||
29 | #include "platform.h" | 28 | #include "platform.h" |
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 95b128ba9087..bb17283275aa 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -24,7 +24,6 @@ | |||
24 | 24 | ||
25 | #include <asm/machdep.h> | 25 | #include <asm/machdep.h> |
26 | #include <asm/udbg.h> | 26 | #include <asm/udbg.h> |
27 | #include <asm/ps3.h> | ||
28 | #include <asm/lv1call.h> | 27 | #include <asm/lv1call.h> |
29 | 28 | ||
30 | #include "platform.h" | 29 | #include "platform.h" |
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 49c0d010d491..42354de3f557 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <asm/firmware.h> | 25 | #include <asm/firmware.h> |
26 | #include <asm/lmb.h> | 26 | #include <asm/lmb.h> |
27 | #include <asm/udbg.h> | 27 | #include <asm/udbg.h> |
28 | #include <asm/ps3.h> | ||
29 | #include <asm/lv1call.h> | 28 | #include <asm/lv1call.h> |
30 | 29 | ||
31 | #include "platform.h" | 30 | #include "platform.h" |
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 6d0d2ac39bd8..5c3da08bc0c4 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | 23 | ||
24 | #include <asm/lmb.h> | 24 | #include <asm/lmb.h> |
25 | #include <asm/ps3.h> | ||
26 | 25 | ||
27 | #include "platform.h" | 26 | #include "platform.h" |
28 | 27 | ||
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 23b111bea9d0..ca04f03305c7 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h | |||
@@ -22,6 +22,9 @@ | |||
22 | #define _PS3_PLATFORM_H | 22 | #define _PS3_PLATFORM_H |
23 | 23 | ||
24 | #include <linux/rtc.h> | 24 | #include <linux/rtc.h> |
25 | #include <scsi/scsi.h> | ||
26 | |||
27 | #include <asm/ps3.h> | ||
25 | 28 | ||
26 | /* htab */ | 29 | /* htab */ |
27 | 30 | ||
@@ -65,4 +68,152 @@ void ps3_spu_set_platform (void); | |||
65 | static inline void ps3_spu_set_platform (void) {} | 68 | static inline void ps3_spu_set_platform (void) {} |
66 | #endif | 69 | #endif |
67 | 70 | ||
71 | /* repository bus info */ | ||
72 | |||
73 | enum ps3_bus_type { | ||
74 | PS3_BUS_TYPE_SB = 4, | ||
75 | PS3_BUS_TYPE_STORAGE = 5, | ||
76 | }; | ||
77 | |||
78 | enum ps3_dev_type { | ||
79 | PS3_DEV_TYPE_STOR_DISK = TYPE_DISK, /* 0 */ | ||
80 | PS3_DEV_TYPE_SB_GELIC = 3, | ||
81 | PS3_DEV_TYPE_SB_USB = 4, | ||
82 | PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ | ||
83 | PS3_DEV_TYPE_SB_GPIO = 6, | ||
84 | PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ | ||
85 | }; | ||
86 | |||
87 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | ||
88 | u64 *value); | ||
89 | int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id); | ||
90 | int ps3_repository_read_bus_type(unsigned int bus_index, | ||
91 | enum ps3_bus_type *bus_type); | ||
92 | int ps3_repository_read_bus_num_dev(unsigned int bus_index, | ||
93 | unsigned int *num_dev); | ||
94 | |||
95 | /* repository bus device info */ | ||
96 | |||
97 | enum ps3_interrupt_type { | ||
98 | PS3_INTERRUPT_TYPE_EVENT_PORT = 2, | ||
99 | PS3_INTERRUPT_TYPE_SB_OHCI = 3, | ||
100 | PS3_INTERRUPT_TYPE_SB_EHCI = 4, | ||
101 | PS3_INTERRUPT_TYPE_OTHER = 5, | ||
102 | }; | ||
103 | |||
104 | enum ps3_reg_type { | ||
105 | PS3_REG_TYPE_SB_OHCI = 3, | ||
106 | PS3_REG_TYPE_SB_EHCI = 4, | ||
107 | PS3_REG_TYPE_SB_GPIO = 5, | ||
108 | }; | ||
109 | |||
110 | int ps3_repository_read_dev_str(unsigned int bus_index, | ||
111 | unsigned int dev_index, const char *dev_str, u64 *value); | ||
112 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, | ||
113 | unsigned int *dev_id); | ||
114 | int ps3_repository_read_dev_type(unsigned int bus_index, | ||
115 | unsigned int dev_index, enum ps3_dev_type *dev_type); | ||
116 | int ps3_repository_read_dev_intr(unsigned int bus_index, | ||
117 | unsigned int dev_index, unsigned int intr_index, | ||
118 | enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id); | ||
119 | int ps3_repository_read_dev_reg_type(unsigned int bus_index, | ||
120 | unsigned int dev_index, unsigned int reg_index, | ||
121 | enum ps3_reg_type *reg_type); | ||
122 | int ps3_repository_read_dev_reg_addr(unsigned int bus_index, | ||
123 | unsigned int dev_index, unsigned int reg_index, u64 *bus_addr, | ||
124 | u64 *len); | ||
125 | int ps3_repository_read_dev_reg(unsigned int bus_index, | ||
126 | unsigned int dev_index, unsigned int reg_index, | ||
127 | enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len); | ||
128 | |||
129 | /* repository bus enumerators */ | ||
130 | |||
131 | struct ps3_repository_device { | ||
132 | unsigned int bus_index; | ||
133 | unsigned int dev_index; | ||
134 | struct ps3_device_id did; | ||
135 | }; | ||
136 | |||
137 | int ps3_repository_find_device(enum ps3_bus_type bus_type, | ||
138 | enum ps3_dev_type dev_type, | ||
139 | const struct ps3_repository_device *start_dev, | ||
140 | struct ps3_repository_device *dev); | ||
141 | static inline int ps3_repository_find_first_device( | ||
142 | enum ps3_bus_type bus_type, enum ps3_dev_type dev_type, | ||
143 | struct ps3_repository_device *dev) | ||
144 | { | ||
145 | return ps3_repository_find_device(bus_type, dev_type, NULL, dev); | ||
146 | } | ||
147 | int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | ||
148 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id); | ||
149 | int ps3_repository_find_reg(const struct ps3_repository_device *dev, | ||
150 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len); | ||
151 | |||
152 | /* repository block device info */ | ||
153 | |||
154 | int ps3_repository_read_stor_dev_port(unsigned int bus_index, | ||
155 | unsigned int dev_index, u64 *port); | ||
156 | int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, | ||
157 | unsigned int dev_index, u64 *blk_size); | ||
158 | int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, | ||
159 | unsigned int dev_index, u64 *num_blocks); | ||
160 | int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, | ||
161 | unsigned int dev_index, unsigned int *num_regions); | ||
162 | int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, | ||
163 | unsigned int dev_index, unsigned int region_index, | ||
164 | unsigned int *region_id); | ||
165 | int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, | ||
166 | unsigned int dev_index, unsigned int region_index, u64 *region_size); | ||
167 | int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, | ||
168 | unsigned int dev_index, unsigned int region_index, u64 *region_start); | ||
169 | int ps3_repository_read_stor_dev_info(unsigned int bus_index, | ||
170 | unsigned int dev_index, u64 *port, u64 *blk_size, | ||
171 | u64 *num_blocks, unsigned int *num_regions); | ||
172 | int ps3_repository_read_stor_dev_region(unsigned int bus_index, | ||
173 | unsigned int dev_index, unsigned int region_index, | ||
174 | unsigned int *region_id, u64 *region_start, u64 *region_size); | ||
175 | |||
176 | /* repository pu and memory info */ | ||
177 | |||
178 | int ps3_repository_read_num_pu(unsigned int *num_pu); | ||
179 | int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id); | ||
180 | int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); | ||
181 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); | ||
182 | int ps3_repository_read_region_total(u64 *region_total); | ||
183 | int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, | ||
184 | u64 *region_total); | ||
185 | |||
186 | /* repository pme info */ | ||
187 | |||
188 | int ps3_repository_read_num_be(unsigned int *num_be); | ||
189 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); | ||
190 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); | ||
191 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); | ||
192 | |||
193 | /* repository 'Other OS' area */ | ||
194 | |||
195 | int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); | ||
196 | int ps3_repository_read_boot_dat_size(unsigned int *size); | ||
197 | int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size); | ||
198 | |||
199 | /* repository spu info */ | ||
200 | |||
201 | /** | ||
202 | * enum spu_resource_type - Type of spu resource. | ||
203 | * @spu_resource_type_shared: Logical spu is shared with other partions. | ||
204 | * @spu_resource_type_exclusive: Logical spu is not shared with other partions. | ||
205 | * | ||
206 | * Returned by ps3_repository_read_spu_resource_id(). | ||
207 | */ | ||
208 | |||
209 | enum ps3_spu_resource_type { | ||
210 | PS3_SPU_RESOURCE_TYPE_SHARED = 0, | ||
211 | PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL, | ||
212 | }; | ||
213 | |||
214 | int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved); | ||
215 | int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id); | ||
216 | int ps3_repository_read_spu_resource_id(unsigned int res_index, | ||
217 | enum ps3_spu_resource_type* resource_type, unsigned int *resource_id); | ||
218 | |||
68 | #endif | 219 | #endif |
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 2416bfadec9e..ae586a0e5d3f 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c | |||
@@ -18,9 +18,10 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <asm/ps3.h> | ||
22 | #include <asm/lv1call.h> | 21 | #include <asm/lv1call.h> |
23 | 22 | ||
23 | #include "platform.h" | ||
24 | |||
24 | enum ps3_vendor_id { | 25 | enum ps3_vendor_id { |
25 | PS3_VENDOR_ID_NONE = 0, | 26 | PS3_VENDOR_ID_NONE = 0, |
26 | PS3_VENDOR_ID_SONY = 0x8000000000000000UL, | 27 | PS3_VENDOR_ID_SONY = 0x8000000000000000UL, |
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index cb91a81352bf..e62505e18813 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <asm/udbg.h> | 32 | #include <asm/udbg.h> |
33 | #include <asm/prom.h> | 33 | #include <asm/prom.h> |
34 | #include <asm/lv1call.h> | 34 | #include <asm/lv1call.h> |
35 | #include <asm/ps3.h> | ||
36 | 35 | ||
37 | #include "platform.h" | 36 | #include "platform.h" |
38 | 37 | ||
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index bde71b0572bd..6fb887961a6d 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c | |||
@@ -23,7 +23,6 @@ | |||
23 | 23 | ||
24 | #include <asm/machdep.h> | 24 | #include <asm/machdep.h> |
25 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
26 | #include <asm/ps3.h> | ||
27 | 26 | ||
28 | #include "platform.h" | 27 | #include "platform.h" |
29 | 28 | ||
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 9f6edc58568d..d1929721b0e4 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c | |||
@@ -26,9 +26,10 @@ | |||
26 | 26 | ||
27 | #include <asm/spu.h> | 27 | #include <asm/spu.h> |
28 | #include <asm/spu_priv1.h> | 28 | #include <asm/spu_priv1.h> |
29 | #include <asm/ps3.h> | ||
30 | #include <asm/lv1call.h> | 29 | #include <asm/lv1call.h> |
31 | 30 | ||
31 | #include "platform.h" | ||
32 | |||
32 | /* spu_management_ops */ | 33 | /* spu_management_ops */ |
33 | 34 | ||
34 | /** | 35 | /** |
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c new file mode 100644 index 000000000000..9f2c6a909e4d --- /dev/null +++ b/arch/powerpc/platforms/ps3/system-bus.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * PS3 system bus driver. | ||
3 | * | ||
4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2006 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/dma-mapping.h> | ||
25 | #include <linux/err.h> | ||
26 | |||
27 | #include <asm/udbg.h> | ||
28 | #include <asm/lv1call.h> | ||
29 | #include <asm/firmware.h> | ||
30 | |||
31 | #include "platform.h" | ||
32 | |||
33 | #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) | ||
34 | static void _dump_mmio_region(const struct ps3_mmio_region* r, | ||
35 | const char* func, int line) | ||
36 | { | ||
37 | pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, | ||
38 | r->did.dev_id); | ||
39 | pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | ||
40 | pr_debug("%s:%d: len %lxh\n", func, line, r->len); | ||
41 | pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); | ||
42 | } | ||
43 | |||
44 | int ps3_mmio_region_create(struct ps3_mmio_region *r) | ||
45 | { | ||
46 | int result; | ||
47 | |||
48 | result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id, | ||
49 | r->bus_addr, r->len, r->page_size, &r->lpar_addr); | ||
50 | |||
51 | if (result) { | ||
52 | pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n", | ||
53 | __func__, __LINE__, ps3_result(result)); | ||
54 | r->lpar_addr = 0; | ||
55 | } | ||
56 | |||
57 | dump_mmio_region(r); | ||
58 | return result; | ||
59 | } | ||
60 | |||
61 | int ps3_free_mmio_region(struct ps3_mmio_region *r) | ||
62 | { | ||
63 | int result; | ||
64 | |||
65 | result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id, | ||
66 | r->lpar_addr); | ||
67 | |||
68 | if (result) | ||
69 | pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n", | ||
70 | __func__, __LINE__, ps3_result(result)); | ||
71 | |||
72 | r->lpar_addr = 0; | ||
73 | return result; | ||
74 | } | ||
75 | |||
76 | static int ps3_system_bus_match(struct device *_dev, | ||
77 | struct device_driver *_drv) | ||
78 | { | ||
79 | int result; | ||
80 | struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv); | ||
81 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
82 | |||
83 | result = dev->match_id == drv->match_id; | ||
84 | |||
85 | pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__, | ||
86 | dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name, | ||
87 | (result ? "match" : "miss")); | ||
88 | return result; | ||
89 | } | ||
90 | |||
91 | static int ps3_system_bus_probe(struct device *_dev) | ||
92 | { | ||
93 | int result; | ||
94 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
95 | struct ps3_system_bus_driver *drv = | ||
96 | to_ps3_system_bus_driver(_dev->driver); | ||
97 | |||
98 | result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0); | ||
99 | |||
100 | if (result) { | ||
101 | pr_debug("%s:%d: lv1_open_device failed (%d)\n", | ||
102 | __func__, __LINE__, result); | ||
103 | result = -EACCES; | ||
104 | goto clean_none; | ||
105 | } | ||
106 | |||
107 | if (dev->d_region->did.bus_id) { | ||
108 | result = ps3_dma_region_create(dev->d_region); | ||
109 | |||
110 | if (result) { | ||
111 | pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", | ||
112 | __func__, __LINE__, result); | ||
113 | BUG_ON("check region type"); | ||
114 | result = -EINVAL; | ||
115 | goto clean_device; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | BUG_ON(!drv); | ||
120 | |||
121 | if (drv->probe) | ||
122 | result = drv->probe(dev); | ||
123 | else | ||
124 | pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, | ||
125 | dev->core.bus_id); | ||
126 | |||
127 | if (result) { | ||
128 | pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__); | ||
129 | goto clean_dma; | ||
130 | } | ||
131 | |||
132 | return result; | ||
133 | |||
134 | clean_dma: | ||
135 | ps3_dma_region_free(dev->d_region); | ||
136 | clean_device: | ||
137 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | ||
138 | clean_none: | ||
139 | return result; | ||
140 | } | ||
141 | |||
142 | static int ps3_system_bus_remove(struct device *_dev) | ||
143 | { | ||
144 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
145 | struct ps3_system_bus_driver *drv = | ||
146 | to_ps3_system_bus_driver(_dev->driver); | ||
147 | |||
148 | if (drv->remove) | ||
149 | drv->remove(dev); | ||
150 | else | ||
151 | pr_info("%s:%d: %s no remove method\n", __func__, __LINE__, | ||
152 | dev->core.bus_id); | ||
153 | |||
154 | ps3_dma_region_free(dev->d_region); | ||
155 | ps3_free_mmio_region(dev->m_region); | ||
156 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | struct bus_type ps3_system_bus_type = { | ||
162 | .name = "ps3_system_bus", | ||
163 | .match = ps3_system_bus_match, | ||
164 | .probe = ps3_system_bus_probe, | ||
165 | .remove = ps3_system_bus_remove, | ||
166 | }; | ||
167 | |||
168 | int __init ps3_system_bus_init(void) | ||
169 | { | ||
170 | int result; | ||
171 | |||
172 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
173 | return 0; | ||
174 | |||
175 | result = bus_register(&ps3_system_bus_type); | ||
176 | BUG_ON(result); | ||
177 | return result; | ||
178 | } | ||
179 | |||
180 | core_initcall(ps3_system_bus_init); | ||
181 | |||
182 | /* Allocates a contiguous real buffer and creates mappings over it. | ||
183 | * Returns the virtual address of the buffer and sets dma_handle | ||
184 | * to the dma address (mapping) of the first page. | ||
185 | */ | ||
186 | |||
187 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, | ||
188 | dma_addr_t *dma_handle, gfp_t flag) | ||
189 | { | ||
190 | int result; | ||
191 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
192 | unsigned long virt_addr; | ||
193 | |||
194 | BUG_ON(!dev->d_region->bus_addr); | ||
195 | |||
196 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); | ||
197 | flag |= __GFP_ZERO; | ||
198 | |||
199 | virt_addr = __get_free_pages(flag, get_order(size)); | ||
200 | |||
201 | if (!virt_addr) { | ||
202 | pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__); | ||
203 | goto clean_none; | ||
204 | } | ||
205 | |||
206 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); | ||
207 | |||
208 | if (result) { | ||
209 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
210 | __func__, __LINE__, result); | ||
211 | BUG_ON("check region type"); | ||
212 | goto clean_alloc; | ||
213 | } | ||
214 | |||
215 | return (void*)virt_addr; | ||
216 | |||
217 | clean_alloc: | ||
218 | free_pages(virt_addr, get_order(size)); | ||
219 | clean_none: | ||
220 | dma_handle = NULL; | ||
221 | return NULL; | ||
222 | } | ||
223 | |||
224 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | ||
225 | dma_addr_t dma_handle) | ||
226 | { | ||
227 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
228 | |||
229 | ps3_dma_unmap(dev->d_region, dma_handle, size); | ||
230 | free_pages((unsigned long)vaddr, get_order(size)); | ||
231 | } | ||
232 | |||
233 | /* Creates TCEs for a user provided buffer. The user buffer must be | ||
234 | * contiguous real kernel storage (not vmalloc). The address of the buffer | ||
235 | * passed here is the kernel (virtual) address of the buffer. The buffer | ||
236 | * need not be page aligned, the dma_addr_t returned will point to the same | ||
237 | * byte within the page as vaddr. | ||
238 | */ | ||
239 | |||
240 | static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | ||
241 | enum dma_data_direction direction) | ||
242 | { | ||
243 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
244 | int result; | ||
245 | unsigned long bus_addr; | ||
246 | |||
247 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | ||
248 | &bus_addr); | ||
249 | |||
250 | if (result) { | ||
251 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
252 | __func__, __LINE__, result); | ||
253 | } | ||
254 | |||
255 | return bus_addr; | ||
256 | } | ||
257 | |||
258 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | ||
259 | size_t size, enum dma_data_direction direction) | ||
260 | { | ||
261 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
262 | int result; | ||
263 | |||
264 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); | ||
265 | |||
266 | if (result) { | ||
267 | pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n", | ||
268 | __func__, __LINE__, result); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | ||
273 | enum dma_data_direction direction) | ||
274 | { | ||
275 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | ||
276 | BUG_ON("do"); | ||
277 | #endif | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
282 | int nents, enum dma_data_direction direction) | ||
283 | { | ||
284 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | ||
285 | BUG_ON("do"); | ||
286 | #endif | ||
287 | } | ||
288 | |||
289 | static int ps3_dma_supported(struct device *_dev, u64 mask) | ||
290 | { | ||
291 | return 1; | ||
292 | } | ||
293 | |||
294 | static struct dma_mapping_ops ps3_dma_ops = { | ||
295 | .alloc_coherent = ps3_alloc_coherent, | ||
296 | .free_coherent = ps3_free_coherent, | ||
297 | .map_single = ps3_map_single, | ||
298 | .unmap_single = ps3_unmap_single, | ||
299 | .map_sg = ps3_map_sg, | ||
300 | .unmap_sg = ps3_unmap_sg, | ||
301 | .dma_supported = ps3_dma_supported | ||
302 | }; | ||
303 | |||
304 | /** | ||
305 | * ps3_system_bus_release_device - remove a device from the system bus | ||
306 | */ | ||
307 | |||
308 | static void ps3_system_bus_release_device(struct device *_dev) | ||
309 | { | ||
310 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
311 | kfree(dev); | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * ps3_system_bus_device_register - add a device to the system bus | ||
316 | * | ||
317 | * ps3_system_bus_device_register() expects the dev object to be allocated | ||
318 | * dynamically by the caller. The system bus takes ownership of the dev | ||
319 | * object and frees the object in ps3_system_bus_release_device(). | ||
320 | */ | ||
321 | |||
322 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) | ||
323 | { | ||
324 | int result; | ||
325 | static unsigned int dev_count = 1; | ||
326 | |||
327 | dev->core.parent = NULL; | ||
328 | dev->core.bus = &ps3_system_bus_type; | ||
329 | dev->core.release = ps3_system_bus_release_device; | ||
330 | |||
331 | dev->core.archdata.of_node = NULL; | ||
332 | dev->core.archdata.dma_ops = &ps3_dma_ops; | ||
333 | dev->core.archdata.numa_node = 0; | ||
334 | |||
335 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x", | ||
336 | dev_count++); | ||
337 | |||
338 | pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); | ||
339 | |||
340 | result = device_register(&dev->core); | ||
341 | return result; | ||
342 | } | ||
343 | |||
344 | EXPORT_SYMBOL_GPL(ps3_system_bus_device_register); | ||
345 | |||
346 | int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) | ||
347 | { | ||
348 | int result; | ||
349 | |||
350 | drv->core.bus = &ps3_system_bus_type; | ||
351 | |||
352 | result = driver_register(&drv->core); | ||
353 | return result; | ||
354 | } | ||
355 | |||
356 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); | ||
357 | |||
358 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) | ||
359 | { | ||
360 | driver_unregister(&drv->core); | ||
361 | } | ||
362 | |||
363 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); | ||