0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/dma-mapping.h>
0010 #include <linux/module.h>
0011
0012 #include <asm/lv1call.h>
0013 #include <asm/ps3stor.h>
0014
0015
0016
0017
0018
0019
0020
0021 static struct ps3_flash_workaround {
0022 int flash_open;
0023 int disk_open;
0024 struct ps3_system_bus_device *disk_sbd;
0025 } ps3_flash_workaround;
0026
0027 static int ps3stor_open_hv_device(struct ps3_system_bus_device *sbd)
0028 {
0029 int error = ps3_open_hv_device(sbd);
0030
0031 if (error)
0032 return error;
0033
0034 if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH)
0035 ps3_flash_workaround.flash_open = 1;
0036
0037 if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
0038 ps3_flash_workaround.disk_open = 1;
0039
0040 return 0;
0041 }
0042
0043 static int ps3stor_close_hv_device(struct ps3_system_bus_device *sbd)
0044 {
0045 int error;
0046
0047 if (sbd->match_id == PS3_MATCH_ID_STOR_DISK
0048 && ps3_flash_workaround.disk_open
0049 && ps3_flash_workaround.flash_open) {
0050 ps3_flash_workaround.disk_sbd = sbd;
0051 return 0;
0052 }
0053
0054 error = ps3_close_hv_device(sbd);
0055
0056 if (error)
0057 return error;
0058
0059 if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
0060 ps3_flash_workaround.disk_open = 0;
0061
0062 if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH) {
0063 ps3_flash_workaround.flash_open = 0;
0064
0065 if (ps3_flash_workaround.disk_sbd) {
0066 ps3_close_hv_device(ps3_flash_workaround.disk_sbd);
0067 ps3_flash_workaround.disk_open = 0;
0068 ps3_flash_workaround.disk_sbd = NULL;
0069 }
0070 }
0071
0072 return 0;
0073 }
0074
0075 static int ps3stor_probe_access(struct ps3_storage_device *dev)
0076 {
0077 int res, error;
0078 unsigned int i;
0079 unsigned long n;
0080
0081 if (dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) {
0082
0083 dev->accessible_regions = 1;
0084 return 0;
0085 }
0086
0087 error = -EPERM;
0088 for (i = 0; i < dev->num_regions; i++) {
0089 dev_dbg(&dev->sbd.core,
0090 "%s:%u: checking accessibility of region %u\n",
0091 __func__, __LINE__, i);
0092
0093 dev->region_idx = i;
0094 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, 0, 1,
0095 0);
0096 if (res) {
0097 dev_dbg(&dev->sbd.core, "%s:%u: read failed, "
0098 "region %u is not accessible\n", __func__,
0099 __LINE__, i);
0100 continue;
0101 }
0102
0103 dev_dbg(&dev->sbd.core, "%s:%u: region %u is accessible\n",
0104 __func__, __LINE__, i);
0105 set_bit(i, &dev->accessible_regions);
0106
0107
0108 error = 0;
0109 }
0110 if (error)
0111 return error;
0112
0113 n = hweight_long(dev->accessible_regions);
0114 if (n > 1)
0115 dev_info(&dev->sbd.core,
0116 "%s:%u: %lu accessible regions found. Only the first "
0117 "one will be used\n",
0118 __func__, __LINE__, n);
0119 dev->region_idx = __ffs(dev->accessible_regions);
0120 dev_info(&dev->sbd.core,
0121 "First accessible region has index %u start %llu size %llu\n",
0122 dev->region_idx, dev->regions[dev->region_idx].start,
0123 dev->regions[dev->region_idx].size);
0124
0125 return 0;
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler)
0137 {
0138 int error, res, alignment;
0139 enum ps3_dma_page_size page_size;
0140
0141 error = ps3stor_open_hv_device(&dev->sbd);
0142 if (error) {
0143 dev_err(&dev->sbd.core,
0144 "%s:%u: ps3_open_hv_device failed %d\n", __func__,
0145 __LINE__, error);
0146 goto fail;
0147 }
0148
0149 error = ps3_sb_event_receive_port_setup(&dev->sbd, PS3_BINDING_CPU_ANY,
0150 &dev->irq);
0151 if (error) {
0152 dev_err(&dev->sbd.core,
0153 "%s:%u: ps3_sb_event_receive_port_setup failed %d\n",
0154 __func__, __LINE__, error);
0155 goto fail_close_device;
0156 }
0157
0158 error = request_irq(dev->irq, handler, 0,
0159 dev->sbd.core.driver->name, dev);
0160 if (error) {
0161 dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n",
0162 __func__, __LINE__, error);
0163 goto fail_sb_event_receive_port_destroy;
0164 }
0165
0166 alignment = min(__ffs(dev->bounce_size),
0167 __ffs((unsigned long)dev->bounce_buf));
0168 if (alignment < 12) {
0169 dev_err(&dev->sbd.core,
0170 "%s:%u: bounce buffer not aligned (%lx at 0x%p)\n",
0171 __func__, __LINE__, dev->bounce_size, dev->bounce_buf);
0172 error = -EINVAL;
0173 goto fail_free_irq;
0174 } else if (alignment < 16)
0175 page_size = PS3_DMA_4K;
0176 else
0177 page_size = PS3_DMA_64K;
0178 dev->sbd.d_region = &dev->dma_region;
0179 ps3_dma_region_init(&dev->sbd, &dev->dma_region, page_size,
0180 PS3_DMA_OTHER, dev->bounce_buf, dev->bounce_size);
0181 res = ps3_dma_region_create(&dev->dma_region);
0182 if (res) {
0183 dev_err(&dev->sbd.core, "%s:%u: cannot create DMA region\n",
0184 __func__, __LINE__);
0185 error = -ENOMEM;
0186 goto fail_free_irq;
0187 }
0188
0189 dev->bounce_lpar = ps3_mm_phys_to_lpar(__pa(dev->bounce_buf));
0190 dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf,
0191 dev->bounce_size, DMA_BIDIRECTIONAL);
0192 if (dma_mapping_error(&dev->sbd.core, dev->bounce_dma)) {
0193 dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n",
0194 __func__, __LINE__);
0195 error = -ENODEV;
0196 goto fail_free_dma;
0197 }
0198
0199 error = ps3stor_probe_access(dev);
0200 if (error) {
0201 dev_err(&dev->sbd.core, "%s:%u: No accessible regions found\n",
0202 __func__, __LINE__);
0203 goto fail_unmap_dma;
0204 }
0205 return 0;
0206
0207 fail_unmap_dma:
0208 dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
0209 DMA_BIDIRECTIONAL);
0210 fail_free_dma:
0211 ps3_dma_region_free(&dev->dma_region);
0212 fail_free_irq:
0213 free_irq(dev->irq, dev);
0214 fail_sb_event_receive_port_destroy:
0215 ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
0216 fail_close_device:
0217 ps3stor_close_hv_device(&dev->sbd);
0218 fail:
0219 return error;
0220 }
0221 EXPORT_SYMBOL_GPL(ps3stor_setup);
0222
0223
0224
0225
0226
0227
0228 void ps3stor_teardown(struct ps3_storage_device *dev)
0229 {
0230 int error;
0231
0232 dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
0233 DMA_BIDIRECTIONAL);
0234 ps3_dma_region_free(&dev->dma_region);
0235
0236 free_irq(dev->irq, dev);
0237
0238 error = ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
0239 if (error)
0240 dev_err(&dev->sbd.core,
0241 "%s:%u: destroy event receive port failed %d\n",
0242 __func__, __LINE__, error);
0243
0244 error = ps3stor_close_hv_device(&dev->sbd);
0245 if (error)
0246 dev_err(&dev->sbd.core,
0247 "%s:%u: ps3_close_hv_device failed %d\n", __func__,
0248 __LINE__, error);
0249 }
0250 EXPORT_SYMBOL_GPL(ps3stor_teardown);
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264 u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar,
0265 u64 start_sector, u64 sectors, int write)
0266 {
0267 unsigned int region_id = dev->regions[dev->region_idx].id;
0268 const char *op = write ? "write" : "read";
0269 int res;
0270
0271 dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
0272 __func__, __LINE__, op, sectors, start_sector);
0273
0274 init_completion(&dev->done);
0275 res = write ? lv1_storage_write(dev->sbd.dev_id, region_id,
0276 start_sector, sectors, 0, lpar,
0277 &dev->tag)
0278 : lv1_storage_read(dev->sbd.dev_id, region_id,
0279 start_sector, sectors, 0, lpar,
0280 &dev->tag);
0281 if (res) {
0282 dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
0283 __LINE__, op, res);
0284 return -1;
0285 }
0286
0287 wait_for_completion(&dev->done);
0288 if (dev->lv1_status) {
0289 dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
0290 __LINE__, op, dev->lv1_status);
0291 return dev->lv1_status;
0292 }
0293
0294 dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__,
0295 op);
0296
0297 return 0;
0298 }
0299 EXPORT_SYMBOL_GPL(ps3stor_read_write_sectors);
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314 u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1,
0315 u64 arg2, u64 arg3, u64 arg4)
0316 {
0317 int res;
0318
0319 dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%llx\n", __func__,
0320 __LINE__, cmd);
0321
0322 init_completion(&dev->done);
0323
0324 res = lv1_storage_send_device_command(dev->sbd.dev_id, cmd, arg1,
0325 arg2, arg3, arg4, &dev->tag);
0326 if (res) {
0327 dev_err(&dev->sbd.core,
0328 "%s:%u: send_device_command 0x%llx failed %d\n",
0329 __func__, __LINE__, cmd, res);
0330 return -1;
0331 }
0332
0333 wait_for_completion(&dev->done);
0334 if (dev->lv1_status) {
0335 dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx failed 0x%llx\n",
0336 __func__, __LINE__, cmd, dev->lv1_status);
0337 return dev->lv1_status;
0338 }
0339
0340 dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx completed\n", __func__,
0341 __LINE__, cmd);
0342
0343 return 0;
0344 }
0345 EXPORT_SYMBOL_GPL(ps3stor_send_command);
0346
0347
0348 MODULE_LICENSE("GPL");
0349 MODULE_DESCRIPTION("PS3 Storage Bus Library");
0350 MODULE_AUTHOR("Sony Corporation");