dma_linux_seq.c 5.92 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 13
#include "aml/dma/linux-seq.h"

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#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:
 ******************************************************************************/

31
int aml_dma_request_linux_seq_copy_init(struct aml_dma_request_linux_seq *req,
Kamil Iskra's avatar
Kamil Iskra committed
32
					const struct aml_tiling *dt,
33
					void *dptr, int dtid,
Kamil Iskra's avatar
Kamil Iskra committed
34 35
					const struct aml_tiling *st,
					const void *sptr, int stid)
36
{
37
	assert(req != NULL);
38

39
	req->type = AML_DMA_REQUEST_TYPE_COPY;
40
	/* figure out pointers */
41 42 43
	req->dest = aml_tiling_tilestart(dt, dptr, dtid);
	req->src = aml_tiling_tilestart(st, sptr, stid);
	req->size = aml_tiling_tilesize(st, stid);
44 45 46 47
	/* TODO: assert size match */
	return 0;
}

48
int aml_dma_request_linux_seq_copy_destroy(struct aml_dma_request_linux_seq *r)
49 50 51 52 53 54 55 56
{
	assert(r != NULL);
	return 0;
}

/*******************************************************************************
 * Internal functions
 ******************************************************************************/
57 58 59 60 61 62 63 64 65
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;
}

66
struct aml_dma_linux_seq_ops aml_dma_linux_seq_inner_ops = {
67
	aml_dma_linux_seq_do_copy,
68 69 70 71 72 73 74
};

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

int aml_dma_linux_seq_create_request(struct aml_dma_data *d,
75
				     struct aml_dma_request **r,
76 77 78 79 80 81 82
				     int type, va_list ap)
{
	assert(d != NULL);
	assert(r != NULL);
	struct aml_dma_linux_seq *dma =
		(struct aml_dma_linux_seq *)d;

83
	struct aml_dma_request_linux_seq *req;
84

85
	pthread_mutex_lock(&dma->data.lock);
86
	req = aml_vector_add(&dma->data.requests);
87

88
	/* init the request */
89
	if (type == AML_DMA_REQUEST_TYPE_COPY) {
90 91 92
		struct aml_tiling *dt, *st;
		void *dptr, *sptr;
		int dtid, stid;
93

94 95 96 97 98 99
		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);
100
		aml_dma_request_linux_seq_copy_init(req, dt, dptr, dtid,
101 102
						    st, sptr, stid);
	}
103
	pthread_mutex_unlock(&dma->data.lock);
104
	*r = (struct aml_dma_request *)req;
105 106 107 108 109 110 111 112 113 114 115
	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;

116 117
	struct aml_dma_request_linux_seq *req =
		(struct aml_dma_request_linux_seq *)r;
118

119
	if (req->type == AML_DMA_REQUEST_TYPE_COPY)
120
		aml_dma_request_linux_seq_copy_destroy(req);
121

122
	/* enough to remove from request vector */
123
	pthread_mutex_lock(&dma->data.lock);
124
	aml_vector_remove(&dma->data.requests, req);
125
	pthread_mutex_unlock(&dma->data.lock);
126 127 128 129 130 131 132 133
	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);
134 135 136
	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;
137 138

	/* execute */
139
	if (req->type == AML_DMA_REQUEST_TYPE_COPY)
140
		dma->ops.do_copy(&dma->data, req);
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

	/* 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:
 ******************************************************************************/

157
int aml_dma_linux_seq_create(struct aml_dma **d, size_t nbreqs)
158 159 160
{
	struct aml_dma *ret = NULL;
	intptr_t baseptr, dataptr;
161 162 163 164
	int err;

	if (d == NULL)
		return -AML_EINVAL;
165 166 167

	/* alloc */
	baseptr = (intptr_t) calloc(1, AML_DMA_LINUX_SEQ_ALLOCSIZE);
168 169 170 171
	if (baseptr == 0) {
		*d = NULL;
		return -AML_ENOMEM;
	}
172 173 174 175
	dataptr = baseptr + sizeof(struct aml_dma);

	ret = (struct aml_dma *)baseptr;
	ret->data = (struct aml_dma_data *)dataptr;
176
	ret->ops = &aml_dma_linux_seq_ops;
177

178 179 180 181 182 183
	err = aml_dma_linux_seq_init(ret, nbreqs);
	if (err) {
		*d = NULL;
		free(ret);
		return err;
	}
184 185 186 187

	*d = ret;
	return 0;
}
188 189

int aml_dma_linux_seq_init(struct aml_dma *d, size_t nbreqs)
190
{
191
	struct aml_dma_linux_seq *dma;
192

193 194 195
	if (d == NULL || d->data == NULL)
		return -AML_EINVAL;
	dma = (struct aml_dma_linux_seq *)d->data;
196
	dma->ops = aml_dma_linux_seq_inner_ops;
197 198 199 200 201 202

	/* request vector */
	aml_vector_init(&dma->data.requests, nbreqs,
			sizeof(struct aml_dma_request_linux_seq),
			offsetof(struct aml_dma_request_linux_seq, type),
			AML_DMA_REQUEST_TYPE_INVALID);
203
	pthread_mutex_init(&dma->data.lock, NULL);
204 205 206
	return 0;
}

207
void aml_dma_linux_seq_fini(struct aml_dma *d)
208
{
209 210
	if (d == NULL || d->data == NULL)
		return;
211
	struct aml_dma_linux_seq *dma = (struct aml_dma_linux_seq *)d->data;
212

213
	aml_vector_fini(&dma->data.requests);
214
	pthread_mutex_destroy(&dma->data.lock);
215 216 217 218 219 220 221 222 223
}

void aml_dma_linux_seq_destroy(struct aml_dma **d)
{
	if (d == NULL)
		return;
	aml_dma_linux_seq_fini(*d);
	free(*d);
	*d = NULL;
224
}