source: trunk/hal/tsar_mips32/drivers/soclib_tty.c @ 435

Last change on this file since 435 was 435, checked in by alain, 6 years ago

Fix a bad bug in scheduler...

File size: 13.2 KB
Line 
1/*
2 * soclib_tty.c - soclib tty driver implementation.
3 *
4 * Author  Alain Greiner (2016)
5 *
6 * Copyright (c)  UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH..
9 *
10 * ALMOS-MKH. is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH. is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <dev_txt.h>
25#include <chdev.h>
26#include <soclib_tty.h>
27#include <remote_spinlock.h>
28#include <thread.h>
29#include <printk.h>
30#include <hal_special.h>
31
32#if (CONFIG_DEBUG_SYS_READ & 1)
33extern uint32_t  enter_tty_cmd_read;
34extern uint32_t  exit_tty_cmd_read;
35
36extern uint32_t  enter_tty_isr_read;
37extern uint32_t  exit_tty_isr_read;
38#endif
39
40#if (CONFIG_DEBUG_SYS_WRITE & 1)
41extern uint32_t  enter_tty_cmd_write;
42extern uint32_t  exit_tty_cmd_write;
43
44extern uint32_t  enter_tty_isr_write;
45extern uint32_t  exit_tty_isr_write;
46#endif
47
48///////////////////////////////////////
49void soclib_tty_init( chdev_t * chdev )
50{
51    xptr_t reg_xp;
52
53    chdev->cmd = &soclib_tty_cmd;
54    chdev->isr = &soclib_tty_isr;
55    chdev->aux = &soclib_tty_aux;
56
57    // get TTY channel and extended pointer on TTY peripheral base address
58    xptr_t   tty_xp  = chdev->base;
59    uint32_t channel = chdev->channel;
60
61    // get SOCLIB_TTY device cluster and local pointer
62    cxy_t      tty_cxy = GET_CXY( tty_xp );
63    uint32_t * tty_ptr = GET_PTR( tty_xp );
64
65    // set TTY_RX_IRQ_ENABLE
66    reg_xp = XPTR( tty_cxy , tty_ptr + (channel * TTY_SPAN) + TTY_RX_IRQ_ENABLE );
67    hal_remote_sw( reg_xp , 1 );
68
69    // reset TTY_TX_IRQ_ENABLE
70    reg_xp = XPTR( tty_cxy , tty_ptr + (channel * TTY_SPAN) + TTY_TX_IRQ_ENABLE );
71    hal_remote_sw( reg_xp , 0 );
72}
73
74//////////////////////////////////////////////////////////////
75void __attribute__ ((noinline)) soclib_tty_cmd( xptr_t th_xp )
76{
77
78#if (CONFIG_DEBUG_SYS_READ & 1)
79if( type == TXT_READ) enter_tty_cmd_read = (uint32_t)hal_get_cycles();
80#endif
81
82#if (CONFIG_DEBUG_SYS_WRITE & 1)
83if( type == TXT_WRITE) enter_tty_cmd_write = (uint32_t)hal_get_cycles();
84#endif
85
86    // get client thread cluster and local pointer
87    cxy_t      th_cxy = GET_CXY( th_xp );
88    thread_t * th_ptr = GET_PTR( th_xp );
89
90    // get command type and extended pointer on TXT device
91    uint32_t type = hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.type ) );
92
93#if CONFIG_DEBUG_HAL_TXT
94uint32_t cycle = (uint32_t)hal_get_cycles();
95if (CONFIG_DEBUG_HAL_TXT < cycle )
96printk("\n[DBG] %s : thread %x enter for %s / cycle %d\n",
97__FUNCTION__ , CURRENT_THREAD , dev_txt_type_str(type) , cycle );
98#endif
99
100    if( type == TXT_WRITE )         // block, enable TX_IRQ, and dechedule for a WRITE
101    {
102        xptr_t dev_xp = (xptr_t)hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.dev_xp ) );
103
104        // get TXT device cluster and local pointer
105        cxy_t     dev_cxy = GET_CXY( dev_xp );
106        chdev_t * dev_ptr = GET_PTR( dev_xp );
107
108        // get extended pointer on SOCLIB_TTY base segment
109        xptr_t tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
110
111        // get SOCLIB_TTY base segment cluster and local pointer
112        cxy_t      tty_cxy = GET_CXY( tty_xp );
113        uint32_t * tty_ptr = GET_PTR( tty_xp );
114
115        // get TTY channel index and channel base address
116        uint32_t   channel = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->channel ) );
117        uint32_t * base    = tty_ptr + TTY_SPAN * channel;
118
119        // block server thread
120        thread_block( CURRENT_THREAD , THREAD_BLOCKED_DEV_ISR );
121
122        // enable relevant TX_IRQ for a WRITE
123        hal_remote_sw( XPTR( tty_cxy , base + TTY_TX_IRQ_ENABLE ) , 1 );
124
125        // deschedule
126        sched_yield( "waiting TXT_TX_ISR completion" );
127    }
128    else if( type == TXT_READ )        // block, and deschedule for a READ
129    {
130        // block server thread
131        thread_block( CURRENT_THREAD , THREAD_BLOCKED_DEV_ISR );
132
133        // deschedule
134        sched_yield( "waiting TXT_RX_ISR completion" );
135    }
136    else
137    {
138        assert( false , __FUNCTION__ , "illegal TXT command\n" );
139    }
140
141#if CONFIG_DEBUG_HAL_TXT
142cycle = (uint32_t)hal_get_cycles();
143if (CONFIG_DEBUG_HAL_TXT < cycle )
144printk("\n[DBG] %s : thread %x exit after %s / cycle %d\n", 
145__FUNCTION__ , CURRENT_THREAD , dev_txt_type_str( type ) , cycle );
146#endif
147
148#if (CONFIG_DEBUG_SYS_READ & 1)
149if( type == TXT_READ ) exit_tty_cmd_read = (uint32_t)hal_get_cycles();
150#endif
151
152#if (CONFIG_DEBUG_SYS_WRITE & 1)
153if( type == TXT_WRITE ) exit_tty_cmd_write = (uint32_t)hal_get_cycles();
154#endif
155
156}  // end soclib_tty_cmd()
157
158/////////////////////////////////////////////////////////////
159void __attribute__ ((noinline)) soclib_tty_aux( void * args )
160{
161    uint32_t   status;
162    bool_t     empty;
163    uint32_t   i;
164
165    xptr_t     dev_xp = ((txt_sync_args_t *)args)->dev_xp;
166    char     * buffer = ((txt_sync_args_t *)args)->buffer;
167    uint32_t   count  = ((txt_sync_args_t *)args)->count;
168   
169    // get TXT0 chdev cluster and local pointer
170    cxy_t     dev_cxy = GET_CXY( dev_xp );
171    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
172
173    // get extended pointer on TTY channel base address
174    xptr_t tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
175
176    // get TTY channel segment cluster and local pointer
177    cxy_t      tty_cxy = GET_CXY( tty_xp );
178    uint32_t * tty_ptr = (uint32_t *)GET_PTR( tty_xp );
179
180    // get extended pointers on TTY_WRITE & TTY_STATUS registers
181    xptr_t write_xp  = XPTR( tty_cxy , tty_ptr + TTY_WRITE );
182    xptr_t status_xp = XPTR( tty_cxy , tty_ptr + TTY_STATUS );
183
184    // loop on characters (busy waiting strategy)
185    for( i = 0 ; i < count ; i++ )
186    {
187        do
188        {
189            // get TTY_STATUS
190            status = hal_remote_lw( status_xp );
191            empty  = ( (status & TTY_STATUS_TX_FULL) == 0 );
192
193            // transfer one byte if TX buffer empty
194            if ( empty )  hal_remote_sb( write_xp , buffer[i] );
195        }
196        while ( empty == false );
197    }
198}  // end soclib_tty_aux()
199
200
201/////////////////////////////////////////////////////////////////
202void __attribute__ ((noinline)) soclib_tty_isr( chdev_t * chdev )
203{
204    uint32_t    type;         // command type
205    uint32_t    count;        // number of bytes in buffer
206    xptr_t      buf_xp;       // extended pointer on buffer
207    xptr_t      error_xp;     // extended pointer on error field in command
208    xptr_t      status_xp;    // extended pointer on TTY_STATUS register
209    xptr_t      write_xp;     // extended pointer on TTY_WRITE register
210    xptr_t      read_xp;      // extended pointer on TTY_READ register
211    uint32_t    status;       // TTY terminal status
212    char        byte;         // read byte
213    xptr_t      client_xp;    // first client thread in waiting queue
214    cxy_t       client_cxy;   // firts client thread cluster
215    thread_t  * client_ptr;   // first client thread pointer
216    pid_t       pid;          // foreground process identifier
217    xptr_t      owner_xp;     // extended pointer on foreground process in owner cluster
218    cxy_t       owner_cxy;   
219    process_t * owner_ptr;
220    uint32_t    i;
221
222#if (CONFIG_DEBUG_SYS_READ & 1)
223enter_tty_isr_read = (uint32_t)hal_get_cycles();
224#endif
225
226#if (CONFIG_DEBUG_SYS_WRITE & 1)
227enter_tty_isr_write = (uint32_t)hal_get_cycles();
228#endif
229
230#if CONFIG_DEBUG_HAL_TXT
231uint32_t cycle = (uint32_t)hal_get_cycles();
232if (CONFIG_DEBUG_HAL_TXT < cycle)
233printk("\n[DBG] %s : enter / cycle %d\n", __FUNCTION__ , cycle );
234#endif
235
236    // get extended pointer on chdev queue root
237    xptr_t root_xp   = XPTR( local_cxy , &chdev->wait_root );
238
239    // get chdev channel
240    uint32_t channel = chdev->channel;
241
242    // get first command if queue non empty
243    if( xlist_is_empty( root_xp ) == false )
244    {
245        // get extended pointer on first client thread
246        client_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );
247
248        // get client thread cluster and local pointer
249        client_cxy = GET_CXY( client_xp );
250        client_ptr = GET_PTR( client_xp );
251
252        // get command arguments
253        type     = hal_remote_lw ( XPTR( client_cxy , &client_ptr->txt_cmd.type   ) );
254        count    = hal_remote_lw ( XPTR( client_cxy , &client_ptr->txt_cmd.count  ) );
255        buf_xp   = hal_remote_lwd( XPTR( client_cxy , &client_ptr->txt_cmd.buf_xp ) );
256        error_xp =                 XPTR( client_cxy , &client_ptr->txt_cmd.error  );
257    }
258    else
259    {
260        type     = 0xFFFFFFFF;
261
262        // these lines to avoid a GCC warning
263        count      = 0;
264        buf_xp     = XPTR_NULL;
265        error_xp   = XPTR_NULL;
266        client_cxy = 0;
267        client_ptr = NULL;
268    }
269
270    // get SOCLIB_TTY peripheral cluster and local pointer
271    cxy_t      tty_cxy = GET_CXY( chdev->base );
272    uint32_t * tty_ptr = GET_PTR( chdev->base );
273
274    // get channel base address
275    uint32_t * base = tty_ptr + TTY_SPAN * chdev->channel;
276
277    // get extended pointer on TTY registers
278    status_xp = XPTR( tty_cxy , base + TTY_STATUS );
279    write_xp  = XPTR( tty_cxy , base + TTY_WRITE );
280    read_xp   = XPTR( tty_cxy , base + TTY_READ );
281
282    // get TTY_STATUS register value
283    status = hal_remote_lw( status_xp );
284
285    // 1. handle RX if TTY_READ buffer full
286    if( status & TTY_STATUS_RX_FULL )   
287    {
288        // get a byte from TTY_READ / acknowledge RX_IRQ
289        byte = (char)hal_remote_lb( read_xp );
290
291        // check character value
292        if( byte == 0x1A )          // ^Z  =>  stop onwner process
293        {
294            // get pid of terminal owner process
295            pid = process_get_txt_owner( channel );
296
297            // get cluster and pointers on owner process descriptor
298            owner_xp  = cluster_get_owner_process_from_pid( pid );
299            owner_cxy = GET_CXY( owner_xp );
300            owner_ptr = GET_PTR( owner_xp );
301
302            // send stop signal to owner process
303            process_sigaction( pid , BLOCK_ALL_THREADS );
304               
305            // atomically update owner process termination state
306            hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
307                                  PROCESS_TERM_STOP );
308            return;
309        }
310        else if( byte == 0x03 )     // ^C  => kill owner process
311        {
312            // get pid of terminal owner process
313            pid = process_get_txt_owner( channel );
314
315            // get cluster and pointers on owner process descriptor
316            owner_xp  = cluster_get_owner_process_from_pid( pid );
317            owner_cxy = GET_CXY( owner_xp );
318            owner_ptr = GET_PTR( owner_xp );
319
320            // send kill signal to owner process
321            process_sigaction( pid , DELETE_ALL_THREADS );
322               
323            // atomically update owner process termination state
324            hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
325                                  PROCESS_TERM_KILL );
326            return;
327        }
328        else if( type == TXT_READ ) // pending TXT_READ
329        {
330            // write character to command buffer
331            hal_remote_sb( buf_xp , byte );
332
333            // set I/O operation status in command
334            hal_remote_sw( error_xp , 0 );
335
336            // unblock server thread
337            thread_unblock( XPTR( local_cxy , chdev->server ) , THREAD_BLOCKED_DEV_ISR );
338        }
339    }
340
341    // 3. handle TX if TXT_WRITE
342    if( type == TXT_WRITE )
343    {
344        // loop on characters
345        for( i = 0 ; i < count ; i++ )
346        {
347            // get TTY_STATUS
348            status = hal_remote_lw( status_xp );
349
350            if( (status & TTY_STATUS_TX_FULL) == 0 ) // TTY_TX empty => move one byte
351            {
352                // get one byte from command buffer
353                byte = (char)hal_remote_lb( buf_xp + i );
354
355                // write byte to TTY_WRITE / acknowledge TX_IRQ
356                hal_remote_sb( write_xp , byte );
357            }
358            else         // TTY_TX full => update command arguments and exit ISR for retry
359            {
360                hal_remote_sw ( XPTR( client_cxy , &client_ptr->txt_cmd.count ), count-i );
361                hal_remote_swd( XPTR( client_cxy , &client_ptr->txt_cmd.buf_xp ), buf_xp+i );
362                return;
363            }
364        }
365
366        // set I/O operation status in command
367        hal_remote_sw( error_xp , 0 );
368
369        // disable TX_IRQ
370        hal_remote_sw( XPTR( tty_cxy , base + TTY_TX_IRQ_ENABLE ) , 0 );
371
372        // unblock server thread
373        thread_unblock( XPTR( local_cxy , chdev->server ) , THREAD_BLOCKED_DEV_ISR );
374    }
375
376    hal_fence();
377
378#if CONFIG_DEBUG_HAL_TXT
379cycle = (uint32_t)hal_get_cycles();
380if (CONFIG_DEBUG_HAL_TXT < cycle)
381printk("\n[DBG] %s : exit after %s / cycle %d\n",
382__FUNCTION__ , dev_txt_type_str( type ) , cycle );
383#endif
384
385#if (CONFIG_DEBUG_SYS_READ & 1)
386if( type == TXT_READ) exit_tty_isr_read = (uint32_t)hal_get_cycles();
387#endif
388
389#if (CONFIG_DEBUG_SYS_WRITE & 1)
390if( type == TXT_WRITE) exit_tty_isr_write = (uint32_t)hal_get_cycles();
391#endif
392
393}  // end soclib_tty_isr()
394
Note: See TracBrowser for help on using the repository browser.