source: trunk/hal/tsar_mips32/drivers/soclib_mtty.c @ 533

Last change on this file since 533 was 533, checked in by nicolas.van.phan@…, 6 years ago

Add untested multi_tty driver

File size: 20.3 KB
RevLine 
[533]1/*
2 * soclib_mtty.c - soclib tty driver implementation.
3 *
4 * Author  Alain Greiner (2016,2017,2018)
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
25#include <hal_kernel_types.h>
26#include <dev_txt.h>
27#include <chdev.h>
28#include <soclib_mtty.h>
29#include <remote_spinlock.h>
30#include <thread.h>
31#include <printk.h>
32#include <hal_special.h>
33
34#if (DEBUG_SYS_READ & 1)
35extern uint32_t  enter_tty_cmd_read;
36extern uint32_t  exit_tty_cmd_read;
37
38extern uint32_t  enter_tty_isr_read;
39extern uint32_t  exit_tty_isr_read;
40#endif
41
42#if (DEBUG_SYS_WRITE & 1)
43extern uint32_t  enter_tty_cmd_write;
44extern uint32_t  exit_tty_cmd_write;
45
46extern uint32_t  enter_tty_isr_write;
47extern uint32_t  exit_tty_isr_write;
48#endif
49
50////////////////////////////////////////////////////////////////////////////////////
51// These global variables implement the MTTY_RX  FIFOs (one per channel)
52////////////////////////////////////////////////////////////////////////////////////
53
54__attribute__((section(".kdata")))
55tty_fifo_t  tty_rx_fifo[CONFIG_MAX_TXT_CHANNELS];
56
57__attribute__((section(".kdata")))
58tty_fifo_t  tty_tx_fifo[CONFIG_MAX_TXT_CHANNELS];
59
60///////////////////////////////////////
61void soclib_mtty_init( chdev_t * chdev )
62{
63    xptr_t reg_xp;
64
65    // initialise function pointers in chdev
66    chdev->cmd = &soclib_mtty_cmd;
67    chdev->isr = &soclib_mtty_isr;
68    chdev->aux = &soclib_mtty_aux;
69
70    // get TTY channel and extended pointer on TTY peripheral base address
71    xptr_t   tty_xp  = chdev->base;
72    uint32_t channel = chdev->channel;
73    bool_t   is_rx   = chdev->is_rx;
74
75    // get SOCLIB_TTY device cluster and local pointer
76    cxy_t      tty_cxy = GET_CXY( tty_xp );
77    uint32_t * tty_ptr = GET_PTR( tty_xp );
78
79    // enable interruptions for RX but not for TX
80    reg_xp = XPTR( tty_cxy , tty_ptr + (channel * MTTY_SPAN) + MTTY_CONFIG );
81    hal_remote_sw( reg_xp , MTTY_CONFIG_RX_ENABLE );
82
83    // reset relevant FIFO
84    if( is_rx )
85    {
86        tty_rx_fifo[channel].sts = 0;
87        tty_rx_fifo[channel].ptr = 0;
88        tty_rx_fifo[channel].ptw = 0;
89    }
90    else
91    {
92        tty_tx_fifo[channel].sts = 0;
93        tty_tx_fifo[channel].ptr = 0;
94        tty_tx_fifo[channel].ptw = 0;
95    }
96}  // end soclib_mtty_init()
97
98//////////////////////////////////////////////////////////////
99void __attribute__ ((noinline)) soclib_mtty_cmd( xptr_t th_xp )
100{
101    tty_fifo_t * fifo;     // MTTY_RX or MTTY_TX FIFO
102    char         byte;     // byte value
103    uint32_t     done;     // number of bytes moved
104
105    // get client thread cluster and local pointer
106    cxy_t      th_cxy = GET_CXY( th_xp );
107    thread_t * th_ptr = GET_PTR( th_xp );
108
109    // get command arguments
110    uint32_t type     = hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.type   ) );
111    xptr_t   buf_xp   = hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.buf_xp ) );
112    uint32_t count    = hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.count  ) );
113    xptr_t   error_xp = XPTR( th_cxy , &th_ptr->txt_cmd.error );
114
115#if (DEBUG_SYS_READ & 1)
116if( type == TXT_READ) enter_tty_cmd_read = (uint32_t)hal_get_cycles();
117#endif
118
119#if (DEBUG_SYS_WRITE & 1)
120if( type == TXT_WRITE) enter_tty_cmd_write = (uint32_t)hal_get_cycles();
121#endif
122
123    // get TXT device cluster and pointers
124    xptr_t     dev_xp = (xptr_t)hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.dev_xp ) );
125    cxy_t      dev_cxy = GET_CXY( dev_xp );
126    chdev_t  * dev_ptr = GET_PTR( dev_xp );
127
128    // get cluster and pointers for SOCLIB_TTY peripheral base segment
129    xptr_t     tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
130    cxy_t      tty_cxy = GET_CXY( tty_xp );
131    uint32_t * tty_ptr = GET_PTR( tty_xp );
132
133    // get TTY channel index and channel base address
134    uint32_t   channel = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->channel ) );
135    uint32_t * base    = tty_ptr + MTTY_SPAN * channel;
136
137    ///////////////////////
138    if( type == TXT_WRITE )         // write bytes to MTTY_TX FIFO
139    {
140        fifo = &tty_tx_fifo[channel];
141
142        done = 0;
143
144        while( done < count )
145        {
146            if( fifo->sts < MTTY_FIFO_DEPTH )   // put one byte to FIFO if TX_FIFO not full
147            {
148                // get one byte from command buffer
149                byte = hal_remote_lb( buf_xp + done );
150
151#if DEBUG_HAL_TXT_TX
152uint32_t tx_cycle = (uint32_t)hal_get_cycles();
153if( DEBUG_HAL_TXT_TX < tx_cycle )
154printk("\n[DBG] %s : thread %x put character <%c> to TXT%d_TX fifo / cycle %d\n",
155__FUNCTION__, CURRENT_THREAD, byte, channel, tx_cycle );
156#endif
157                // write byte to FIFO
158                fifo->data[fifo->ptw] = byte;
159
160                // prevent race
161                hal_fence();
162
163                // update FIFO state
164                fifo->ptw = (fifo->ptw + 1) % MTTY_FIFO_DEPTH;
165                hal_atomic_add( &fifo->sts , 1 );
166
167                // udate number of bytes moved
168                done++;
169
170                // enable TX_IRQ
171                xptr_t config_xp = XPTR( tty_cxy , base + MTTY_CONFIG );
172                uint32_t old = hal_remote_lw( config_xp );
173                uint32_t new = old | MTTY_CONFIG_TX_ENABLE;
174                hal_remote_atomic_cas( config_xp , old , new );
175            }
176            else                                // block & deschedule if TX_FIFO full
177            {
178                // block on ISR
179                thread_block( XPTR( local_cxy , CURRENT_THREAD ) , THREAD_BLOCKED_ISR );
180
181                // deschedule
182                sched_yield( "MTTY_TX_FIFO full" ); 
183            }
184        }
185
186        // set error status in command and return
187        hal_remote_sw( error_xp , 0 );
188    }
189    ///////////////////////////
190    else if( type == TXT_READ )       // read bytes from MTTY_RX FIFO   
191    {
192        fifo = &tty_rx_fifo[channel];
193
194        done = 0;
195
196        while( done < count )
197        {
198            if( fifo->sts > 0 )               // get byte from FIFO if not empty
199            {
200                // get one byte from FIFO
201                char byte = fifo->data[fifo->ptr];
202
203#if DEBUG_HAL_TXT_RX
204uint32_t rx_cycle = (uint32_t)hal_get_cycles();
205if( DEBUG_HAL_TXT_RX < rx_cycle )
206printk("\n[DBG] %s : thread %x get character <%c> from TXT%d_RX fifo / cycle %d\n",
207__FUNCTION__, CURRENT_THREAD, byte, channel, rx_cycle );
208#endif
209                // update FIFO state
210                fifo->ptr = (fifo->ptr + 1) % MTTY_FIFO_DEPTH;
211                hal_atomic_add( &fifo->sts , -1 );
212
213                // set byte to command buffer
214                hal_remote_sb( buf_xp + done , byte );
215
216                // udate number of bytes
217                done++;
218            }
219            else                             //  deschedule if FIFO empty
220            {
221                // block on ISR
222                thread_block( XPTR( local_cxy , CURRENT_THREAD ) , THREAD_BLOCKED_ISR );
223   
224                // deschedule
225                sched_yield( "MTTY_RX_FIFO empty" );
226            }
227        }  // end while
228
229        // set error status in command
230        hal_remote_sw( error_xp , 0 );
231    }
232    else
233    {
234        assert( false , __FUNCTION__ , "illegal TXT command\n" );
235    }
236
237#if (DEBUG_SYS_READ & 1)
238if( type == TXT_READ ) exit_tty_cmd_read = (uint32_t)hal_get_cycles();
239#endif
240
241#if (DEBUG_SYS_WRITE & 1)
242if( type == TXT_WRITE ) exit_tty_cmd_write = (uint32_t)hal_get_cycles();
243#endif
244
245}  // end soclib_mtty_cmd()
246
247/////////////////////////////////////////////////////////////////
248void __attribute__ ((noinline)) soclib_mtty_isr( chdev_t * chdev )
249{
250    thread_t   * server;            // pointer on TXT chdev server thread
251    lid_t        server_lid;        // local index of core running the server thread
252    uint32_t     channel;           // TXT chdev channel
253    bool_t       is_rx;             // TXT chdev direction
254    char         byte;              // byte value
255    xptr_t       owner_xp;          // extended pointer on TXT owner process
256    cxy_t        owner_cxy;         // TXT owner process cluster
257    process_t  * owner_ptr;         // local pointer on TXT owner process
258    pid_t        owner_pid;         // TXT owner process identifier
259    tty_fifo_t * fifo;              // pointer on MTTY_TX or MTTY_RX FIFO
260    cxy_t        tty_cxy;           // soclib_mtty cluster
261    uint32_t   * tty_ptr;           // soclib_mtty segment base address
262    uint32_t   * base;              // soclib_mtty channel base address
263    xptr_t       status_xp;         // extended pointer on MTTY_STATUS register
264    xptr_t       write_xp;          // extended pointer on MTTY_WRITE register
265    xptr_t       read_xp;           // extended pointer on MTTY_READ register
266    xptr_t       parent_xp;         // extended pointer on parent process
267    cxy_t        parent_cxy;        // parent process cluster
268    process_t  * parent_ptr;        // local pointer on parent process
269    xptr_t       children_lock_xp;  // extended pointer on children processes lock
270    thread_t   * parent_main_ptr;   // extended pointer on parent process main thread
271    xptr_t       parent_main_xp;    // local pointer on parent process main thread
272
273    // get TXT chdev channel, direction and server thread
274    channel    = chdev->channel;
275    is_rx      = chdev->is_rx;
276    server     = chdev->server;
277    server_lid = server->core->lid;
278
279#if (DEBUG_SYS_READ & 1)
280if( is_rx ) enter_tty_isr_read = (uint32_t)hal_get_cycles();
281#endif
282
283#if (DEBUG_SYS_WRITE & 1)
284if( is_rx == 0 ) enter_tty_isr_write = (uint32_t)hal_get_cycles();
285#endif
286
287#if DEBUG_HAL_TXT_RX
288uint32_t rx_cycle = (uint32_t)hal_get_cycles();
289#endif
290
291#if DEBUG_HAL_TXT_TX
292uint32_t tx_cycle = (uint32_t)hal_get_cycles();
293#endif
294
295    // get SOCLIB_TTY peripheral cluster and local pointer
296    tty_cxy = GET_CXY( chdev->base );
297    tty_ptr = GET_PTR( chdev->base );
298
299    // get channel base address
300    base    = tty_ptr + MTTY_SPAN * channel;
301
302    // get extended pointer on TTY registers
303    status_xp = XPTR( tty_cxy , base + MTTY_STATUS );
304    write_xp  = XPTR( tty_cxy , base + MTTY_WRITE );
305    read_xp   = XPTR( tty_cxy , base + MTTY_READ );
306
307    /////////////////////////// handle RX //////////////////////
308    if( is_rx )
309    {
310        fifo = &tty_rx_fifo[channel];
311
312        // try to move bytes until MTTY_READ register empty
313        while( hal_remote_lw( status_xp ) & MTTY_STATUS_RX_FULL )   
314        {
315            // get one byte from MTTY_READ register & acknowledge RX_IRQ
316            byte = (char)hal_remote_lb( read_xp );
317
318            // filter special character ^Z  => block TXT owner process
319            if( byte == 0x1A ) 
320            {
321
322#if DEBUG_HAL_TXT_RX
323if( DEBUG_HAL_TXT_RX < rx_cycle )
324printk("\n[DBG] %s : read ^Z character from TXT%d\n", __FUNCTION__, channel );
325#endif
326                // get pointers on TXT owner process in owner cluster
327                owner_xp  = process_txt_get_owner( channel );
328               
329                // check process exist
330                assert( (owner_xp != XPTR_NULL) , __FUNCTION__, 
331                "TXT owner process not found\n" );
332
333                // get relevant infos on TXT owner process
334                owner_cxy = GET_CXY( owner_xp );
335                owner_ptr = GET_PTR( owner_xp );
336                owner_pid = hal_remote_lw( XPTR( owner_cxy , &owner_ptr->pid ) );
337
338                // block TXT owner process only if it is not the INIT process
339                if( owner_pid != 1 )
340                {
341                    // get parent process descriptor pointers
342                    parent_xp  = hal_remote_lwd( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
343                    parent_cxy = GET_CXY( parent_xp );
344                    parent_ptr = GET_PTR( parent_xp );
345
346                    // get extended pointer on lock protecting children list in parent process
347                    children_lock_xp = XPTR( parent_cxy , &parent_ptr->children_lock ); 
348
349                    // get pointers on the parent process main thread
350                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
351                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
352
353                    // transfer TXT ownership
354                    process_txt_transfer_ownership( owner_xp );
355
356                    // block all threads in all clusters, but the main thread
357                    process_sigaction( owner_pid , BLOCK_ALL_THREADS );
358
359                    // block the main thread
360                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
361                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
362
363                    // atomically update owner process termination state
364                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
365                                          PROCESS_TERM_STOP );
366
367                    // take the children lock and unblock the parent process main thread
368                    remote_spinlock_lock( children_lock_xp );
369                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
370                    remote_spinlock_unlock( children_lock_xp );
371
372                    return;
373                }
374            }
375
376            // filter special character ^C  => kill TXT owner process
377            if( byte == 0x03 )
378            {
379
380#if DEBUG_HAL_TXT_RX
381if( DEBUG_HAL_TXT_RX < rx_cycle )
382printk("\n[DBG] %s : read ^C character from TXT%d\n", __FUNCTION__, channel );
383#endif
384                // get pointer on TXT owner process in owner cluster
385                owner_xp  = process_txt_get_owner( channel );
386
387                // check process exist
388                assert( (owner_xp != XPTR_NULL) , __FUNCTION__,
389                "TXT owner process not found\n" );
390
391                // get relevant infos on TXT owner process
392                owner_cxy = GET_CXY( owner_xp );
393                owner_ptr = GET_PTR( owner_xp );
394                owner_pid = hal_remote_lw( XPTR( owner_cxy , &owner_ptr->pid ) );
395
396                // kill TXT owner process only if it is not the INIT process
397                if( owner_pid != 1 )
398                {
399                    // get parent process descriptor pointers
400                    parent_xp  = hal_remote_lwd( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
401                    parent_cxy = GET_CXY( parent_xp );
402                    parent_ptr = GET_PTR( parent_xp );
403
404                    // get extended pointer on lock protecting children list in parent process
405                    children_lock_xp = XPTR( parent_cxy , &parent_ptr->children_lock ); 
406
407                    // get pointers on the parent process main thread
408                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
409                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
410
411                    // remove process from TXT list
412                    process_txt_detach( owner_xp );
413
414                    // mark for delete all thread in all clusters, but the main
415                    process_sigaction( owner_pid , DELETE_ALL_THREADS );
416               
417                    // block main thread
418                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
419                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
420
421                    // atomically update owner process termination state
422                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
423                                          PROCESS_TERM_KILL );
424
425                    // take the children lock and unblock the parent process main thread
426                    remote_spinlock_lock( children_lock_xp );
427                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
428                    remote_spinlock_unlock( children_lock_xp );
429
430                    return;
431                }
432            }
433
434            // write byte in MTTY_RX FIFO if not full / discard byte if full
435            if ( fifo->sts < MTTY_FIFO_DEPTH )
436            {
437
438#if DEBUG_HAL_TXT_RX
439if( DEBUG_HAL_TXT_RX < rx_cycle )
440printk("\n[DBG] %s : put character <%c> to TXT%d_RX fifo\n",
441__FUNCTION__, byte, channel );
442#endif
443                // store byte into FIFO
444                fifo->data[fifo->ptw] = (char)byte; 
445
446                // avoid race
447                hal_fence();
448
449                // update RX_FIFO state
450                fifo->ptw = (fifo->ptw + 1) % MTTY_FIFO_DEPTH;
451                hal_atomic_add( &fifo->sts , 1 );
452
453                // unblock TXT_RX server thread
454                thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
455
456                // send IPI to core running server thread
457                dev_pic_send_ipi( local_cxy , server_lid );
458            }
459            else
460            {
461                printk("\n[WARNING] %s : MTTY_RX_FIFO[%d] full => discard character <%x>\n",
462                __FUNCTION__, channel, (uint32_t)byte );
463            }
464        }  // end while MTTY_READ register full
465
466    }  // end RX
467
468    ///////////////////////  handle TX  /////////////////////////////
469    else
470    {
471        fifo = &tty_tx_fifo[channel];
472
473        // try to move bytes until TX_FIFO empty
474        while( fifo->sts > 0 )
475        {
476            // write one byte to MTTY_WRITE register if empty / exit loop if full
477            if( (hal_remote_lw( status_xp ) & MTTY_STATUS_TX_FULL) == 0 ) 
478            {
479                // get one byte from TX_FIFO
480                byte = fifo->data[fifo->ptr];
481
482#if DEBUG_HAL_TXT_TX
483if( DEBUG_HAL_TXT_TX < tx_cycle )
484printk("\n[DBG] %s : get character <%c> from TXT%d_TX fifo\n",
485__FUNCTION__, byte, channel );
486#endif
487                // update TX_FIFO state
488                fifo->ptr = (fifo->ptr + 1) % MTTY_FIFO_DEPTH;
489                hal_atomic_add( &fifo->sts , -1 );
490
491                // write byte to MTTY_WRITE register & acknowledge TX_IRQ
492                hal_remote_sb( write_xp , byte );
493            }
494        }
495
496        // disable TX_IRQ
497        xptr_t config_xp = XPTR( tty_cxy , base + MTTY_CONFIG );
498        uint32_t old = hal_remote_lw( config_xp );
499        uint32_t new = old & ~(MTTY_CONFIG_TX_ENABLE);
500        hal_remote_atomic_cas( config_xp , old , new );
501        //hal_remote_sw( XPTR( tty_cxy , base + MTTY_TX_IRQ_ENABLE ) , 0 );
502
503        // unblock TXT_TX server thread
504        thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
505
506        // send IPI to core running server thread
507        dev_pic_send_ipi( local_cxy , server_lid );
508
509    }  // end TX
510
511    hal_fence();
512
513#if (DEBUG_SYS_READ & 1)
514if( is_rx ) exit_tty_isr_read = (uint32_t)hal_get_cycles();
515#endif
516
517#if (DEBUG_SYS_WRITE & 1)
518if( is_rx == 0 ) exit_tty_isr_write = (uint32_t)hal_get_cycles();
519#endif
520
521}  // end soclib_mtty_isr()
522
523/////////////////////////////////////////////////////////////
524void __attribute__ ((noinline)) soclib_mtty_aux( void * args )
525{
526    uint32_t   status;
527    bool_t     empty;
528    uint32_t   i;
529
530    xptr_t     dev_xp = ((txt_sync_args_t *)args)->dev_xp;
531    char     * buffer = ((txt_sync_args_t *)args)->buffer;
532    uint32_t   count  = ((txt_sync_args_t *)args)->count;
533   
534    // get TXT0 chdev cluster and local pointer
535    cxy_t     dev_cxy = GET_CXY( dev_xp );
536    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
537
538    // get extended pointer on TTY channel base address
539    xptr_t tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
540
541    // get TTY channel segment cluster and local pointer
542    cxy_t      tty_cxy = GET_CXY( tty_xp );
543    uint32_t * tty_ptr = (uint32_t *)GET_PTR( tty_xp );
544
545    // get extended pointers on MTTY_WRITE & MTTY_STATUS registers
546    xptr_t write_xp  = XPTR( tty_cxy , tty_ptr + MTTY_WRITE );
547    xptr_t status_xp = XPTR( tty_cxy , tty_ptr + MTTY_STATUS );
548
549    // loop on characters (busy waiting policy)
550    for( i = 0 ; i < count ; i++ )
551    {
552        do
553        {
554            // get MTTY_STATUS
555            status = hal_remote_lw( status_xp );
556            empty  = ( (status & MTTY_STATUS_TX_FULL) == 0 );
557
558            // transfer one byte if TX buffer empty
559            if ( empty )  hal_remote_sb( write_xp , buffer[i] );
560        }
561        while ( empty == false );
562    }
563}  // end soclib_mtty_aux()
564
565
566
Note: See TracBrowser for help on using the repository browser.