in mv_xor_v2.c [714:877]
static int mv_xor_v2_probe(struct platform_device *pdev)
{
struct mv_xor_v2_device *xor_dev;
struct resource *res;
int i, ret = 0;
struct dma_device *dma_dev;
struct mv_xor_v2_sw_desc *sw_desc;
BUILD_BUG_ON(sizeof(struct mv_xor_v2_descriptor) !=
MV_XOR_V2_EXT_DESC_SIZE);
xor_dev = devm_kzalloc(&pdev->dev, sizeof(*xor_dev), GFP_KERNEL);
if (!xor_dev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xor_dev->dma_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xor_dev->dma_base))
return PTR_ERR(xor_dev->dma_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
xor_dev->glob_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xor_dev->glob_base))
return PTR_ERR(xor_dev->glob_base);
platform_set_drvdata(pdev, xor_dev);
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
if (ret)
return ret;
xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg");
if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) {
if (!IS_ERR(xor_dev->reg_clk)) {
ret = clk_prepare_enable(xor_dev->reg_clk);
if (ret)
return ret;
} else {
return PTR_ERR(xor_dev->reg_clk);
}
}
xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
if (PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) {
ret = EPROBE_DEFER;
goto disable_reg_clk;
}
if (!IS_ERR(xor_dev->clk)) {
ret = clk_prepare_enable(xor_dev->clk);
if (ret)
goto disable_reg_clk;
}
ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
mv_xor_v2_set_msi_msg);
if (ret)
goto disable_clk;
xor_dev->irq = msi_get_virq(&pdev->dev, 0);
ret = devm_request_irq(&pdev->dev, xor_dev->irq,
mv_xor_v2_interrupt_handler, 0,
dev_name(&pdev->dev), xor_dev);
if (ret)
goto free_msi_irqs;
tasklet_setup(&xor_dev->irq_tasklet, mv_xor_v2_tasklet);
xor_dev->desc_size = mv_xor_v2_set_desc_size(xor_dev);
dma_cookie_init(&xor_dev->dmachan);
/*
* allocate coherent memory for hardware descriptors
* note: writecombine gives slightly better performance, but
* requires that we explicitly flush the writes
*/
xor_dev->hw_desq_virt =
dma_alloc_coherent(&pdev->dev,
xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
&xor_dev->hw_desq, GFP_KERNEL);
if (!xor_dev->hw_desq_virt) {
ret = -ENOMEM;
goto free_msi_irqs;
}
/* alloc memory for the SW descriptors */
xor_dev->sw_desq = devm_kcalloc(&pdev->dev,
MV_XOR_V2_DESC_NUM, sizeof(*sw_desc),
GFP_KERNEL);
if (!xor_dev->sw_desq) {
ret = -ENOMEM;
goto free_hw_desq;
}
spin_lock_init(&xor_dev->lock);
/* init the free SW descriptors list */
INIT_LIST_HEAD(&xor_dev->free_sw_desc);
/* add all SW descriptors to the free list */
for (i = 0; i < MV_XOR_V2_DESC_NUM; i++) {
struct mv_xor_v2_sw_desc *sw_desc =
xor_dev->sw_desq + i;
sw_desc->idx = i;
dma_async_tx_descriptor_init(&sw_desc->async_tx,
&xor_dev->dmachan);
sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
async_tx_ack(&sw_desc->async_tx);
list_add(&sw_desc->free_list,
&xor_dev->free_sw_desc);
}
dma_dev = &xor_dev->dmadev;
/* set DMA capabilities */
dma_cap_zero(dma_dev->cap_mask);
dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
dma_cap_set(DMA_XOR, dma_dev->cap_mask);
dma_cap_set(DMA_INTERRUPT, dma_dev->cap_mask);
/* init dma link list */
INIT_LIST_HEAD(&dma_dev->channels);
/* set base routines */
dma_dev->device_tx_status = dma_cookie_status;
dma_dev->device_issue_pending = mv_xor_v2_issue_pending;
dma_dev->dev = &pdev->dev;
dma_dev->device_prep_dma_memcpy = mv_xor_v2_prep_dma_memcpy;
dma_dev->device_prep_dma_interrupt = mv_xor_v2_prep_dma_interrupt;
dma_dev->max_xor = 8;
dma_dev->device_prep_dma_xor = mv_xor_v2_prep_dma_xor;
xor_dev->dmachan.device = dma_dev;
list_add_tail(&xor_dev->dmachan.device_node,
&dma_dev->channels);
mv_xor_v2_enable_imsg_thrd(xor_dev);
mv_xor_v2_descq_init(xor_dev);
ret = dma_async_device_register(dma_dev);
if (ret)
goto free_hw_desq;
dev_notice(&pdev->dev, "Marvell Version 2 XOR driver\n");
return 0;
free_hw_desq:
dma_free_coherent(&pdev->dev,
xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
xor_dev->hw_desq_virt, xor_dev->hw_desq);
free_msi_irqs:
platform_msi_domain_free_irqs(&pdev->dev);
disable_clk:
clk_disable_unprepare(xor_dev->clk);
disable_reg_clk:
clk_disable_unprepare(xor_dev->reg_clk);
return ret;
}