linux/drivers/gpu/host1x/channel.c
<<
>>
Prefs
   1/*
   2 * Tegra host1x Channel
   3 *
   4 * Copyright (c) 2010-2013, NVIDIA Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include <linux/slab.h>
  20#include <linux/module.h>
  21
  22#include "channel.h"
  23#include "dev.h"
  24#include "job.h"
  25
  26/* Constructor for the host1x device list */
  27int host1x_channel_list_init(struct host1x *host)
  28{
  29        INIT_LIST_HEAD(&host->chlist.list);
  30        mutex_init(&host->chlist_mutex);
  31
  32        if (host->info->nb_channels > BITS_PER_LONG) {
  33                WARN(1, "host1x hardware has more channels than supported by the driver\n");
  34                return -ENOSYS;
  35        }
  36
  37        return 0;
  38}
  39
  40int host1x_job_submit(struct host1x_job *job)
  41{
  42        struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
  43
  44        return host1x_hw_channel_submit(host, job);
  45}
  46EXPORT_SYMBOL(host1x_job_submit);
  47
  48struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)
  49{
  50        int err = 0;
  51
  52        mutex_lock(&channel->reflock);
  53
  54        if (channel->refcount == 0)
  55                err = host1x_cdma_init(&channel->cdma);
  56
  57        if (!err)
  58                channel->refcount++;
  59
  60        mutex_unlock(&channel->reflock);
  61
  62        return err ? NULL : channel;
  63}
  64EXPORT_SYMBOL(host1x_channel_get);
  65
  66void host1x_channel_put(struct host1x_channel *channel)
  67{
  68        mutex_lock(&channel->reflock);
  69
  70        if (channel->refcount == 1) {
  71                struct host1x *host = dev_get_drvdata(channel->dev->parent);
  72
  73                host1x_hw_cdma_stop(host, &channel->cdma);
  74                host1x_cdma_deinit(&channel->cdma);
  75        }
  76
  77        channel->refcount--;
  78
  79        mutex_unlock(&channel->reflock);
  80}
  81EXPORT_SYMBOL(host1x_channel_put);
  82
  83struct host1x_channel *host1x_channel_request(struct device *dev)
  84{
  85        struct host1x *host = dev_get_drvdata(dev->parent);
  86        unsigned int max_channels = host->info->nb_channels;
  87        struct host1x_channel *channel = NULL;
  88        unsigned long index;
  89        int err;
  90
  91        mutex_lock(&host->chlist_mutex);
  92
  93        index = find_first_zero_bit(&host->allocated_channels, max_channels);
  94        if (index >= max_channels)
  95                goto fail;
  96
  97        channel = kzalloc(sizeof(*channel), GFP_KERNEL);
  98        if (!channel)
  99                goto fail;
 100
 101        err = host1x_hw_channel_init(host, channel, index);
 102        if (err < 0)
 103                goto fail;
 104
 105        /* Link device to host1x_channel */
 106        channel->dev = dev;
 107
 108        /* Add to channel list */
 109        list_add_tail(&channel->list, &host->chlist.list);
 110
 111        host->allocated_channels |= BIT(index);
 112
 113        mutex_unlock(&host->chlist_mutex);
 114        return channel;
 115
 116fail:
 117        dev_err(dev, "failed to init channel\n");
 118        kfree(channel);
 119        mutex_unlock(&host->chlist_mutex);
 120        return NULL;
 121}
 122EXPORT_SYMBOL(host1x_channel_request);
 123
 124void host1x_channel_free(struct host1x_channel *channel)
 125{
 126        struct host1x *host = dev_get_drvdata(channel->dev->parent);
 127
 128        host->allocated_channels &= ~BIT(channel->id);
 129        list_del(&channel->list);
 130        kfree(channel);
 131}
 132EXPORT_SYMBOL(host1x_channel_free);
 133