dma_linux_seq.c 7.12 KB
Newer Older
Swann Perarnau's avatar
Swann Perarnau committed
1
2
3
4
5
6
7
8
9
10
/*******************************************************************************
 * Copyright 2019 UChicago Argonne, LLC.
 * (c.f. AUTHORS, LICENSE)
 *
 * This file is part of the AML project.
 * For more info, see https://xgitlab.cels.anl.gov/argo/aml
 *
 * SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/

11
#include "aml.h"
12
#include "aml/dma/linux-seq.h"
13
#include "aml/layout/dense.h"
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <assert.h>
#include <errno.h>
#include <sys/mman.h>

/*******************************************************************************
 * Linux-backed, sequential dma
 * The dma itself is organized into several different components
 * - request types: copy or move
 * - implementation of the request
 * - user API (i.e. generic request creation and call)
 * - how to init the dma
 ******************************************************************************/

/*******************************************************************************
 * Requests:
 ******************************************************************************/

32
33
int aml_dma_request_linux_seq_copy_init(struct aml_dma_request_linux_seq *req,
					struct aml_layout *dest,
34
					struct aml_layout *src,
35
36
					aml_dma_operator op,
					void *op_arg)
37
{
38
	assert(req != NULL);
39
	req->type = AML_DMA_REQUEST_TYPE_LAYOUT;
40
41
	aml_layout_duplicate(dest, &req->dest);
	aml_layout_duplicate(src, &req->src);
42
	req->op = op;
43
	req->op_arg = op_arg;
44
45
46
	return 0;
}

47
int aml_dma_request_linux_seq_copy_destroy(struct aml_dma_request_linux_seq *r)
48
{
49
	assert(r != NULL);
50
51
	aml_layout_destroy(&r->src);
	aml_layout_destroy(&r->dest);
52
	return 0;
53
54
55
56
57
}

/*******************************************************************************
 * Internal functions
 ******************************************************************************/
58

59
int aml_dma_linux_seq_do_copy(struct aml_dma_linux_seq_data *dma,
60
			      struct aml_dma_request_linux_seq *req)
61
62
63
{
	assert(dma != NULL);
	assert(req != NULL);
64
	assert(req->op != NULL);
65
	return req->op(req->dest, req->src, req->op_arg);
66
67
}

68
struct aml_dma_linux_seq_inner_ops aml_dma_linux_seq_inner_ops = {
69
	aml_dma_linux_seq_do_copy,
70
71
72
73
74
75
76
};

/*******************************************************************************
 * Public API
 ******************************************************************************/

int aml_dma_linux_seq_create_request(struct aml_dma_data *d,
77
				     struct aml_dma_request **r,
78
				     struct aml_layout *dest,
79
				     struct aml_layout *src,
80
				     aml_dma_operator op, void *op_arg)
81
{
82
	/* NULL checks done by the generic API */
83
84
	assert(d != NULL);
	assert(r != NULL);
85
86
	assert(dest != NULL);
	assert(src != NULL);
87
88
	struct aml_dma_linux_seq *dma =
		(struct aml_dma_linux_seq *)d;
89
	struct aml_dma_request_linux_seq *req;
90

91
92
	if (op == NULL)
		op = dma->data.default_op;
93
94
	if (op_arg == NULL)
		op_arg = dma->data.default_op_arg;
95

96
	pthread_mutex_lock(&dma->data.lock);
97
	req = aml_vector_add(dma->data.requests);
98
	aml_dma_request_linux_seq_copy_init(req, dest, src, op, op_arg);
99
	pthread_mutex_unlock(&dma->data.lock);
100
101
	*r = (struct aml_dma_request *)req;
	return 0;
102
103
104
}

int aml_dma_linux_seq_destroy_request(struct aml_dma_data *d,
Swann Perarnau's avatar
Swann Perarnau committed
105
				      struct aml_dma_request **r)
106
{
107
	assert(d != NULL); assert(r != NULL);
108
109
	struct aml_dma_linux_seq *dma =
		(struct aml_dma_linux_seq *)d;
Swann Perarnau's avatar
Swann Perarnau committed
110
	struct aml_dma_request_linux_seq *req;
111

Swann Perarnau's avatar
Swann Perarnau committed
112
113
114
115
	if (*r == NULL)
		return -AML_EINVAL;
	req = (struct aml_dma_request_linux_seq *)*r;

116
	aml_dma_request_linux_seq_copy_destroy(req);
117
118
	pthread_mutex_lock(&dma->data.lock);
	aml_vector_remove(dma->data.requests, req);
119
	pthread_mutex_unlock(&dma->data.lock);
Swann Perarnau's avatar
Swann Perarnau committed
120
	*r = NULL;
121
122
123
124
	return 0;
}

int aml_dma_linux_seq_wait_request(struct aml_dma_data *d,
Swann Perarnau's avatar
Swann Perarnau committed
125
				   struct aml_dma_request **r)
