diff options
-rw-r--r-- | drivers/dma/ti-dma-crossbar.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index fccf65f89075..7b1e3ea874bf 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/list.h> #include <linux/io.h> -#include <linux/idr.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_dma.h> @@ -198,7 +197,8 @@ struct ti_dra7_xbar_data { void __iomem *iomem; struct dma_router dmarouter; - struct idr map_idr; + struct mutex mutex; + unsigned long *dma_inuse; u16 safe_val; /* Value to rest the crossbar lines */ u32 xbar_requests; /* number of DMA requests connected to XBAR */ @@ -225,7 +225,9 @@ static void ti_dra7_xbar_free(struct device *dev, void *route_data) map->xbar_in, map->xbar_out); ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val); - idr_remove(&xbar->map_idr, map->xbar_out); + mutex_lock(&xbar->mutex); + clear_bit(map->xbar_out, xbar->dma_inuse); + mutex_unlock(&xbar->mutex); kfree(map); } @@ -255,8 +257,17 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, return ERR_PTR(-ENOMEM); } - map->xbar_out = idr_alloc(&xbar->map_idr, NULL, 0, xbar->dma_requests, - GFP_KERNEL); + mutex_lock(&xbar->mutex); + map->xbar_out = find_first_zero_bit(xbar->dma_inuse, + xbar->dma_requests); + mutex_unlock(&xbar->mutex); + if (map->xbar_out == xbar->dma_requests) { + dev_err(&pdev->dev, "Run out of free DMA requests\n"); + kfree(map); + return ERR_PTR(-ENOMEM); + } + set_bit(map->xbar_out, xbar->dma_inuse); + map->xbar_in = (u16)dma_spec->args[0]; dma_spec->args[0] = map->xbar_out + xbar->dma_offset; @@ -303,8 +314,6 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev) if (!xbar) return -ENOMEM; - idr_init(&xbar->map_idr); - dma_node = of_parse_phandle(node, "dma-masters", 0); if (!dma_node) { dev_err(&pdev->dev, "Can't get DMA master node\n"); @@ -326,6 +335,12 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev) } of_node_put(dma_node); + xbar->dma_inuse = devm_kcalloc(&pdev->dev, + BITS_TO_LONGS(xbar->dma_requests), + sizeof(unsigned long), GFP_KERNEL); + if (!xbar->dma_inuse) + return -ENOMEM; + if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) { dev_info(&pdev->dev, "Missing XBAR input information, using %u.\n", @@ -347,6 +362,7 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev) xbar->dmarouter.route_free = ti_dra7_xbar_free; xbar->dma_offset = (u32)match->data; + mutex_init(&xbar->mutex); platform_set_drvdata(pdev, xbar); /* Reset the crossbar */ |