in ps3vram.c [609:788]
static int ps3vram_probe(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv;
int error, status;
struct gendisk *gendisk;
u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar,
reports_size, xdr_lpar;
char *rest;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto fail;
}
spin_lock_init(&priv->lock);
bio_list_init(&priv->list);
ps3_system_bus_set_drvdata(dev, priv);
/* Allocate XDR buffer (1MiB aligned) */
priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
get_order(XDR_BUF_SIZE));
if (priv->xdr_buf == NULL) {
dev_err(&dev->core, "Could not allocate XDR buffer\n");
error = -ENOMEM;
goto fail_free_priv;
}
/* Put FIFO at begginning of XDR buffer */
priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET);
priv->fifo_ptr = priv->fifo_base;
/* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */
if (ps3_open_hv_device(dev)) {
dev_err(&dev->core, "ps3_open_hv_device failed\n");
error = -EAGAIN;
goto out_free_xdr_buf;
}
/* Request memory */
status = -1;
ddr_size = ALIGN(memparse(size, &rest), 1024*1024);
if (!ddr_size) {
dev_err(&dev->core, "Specified size is too small\n");
error = -EINVAL;
goto out_close_gpu;
}
while (ddr_size > 0) {
status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0,
&priv->memory_handle,
&ddr_lpar);
if (!status)
break;
ddr_size -= 1024*1024;
}
if (status) {
dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n",
status);
error = -ENOMEM;
goto out_close_gpu;
}
/* Request context */
status = lv1_gpu_context_allocate(priv->memory_handle, 0,
&priv->context_handle, &ctrl_lpar,
&info_lpar, &reports_lpar,
&reports_size);
if (status) {
dev_err(&dev->core, "lv1_gpu_context_allocate failed %d\n",
status);
error = -ENOMEM;
goto out_free_memory;
}
/* Map XDR buffer to RSX */
xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf));
status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
xdr_lpar, XDR_BUF_SIZE,
CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
CBE_IOPTE_M);
if (status) {
dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
status);
error = -ENOMEM;
goto out_free_context;
}
priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
if (!priv->ctrl) {
dev_err(&dev->core, "ioremap CTRL failed\n");
error = -ENOMEM;
goto out_unmap_context;
}
priv->reports = ioremap(reports_lpar, reports_size);
if (!priv->reports) {
dev_err(&dev->core, "ioremap REPORTS failed\n");
error = -ENOMEM;
goto out_unmap_ctrl;
}
mutex_lock(&ps3_gpu_mutex);
ps3vram_init_ring(dev);
mutex_unlock(&ps3_gpu_mutex);
priv->size = ddr_size;
ps3vram_bind(dev);
mutex_lock(&ps3_gpu_mutex);
error = ps3vram_wait_ring(dev, 100);
mutex_unlock(&ps3_gpu_mutex);
if (error < 0) {
dev_err(&dev->core, "Failed to initialize channels\n");
error = -ETIMEDOUT;
goto out_unmap_reports;
}
error = ps3vram_cache_init(dev);
if (error < 0) {
goto out_unmap_reports;
}
ps3vram_proc_init(dev);
gendisk = blk_alloc_disk(NUMA_NO_NODE);
if (!gendisk) {
dev_err(&dev->core, "blk_alloc_disk failed\n");
error = -ENOMEM;
goto out_cache_cleanup;
}
priv->gendisk = gendisk;
gendisk->major = ps3vram_major;
gendisk->minors = 1;
gendisk->flags |= GENHD_FL_NO_PART;
gendisk->fops = &ps3vram_fops;
gendisk->private_data = dev;
strlcpy(gendisk->disk_name, DEVICE_NAME, sizeof(gendisk->disk_name));
set_capacity(gendisk, priv->size >> 9);
blk_queue_max_segments(gendisk->queue, BLK_MAX_SEGMENTS);
blk_queue_max_segment_size(gendisk->queue, BLK_MAX_SEGMENT_SIZE);
blk_queue_max_hw_sectors(gendisk->queue, BLK_SAFE_MAX_SECTORS);
dev_info(&dev->core, "%s: Using %llu MiB of GPU memory\n",
gendisk->disk_name, get_capacity(gendisk) >> 11);
error = device_add_disk(&dev->core, gendisk, NULL);
if (error)
goto out_cleanup_disk;
return 0;
out_cleanup_disk:
blk_cleanup_disk(gendisk);
out_cache_cleanup:
remove_proc_entry(DEVICE_NAME, NULL);
ps3vram_cache_cleanup(dev);
out_unmap_reports:
iounmap(priv->reports);
out_unmap_ctrl:
iounmap(priv->ctrl);
out_unmap_context:
lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar,
XDR_BUF_SIZE, CBE_IOPTE_M);
out_free_context:
lv1_gpu_context_free(priv->context_handle);
out_free_memory:
lv1_gpu_memory_free(priv->memory_handle);
out_close_gpu:
ps3_close_hv_device(dev);
out_free_xdr_buf:
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
fail_free_priv:
kfree(priv);
ps3_system_bus_set_drvdata(dev, NULL);
fail:
return error;
}