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

Last change on this file since 451 was 451, checked in by alain, 3 years ago

Fix a bug in soclib_pic driver (bad separation between IOPIC an LAPIC initialisation)

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