brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 08077af Raw
187 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Tegra host1x Channel4 *5 * Copyright (c) 2010-2013, NVIDIA Corporation.6 */7 8#include <linux/slab.h>9#include <linux/module.h>10 11#include "channel.h"12#include "dev.h"13#include "job.h"14 15/* Constructor for the host1x device list */16int host1x_channel_list_init(struct host1x_channel_list *chlist,17			     unsigned int num_channels)18{19	chlist->channels = kcalloc(num_channels, sizeof(struct host1x_channel),20				   GFP_KERNEL);21	if (!chlist->channels)22		return -ENOMEM;23 24	chlist->allocated_channels = bitmap_zalloc(num_channels, GFP_KERNEL);25	if (!chlist->allocated_channels) {26		kfree(chlist->channels);27		return -ENOMEM;28	}29 30	mutex_init(&chlist->lock);31 32	return 0;33}34 35void host1x_channel_list_free(struct host1x_channel_list *chlist)36{37	bitmap_free(chlist->allocated_channels);38	kfree(chlist->channels);39}40 41int host1x_job_submit(struct host1x_job *job)42{43	struct host1x *host = dev_get_drvdata(job->channel->dev->parent);44 45	return host1x_hw_channel_submit(host, job);46}47EXPORT_SYMBOL(host1x_job_submit);48 49struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)50{51	kref_get(&channel->refcount);52 53	return channel;54}55EXPORT_SYMBOL(host1x_channel_get);56 57/**58 * host1x_channel_get_index() - Attempt to get channel reference by index59 * @host: Host1x device object60 * @index: Index of channel61 *62 * If channel number @index is currently allocated, increase its refcount63 * and return a pointer to it. Otherwise, return NULL.64 */65struct host1x_channel *host1x_channel_get_index(struct host1x *host,66						unsigned int index)67{68	struct host1x_channel *ch = &host->channel_list.channels[index];69 70	if (!kref_get_unless_zero(&ch->refcount))71		return NULL;72 73	return ch;74}75 76void host1x_channel_stop(struct host1x_channel *channel)77{78	struct host1x *host = dev_get_drvdata(channel->dev->parent);79 80	host1x_hw_cdma_stop(host, &channel->cdma);81}82EXPORT_SYMBOL(host1x_channel_stop);83 84/**85 * host1x_channel_stop_all() - disable CDMA on allocated channels86 * @host: host1x instance87 *88 * Stop CDMA on allocated channels89 */90void host1x_channel_stop_all(struct host1x *host)91{92	struct host1x_channel_list *chlist = &host->channel_list;93	int bit;94 95	mutex_lock(&chlist->lock);96 97	for_each_set_bit(bit, chlist->allocated_channels, host->info->nb_channels)98		host1x_channel_stop(&chlist->channels[bit]);99 100	mutex_unlock(&chlist->lock);101}102 103static void release_channel(struct kref *kref)104{105	struct host1x_channel *channel =106		container_of(kref, struct host1x_channel, refcount);107	struct host1x *host = dev_get_drvdata(channel->dev->parent);108	struct host1x_channel_list *chlist = &host->channel_list;109 110	host1x_hw_cdma_stop(host, &channel->cdma);111	host1x_cdma_deinit(&channel->cdma);112 113	clear_bit(channel->id, chlist->allocated_channels);114}115 116void host1x_channel_put(struct host1x_channel *channel)117{118	kref_put(&channel->refcount, release_channel);119}120EXPORT_SYMBOL(host1x_channel_put);121 122static struct host1x_channel *acquire_unused_channel(struct host1x *host)123{124	struct host1x_channel_list *chlist = &host->channel_list;125	unsigned int max_channels = host->info->nb_channels;126	unsigned int index;127 128	mutex_lock(&chlist->lock);129 130	index = find_first_zero_bit(chlist->allocated_channels, max_channels);131	if (index >= max_channels) {132		mutex_unlock(&chlist->lock);133		dev_err(host->dev, "failed to find free channel\n");134		return NULL;135	}136 137	chlist->channels[index].id = index;138 139	set_bit(index, chlist->allocated_channels);140 141	mutex_unlock(&chlist->lock);142 143	return &chlist->channels[index];144}145 146/**147 * host1x_channel_request() - Allocate a channel148 * @client: Host1x client this channel will be used to send commands to149 *150 * Allocates a new host1x channel for @client. May return NULL if CDMA151 * initialization fails.152 */153struct host1x_channel *host1x_channel_request(struct host1x_client *client)154{155	struct host1x *host = dev_get_drvdata(client->dev->parent);156	struct host1x_channel_list *chlist = &host->channel_list;157	struct host1x_channel *channel;158	int err;159 160	channel = acquire_unused_channel(host);161	if (!channel)162		return NULL;163 164	kref_init(&channel->refcount);165	mutex_init(&channel->submitlock);166	channel->client = client;167	channel->dev = client->dev;168 169	err = host1x_hw_channel_init(host, channel, channel->id);170	if (err < 0)171		goto fail;172 173	err = host1x_cdma_init(&channel->cdma);174	if (err < 0)175		goto fail;176 177	return channel;178 179fail:180	clear_bit(channel->id, chlist->allocated_channels);181 182	dev_err(client->dev, "failed to initialize channel\n");183 184	return NULL;185}186EXPORT_SYMBOL(host1x_channel_request);187