/** * dma_chan_get - try to grab a dma channel's parent driver module * @chan - channel to grab * * Must be called under dma_list_mutex */ static int dma_chan_get(struct dma_chan *chan) { int err = -ENODEV; struct module *owner = dma_chan_to_owner(chan); if (chan->client_count) { __module_get(owner); err = 0; } else if (try_module_get(owner)) err = 0; if (err == 0) chan->client_count++; /* allocate upon first client reference */ if (chan->client_count == 1 && err == 0) { int desc_cnt = chan->device->device_alloc_chan_resources(chan); if (desc_cnt < 0) { err = desc_cnt; chan->client_count = 0; module_put(owner); } else if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) balance_ref_count(chan); } return err; }
/** * dma_chan_get - try to grab a dma channel's parent driver module * @chan - channel to grab * * Must be called under dma_list_mutex */ static int dma_chan_get(struct dma_chan *chan) { struct module *owner = dma_chan_to_owner(chan); int ret; /* The channel is already in use, update client count */ if (chan->client_count) { __module_get(owner); goto out; } if (!try_module_get(owner)) return -ENODEV; /* allocate upon first client reference */ if (chan->device->device_alloc_chan_resources) { ret = chan->device->device_alloc_chan_resources(chan); if (ret < 0) goto err_out; } if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) balance_ref_count(chan); out: chan->client_count++; return 0; err_out: module_put(owner); return ret; }
/** * dma_chan_put - drop a reference to a dma channel's parent driver module * @chan - channel to release * * Must be called under dma_list_mutex */ static void dma_chan_put(struct dma_chan *chan) { if (!chan->client_count) return; /* this channel failed alloc_chan_resources */ chan->client_count--; module_put(dma_chan_to_owner(chan)); if (chan->client_count == 0) chan->device->device_free_chan_resources(chan); }
/** * balance_ref_count - catch up the channel reference count * @chan - channel to balance ->client_count versus dmaengine_ref_count * * balance_ref_count must be called under dma_list_mutex */ static void balance_ref_count(struct dma_chan *chan) { struct module *owner = dma_chan_to_owner(chan); while (chan->client_count < dmaengine_ref_count) { __module_get(owner); chan->client_count++; } }
/** * dma_chan_put - drop a reference to a dma channel's parent driver module * @chan - channel to release * * Must be called under dma_list_mutex */ static void dma_chan_put(struct dma_chan *chan) { /* This channel is not in use, bail out */ if (!chan->client_count) return; chan->client_count--; module_put(dma_chan_to_owner(chan)); /* This channel is not in use anymore, free it */ if (!chan->client_count && chan->device->device_free_chan_resources) chan->device->device_free_chan_resources(chan); }
/** * dma_chan_put - drop a reference to a dma channel's parent driver module * @chan - channel to release * * Must be called under dma_list_mutex */ static void dma_chan_put(struct dma_chan *chan) { /* This channel is not in use, bail out */ if (!chan->client_count) return; chan->client_count--; module_put(dma_chan_to_owner(chan)); /* This channel is not in use anymore, free it */ if (!chan->client_count && chan->device->device_free_chan_resources) chan->device->device_free_chan_resources(chan); /* If the channel is used via a DMA request router, free the mapping */ if (chan->router && chan->router->route_free) { chan->router->route_free(chan->router->dev, chan->route_data); chan->router = NULL; chan->route_data = NULL; } }
/** * dma_chan_put - drop a reference to a dma channel's parent driver module * @chan - channel to release * * Must be called under dma_list_mutex */ static void dma_chan_put(struct dma_chan *chan) { /* This channel is not in use, bail out */ if (!chan->client_count) return; chan->client_count--; module_put(dma_chan_to_owner(chan)); /* This channel is not in use anymore, free it */ if (!chan->client_count && chan->device->device_free_chan_resources) { /* Make sure all operations have completed */ dmaengine_synchronize(chan); chan->device->device_free_chan_resources(chan); } /* If the channel is used via a DMA request router, free the mapping */ if (chan->router && chan->router->route_free) { chan->router->route_free(chan->router->dev, chan->route_data); chan->router = NULL; chan->route_data = NULL; } }