cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

channel.c (4051B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Tegra host1x Channel
      4 *
      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 =
     25		kcalloc(BITS_TO_LONGS(num_channels), sizeof(unsigned long),
     26			GFP_KERNEL);
     27	if (!chlist->allocated_channels) {
     28		kfree(chlist->channels);
     29		return -ENOMEM;
     30	}
     31
     32	bitmap_zero(chlist->allocated_channels, num_channels);
     33
     34	return 0;
     35}
     36
     37void host1x_channel_list_free(struct host1x_channel_list *chlist)
     38{
     39	kfree(chlist->allocated_channels);
     40	kfree(chlist->channels);
     41}
     42
     43int host1x_job_submit(struct host1x_job *job)
     44{
     45	struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
     46
     47	return host1x_hw_channel_submit(host, job);
     48}
     49EXPORT_SYMBOL(host1x_job_submit);
     50
     51struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)
     52{
     53	kref_get(&channel->refcount);
     54
     55	return channel;
     56}
     57EXPORT_SYMBOL(host1x_channel_get);
     58
     59/**
     60 * host1x_channel_get_index() - Attempt to get channel reference by index
     61 * @host: Host1x device object
     62 * @index: Index of channel
     63 *
     64 * If channel number @index is currently allocated, increase its refcount
     65 * and return a pointer to it. Otherwise, return NULL.
     66 */
     67struct host1x_channel *host1x_channel_get_index(struct host1x *host,
     68						unsigned int index)
     69{
     70	struct host1x_channel *ch = &host->channel_list.channels[index];
     71
     72	if (!kref_get_unless_zero(&ch->refcount))
     73		return NULL;
     74
     75	return ch;
     76}
     77
     78void host1x_channel_stop(struct host1x_channel *channel)
     79{
     80	struct host1x *host = dev_get_drvdata(channel->dev->parent);
     81
     82	host1x_hw_cdma_stop(host, &channel->cdma);
     83}
     84EXPORT_SYMBOL(host1x_channel_stop);
     85
     86static void release_channel(struct kref *kref)
     87{
     88	struct host1x_channel *channel =
     89		container_of(kref, struct host1x_channel, refcount);
     90	struct host1x *host = dev_get_drvdata(channel->dev->parent);
     91	struct host1x_channel_list *chlist = &host->channel_list;
     92
     93	host1x_hw_cdma_stop(host, &channel->cdma);
     94	host1x_cdma_deinit(&channel->cdma);
     95
     96	clear_bit(channel->id, chlist->allocated_channels);
     97}
     98
     99void host1x_channel_put(struct host1x_channel *channel)
    100{
    101	kref_put(&channel->refcount, release_channel);
    102}
    103EXPORT_SYMBOL(host1x_channel_put);
    104
    105static struct host1x_channel *acquire_unused_channel(struct host1x *host)
    106{
    107	struct host1x_channel_list *chlist = &host->channel_list;
    108	unsigned int max_channels = host->info->nb_channels;
    109	unsigned int index;
    110
    111	index = find_first_zero_bit(chlist->allocated_channels, max_channels);
    112	if (index >= max_channels) {
    113		dev_err(host->dev, "failed to find free channel\n");
    114		return NULL;
    115	}
    116
    117	chlist->channels[index].id = index;
    118
    119	set_bit(index, chlist->allocated_channels);
    120
    121	return &chlist->channels[index];
    122}
    123
    124/**
    125 * host1x_channel_request() - Allocate a channel
    126 * @client: Host1x client this channel will be used to send commands to
    127 *
    128 * Allocates a new host1x channel for @client. May return NULL if CDMA
    129 * initialization fails.
    130 */
    131struct host1x_channel *host1x_channel_request(struct host1x_client *client)
    132{
    133	struct host1x *host = dev_get_drvdata(client->dev->parent);
    134	struct host1x_channel_list *chlist = &host->channel_list;
    135	struct host1x_channel *channel;
    136	int err;
    137
    138	channel = acquire_unused_channel(host);
    139	if (!channel)
    140		return NULL;
    141
    142	kref_init(&channel->refcount);
    143	mutex_init(&channel->submitlock);
    144	channel->client = client;
    145	channel->dev = client->dev;
    146
    147	err = host1x_hw_channel_init(host, channel, channel->id);
    148	if (err < 0)
    149		goto fail;
    150
    151	err = host1x_cdma_init(&channel->cdma);
    152	if (err < 0)
    153		goto fail;
    154
    155	return channel;
    156
    157fail:
    158	clear_bit(channel->id, chlist->allocated_channels);
    159
    160	dev_err(client->dev, "failed to initialize channel\n");
    161
    162	return NULL;
    163}
    164EXPORT_SYMBOL(host1x_channel_request);