]>
Commit | Line | Data |
---|---|---|
6579324a TB |
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 */ | |
27 | int 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 | ||
40 | int 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 | } | |
fae798a1 | 46 | EXPORT_SYMBOL(host1x_job_submit); |
6579324a TB |
47 | |
48 | struct 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 | } | |
fae798a1 | 64 | EXPORT_SYMBOL(host1x_channel_get); |
6579324a TB |
65 | |
66 | void 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 | } | |
fae798a1 | 81 | EXPORT_SYMBOL(host1x_channel_put); |
6579324a TB |
82 | |
83 | struct host1x_channel *host1x_channel_request(struct device *dev) | |
84 | { | |
85 | struct host1x *host = dev_get_drvdata(dev->parent); | |
14c95fc8 | 86 | unsigned int max_channels = host->info->nb_channels; |
6579324a | 87 | struct host1x_channel *channel = NULL; |
e18e33af TR |
88 | unsigned long index; |
89 | int err; | |
6579324a TB |
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 | ||
116 | fail: | |
117 | dev_err(dev, "failed to init channel\n"); | |
118 | kfree(channel); | |
119 | mutex_unlock(&host->chlist_mutex); | |
120 | return NULL; | |
121 | } | |
fae798a1 | 122 | EXPORT_SYMBOL(host1x_channel_request); |
6579324a TB |
123 | |
124 | void 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 | } | |
fae798a1 | 132 | EXPORT_SYMBOL(host1x_channel_free); |