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