Skip to content

Commit 68d6c60

Browse files
marcelmarcel
authored andcommitted
Add DMA memory allocation and freeing.
Slightly rework the tag handling.
1 parent e853cb9 commit 68d6c60

File tree

4 files changed

+181
-41
lines changed

4 files changed

+181
-41
lines changed

sys/dev/proto/proto_busdma.c

Lines changed: 141 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$");
3939
#include <sys/queue.h>
4040
#include <sys/rman.h>
4141
#include <sys/sbuf.h>
42+
#include <vm/vm.h>
43+
#include <vm/pmap.h>
4244

4345
#include <dev/proto/proto.h>
4446
#include <dev/proto/proto_dev.h>
@@ -47,45 +49,139 @@ __FBSDID("$FreeBSD$");
4749
MALLOC_DEFINE(M_PROTO_BUSDMA, "proto_busdma", "DMA management data");
4850

4951
static int
50-
proto_busdma_tag_create(struct proto_ioc_busdma *ioc,
51-
struct proto_tag **tag_io, bus_dma_tag_t *busdma_tag_io)
52+
proto_busdma_tag_create(struct proto_busdma *busdma, struct proto_tag *parent,
53+
struct proto_ioc_busdma *ioc)
5254
{
5355
struct proto_tag *tag;
54-
int error;
5556

56-
error = bus_dma_tag_create(*busdma_tag_io, ioc->u.tag.align,
57-
ioc->u.tag.bndry, ioc->u.tag.maxaddr, BUS_SPACE_MAXADDR,
58-
NULL, NULL, ioc->u.tag.maxsz, ioc->u.tag.nsegs,
59-
ioc->u.tag.maxsegsz, ioc->u.tag.flags, NULL, NULL,
60-
busdma_tag_io);
61-
if (error)
62-
return (error);
57+
/*
58+
* If nsegs is 1, ignore maxsegsz. What this means is that if we have
59+
* just 1 segment, then maxsz should be equal to maxsegsz. To keep it
60+
* simple for us, limit maxsegsz to maxsz in any case.
61+
*/
62+
if (ioc->u.tag.maxsegsz > ioc->u.tag.maxsz || ioc->u.tag.nsegs == 1)
63+
ioc->u.tag.maxsegsz = ioc->u.tag.maxsz;
64+
65+
/* A bndry of 0 really means ~0, or no boundary. */
66+
if (ioc->u.tag.bndry == 0)
67+
ioc->u.tag.bndry = ~0U;
6368

6469
tag = malloc(sizeof(*tag), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
65-
tag->parent = *tag_io;
66-
tag->busdma_tag = *busdma_tag_io;
67-
*tag_io = tag;
70+
if (parent != NULL) {
71+
tag->parent = parent;
72+
LIST_INSERT_HEAD(&parent->children, tag, peers);
73+
tag->align = MAX(ioc->u.tag.align, parent->align);
74+
tag->bndry = MIN(ioc->u.tag.bndry, parent->bndry);
75+
tag->maxaddr = MIN(ioc->u.tag.maxaddr, parent->maxaddr);
76+
tag->maxsz = MIN(ioc->u.tag.maxsz, parent->maxsz);
77+
tag->maxsegsz = MIN(ioc->u.tag.maxsegsz, parent->maxsegsz);
78+
tag->nsegs = MIN(ioc->u.tag.nsegs, parent->nsegs);
79+
tag->datarate = MIN(ioc->u.tag.datarate, parent->datarate);
80+
/* Write constraints back */
81+
ioc->u.tag.align = tag->align;
82+
ioc->u.tag.bndry = tag->bndry;
83+
ioc->u.tag.maxaddr = tag->maxaddr;
84+
ioc->u.tag.maxsz = tag->maxsz;
85+
ioc->u.tag.maxsegsz = tag->maxsegsz;
86+
ioc->u.tag.nsegs = tag->nsegs;
87+
ioc->u.tag.datarate = tag->datarate;
88+
} else {
89+
tag->align = ioc->u.tag.align;
90+
tag->bndry = ioc->u.tag.bndry;
91+
tag->maxaddr = ioc->u.tag.maxaddr;
92+
tag->maxsz = ioc->u.tag.maxsz;
93+
tag->maxsegsz = ioc->u.tag.maxsegsz;
94+
tag->nsegs = ioc->u.tag.nsegs;
95+
tag->datarate = ioc->u.tag.datarate;
96+
}
97+
LIST_INSERT_HEAD(&busdma->tags, tag, tags);
98+
ioc->result = (uintptr_t)(void *)tag;
6899
return (0);
69100
}
70101

71-
static void
72-
proto_busdma_tag_destroy(struct proto_tag *tag)
102+
static int
103+
proto_busdma_tag_destroy(struct proto_busdma *busdma, struct proto_tag *tag)
73104
{
74105

75-
bus_dma_tag_destroy(tag->busdma_tag);
106+
if (!LIST_EMPTY(&tag->mds))
107+
return (EBUSY);
108+
if (!LIST_EMPTY(&tag->children))
109+
return (EBUSY);
110+
111+
if (tag->parent != NULL) {
112+
LIST_REMOVE(tag, peers);
113+
tag->parent = NULL;
114+
}
115+
LIST_REMOVE(tag, tags);
76116
free(tag, M_PROTO_BUSDMA);
117+
return (0);
77118
}
78119

79120
static struct proto_tag *
80121
proto_busdma_tag_lookup(struct proto_busdma *busdma, u_long key)
81122
{
82123
struct proto_tag *tag;
83124

84-
LIST_FOREACH(tag, &busdma->tags, link) {
125+
LIST_FOREACH(tag, &busdma->tags, tags) {
85126
if ((void *)tag == (void *)key)
86127
return (tag);
87-
}
88-
return (NULL);
128+
}
129+
return (NULL);
130+
}
131+
132+
static int
133+
proto_busdma_mem_alloc(struct proto_busdma *busdma, struct proto_tag *tag,
134+
struct proto_ioc_busdma *ioc)
135+
{
136+
struct proto_md *md;
137+
int error;
138+
139+
md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
140+
md->tag = tag;
141+
142+
error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry,
143+
tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz,
144+
tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag);
145+
if (error) {
146+
free(md, M_PROTO_BUSDMA);
147+
return (error);
148+
}
149+
error = bus_dmamem_alloc(md->bd_tag, &md->kva, 0, &md->bd_map);
150+
if (error) {
151+
bus_dma_tag_destroy(md->bd_tag);
152+
free(md, M_PROTO_BUSDMA);
153+
return (error);
154+
}
155+
LIST_INSERT_HEAD(&tag->mds, md, peers);
156+
LIST_INSERT_HEAD(&busdma->mds, md, mds);
157+
ioc->u.mem.nsegs = 1;
158+
ioc->u.mem.physaddr = pmap_kextract((uintptr_t)(md->kva));
159+
ioc->result = (uintptr_t)(void *)md;
160+
return (0);
161+
}
162+
163+
static int
164+
proto_busdma_mem_free(struct proto_busdma *busdma, struct proto_md *md)
165+
{
166+
167+
LIST_REMOVE(md, mds);
168+
LIST_REMOVE(md, peers);
169+
bus_dmamem_free(md->bd_tag, md->kva, md->bd_map);
170+
bus_dma_tag_destroy(md->bd_tag);
171+
free(md, M_PROTO_BUSDMA);
172+
return (0);
173+
}
174+
175+
static struct proto_md *
176+
proto_busdma_md_lookup(struct proto_busdma *busdma, u_long key)
177+
{
178+
struct proto_md *md;
179+
180+
LIST_FOREACH(md, &busdma->mds, mds) {
181+
if ((void *)md == (void *)key)
182+
return (md);
183+
}
184+
return (NULL);
89185
}
90186

