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