OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [ps3/] [ps3stor_lib.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * PS3 Storage Library
3
 *
4
 * Copyright (C) 2007 Sony Computer Entertainment Inc.
5
 * Copyright 2007 Sony Corp.
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published
9
 * by the Free Software Foundation; version 2 of the License.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along
17
 * with this program; if not, write to the Free Software Foundation, Inc.,
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
 
21
#include <linux/dma-mapping.h>
22
 
23
#include <asm/lv1call.h>
24
#include <asm/ps3stor.h>
25
 
26
 
27
static int ps3stor_probe_access(struct ps3_storage_device *dev)
28
{
29
        int res, error;
30
        unsigned int i;
31
        unsigned long n;
32
 
33
        if (dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) {
34
                /* special case: CD-ROM is assumed always accessible */
35
                dev->accessible_regions = 1;
36
                return 0;
37
        }
38
 
39
        error = -EPERM;
40
        for (i = 0; i < dev->num_regions; i++) {
41
                dev_dbg(&dev->sbd.core,
42
                        "%s:%u: checking accessibility of region %u\n",
43
                        __func__, __LINE__, i);
44
 
45
                dev->region_idx = i;
46
                res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, 0, 1,
47
                                                 0);
48
                if (res) {
49
                        dev_dbg(&dev->sbd.core, "%s:%u: read failed, "
50
                                "region %u is not accessible\n", __func__,
51
                                __LINE__, i);
52
                        continue;
53
                }
54
 
55
                dev_dbg(&dev->sbd.core, "%s:%u: region %u is accessible\n",
56
                        __func__, __LINE__, i);
57
                set_bit(i, &dev->accessible_regions);
58
 
59
                /* We can access at least one region */
60
                error = 0;
61
        }
62
        if (error)
63
                return error;
64
 
65
        n = hweight_long(dev->accessible_regions);
66
        if (n > 1)
67
                dev_info(&dev->sbd.core,
68
                         "%s:%u: %lu accessible regions found. Only the first "
69
                         "one will be used\n",
70
                         __func__, __LINE__, n);
71
        dev->region_idx = __ffs(dev->accessible_regions);
72
        dev_info(&dev->sbd.core,
73
                 "First accessible region has index %u start %lu size %lu\n",
74
                 dev->region_idx, dev->regions[dev->region_idx].start,
75
                 dev->regions[dev->region_idx].size);
76
 
77
        return 0;
78
}
79
 
80
 
81
/**
82
 *      ps3stor_setup - Setup a storage device before use
83
 *      @dev: Pointer to a struct ps3_storage_device
84
 *      @handler: Pointer to an interrupt handler
85
 *
86
 *      Returns 0 for success, or an error code
87
 */
88
int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler)
89
{
90
        int error, res, alignment;
91
        enum ps3_dma_page_size page_size;
92
 
93
        error = ps3_open_hv_device(&dev->sbd);
94
        if (error) {
95
                dev_err(&dev->sbd.core,
96
                        "%s:%u: ps3_open_hv_device failed %d\n", __func__,
97
                        __LINE__, error);
98
                goto fail;
99
        }
100
 
101
        error = ps3_sb_event_receive_port_setup(&dev->sbd, PS3_BINDING_CPU_ANY,
102
                                                &dev->irq);
103
        if (error) {
104
                dev_err(&dev->sbd.core,
105
                        "%s:%u: ps3_sb_event_receive_port_setup failed %d\n",
106
                       __func__, __LINE__, error);
107
                goto fail_close_device;
108
        }
109
 
110
        error = request_irq(dev->irq, handler, IRQF_DISABLED,
111
                            dev->sbd.core.driver->name, dev);
112
        if (error) {
113
                dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n",
114
                        __func__, __LINE__, error);
115
                goto fail_sb_event_receive_port_destroy;
116
        }
117
 
118
        alignment = min(__ffs(dev->bounce_size),
119
                        __ffs((unsigned long)dev->bounce_buf));
120
        if (alignment < 12) {
121
                dev_err(&dev->sbd.core,
122
                        "%s:%u: bounce buffer not aligned (%lx at 0x%p)\n",
123
                        __func__, __LINE__, dev->bounce_size, dev->bounce_buf);
124
                error = -EINVAL;
125
                goto fail_free_irq;
126
        } else if (alignment < 16)
127
                page_size = PS3_DMA_4K;
128
        else
129
                page_size = PS3_DMA_64K;
130
        dev->sbd.d_region = &dev->dma_region;
131
        ps3_dma_region_init(&dev->sbd, &dev->dma_region, page_size,
132
                            PS3_DMA_OTHER, dev->bounce_buf, dev->bounce_size);
133
        res = ps3_dma_region_create(&dev->dma_region);
134
        if (res) {
135
                dev_err(&dev->sbd.core, "%s:%u: cannot create DMA region\n",
136
                        __func__, __LINE__);
137
                error = -ENOMEM;
138
                goto fail_free_irq;
139
        }
140
 
141
        dev->bounce_lpar = ps3_mm_phys_to_lpar(__pa(dev->bounce_buf));
142
        dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf,
143
                                         dev->bounce_size, DMA_BIDIRECTIONAL);
144
        if (!dev->bounce_dma) {
145
                dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n",
146
                        __func__, __LINE__);
147
                error = -ENODEV;
148
                goto fail_free_dma;
149
        }
150
 
