@@ -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$");
4749MALLOC_DEFINE (M_PROTO_BUSDMA , "proto_busdma" , "DMA management data" );
4850
4951static 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
79120static struct proto_tag *
80121proto_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
91187struct proto_busdma *
@@ -109,12 +205,13 @@ proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma)
109205int
110206proto_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 ;
0 commit comments