xref: /OK3568_Linux_fs/kernel/arch/powerpc/platforms/ps3/system-bus.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  PS3 system bus driver.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2006 Sony Computer Entertainment Inc.
6*4882a593Smuzhiyun  *  Copyright 2006 Sony Corp.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/export.h>
12*4882a593Smuzhiyun #include <linux/dma-map-ops.h>
13*4882a593Smuzhiyun #include <linux/err.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <asm/udbg.h>
17*4882a593Smuzhiyun #include <asm/lv1call.h>
18*4882a593Smuzhiyun #include <asm/firmware.h>
19*4882a593Smuzhiyun #include <asm/cell-regs.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "platform.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static struct device ps3_system_bus = {
24*4882a593Smuzhiyun 	.init_name = "ps3_system",
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* FIXME: need device usage counters! */
28*4882a593Smuzhiyun static struct {
29*4882a593Smuzhiyun 	struct mutex mutex;
30*4882a593Smuzhiyun 	int sb_11; /* usb 0 */
31*4882a593Smuzhiyun 	int sb_12; /* usb 0 */
32*4882a593Smuzhiyun 	int gpu;
33*4882a593Smuzhiyun } usage_hack;
34*4882a593Smuzhiyun 
ps3_is_device(struct ps3_system_bus_device * dev,u64 bus_id,u64 dev_id)35*4882a593Smuzhiyun static int ps3_is_device(struct ps3_system_bus_device *dev, u64 bus_id,
36*4882a593Smuzhiyun 			 u64 dev_id)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	return dev->bus_id == bus_id && dev->dev_id == dev_id;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun 
ps3_open_hv_device_sb(struct ps3_system_bus_device * dev)41*4882a593Smuzhiyun static int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	int result;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	BUG_ON(!dev->bus_id);
46*4882a593Smuzhiyun 	mutex_lock(&usage_hack.mutex);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	if (ps3_is_device(dev, 1, 1)) {
49*4882a593Smuzhiyun 		usage_hack.sb_11++;
50*4882a593Smuzhiyun 		if (usage_hack.sb_11 > 1) {
51*4882a593Smuzhiyun 			result = 0;
52*4882a593Smuzhiyun 			goto done;
53*4882a593Smuzhiyun 		}
54*4882a593Smuzhiyun 	}
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	if (ps3_is_device(dev, 1, 2)) {
57*4882a593Smuzhiyun 		usage_hack.sb_12++;
58*4882a593Smuzhiyun 		if (usage_hack.sb_12 > 1) {
59*4882a593Smuzhiyun 			result = 0;
60*4882a593Smuzhiyun 			goto done;
61*4882a593Smuzhiyun 		}
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	result = lv1_open_device(dev->bus_id, dev->dev_id, 0);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	if (result) {
67*4882a593Smuzhiyun 		pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__,
68*4882a593Smuzhiyun 			__LINE__, ps3_result(result));
69*4882a593Smuzhiyun 			result = -EPERM;
70*4882a593Smuzhiyun 	}
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun done:
73*4882a593Smuzhiyun 	mutex_unlock(&usage_hack.mutex);
74*4882a593Smuzhiyun 	return result;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
ps3_close_hv_device_sb(struct ps3_system_bus_device * dev)77*4882a593Smuzhiyun static int ps3_close_hv_device_sb(struct ps3_system_bus_device *dev)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	int result;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	BUG_ON(!dev->bus_id);
82*4882a593Smuzhiyun 	mutex_lock(&usage_hack.mutex);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (ps3_is_device(dev, 1, 1)) {
85*4882a593Smuzhiyun 		usage_hack.sb_11--;
86*4882a593Smuzhiyun 		if (usage_hack.sb_11) {
87*4882a593Smuzhiyun 			result = 0;
88*4882a593Smuzhiyun 			goto done;
89*4882a593Smuzhiyun 		}
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (ps3_is_device(dev, 1, 2)) {
93*4882a593Smuzhiyun 		usage_hack.sb_12--;
94*4882a593Smuzhiyun 		if (usage_hack.sb_12) {
95*4882a593Smuzhiyun 			result = 0;
96*4882a593Smuzhiyun 			goto done;
97*4882a593Smuzhiyun 		}
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	result = lv1_close_device(dev->bus_id, dev->dev_id);
101*4882a593Smuzhiyun 	BUG_ON(result);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun done:
104*4882a593Smuzhiyun 	mutex_unlock(&usage_hack.mutex);
105*4882a593Smuzhiyun 	return result;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
ps3_open_hv_device_gpu(struct ps3_system_bus_device * dev)108*4882a593Smuzhiyun static int ps3_open_hv_device_gpu(struct ps3_system_bus_device *dev)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	int result;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	mutex_lock(&usage_hack.mutex);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	usage_hack.gpu++;
115*4882a593Smuzhiyun 	if (usage_hack.gpu > 1) {
116*4882a593Smuzhiyun 		result = 0;
117*4882a593Smuzhiyun 		goto done;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	result = lv1_gpu_open(0);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	if (result) {
123*4882a593Smuzhiyun 		pr_debug("%s:%d: lv1_gpu_open failed: %s\n", __func__,
124*4882a593Smuzhiyun 			__LINE__, ps3_result(result));
125*4882a593Smuzhiyun 			result = -EPERM;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun done:
129*4882a593Smuzhiyun 	mutex_unlock(&usage_hack.mutex);
130*4882a593Smuzhiyun 	return result;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
ps3_close_hv_device_gpu(struct ps3_system_bus_device * dev)133*4882a593Smuzhiyun static int ps3_close_hv_device_gpu(struct ps3_system_bus_device *dev)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	int result;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	mutex_lock(&usage_hack.mutex);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	usage_hack.gpu--;
140*4882a593Smuzhiyun 	if (usage_hack.gpu) {
141*4882a593Smuzhiyun 		result = 0;
142*4882a593Smuzhiyun 		goto done;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	result = lv1_gpu_close();
146*4882a593Smuzhiyun 	BUG_ON(result);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun done:
149*4882a593Smuzhiyun 	mutex_unlock(&usage_hack.mutex);
150*4882a593Smuzhiyun 	return result;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
ps3_open_hv_device(struct ps3_system_bus_device * dev)153*4882a593Smuzhiyun int ps3_open_hv_device(struct ps3_system_bus_device *dev)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	BUG_ON(!dev);
156*4882a593Smuzhiyun 	pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	switch (dev->match_id) {
159*4882a593Smuzhiyun 	case PS3_MATCH_ID_EHCI:
160*4882a593Smuzhiyun 	case PS3_MATCH_ID_OHCI:
161*4882a593Smuzhiyun 	case PS3_MATCH_ID_GELIC:
162*4882a593Smuzhiyun 	case PS3_MATCH_ID_STOR_DISK:
163*4882a593Smuzhiyun 	case PS3_MATCH_ID_STOR_ROM:
164*4882a593Smuzhiyun 	case PS3_MATCH_ID_STOR_FLASH:
165*4882a593Smuzhiyun 		return ps3_open_hv_device_sb(dev);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	case PS3_MATCH_ID_SOUND:
168*4882a593Smuzhiyun 	case PS3_MATCH_ID_GPU:
169*4882a593Smuzhiyun 		return ps3_open_hv_device_gpu(dev);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	case PS3_MATCH_ID_AV_SETTINGS:
172*4882a593Smuzhiyun 	case PS3_MATCH_ID_SYSTEM_MANAGER:
173*4882a593Smuzhiyun 		pr_debug("%s:%d: unsupported match_id: %u\n", __func__,
174*4882a593Smuzhiyun 			__LINE__, dev->match_id);
175*4882a593Smuzhiyun 		pr_debug("%s:%d: bus_id: %llu\n", __func__, __LINE__,
176*4882a593Smuzhiyun 			dev->bus_id);
177*4882a593Smuzhiyun 		BUG();
178*4882a593Smuzhiyun 		return -EINVAL;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	default:
181*4882a593Smuzhiyun 		break;
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__,
185*4882a593Smuzhiyun 		dev->match_id);
186*4882a593Smuzhiyun 	BUG();
187*4882a593Smuzhiyun 	return -ENODEV;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_open_hv_device);
190*4882a593Smuzhiyun 
ps3_close_hv_device(struct ps3_system_bus_device * dev)191*4882a593Smuzhiyun int ps3_close_hv_device(struct ps3_system_bus_device *dev)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	BUG_ON(!dev);
194*4882a593Smuzhiyun 	pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	switch (dev->match_id) {
197*4882a593Smuzhiyun 	case PS3_MATCH_ID_EHCI:
198*4882a593Smuzhiyun 	case PS3_MATCH_ID_OHCI:
199*4882a593Smuzhiyun 	case PS3_MATCH_ID_GELIC:
200*4882a593Smuzhiyun 	case PS3_MATCH_ID_STOR_DISK:
201*4882a593Smuzhiyun 	case PS3_MATCH_ID_STOR_ROM:
202*4882a593Smuzhiyun 	case PS3_MATCH_ID_STOR_FLASH:
203*4882a593Smuzhiyun 		return ps3_close_hv_device_sb(dev);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	case PS3_MATCH_ID_SOUND:
206*4882a593Smuzhiyun 	case PS3_MATCH_ID_GPU:
207*4882a593Smuzhiyun 		return ps3_close_hv_device_gpu(dev);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	case PS3_MATCH_ID_AV_SETTINGS:
210*4882a593Smuzhiyun 	case PS3_MATCH_ID_SYSTEM_MANAGER:
211*4882a593Smuzhiyun 		pr_debug("%s:%d: unsupported match_id: %u\n", __func__,
212*4882a593Smuzhiyun 			__LINE__, dev->match_id);
213*4882a593Smuzhiyun 		pr_debug("%s:%d: bus_id: %llu\n", __func__, __LINE__,
214*4882a593Smuzhiyun 			dev->bus_id);
215*4882a593Smuzhiyun 		BUG();
216*4882a593Smuzhiyun 		return -EINVAL;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	default:
219*4882a593Smuzhiyun 		break;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__,
223*4882a593Smuzhiyun 		dev->match_id);
224*4882a593Smuzhiyun 	BUG();
225*4882a593Smuzhiyun 	return -ENODEV;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_close_hv_device);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
_dump_mmio_region(const struct ps3_mmio_region * r,const char * func,int line)230*4882a593Smuzhiyun static void _dump_mmio_region(const struct ps3_mmio_region* r,
231*4882a593Smuzhiyun 	const char* func, int line)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	pr_debug("%s:%d: dev       %llu:%llu\n", func, line, r->dev->bus_id,
234*4882a593Smuzhiyun 		r->dev->dev_id);
235*4882a593Smuzhiyun 	pr_debug("%s:%d: bus_addr  %lxh\n", func, line, r->bus_addr);
236*4882a593Smuzhiyun 	pr_debug("%s:%d: len       %lxh\n", func, line, r->len);
237*4882a593Smuzhiyun 	pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
ps3_sb_mmio_region_create(struct ps3_mmio_region * r)240*4882a593Smuzhiyun static int ps3_sb_mmio_region_create(struct ps3_mmio_region *r)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	int result;
243*4882a593Smuzhiyun 	u64 lpar_addr;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	result = lv1_map_device_mmio_region(r->dev->bus_id, r->dev->dev_id,
246*4882a593Smuzhiyun 		r->bus_addr, r->len, r->page_size, &lpar_addr);
247*4882a593Smuzhiyun 	r->lpar_addr = lpar_addr;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (result) {
250*4882a593Smuzhiyun 		pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
251*4882a593Smuzhiyun 			__func__, __LINE__, ps3_result(result));
252*4882a593Smuzhiyun 		r->lpar_addr = 0;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	dump_mmio_region(r);
256*4882a593Smuzhiyun 	return result;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
ps3_ioc0_mmio_region_create(struct ps3_mmio_region * r)259*4882a593Smuzhiyun static int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	/* device specific; do nothing currently */
262*4882a593Smuzhiyun 	return 0;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
ps3_mmio_region_create(struct ps3_mmio_region * r)265*4882a593Smuzhiyun int ps3_mmio_region_create(struct ps3_mmio_region *r)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	return r->mmio_ops->create(r);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_mmio_region_create);
270*4882a593Smuzhiyun 
ps3_sb_free_mmio_region(struct ps3_mmio_region * r)271*4882a593Smuzhiyun static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	int result;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	dump_mmio_region(r);
276*4882a593Smuzhiyun 	result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id,
277*4882a593Smuzhiyun 		r->lpar_addr);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	if (result)
280*4882a593Smuzhiyun 		pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
281*4882a593Smuzhiyun 			__func__, __LINE__, ps3_result(result));
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	r->lpar_addr = 0;
284*4882a593Smuzhiyun 	return result;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
ps3_ioc0_free_mmio_region(struct ps3_mmio_region * r)287*4882a593Smuzhiyun static int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	/* device specific; do nothing currently */
290*4882a593Smuzhiyun 	return 0;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 
ps3_free_mmio_region(struct ps3_mmio_region * r)294*4882a593Smuzhiyun int ps3_free_mmio_region(struct ps3_mmio_region *r)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	return r->mmio_ops->free(r);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_free_mmio_region);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun static const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = {
302*4882a593Smuzhiyun 	.create = ps3_sb_mmio_region_create,
303*4882a593Smuzhiyun 	.free = ps3_sb_free_mmio_region
304*4882a593Smuzhiyun };
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun static const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = {
307*4882a593Smuzhiyun 	.create = ps3_ioc0_mmio_region_create,
308*4882a593Smuzhiyun 	.free = ps3_ioc0_free_mmio_region
309*4882a593Smuzhiyun };
310*4882a593Smuzhiyun 
ps3_mmio_region_init(struct ps3_system_bus_device * dev,struct ps3_mmio_region * r,unsigned long bus_addr,unsigned long len,enum ps3_mmio_page_size page_size)311*4882a593Smuzhiyun int ps3_mmio_region_init(struct ps3_system_bus_device *dev,
312*4882a593Smuzhiyun 	struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len,
313*4882a593Smuzhiyun 	enum ps3_mmio_page_size page_size)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	r->dev = dev;
316*4882a593Smuzhiyun 	r->bus_addr = bus_addr;
317*4882a593Smuzhiyun 	r->len = len;
318*4882a593Smuzhiyun 	r->page_size = page_size;
319*4882a593Smuzhiyun 	switch (dev->dev_type) {
320*4882a593Smuzhiyun 	case PS3_DEVICE_TYPE_SB:
321*4882a593Smuzhiyun 		r->mmio_ops = &ps3_mmio_sb_region_ops;
322*4882a593Smuzhiyun 		break;
323*4882a593Smuzhiyun 	case PS3_DEVICE_TYPE_IOC0:
324*4882a593Smuzhiyun 		r->mmio_ops = &ps3_mmio_ioc0_region_ops;
325*4882a593Smuzhiyun 		break;
326*4882a593Smuzhiyun 	default:
327*4882a593Smuzhiyun 		BUG();
328*4882a593Smuzhiyun 		return -EINVAL;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 	return 0;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_mmio_region_init);
333*4882a593Smuzhiyun 
ps3_system_bus_match(struct device * _dev,struct device_driver * _drv)334*4882a593Smuzhiyun static int ps3_system_bus_match(struct device *_dev,
335*4882a593Smuzhiyun 	struct device_driver *_drv)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	int result;
338*4882a593Smuzhiyun 	struct ps3_system_bus_driver *drv = ps3_drv_to_system_bus_drv(_drv);
339*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if (!dev->match_sub_id)
342*4882a593Smuzhiyun 		result = dev->match_id == drv->match_id;
343*4882a593Smuzhiyun 	else
344*4882a593Smuzhiyun 		result = dev->match_sub_id == drv->match_sub_id &&
345*4882a593Smuzhiyun 			dev->match_id == drv->match_id;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (result)
348*4882a593Smuzhiyun 		pr_info("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): match\n",
349*4882a593Smuzhiyun 			__func__, __LINE__,
350*4882a593Smuzhiyun 			dev->match_id, dev->match_sub_id, dev_name(&dev->core),
351*4882a593Smuzhiyun 			drv->match_id, drv->match_sub_id, drv->core.name);
352*4882a593Smuzhiyun 	else
353*4882a593Smuzhiyun 		pr_debug("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): miss\n",
354*4882a593Smuzhiyun 			__func__, __LINE__,
355*4882a593Smuzhiyun 			dev->match_id, dev->match_sub_id, dev_name(&dev->core),
356*4882a593Smuzhiyun 			drv->match_id, drv->match_sub_id, drv->core.name);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	return result;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
ps3_system_bus_probe(struct device * _dev)361*4882a593Smuzhiyun static int ps3_system_bus_probe(struct device *_dev)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	int result = 0;
364*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
365*4882a593Smuzhiyun 	struct ps3_system_bus_driver *drv;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	BUG_ON(!dev);
368*4882a593Smuzhiyun 	dev_dbg(_dev, "%s:%d\n", __func__, __LINE__);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	drv = ps3_system_bus_dev_to_system_bus_drv(dev);
371*4882a593Smuzhiyun 	BUG_ON(!drv);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (drv->probe)
374*4882a593Smuzhiyun 		result = drv->probe(dev);
375*4882a593Smuzhiyun 	else
376*4882a593Smuzhiyun 		pr_debug("%s:%d: %s no probe method\n", __func__, __LINE__,
377*4882a593Smuzhiyun 			dev_name(&dev->core));
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core));
380*4882a593Smuzhiyun 	return result;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
ps3_system_bus_remove(struct device * _dev)383*4882a593Smuzhiyun static int ps3_system_bus_remove(struct device *_dev)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	int result = 0;
386*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
387*4882a593Smuzhiyun 	struct ps3_system_bus_driver *drv;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	BUG_ON(!dev);
390*4882a593Smuzhiyun 	dev_dbg(_dev, "%s:%d\n", __func__, __LINE__);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	drv = ps3_system_bus_dev_to_system_bus_drv(dev);
393*4882a593Smuzhiyun 	BUG_ON(!drv);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (drv->remove)
396*4882a593Smuzhiyun 		result = drv->remove(dev);
397*4882a593Smuzhiyun 	else
398*4882a593Smuzhiyun 		dev_dbg(&dev->core, "%s:%d %s: no remove method\n",
399*4882a593Smuzhiyun 			__func__, __LINE__, drv->core.name);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core));
402*4882a593Smuzhiyun 	return result;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
ps3_system_bus_shutdown(struct device * _dev)405*4882a593Smuzhiyun static void ps3_system_bus_shutdown(struct device *_dev)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
408*4882a593Smuzhiyun 	struct ps3_system_bus_driver *drv;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	BUG_ON(!dev);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
413*4882a593Smuzhiyun 		dev->match_id);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (!dev->core.driver) {
416*4882a593Smuzhiyun 		dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
417*4882a593Smuzhiyun 			__LINE__);
418*4882a593Smuzhiyun 		return;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	drv = ps3_system_bus_dev_to_system_bus_drv(dev);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	BUG_ON(!drv);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__,
426*4882a593Smuzhiyun 		dev_name(&dev->core), drv->core.name);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	if (drv->shutdown)
429*4882a593Smuzhiyun 		drv->shutdown(dev);
430*4882a593Smuzhiyun 	else if (drv->remove) {
431*4882a593Smuzhiyun 		dev_dbg(&dev->core, "%s:%d %s: no shutdown, calling remove\n",
432*4882a593Smuzhiyun 			__func__, __LINE__, drv->core.name);
433*4882a593Smuzhiyun 		drv->remove(dev);
434*4882a593Smuzhiyun 	} else {
435*4882a593Smuzhiyun 		dev_dbg(&dev->core, "%s:%d %s: no shutdown method\n",
436*4882a593Smuzhiyun 			__func__, __LINE__, drv->core.name);
437*4882a593Smuzhiyun 		BUG();
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
ps3_system_bus_uevent(struct device * _dev,struct kobj_uevent_env * env)443*4882a593Smuzhiyun static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	if (add_uevent_var(env, "MODALIAS=ps3:%d:%d", dev->match_id,
448*4882a593Smuzhiyun 			   dev->match_sub_id))
449*4882a593Smuzhiyun 		return -ENOMEM;
450*4882a593Smuzhiyun 	return 0;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
modalias_show(struct device * _dev,struct device_attribute * a,char * buf)453*4882a593Smuzhiyun static ssize_t modalias_show(struct device *_dev, struct device_attribute *a,
454*4882a593Smuzhiyun 	char *buf)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
457*4882a593Smuzhiyun 	int len = snprintf(buf, PAGE_SIZE, "ps3:%d:%d\n", dev->match_id,
458*4882a593Smuzhiyun 			   dev->match_sub_id);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun static DEVICE_ATTR_RO(modalias);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun static struct attribute *ps3_system_bus_dev_attrs[] = {
465*4882a593Smuzhiyun 	&dev_attr_modalias.attr,
466*4882a593Smuzhiyun 	NULL,
467*4882a593Smuzhiyun };
468*4882a593Smuzhiyun ATTRIBUTE_GROUPS(ps3_system_bus_dev);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun struct bus_type ps3_system_bus_type = {
471*4882a593Smuzhiyun 	.name = "ps3_system_bus",
472*4882a593Smuzhiyun 	.match = ps3_system_bus_match,
473*4882a593Smuzhiyun 	.uevent = ps3_system_bus_uevent,
474*4882a593Smuzhiyun 	.probe = ps3_system_bus_probe,
475*4882a593Smuzhiyun 	.remove = ps3_system_bus_remove,
476*4882a593Smuzhiyun 	.shutdown = ps3_system_bus_shutdown,
477*4882a593Smuzhiyun 	.dev_groups = ps3_system_bus_dev_groups,
478*4882a593Smuzhiyun };
479*4882a593Smuzhiyun 
ps3_system_bus_init(void)480*4882a593Smuzhiyun static int __init ps3_system_bus_init(void)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	int result;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
485*4882a593Smuzhiyun 		return -ENODEV;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	mutex_init(&usage_hack.mutex);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	result = device_register(&ps3_system_bus);
492*4882a593Smuzhiyun 	BUG_ON(result);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	result = bus_register(&ps3_system_bus_type);
495*4882a593Smuzhiyun 	BUG_ON(result);
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
498*4882a593Smuzhiyun 	return result;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun core_initcall(ps3_system_bus_init);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun /* Allocates a contiguous real buffer and creates mappings over it.
504*4882a593Smuzhiyun  * Returns the virtual address of the buffer and sets dma_handle
505*4882a593Smuzhiyun  * to the dma address (mapping) of the first page.
506*4882a593Smuzhiyun  */
ps3_alloc_coherent(struct device * _dev,size_t size,dma_addr_t * dma_handle,gfp_t flag,unsigned long attrs)507*4882a593Smuzhiyun static void * ps3_alloc_coherent(struct device *_dev, size_t size,
508*4882a593Smuzhiyun 				 dma_addr_t *dma_handle, gfp_t flag,
509*4882a593Smuzhiyun 				 unsigned long attrs)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	int result;
512*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
513*4882a593Smuzhiyun 	unsigned long virt_addr;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
516*4882a593Smuzhiyun 	flag |= __GFP_ZERO;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	virt_addr = __get_free_pages(flag, get_order(size));
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (!virt_addr) {
521*4882a593Smuzhiyun 		pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__);
522*4882a593Smuzhiyun 		goto clean_none;
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle,
526*4882a593Smuzhiyun 			     CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
527*4882a593Smuzhiyun 			     CBE_IOPTE_SO_RW | CBE_IOPTE_M);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (result) {
530*4882a593Smuzhiyun 		pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
531*4882a593Smuzhiyun 			__func__, __LINE__, result);
532*4882a593Smuzhiyun 		BUG_ON("check region type");
533*4882a593Smuzhiyun 		goto clean_alloc;
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	return (void*)virt_addr;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun clean_alloc:
539*4882a593Smuzhiyun 	free_pages(virt_addr, get_order(size));
540*4882a593Smuzhiyun clean_none:
541*4882a593Smuzhiyun 	dma_handle = NULL;
542*4882a593Smuzhiyun 	return NULL;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
ps3_free_coherent(struct device * _dev,size_t size,void * vaddr,dma_addr_t dma_handle,unsigned long attrs)545*4882a593Smuzhiyun static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
546*4882a593Smuzhiyun 			      dma_addr_t dma_handle, unsigned long attrs)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	ps3_dma_unmap(dev->d_region, dma_handle, size);
551*4882a593Smuzhiyun 	free_pages((unsigned long)vaddr, get_order(size));
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun /* Creates TCEs for a user provided buffer.  The user buffer must be
555*4882a593Smuzhiyun  * contiguous real kernel storage (not vmalloc).  The address passed here
556*4882a593Smuzhiyun  * comprises a page address and offset into that page. The dma_addr_t
557*4882a593Smuzhiyun  * returned will point to the same byte within the page as was passed in.
558*4882a593Smuzhiyun  */
559*4882a593Smuzhiyun 
ps3_sb_map_page(struct device * _dev,struct page * page,unsigned long offset,size_t size,enum dma_data_direction direction,unsigned long attrs)560*4882a593Smuzhiyun static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
561*4882a593Smuzhiyun 	unsigned long offset, size_t size, enum dma_data_direction direction,
562*4882a593Smuzhiyun 	unsigned long attrs)
563*4882a593Smuzhiyun {
564*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
565*4882a593Smuzhiyun 	int result;
566*4882a593Smuzhiyun 	dma_addr_t bus_addr;
567*4882a593Smuzhiyun 	void *ptr = page_address(page) + offset;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
570*4882a593Smuzhiyun 			     &bus_addr,
571*4882a593Smuzhiyun 			     CBE_IOPTE_PP_R | CBE_IOPTE_PP_W |
572*4882a593Smuzhiyun 			     CBE_IOPTE_SO_RW | CBE_IOPTE_M);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	if (result) {
575*4882a593Smuzhiyun 		pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
576*4882a593Smuzhiyun 			__func__, __LINE__, result);
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	return bus_addr;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
ps3_ioc0_map_page(struct device * _dev,struct page * page,unsigned long offset,size_t size,enum dma_data_direction direction,unsigned long attrs)582*4882a593Smuzhiyun static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
583*4882a593Smuzhiyun 				    unsigned long offset, size_t size,
584*4882a593Smuzhiyun 				    enum dma_data_direction direction,
585*4882a593Smuzhiyun 				    unsigned long attrs)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
588*4882a593Smuzhiyun 	int result;
589*4882a593Smuzhiyun 	dma_addr_t bus_addr;
590*4882a593Smuzhiyun 	u64 iopte_flag;
591*4882a593Smuzhiyun 	void *ptr = page_address(page) + offset;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	iopte_flag = CBE_IOPTE_M;
594*4882a593Smuzhiyun 	switch (direction) {
595*4882a593Smuzhiyun 	case DMA_BIDIRECTIONAL:
596*4882a593Smuzhiyun 		iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
597*4882a593Smuzhiyun 		break;
598*4882a593Smuzhiyun 	case DMA_TO_DEVICE:
599*4882a593Smuzhiyun 		iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R;
600*4882a593Smuzhiyun 		break;
601*4882a593Smuzhiyun 	case DMA_FROM_DEVICE:
602*4882a593Smuzhiyun 		iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
603*4882a593Smuzhiyun 		break;
604*4882a593Smuzhiyun 	default:
605*4882a593Smuzhiyun 		/* not happned */
606*4882a593Smuzhiyun 		BUG();
607*4882a593Smuzhiyun 	};
608*4882a593Smuzhiyun 	result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
609*4882a593Smuzhiyun 			     &bus_addr, iopte_flag);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	if (result) {
612*4882a593Smuzhiyun 		pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
613*4882a593Smuzhiyun 			__func__, __LINE__, result);
614*4882a593Smuzhiyun 	}
615*4882a593Smuzhiyun 	return bus_addr;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun 
ps3_unmap_page(struct device * _dev,dma_addr_t dma_addr,size_t size,enum dma_data_direction direction,unsigned long attrs)618*4882a593Smuzhiyun static void ps3_unmap_page(struct device *_dev, dma_addr_t dma_addr,
619*4882a593Smuzhiyun 	size_t size, enum dma_data_direction direction, unsigned long attrs)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
622*4882a593Smuzhiyun 	int result;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	result = ps3_dma_unmap(dev->d_region, dma_addr, size);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	if (result) {
627*4882a593Smuzhiyun 		pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n",
628*4882a593Smuzhiyun 			__func__, __LINE__, result);
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun 
ps3_sb_map_sg(struct device * _dev,struct scatterlist * sgl,int nents,enum dma_data_direction direction,unsigned long attrs)632*4882a593Smuzhiyun static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl,
633*4882a593Smuzhiyun 	int nents, enum dma_data_direction direction, unsigned long attrs)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun #if defined(CONFIG_PS3_DYNAMIC_DMA)
636*4882a593Smuzhiyun 	BUG_ON("do");
637*4882a593Smuzhiyun 	return -EPERM;
638*4882a593Smuzhiyun #else
639*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
640*4882a593Smuzhiyun 	struct scatterlist *sg;
641*4882a593Smuzhiyun 	int i;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	for_each_sg(sgl, sg, nents, i) {
644*4882a593Smuzhiyun 		int result = ps3_dma_map(dev->d_region, sg_phys(sg),
645*4882a593Smuzhiyun 					sg->length, &sg->dma_address, 0);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 		if (result) {
648*4882a593Smuzhiyun 			pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
649*4882a593Smuzhiyun 				__func__, __LINE__, result);
650*4882a593Smuzhiyun 			return -EINVAL;
651*4882a593Smuzhiyun 		}
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 		sg->dma_length = sg->length;
654*4882a593Smuzhiyun 	}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	return nents;
657*4882a593Smuzhiyun #endif
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
ps3_ioc0_map_sg(struct device * _dev,struct scatterlist * sg,int nents,enum dma_data_direction direction,unsigned long attrs)660*4882a593Smuzhiyun static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg,
661*4882a593Smuzhiyun 			   int nents,
662*4882a593Smuzhiyun 			   enum dma_data_direction direction,
663*4882a593Smuzhiyun 			   unsigned long attrs)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	BUG();
666*4882a593Smuzhiyun 	return 0;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
ps3_sb_unmap_sg(struct device * _dev,struct scatterlist * sg,int nents,enum dma_data_direction direction,unsigned long attrs)669*4882a593Smuzhiyun static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg,
670*4882a593Smuzhiyun 	int nents, enum dma_data_direction direction, unsigned long attrs)
671*4882a593Smuzhiyun {
672*4882a593Smuzhiyun #if defined(CONFIG_PS3_DYNAMIC_DMA)
673*4882a593Smuzhiyun 	BUG_ON("do");
674*4882a593Smuzhiyun #endif
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
ps3_ioc0_unmap_sg(struct device * _dev,struct scatterlist * sg,int nents,enum dma_data_direction direction,unsigned long attrs)677*4882a593Smuzhiyun static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg,
678*4882a593Smuzhiyun 			    int nents, enum dma_data_direction direction,
679*4882a593Smuzhiyun 			    unsigned long attrs)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun 	BUG();
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun 
ps3_dma_supported(struct device * _dev,u64 mask)684*4882a593Smuzhiyun static int ps3_dma_supported(struct device *_dev, u64 mask)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun 	return mask >= DMA_BIT_MASK(32);
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun static const struct dma_map_ops ps3_sb_dma_ops = {
690*4882a593Smuzhiyun 	.alloc = ps3_alloc_coherent,
691*4882a593Smuzhiyun 	.free = ps3_free_coherent,
692*4882a593Smuzhiyun 	.map_sg = ps3_sb_map_sg,
693*4882a593Smuzhiyun 	.unmap_sg = ps3_sb_unmap_sg,
694*4882a593Smuzhiyun 	.dma_supported = ps3_dma_supported,
695*4882a593Smuzhiyun 	.map_page = ps3_sb_map_page,
696*4882a593Smuzhiyun 	.unmap_page = ps3_unmap_page,
697*4882a593Smuzhiyun 	.mmap = dma_common_mmap,
698*4882a593Smuzhiyun 	.get_sgtable = dma_common_get_sgtable,
699*4882a593Smuzhiyun 	.alloc_pages = dma_common_alloc_pages,
700*4882a593Smuzhiyun 	.free_pages = dma_common_free_pages,
701*4882a593Smuzhiyun };
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun static const struct dma_map_ops ps3_ioc0_dma_ops = {
704*4882a593Smuzhiyun 	.alloc = ps3_alloc_coherent,
705*4882a593Smuzhiyun 	.free = ps3_free_coherent,
706*4882a593Smuzhiyun 	.map_sg = ps3_ioc0_map_sg,
707*4882a593Smuzhiyun 	.unmap_sg = ps3_ioc0_unmap_sg,
708*4882a593Smuzhiyun 	.dma_supported = ps3_dma_supported,
709*4882a593Smuzhiyun 	.map_page = ps3_ioc0_map_page,
710*4882a593Smuzhiyun 	.unmap_page = ps3_unmap_page,
711*4882a593Smuzhiyun 	.mmap = dma_common_mmap,
712*4882a593Smuzhiyun 	.get_sgtable = dma_common_get_sgtable,
713*4882a593Smuzhiyun 	.alloc_pages = dma_common_alloc_pages,
714*4882a593Smuzhiyun 	.free_pages = dma_common_free_pages,
715*4882a593Smuzhiyun };
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun /**
718*4882a593Smuzhiyun  * ps3_system_bus_release_device - remove a device from the system bus
719*4882a593Smuzhiyun  */
720*4882a593Smuzhiyun 
ps3_system_bus_release_device(struct device * _dev)721*4882a593Smuzhiyun static void ps3_system_bus_release_device(struct device *_dev)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
724*4882a593Smuzhiyun 	kfree(dev);
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun /**
728*4882a593Smuzhiyun  * ps3_system_bus_device_register - add a device to the system bus
729*4882a593Smuzhiyun  *
730*4882a593Smuzhiyun  * ps3_system_bus_device_register() expects the dev object to be allocated
731*4882a593Smuzhiyun  * dynamically by the caller.  The system bus takes ownership of the dev
732*4882a593Smuzhiyun  * object and frees the object in ps3_system_bus_release_device().
733*4882a593Smuzhiyun  */
734*4882a593Smuzhiyun 
ps3_system_bus_device_register(struct ps3_system_bus_device * dev)735*4882a593Smuzhiyun int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun 	int result;
738*4882a593Smuzhiyun 	static unsigned int dev_ioc0_count;
739*4882a593Smuzhiyun 	static unsigned int dev_sb_count;
740*4882a593Smuzhiyun 	static unsigned int dev_vuart_count;
741*4882a593Smuzhiyun 	static unsigned int dev_lpm_count;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (!dev->core.parent)
744*4882a593Smuzhiyun 		dev->core.parent = &ps3_system_bus;
745*4882a593Smuzhiyun 	dev->core.bus = &ps3_system_bus_type;
746*4882a593Smuzhiyun 	dev->core.release = ps3_system_bus_release_device;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	switch (dev->dev_type) {
749*4882a593Smuzhiyun 	case PS3_DEVICE_TYPE_IOC0:
750*4882a593Smuzhiyun 		dev->core.dma_ops = &ps3_ioc0_dma_ops;
751*4882a593Smuzhiyun 		dev_set_name(&dev->core, "ioc0_%02x", ++dev_ioc0_count);
752*4882a593Smuzhiyun 		break;
753*4882a593Smuzhiyun 	case PS3_DEVICE_TYPE_SB:
754*4882a593Smuzhiyun 		dev->core.dma_ops = &ps3_sb_dma_ops;
755*4882a593Smuzhiyun 		dev_set_name(&dev->core, "sb_%02x", ++dev_sb_count);
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 		break;
758*4882a593Smuzhiyun 	case PS3_DEVICE_TYPE_VUART:
759*4882a593Smuzhiyun 		dev_set_name(&dev->core, "vuart_%02x", ++dev_vuart_count);
760*4882a593Smuzhiyun 		break;
761*4882a593Smuzhiyun 	case PS3_DEVICE_TYPE_LPM:
762*4882a593Smuzhiyun 		dev_set_name(&dev->core, "lpm_%02x", ++dev_lpm_count);
763*4882a593Smuzhiyun 		break;
764*4882a593Smuzhiyun 	default:
765*4882a593Smuzhiyun 		BUG();
766*4882a593Smuzhiyun 	};
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	dev->core.of_node = NULL;
769*4882a593Smuzhiyun 	set_dev_node(&dev->core, 0);
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	pr_debug("%s:%d add %s\n", __func__, __LINE__, dev_name(&dev->core));
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	result = device_register(&dev->core);
774*4882a593Smuzhiyun 	return result;
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
778*4882a593Smuzhiyun 
ps3_system_bus_driver_register(struct ps3_system_bus_driver * drv)779*4882a593Smuzhiyun int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun 	int result;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
786*4882a593Smuzhiyun 		return -ENODEV;
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	drv->core.bus = &ps3_system_bus_type;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	result = driver_register(&drv->core);
791*4882a593Smuzhiyun 	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
792*4882a593Smuzhiyun 	return result;
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
796*4882a593Smuzhiyun 
ps3_system_bus_driver_unregister(struct ps3_system_bus_driver * drv)797*4882a593Smuzhiyun void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
798*4882a593Smuzhiyun {
799*4882a593Smuzhiyun 	pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
800*4882a593Smuzhiyun 	driver_unregister(&drv->core);
801*4882a593Smuzhiyun 	pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
805