1
/*
2
 * Copyright (C) 2009-2010 Felipe Contreras
3
 * Copyright (C) 2009-2010 Nokia Corporation
4
 * Copyright (C) 2009 Igalia S.L
5
 *
6
 * Author: Felipe Contreras <felipe.contreras@nokia.com>
7
 *
8
 * This file may be used under the terms of the GNU Lesser General Public
9
 * License version 2.1, a copy of which is found in LICENSE included in the
10
 * packaging of this file.
11
 */
12
13
#include <stdlib.h>
14
#include <string.h>
15
#include <stdbool.h>
16
#include <signal.h>
17
#include <stdio.h>
18
19
#include "dmm_buffer.h"
20
#include "dsp_bridge.h"
21
#include "log.h"
22
23
static unsigned long input_buffer_size = 0x1000;
24
static unsigned long output_buffer_size = 0x1000;
25
static bool done;
26
static int ntimes;
27
static bool do_fault;
28
static bool do_ping;
29
static bool do_write;
30
static bool do_corruption;
31
static unsigned long corruption_point;
32
33
static int dsp_handle;
34
static void *proc;
35
struct dsp_notification *events[3];
36
37
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
38
39
static void
40
signal_handler(int signal)
41
{
42
	done = true;
43
}
44
45
static inline struct dsp_node *
46
create_node(void)
47
{
48
	struct dsp_node *node;
49
	const struct dsp_uuid test_uuid = { 0x3dac26d0, 0x6d4b, 0x11dd, 0xad, 0x8b,
50
		{ 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } };
51
52
	if (!dsp_register(dsp_handle, &test_uuid, DSP_DCD_LIBRARYTYPE, "/lib/dsp/test.dll64P"))
53
		return false;
54
55
	if (!dsp_register(dsp_handle, &test_uuid, DSP_DCD_NODETYPE, "/lib/dsp/test.dll64P"))
56
		return false;
57
58
	if (!dsp_node_allocate(dsp_handle, proc, &test_uuid, NULL, NULL, &node)) {
59
		pr_err("dsp node allocate failed");
60
		return NULL;
61
	}
62
63
	if (!dsp_node_create(dsp_handle, node)) {
64
		pr_err("dsp node create failed");
65
		return NULL;
66
	}
67
68
	pr_info("dsp node created");
69
70
	return node;
71
}
72
73
static inline bool
74
destroy_node(struct dsp_node *node)
75
{
76
	if (node) {
77
		if (!dsp_node_free(dsp_handle, node)) {
78
			pr_err("dsp node free failed");
79
			return false;
80
		}
81
82
		pr_info("dsp node deleted");
83
	}
84
85
	return true;
86
}
87
88
static inline void
89
configure_dsp_node(void *node,
90
		dmm_buffer_t *input_buffer,
91
		dmm_buffer_t *output_buffer)
