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

Last change on this file since 384 was 350, checked in by alain, 10 years ago

Introducing two modifications regarding the locks protecting
exclusive access to BDV and TTY peripherals channels:

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