source: soft/giet_vm/giet_drivers/tty_driver.c @ 313

Last change on this file since 313 was 313, checked in by alain, 11 years ago

The main modif is in TTY driver: The hard lock implemented in the
vci_multi_tty component is not used anymore, because this (non cacheable)
lock was not scalable... It has been replaced by a software (cacheable) lock
that has a better scalability in case of hardware cache coherence.
(see the _tty_get_lock() and _tty_release_lock() functions)

File size: 10.3 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : tty_driver.c
3// Date     : 23/05/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The tty_driver.c and tty_drivers.h files are part ot the GIET-VM kernel.
8// This driver supports the SocLib vci_multi_tty component.
9//
10// The total number of TTY terminals must be defined by the configuration
11// parameter NB_TTY_CHANNELS in the hard_config.h file.
12//
13// The "system" terminal is TTY[0].
14// The "user" TTYs are allocated to applications by the GIET in the boot phase,
15// as defined in the mapping_info data structure. The corresponding tty_id must
16// be stored in the context of the task by the boot code.
17//
18// The seg_tty_base must be defined in giet_vsegs.ld file.
19///////////////////////////////////////////////////////////////////////////////////
20// Implementation note:
21//
22// All physical accesses to device registers are done by the two
23// _tty_get_register(), _tty_set_register() low-level functions,
24// that are handling virtual / physical addressing.
25///////////////////////////////////////////////////////////////////////////////////
26
27#include <giet_config.h>
28#include <tty_driver.h>
29#include <xcu_driver.h>
30#include <ctx_handler.h>
31#include <utils.h>
32
33#if !defined(NB_TTY_CHANNELS)
34# error: You must define NB_TTY_CHANNELS in the hard_config.h file
35#endif
36
37#if (NB_TTY_CHANNELS < 1)
38# error: NB_TTY_CHANNELS cannot be smaller than 1!
39#endif
40
41#define in_unckdata __attribute__((section (".unckdata")))
42#define in_kdata    __attribute__((section (".kdata")))
43
44//////////////////////////////////////////////////////////////////////////////
45//   TTY global variables
46//////////////////////////////////////////////////////////////////////////////
47
48in_unckdata volatile unsigned int _tty_rx_buf[NB_TTY_CHANNELS];
49
50in_unckdata volatile unsigned int _tty_rx_full[NB_TTY_CHANNELS] 
51                                     = { [0 ... NB_TTY_CHANNELS - 1] = 0 };
52
53in_kdata unsigned int _tty_lock[NB_TTY_CHANNELS] 
54                        = { [0 ... NB_TTY_CHANNELS - 1] = 0 };
55
56//////////////////////////////////////////////////////////////////////////////
57// This low level function returns the value of register (channel / index)
58//////////////////////////////////////////////////////////////////////////////
59unsigned int _tty_get_register( unsigned int channel,
60                                unsigned int index )
61{
62    unsigned int* vaddr = (unsigned int*)&seg_tty_base + channel*TTY_SPAN + index;
63    return _io_extended_read( vaddr );
64}
65
66//////////////////////////////////////////////////////////////////////////////
67// This low level function set a new value in register (channel / index) 
68//////////////////////////////////////////////////////////////////////////////
69void _tty_set_register( unsigned int channel,
70                        unsigned int index,
71                        unsigned int value )
72{
73    unsigned int* vaddr = (unsigned int*)&seg_tty_base + channel*TTY_SPAN + index;
74    _io_extended_write( vaddr, value );
75}
76
77/////////////////////////////////////////////////////////////////////////////////
78// This non-blocking function writes a character string from a fixed-length
79// buffer to a TTY terminal identified by the channel argument.
80// This function is intended to be used to handle a system call, and should
81// not be used by the kernel for log messages on TTY 0.
82// protecting exclusive access to the selected terminal.
83// If channel argument is 0xFFFFFFFF, the TTY index is found in the task context.
84// This is a non blocking call: it tests the TTY_STATUS register, and stops
85// the transfer as soon as the TTY_STATUS[WRITE] bit is set.
86/////////////////////////////////////////////////////////////////////////////////
87// Returns  the number of characters that have been written.
88/////////////////////////////////////////////////////////////////////////////////
89unsigned int _tty_write( const char*  buffer,   
90                         unsigned int length,    // number of characters
91                         unsigned int channel)   // channel index
92{
93    unsigned int  nwritten;
94
95    // compute and check tty channel
96    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
97    if( channel >= NB_TTY_CHANNELS ) return -1;
98
99    // write string to TTY channel
100    for (nwritten = 0; nwritten < length; nwritten++) 
101    {
102        // check tty's status
103        if ( _tty_get_register( channel, TTY_STATUS ) & 0x2 )  break;
104
105        // write one byte
106        _tty_set_register( channel, TTY_WRITE, (unsigned int)buffer[nwritten] );
107    }
108   
109    return nwritten;
110}
111
112//////////////////////////////////////////////////////////////////////////////
113// This non-blocking function fetches one character from the
114// terminal identified by the channel argument. If the channel argument
115// is 0xFFFFFFFF, the channel index is obtained from the current task context.
116// It uses the TTY_GET_IRQ[tty_id] interrupt and the buffer must have been
117// filled by the TTY_ISR.
118// It test the _tty_rx_full[tty_id] variable, read the _tty_rx_buf[tty_id]
119// buffer, writes this character to the target buffer, and resets the
120// _tty_rx_full[tty_id] register.
121// The length argument is not used.
122//////////////////////////////////////////////////////////////////////////////
123// Returns  the number of characters that have been read (0/1).
124//////////////////////////////////////////////////////////////////////////////
125unsigned int _tty_read( char*        buffer, 
126                        unsigned int length,    // unused
127                        unsigned int channel)   // channel index
128{
129    // compute and check tty channel
130    if( channel == 0xFFFFFFFF )  channel = _get_context_slot(CTX_TTY_ID);
131    if( channel >= NB_TTY_CHANNELS ) return -1;
132
133    // read one character from TTY channel
134    if (_tty_rx_full[channel] == 0) 
135    {
136        return 0;
137    }
138    else 
139    {
140        *buffer = _tty_rx_buf[channel];
141        _tty_rx_full[channel] = 0;
142        return 1;
143    }
144}
145
146//////////////////////////////////////////////////////////////////////////////
147// This function try to take the hardwired lock protecting
148// exclusive access to TTY terminal identified by the "channel" argument.
149// It enters a critical section before taking the lock, and save the SR value
150// at address defined by the "save_sr_ptr" argument.
151// It returns only when the lock has been successfully taken.
152//////////////////////////////////////////////////////////////////////////////
153void _tty_get_lock( unsigned int   channel,
154                    unsigned int * save_sr_ptr )
155{
156    if( channel >= NB_TTY_CHANNELS ) _exit();
157
158    _it_disable( save_sr_ptr );
159
160//    while ( _tty_get_register( channel, TTY_CONFIG ) ); // busy waiting
161
162    _get_lock( &_tty_lock[channel] );
163}
164
165//////////////////////////////////////////////////////////////////////////////
166// This function releases the hardwired lock protecting
167// exclusive access to TTY terminal identified by the channel argument.
168// It exit the critical section after lock release, and restore SR value
169// from address defined by the "save_sr_ptr" argument.
170//////////////////////////////////////////////////////////////////////////////
171void _tty_release_lock( unsigned int   channel,
172                        unsigned int * save_sr_ptr )
173{
174    if( channel >= NB_TTY_CHANNELS ) _exit();
175
176//    _tty_set_register( channel, TTY_CONFIG, 0 );
177
178    _release_lock( &_tty_lock[channel] );
179   
180    _it_restore( save_sr_ptr );
181}
182
183///////////////////////////////////////////////////////////////////////////////////
184// This ISR handles the IRQ signaling that the RX buffer is not empty.
185// IT can be an HWI or an SWI.
186// There is one communication buffer _tty_rx_buf[i] and one synchronisation
187// variable _tty_rx_full[i] per channel.
188// Does nothing if the TTY_RX buffer is empty, or if the kernel buffer is full
189// when the ISR is called.
190///////////////////////////////////////////////////////////////////////////////////
191void _tty_rx_isr( unsigned int irq_type,   // HWI / WTI
192                  unsigned int irq_id,     // index returned by XCU
193                  unsigned int channel )   // TTY channel
194{
195    unsigned int cluster_xy = _get_procid() / NB_PROCS_MAX;
196
197    // get TTY status
198    unsigned int status = _tty_get_register( channel, TTY_STATUS );
199
200    // check both TTY status and kernel buffer status:
201    // does nothing if kernel buffer full or tty_buffer empty
202    if ( ((status & 0x1) == 0) || 
203         (_tty_rx_full[channel] != 0) )  return;
204 
205    // reset WTI in XCU if WTI type
206    if ( irq_type == IRQ_TYPE_WTI ) 
207    {
208        unsigned int value;
209        _xcu_get_wti_value( cluster_xy, irq_id, &value );
210    }
211
212    // transfer character to kernel buffer and acknowledge TTY IRQ
213    _tty_rx_buf[channel]  = _tty_get_register( channel, TTY_READ ); 
214
215    // set kernel buffer status
216    asm volatile( "sync" );
217    _tty_rx_full[channel] = 1;
218
219#if GIET_DEBUG_IRQS  // we don't take the TTY lock to avoid deadlock
220unsigned int x              = cluster_xy >> Y_WIDTH;
221unsigned int y              = cluster_xy & ((1<<Y_WIDTH)-1);
222unsigned int lpid           = _get_procid() % NB_PROCS_MAX;
223_puts("\n[IRQS DEBUG] Processor[");
224_putd(x );
225_puts(",");
226_putd(y );
227_puts(",");
228_putd(lpid );
229_puts("] enters _tty_rx_isr() at cycle ");
230_putd(_get_proctime() );
231_puts("\n  read byte = ");
232_putx(_tty_rx_buf[channel] );
233_puts("\n");
234#endif
235
236}
237
238///////////////////////////////////////////////////////////////////////////////////
239// This ISR handles the IRQ signaling that the TX buffer is empty.
240// IT can be an HWI or an SWI.
241// There is one single multi_tty component controling all channels.
242// There is one communication buffer _tty_rx_buf[i] and one synchronisation
243// variable _tty_rx_full[i] per channel.
244// A character is lost if the buffer is full when the ISR is executed.
245///////////////////////////////////////////////////////////////////////////////////
246void _tty_tx_isr( unsigned int irq_type,   // HWI / WTI
247                  unsigned int irq_id,     // index returned by XCU
248                  unsigned int channel )   // TTY channel
249{
250    _puts("\n[GIET ERROR] the _tty_tx_isr() is not implemented\n");
251    _exit();
252}
253
254// Local Variables:
255// tab-width: 4
256// c-basic-offset: 4
257// c-file-offsets:((innamespace . 0)(inline-open . 0))
258// indent-tabs-mode: nil
259// End:
260// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
261
Note: See TracBrowser for help on using the repository browser.