Ignore:
Timestamp:
Apr 26, 2017, 2:10:21 PM (7 years ago)
Author:
alain
Message:

Introduce the chdev_t structure in place of device_t.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/drivers/soclib/soclib_dma.c

    r1 r4  
    11/*
    2  * soclib_dma.c - soclib DMA driver
     2 * soclib_dma.c - soclib Multi Channels DMA driver implementation
    33 *
    4  * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
    5  * Copyright (c) 2011,2012 UPMC Sorbonne Universites
     4 * Author     Alain Greiner (2017)
     5
     6 * Copyright (c) UPMC Sorbonne Universites
    67 *
    7  * This file is part of ALMOS-kernel.
     8 * This file is part of ALMOS-MKH.
    89 *
    9  * ALMOS-kernel is free software; you can redistribute it and/or modify it
     10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
    1011 * under the terms of the GNU General Public License as published by
    1112 * the Free Software Foundation; version 2.0 of the License.
    1213 *
    13  * ALMOS-kernel is distributed in the hope that it will be useful, but
     14 * ALMOS-MKH is distributed in the hope that it will be useful, but
    1415 * WITHOUT ANY WARRANTY; without even the implied warranty of
    1516 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     
    1718 *
    1819 * You should have received a copy of the GNU General Public License
    19  * along with ALMOS-kernel; if not, write to the Free Software Foundation,
     20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
    2021 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
    2122 */
    2223
    23 #include <errno.h>
    24 #include <cpu.h>
    25 #include <device.h>
    26 #include <driver.h>
    27 #include <drvdb.h>
    28 #include <kmem.h>
    29 #include <scheduler.h>
     24#include <hal_types.h>
     25#include <chdev.h>
     26#include <dev_dma.h>
    3027#include <thread.h>
    31 #include <task.h>
    32 #include <list.h>
    33 #include <event.h>
    3428#include <soclib_dma.h>
    35 #include <string.h>
    3629
    37 /* DMA mapped registers offset */
    38 #define DMA_SRC_REG          0
    39 #define DMA_DST_REG          1
    40 #define DMA_LEN_REG          2
    41 #define DMA_RESET_REG        3
    42 #define DMA_IRQ_DISABLED     4
     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 );
    4336
    44 struct dma_context_s
     37    // enable interrupts
     38        hal_remote_sw( XPTR( dma_cxy , dma_ptr + DMA_IRQ_DISABLED ) , 0 );
     39
     40} // soclib_dma_init()
     41
     42//////////////////////////////////////////////////////////////////
     43void __attribute__ ((noinline)) soclib_dma_cmd( xptr_t thread_xp )
    4544{
    46         struct list_entry request_queue;
    47         struct wait_queue_s pending;
    48 };
     45    xptr_t     dev_xp;       // extended pointer on DMA devive
     46    xptr_t     dst_xp;       // extended pointer on destination buffer
     47    xptr_t     src_xp;       // extended pointer on source buffer
     48    uint32_t   size;         // buffer size
    4949
    50 static void dma_start_request(struct device_s *dma, dev_request_t *ptr)
     50    // get client thread cluster and local pointer
     51    cxy_t      thread_cxy = GET_CXY( thread_xp );
     52    thread_t * thread_ptr = (thread_t *)GET_PTR( thread_xp );
     53
     54    // get command arguments and extended pointer on DMA device
     55    dev_xp = (xptr_t)hal_remote_lwd( XPTR( thread_cxy , &thread_ptr->command.dma.dev_xp ) );
     56    dst_xp = (xptr_t)hal_remote_lwd( XPTR( thread_cxy , &thread_ptr->command.dma.dst_xp ) );
     57    src_xp = (xptr_t)hal_remote_lwd( XPTR( thread_cxy , &thread_ptr->command.dma.src_xp ) );
     58    size   =         hal_remote_lw ( XPTR( thread_cxy , &thread_ptr->command.dma.size   ) );
     59
     60    // get DMA device cluster and local pointer
     61    cxy_t     dev_cxy = GET_CXY( dev_xp );
     62    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
     63
     64    // get extended pointer on SOCLIB-DMA peripheral
     65    xptr_t     dma_xp = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->base ) );
     66
     67    // get SOCLIB_DMA device cluster and local pointer
     68    cxy_t      dma_cxy = GET_CXY( dma_xp );
     69    uint32_t * dma_ptr = (uint32_t *)GET_PTR( dma_xp );
     70
     71    // get DMA channel index and channel base address
     72    uint32_t * base = dma_ptr + DMA_SPAN * dev_ptr->channel;
     73
     74    // split dst and src buffers addresses in two 32 bits words
     75    uint32_t   dst_lsb = (uint32_t)(dst_xp);
     76    uint32_t   dst_msb = (uint32_t)(dst_xp>>32);
     77    uint32_t   src_lsb = (uint32_t)(src_xp);
     78    uint32_t   src_msb = (uint32_t)(src_xp>>32);
     79
     80    // set SOCLIB_DMA registers to start tranfer operation
     81    hal_remote_sw( XPTR( dma_cxy , base + DMA_SRC     ) , src_lsb );
     82    hal_remote_sw( XPTR( dma_cxy , base + DMA_SRC_EXT ) , src_msb );
     83    hal_remote_sw( XPTR( dma_cxy , base + DMA_DST     ) , dst_lsb );
     84    hal_remote_sw( XPTR( dma_cxy , base + DMA_DST_EXT ) , dst_msb );
     85    hal_remote_sw( XPTR( dma_cxy , base + DMA_LEN     ) , size    );
     86
     87    // Block and deschedule server thread
     88    thread_block( CURRENT_THREAD , THREAD_BLOCKED_DEV_ISR );
     89    sched_yield();
     90   
     91} // soclib_dma_cmd()
     92
     93/////////////////////////////////////////////////////////////////
     94void __attribute__ ((noinline)) soclib_dma_isr( chdev_t * chdev )
    5195{
    52         volatile uint32_t *base = dma->base;
    53         dev_request_t *rq;
     96    // get extended pointer on client thread
     97    xptr_t root      = XPTR( local_cxy , &chdev->wait_root );
     98    xptr_t client_xp = XLIST_FIRST_ELEMENT( root , thread_t , wait_list );
    5499
    55         rq = (ptr->flags & DEV_RQ_NESTED) ? ptr->data : ptr;
     100    // get extended pointer on server thread
     101    xptr_t server_xp = XPTR( local_cxy , &chdev->server );
    56102
    57         base[DMA_SRC_REG]      = (unsigned int)rq->src;
    58         base[DMA_DST_REG]      = (unsigned int)rq->dst;
    59         base[DMA_IRQ_DISABLED] = 0;
    60         base[DMA_LEN_REG]      = rq->count;
    61 }
     103    // get client thread cluster and local pointer
     104    cxy_t      client_cxy = GET_CXY( client_xp );
     105    thread_t * client_ptr = (thread_t *)GET_PTR( client_xp );
    62106
    63 static void dma_irq_handler(struct irq_action_s *action)
    64 {
    65         struct dma_context_s *ctx;
    66         struct device_s *dma;
    67         dev_request_t *rq;
    68         dev_request_t *frag;
    69         dev_request_t *new_rq;
    70         error_t err;
    71         volatile uint32_t *base;
    72         struct thread_s *this;
     107    // get SOCLIB_DMA peripheral cluster and local pointer
     108    cxy_t      dma_cxy  = GET_CXY( chdev->base );
     109    uint32_t * dma_ptr  = (uint32_t *)GET_PTR( chdev->base );
    73110
    74         dma  = action->dev;
    75         base = dma->base;
    76         ctx  = (struct dma_context_s*)dma->data;
     111    // get DMA channel base address
     112    uint32_t * base = dma_ptr + (DMA_SPAN * chdev->channel);
    77113
    78         cpu_spinlock_lock(&dma->lock.val);
    79  
    80         err = base[DMA_LEN_REG];
    81         base[DMA_RESET_REG] = 0;
     114    // get DMA status register
     115        uint32_t status = hal_remote_lw( XPTR( dma_cxy , base + DMA_LEN ) );   
    82116
    83         /* even if this case is realy low probable, we have to check for empty list ! */
    84         if(list_empty(&ctx->request_queue))
    85         {
    86                 cpu_spinlock_unlock(&dma->lock.val);
    87                 return;
    88         }
     117    // acknowledge IRQ
     118    hal_remote_sw( XPTR( dma_cxy , base + DMA_RESET ) , 0 );
    89119
    90         rq = list_first(&ctx->request_queue, dev_request_t, list);
     120    // set operation status in command
     121        error_t  error = ( status != DMA_SUCCESS );
     122    hal_remote_sw( XPTR( client_cxy , &client_ptr->command.dma.error ) , error );
    91123
    92         if(rq->flags & DEV_RQ_NESTED)
    93         {
    94                 frag = rq->data;
     124    // unblock server thread
     125    thread_unblock( server_xp , THREAD_BLOCKED_DEV_ISR );
    95126
    96                 event_set_error(&frag->event, err);
    97                 event_set_senderId(&frag->event, dma);
    98                 event_send(&frag->event, current_cpu->gid);
     127    // unblock client thread
     128    thread_unblock( client_xp , THREAD_BLOCKED_IO );
    99129
    100                 if((err == 0) && (frag->data != NULL))
    101                 {
    102                         rq->data = frag->data;
    103                         dma_start_request(dma,frag->data);
    104                         cpu_spinlock_unlock(&dma->lock.val);
    105                         return;
    106                 }
    107         }
    108 
    109         list_unlink(&rq->list);
    110  
    111         if(!(list_empty(&ctx->request_queue)))
    112         {
    113                 new_rq = list_first(&ctx->request_queue, dev_request_t, list);
    114                 dma_start_request(dma,new_rq);
    115         }
    116  
    117         if(!(rq->flags & DEV_RQ_NOBLOCK))
    118         {
    119                 rq->err = err;
    120                 wakeup_one(&ctx->pending, WAIT_FIRST);
    121                 cpu_spinlock_unlock(&dma->lock.val);
    122                 return;
    123         }
    124  
    125         cpu_spinlock_unlock(&dma->lock.val);
    126 
    127         this = CURRENT_THREAD;
    128  
    129         event_set_error(&rq->event, err);
    130         event_set_senderId(&rq->event, dma);
    131         event_send(&rq->event, current_cpu->gid);
    132 }
    133 
    134 static void dma_fraglist_destroy(dev_request_t *ptr)
    135 {
    136         kmem_req_t req;
    137         dev_request_t *frag;
    138 
    139         req.type = KMEM_DMA_REQUEST;
    140         frag     = ptr;
    141 
    142         while(frag != NULL);
    143         {
    144                 req.ptr = frag;
    145                 frag    = frag->data;
    146 
    147                 kmem_free(&req);
    148         }
    149 }
    150 
    151 static EVENT_HANDLER(dma_async_frag_event)
    152 {
    153         dev_request_t *frag;
    154         kmem_req_t req;
    155         error_t err;
    156 
    157         frag = event_get_argument(event);
    158         err  = event_get_error(event);
    159 
    160         assert(frag != NULL && "corrupted frag");
    161 
    162         if(err)
    163         {
    164                 dma_fraglist_destroy(frag);
    165                 return 0;
    166         }
    167 
    168         req.type = KMEM_DMA_REQUEST;
    169         req.ptr  = frag;
    170 
    171         kmem_free(&req);
    172         return 0;
    173 }
    174 
    175 static error_t dma_frag_init(dev_request_t *frag, uint_t src_start, uint_t dst_start, uint_t count)
    176 {
    177         //FIXME(40) use extent registers
    178         frag->src   = task_vaddr2paddr(current_task, (void*)src_start);
    179         frag->dst   = task_vaddr2paddr(current_task, (void*)dst_start);
    180         frag->count = count;
    181         frag->flags = 0;
    182 
    183         if((frag->src == NULL) || (frag->dst == NULL))
    184                 return EPERM;
    185 
    186         event_set_priority(&frag->event, E_FUNC);
    187         event_set_handler(&frag->event, &dma_async_frag_event);
    188         event_set_argument(&frag->event, frag);
    189         return 0;
    190 }
    191 
    192 static error_t dma_fraglist_build(dev_request_t *rq)
    193 {
    194         kmem_req_t req;
    195         dev_request_t *frag;
    196         dev_request_t *parent_frag;
    197         struct slist_entry *root;
    198         struct slist_entry *iter;
    199         uint_t src_start;
    200         uint_t dst_start;
    201         uint_t count;
    202         error_t err;
    203 
    204         if(rq->count == 0)
    205                 return EINVAL;
    206 
    207         src_start = (uint_t)rq->src;
    208         dst_start = (uint_t)rq->dst;
    209 
    210         if((src_start + rq->count) <= ((src_start & ~PMM_PAGE_MASK) + PMM_PAGE_SIZE) &&
    211            (dst_start + rq->count) <= ((dst_start & ~PMM_PAGE_MASK) + PMM_PAGE_SIZE))
    212         {
    213                 //FIXME(40) use extent registers
    214                 rq->src = task_vaddr2paddr(current_task, rq->src);
    215                 rq->dst = task_vaddr2paddr(current_task, rq->dst);
    216 
    217                 if((rq->src == NULL) || (rq->dst == NULL))
    218                         return EPERM;
    219 
    220                 return 0;
    221         }
    222 
    223         if((src_start & PMM_PAGE_MASK) || (dst_start & PMM_PAGE_MASK)) {
    224                 return ENOSYS;
    225         }
    226 
    227         req.type    = KMEM_DMA_REQUEST;
    228         req.size    = sizeof(*rq);
    229         req.flags   = AF_KERNEL;
    230         root        = (struct slist_entry *)&rq->data;
    231         iter        = (struct slist_entry *)&rq->list;
    232         count       = rq->count;
    233         rq->data    = NULL;
    234         rq->flags  &= ~DEV_RQ_NESTED;
    235         parent_frag = rq;
    236 
    237         while(count)
    238         {
    239                 frag = kmem_alloc(&req);
    240 
    241                 if(frag == NULL)
    242                 {
    243                         err = ENOMEM;
    244                         goto fail_nomem;
    245                 }
    246 
    247                 if(count >= PMM_PAGE_SIZE)
    248                 {
    249                         err = dma_frag_init(frag, src_start, dst_start, PMM_PAGE_SIZE);
    250 
    251                         if(err)
    252                                 goto fail_init;
    253 
    254                         src_start += PMM_PAGE_SIZE;
    255                         dst_start += PMM_PAGE_SIZE;
    256                         count     -= PMM_PAGE_SIZE;
    257                 }
    258                 else
    259                 {
    260                         err = dma_frag_init(frag, src_start, dst_start, count);
    261 
    262                         if(err)
    263                                 goto fail_init;
    264 
    265                         count -= count;
    266                 }
    267 
    268                 parent_frag->data = frag;
    269                 frag->data        = NULL;
    270                 parent_frag       = frag;
    271         }
    272 
    273         rq->flags |= DEV_RQ_NESTED;
    274         return 0;
    275 
    276 fail_init:
    277 fail_nomem:
    278         dma_fraglist_destroy(rq->data);
    279         return err;
    280 }
     130} // soclib_dma_isr()
    281131
    282132
    283 static sint_t dma_request(struct device_s *dma, dev_request_t *rq)
    284 {
    285         struct dma_context_s *ctx;
    286         uint_t irq_state;
    287         sint_t err;
    288133
    289         rq->err = 0;
    290         ctx     = (struct dma_context_s*)dma->data;
    291 
    292         err = dma_fraglist_build(rq);
    293 
    294         if(err)
    295                 return err;
    296 
    297         spinlock_lock_noirq(&dma->lock,&irq_state);
    298 
    299         if(list_empty(&ctx->request_queue))
    300         {
    301                 list_add(&ctx->request_queue, &rq->list);
    302                 dma_start_request(dma, rq);
    303         }
    304         else
    305                 list_add_last(&ctx->request_queue, &rq->list);
    306 
    307         if(rq->flags & DEV_RQ_NOBLOCK)
    308         {
    309                 spinlock_unlock_noirq(&dma->lock, irq_state);
    310                 return 0;
    311         }
    312 
    313         wait_on(&ctx->pending, WAIT_LAST);
    314         spinlock_unlock_noirq(&dma->lock,irq_state);
    315         sched_sleep(CURRENT_THREAD);
    316 
    317         return rq->err;
    318 }
    319 
    320 static sint_t dma_open(struct device_s *dma, dev_request_t *rq)
    321 {
    322         return EPERM;
    323 }
    324 
    325 struct device_s *__sys_dma;
    326 static uint_t dma_count = 0;
    327 
    328 error_t soclib_dma_init(struct device_s *dma)
    329 {
    330         kmem_req_t req;
    331         struct dma_context_s *ctx;
    332 
    333         spinlock_init(&dma->lock,"DevDMA (SoCLib)");
    334         dma->type = DEV_BLK;
    335 
    336         dma->action.dev         = dma;
    337         dma->action.irq_handler = &dma_irq_handler;
    338         dma->action.data        = NULL;
    339 
    340         if(dma_count == 0)
    341                 __sys_dma = dma;
    342 
    343         sprintk(dma->name,
    344 #if CONFIG_ROOTFS_IS_VFAT
    345                 "DMA%d"
    346 #else
    347                 "dma%d"
    348 #endif
    349                 ,dma_count++);
    350 
    351         metafs_init(&dma->node, dma->name);
    352  
    353         dma->op.dev.open       = &dma_open;
    354         dma->op.dev.read       = &dma_request;
    355         dma->op.dev.write      = &dma_request;
    356         dma->op.dev.close      = NULL;
    357         dma->op.dev.lseek      = NULL;
    358         dma->op.dev.mmap       = NULL;
    359         dma->op.dev.munmap     = NULL;
    360         dma->op.dev.set_params = NULL;
    361         dma->op.dev.get_params = NULL;
    362         dma->op.drvid          = SOCLIB_DMA_ID;
    363 
    364         req.type  = KMEM_GENERIC;
    365         req.size  = sizeof(*ctx);
    366         req.flags = AF_BOOT | AF_ZERO;
    367  
    368         if((ctx = kmem_alloc(&req)) == NULL)
    369                 return ENOMEM;
    370 
    371         wait_queue_init(&ctx->pending, dma->name);
    372         list_root_init(&ctx->request_queue);
    373         dma->data = (void *)ctx;
    374         return 0;
    375 }
    376 
    377 driver_t soclib_dma_driver = { .init = &soclib_dma_init };
Note: See TracChangeset for help on using the changeset viewer.