blob: a776542c8050db060b367f7c06bb1cba7ac242d9 [file] [log] [blame]
Neela Chithirala49087422022-02-14 03:48:34 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * GXP client structure.
4 *
5 * Copyright (C) 2021 Google LLC
6 */
7
Aurora pro automergerfa5cf572022-04-22 17:10:21 +08008#include <linux/list.h>
Neela Chithirala49087422022-02-14 03:48:34 +00009#include <linux/slab.h>
10#include <linux/types.h>
11
Aurora pro automerger0ffef442023-02-17 09:18:51 +000012#include <gcip/gcip-pm.h>
13
Neela Chithirala49087422022-02-14 03:48:34 +000014#include "gxp-client.h"
15#include "gxp-dma.h"
16#include "gxp-internal.h"
17#include "gxp-pm.h"
18#include "gxp-vd.h"
Aurora pro automerger0ffef442023-02-17 09:18:51 +000019#include "gxp.h"
Neela Chithirala49087422022-02-14 03:48:34 +000020
21struct gxp_client *gxp_client_create(struct gxp_dev *gxp)
22{
23 struct gxp_client *client;
24
Aurora pro automerger27bed782022-04-28 17:59:17 +080025 client = kzalloc(sizeof(*client), GFP_KERNEL);
Neela Chithirala49087422022-02-14 03:48:34 +000026 if (!client)
27 return ERR_PTR(-ENOMEM);
28
29 client->gxp = gxp;
Aurora pro automerger51c89d92023-02-02 11:46:21 +000030 lockdep_register_key(&client->key);
31 __init_rwsem(&client->semaphore, "&client->semaphore", &client->key);
Neela Chithirala49087422022-02-14 03:48:34 +000032 client->has_block_wakelock = false;
Aurora pro automerger27bed782022-04-28 17:59:17 +080033 client->has_vd_wakelock = false;
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000034 client->requested_states = off_states;
Neela Chithirala49087422022-02-14 03:48:34 +000035 client->vd = NULL;
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000036
Neela Chithirala49087422022-02-14 03:48:34 +000037 return client;
38}
39
40void gxp_client_destroy(struct gxp_client *client)
41{
42 struct gxp_dev *gxp = client->gxp;
Neela Chithiralaa739c7f2022-03-21 04:33:21 +000043 int core;
Neela Chithirala49087422022-02-14 03:48:34 +000044
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000045 if (client->vd && client->vd->state != GXP_VD_OFF) {
Aurora pro automerger0ffef442023-02-17 09:18:51 +000046 down_write(&gxp->vd_semaphore);
Neela Chithirala49087422022-02-14 03:48:34 +000047 gxp_vd_stop(client->vd);
Aurora pro automerger0ffef442023-02-17 09:18:51 +000048 up_write(&gxp->vd_semaphore);
49 }
50
51 if (client->vd && client->has_block_wakelock) {
52 down_write(&gxp->vd_semaphore);
53 gxp_vd_block_unready(client->vd);
54 up_write(&gxp->vd_semaphore);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000055 }
Neela Chithirala49087422022-02-14 03:48:34 +000056
Neela Chithiralaa739c7f2022-03-21 04:33:21 +000057 for (core = 0; core < GXP_NUM_CORES; core++) {
58 if (client->mb_eventfds[core])
Aurora pro automerger27bed782022-04-28 17:59:17 +080059 gxp_eventfd_put(client->mb_eventfds[core]);
Neela Chithiralaa739c7f2022-03-21 04:33:21 +000060 }
61
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000062#if (IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_ANDROID)) && \
63 !IS_ENABLED(CONFIG_GXP_GEM5)
Aurora pro automerger261baf52022-08-09 03:58:01 +000064 if (client->tpu_file) {
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000065 if (client->vd) {
66 if (gxp->before_unmap_tpu_mbx_queue)
67 gxp->before_unmap_tpu_mbx_queue(gxp, client);
Aurora pro automergerec2e64f2023-03-14 02:07:34 +000068 if (gxp_is_direct_mode(gxp))
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000069 gxp_dma_unmap_tpu_buffer(gxp,
70 client->vd->domain,
71 client->mbx_desc);
72 }
Aurora pro automerger261baf52022-08-09 03:58:01 +000073 fput(client->tpu_file);
74 client->tpu_file = NULL;
Aurora pro automerger261baf52022-08-09 03:58:01 +000075 }
76#endif
77
Neela Chithirala8f54b932022-03-14 05:24:14 +000078 if (client->has_block_wakelock) {
Aurora pro automerger0ffef442023-02-17 09:18:51 +000079 gcip_pm_put(client->gxp->power_mgr->pm);
Aurora pro automerger35e34032022-05-14 14:55:22 -070080 gxp_pm_update_requested_power_states(
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000081 gxp, client->requested_states, off_states);
Neela Chithirala8f54b932022-03-14 05:24:14 +000082 }
Neela Chithirala49087422022-02-14 03:48:34 +000083
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000084 if (client->vd) {
85 down_write(&gxp->vd_semaphore);
Aurora pro automerger27bed782022-04-28 17:59:17 +080086 gxp_vd_release(client->vd);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000087 up_write(&gxp->vd_semaphore);
88 }
Neela Chithirala49087422022-02-14 03:48:34 +000089
Aurora pro automerger51c89d92023-02-02 11:46:21 +000090 lockdep_unregister_key(&client->key);
Neela Chithirala49087422022-02-14 03:48:34 +000091 kfree(client);
92}
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +000093
94static int gxp_set_secure_vd(struct gxp_virtual_device *vd)
95{
96 struct gxp_dev *gxp = vd->gxp;
97
98 if (gxp_is_direct_mode(gxp))
99 return 0;
100
101 mutex_lock(&gxp->secure_vd_lock);
102 if (gxp->secure_vd) {
103 mutex_unlock(&gxp->secure_vd_lock);
104 return -EEXIST;
105 }
106 vd->is_secure = true;
107 gxp->secure_vd = vd;
108 mutex_unlock(&gxp->secure_vd_lock);
109
110 return 0;
111}
112
113int gxp_client_allocate_virtual_device(struct gxp_client *client,
114 uint core_count, u8 flags)
115{
116 struct gxp_dev *gxp = client->gxp;
117 struct gxp_virtual_device *vd;
118 int ret;
119
120 lockdep_assert_held(&client->semaphore);
121 if (client->vd) {
122 dev_err(gxp->dev,
123 "Virtual device was already allocated for client\n");
124 return -EINVAL;
125 }
126
127 down_write(&gxp->vd_semaphore);
128 vd = gxp_vd_allocate(gxp, core_count);
129 if (IS_ERR(vd)) {
130 ret = PTR_ERR(vd);
131 dev_err(gxp->dev,
132 "Failed to allocate virtual device for client (%d)\n",
133 ret);
134 goto error;
135 }
136 if (flags & GXP_ALLOCATE_VD_SECURE) {
137 ret = gxp_set_secure_vd(vd);
138 if (ret)
139 goto error_vd_release;
140 }
141 if (client->has_block_wakelock) {
142 ret = gxp_vd_block_ready(vd);
143 if (ret)
144 goto error_vd_release;
145 }
146 up_write(&gxp->vd_semaphore);
147
148 client->vd = vd;
149 return 0;
150
151error_vd_release:
152 gxp_vd_release(vd);
153error:
154 up_write(&gxp->vd_semaphore);
155 return ret;
156}
157
158static int gxp_client_request_power_states(struct gxp_client *client,
159 struct gxp_power_states requested_states)
160{
161 struct gxp_dev *gxp = client->gxp;
162 int ret;
163
164 if (gxp->request_power_states) {
165 ret = gxp->request_power_states(client, requested_states);
166 if (ret != -EOPNOTSUPP)
167 return ret;
168 }
169 gxp_pm_update_requested_power_states(gxp, client->requested_states,
170 requested_states);
171 client->requested_states = requested_states;
172 return 0;
173}
174
175int gxp_client_acquire_block_wakelock(struct gxp_client *client,
176 bool *acquired_wakelock)
177{
178 struct gxp_dev *gxp = client->gxp;
179 int ret;
180
181 lockdep_assert_held(&client->semaphore);
182 if (!client->has_block_wakelock) {
Aurora pro automerger0ffef442023-02-17 09:18:51 +0000183 ret = gcip_pm_get(gxp->power_mgr->pm);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +0000184 if (ret)
185 return ret;
186 *acquired_wakelock = true;
187 if (client->vd) {
Aurora pro automerger51c89d92023-02-02 11:46:21 +0000188 down_write(&gxp->vd_semaphore);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +0000189 ret = gxp_vd_block_ready(client->vd);
Aurora pro automerger51c89d92023-02-02 11:46:21 +0000190 up_write(&gxp->vd_semaphore);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +0000191 if (ret)
192 goto err_wakelock_release;
193 }
194 } else {
195 *acquired_wakelock = false;
196 }
197 client->has_block_wakelock = true;
198
199 /*
200 * Update client's TGID+PID in case the process that opened
201 * /dev/gxp is not the one that called this IOCTL.
202 */
203 client->tgid = current->tgid;
204 client->pid = current->pid;
205
206 return 0;
207
208err_wakelock_release:
209 if (*acquired_wakelock) {
Aurora pro automerger0ffef442023-02-17 09:18:51 +0000210 gcip_pm_put(gxp->power_mgr->pm);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +0000211 *acquired_wakelock = false;
212 }
213 return ret;
214}
215
216void gxp_client_release_block_wakelock(struct gxp_client *client)
217{
218 struct gxp_dev *gxp = client->gxp;
219
220 lockdep_assert_held(&client->semaphore);
221 if (!client->has_block_wakelock)
222 return;
223
Aurora pro automerger0ffef442023-02-17 09:18:51 +0000224 gxp_client_release_vd_wakelock(client);
225
226 if (client->vd) {
227 down_write(&gxp->vd_semaphore);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +0000228 gxp_vd_block_unready(client->vd);
Aurora pro automerger0ffef442023-02-17 09:18:51 +0000229 up_write(&gxp->vd_semaphore);
230 }
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +0000231
Aurora pro automerger0ffef442023-02-17 09:18:51 +0000232 gcip_pm_put(gxp->power_mgr->pm);
Aurora pro automerger8a4b0d92023-01-06 06:59:41 +0000233 client->has_block_wakelock = false;
234}
235
236int gxp_client_acquire_vd_wakelock(struct gxp_client *client,
237 struct gxp_power_states requested_states)
238{
239 struct gxp_dev *gxp = client->gxp;
240 int ret = 0;
241 enum gxp_virtual_device_state orig_state;
242
243 lockdep_assert_held(&client->semaphore);
244 if (!client->has_block_wakelock) {
245 dev_err(gxp->dev,
246 "Must hold BLOCK wakelock to acquire VIRTUAL_DEVICE wakelock\n");
247 return -EINVAL;
248 }
249
250 if (client->vd->state == GXP_VD_UNAVAILABLE) {
251 dev_err(gxp->dev,
252 "Cannot acquire VIRTUAL_DEVICE wakelock on a broken virtual device\n");
253 return -ENODEV;
254 }
255
256 if (!client->has_vd_wakelock) {
257 down_write(&gxp->vd_semaphore);
258 orig_state = client->vd->state;
259 if (client->vd->state == GXP_VD_READY || client->vd->state == GXP_VD_OFF)
260 ret = gxp_vd_run(client->vd);
261 else
262 ret = gxp_vd_resume(client->vd);
263 up_write(&gxp->vd_semaphore);
264 }
265
266 if (ret)
267 goto out;
268
269 ret = gxp_client_request_power_states(client, requested_states);
270 if (ret)
271 goto out_release_vd_wakelock;
272
273 client->has_vd_wakelock = true;
274 return 0;
275
276out_release_vd_wakelock:
277 if (!client->has_vd_wakelock) {
278 down_write(&gxp->vd_semaphore);
279 if (orig_state == GXP_VD_READY || orig_state == GXP_VD_OFF)
280 gxp_vd_stop(client->vd);
281 else
282 gxp_vd_suspend(client->vd);
283 up_write(&gxp->vd_semaphore);
284 }
285out:
286 return ret;
287}
288
289void gxp_client_release_vd_wakelock(struct gxp_client *client)
290{
291 struct gxp_dev *gxp = client->gxp;
292
293 lockdep_assert_held(&client->semaphore);
294 if (!client->has_vd_wakelock)
295 return;
296
297 /*
298 * Currently VD state will not be GXP_VD_UNAVAILABLE if
299 * has_vd_wakelock is true. Add this check just in case
300 * GXP_VD_UNAVAILABLE will occur in more scenarios in the
301 * future.
302 */
303 if (client->vd->state == GXP_VD_UNAVAILABLE)
304 return;
305
306 down_write(&gxp->vd_semaphore);
307 gxp_vd_suspend(client->vd);
308 up_write(&gxp->vd_semaphore);
309
310 gxp_client_request_power_states(client, off_states);
311 client->has_vd_wakelock = false;
312}
313
314bool gxp_client_has_available_vd(struct gxp_client *client, const char *name)
315{
316 struct gxp_dev *gxp = client->gxp;
317
318 lockdep_assert_held(&client->semaphore);
319 if (!client->vd) {
320 dev_err(gxp->dev,
321 "%s requires the client allocate a VIRTUAL_DEVICE\n",
322 name);
323 return false;
324 }
325 if (client->vd->state == GXP_VD_UNAVAILABLE) {
326 dev_err(gxp->dev, "Cannot do %s on a broken virtual device\n",
327 name);
328 return false;
329 }
330 return true;
331}