xref: /OK3568_Linux_fs/kernel/arch/powerpc/platforms/ps3/device-init.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  PS3 device registration routines.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2007 Sony Computer Entertainment Inc.
6*4882a593Smuzhiyun  *  Copyright 2007 Sony Corp.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/freezer.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/kthread.h>
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/reboot.h>
16*4882a593Smuzhiyun #include <linux/rcuwait.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <asm/firmware.h>
19*4882a593Smuzhiyun #include <asm/lv1call.h>
20*4882a593Smuzhiyun #include <asm/ps3stor.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "platform.h"
23*4882a593Smuzhiyun 
ps3_register_lpm_devices(void)24*4882a593Smuzhiyun static int __init ps3_register_lpm_devices(void)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	int result;
27*4882a593Smuzhiyun 	u64 tmp1;
28*4882a593Smuzhiyun 	u64 tmp2;
29*4882a593Smuzhiyun 	struct ps3_system_bus_device *dev;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
34*4882a593Smuzhiyun 	if (!dev)
35*4882a593Smuzhiyun 		return -ENOMEM;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	dev->match_id = PS3_MATCH_ID_LPM;
38*4882a593Smuzhiyun 	dev->dev_type = PS3_DEVICE_TYPE_LPM;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	/* The current lpm driver only supports a single BE processor. */
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	result = ps3_repository_read_be_node_id(0, &dev->lpm.node_id);
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	if (result) {
45*4882a593Smuzhiyun 		pr_debug("%s:%d: ps3_repository_read_be_node_id failed \n",
46*4882a593Smuzhiyun 			__func__, __LINE__);
47*4882a593Smuzhiyun 		goto fail_read_repo;
48*4882a593Smuzhiyun 	}
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	result = ps3_repository_read_lpm_privileges(dev->lpm.node_id, &tmp1,
51*4882a593Smuzhiyun 		&dev->lpm.rights);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (result) {
54*4882a593Smuzhiyun 		pr_debug("%s:%d: ps3_repository_read_lpm_privileges failed\n",
55*4882a593Smuzhiyun 			__func__, __LINE__);
56*4882a593Smuzhiyun 		goto fail_read_repo;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	lv1_get_logical_partition_id(&tmp2);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	if (tmp1 != tmp2) {
62*4882a593Smuzhiyun 		pr_debug("%s:%d: wrong lpar\n",
63*4882a593Smuzhiyun 			__func__, __LINE__);
64*4882a593Smuzhiyun 		result = -ENODEV;
65*4882a593Smuzhiyun 		goto fail_rights;
66*4882a593Smuzhiyun 	}
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	if (!(dev->lpm.rights & PS3_LPM_RIGHTS_USE_LPM)) {
69*4882a593Smuzhiyun 		pr_debug("%s:%d: don't have rights to use lpm\n",
70*4882a593Smuzhiyun 			__func__, __LINE__);
71*4882a593Smuzhiyun 		result = -EPERM;
72*4882a593Smuzhiyun 		goto fail_rights;
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	pr_debug("%s:%d: pu_id %llu, rights %llu(%llxh)\n",
76*4882a593Smuzhiyun 		__func__, __LINE__, dev->lpm.pu_id, dev->lpm.rights,
77*4882a593Smuzhiyun 		dev->lpm.rights);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	result = ps3_repository_read_pu_id(0, &dev->lpm.pu_id);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if (result) {
82*4882a593Smuzhiyun 		pr_debug("%s:%d: ps3_repository_read_pu_id failed \n",
83*4882a593Smuzhiyun 			__func__, __LINE__);
84*4882a593Smuzhiyun 		goto fail_read_repo;
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(dev);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	if (result) {
90*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
91*4882a593Smuzhiyun 			__func__, __LINE__);
92*4882a593Smuzhiyun 		goto fail_register;
93*4882a593Smuzhiyun 	}
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
96*4882a593Smuzhiyun 	return 0;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun fail_register:
100*4882a593Smuzhiyun fail_rights:
101*4882a593Smuzhiyun fail_read_repo:
102*4882a593Smuzhiyun 	kfree(dev);
103*4882a593Smuzhiyun 	pr_debug(" <- %s:%d: failed\n", __func__, __LINE__);
104*4882a593Smuzhiyun 	return result;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun /**
108*4882a593Smuzhiyun  * ps3_setup_gelic_device - Setup and register a gelic device instance.
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * Allocates memory for a struct ps3_system_bus_device instance, initialises the
111*4882a593Smuzhiyun  * structure members, and registers the device instance with the system bus.
112*4882a593Smuzhiyun  */
113*4882a593Smuzhiyun 
ps3_setup_gelic_device(const struct ps3_repository_device * repo)114*4882a593Smuzhiyun static int __init ps3_setup_gelic_device(
115*4882a593Smuzhiyun 	const struct ps3_repository_device *repo)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	int result;
118*4882a593Smuzhiyun 	struct layout {
119*4882a593Smuzhiyun 		struct ps3_system_bus_device dev;
120*4882a593Smuzhiyun 		struct ps3_dma_region d_region;
121*4882a593Smuzhiyun 	} *p;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB);
126*4882a593Smuzhiyun 	BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_GELIC);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	p = kzalloc(sizeof(struct layout), GFP_KERNEL);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (!p) {
131*4882a593Smuzhiyun 		result = -ENOMEM;
132*4882a593Smuzhiyun 		goto fail_malloc;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	p->dev.match_id = PS3_MATCH_ID_GELIC;
136*4882a593Smuzhiyun 	p->dev.dev_type = PS3_DEVICE_TYPE_SB;
137*4882a593Smuzhiyun 	p->dev.bus_id = repo->bus_id;
138*4882a593Smuzhiyun 	p->dev.dev_id = repo->dev_id;
139*4882a593Smuzhiyun 	p->dev.d_region = &p->d_region;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	result = ps3_repository_find_interrupt(repo,
142*4882a593Smuzhiyun 		PS3_INTERRUPT_TYPE_EVENT_PORT, &p->dev.interrupt_id);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (result) {
145*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
146*4882a593Smuzhiyun 			__func__, __LINE__);
147*4882a593Smuzhiyun 		goto fail_find_interrupt;
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	BUG_ON(p->dev.interrupt_id != 0);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K,
153*4882a593Smuzhiyun 		PS3_DMA_OTHER, NULL, 0);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	if (result) {
156*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_dma_region_init failed\n",
157*4882a593Smuzhiyun 			__func__, __LINE__);
158*4882a593Smuzhiyun 		goto fail_dma_init;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(&p->dev);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (result) {
164*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
165*4882a593Smuzhiyun 			__func__, __LINE__);
166*4882a593Smuzhiyun 		goto fail_device_register;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
170*4882a593Smuzhiyun 	return result;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun fail_device_register:
173*4882a593Smuzhiyun fail_dma_init:
174*4882a593Smuzhiyun fail_find_interrupt:
175*4882a593Smuzhiyun 	kfree(p);
176*4882a593Smuzhiyun fail_malloc:
177*4882a593Smuzhiyun 	pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__);
178*4882a593Smuzhiyun 	return result;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
ps3_setup_uhc_device(const struct ps3_repository_device * repo,enum ps3_match_id match_id,enum ps3_interrupt_type interrupt_type,enum ps3_reg_type reg_type)181*4882a593Smuzhiyun static int __ref ps3_setup_uhc_device(
182*4882a593Smuzhiyun 	const struct ps3_repository_device *repo, enum ps3_match_id match_id,
183*4882a593Smuzhiyun 	enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	int result;
186*4882a593Smuzhiyun 	struct layout {
187*4882a593Smuzhiyun 		struct ps3_system_bus_device dev;
188*4882a593Smuzhiyun 		struct ps3_dma_region d_region;
189*4882a593Smuzhiyun 		struct ps3_mmio_region m_region;
190*4882a593Smuzhiyun 	} *p;
191*4882a593Smuzhiyun 	u64 bus_addr;
192*4882a593Smuzhiyun 	u64 len;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB);
197*4882a593Smuzhiyun 	BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_USB);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	p = kzalloc(sizeof(struct layout), GFP_KERNEL);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (!p) {
202*4882a593Smuzhiyun 		result = -ENOMEM;
203*4882a593Smuzhiyun 		goto fail_malloc;
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	p->dev.match_id = match_id;
207*4882a593Smuzhiyun 	p->dev.dev_type = PS3_DEVICE_TYPE_SB;
208*4882a593Smuzhiyun 	p->dev.bus_id = repo->bus_id;
209*4882a593Smuzhiyun 	p->dev.dev_id = repo->dev_id;
210*4882a593Smuzhiyun 	p->dev.d_region = &p->d_region;
211*4882a593Smuzhiyun 	p->dev.m_region = &p->m_region;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	result = ps3_repository_find_interrupt(repo,
214*4882a593Smuzhiyun 		interrupt_type, &p->dev.interrupt_id);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (result) {
217*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
218*4882a593Smuzhiyun 			__func__, __LINE__);
219*4882a593Smuzhiyun 		goto fail_find_interrupt;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	result = ps3_repository_find_reg(repo, reg_type,
223*4882a593Smuzhiyun 		&bus_addr, &len);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	if (result) {
226*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_repository_find_reg failed\n",
227*4882a593Smuzhiyun 			__func__, __LINE__);
228*4882a593Smuzhiyun 		goto fail_find_reg;
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K,
232*4882a593Smuzhiyun 		PS3_DMA_INTERNAL, NULL, 0);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (result) {
235*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_dma_region_init failed\n",
236*4882a593Smuzhiyun 			__func__, __LINE__);
237*4882a593Smuzhiyun 		goto fail_dma_init;
238*4882a593Smuzhiyun 	}
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	result = ps3_mmio_region_init(&p->dev, p->dev.m_region, bus_addr, len,
241*4882a593Smuzhiyun 		PS3_MMIO_4K);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (result) {
244*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_mmio_region_init failed\n",
245*4882a593Smuzhiyun 			__func__, __LINE__);
246*4882a593Smuzhiyun 		goto fail_mmio_init;
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(&p->dev);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	if (result) {
252*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
253*4882a593Smuzhiyun 			__func__, __LINE__);
254*4882a593Smuzhiyun 		goto fail_device_register;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
258*4882a593Smuzhiyun 	return result;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun fail_device_register:
261*4882a593Smuzhiyun fail_mmio_init:
262*4882a593Smuzhiyun fail_dma_init:
263*4882a593Smuzhiyun fail_find_reg:
264*4882a593Smuzhiyun fail_find_interrupt:
265*4882a593Smuzhiyun 	kfree(p);
266*4882a593Smuzhiyun fail_malloc:
267*4882a593Smuzhiyun 	pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__);
268*4882a593Smuzhiyun 	return result;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
ps3_setup_ehci_device(const struct ps3_repository_device * repo)271*4882a593Smuzhiyun static int __init ps3_setup_ehci_device(
272*4882a593Smuzhiyun 	const struct ps3_repository_device *repo)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	return ps3_setup_uhc_device(repo, PS3_MATCH_ID_EHCI,
275*4882a593Smuzhiyun 		PS3_INTERRUPT_TYPE_SB_EHCI, PS3_REG_TYPE_SB_EHCI);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
ps3_setup_ohci_device(const struct ps3_repository_device * repo)278*4882a593Smuzhiyun static int __init ps3_setup_ohci_device(
279*4882a593Smuzhiyun 	const struct ps3_repository_device *repo)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	return ps3_setup_uhc_device(repo, PS3_MATCH_ID_OHCI,
282*4882a593Smuzhiyun 		PS3_INTERRUPT_TYPE_SB_OHCI, PS3_REG_TYPE_SB_OHCI);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
ps3_setup_vuart_device(enum ps3_match_id match_id,unsigned int port_number)285*4882a593Smuzhiyun static int __init ps3_setup_vuart_device(enum ps3_match_id match_id,
286*4882a593Smuzhiyun 	unsigned int port_number)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	int result;
289*4882a593Smuzhiyun 	struct layout {
290*4882a593Smuzhiyun 		struct ps3_system_bus_device dev;
291*4882a593Smuzhiyun 	} *p;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	pr_debug(" -> %s:%d: match_id %u, port %u\n", __func__, __LINE__,
294*4882a593Smuzhiyun 		match_id, port_number);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	p = kzalloc(sizeof(struct layout), GFP_KERNEL);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (!p)
299*4882a593Smuzhiyun 		return -ENOMEM;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	p->dev.match_id = match_id;
302*4882a593Smuzhiyun 	p->dev.dev_type = PS3_DEVICE_TYPE_VUART;
303*4882a593Smuzhiyun 	p->dev.port_number = port_number;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(&p->dev);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (result) {
308*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
309*4882a593Smuzhiyun 			__func__, __LINE__);
310*4882a593Smuzhiyun 		goto fail_device_register;
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
313*4882a593Smuzhiyun 	return 0;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun fail_device_register:
316*4882a593Smuzhiyun 	kfree(p);
317*4882a593Smuzhiyun 	pr_debug(" <- %s:%d fail\n", __func__, __LINE__);
318*4882a593Smuzhiyun 	return result;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
ps3_setup_storage_dev(const struct ps3_repository_device * repo,enum ps3_match_id match_id)321*4882a593Smuzhiyun static int ps3_setup_storage_dev(const struct ps3_repository_device *repo,
322*4882a593Smuzhiyun 				 enum ps3_match_id match_id)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	int result;
325*4882a593Smuzhiyun 	struct ps3_storage_device *p;
326*4882a593Smuzhiyun 	u64 port, blk_size, num_blocks;
327*4882a593Smuzhiyun 	unsigned int num_regions, i;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	pr_debug(" -> %s:%u: match_id %u\n", __func__, __LINE__, match_id);
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	result = ps3_repository_read_stor_dev_info(repo->bus_index,
332*4882a593Smuzhiyun 						   repo->dev_index, &port,
333*4882a593Smuzhiyun 						   &blk_size, &num_blocks,
334*4882a593Smuzhiyun 						   &num_regions);
335*4882a593Smuzhiyun 	if (result) {
336*4882a593Smuzhiyun 		printk(KERN_ERR "%s:%u: _read_stor_dev_info failed %d\n",
337*4882a593Smuzhiyun 		       __func__, __LINE__, result);
338*4882a593Smuzhiyun 		return -ENODEV;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	pr_debug("%s:%u: (%u:%u:%u): port %llu blk_size %llu num_blocks %llu "
342*4882a593Smuzhiyun 		 "num_regions %u\n", __func__, __LINE__, repo->bus_index,
343*4882a593Smuzhiyun 		 repo->dev_index, repo->dev_type, port, blk_size, num_blocks,
344*4882a593Smuzhiyun 		 num_regions);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	p = kzalloc(struct_size(p, regions, num_regions), GFP_KERNEL);
347*4882a593Smuzhiyun 	if (!p) {
348*4882a593Smuzhiyun 		result = -ENOMEM;
349*4882a593Smuzhiyun 		goto fail_malloc;
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	p->sbd.match_id = match_id;
353*4882a593Smuzhiyun 	p->sbd.dev_type = PS3_DEVICE_TYPE_SB;
354*4882a593Smuzhiyun 	p->sbd.bus_id = repo->bus_id;
355*4882a593Smuzhiyun 	p->sbd.dev_id = repo->dev_id;
356*4882a593Smuzhiyun 	p->sbd.d_region = &p->dma_region;
357*4882a593Smuzhiyun 	p->blk_size = blk_size;
358*4882a593Smuzhiyun 	p->num_regions = num_regions;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	result = ps3_repository_find_interrupt(repo,
361*4882a593Smuzhiyun 					       PS3_INTERRUPT_TYPE_EVENT_PORT,
362*4882a593Smuzhiyun 					       &p->sbd.interrupt_id);
363*4882a593Smuzhiyun 	if (result) {
364*4882a593Smuzhiyun 		printk(KERN_ERR "%s:%u: find_interrupt failed %d\n", __func__,
365*4882a593Smuzhiyun 		       __LINE__, result);
366*4882a593Smuzhiyun 		result = -ENODEV;
367*4882a593Smuzhiyun 		goto fail_find_interrupt;
368*4882a593Smuzhiyun 	}
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	for (i = 0; i < num_regions; i++) {
371*4882a593Smuzhiyun 		unsigned int id;
372*4882a593Smuzhiyun 		u64 start, size;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		result = ps3_repository_read_stor_dev_region(repo->bus_index,
375*4882a593Smuzhiyun 							     repo->dev_index,
376*4882a593Smuzhiyun 							     i, &id, &start,
377*4882a593Smuzhiyun 							     &size);
378*4882a593Smuzhiyun 		if (result) {
379*4882a593Smuzhiyun 			printk(KERN_ERR
380*4882a593Smuzhiyun 			       "%s:%u: read_stor_dev_region failed %d\n",
381*4882a593Smuzhiyun 			       __func__, __LINE__, result);
382*4882a593Smuzhiyun 			result = -ENODEV;
383*4882a593Smuzhiyun 			goto fail_read_region;
384*4882a593Smuzhiyun 		}
385*4882a593Smuzhiyun 		pr_debug("%s:%u: region %u: id %u start %llu size %llu\n",
386*4882a593Smuzhiyun 			 __func__, __LINE__, i, id, start, size);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 		p->regions[i].id = id;
389*4882a593Smuzhiyun 		p->regions[i].start = start;
390*4882a593Smuzhiyun 		p->regions[i].size = size;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(&p->sbd);
394*4882a593Smuzhiyun 	if (result) {
395*4882a593Smuzhiyun 		pr_debug("%s:%u ps3_system_bus_device_register failed\n",
396*4882a593Smuzhiyun 			 __func__, __LINE__);
397*4882a593Smuzhiyun 		goto fail_device_register;
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	pr_debug(" <- %s:%u\n", __func__, __LINE__);
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun fail_device_register:
404*4882a593Smuzhiyun fail_read_region:
405*4882a593Smuzhiyun fail_find_interrupt:
406*4882a593Smuzhiyun 	kfree(p);
407*4882a593Smuzhiyun fail_malloc:
408*4882a593Smuzhiyun 	pr_debug(" <- %s:%u: fail.\n", __func__, __LINE__);
409*4882a593Smuzhiyun 	return result;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
ps3_register_vuart_devices(void)412*4882a593Smuzhiyun static int __init ps3_register_vuart_devices(void)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	int result;
415*4882a593Smuzhiyun 	unsigned int port_number;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	result = ps3_repository_read_vuart_av_port(&port_number);
420*4882a593Smuzhiyun 	if (result)
421*4882a593Smuzhiyun 		port_number = 0; /* av default */
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	result = ps3_setup_vuart_device(PS3_MATCH_ID_AV_SETTINGS, port_number);
424*4882a593Smuzhiyun 	WARN_ON(result);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	result = ps3_repository_read_vuart_sysmgr_port(&port_number);
427*4882a593Smuzhiyun 	if (result)
428*4882a593Smuzhiyun 		port_number = 2; /* sysmgr default */
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	result = ps3_setup_vuart_device(PS3_MATCH_ID_SYSTEM_MANAGER,
431*4882a593Smuzhiyun 		port_number);
432*4882a593Smuzhiyun 	WARN_ON(result);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
435*4882a593Smuzhiyun 	return result;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
ps3_register_sound_devices(void)438*4882a593Smuzhiyun static int __init ps3_register_sound_devices(void)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun 	int result;
441*4882a593Smuzhiyun 	struct layout {
442*4882a593Smuzhiyun 		struct ps3_system_bus_device dev;
443*4882a593Smuzhiyun 		struct ps3_dma_region d_region;
444*4882a593Smuzhiyun 		struct ps3_mmio_region m_region;
445*4882a593Smuzhiyun 	} *p;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	p = kzalloc(sizeof(*p), GFP_KERNEL);
450*4882a593Smuzhiyun 	if (!p)
451*4882a593Smuzhiyun 		return -ENOMEM;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	p->dev.match_id = PS3_MATCH_ID_SOUND;
454*4882a593Smuzhiyun 	p->dev.dev_type = PS3_DEVICE_TYPE_IOC0;
455*4882a593Smuzhiyun 	p->dev.d_region = &p->d_region;
456*4882a593Smuzhiyun 	p->dev.m_region = &p->m_region;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(&p->dev);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	if (result) {
461*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
462*4882a593Smuzhiyun 			__func__, __LINE__);
463*4882a593Smuzhiyun 		goto fail_device_register;
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
466*4882a593Smuzhiyun 	return 0;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun fail_device_register:
469*4882a593Smuzhiyun 	kfree(p);
470*4882a593Smuzhiyun 	pr_debug(" <- %s:%d failed\n", __func__, __LINE__);
471*4882a593Smuzhiyun 	return result;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
ps3_register_graphics_devices(void)474*4882a593Smuzhiyun static int __init ps3_register_graphics_devices(void)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	int result;
477*4882a593Smuzhiyun 	struct layout {
478*4882a593Smuzhiyun 		struct ps3_system_bus_device dev;
479*4882a593Smuzhiyun 	} *p;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	p = kzalloc(sizeof(struct layout), GFP_KERNEL);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	if (!p)
486*4882a593Smuzhiyun 		return -ENOMEM;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	p->dev.match_id = PS3_MATCH_ID_GPU;
489*4882a593Smuzhiyun 	p->dev.match_sub_id = PS3_MATCH_SUB_ID_GPU_FB;
490*4882a593Smuzhiyun 	p->dev.dev_type = PS3_DEVICE_TYPE_IOC0;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(&p->dev);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (result) {
495*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
496*4882a593Smuzhiyun 			__func__, __LINE__);
497*4882a593Smuzhiyun 		goto fail_device_register;
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
501*4882a593Smuzhiyun 	return 0;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun fail_device_register:
504*4882a593Smuzhiyun 	kfree(p);
505*4882a593Smuzhiyun 	pr_debug(" <- %s:%d failed\n", __func__, __LINE__);
506*4882a593Smuzhiyun 	return result;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
ps3_register_ramdisk_device(void)509*4882a593Smuzhiyun static int __init ps3_register_ramdisk_device(void)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	int result;
512*4882a593Smuzhiyun 	struct layout {
513*4882a593Smuzhiyun 		struct ps3_system_bus_device dev;
514*4882a593Smuzhiyun 	} *p;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	p = kzalloc(sizeof(struct layout), GFP_KERNEL);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (!p)
521*4882a593Smuzhiyun 		return -ENOMEM;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	p->dev.match_id = PS3_MATCH_ID_GPU;
524*4882a593Smuzhiyun 	p->dev.match_sub_id = PS3_MATCH_SUB_ID_GPU_RAMDISK;
525*4882a593Smuzhiyun 	p->dev.dev_type = PS3_DEVICE_TYPE_IOC0;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	result = ps3_system_bus_device_register(&p->dev);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (result) {
530*4882a593Smuzhiyun 		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
531*4882a593Smuzhiyun 			__func__, __LINE__);
532*4882a593Smuzhiyun 		goto fail_device_register;
533*4882a593Smuzhiyun 	}
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
536*4882a593Smuzhiyun 	return 0;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun fail_device_register:
539*4882a593Smuzhiyun 	kfree(p);
540*4882a593Smuzhiyun 	pr_debug(" <- %s:%d failed\n", __func__, __LINE__);
541*4882a593Smuzhiyun 	return result;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun /**
545*4882a593Smuzhiyun  * ps3_setup_dynamic_device - Setup a dynamic device from the repository
546*4882a593Smuzhiyun  */
547*4882a593Smuzhiyun 
ps3_setup_dynamic_device(const struct ps3_repository_device * repo)548*4882a593Smuzhiyun static int ps3_setup_dynamic_device(const struct ps3_repository_device *repo)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun 	int result;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	switch (repo->dev_type) {
553*4882a593Smuzhiyun 	case PS3_DEV_TYPE_STOR_DISK:
554*4882a593Smuzhiyun 		result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 		/* Some devices are not accessible from the Other OS lpar. */
557*4882a593Smuzhiyun 		if (result == -ENODEV) {
558*4882a593Smuzhiyun 			result = 0;
559*4882a593Smuzhiyun 			pr_debug("%s:%u: not accessible\n", __func__,
560*4882a593Smuzhiyun 				 __LINE__);
561*4882a593Smuzhiyun 		}
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 		if (result)
564*4882a593Smuzhiyun 			pr_debug("%s:%u ps3_setup_storage_dev failed\n",
565*4882a593Smuzhiyun 				 __func__, __LINE__);
566*4882a593Smuzhiyun 		break;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	case PS3_DEV_TYPE_STOR_ROM:
569*4882a593Smuzhiyun 		result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_ROM);
570*4882a593Smuzhiyun 		if (result)
571*4882a593Smuzhiyun 			pr_debug("%s:%u ps3_setup_storage_dev failed\n",
572*4882a593Smuzhiyun 				 __func__, __LINE__);
573*4882a593Smuzhiyun 		break;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	case PS3_DEV_TYPE_STOR_FLASH:
576*4882a593Smuzhiyun 		result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_FLASH);
577*4882a593Smuzhiyun 		if (result)
578*4882a593Smuzhiyun 			pr_debug("%s:%u ps3_setup_storage_dev failed\n",
579*4882a593Smuzhiyun 				 __func__, __LINE__);
580*4882a593Smuzhiyun 		break;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	default:
583*4882a593Smuzhiyun 		result = 0;
584*4882a593Smuzhiyun 		pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__,
585*4882a593Smuzhiyun 			repo->dev_type);
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	return result;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun /**
592*4882a593Smuzhiyun  * ps3_setup_static_device - Setup a static device from the repository
593*4882a593Smuzhiyun  */
594*4882a593Smuzhiyun 
ps3_setup_static_device(const struct ps3_repository_device * repo)595*4882a593Smuzhiyun static int __init ps3_setup_static_device(const struct ps3_repository_device *repo)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	int result;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	switch (repo->dev_type) {
600*4882a593Smuzhiyun 	case PS3_DEV_TYPE_SB_GELIC:
601*4882a593Smuzhiyun 		result = ps3_setup_gelic_device(repo);
602*4882a593Smuzhiyun 		if (result) {
603*4882a593Smuzhiyun 			pr_debug("%s:%d ps3_setup_gelic_device failed\n",
604*4882a593Smuzhiyun 				__func__, __LINE__);
605*4882a593Smuzhiyun 		}
606*4882a593Smuzhiyun 		break;
607*4882a593Smuzhiyun 	case PS3_DEV_TYPE_SB_USB:
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 		/* Each USB device has both an EHCI and an OHCI HC */
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 		result = ps3_setup_ehci_device(repo);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 		if (result) {
614*4882a593Smuzhiyun 			pr_debug("%s:%d ps3_setup_ehci_device failed\n",
615*4882a593Smuzhiyun 				__func__, __LINE__);
616*4882a593Smuzhiyun 		}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 		result = ps3_setup_ohci_device(repo);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 		if (result) {
621*4882a593Smuzhiyun 			pr_debug("%s:%d ps3_setup_ohci_device failed\n",
622*4882a593Smuzhiyun 				__func__, __LINE__);
623*4882a593Smuzhiyun 		}
624*4882a593Smuzhiyun 		break;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	default:
627*4882a593Smuzhiyun 		return ps3_setup_dynamic_device(repo);
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	return result;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun 
ps3_find_and_add_device(u64 bus_id,u64 dev_id)633*4882a593Smuzhiyun static void ps3_find_and_add_device(u64 bus_id, u64 dev_id)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	struct ps3_repository_device repo;
636*4882a593Smuzhiyun 	int res;
637*4882a593Smuzhiyun 	unsigned int retries;
638*4882a593Smuzhiyun 	unsigned long rem;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	/*
641*4882a593Smuzhiyun 	 * On some firmware versions (e.g. 1.90), the device may not show up
642*4882a593Smuzhiyun 	 * in the repository immediately
643*4882a593Smuzhiyun 	 */
644*4882a593Smuzhiyun 	for (retries = 0; retries < 10; retries++) {
645*4882a593Smuzhiyun 		res = ps3_repository_find_device_by_id(&repo, bus_id, dev_id);
646*4882a593Smuzhiyun 		if (!res)
647*4882a593Smuzhiyun 			goto found;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 		rem = msleep_interruptible(100);
650*4882a593Smuzhiyun 		if (rem)
651*4882a593Smuzhiyun 			break;
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun 	pr_warn("%s:%u: device %llu:%llu not found\n",
654*4882a593Smuzhiyun 		__func__, __LINE__, bus_id, dev_id);
655*4882a593Smuzhiyun 	return;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun found:
658*4882a593Smuzhiyun 	if (retries)
659*4882a593Smuzhiyun 		pr_debug("%s:%u: device %llu:%llu found after %u retries\n",
660*4882a593Smuzhiyun 			 __func__, __LINE__, bus_id, dev_id, retries);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	ps3_setup_dynamic_device(&repo);
663*4882a593Smuzhiyun 	return;
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun #define PS3_NOTIFICATION_DEV_ID		ULONG_MAX
667*4882a593Smuzhiyun #define PS3_NOTIFICATION_INTERRUPT_ID	0
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun struct ps3_notification_device {
670*4882a593Smuzhiyun 	struct ps3_system_bus_device sbd;
671*4882a593Smuzhiyun 	spinlock_t lock;
672*4882a593Smuzhiyun 	u64 tag;
673*4882a593Smuzhiyun 	u64 lv1_status;
674*4882a593Smuzhiyun 	struct rcuwait wait;
675*4882a593Smuzhiyun 	bool done;
676*4882a593Smuzhiyun };
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun enum ps3_notify_type {
679*4882a593Smuzhiyun 	notify_device_ready = 0,
680*4882a593Smuzhiyun 	notify_region_probe = 1,
681*4882a593Smuzhiyun 	notify_region_update = 2,
682*4882a593Smuzhiyun };
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun struct ps3_notify_cmd {
685*4882a593Smuzhiyun 	u64 operation_code;		/* must be zero */
686*4882a593Smuzhiyun 	u64 event_mask;			/* OR of 1UL << enum ps3_notify_type */
687*4882a593Smuzhiyun };
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun struct ps3_notify_event {
690*4882a593Smuzhiyun 	u64 event_type;			/* enum ps3_notify_type */
691*4882a593Smuzhiyun 	u64 bus_id;
692*4882a593Smuzhiyun 	u64 dev_id;
693*4882a593Smuzhiyun 	u64 dev_type;
694*4882a593Smuzhiyun 	u64 dev_port;
695*4882a593Smuzhiyun };
696*4882a593Smuzhiyun 
ps3_notification_interrupt(int irq,void * data)697*4882a593Smuzhiyun static irqreturn_t ps3_notification_interrupt(int irq, void *data)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	struct ps3_notification_device *dev = data;
700*4882a593Smuzhiyun 	int res;
701*4882a593Smuzhiyun 	u64 tag, status;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	spin_lock(&dev->lock);
704*4882a593Smuzhiyun 	res = lv1_storage_get_async_status(PS3_NOTIFICATION_DEV_ID, &tag,
705*4882a593Smuzhiyun 					   &status);
706*4882a593Smuzhiyun 	if (tag != dev->tag)
707*4882a593Smuzhiyun 		pr_err("%s:%u: tag mismatch, got %llx, expected %llx\n",
708*4882a593Smuzhiyun 		       __func__, __LINE__, tag, dev->tag);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	if (res) {
711*4882a593Smuzhiyun 		pr_err("%s:%u: res %d status 0x%llx\n", __func__, __LINE__, res,
712*4882a593Smuzhiyun 		       status);
713*4882a593Smuzhiyun 	} else {
714*4882a593Smuzhiyun 		pr_debug("%s:%u: completed, status 0x%llx\n", __func__,
715*4882a593Smuzhiyun 			 __LINE__, status);
716*4882a593Smuzhiyun 		dev->lv1_status = status;
717*4882a593Smuzhiyun 		dev->done = true;
718*4882a593Smuzhiyun 		rcuwait_wake_up(&dev->wait);
719*4882a593Smuzhiyun 	}
720*4882a593Smuzhiyun 	spin_unlock(&dev->lock);
721*4882a593Smuzhiyun 	return IRQ_HANDLED;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun 
ps3_notification_read_write(struct ps3_notification_device * dev,u64 lpar,int write)724*4882a593Smuzhiyun static int ps3_notification_read_write(struct ps3_notification_device *dev,
725*4882a593Smuzhiyun 				       u64 lpar, int write)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun 	const char *op = write ? "write" : "read";
728*4882a593Smuzhiyun 	unsigned long flags;
729*4882a593Smuzhiyun 	int res;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->lock, flags);
732*4882a593Smuzhiyun 	res = write ? lv1_storage_write(dev->sbd.dev_id, 0, 0, 1, 0, lpar,
733*4882a593Smuzhiyun 					&dev->tag)
734*4882a593Smuzhiyun 		    : lv1_storage_read(dev->sbd.dev_id, 0, 0, 1, 0, lpar,
735*4882a593Smuzhiyun 				       &dev->tag);
736*4882a593Smuzhiyun 	dev->done = false;
737*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev->lock, flags);
738*4882a593Smuzhiyun 	if (res) {
739*4882a593Smuzhiyun 		pr_err("%s:%u: %s failed %d\n", __func__, __LINE__, op, res);
740*4882a593Smuzhiyun 		return -EPERM;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 	pr_debug("%s:%u: notification %s issued\n", __func__, __LINE__, op);
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	rcuwait_wait_event(&dev->wait, dev->done || kthread_should_stop(), TASK_IDLE);
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	if (kthread_should_stop())
747*4882a593Smuzhiyun 		res = -EINTR;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	if (dev->lv1_status) {
750*4882a593Smuzhiyun 		pr_err("%s:%u: %s not completed, status 0x%llx\n", __func__,
751*4882a593Smuzhiyun 		       __LINE__, op, dev->lv1_status);
752*4882a593Smuzhiyun 		return -EIO;
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun 	pr_debug("%s:%u: notification %s completed\n", __func__, __LINE__, op);
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	return 0;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun static struct task_struct *probe_task;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun /**
762*4882a593Smuzhiyun  * ps3_probe_thread - Background repository probing at system startup.
763*4882a593Smuzhiyun  *
764*4882a593Smuzhiyun  * This implementation only supports background probing on a single bus.
765*4882a593Smuzhiyun  * It uses the hypervisor's storage device notification mechanism to wait until
766*4882a593Smuzhiyun  * a storage device is ready.  The device notification mechanism uses a
767*4882a593Smuzhiyun  * pseudo device to asynchronously notify the guest when storage devices become
768*4882a593Smuzhiyun  * ready.  The notification device has a block size of 512 bytes.
769*4882a593Smuzhiyun  */
770*4882a593Smuzhiyun 
ps3_probe_thread(void * data)771*4882a593Smuzhiyun static int ps3_probe_thread(void *data)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun 	struct ps3_notification_device dev;
774*4882a593Smuzhiyun 	int res;
775*4882a593Smuzhiyun 	unsigned int irq;
776*4882a593Smuzhiyun 	u64 lpar;
777*4882a593Smuzhiyun 	void *buf;
778*4882a593Smuzhiyun 	struct ps3_notify_cmd *notify_cmd;
779*4882a593Smuzhiyun 	struct ps3_notify_event *notify_event;
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__);
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	buf = kzalloc(512, GFP_KERNEL);
784*4882a593Smuzhiyun 	if (!buf)
785*4882a593Smuzhiyun 		return -ENOMEM;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	lpar = ps3_mm_phys_to_lpar(__pa(buf));
788*4882a593Smuzhiyun 	notify_cmd = buf;
789*4882a593Smuzhiyun 	notify_event = buf;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	/* dummy system bus device */
792*4882a593Smuzhiyun 	dev.sbd.bus_id = (u64)data;
793*4882a593Smuzhiyun 	dev.sbd.dev_id = PS3_NOTIFICATION_DEV_ID;
794*4882a593Smuzhiyun 	dev.sbd.interrupt_id = PS3_NOTIFICATION_INTERRUPT_ID;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	res = lv1_open_device(dev.sbd.bus_id, dev.sbd.dev_id, 0);
797*4882a593Smuzhiyun 	if (res) {
798*4882a593Smuzhiyun 		pr_err("%s:%u: lv1_open_device failed %s\n", __func__,
799*4882a593Smuzhiyun 		       __LINE__, ps3_result(res));
800*4882a593Smuzhiyun 		goto fail_free;
801*4882a593Smuzhiyun 	}
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	res = ps3_sb_event_receive_port_setup(&dev.sbd, PS3_BINDING_CPU_ANY,
804*4882a593Smuzhiyun 					      &irq);
805*4882a593Smuzhiyun 	if (res) {
806*4882a593Smuzhiyun 		pr_err("%s:%u: ps3_sb_event_receive_port_setup failed %d\n",
807*4882a593Smuzhiyun 		       __func__, __LINE__, res);
808*4882a593Smuzhiyun 	       goto fail_close_device;
809*4882a593Smuzhiyun 	}
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	spin_lock_init(&dev.lock);
812*4882a593Smuzhiyun 	rcuwait_init(&dev.wait);
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	res = request_irq(irq, ps3_notification_interrupt, 0,
815*4882a593Smuzhiyun 			  "ps3_notification", &dev);
816*4882a593Smuzhiyun 	if (res) {
817*4882a593Smuzhiyun 		pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__,
818*4882a593Smuzhiyun 		       res);
819*4882a593Smuzhiyun 		goto fail_sb_event_receive_port_destroy;
820*4882a593Smuzhiyun 	}
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	/* Setup and write the request for device notification. */
823*4882a593Smuzhiyun 	notify_cmd->operation_code = 0; /* must be zero */
824*4882a593Smuzhiyun 	notify_cmd->event_mask = 1UL << notify_region_probe;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	res = ps3_notification_read_write(&dev, lpar, 1);
827*4882a593Smuzhiyun 	if (res)
828*4882a593Smuzhiyun 		goto fail_free_irq;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	/* Loop here processing the requested notification events. */
831*4882a593Smuzhiyun 	do {
832*4882a593Smuzhiyun 		try_to_freeze();
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 		memset(notify_event, 0, sizeof(*notify_event));
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 		res = ps3_notification_read_write(&dev, lpar, 0);
837*4882a593Smuzhiyun 		if (res)
838*4882a593Smuzhiyun 			break;
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 		pr_debug("%s:%u: notify event type 0x%llx bus id %llu dev id %llu"
841*4882a593Smuzhiyun 			 " type %llu port %llu\n", __func__, __LINE__,
842*4882a593Smuzhiyun 			 notify_event->event_type, notify_event->bus_id,
843*4882a593Smuzhiyun 			 notify_event->dev_id, notify_event->dev_type,
844*4882a593Smuzhiyun 			 notify_event->dev_port);
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 		if (notify_event->event_type != notify_region_probe ||
847*4882a593Smuzhiyun 		    notify_event->bus_id != dev.sbd.bus_id) {
848*4882a593Smuzhiyun 			pr_warn("%s:%u: bad notify_event: event %llu, dev_id %llu, dev_type %llu\n",
849*4882a593Smuzhiyun 				__func__, __LINE__, notify_event->event_type,
850*4882a593Smuzhiyun 				notify_event->dev_id, notify_event->dev_type);
851*4882a593Smuzhiyun 			continue;
852*4882a593Smuzhiyun 		}
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 		ps3_find_and_add_device(dev.sbd.bus_id, notify_event->dev_id);
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	} while (!kthread_should_stop());
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun fail_free_irq:
859*4882a593Smuzhiyun 	free_irq(irq, &dev);
860*4882a593Smuzhiyun fail_sb_event_receive_port_destroy:
861*4882a593Smuzhiyun 	ps3_sb_event_receive_port_destroy(&dev.sbd, irq);
862*4882a593Smuzhiyun fail_close_device:
863*4882a593Smuzhiyun 	lv1_close_device(dev.sbd.bus_id, dev.sbd.dev_id);
864*4882a593Smuzhiyun fail_free:
865*4882a593Smuzhiyun 	kfree(buf);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	probe_task = NULL;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__);
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	return 0;
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun /**
875*4882a593Smuzhiyun  * ps3_stop_probe_thread - Stops the background probe thread.
876*4882a593Smuzhiyun  *
877*4882a593Smuzhiyun  */
878*4882a593Smuzhiyun 
ps3_stop_probe_thread(struct notifier_block * nb,unsigned long code,void * data)879*4882a593Smuzhiyun static int ps3_stop_probe_thread(struct notifier_block *nb, unsigned long code,
880*4882a593Smuzhiyun 				 void *data)
881*4882a593Smuzhiyun {
882*4882a593Smuzhiyun 	if (probe_task)
883*4882a593Smuzhiyun 		kthread_stop(probe_task);
884*4882a593Smuzhiyun 	return 0;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun static struct notifier_block nb = {
888*4882a593Smuzhiyun 	.notifier_call = ps3_stop_probe_thread
889*4882a593Smuzhiyun };
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun /**
892*4882a593Smuzhiyun  * ps3_start_probe_thread - Starts the background probe thread.
893*4882a593Smuzhiyun  *
894*4882a593Smuzhiyun  */
895*4882a593Smuzhiyun 
ps3_start_probe_thread(enum ps3_bus_type bus_type)896*4882a593Smuzhiyun static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type)
897*4882a593Smuzhiyun {
898*4882a593Smuzhiyun 	int result;
899*4882a593Smuzhiyun 	struct task_struct *task;
900*4882a593Smuzhiyun 	struct ps3_repository_device repo;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	memset(&repo, 0, sizeof(repo));
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	repo.bus_type = bus_type;
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 	result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index);
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	if (result) {
911*4882a593Smuzhiyun 		printk(KERN_ERR "%s: Cannot find bus (%d)\n", __func__, result);
912*4882a593Smuzhiyun 		return -ENODEV;
913*4882a593Smuzhiyun 	}
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id);
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	if (result) {
918*4882a593Smuzhiyun 		printk(KERN_ERR "%s: read_bus_id failed %d\n", __func__,
919*4882a593Smuzhiyun 			result);
920*4882a593Smuzhiyun 		return -ENODEV;
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	task = kthread_run(ps3_probe_thread, (void *)repo.bus_id,
924*4882a593Smuzhiyun 			   "ps3-probe-%u", bus_type);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	if (IS_ERR(task)) {
927*4882a593Smuzhiyun 		result = PTR_ERR(task);
928*4882a593Smuzhiyun 		printk(KERN_ERR "%s: kthread_run failed %d\n", __func__,
929*4882a593Smuzhiyun 		       result);
930*4882a593Smuzhiyun 		return result;
931*4882a593Smuzhiyun 	}
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	probe_task = task;
934*4882a593Smuzhiyun 	register_reboot_notifier(&nb);
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
937*4882a593Smuzhiyun 	return 0;
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun /**
941*4882a593Smuzhiyun  * ps3_register_devices - Probe the system and register devices found.
942*4882a593Smuzhiyun  *
943*4882a593Smuzhiyun  * A device_initcall() routine.
944*4882a593Smuzhiyun  */
945*4882a593Smuzhiyun 
ps3_register_devices(void)946*4882a593Smuzhiyun static int __init ps3_register_devices(void)
947*4882a593Smuzhiyun {
948*4882a593Smuzhiyun 	int result;
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
951*4882a593Smuzhiyun 		return -ENODEV;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	/* ps3_repository_dump_bus_info(); */
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	result = ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE);
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	ps3_register_vuart_devices();
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	ps3_register_graphics_devices();
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	ps3_repository_find_devices(PS3_BUS_TYPE_SB, ps3_setup_static_device);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	ps3_register_sound_devices();
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	ps3_register_lpm_devices();
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	ps3_register_ramdisk_device();
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
972*4882a593Smuzhiyun 	return 0;
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun device_initcall(ps3_register_devices);
976