dma_linux_seq.c 5.38 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 35
					struct aml_layout *src,
					aml_dma_operator op)
36
{
37
	assert(req != NULL);
38
	req->type = AML_DMA_REQUEST_TYPE_LAYOUT;
39 40
	req->dest = dest;
	req->src = src;
41
	req->op = op;
42 43 44
	return 0;
}

45
int aml_dma_request_linux_seq_copy_destroy(struct aml_dma_request_linux_seq *r)
46
{
47 48
	assert(r != NULL);
	return 0;
49 50 51 52 53
}

/*******************************************************************************
 * Internal functions
 ******************************************************************************/
54

55
int aml_dma_linux_seq_do_copy(struct aml_dma_linux_seq_data *dma,
56
			      struct aml_dma_request_linux_seq *req)
57 58 59
{
	assert(dma != NULL);
	assert(req != NULL);
60 61
	assert(req->op != NULL);
	return req->op(req->dest, req->src);
62 63
}

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

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

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

87 88 89
	if (op == NULL)
		op = dma->data.default_op;

90
	pthread_mutex_lock(&dma->data.lock);
91
	req = aml_vector_add(dma->data.requests);
92
	aml_dma_request_linux_seq_copy_init(req, dest, src, op);
93
	pthread_mutex_unlock(&dma->data.lock);
94 95
	*r = (struct aml_dma_request *)req;
	return 0;
96 97 98
}

int aml_dma_linux_seq_destroy_request(struct aml_dma_data *d,
Swann Perarnau's avatar
Swann Perarnau committed
99
				      struct aml_dma_request **r)
100 101 102 103 104
{
	assert(d != NULL);
	assert(r != NULL);
	struct aml_dma_linux_seq *dma =
		(struct aml_dma_linux_seq *)d;
Swann Perarnau's avatar
Swann Perarnau committed
105
	struct aml_dma_request_linux_seq *req;
106

Swann Perarnau's avatar
Swann Perarnau committed
107 108 109 110
	if (*r == NULL)
		return -AML_EINVAL;
	req = (struct aml_dma_request_linux_seq *)*r;

111
	aml_dma_request_linux_seq_copy_destroy(req);
112 113
	pthread_mutex_lock(&dma->data.lock);
	aml_vector_remove(dma->data.requests, req);
114
	pthread_mutex_unlock(&dma->data.lock);
Swann Perarnau's avatar
Swann Perarnau committed
115
	*r = NULL;
116 117 118 119
	return 0;
}

int aml_dma_linux_seq_wait_request(struct aml_dma_data *d,
Swann Perarnau's avatar
Swann Perarnau committed
120
				   struct aml_dma_request **r)
121 122 123
{
	assert(d != NULL);
	assert(r != NULL);
124
	struct aml_dma_linux_seq *dma = (struct aml_dma_linux_seq *)d;
Swann Perarnau's avatar
Swann Perarnau committed
125
	struct aml_dma_request_linux_seq *req;
126

Swann Perarnau's avatar
Swann Perarnau committed
127 128 129 130
	if (*r == NULL)
		return -AML_EINVAL;
	req = (struct aml_dma_request_linux_seq *)*r;

131
	/* execute */
132 133
	if (req->type != AML_DMA_REQUEST_TYPE_INVALID)
		dma->ops.do_copy(&dma->data, req);
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

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

150 151
int aml_dma_linux_seq_create(struct aml_dma **dma, size_t nbreqs,
			     aml_dma_operator op)
152 153
{
	struct aml_dma *ret = NULL;
154
	struct aml_dma_linux_seq *d;
155

156
	if (dma == NULL)
157
		return -AML_EINVAL;
158

159 160
	*dma = NULL;

161
	ret = AML_INNER_MALLOC_2(struct aml_dma, struct aml_dma_linux_seq);
162
	if (ret == NULL)
163
		return -AML_ENOMEM;
164

165 166
	ret->data = AML_INNER_MALLOC_NEXTPTR(ret, struct aml_dma,
					     struct aml_dma_linux_seq);
167 168
	ret->ops = &aml_dma_linux_seq_ops;
	d = (struct aml_dma_linux_seq *)ret->data;
169

170
	d->ops = aml_dma_linux_seq_inner_ops;
171 172 173 174 175

	if (op == NULL)
		op = aml_copy_layout_generic;
	d->data.default_op = op;

176
	aml_vector_create(&d->data.requests, nbreqs,
177 178
			  sizeof(struct aml_dma_request_linux_seq),
			  offsetof(struct aml_dma_request_linux_seq, type),
179 180
			  AML_DMA_REQUEST_TYPE_INVALID);
	pthread_mutex_init(&d->data.lock, NULL);
181

182
	*dma = ret;
183 184 185
	return 0;
}

186
void aml_dma_linux_seq_destroy(struct aml_dma **dma)
187
{
188 189
	struct aml_dma *d;
	struct aml_dma_linux_seq *l;
190

191 192 193
	if (dma == NULL)
		return;
	d = *dma;
194
	if (d == NULL)
195
		return;
196 197

	assert(d->data != NULL);
198 199 200 201 202
	l = (struct aml_dma_linux_seq *)d->data;
	aml_vector_destroy(&l->data.requests);
	pthread_mutex_destroy(&l->data.lock);
	free(d);
	*dma = NULL;
203
}