1b8e80941Smrg/*
2b8e80941Smrg * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org>
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21b8e80941Smrg * SOFTWARE.
22b8e80941Smrg *
23b8e80941Smrg * Authors:
24b8e80941Smrg *    Rob Clark <robclark@freedesktop.org>
25b8e80941Smrg */
26b8e80941Smrg
27b8e80941Smrg#include "util/slab.h"
28b8e80941Smrg
29b8e80941Smrg#include "msm_priv.h"
30b8e80941Smrg
31b8e80941Smrgstatic int query_param(struct fd_pipe *pipe, uint32_t param,
32b8e80941Smrg		uint64_t *value)
33b8e80941Smrg{
34b8e80941Smrg	struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
35b8e80941Smrg	struct drm_msm_param req = {
36b8e80941Smrg			.pipe = msm_pipe->pipe,
37b8e80941Smrg			.param = param,
38b8e80941Smrg	};
39b8e80941Smrg	int ret;
40b8e80941Smrg
41b8e80941Smrg	ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_GET_PARAM,
42b8e80941Smrg			&req, sizeof(req));
43b8e80941Smrg	if (ret)
44b8e80941Smrg		return ret;
45b8e80941Smrg
46b8e80941Smrg	*value = req.value;
47b8e80941Smrg
48b8e80941Smrg	return 0;
49b8e80941Smrg}
50b8e80941Smrg
51b8e80941Smrgstatic int query_queue_param(struct fd_pipe *pipe, uint32_t param,
52b8e80941Smrg		uint64_t *value)
53b8e80941Smrg{
54b8e80941Smrg	struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
55b8e80941Smrg	struct drm_msm_submitqueue_query req = {
56b8e80941Smrg			.data = VOID2U64(value),
57b8e80941Smrg			.id = msm_pipe->queue_id,
58b8e80941Smrg			.param = param,
59b8e80941Smrg			.len = sizeof(*value),
60b8e80941Smrg	};
61b8e80941Smrg	int ret;
62b8e80941Smrg
63b8e80941Smrg	ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_QUERY,
64b8e80941Smrg			&req, sizeof(req));
65b8e80941Smrg	if (ret)
66b8e80941Smrg		return ret;
67b8e80941Smrg
68b8e80941Smrg	return 0;
69b8e80941Smrg}
70b8e80941Smrg
71b8e80941Smrgstatic int msm_pipe_get_param(struct fd_pipe *pipe,
72b8e80941Smrg		enum fd_param_id param, uint64_t *value)
73b8e80941Smrg{
74b8e80941Smrg	struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
75b8e80941Smrg	switch(param) {
76b8e80941Smrg	case FD_DEVICE_ID: // XXX probably get rid of this..
77b8e80941Smrg	case FD_GPU_ID:
78b8e80941Smrg		*value = msm_pipe->gpu_id;
79b8e80941Smrg		return 0;
80b8e80941Smrg	case FD_GMEM_SIZE:
81b8e80941Smrg		*value = msm_pipe->gmem;
82b8e80941Smrg		return 0;
83b8e80941Smrg	case FD_GMEM_BASE:
84b8e80941Smrg		*value = msm_pipe->gmem_base;
85b8e80941Smrg		return 0;
86b8e80941Smrg	case FD_CHIP_ID:
87b8e80941Smrg		*value = msm_pipe->chip_id;
88b8e80941Smrg		return 0;
89b8e80941Smrg	case FD_MAX_FREQ:
90b8e80941Smrg		return query_param(pipe, MSM_PARAM_MAX_FREQ, value);
91b8e80941Smrg	case FD_TIMESTAMP:
92b8e80941Smrg		return query_param(pipe, MSM_PARAM_TIMESTAMP, value);
93b8e80941Smrg	case FD_NR_RINGS:
94b8e80941Smrg		return query_param(pipe, MSM_PARAM_NR_RINGS, value);
95b8e80941Smrg	case FD_PP_PGTABLE:
96b8e80941Smrg		return query_param(pipe, MSM_PARAM_PP_PGTABLE, value);
97b8e80941Smrg	case FD_CTX_FAULTS:
98b8e80941Smrg		return query_queue_param(pipe, MSM_SUBMITQUEUE_PARAM_FAULTS, value);
99b8e80941Smrg	case FD_GLOBAL_FAULTS:
100b8e80941Smrg		return query_param(pipe, MSM_PARAM_FAULTS, value);
101b8e80941Smrg	default:
102b8e80941Smrg		ERROR_MSG("invalid param id: %d", param);
103b8e80941Smrg		return -1;
104b8e80941Smrg	}
105b8e80941Smrg}
106b8e80941Smrg
107b8e80941Smrgstatic int msm_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp,
108b8e80941Smrg		uint64_t timeout)
109b8e80941Smrg{
110b8e80941Smrg	struct fd_device *dev = pipe->dev;
111b8e80941Smrg	struct drm_msm_wait_fence req = {
112b8e80941Smrg			.fence = timestamp,
113b8e80941Smrg			.queueid = to_msm_pipe(pipe)->queue_id,
114b8e80941Smrg	};
115b8e80941Smrg	int ret;
116b8e80941Smrg
117b8e80941Smrg	get_abs_timeout(&req.timeout, timeout);
118b8e80941Smrg
119b8e80941Smrg	ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req));
120b8e80941Smrg	if (ret) {
121b8e80941Smrg		ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno));
122b8e80941Smrg		return ret;
123b8e80941Smrg	}
124b8e80941Smrg
125b8e80941Smrg	return 0;
126b8e80941Smrg}
127b8e80941Smrg
128b8e80941Smrgstatic int open_submitqueue(struct fd_pipe *pipe, uint32_t prio)
129b8e80941Smrg{
130b8e80941Smrg	struct drm_msm_submitqueue req = {
131b8e80941Smrg		.flags = 0,
132b8e80941Smrg		.prio = prio,
133b8e80941Smrg	};
134b8e80941Smrg	uint64_t nr_rings = 1;
135b8e80941Smrg	int ret;
136b8e80941Smrg
137b8e80941Smrg	if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) {
138b8e80941Smrg		to_msm_pipe(pipe)->queue_id = 0;
139b8e80941Smrg		return 0;
140b8e80941Smrg	}
141b8e80941Smrg
142b8e80941Smrg	msm_pipe_get_param(pipe, FD_NR_RINGS, &nr_rings);
143b8e80941Smrg
144b8e80941Smrg	req.prio = MIN2(req.prio, MAX2(nr_rings, 1) - 1);
145b8e80941Smrg
146b8e80941Smrg	ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_NEW,
147b8e80941Smrg			&req, sizeof(req));
148b8e80941Smrg	if (ret) {
149b8e80941Smrg		ERROR_MSG("could not create submitqueue! %d (%s)", ret, strerror(errno));
150b8e80941Smrg		return ret;
151b8e80941Smrg	}
152b8e80941Smrg
153b8e80941Smrg	to_msm_pipe(pipe)->queue_id = req.id;
154b8e80941Smrg	return 0;
155b8e80941Smrg}
156b8e80941Smrg
157b8e80941Smrgstatic void close_submitqueue(struct fd_pipe *pipe, uint32_t queue_id)
158b8e80941Smrg{
159b8e80941Smrg	if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES)
160b8e80941Smrg		return;
161b8e80941Smrg
162b8e80941Smrg	drmCommandWrite(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE,
163b8e80941Smrg			&queue_id, sizeof(queue_id));
164b8e80941Smrg}
165b8e80941Smrg
166b8e80941Smrgstatic void msm_pipe_destroy(struct fd_pipe *pipe)
167b8e80941Smrg{
168b8e80941Smrg	struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
169b8e80941Smrg	close_submitqueue(pipe, msm_pipe->queue_id);
170b8e80941Smrg	free(msm_pipe);
171b8e80941Smrg}
172b8e80941Smrg
173b8e80941Smrgstatic const struct fd_pipe_funcs sp_funcs = {
174b8e80941Smrg		.ringbuffer_new_object = msm_ringbuffer_sp_new_object,
175b8e80941Smrg		.submit_new = msm_submit_sp_new,
176b8e80941Smrg		.get_param = msm_pipe_get_param,
177b8e80941Smrg		.wait = msm_pipe_wait,
178b8e80941Smrg		.destroy = msm_pipe_destroy,
179b8e80941Smrg};
180b8e80941Smrg
181b8e80941Smrgstatic const struct fd_pipe_funcs legacy_funcs = {
182b8e80941Smrg		.ringbuffer_new_object = msm_ringbuffer_new_object,
183b8e80941Smrg		.submit_new = msm_submit_new,
184b8e80941Smrg		.get_param = msm_pipe_get_param,
185b8e80941Smrg		.wait = msm_pipe_wait,
186b8e80941Smrg		.destroy = msm_pipe_destroy,
187b8e80941Smrg};
188b8e80941Smrg
189b8e80941Smrgstatic uint64_t get_param(struct fd_pipe *pipe, uint32_t param)
190b8e80941Smrg{
191b8e80941Smrg	uint64_t value;
192b8e80941Smrg	int ret = query_param(pipe, param, &value);
193b8e80941Smrg	if (ret) {
194b8e80941Smrg		ERROR_MSG("get-param failed! %d (%s)", ret, strerror(errno));
195b8e80941Smrg		return 0;
196b8e80941Smrg	}
197b8e80941Smrg	return value;
198b8e80941Smrg}
199b8e80941Smrg
200b8e80941Smrgstruct fd_pipe * msm_pipe_new(struct fd_device *dev,
201b8e80941Smrg		enum fd_pipe_id id, uint32_t prio)
202b8e80941Smrg{
203b8e80941Smrg	static const uint32_t pipe_id[] = {
204b8e80941Smrg			[FD_PIPE_3D] = MSM_PIPE_3D0,
205b8e80941Smrg			[FD_PIPE_2D] = MSM_PIPE_2D0,
206b8e80941Smrg	};
207b8e80941Smrg	struct msm_pipe *msm_pipe = NULL;
208b8e80941Smrg	struct fd_pipe *pipe = NULL;
209b8e80941Smrg
210b8e80941Smrg	msm_pipe = calloc(1, sizeof(*msm_pipe));
211b8e80941Smrg	if (!msm_pipe) {
212b8e80941Smrg		ERROR_MSG("allocation failed");
213b8e80941Smrg		goto fail;
214b8e80941Smrg	}
215b8e80941Smrg
216b8e80941Smrg	pipe = &msm_pipe->base;
217b8e80941Smrg
218b8e80941Smrg	if (fd_device_version(dev) >= FD_VERSION_SOFTPIN) {
219b8e80941Smrg		pipe->funcs = &sp_funcs;
220b8e80941Smrg	} else {
221b8e80941Smrg		pipe->funcs = &legacy_funcs;
222b8e80941Smrg	}
223b8e80941Smrg
224b8e80941Smrg	/* initialize before get_param(): */
225b8e80941Smrg	pipe->dev = dev;
226b8e80941Smrg	msm_pipe->pipe = pipe_id[id];
227b8e80941Smrg
228b8e80941Smrg	/* these params should be supported since the first version of drm/msm: */
229b8e80941Smrg	msm_pipe->gpu_id = get_param(pipe, MSM_PARAM_GPU_ID);
230b8e80941Smrg	msm_pipe->gmem   = get_param(pipe, MSM_PARAM_GMEM_SIZE);
231b8e80941Smrg	msm_pipe->chip_id = get_param(pipe, MSM_PARAM_CHIP_ID);
232b8e80941Smrg
233b8e80941Smrg	if (fd_device_version(pipe->dev) >= FD_VERSION_GMEM_BASE)
234b8e80941Smrg		msm_pipe->gmem_base = get_param(pipe, MSM_PARAM_GMEM_BASE);
235b8e80941Smrg
236b8e80941Smrg	if (! msm_pipe->gpu_id)
237b8e80941Smrg		goto fail;
238b8e80941Smrg
239b8e80941Smrg	INFO_MSG("Pipe Info:");
240b8e80941Smrg	INFO_MSG(" GPU-id:          %d", msm_pipe->gpu_id);
241b8e80941Smrg	INFO_MSG(" Chip-id:         0x%08x", msm_pipe->chip_id);
242b8e80941Smrg	INFO_MSG(" GMEM size:       0x%08x", msm_pipe->gmem);
243b8e80941Smrg
244b8e80941Smrg	if (open_submitqueue(pipe, prio))
245b8e80941Smrg		goto fail;
246b8e80941Smrg
247b8e80941Smrg	return pipe;
248b8e80941Smrgfail:
249b8e80941Smrg	if (pipe)
250b8e80941Smrg		fd_pipe_del(pipe);
251b8e80941Smrg	return NULL;
252b8e80941Smrg}
253