dma_linux_seq.c 7.37 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <aml.h>
#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:
 ******************************************************************************/

19
int aml_dma_request_linux_seq_copy_init(struct aml_dma_request_linux_seq *req,
Kamil Iskra's avatar
Kamil Iskra committed
20
					const struct aml_tiling *dt,
21
					void *dptr, int dtid,
Kamil Iskra's avatar
Kamil Iskra committed
22
23
					const struct aml_tiling *st,
					const void *sptr, int stid)
24
{
25
	assert(req != NULL);
26

27
	req->type = AML_DMA_REQUEST_TYPE_MOVE;
28
	/* figure out pointers */
29
30
31
	req->dest = aml_tiling_tilestart(dt, dptr, dtid);
	req->src = aml_tiling_tilestart(st, sptr, stid);
	req->size = aml_tiling_tilesize(st, stid);
32
33
34
35
	/* TODO: assert size match */
	return 0;
}

36
int aml_dma_request_linux_seq_copy_destroy(struct aml_dma_request_linux_seq *r)
37
38
39
40
41
{
	assert(r != NULL);
	return 0;
}

42
int aml_dma_request_linux_seq_move_init(struct aml_dma_request_linux_seq *req,
43
					struct aml_area *darea,
Kamil Iskra's avatar
Kamil Iskra committed
44
					const struct aml_tiling *tiling,
45
46
					void *startptr, int tileid)
{
47
	assert(req != NULL);
48
49
	struct aml_binding *binding;

50
	req->type = AML_DMA_REQUEST_TYPE_MOVE;
51
	aml_area_binding(darea, &binding);
52
53
54
55
56
	req->count = aml_binding_nbpages(binding, tiling, startptr, tileid);
	req->pages = calloc(req->count, sizeof(void *));
	req->nodes = calloc(req->count, sizeof(int));
	aml_binding_pages(binding, req->pages, tiling, startptr, tileid);
	aml_binding_nodes(binding, req->nodes, tiling, startptr, tileid);
57
58
59
60
	free(binding);
	return 0;
}

61
int aml_dma_request_linux_seq_move_destroy(struct aml_dma_request_linux_seq *req)
62
{
63
64
65
	assert(req != NULL);
	free(req->pages);
	free(req->nodes);
66
67
68
69
70
71
	return 0;
}

/*******************************************************************************
 * Internal functions
 ******************************************************************************/
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
int aml_dma_linux_seq_do_copy(struct aml_dma_linux_seq_data *dma,
			      struct aml_dma_request_linux_seq *req)
{
	assert(dma != NULL);
	assert(req != NULL);
	memcpy(req->dest, req->src, req->size);
	return 0;
}

int aml_dma_linux_seq_do_move(struct aml_dma_linux_seq_data *dma,
			      struct aml_dma_request_linux_seq *req)
{
	assert(dma != NULL);
	assert(req != NULL);
	int status[req->count];
	int err;
	err = move_pages(0, req->count, req->pages, req->nodes, status,
			 MPOL_MF_MOVE);
	if(err)
	{
		perror("move_pages:");
		return errno;
	}
	return 0;
}

98
99

int aml_dma_linux_seq_add_request(struct aml_dma_linux_seq_data *data,
100
				  struct aml_dma_request_linux_seq **req)
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{
	for(int i = 0; i < data->size; i++)
	{
		if(data->requests[i].type == AML_DMA_REQUEST_TYPE_INVALID)
		{
			*req = &data->requests[i];
			return 0;
		}
	}
	/* TODO: slow path, need to resize the array */
	return 0;
}

int aml_dma_linux_seq_remove_request(struct aml_dma_linux_seq_data *data,
115
				     struct aml_dma_request_linux_seq **req)
116
117
118
119
120
121
122
{
	/* TODO: assert that the pointer is in the right place */
	(*req)->type = AML_DMA_REQUEST_TYPE_INVALID;
	return 0;
}

struct aml_dma_linux_seq_ops aml_dma_linux_seq_inner_ops = {
123
124
	aml_dma_linux_seq_do_copy,
	aml_dma_linux_seq_do_move,
125
126
127
128
129
130
131
132
133
	aml_dma_linux_seq_add_request,
	aml_dma_linux_seq_remove_request,
};

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

