source: trunk/hal/tsar_mips32/drivers/soclib_dma.c

Last change on this file was 657, checked in by alain, 5 years ago

Introduce remote_buf.c/.h & socket.c/.h files.
Update dev_nic.c/.h files.

File size: 8.2 KB
Line 
1/*
2 * soclib_dma.c - soclib Multi Channels DMA driver implementation
3 *
4 * Author     Alain Greiner (2017,2018,2019,2020)
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 <hal_kernel_types.h>
25#include <chdev.h>
26#include <dev_dma.h>
27#include <thread.h>
28#include <soclib_dma.h>
29
30///////////////////////////////////////
31void soclib_dma_init( chdev_t * chdev )
32{
33    // get hardware device cluster and local pointer
34    cxy_t      dma_cxy  = GET_CXY( chdev->base );
35    uint32_t * dma_ptr  = (uint32_t *)GET_PTR( chdev->base );
36
37    // set driver specific fields in chdev descriptor
38    chdev->cmd = &soclib_dma_cmd;
39    chdev->isr = &soclib_dma_isr;
40
41    // disable interrupts
42        hal_remote_s32( XPTR( dma_cxy , dma_ptr + DMA_IRQ_DISABLED ) , 1 );
43
44} // soclib_dma_init()
45
46//////////////////////////////////////////////////////////////////
47void __attribute__ ((noinline)) soclib_dma_cmd( xptr_t thread_xp )
48{
49    bool_t     sync;
50    xptr_t     dev_xp;       // extended pointer on DMA devive
51    xptr_t     dst_xp;       // extended pointer on destination buffer
52    xptr_t     src_xp;       // extended pointer on source buffer
53    uint32_t   size;         // buffer size
54    uint32_t   status;       // DMA status
55
56    // get client thread cluster and local pointer
57    cxy_t      client_cxy = GET_CXY( thread_xp );
58    thread_t * client_ptr = (thread_t *)GET_PTR( thread_xp );
59
60#if (DEBUG_HAL_IOC_RX || DEBUG_HAL_IOC_TX)
61uint32_t    cycle        = (uint32_t)hal_get_cycles();
62thread_t  * this         = CURRENT_THREAD;
63process_t * process      = hal_remote_lpt( XPTR( th_cxy , &th_ptr->process ) );
64pid_t       client_pid   = hal_remote_l32( XPTR( th_cxy , &process->pid ) );
65trdid_t     client_trdid = hal_remote_l32( XPTR( th_cxy , &th_ptr->trdid ) );
66#endif
67
68// TODO both the client and the server threads are allways local,
69// we could replace all these remote accesses by local accesses !!!  [AG]
70
71    // get command arguments and extended pointer on DMA device descriptor
72    sync   =         hal_remote_l32( XPTR( client_cxy , &client_ptr->dma_cmd.sync   ) );
73    dev_xp = (xptr_t)hal_remote_l64( XPTR( client_cxy , &client_ptr->dma_cmd.dev_xp ) );
74    dst_xp = (xptr_t)hal_remote_l64( XPTR( client_cxy , &client_ptr->dma_cmd.dst_xp ) );
75    src_xp = (xptr_t)hal_remote_l64( XPTR( client_cxy , &client_ptr->dma_cmd.src_xp ) );
76    size   =         hal_remote_l32( XPTR( client_cxy , &client_ptr->dma_cmd.size   ) );
77
78    // get DMA device cluster and local pointer
79    cxy_t     dev_cxy = GET_CXY( dev_xp );
80    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
81
82    // get pointers on DMA peripheral
83    xptr_t     dma_xp  = hal_remote_l32( XPTR( dev_cxy , &dev_ptr->base ) );
84    cxy_t      dma_cxy = GET_CXY( dma_xp );
85    uint32_t * dma_ptr = GET_PTR( dma_xp );
86
87    // get DMA channel index and channel base address
88    uint32_t * base = dma_ptr + DMA_SPAN * dev_ptr->channel;
89
90    // split dst and src buffers addresses in two 32 bits words
91    uint32_t   dst_lsb = (uint32_t)(dst_xp);
92    uint32_t   dst_msb = (uint32_t)(dst_xp>>32);
93    uint32_t   src_lsb = (uint32_t)(src_xp);
94    uint32_t   src_msb = (uint32_t)(src_xp>>32);
95
96    // set SOCLIB_DMA registers and launch tranfer operation
97    hal_remote_s32( XPTR( dma_cxy , base + DMA_SRC     ) , src_lsb ); 
98    hal_remote_s32( XPTR( dma_cxy , base + DMA_SRC_EXT ) , src_msb ); 
99    hal_remote_s32( XPTR( dma_cxy , base + DMA_DST     ) , dst_lsb );
100    hal_remote_s32( XPTR( dma_cxy , base + DMA_DST_EXT ) , dst_msb );
101    hal_remote_s32( XPTR( dma_cxy , base + DMA_LEN_STS ) , size    );
102
103 #if DEBUG_HAL_DMA
104if( DEBUG_HAL_DMA < cycle )
105printk("\n[%s] thread[%x,%x] launched DMA for client thread[%x,%x] / cycle %d\n",
106__FUNCTION__, this->process->pid, this->trdid, client_pid, client_trdid, cycle );
107#endif
108
109    // waiting policy  depends on the command type
110    // - for an asynchronous command, this function is called by the server thread
111    //   => block and deschedule after launching the transfer.
112    //   The operation status is reported in the command by the ISR, and the
113    //   server thread is re-activated by the ISR.
114    // - for a synchronous command, this function is called by the client thread
115    //   => mask the DMA_IRQ and poll the DMA status register until transfer completion,
116    //   and reports status in the command when the transfer is completed.
117
118    if( sync )                            // client thread poll status until completion
119    {
120        while( 1 )
121        {
122            status = hal_remote_l32( XPTR( dma_cxy , base + DMA_LEN_STS ) );
123
124            if( (status == DMA_SUCCESS) || (status == DMA_IDLE) )
125            {
126                // set operation status in command
127                hal_remote_s32( XPTR( client_cxy , &client_ptr->dma_cmd.error ) , 0 );
128
129#if DEBUG_HAL_DMA
130cycle = (uint32_t)hal_get_cycles();
131if( DEBUG_HAL_DMA < cycle )
132printk("\n[%s] thread[%x,%x] exit after SYNC success / cycle %d\n",
133__FUNCTION__, this->process->pid, this->trdid, cycle );
134#endif
135                // exit while
136                break;
137            }
138            else if( (status == DMA_ERROR_READ) || (status == DMA_ERROR_WRITE) )
139            {
140                // set operation status in command
141                hal_remote_s32( XPTR( client_cxy , &client_ptr->dma_cmd.error ) , 1 );
142
143#if DEBUG_HAL_DMA
144cycle = (uint32_t)hal_get_cycles();
145if( DEBUG_HAL_DMA < cycle )
146printk("\n[%s] thread[%x,%x] exit after SYNC failure / cycle %d\n",
147__FUNCTION__, this->process->pid, this->trdid, cycle );
148#endif
149                // exit while
150                break;
151            }
152        }
153    }   
154    else                                // server thread block and deschedule
155    {
156        // server thread blocks on ISR
157        thread_block( XPTR( local_cxy , CURRENT_THREAD ) , THREAD_BLOCKED_ISR );
158
159        // enable DMA interrupts
160            hal_remote_s32( XPTR( dma_cxy , dma_ptr + DMA_IRQ_DISABLED ) , 0 );
161
162        // server thread deschedules
163        sched_yield("blocked on ISR");
164
165        // disable DMA interrupts
166            hal_remote_s32( XPTR( dma_cxy , dma_ptr + DMA_IRQ_DISABLED ) , 1 );
167
168#if DEBUG_HAL_DMA
169cycle = (uint32_t)hal_get_cycles();
170if( DEBUG_HAL_DMA < cycle )
171printk("\n[%s] thread[%x,%x] exit after ASYNC / client thread[%x,%x] / cycle %d\n",
172__FUNCTION__ , this->process->pid, this->trdid, client_pid, client_trdid, cycle );
173#endif
174
175    }
176} // soclib_dma_cmd()
177
178/////////////////////////////////////////////////////////////////
179void __attribute__ ((noinline)) soclib_dma_isr( chdev_t * chdev )
180{
181    // get extended pointer on server thread
182    xptr_t server_xp = XPTR( local_cxy , &chdev->server );
183
184   // get extended pointer on client thread
185    xptr_t root      = XPTR( local_cxy , &chdev->wait_root );
186    xptr_t client_xp = XLIST_FIRST( root , thread_t , wait_list );
187
188    // get client thread cluster and local pointer
189    cxy_t      client_cxy = GET_CXY( client_xp );
190    thread_t * client_ptr = (thread_t *)GET_PTR( client_xp );
191
192    // get SOCLIB_DMA peripheral cluster and local pointer
193    cxy_t      dma_cxy  = GET_CXY( chdev->base );
194    uint32_t * dma_ptr  = (uint32_t *)GET_PTR( chdev->base );
195
196    // build DMA channel base address
197    uint32_t * base = dma_ptr + (DMA_SPAN * chdev->channel);
198
199    // get DMA status register
200        uint32_t status = hal_remote_l32( XPTR( dma_cxy , base + DMA_LEN_STS ) );   
201
202    // acknowledge IRQ
203    hal_remote_s32( XPTR( dma_cxy , base + DMA_RESET ) , 0 );
204
205    // set operation status in command
206        error_t  error = ( status != DMA_SUCCESS ); 
207    hal_remote_s32( XPTR( client_cxy , &client_ptr->dma_cmd.error ) , error );
208
209    // unblock server thread
210    thread_unblock( server_xp , THREAD_BLOCKED_ISR );
211
212} // soclib_dma_isr()
213
214
215
Note: See TracBrowser for help on using the repository browser.