diff options
Diffstat (limited to 'arch/arm/mach-davinci/dma.c')
| -rw-r--r-- | arch/arm/mach-davinci/dma.c | 67 | 
1 files changed, 51 insertions, 16 deletions
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 648fbb760ae..15dd886df04 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -226,11 +226,11 @@ struct edma {  	 */  	DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY); -	/* The edma_noevent bit for each channel is clear unless -	 * it doesn't trigger DMA events on this platform.  It uses a -	 * bit of SOC-specific initialization code. +	/* The edma_unused bit for each channel is clear unless +	 * it is not being used on this platform. It uses a bit +	 * of SOC-specific initialization code.  	 */ -	DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH); +	DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH);  	unsigned	irq_res_start;  	unsigned	irq_res_end; @@ -243,6 +243,7 @@ struct edma {  };  static struct edma *edma_info[EDMA_MAX_CC]; +static int arch_num_cc;  /* dummy param set used to (re)initialize parameter RAM slots */  static const struct edmacc_param dummy_paramset = { @@ -555,8 +556,27 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,  	return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1);  } +static int prepare_unused_channel_list(struct device *dev, void *data) +{ +	struct platform_device *pdev = to_platform_device(dev); +	int i, ctlr; + +	for (i = 0; i < pdev->num_resources; i++) { +		if ((pdev->resource[i].flags & IORESOURCE_DMA) && +				(int)pdev->resource[i].start >= 0) { +			ctlr = EDMA_CTLR(pdev->resource[i].start); +			clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start), +					edma_info[ctlr]->edma_unused); +		} +	} + +	return 0; +} +  /*-----------------------------------------------------------------------*/ +static bool unused_chan_list_done; +  /* Resource alloc/free:  dma channels, parameter RAM slots */  /** @@ -594,7 +614,22 @@ int edma_alloc_channel(int channel,  		void *data,  		enum dma_event_q eventq_no)  { -	unsigned i, done, ctlr = 0; +	unsigned i, done = 0, ctlr = 0; +	int ret = 0; + +	if (!unused_chan_list_done) { +		/* +		 * Scan all the platform devices to find out the EDMA channels +		 * used and clear them in the unused list, making the rest +		 * available for ARM usage. +		 */ +		ret = bus_for_each_dev(&platform_bus_type, NULL, NULL, +				prepare_unused_channel_list); +		if (ret < 0) +			return ret; + +		unused_chan_list_done = true; +	}  	if (channel >= 0) {  		ctlr = EDMA_CTLR(channel); @@ -602,15 +637,15 @@ int edma_alloc_channel(int channel,  	}  	if (channel < 0) { -		for (i = 0; i < EDMA_MAX_CC; i++) { +		for (i = 0; i < arch_num_cc; i++) {  			channel = 0;  			for (;;) {  				channel = find_next_bit(edma_info[i]-> -						edma_noevent, +						edma_unused,  						edma_info[i]->num_channels,  						channel);  				if (channel == edma_info[i]->num_channels) -					return -ENOMEM; +					break;  				if (!test_and_set_bit(channel,  						edma_info[i]->edma_inuse)) {  					done = 1; @@ -622,6 +657,8 @@ int edma_alloc_channel(int channel,  			if (done)  				break;  		} +		if (!done) +			return -ENOMEM;  	} else if (channel >= edma_info[ctlr]->num_channels) {  		return -EINVAL;  	} else if (test_and_set_bit(channel, edma_info[ctlr]->edma_inuse)) { @@ -642,7 +679,7 @@ int edma_alloc_channel(int channel,  	map_dmach_queue(ctlr, channel, eventq_no); -	return channel; +	return EDMA_CTLR_CHAN(ctlr, channel);  }  EXPORT_SYMBOL(edma_alloc_channel); @@ -1219,7 +1256,7 @@ int edma_start(unsigned channel)  		unsigned int mask = (1 << (channel & 0x1f));  		/* EDMA channels without event association */ -		if (test_bit(channel, edma_info[ctlr]->edma_noevent)) { +		if (test_bit(channel, edma_info[ctlr]->edma_unused)) {  			pr_debug("EDMA: ESR%d %08x\n", j,  				edma_shadow0_read_array(ctlr, SH_ESR, j));  			edma_shadow0_write_array(ctlr, SH_ESR, j, mask); @@ -1344,7 +1381,6 @@ static int __init edma_probe(struct platform_device *pdev)  	const s8		(*queue_tc_mapping)[2];  	int			i, j, found = 0;  	int			status = -1; -	const s8		*noevent;  	int			irq[EDMA_MAX_CC] = {0, 0};  	int			err_irq[EDMA_MAX_CC] = {0, 0};  	struct resource		*r[EDMA_MAX_CC] = {NULL}; @@ -1407,11 +1443,9 @@ static int __init edma_probe(struct platform_device *pdev)  			memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i),  					&dummy_paramset, PARM_SIZE); -		noevent = info[j].noevent; -		if (noevent) { -			while (*noevent != -1) -				set_bit(*noevent++, edma_info[j]->edma_noevent); -		} +		/* Mark all channels as unused */ +		memset(edma_info[j]->edma_unused, 0xff, +			sizeof(edma_info[j]->edma_unused));  		sprintf(irq_name, "edma%d", j);  		irq[j] = platform_get_irq_byname(pdev, irq_name); @@ -1467,6 +1501,7 @@ static int __init edma_probe(struct platform_device *pdev)  			edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);  			edma_write_array(j, EDMA_QRAE, i, 0x0);  		} +		arch_num_cc++;  	}  	if (tc_errs_handled) {  |