aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2008-07-08 14:58:21 -0400
committerDan Williams <dan.j.williams@intel.com>2008-07-08 14:58:21 -0400
commit7cc5bf9a3a84e5a02e23e5739fb894790b37c101 (patch)
treeb526b348ed1b64884bf672924540bb5dc29cb211
parent9c402f4e196290692d998b188f9094deb1619e57 (diff)
dmaengine: track the number of clients using a channel
Haavard's dma-slave interface would like to test for exclusive access to a channel. The standard channel refcounting is not sufficient in that it tracks more than just client references, it is also inaccurate as reference counts are percpu until the channel is removed. This change also enables a future fix to deallocate resources when a client declines to use a capable channel. Acked-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/dma/dmaengine.c14
-rw-r--r--include/linux/dmaengine.h2
2 files changed, 12 insertions, 4 deletions
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 99c22b42bada..10de69eb1a3e 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -183,9 +183,10 @@ static void dma_client_chan_alloc(struct dma_client *client)
183 /* we are done once this client rejects 183 /* we are done once this client rejects
184 * an available resource 184 * an available resource
185 */ 185 */
186 if (ack == DMA_ACK) 186 if (ack == DMA_ACK) {
187 dma_chan_get(chan); 187 dma_chan_get(chan);
188 else if (ack == DMA_NAK) 188 chan->client_count++;
189 } else if (ack == DMA_NAK)
189 return; 190 return;
190 } 191 }
191 } 192 }
@@ -272,8 +273,10 @@ static void dma_clients_notify_removed(struct dma_chan *chan)
272 /* client was holding resources for this channel so 273 /* client was holding resources for this channel so
273 * free it 274 * free it
274 */ 275 */
275 if (ack == DMA_ACK) 276 if (ack == DMA_ACK) {
276 dma_chan_put(chan); 277 dma_chan_put(chan);
278 chan->client_count--;
279 }
277 } 280 }
278 281
279 mutex_unlock(&dma_list_mutex); 282 mutex_unlock(&dma_list_mutex);
@@ -313,8 +316,10 @@ void dma_async_client_unregister(struct dma_client *client)
313 ack = client->event_callback(client, chan, 316 ack = client->event_callback(client, chan,
314 DMA_RESOURCE_REMOVED); 317 DMA_RESOURCE_REMOVED);
315 318
316 if (ack == DMA_ACK) 319 if (ack == DMA_ACK) {
317 dma_chan_put(chan); 320 dma_chan_put(chan);
321 chan->client_count--;
322 }
318 } 323 }
319 324
320 list_del(&client->global_node); 325 list_del(&client->global_node);
@@ -394,6 +399,7 @@ int dma_async_device_register(struct dma_device *device)
394 kref_get(&device->refcount); 399 kref_get(&device->refcount);
395 kref_get(&device->refcount); 400 kref_get(&device->refcount);
396 kref_init(&chan->refcount); 401 kref_init(&chan->refcount);
402 chan->client_count = 0;
397 chan->slow_ref = 0; 403 chan->slow_ref = 0;
398 INIT_RCU_HEAD(&chan->rcu); 404 INIT_RCU_HEAD(&chan->rcu);
399 } 405 }
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index d08a5c5eb928..6432b8343220 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -139,6 +139,7 @@ struct dma_chan_percpu {
139 * @rcu: the DMA channel's RCU head 139 * @rcu: the DMA channel's RCU head
140 * @device_node: used to add this to the device chan list 140 * @device_node: used to add this to the device chan list
141 * @local: per-cpu pointer to a struct dma_chan_percpu 141 * @local: per-cpu pointer to a struct dma_chan_percpu
142 * @client-count: how many clients are using this channel
142 */ 143 */
143struct dma_chan { 144struct dma_chan {
144 struct dma_device *device; 145 struct dma_device *device;
@@ -154,6 +155,7 @@ struct dma_chan {
154 155
155 struct list_head device_node; 156 struct list_head device_node;
156 struct dma_chan_percpu *local; 157 struct dma_chan_percpu *local;
158 int client_count;
157}; 159};
158 160
159#define to_dma_chan(p) container_of(p, struct dma_chan, dev) 161#define to_dma_chan(p) container_of(p, struct dma_chan, dev)