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}
  46
  47struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)
  48{
  49        int err = 0;
  50
  51        mutex_lock(&channel->reflock);
  52
  53        if (channel->refcount == 0)
  54                err = host1x_cdma_init(&channel->cdma);
  55
  56        if (!err)
  57                channel->refcount++;
  58
  59        mutex_unlock(&channel->reflock);
  60
  61        return err ? NULL : channel;
  62}
  63
  64void host1x_channel_put(struct host1x_channel *channel)
  65{
  66        mutex_lock(&channel->reflock);
  67
  68        if (channel->refcount == 1) {
  69                struct host1x *host = dev_get_drvdata(channel->dev->parent);
  70
  71                host1x_hw_cdma_stop(host, &channel->cdma);
  72                host1x_cdma_deinit(&channel->cdma);
  73        }
  74
  75        channel->refcount--;
  76
  77        mutex_unlock(&channel->reflock);
  78}
  79
  80struct host1x_channel *host1x_channel_request(struct device *dev)
  81{
  82        struct host1x *host = dev_get_drvdata(dev->parent);
  83        int max_channels = host->info->nb_channels;
  84        struct host1x_channel *channel = NULL;
  85        int index, err;
  86
  87        mutex_lock(&host->chlist_mutex);
  88
  89        index = find_first_zero_bit(&host->allocated_channels, max_channels);
  90        if (index >= max_channels)
  91                goto fail;
  92
  93        channel = kzalloc(sizeof(*channel), GFP_KERNEL);
  94        if (!channel)
  95                goto fail;
  96
  97        err = host1x_hw_channel_init(host, channel, index);
  98        if (err < 0)
  99                goto fail;
 100
 101        /* Link device to host1x_channel */
 102        channel->dev = dev;
 103
 104        /* Add to channel list */
 105        list_add_tail(&channel->list, &host->chlist.list);
 106
 107        host->allocated_channels |= BIT(index);
 108
 109        mutex_unlock(&host->chlist_mutex);
 110        return channel;
 111
 112fail:
 113        dev_err(dev, "failed to init channel\n");
 114        kfree(channel);
 115        mutex_unlock(&host->chlist_mutex);
 116        return NULL;
 117}
 118
 119void host1x_channel_free(struct host1x_channel *channel)
 120{
 121        struct host1x *host = dev_get_drvdata(channel->dev->parent);
 122
 123        host->allocated_channels &= ~BIT(channel->id);
 124        list_del(&channel->list);
 125        kfree(channel);
 126}
 127