92
{
93
	struct dsp_msg msg;
94
95
	msg.cmd = 0;
96
	msg.arg_1 = (uint32_t) input_buffer->map;
97
	msg.arg_2 = (uint32_t) output_buffer->map;
98
	if (do_fault)
99
		msg.arg_2 = 0x12345678;
100
	if (do_corruption)
101
		msg.arg_2 = corruption_point;
102
	dsp_node_put_message(dsp_handle, node, &msg, -1);
103
}
104
105
static bool register_msgs(struct dsp_node *node)
106
{
107
	events[0] = calloc(1, sizeof(struct dsp_notification));
108
	if (!dsp_node_register_notify(dsp_handle, node,
109
				DSP_NODEMESSAGEREADY, 1,
110
				events[0]))
111
		return false;
112
113
	events[1] = calloc(1, sizeof(struct dsp_notification));
114
	if (!dsp_register_notify(dsp_handle, proc,
115
				DSP_MMUFAULT, 1,
116
				events[1]))
117
		return false;
118
119
	events[2] = calloc(1, sizeof(struct dsp_notification));
120
	if (!dsp_register_notify(dsp_handle, proc,
121
				DSP_SYSERROR, 1,
122
				events[2]))
123
		return false;
124
125
	return true;
126
}
127
128
static bool check_events(struct dsp_node *node, struct dsp_msg *msg)
129
{
130
	unsigned int index = 0;
131
	pr_debug("waiting for events");
132
	if (!dsp_wait_for_events(dsp_handle, events, 3, &index, 1000)) {
133
		pr_warning("failed waiting for events");
134
		return false;
135
	}
136
137
	switch (index) {
138
	case 0:
139
		dsp_node_get_message(dsp_handle, node, msg, 100);
140
		pr_debug("got dsp message: 0x%0x 0x%0x 0x%0x",
141
				msg->cmd, msg->arg_1, msg->arg_2);
142
		return true;
143
	case 1:
144
		pr_err("got DSP MMUFAULT");
145
		return false;
146
	case 2:
147
		pr_err("got DSP SYSERROR");
148
		return false;
149
	default:
150
		pr_err("wrong event index");
151
		return false;
152
	}
153
}
154
155
static void run_dmm(struct dsp_node *node, unsigned long times)
156
{
157
	dmm_buffer_t *input_buffer;
158
	dmm_buffer_t *output_buffer;
159
	unsigned long total_times;
160
161
	input_buffer = dmm_buffer_new(dsp_handle, proc, DMA_TO_DEVICE);
162
	output_buffer = dmm_buffer_new(dsp_handle, proc, DMA_FROM_DEVICE);
163
164
	dmm_buffer_allocate(input_buffer, input_buffer_size);
165
	dmm_buffer_allocate(output_buffer, output_buffer_size);
166
167
	if (do_corruption) {
168
		char *ptr = input_buffer->data;
169
		for (unsigned i = 0; i < input_buffer->size; i++)
170
			ptr[i] = 0x6b;
171
	}
172
173
	dmm_buffer_map(output_buffer);
174
	dmm_buffer_map(input_buffer);
175
176
	configure_dsp_node(node, input_buffer, output_buffer);
177
178
	total_times = times;
179
	pr_info("running %lu times", times);
180
181
	while (!done) {
182
		struct dsp_msg msg;
183
184
		if (do_write) {
185
			static unsigned char foo = 1;
186
			unsigned int i;
187
			for (i = 0; i < input_buffer->size; i++)
188
				((char *) input_buffer->data)[i] = foo;
189
			foo++;
190
		}
191
192
		dmm_buffer_begin(input_buffer, input_buffer->size);
193
		dmm_buffer_begin(output_buffer, output_buffer->size);
194
		msg.cmd = 1;
195
		msg.arg_1 = input_buffer->size;
196
		dsp_node_put_message(dsp_handle, node, &msg, -1);
197
		if (!check_events(node, &msg)) {
198
			done = true;
199
			break;
200
		}
201
202
		dmm_buffer_end(input_buffer, input_buffer->size);
203
		dmm_buffer_end(output_buffer, output_buffer->size);
204
205
		if (--times == 0)
206
			break;
207
	}
208
209
	dmm_buffer_unmap(output_buffer);
210
	dmm_buffer_unmap(input_buffer);
211
212
	dmm_buffer_free(output_buffer);
213
	dmm_buffer_free(input_buffer);
214
215
	printf("copied %lu times successfully\n", total_times);
216
}
217
218
static void run_ping(struct dsp_node *node, unsigned long times)
219
{
220
	while (!done) {
221
		struct dsp_msg msg;
222
223
		if (!dsp_send_message(dsp_handle, node, 2, 0, 0)) {
224
			pr_err("dsp node put message failed");
225
			continue;
226
		}
227
228
		if (!check_events(node, &msg)) {
229
			done = true;
230
			break;
231
		}
232
233
		printf("ping: id=%d, msg=%d, mem=%d\n",
234
				msg.cmd, msg.arg_1, msg.arg_2);
235
236
		if (--times == 0)
237
			break;
238
	}
239
}
240
241
static bool run_task(struct dsp_node *node, unsigned long times)
242
{
243
	unsigned long exit_status;
244
245
	register_msgs(node);
246
247
	if (!dsp_node_run(dsp_handle, node)) {
248
		pr_err("dsp node run failed");
249
		return false;
250
	}
251
252
	pr_info("dsp node running");
253
254
	if (do_ping)
255
		run_ping(node, times);
256
	else
257
		run_dmm(node, times);
258
259
	if (!dsp_node_terminate(dsp_handle, node, &exit_status)) {
260
		pr_err("dsp node terminate failed: %lx", exit_status);
261
		return false;
262
	}
263
264
	pr_info("dsp node terminated");
265
266
	return true;
267
}
268
269
static void handle_options(int *argc, const char ***argv)
270
{
271
	while (*argc > 0) {
272
		const char *cmd = (*argv)[0];
273
		if (cmd[0] != '-')
274
			break;
275
276
#ifdef DEBUG
277
		if (!strcmp(cmd, "-d") || !strcmp(cmd, "--debug"))
278
			debug_level = 4;
279
#endif
280
281
		if (!strcmp(cmd, "-n") || !strcmp(cmd, "--ntimes")) {
282
			if (*argc < 2) {
283
				pr_err("bad option");
284
				exit(-1);
285
			}
286
			ntimes = atoi((*argv)[1]);
287
			(*argv)++;
288
			(*argc)--;
289
		}
290
291
		if (!strcmp(cmd, "-s") || !strcmp(cmd, "--size")) {
292
			if (*argc < 2) {
293
				pr_err("bad option");
294
				exit(-1);
295
			}
296
			input_buffer_size = output_buffer_size = strtol((*argv)[1], NULL, 16);
297
			(*argv)++;
298
			(*argc)--;
299
		}
300
301
		if (!strcmp(cmd, "-c") || !strcmp(cmd, "--corrupt")) {
302
			if (*argc < 2) {
303
				pr_err("bad option");
304
				exit(-1);
305
			}
306
			do_corruption = 1;
307
			corruption_point = strtoll((*argv)[1], NULL, 16);
308
			(*argv)++;
309
			(*argc)--;
310
		}
311
312
		if (!strcmp(cmd, "-f") || !strcmp(cmd, "--fault"))
313
			do_fault = 1;
314
315
		if (!strcmp(cmd, "-p") || !strcmp(cmd, "--ping"))
316
			do_ping = 1;
317
318
		if (!strcmp(cmd, "-w") || !strcmp(cmd, "--write"))
319
			do_write = 1;
320
321
		(*argv)++;
322
		(*argc)--;
323
	}
324
}
325
326
int main(int argc, const char **argv)
327
{
328
	struct dsp_node *node;
329
	int ret = 0;
330
	unsigned i;
331
332
	signal(SIGINT, signal_handler);
333
334
#ifdef DEBUG
335
	debug_level = 3;
336
#endif
337
	ntimes = 1000;
338
339
	argc--; argv++;
340
	handle_options(&argc, &argv);
341
342
	dsp_handle = dsp_open();
343
344
	if (dsp_handle < 0) {
345
		pr_err("dsp open failed");
346
		return -1;
347
	}
348
349
	if (!dsp_attach(dsp_handle, 0, NULL, &proc)) {
350
		pr_err("dsp attach failed");
351
		ret = -1;
352
		goto leave;
353
	}
354
355
	node = create_node();
356
	if (!node) {
357
		pr_err("dsp node creation failed");
358
		ret = -1;
359
		goto leave;
360
	}
361
362
	run_task(node, ntimes);
363
	destroy_node(node);
364
365
leave:
366
	if (proc) {
367
		if (!dsp_detach(dsp_handle, proc)) {
368
			pr_err("dsp detach failed");
369
			ret = -1;
370
		}
371
		proc = NULL;
372
	}
373
374
	for (i = 0; i < ARRAY_SIZE(events); i++)
375
		free(events[i]);
376
377
	if (dsp_handle > 0) {
378
		if (dsp_close(dsp_handle) < 0) {
379
			pr_err("dsp close failed");
380
			return -1;
381
		}
382
	}
383
384
	return ret;
385
}