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