91187
struct proto_busdma *
@@ -109,12 +205,13 @@ proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma)
109205
int
110206
proto_busdma_cleanup(struct proto_softc *sc, struct proto_busdma *busdma)
111207
{
208+
struct proto_md *md, *md1;
112209
struct proto_tag *tag, *tag1;
113210

114-
LIST_FOREACH_SAFE(tag, &busdma->tags, link, tag1) {
115-
LIST_REMOVE(tag, link);
116-
proto_busdma_tag_destroy(tag);
117-
}
211+
LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1)
212+
proto_busdma_mem_free(busdma, md);
213+
LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1)
214+
proto_busdma_tag_destroy(busdma, tag);
118215
return (0);
119216
}
120217

@@ -123,41 +220,46 @@ proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
123220
struct proto_ioc_busdma *ioc)
124221
{
125222
struct proto_tag *tag;
126-
bus_dma_tag_t busdma_tag;
223+
struct proto_md *md;
127224
int error;
128225

129226
error = 0;
130227
switch (ioc->request) {
131228
case PROTO_IOC_BUSDMA_TAG_CREATE:
132-
busdma_tag = bus_get_dma_tag(sc->sc_dev);
133-
tag = NULL;
134-
error = proto_busdma_tag_create(ioc, &tag, &busdma_tag);
135-
if (error)
136-
break;
137-
LIST_INSERT_HEAD(&busdma->tags, tag, link);
138-
ioc->key = (uintptr_t)(void *)tag;
229+
busdma->bd_roottag = bus_get_dma_tag(sc->sc_dev);
230+
error = proto_busdma_tag_create(busdma, NULL, ioc);
139231
break;
140232
case PROTO_IOC_BUSDMA_TAG_DERIVE:
141233
tag = proto_busdma_tag_lookup(busdma, ioc->key);
142234
if (tag == NULL) {
143235
error = EINVAL;
144236
break;
145237
}
146-
busdma_tag = tag->busdma_tag;
147-
error = proto_busdma_tag_create(ioc, &tag, &busdma_tag);
148-
if (error)
149-
break;
150-
LIST_INSERT_HEAD(&busdma->tags, tag, link);
151-
ioc->key = (uintptr_t)(void *)tag;
238+
error = proto_busdma_tag_create(busdma, tag, ioc);
152239
break;
153240
case PROTO_IOC_BUSDMA_TAG_DESTROY:
154241
tag = proto_busdma_tag_lookup(busdma, ioc->key);
155242
if (tag == NULL) {
156243
error = EINVAL;
157244
break;
158245
}
159-
LIST_REMOVE(tag, link);
160-
proto_busdma_tag_destroy(tag);
246+
error = proto_busdma_tag_destroy(busdma, tag);
247+
break;
248+
case PROTO_IOC_BUSDMA_MEM_ALLOC:
249+
tag = proto_busdma_tag_lookup(busdma, ioc->u.mem.tag);
250+
if (tag == NULL) {
251+
error = EINVAL;
252+
break;
253+
}
254+
error = proto_busdma_mem_alloc(busdma, tag, ioc);
255+
break;
256+
case PROTO_IOC_BUSDMA_MEM_FREE:
257+
md = proto_busdma_md_lookup(busdma, ioc->key);
258+
if (md == NULL) {
259+
error = EINVAL;
260+
break;
261+
}
262+
error = proto_busdma_mem_free(busdma, md);
161263
break;
162264
default:
163265
error = EINVAL;

sys/dev/proto/proto_busdma.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,36 @@
2929
#ifndef _DEV_PROTO_BUSDMA_H_
3030
#define _DEV_PROTO_BUSDMA_H_
3131

32+
struct proto_md;
33+
3234
struct proto_tag {
33-
LIST_ENTRY(proto_tag) link;
35+
LIST_ENTRY(proto_tag) tags;
3436
struct proto_tag *parent;
35-
bus_dma_tag_t busdma_tag;
37+
LIST_ENTRY(proto_tag) peers;
38+
LIST_HEAD(,proto_tag) children;
39+
LIST_HEAD(,proto_md) mds;
40+
bus_addr_t align;
41+
bus_addr_t bndry;
42+
bus_addr_t maxaddr;
43+
bus_size_t maxsz;
44+
bus_size_t maxsegsz;
45+
u_int nsegs;
46+
u_int datarate;
47+
};
48+
49+
struct proto_md {
50+
LIST_ENTRY(proto_md) mds;
51+
LIST_ENTRY(proto_md) peers;
52+
struct proto_tag *tag;
53+
void *kva;
54+
bus_dma_tag_t bd_tag;
55+
bus_dmamap_t bd_map;
3656
};
3757

3858
struct proto_busdma {
3959
LIST_HEAD(,proto_tag) tags;
60+
LIST_HEAD(,proto_md) mds;
61+
bus_dma_tag_t bd_roottag;
4062
};
4163

4264
struct proto_busdma *proto_busdma_attach(struct proto_softc *);

sys/dev/proto/proto_core.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@ proto_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
370370
error = 0;
371371
switch (cmd) {
372372
case PROTO_IOC_REGION:
373+
if (r->r_type == PROTO_RES_BUSDMA) {
374+
error = EINVAL;
375+
break;
376+
}
373377
region = (struct proto_ioc_region *)data;
374378
region->size = r->r_size;
375379
if (r->r_type == PROTO_RES_PCICFG)
@@ -378,6 +382,10 @@ proto_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
378382
region->address = rman_get_start(r->r_d.res);
379383
break;
380384
case PROTO_IOC_BUSDMA:
385+
if (r->r_type != PROTO_RES_BUSDMA) {
386+
error = EINVAL;
387+
break;
388+
}
381389
busdma = (struct proto_ioc_busdma *)data;
382390
error = proto_busdma_ioctl(sc, r->r_d.busdma, busdma);
383391
break;

sys/dev/proto/proto_dev.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct proto_ioc_busdma {
4545
#define PROTO_IOC_BUSDMA_TAG_CREATE 1
4646
#define PROTO_IOC_BUSDMA_TAG_DERIVE 2
4747
#define PROTO_IOC_BUSDMA_TAG_DESTROY 3
48+
#define PROTO_IOC_BUSDMA_MEM_ALLOC 10
49+
#define PROTO_IOC_BUSDMA_MEM_FREE 11
4850
unsigned long key;
4951
union {
5052
struct {
@@ -57,6 +59,12 @@ struct proto_ioc_busdma {
5759
unsigned int datarate;
5860
unsigned int flags;
5961
} tag;
62+
struct {
63+
unsigned long tag;
64+
unsigned int flags;
65+
unsigned int nsegs;
66+
unsigned long physaddr;
67+
} mem;
6068
} u;
6169
unsigned long result;
6270
};

0 commit comments

Comments
 (0)