Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Tegra host1x Channel
0004  *
0005  * Copyright (c) 2010-2013, NVIDIA Corporation.
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 
0011 #include "channel.h"
0012 #include "dev.h"
0013 #include "job.h"
0014 
0015 /* Constructor for the host1x device list */
0016 int host1x_channel_list_init(struct host1x_channel_list *chlist,
0017                  unsigned int num_channels)
0018 {
0019     chlist->channels = kcalloc(num_channels, sizeof(struct host1x_channel),
0020                    GFP_KERNEL);
0021     if (!chlist->channels)
0022         return -ENOMEM;
0023 
0024     chlist->allocated_channels = bitmap_zalloc(num_channels, GFP_KERNEL);
0025     if (!chlist->allocated_channels) {
0026         kfree(chlist->channels);
0027         return -ENOMEM;
0028     }
0029 
0030     return 0;
0031 }
0032 
0033 void host1x_channel_list_free(struct host1x_channel_list *chlist)
0034 {
0035     bitmap_free(chlist->allocated_channels);
0036     kfree(chlist->channels);
0037 }
0038 
0039 int host1x_job_submit(struct host1x_job *job)
0040 {
0041     struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
0042 
0043     return host1x_hw_channel_submit(host, job);
0044 }
0045 EXPORT_SYMBOL(host1x_job_submit);
0046 
0047 struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)
0048 {
0049     kref_get(&channel->refcount);
0050 
0051     return channel;
0052 }
0053 EXPORT_SYMBOL(host1x_channel_get);
0054 
0055 /**
0056  * host1x_channel_get_index() - Attempt to get channel reference by index
0057  * @host: Host1x device object
0058  * @index: Index of channel
0059  *
0060  * If channel number @index is currently allocated, increase its refcount
0061  * and return a pointer to it. Otherwise, return NULL.
0062  */
0063 struct host1x_channel *host1x_channel_get_index(struct host1x *host,
0064                         unsigned int index)
0065 {
0066     struct host1x_channel *ch = &host->channel_list.channels[index];
0067 
0068     if (!kref_get_unless_zero(&ch->refcount))
0069         return NULL;
0070 
0071     return ch;
0072 }
0073 
0074 void host1x_channel_stop(struct host1x_channel *channel)
0075 {
0076     struct host1x *host = dev_get_drvdata(channel->dev->parent);
0077 
0078     host1x_hw_cdma_stop(host, &channel->cdma);
0079 }
0080 EXPORT_SYMBOL(host1x_channel_stop);
0081 
0082 static void release_channel(struct kref *kref)
0083 {
0084     struct host1x_channel *channel =
0085         container_of(kref, struct host1x_channel, refcount);
0086     struct host1x *host = dev_get_drvdata(channel->dev->parent);
0087     struct host1x_channel_list *chlist = &host->channel_list;
0088 
0089     host1x_hw_cdma_stop(host, &channel->cdma);
0090     host1x_cdma_deinit(&channel->cdma);
0091 
0092     clear_bit(channel->id, chlist->allocated_channels);
0093 }
0094 
0095 void host1x_channel_put(struct host1x_channel *channel)
0096 {
0097     kref_put(&channel->refcount, release_channel);
0098 }
0099 EXPORT_SYMBOL(host1x_channel_put);
0100 
0101 static struct host1x_channel *acquire_unused_channel(struct host1x *host)
0102 {
0103     struct host1x_channel_list *chlist = &host->channel_list;
0104     unsigned int max_channels = host->info->nb_channels;
0105     unsigned int index;
0106 
0107     index = find_first_zero_bit(chlist->allocated_channels, max_channels);
0108     if (index >= max_channels) {
0109         dev_err(host->dev, "failed to find free channel\n");
0110         return NULL;
0111     }
0112 
0113     chlist->channels[index].id = index;
0114 
0115     set_bit(index, chlist->allocated_channels);
0116 
0117     return &chlist->channels[index];
0118 }
0119 
0120 /**
0121  * host1x_channel_request() - Allocate a channel
0122  * @client: Host1x client this channel will be used to send commands to
0123  *
0124  * Allocates a new host1x channel for @client. May return NULL if CDMA
0125  * initialization fails.
0126  */
0127 struct host1x_channel *host1x_channel_request(struct host1x_client *client)
0128 {
0129     struct host1x *host = dev_get_drvdata(client->dev->parent);
0130     struct host1x_channel_list *chlist = &host->channel_list;
0131     struct host1x_channel *channel;
0132     int err;
0133 
0134     channel = acquire_unused_channel(host);
0135     if (!channel)
0136         return NULL;
0137 
0138     kref_init(&channel->refcount);
0139     mutex_init(&channel->submitlock);
0140     channel->client = client;
0141     channel->dev = client->dev;
0142 
0143     err = host1x_hw_channel_init(host, channel, channel->id);
0144     if (err < 0)
0145         goto fail;
0146 
0147     err = host1x_cdma_init(&channel->cdma);
0148     if (err < 0)
0149         goto fail;
0150 
0151     return channel;
0152 
0153 fail:
0154     clear_bit(channel->id, chlist->allocated_channels);
0155 
0156     dev_err(client->dev, "failed to initialize channel\n");
0157 
0158     return NULL;
0159 }
0160 EXPORT_SYMBOL(host1x_channel_request);