in iop-adma.c [1265:1433]
static int iop_adma_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = 0, i;
struct iop_adma_device *adev;
struct iop_adma_chan *iop_chan;
struct dma_device *dma_dev;
struct iop_adma_platform_data *plat_data = dev_get_platdata(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), pdev->name))
return -EBUSY;
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
dma_dev = &adev->common;
/* allocate coherent memory for hardware descriptors
* note: writecombine gives slightly better performance, but
* requires that we explicitly flush the writes
*/
adev->dma_desc_pool_virt = dma_alloc_wc(&pdev->dev,
plat_data->pool_size,
&adev->dma_desc_pool,
GFP_KERNEL);
if (!adev->dma_desc_pool_virt) {
ret = -ENOMEM;
goto err_free_adev;
}
dev_dbg(&pdev->dev, "%s: allocated descriptor pool virt %p phys %pad\n",
__func__, adev->dma_desc_pool_virt, &adev->dma_desc_pool);
adev->id = plat_data->hw_id;
/* discover transaction capabilites from the platform data */
dma_dev->cap_mask = plat_data->cap_mask;
adev->pdev = pdev;
platform_set_drvdata(pdev, adev);
INIT_LIST_HEAD(&dma_dev->channels);
/* set base routines */
dma_dev->device_alloc_chan_resources = iop_adma_alloc_chan_resources;
dma_dev->device_free_chan_resources = iop_adma_free_chan_resources;
dma_dev->device_tx_status = iop_adma_status;
dma_dev->device_issue_pending = iop_adma_issue_pending;
dma_dev->dev = &pdev->dev;
/* set prep routines based on capability */
if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask))
dma_dev->device_prep_dma_memcpy = iop_adma_prep_dma_memcpy;
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
dma_dev->max_xor = iop_adma_get_max_xor();
dma_dev->device_prep_dma_xor = iop_adma_prep_dma_xor;
}
if (dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask))
dma_dev->device_prep_dma_xor_val =
iop_adma_prep_dma_xor_val;
if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
dma_set_maxpq(dma_dev, iop_adma_get_max_pq(), 0);
dma_dev->device_prep_dma_pq = iop_adma_prep_dma_pq;
}
if (dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask))
dma_dev->device_prep_dma_pq_val =
iop_adma_prep_dma_pq_val;
if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask))
dma_dev->device_prep_dma_interrupt =
iop_adma_prep_dma_interrupt;
iop_chan = kzalloc(sizeof(*iop_chan), GFP_KERNEL);
if (!iop_chan) {
ret = -ENOMEM;
goto err_free_dma;
}
iop_chan->device = adev;
iop_chan->mmr_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!iop_chan->mmr_base) {
ret = -ENOMEM;
goto err_free_iop_chan;
}
tasklet_setup(&iop_chan->irq_tasklet, iop_adma_tasklet);
/* clear errors before enabling interrupts */
iop_adma_device_clear_err_status(iop_chan);
for (i = 0; i < 3; i++) {
static const irq_handler_t handler[] = {
iop_adma_eot_handler,
iop_adma_eoc_handler,
iop_adma_err_handler
};
int irq = platform_get_irq(pdev, i);
if (irq < 0) {
ret = -ENXIO;
goto err_free_iop_chan;
} else {
ret = devm_request_irq(&pdev->dev, irq,
handler[i], 0, pdev->name, iop_chan);
if (ret)
goto err_free_iop_chan;
}
}
spin_lock_init(&iop_chan->lock);
INIT_LIST_HEAD(&iop_chan->chain);
INIT_LIST_HEAD(&iop_chan->all_slots);
iop_chan->common.device = dma_dev;
dma_cookie_init(&iop_chan->common);
list_add_tail(&iop_chan->common.device_node, &dma_dev->channels);
if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
ret = iop_adma_memcpy_self_test(adev);
dev_dbg(&pdev->dev, "memcpy self test returned %d\n", ret);
if (ret)
goto err_free_iop_chan;
}
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
ret = iop_adma_xor_val_self_test(adev);
dev_dbg(&pdev->dev, "xor self test returned %d\n", ret);
if (ret)
goto err_free_iop_chan;
}
if (dma_has_cap(DMA_PQ, dma_dev->cap_mask) &&
dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) {
#ifdef CONFIG_RAID6_PQ
ret = iop_adma_pq_zero_sum_self_test(adev);
dev_dbg(&pdev->dev, "pq self test returned %d\n", ret);
#else
/* can not test raid6, so do not publish capability */
dma_cap_clear(DMA_PQ, dma_dev->cap_mask);
dma_cap_clear(DMA_PQ_VAL, dma_dev->cap_mask);
ret = 0;
#endif
if (ret)
goto err_free_iop_chan;
}
dev_info(&pdev->dev, "Intel(R) IOP: ( %s%s%s%s%s%s)\n",
dma_has_cap(DMA_PQ, dma_dev->cap_mask) ? "pq " : "",
dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask) ? "pq_val " : "",
dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "",
dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask) ? "xor_val " : "",
dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "",
dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "");
dma_async_device_register(dma_dev);
goto out;
err_free_iop_chan:
kfree(iop_chan);
err_free_dma:
dma_free_coherent(&adev->pdev->dev, plat_data->pool_size,
adev->dma_desc_pool_virt, adev->dma_desc_pool);
err_free_adev:
kfree(adev);
out:
return ret;
}