1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32 33 34 35
36
37 import xdc.rov.ViewInfo;
38
39 import xdc.runtime.Error;
40 import xdc.runtime.Assert;
41 import xdc.runtime.IHeap;
42 import xdc.runtime.IGateProvider;
43 import ti.sdo.utils.List;
44 import ti.sdo.utils.NameServer;
45 import xdc.runtime.knl.Sync;
46 import xdc.runtime.knl.ISync;
47
48 /*!
49 * ======== Stream ========
50 *
51 * Module to stream data to/from a driver.
52 *
53 * This module offers both the issue/reclaim model and the read/write model to
54 * send and receive data from drivers.
55 *
56 * In the issue/reclaim model, the client calls {@link #issue} when he has
57 * a buffer of data. issue() is non-blocking and returns. The buffer
58 * has been issued for IO. To get the buffer back the client has to call
59 * {@link #reclaim}. A call to reclaim() can block. Upon return from reclaim(),
60 * the client can re-use his buffer.
61 *
62 * The client can issue many buffers before reclaiming them.
63 * Buffers are always reclaimed in the order that they were issued.
64 * The client can optionally pass a user argument to issue().
65 *
66 * In the read/write model, clients will call {@link #read} or {@link #write}
67 * to send/receive data. Here the client may block until buffer is ready or
68 * a timeout occurs.
69 *
70 * Stream also provides {@link #control} to send down driver specific control
71 * commands. There is {@link #abort} function to abort the stream.
72 *
73 * Stream also maintains a name table of {@link IConverter} handles.
74 * This table is used by Stream to create an IO stack. The name passed to
75 * {@link #create} is usually of the form "/scale/uart". This name may
76 * correspond to the following IO stack.
77 *
78 * Stream Instance
79 *
80 * |
81
82 * V
83 *
84 * IConverter Instance (/scale)
85 *
86 * |
87 *
88 * V
89 *
90 * IDriver Instance (/uart)
91 *
92 * In this case the Stream requires "/scale" to be in its IConverter table
93 * and "/uart" to be in {@link DriverTable}. The IConverter table associates
94 * a name with an IConverter Handle. Note that these names have to be of the
95 * form "/name1".
96 *
97 * This module uses {@link ti.sdo.utils.NameServer} to maintain its IConverter
98 * table
99 *
100 * Stream uses the {@link xdc.runtime.knl.Sync} module for synchronization.
101 * Stream will call {@link xdc.runtime.knl.Sync#signal} when IO completes and
102 * {@link xdc.runtime.knl.Sync#wait} to wait for IO completion.
103 *
104 * Stream will create a Sync.Handle passing NULL for ISync
105 * handle to {@link #create}.
106 */
107
108 @InstanceFinalize
109 @InstanceInitError
110 @ModuleStartup
111
112 module Stream
113 {
114 const UInt INPUT = 0; /*! mode for input */
115 const UInt OUTPUT = 1; /*! mode for output */
116 const UInt INOUT = 2; /*! mode for input & output */
117
118 /*!
119 * Error raised when name not found in IConverter Table and DriverTable.
120 */
121 config Error.Id E_notFound = {
122 msg: "E_notFound: %s name not found"
123 };
124
125 /*!
126 * Error raised when there are no packets for IO
127 */
128 config Error.Id E_noPackets = {
129 msg: "E_noPackets: No packets available. maxIssues is %d"
130 };
131
132 /*!
133 * Error raised when reclaim called but no outstanding buffers issued
134 *
135 * Clients can check for this error while calling {@link #reclaim} to make
136 * sure they got all their buffers back.
137 * @p(code)
138 * #include <xdc/runtime/Error.h>
139 * #include <ti/sdo/io/Stream.h>
140 *
141 * Error_Block eb;
142 * Stream_Handle streamHdl;
143 * SizeT len;
144 * Ptr *bufp;
145 *
146 * Error_init(&eb);
147 *
148 * do {
149 * len = Stream_reclaim(streamHdl, bufp, NULL, &eb);
150 * }while (!Error_check(&eb));
151 *
152 * if (Error_getId == Stream_E_noBuffersIssued) {
153 * ....all issues buffers have been reclaimed
154 * }
155 * @p
156 *
157 */
158 config Error.Id E_noBuffersIssued = {
159 msg: "E_noBuffersIssued: No outstanding buffers"
160 };
161
162 /*!
163 * Error raised when a timeout occurs during reclaim
164 */
165 config Error.Id E_timeout = {
166 msg: "E_timeout: Timeout"
167 };
168
169 /*!
170 * Assert when {@link #read} or {@link #write} on wrong channel
171 *
172 * Assert when {@link #read} is called and mode = {@link #OUTPUT} or
173 * when {@link #write} is called and mode = {@link #INPUT}
174 */
175 config Assert.Id A_badMode = {
176 msg: "A_badMode: Bad Mode"
177 };
178
179 /*!
180 * Assert when there are more packets to be reclaimed
181 */
182 config Assert.Id A_pendingReclaims = {
183 msg: "A_pendingReclaims: Packets issued but not reclaimed"
184 };
185
186 /*!
187 * Assert when ISync is non-blocking but Stream_read/write called
188 */
189 config Assert.Id A_syncNonBlocking = {
190 msg: "A_syncNonBlocking: ISync should have blocking quality"
191 };
192
193 /*!
194 * Max entries that can be added at runtime
195 *
196 * This module requires total number of converters that need
197 * to be added at runtime to be identified at configuration time.
198 */
199 config UInt maxRuntimeEntries = 0;
200
201 /*!
202 * For making the table thread safe.
203 */
204 config IGateProvider.Handle gate = null;
205
206 /*!
207 * Length, in MAUs, of the name field in the table.
208 */
209 config UInt maxNameLen = 16;
210
211 /*!
212 * Section name used to place the IConverter table.
213 */
214 metaonly config String tableSection = null;
215
216 metaonly struct BasicView {
217 String label;
218 UInt maxIssues;
219 UInt issued;
220 UInt ready;
221 String mode;
222 Bool userSuppliedSync;
223
224 }
225
226 @Facet
227 metaonly config ViewInfo.Instance rovViewInfo =
228 ViewInfo.create({
229 viewMap: [
230 ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}],
231 ]
232 });
233
234 /*!
235 * ======== add ========
236 * Add to IConverter table at runtime.
237 *
238 * This API is not thread safe. Set {@link #gate} parameter
239 * to protect table if called from multiple threads.
240 *
241 * @param(name) Name of entry
242 * @param(handle) IConverter handle
243 * @param(eb) Error Block
244 */
245 Void add(String name, IConverter.Handle handle, Error.Block *eb);
246
247 /*!
248 * ======== addMeta ========
249 * Add to IConverter table at configuration time.
250 *
251 * @param(name) name of entry
252 * @param(handle) IConverter handle
253 */
254 metaonly Void addMeta(String name, IConverter.Handle handle);
255
256 /*!
257 * ======== remove ========
258 * Remove entry from IConverter table at runtime.
259 *
260 * This API is not thread safe. Set {@link #gate} parameter
261 * to protect table if called from multiple threads.
262 *
263 * @param(name) name of entry
264 * @param(eb) error block
265 */
266 Void remove(String name, Error.Block *eb);
267
268 /*!
269 * @_nodoc
270 * Match a name to name in IConverter table. return length matched.
271 */
272 Int match(String name, IConverter.Handle *handle, Error.Block *eb);
273
274 /*!
275 * @_nodoc
276 * io completed log functions called by DriverAdapter
277 */
278 Void completedLog(UArg buf, UArg size, UArg arg);
279
280 instance:
281
282 /*! Max outstanding issues */
283 config UInt maxIssues = 2;
284
285 /*! Heap used to allocate {@link DriverTypes#Packet} in dynamic create */
286 config IHeap.Handle packetHeap = null;
287
288 /*!
289 * Section name used to place {@link DriverTypes#Packet}
290 *
291 * Default of null results in no explicit section placement.
292 */
293 metaonly config String packetSection = null;
294
295 /*! ISync handle used to signal IO completion */
296 config ISync.Handle sync = null;
297
298 /*! Channel params for driver if present in IO stack */
299 config UArg chanParams = null;
300
301 /*!
302 * ======== create ========
303 * Create a Stream Instance.
304 *
305 * Creates a new Stream instance and sets up the IO stack specified by
306 * name.
307 * The name is usually of the following form "/scale/uart".
308 * The mode is either {@link #INPUT} or {@link #OUTPUT}.
309 *
310 * @param(name) name that identifies the IO stack
311 * @param(mode) mode of channel.
312 */
313 create(String name, UInt mode);
314
315 /*!
316 * ======== issue ========
317 * Issue a buffer to the stream.
318 *
319 * This function issues a buffer to the stream for IO. This API is
320 * non-blocking.
321 *
322 * Failure of issue() indicates that the stream was not able to accept the
323 * buffer being issued or that there was a error from the underlying
324 * IConverter or IDriver. Note that the error could be driver specific.
325 * If issue() fails because of an underlying driver problem
326 * {@link #abort} should be called before attempting more I/O through the
327 * stream.
328 *
329 * The interpretation of the logical size of a buffer, is
330 * direction dependent.
331 * For a stream opened in {@link DriverTypes#OUTPUT} mode, the logical size
332 * of the buffer indicates the number of minimum addressable units of of
333 * data it contains.
334 *
335 * For a stream opened in {@link DriverTypes#INPUT} mode, the logical size
336 * of a buffer indicates the number of minimum addressable units being
337 * requested by the client. In either case, the logical size of the buffer
338 * must be less than or equal to the physical size of the buffer.
339 *
340 * issue() is used in conjunction with {@link #reclaim}. The issue() call
341 * sends a buffer to a stream, and reclaim() retrieves a buffer
342 * from a stream. In normal operation each issue() call is followed by an
343 * reclaim() call.
344 *
345 * Short bursts of multiple issue() calls can be made without an
346 * intervening reclaim() call followed by short bursts of reclaim() calls,
347 * but over the life of the stream issue() and reclaim() must be called
348 * the same number of times. The number of issue() calls can exceed the
349 * number of reclaim() calls by {@link #maxIssues}.
350 *
351 * The client argument is not interpreted by Stream or the underlying
352 * modules, but is offered as a service to the stream client. All compliant
353 * device drivers preserve the value of arg and maintain its association
354 * with the data that it was issued with. arg provides a method for a
355 * client to associate additional information with a particular buffer of
356 * data. The arg is returned during reclaim().
357 *
358 * @param(buf) buffer pointer
359 * @param(size) size of buffer
360 * @param(arg) app arg
361 * @param(eb) error block
362 *
363 */
364 Void issue(Ptr buf, SizeT size, UArg arg, Error.Block *eb);
365
366 /*!
367 * ======== reclaim ========
368 * Reclaim a buffer that was previously issued by calling {@link #issue}.
369 *
370 * reclaim() is used to request a buffer back from a stream.
371 *
372 * If a stream was created in {@link DriverTypes#OUTPUT} mode, then
373 * reclaim() returns a processed buffer, and size is zero.
374 * If a stream was opened in {@link DriverTypes#INPUT} mode, reclaim()
375 * returns a full buffer, and size is the number of minimum addressable
376 * units of data in the buffer.
377 *
378 * reclaim() blocks until a buffer can be returned to the caller, or until
379 * a timeout occurs.
380 *
381 * Failure of reclaim() indicates that no buffer was returned to
382 * the client. Therefore, if reclaim() fails, the client should
383 * not attempt to de-reference pbufp, since it is not guaranteed to contain
384 * a valid buffer pointer.
385 *
386 * reclaim() is used in conjunction with {@link #issue} to operate
387 * a stream. The issue() call sends a buffer to a stream, and
388 * reclaim() retrieves a buffer from a stream. In normal operation
389 * each issue call is followed by an reclaim call.
390 *
391 * Short bursts of multiple issue() calls can be made without an
392 * intervening reclaim() call followed by short bursts of reclaim() calls,
393 * but over the life of the stream issue() and reclaim() must be called
394 * the same number of times. The number of issue() calls can exceed the
395 * number of reclaim() calls by {@link #maxIssues}.
396 *
397 * A reclaim() call should not be made without at least one
398 * outstanding issue() call. Calling reclaim() with no
399 * outstanding issue() calls results in an error {@link #E_noBuffersIssued}
400 *
401 * reclaim() only returns buffers that were passed in using issue(). It
402 * also returns the buffers in the same order that they were issued.
403 *
404 * reclaim() returns the size transferred in case of success.
405 * It returns zero when an error is caught. In case of timeout, the error
406 * is {@link #E_timeout}.
407 *
408 * @param(pbufp) returned buffer pointer
409 * @param(timeout) timeout in microseconds
410 * @param(parg) pointer to client arg. Can be null.
411 * @param(eb) error block
412 * @b(returns) size transferred
413 *
414 */
415 SizeT reclaim(Ptr *pbufp, UInt timeout, UArg *parg, Error.Block *eb);
416
417 /*!
418 * ======== read ========
419 * Read data from a stream.
420 *
421 * Equivalent to an issue/reclaim pair for a instance with
422 * mode = DriverTypes.INPUT. This call is synchronous and the buffer
423 * has data upon return from this API.
424 *
425 * @param(bufp) buffer pointer
426 * @param(size) size of buffer
427 * @param(timeout) timeout in microseconds
428 * @param(eb) error block
429 * @b(returns) size transferred
430 */
431 SizeT read (Ptr bufp, SizeT size, UInt timeout, Error.Block *eb);
432
433 /*!
434 * ======== write ========
435 * Write data to a stream
436 *
437 * Equivalent to an issue/reclaim pair for a instance with
438 * mode = DriverTypes.OUTPUT.
439 * This call is synchronous and the driver has finished processing the
440 * buffer upon return from this API.
441 *
442 * @param(bufp) buffer pointer
443 * @param(size) size of buffer
444 * @param(timeout) timeout in microseconds
445 * @param(eb) error block
446 * @b(returns) size transferred
447 */
448 SizeT write (Ptr bufp, SizeT size, UInt timeout, Error.Block *eb);
449
450 /*!
451 * ======== submit ========
452 * @_nodoc
453 * Convenience API to send driver specific command.
454 *
455 * Equivalent to an issue/reclaim pair for a instance with
456 * driver specific command.
457 *
458 * @param(bufp) buffer pointer
459 * @param(size) size of buffer
460 * @param(cmd) driver specific packet command
461 * @param(timeout) timeout in microseconds
462 * @param(eb) error block
463 * @b(returns) size transferred
464 */
465 SizeT submit (Ptr bufp, SizeT size, DriverTypes.PacketCmd cmd, UInt timeout, Error.Block *eb);
466
467 /*!
468 * ======== control ========
469 * Send a control command to the driver.
470 *
471 * @param(cmd) device specific command
472 * @param(cmdArg) command specific arg
473 * @param(eb) error block
474 */
475 Void control(DriverTypes.ControlCmd cmd, UArg cmdArg, Error.Block *eb);
476
477 /*!
478 * ======== abort ========
479 * Abort all pending IO.
480 *
481 * The underlying device connected to stream is idled as a result of
482 * calling abort and all buffers are ready for reclaim().
483 *
484 * The client still needs to call {@link #reclaim} to get back his
485 * buffers. However the client will NOT block when calling reclaim()
486 * after an abort().
487 *
488 * @param(eb) error block
489 * @b(returns) number of buffers aborted
490 */
491 UInt abort(Error.Block *eb);
492
493 /*!
494 * ======== prime ========
495 * Prime an {@link #OUTPUT} stream instance.
496 *
497 * This API facilitates buffering of an output channel. Consider a
498 * task that constantly gets data from input channel and sends to an
499 * output channel. To start with it may want to issue buffers to the
500 * input channel and output channel to enable double buffering.
501 * For an input channel there is no problem. For an output channel however
502 * the buffer data is sent out through the peripheral and in the case of a
503 * heterogenous system, the data will be sent to the other processor.
504 *
505 * In such cases where the driver cannot handle dummy buffers,
506 * Stream_prime can be used to make buffers available instantly for
507 * reclaim without actually sending the buffers to the driver.
508 * This API is non-blocking.
509 *
510 * The primary use of prime() is used when applications want to prime
511 * an output channel at startup, without sending data to the driver.
512 * This allows them to reclaim and issue in their task.
513 *
514 * Failure of prime() indicates that the stream was not able to accept the
515 * buffer being issued due to un-avaibailibity of IO packets.
516 *
517 * The client argument is not interpreted by Stream.
518 *
519 * @param(buf) buffer pointer
520 * @param(arg) app arg
521 * @param(eb) error block
522 */
523 Void prime(Ptr buf, UArg arg, Error.Block *eb);
524
525 internal:
526
527 /*!
528 * Structure of entry in IConverter Table
529 *
530 * @field(name)
531 * Name of table entry.
532 *
533 * @field(handle)
534 * {@link IConverter#Handle} instance to be used in the IO stack
535 *
536 */
537 struct Entry {
538 String name;
539 IConverter.Handle handle;
540 };
541
542 /*!
543 * Array for all statically configured IConverter table entries
544 */
545 metaonly config Entry staticEntries[];
546
547 /*! callback for lower layer */
548 Void internalCallback(UArg arg);
549
550 /*! instance postInit */
551 Int postInit(Object *obj, Error.Block *eb);
552
553 /*! extension to pass down driver specific command */
554 Void issueX(Object *obj, Ptr bufp, SizeT size, UArg arg,
555 DriverTypes.PacketCmd cmd, Error.Block *eb);
556
557
558 struct Instance_State {
559 String name;
560 UArg chanParams;
561 Bool drvAdapHdl;
562 DriverTypes.Packet packets[];
563 UInt maxIssues;
564 UInt issued;
565 UInt ready;
566 UInt mode;
567 IHeap.Handle packetHeap;
568 ISync.Handle complete;
569 Bool userSync;
570 IConverter.Handle convHandle;
571 List.Object freeList;
572 };
573
574
575 struct Module_State {
576 NameServer.Handle convTable;
577 };
578 }
579 580 581 582
583