126
127
128
{
	assert(d != NULL);
	assert(r != NULL);
129
	struct aml_dma_linux_seq *dma = (struct aml_dma_linux_seq *)d;
Swann Perarnau's avatar
Swann Perarnau committed
130
	struct aml_dma_request_linux_seq *req;
131

Swann Perarnau's avatar
Swann Perarnau committed
132
133
134
135
	if (*r == NULL)
		return -AML_EINVAL;
	req = (struct aml_dma_request_linux_seq *)*r;

136
	/* execute */
137
138
	if (req->type != AML_DMA_REQUEST_TYPE_INVALID)
		dma->ops.do_copy(&dma->data, req);
139
140
141
142
143
144

	/* destroy a completed request */
	aml_dma_linux_seq_destroy_request(d, r);
	return 0;
}

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
int aml_dma_linux_seq_fprintf(const struct aml_dma_data *data,
			      FILE *stream, const char *prefix)
{
	const struct aml_dma_linux_seq *d;
	size_t vsize;

	fprintf(stream, "%s: dma-linux-seq: %p:\n", prefix, (void *)data);
	if (data == NULL)
		return AML_SUCCESS;

	d = (const struct aml_dma_linux_seq *)data;

	vsize = aml_vector_size(d->data.requests);
	/* ugly cast because ISO C forbids function pointer to void * */
	fprintf(stream, "%s: op: %p\n", prefix,
		(void *) (intptr_t) d->data.default_op);
	fprintf(stream, "%s: op-arg: %p\n", prefix, d->data.default_op_arg);
	fprintf(stream, "%s: requests: %zu\n", prefix, vsize);
	for (size_t i = 0; i < vsize; i++) {
		const struct aml_dma_request_linux_seq *r;

		r = aml_vector_get(d->data.requests, i);
		fprintf(stream, "%s: type: %d\n", prefix, r->type);
		if (r->type == AML_DMA_REQUEST_TYPE_INVALID)
			continue;

		fprintf(stream, "%s: layout-dest: %p\n", prefix,
			(void *)r->dest);
		aml_layout_fprintf(stream, prefix, r->dest);
		fprintf(stream, "%s: layout-src: %p\n", prefix, (void *)r->src);
		aml_layout_fprintf(stream, prefix, r->src);
		fprintf(stream, "%s: op: %p\n", prefix,
			(void *) (intptr_t)r->op);
		fprintf(stream, "%s: op-arg: %p\n", prefix, (void *)r->op_arg);
	}
	return AML_SUCCESS;
}

183
184
185
186
struct aml_dma_ops aml_dma_linux_seq_ops = {
	aml_dma_linux_seq_create_request,
	aml_dma_linux_seq_destroy_request,
	aml_dma_linux_seq_wait_request,
187
	aml_dma_linux_seq_fprintf,
188
189
190
191
192
193
};

/*******************************************************************************
 * Init functions:
 ******************************************************************************/

194
int aml_dma_linux_seq_create(struct aml_dma **dma, size_t nbreqs,
195
			     aml_dma_operator op, void *op_arg)
196
197
{
	struct aml_dma *ret = NULL;
198
	struct aml_dma_linux_seq *d;
199

200
	if (dma == NULL)
201
		return -AML_EINVAL;
202

203
204
	*dma = NULL;

Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
205
	ret = AML_INNER_MALLOC(struct aml_dma, struct aml_dma_linux_seq);
206
	if (ret == NULL)
207
		return -AML_ENOMEM;
208

Nicolas Denoyelle's avatar
Nicolas Denoyelle committed
209
210
211
	ret->data = AML_INNER_MALLOC_GET_FIELD(ret, 2,
					       struct aml_dma,
					       struct aml_dma_linux_seq);
212
213
	ret->ops = &aml_dma_linux_seq_ops;
	d = (struct aml_dma_linux_seq *)ret->data;
214

215
	d->ops = aml_dma_linux_seq_inner_ops;
216

217
	if (op == NULL) {
218
		op = aml_copy_layout_generic;
219
220
		op_arg = NULL;
	}
221
	d->data.default_op = op;
222
	d->data.default_op_arg = op_arg;
223

224
	aml_vector_create(&d->data.requests, nbreqs,
225
226
			  sizeof(struct aml_dma_request_linux_seq),
			  offsetof(struct aml_dma_request_linux_seq, type),
227
228
			  AML_DMA_REQUEST_TYPE_INVALID);
	pthread_mutex_init(&d->data.lock, NULL);
229

230
	*dma = ret;
231
232
233
	return 0;
}

234
void aml_dma_linux_seq_destroy(struct aml_dma **d)
235
{
236
	struct aml_dma_linux_seq *dma;
237

238
	if (d == NULL || *d == NULL)
239
		return;
240

241
242
243
244
245
246
247
248
249
250
251
	dma = (struct aml_dma_linux_seq *)(*d)->data;
	for (size_t i = 0; i < aml_vector_size(dma->data.requests); i++) {
		struct aml_dma_request_linux_seq *req;

		req = aml_vector_get(dma->data.requests, i);
		aml_dma_request_linux_seq_copy_destroy(req);
	}
	aml_vector_destroy(&dma->data.requests);
	pthread_mutex_destroy(&dma->data.lock);
	free(*d);
	*d = NULL;
252
}