int aml_dma_linux_seq_create_request(struct aml_dma_data *d,
134
				     struct aml_dma_request **r,
135
136
137
138
139
140
141
				     int type, va_list ap)
{
	assert(d != NULL);
	assert(r != NULL);
	struct aml_dma_linux_seq *dma =
		(struct aml_dma_linux_seq *)d;

142
	struct aml_dma_request_linux_seq *req;
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

	/* find an available request slot */
	dma->ops.add_request(&dma->data, &req);

	/* init the request */
	if(type == AML_DMA_REQUEST_TYPE_COPY)
	{
		struct aml_tiling *dt, *st;
		void *dptr, *sptr;
		int dtid, stid;
		dt = va_arg(ap, struct aml_tiling *);
		dptr = va_arg(ap, void *);
		dtid = va_arg(ap, int);
		st = va_arg(ap, struct aml_tiling *);
		sptr = va_arg(ap, void *);
		stid = va_arg(ap, int);
159
		aml_dma_request_linux_seq_copy_init(req, dt, dptr, dtid,
160
161
162
163
164
165
166
167
						    st, sptr, stid);
	}
	else if(type == AML_DMA_REQUEST_TYPE_MOVE)
	{
		struct aml_area *darea = va_arg(ap, struct aml_area *);
		struct aml_tiling *st = va_arg(ap, struct aml_tiling *);
		void *sptr = va_arg(ap, void *);
		int stid = va_arg(ap, int);
168
		aml_dma_request_linux_seq_move_init(req, darea, st, sptr, stid);
169
	}
170
	*r = (struct aml_dma_request *)req;
171
172
173
174
175
176
177
178
179
180
181
	return 0;
}

int aml_dma_linux_seq_destroy_request(struct aml_dma_data *d,
				      struct aml_dma_request *r)
{
	assert(d != NULL);
	assert(r != NULL);
	struct aml_dma_linux_seq *dma =
		(struct aml_dma_linux_seq *)d;

182
183
	struct aml_dma_request_linux_seq *req =
		(struct aml_dma_request_linux_seq *)r;
184
185

	if(req->type == AML_DMA_REQUEST_TYPE_COPY)
186
		aml_dma_request_linux_seq_copy_destroy(req);
187
	else if(req->type == AML_DMA_REQUEST_TYPE_MOVE)
188
		aml_dma_request_linux_seq_move_destroy(req);
189
190
191
192
193
194
195
196
197
198

	dma->ops.remove_request(&dma->data, &req);
	return 0;
}

int aml_dma_linux_seq_wait_request(struct aml_dma_data *d,
				   struct aml_dma_request *r)
{
	assert(d != NULL);
	assert(r != NULL);
199
200
201
	struct aml_dma_linux_seq *dma = (struct aml_dma_linux_seq *)d;
	struct aml_dma_request_linux_seq *req =
		(struct aml_dma_request_linux_seq *)r;
202
203
204

	/* execute */
	if(req->type == AML_DMA_REQUEST_TYPE_COPY)
205
		dma->ops.do_copy(&dma->data, req);
206
	else if(req->type == AML_DMA_REQUEST_TYPE_MOVE)
207
		dma->ops.do_move(&dma->data, req);
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

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

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,
};

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

int aml_dma_linux_seq_create(struct aml_dma **d, ...)
{
	va_list ap;
	struct aml_dma *ret = NULL;
	intptr_t baseptr, dataptr;
	va_start(ap, d);

	/* alloc */
	baseptr = (intptr_t) calloc(1, AML_DMA_LINUX_SEQ_ALLOCSIZE);
	dataptr = baseptr + sizeof(struct aml_dma);

	ret = (struct aml_dma *)baseptr;
	ret->data = (struct aml_dma_data *)dataptr;

	aml_dma_linux_seq_vinit(ret, ap);

	va_end(ap);
	*d = ret;
	return 0;
}
int aml_dma_linux_seq_vinit(struct aml_dma *d, va_list ap)
{
	d->ops = &aml_dma_linux_seq_ops;
	struct aml_dma_linux_seq *dma = (struct aml_dma_linux_seq *)d->data;

	dma->ops = aml_dma_linux_seq_inner_ops;
	/* allocate request array */
	dma->data.size = va_arg(ap, size_t);
	dma->data.requests = calloc(dma->data.size,
253
				     sizeof(struct aml_dma_request_linux_seq));
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
	for(int i = 0; i < dma->data.size; i++)
		dma->data.requests[i].type = AML_DMA_REQUEST_TYPE_INVALID;
	return 0;
}
int aml_dma_linux_seq_init(struct aml_dma *d, ...)
{
	int err;
	va_list ap;
	va_start(ap, d);
	err = aml_dma_linux_seq_vinit(d, ap);
	va_end(ap);
	return err;
}

int aml_dma_linux_seq_destroy(struct aml_dma *d)
{
	struct aml_dma_linux_seq *dma = (struct aml_dma_linux_seq *)d->data;
	free(dma->data.requests);
	return 0;
}