151
        error = ps3stor_probe_access(dev);
152
        if (error) {
153
                dev_err(&dev->sbd.core, "%s:%u: No accessible regions found\n",
154
                        __func__, __LINE__);
155
                goto fail_unmap_dma;
156
        }
157
        return 0;
158
 
159
fail_unmap_dma:
160
        dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
161
                         DMA_BIDIRECTIONAL);
162
fail_free_dma:
163
        ps3_dma_region_free(&dev->dma_region);
164
fail_free_irq:
165
        free_irq(dev->irq, dev);
166
fail_sb_event_receive_port_destroy:
167
        ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
168
fail_close_device:
169
        ps3_close_hv_device(&dev->sbd);
170
fail:
171
        return error;
172
}
173
EXPORT_SYMBOL_GPL(ps3stor_setup);
174
 
175
 
176
/**
177
 *      ps3stor_teardown - Tear down a storage device after use
178
 *      @dev: Pointer to a struct ps3_storage_device
179
 */
180
void ps3stor_teardown(struct ps3_storage_device *dev)
181
{
182
        int error;
183
 
184
        dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
185
                         DMA_BIDIRECTIONAL);
186
        ps3_dma_region_free(&dev->dma_region);
187
 
188
        free_irq(dev->irq, dev);
189
 
190
        error = ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
191
        if (error)
192
                dev_err(&dev->sbd.core,
193
                        "%s:%u: destroy event receive port failed %d\n",
194
                        __func__, __LINE__, error);
195
 
196
        error = ps3_close_hv_device(&dev->sbd);
197
        if (error)
198
                dev_err(&dev->sbd.core,
199
                        "%s:%u: ps3_close_hv_device failed %d\n", __func__,
200
                        __LINE__, error);
201
}
202
EXPORT_SYMBOL_GPL(ps3stor_teardown);
203
 
204
 
205
/**
206
 *      ps3stor_read_write_sectors - read/write from/to a storage device
207
 *      @dev: Pointer to a struct ps3_storage_device
208
 *      @lpar: HV logical partition address
209
 *      @start_sector: First sector to read/write
210
 *      @sectors: Number of sectors to read/write
211
 *      @write: Flag indicating write (non-zero) or read (zero)
212
 *
213
 *      Returns 0 for success, -1 in case of failure to submit the command, or
214
 *      an LV1 status value in case of other errors
215
 */
216
u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar,
217
                               u64 start_sector, u64 sectors, int write)
218
{
219
        unsigned int region_id = dev->regions[dev->region_idx].id;
220
        const char *op = write ? "write" : "read";
221
        int res;
222
 
223
        dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
224
                __func__, __LINE__, op, sectors, start_sector);
225
 
226
        init_completion(&dev->done);
227
        res = write ? lv1_storage_write(dev->sbd.dev_id, region_id,
228
                                        start_sector, sectors, 0, lpar,
229
                                        &dev->tag)
230
                    : lv1_storage_read(dev->sbd.dev_id, region_id,
231
                                       start_sector, sectors, 0, lpar,
232
                                       &dev->tag);
233
        if (res) {
234
                dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
235
                        __LINE__, op, res);
236
                return -1;
237
        }
238
 
239
        wait_for_completion(&dev->done);
240
        if (dev->lv1_status) {
241
                dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
242
                        __LINE__, op, dev->lv1_status);
243
                return dev->lv1_status;
244
        }
245
 
246
        dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__,
247
                op);
248
 
249
        return 0;
250
}
251
EXPORT_SYMBOL_GPL(ps3stor_read_write_sectors);
252
 
253
 
254
/**
255
 *      ps3stor_send_command - send a device command to a storage device
256
 *      @dev: Pointer to a struct ps3_storage_device
257
 *      @cmd: Command number
258
 *      @arg1: First command argument
259
 *      @arg2: Second command argument
260
 *      @arg3: Third command argument
261
 *      @arg4: Fourth command argument
262
 *
263
 *      Returns 0 for success, -1 in case of failure to submit the command, or
264
 *      an LV1 status value in case of other errors
265
 */
266
u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1,
267
                         u64 arg2, u64 arg3, u64 arg4)
268
{
269
        int res;
270
 
271
        dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%lx\n", __func__,
272
                __LINE__, cmd);
273
 
274
        init_completion(&dev->done);
275
 
276
        res = lv1_storage_send_device_command(dev->sbd.dev_id, cmd, arg1,
277
                                              arg2, arg3, arg4, &dev->tag);
278
        if (res) {
279
                dev_err(&dev->sbd.core,
280
                        "%s:%u: send_device_command 0x%lx failed %d\n",
281
                        __func__, __LINE__, cmd, res);
282
                return -1;
283
        }
284
 
285
        wait_for_completion(&dev->done);
286
        if (dev->lv1_status) {
287
                dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx failed 0x%lx\n",
288
                        __func__, __LINE__, cmd, dev->lv1_status);
289
                return dev->lv1_status;
290
        }
291
 
292
        dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx completed\n", __func__,
293
                __LINE__, cmd);
294
 
295
        return 0;
296
}
297
EXPORT_SYMBOL_GPL(ps3stor_send_command);
298
 
299
 
300
MODULE_LICENSE("GPL");
301
MODULE_DESCRIPTION("PS3 Storage Bus Library");
302
MODULE_AUTHOR("Sony Corporation");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.