source: soft/giet_vm/sys/drivers.c @ 244

Last change on this file since 244 was 238, checked in by alain, 11 years ago

Major evolution to support physical addresses larger than 32 bits.
The map.xml format has been modified: the vsegs associated to schedulers
are now explicitely defined and mapped in the page tables.

File size: 54.8 KB
RevLine 
[158]1///////////////////////////////////////////////////////////////////////////////////
2// File     : drivers.c
[238]3// Date     : 23/05/2013
[158]4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
[189]7// The drivers.c and drivers.h files are part ot the GIET-VM nano kernel.
[158]8// They contains the drivers for the peripherals available in the SoCLib library:
9// - vci_multi_tty
10// - vci_multi_timer
11// - vci_multi_dma
12// - vci_multi_icu
[203]13// - vci_xicu & vci_multi_icu
[158]14// - vci_gcd
15// - vci_frame_buffer
16// - vci_block_device
17//
[238]18// For the peripherals replicated in each cluster (ICU, TIMER, DMA),
19// the corresponding (virtual) base addresses must be completed by an offset
20// depending on the cluster index.
21//
22// The following global parameter must be defined in the giet_config.h file:
23// - GIET_CLUSTER_INCREMENT
24//
25// The following global parameters must be defined in the hard_config.h file:
[189]26// - NB_CLUSTERS   
27// - NB_PROCS_MAX 
[238]28// - NB_TIM_CHANNELS   
29// - NB_DMA_CHANNELS     
30// - NB_TTY_CHANNELS_MAX   
[158]31//
[218]32// The following virtual base addresses must be defined in the giet_vsegs.ld file:
[158]33// - seg_icu_base
[203]34// - seg_tim_base
[238]35// - seg_dma_base
[158]36// - seg_tty_base
37// - seg_gcd_base
[203]38// - seg_fbf_base
[158]39// - seg_ioc_base
[218]40// - seg_nic_base
[238]41// - seg_cma_base
42// - seg_iob_base
43//
[158]44///////////////////////////////////////////////////////////////////////////////////
45
[166]46#include <vm_handler.h>
[158]47#include <sys_handler.h>
48#include <giet_config.h>
49#include <drivers.h>
50#include <common.h>
51#include <hwr_mapping.h>
52#include <mips32_registers.h>
53#include <ctx_handler.h>
54
55#if !defined(NB_CLUSTERS)
[238]56# error: You must define NB_CLUSTERS in the hard_config.h file
[158]57#endif
[189]58
59#if !defined(NB_PROCS_MAX)
[238]60# error: You must define NB_PROCS_MAX in the hard_config.h file
[189]61#endif
62
63#if (NB_PROCS_MAX > 8)
64# error: NB_PROCS_MAX cannot be larger than 8!
65#endif
66
[238]67#if !defined(GIET_CLUSTER_INCREMENT)
68# error: You must define GIET_CLUSTER_INCREMENT in the giet_config.h file
[158]69#endif
[189]70
[238]71#if !defined(NB_TTY_CHANNELS)
72# error: You must define NB_TTY_CHANNELS in the hard_config.h file
[158]73#endif
74
[238]75#if (NB_TTY_CHANNELS < 1)
76# error: NB_TTY_CHANNELS cannot be smaller than 1!
[165]77#endif
78
[238]79#if !defined(NB_DMA_CHANNELS)
80# error: You must define NB_DMA_CHANNELS in the hard_config.h file
[165]81#endif
82
[238]83#if (NB_DMA_CHANNELS > 8)
84# error: NB_DMA_CHANNELS cannot be smaller than 8!
[165]85#endif
86
[238]87#if !defined(NB_TIM_CHANNELS)
88#define NB_TIM_CHANNELS 0
[189]89#endif
[165]90
[238]91#if ( (NB_TIM_CHANNELS + NB_PROC_MAX) > 32 )
92# error: NB_TIM_CHANNELS + NB_PROCS_MAX cannot be larger than 32
[189]93#endif
[158]94
[238]95#if !defined(NB_IOC_CHANNELS)
96# error: You must define NB_IOC_CHANNELS in the hard_config.h file
[189]97#endif
[158]98
[238]99#if ( NB_IOC_CHANNELS > 8 )
100# error: NB_IOC_CHANNELS cannot be larger than 8
101#endif
102
103#if !defined(NB_NIC_CHANNELS)
104# error: You must define NB_NIC_CHANNELS in the hard_config.h file
105#endif
106
107#if ( NB_NIC_CHANNELS > 8 )
108# error: NB_NIC_CHANNELS cannot be larger than 8
109#endif
110
111#if !defined(NB_CMA_CHANNELS)
112# error: You must define NB_CMA_CHANNELS in the hard_config.h file
113#endif
114
115#if ( NB_CMA_CHANNELS > 8 )
116# error: NB_CMA_CHANNELS cannot be larger than 8
117#endif
118
[215]119#if !defined( USE_XICU )
[238]120# error: You must define USE_XICU in the hard_config.h file
[215]121#endif
[158]122
[215]123#if !defined( IOMMU_ACTIVE )
[238]124# error: You must define IOMMU_ACTIVE in the hard_config.h file
[215]125#endif
126
127
[189]128#define in_unckdata __attribute__((section (".unckdata")))
[169]129
[158]130//////////////////////////////////////////////////////////////////////////////
[228]131//     Timers driver
[158]132//////////////////////////////////////////////////////////////////////////////
[238]133// This peripheral is replicated in all clusters.
[203]134// The timers can be implemented in a vci_timer component or in a vci_xicu
[215]135// component (depending on the USE_XICU parameter).
[203]136// There is one timer (or xicu) component per cluster.
[189]137// There is two types of timers:
138// - "system" timers : one per processor, used for context switch.
139//   local_id in [0, NB_PROCS_MAX-1],
140// - "user" timers : requested by the task in the mapping_info data structure.
[203]141//   For each user timer, the timer_id is stored in the context of the task.
[238]142// The global index is cluster_id * (NB_PROCS_MAX+NB_TIM_CHANNELS) + local_id
[158]143//////////////////////////////////////////////////////////////////////////////
[238]144// The (virtual) base address of the associated segment is:
145//
146//       timer_address = seg_icu_base + cluster_id * GIET_CLUSTER_INCREMENT
147//
148// - cluster id is an explicit argument of all access functions
149// - seg_icu_base must be defined in the giet_vsegs.ld file
150// - GIET_CLUSTER_INCREMENT must be defined in the giet_config.h file
151////////////////////////////////////////////////////////////////////////////////
[158]152
[189]153// User Timer signaling variables
154
[238]155#if (NB_TIM_CHANNELS > 0)
156in_unckdata volatile unsigned char _user_timer_event[NB_CLUSTERS * NB_TIM_CHANNELS] 
157                            = { [0 ... ((NB_CLUSTERS * NB_TIM_CHANNELS) - 1)] = 0 };
[189]158#endif
159
[158]160//////////////////////////////////////////////////////////////////////////////
[203]161//     _timer_start()
162// This function activates a timer in the vci_timer (or vci_xicu) component
163// by writing in the proper register the period value.
164// It can be used by both the kernel to initialise a "system" timer,
[189]165// or by a task (through a system call) to configure an "user" timer.
[158]166// Returns 0 if success, > 0 if error.
167//////////////////////////////////////////////////////////////////////////////
[238]168unsigned int _timer_start( unsigned int cluster_id, 
169                           unsigned int local_id, 
170                           unsigned int period) 
171{
[165]172    // parameters checking
[238]173    if (cluster_id >= NB_CLUSTERS)  return 1;
174    if (local_id >= NB_TIM_CHANNELS)  return 2;
[158]175
[215]176#if USE_XICU
[238]177    unsigned int * timer_address = (unsigned int *) ((char *) &seg_icu_base + 
178                                                     (cluster_id * GIET_CLUSTER_INCREMENT));
[158]179
[203]180    timer_address[XICU_REG(XICU_PTI_PER, local_id)] = period;
[189]181#else
[238]182    unsigned int* timer_address = (unsigned int *) ((char *) &seg_tim_base + 
183                                                    (cluster_id * GIET_CLUSTER_INCREMENT));
[189]184
[203]185    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period;
[228]186    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0x3;
[189]187#endif
[158]188    return 0;
189}
[228]190
[189]191//////////////////////////////////////////////////////////////////////////////
[203]192//     _timer_stop()
193// This function desactivates a timer in the vci_timer (or vci_xicu) component
194// by writing in the proper register.
[189]195// Returns 0 if success, > 0 if error.
196//////////////////////////////////////////////////////////////////////////////
[238]197unsigned int _timer_stop( unsigned int cluster_id, 
198                          unsigned int local_id) 
199{
[203]200    // parameters checking
[238]201    if (cluster_id >= NB_CLUSTERS)  return 1;
202    if (local_id >= NB_TIM_CHANNELS)  return 2;
[158]203
[215]204#if USE_XICU
[238]205    unsigned int * timer_address = (unsigned int *) ((char *) &seg_icu_base + 
206                                                     (cluster_id * GIET_CLUSTER_INCREMENT));
[203]207
208    timer_address[XICU_REG(XICU_PTI_PER, local_id)] = 0;
209#else
[238]210    unsigned int* timer_address = (unsigned int *) ((char *) &seg_tim_base + 
211                                                    (cluster_id * GIET_CLUSTER_INCREMENT));
212
[203]213    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0;
214#endif
215    return 0;
[189]216}
[228]217
218
[158]219//////////////////////////////////////////////////////////////////////////////
[203]220//     _timer_reset_irq()
221// This function acknowlegge a timer interrupt in the vci_timer (or vci_xicu)
[204]222// component by reading/writing in the proper register.
[203]223// It can be used by both the isr_switch() for a "system" timer,
224// or by the _isr_timer() for an "user" timer.
[158]225// Returns 0 if success, > 0 if error.
226//////////////////////////////////////////////////////////////////////////////
[238]227unsigned int _timer_reset_irq( unsigned int cluster_id, 
228                               unsigned int local_id ) 
229{
[203]230    // parameters checking
[238]231    if (cluster_id >= NB_CLUSTERS)  return 1;
232    if (local_id >= NB_TIM_CHANNELS)  return 2;
[158]233
[215]234#if USE_XICU
[228]235    unsigned int * timer_address = (unsigned int *) ((char *) &seg_icu_base +
[238]236                                                     (cluster_id * GIET_CLUSTER_INCREMENT));
[203]237
238    unsigned int bloup = timer_address[XICU_REG(XICU_PTI_ACK, local_id)];
[228]239    bloup++; // to avoid a warning
[203]240#else
[232]241    unsigned int * timer_address = (unsigned int *) ((char *) &seg_tim_base + 
[238]242            (cluster_id * GIET_CLUSTER_INCREMENT));
[203]243
244    timer_address[local_id * TIMER_SPAN + TIMER_RESETIRQ] = 0;
245#endif
246    return 0;
[158]247}
248
[228]249
[232]250////////////////////////////////////////////////
251// _timer_reset_irq_cpt()
252////////////////////////////////////////////////
253//unsigned int _timer_reset_irq_cpt(unsigned int cluster_id, unsigned int local_id) {
254//    // parameters checking
[237]255//    if (cluster_id >= NB_CLUSTERS) {
256//        return 1;
257//    }
[238]258//    if (local_id >= NB_TIM_CHANNELS) {
[237]259//        return 2;
260//    }
[232]261//
262//#if USE_XICU
263//#error // not implemented
264//#else
[238]265//    unsigned int * timer_address = (unsigned int *) ((char *) &seg_tim_base + (cluster_id * GIET_CLUSTER_INCREMENT));
[237]266//    unsigned int timer_period = timer_address[local_id * TIMER_SPAN + TIMER_PERIOD];
[232]267//
[237]268//    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = timer_period;
[232]269//#endif
270//
271//    return 0;
272//}
273
274
[158]275/////////////////////////////////////////////////////////////////////////////////
[228]276//     VciMultiTty driver
[158]277/////////////////////////////////////////////////////////////////////////////////
[189]278// There is only one multi_tty controler in the architecture.
[238]279// The total number of TTYs is defined by the configuration parameter NB_TTY_CHANNELS.
[189]280// The "system" terminal is TTY[0].
281// The "user" TTYs are allocated to applications by the GIET in the boot phase,
282// as defined in the mapping_info data structure. The corresponding tty_id must
283// be stored in the context of the task by the boot code.
284// The TTY address is : seg_tty_base + tty_id*TTY_SPAN
285/////////////////////////////////////////////////////////////////////////////////
[158]286
[189]287// TTY variables
[238]288in_unckdata volatile unsigned char _tty_get_buf[NB_TTY_CHANNELS];
289in_unckdata volatile unsigned char _tty_get_full[NB_TTY_CHANNELS] 
290                                     = { [0 ... NB_TTY_CHANNELS - 1] = 0 };
[228]291in_unckdata unsigned int _tty_put_lock = 0;  // protect kernel TTY[0]
[189]292
293////////////////////////////////////////////////////////////////////////////////
294//      _tty_error()
295////////////////////////////////////////////////////////////////////////////////
[238]296void _tty_error(unsigned int tty_id, unsigned int task_id) 
297{
[189]298    unsigned int proc_id = _procid();
299
300    _get_lock(&_tty_put_lock);
[228]301    if (tty_id == 0xFFFFFFFF) {
[226]302        _puts("\n[GIET ERROR] no TTY assigned to the task ");
[228]303    }
304    else {
[226]305        _puts("\n[GIET ERROR] TTY index too large for task ");
[228]306    }
307    _putd(task_id);
[189]308    _puts(" on processor ");
[228]309    _putd(proc_id);
[189]310    _puts("\n");
311    _release_lock(&_tty_put_lock);
312}
[228]313
314
[189]315/////////////////////////////////////////////////////////////////////////////////
316//      _tty_write()
[158]317// Write one or several characters directly from a fixed-length user buffer to
318// the TTY_WRITE register of the TTY controler.
319// It doesn't use the TTY_PUT_IRQ interrupt and the associated kernel buffer.
320// This is a non blocking call: it tests the TTY_STATUS register, and stops
321// the transfer as soon as the TTY_STATUS[WRITE] bit is set.
322// The function returns  the number of characters that have been written.
[189]323/////////////////////////////////////////////////////////////////////////////////
[238]324unsigned int _tty_write(const char * buffer, 
325                        unsigned int length) 
326{
[228]327    unsigned int nwritten;
[238]328    unsigned int tty_id = _get_context_slot(CTX_TTY_ID);
329    unsigned int* tty_address = (unsigned int *) &seg_tty_base;
[158]330
[238]331    for (nwritten = 0; nwritten < length; nwritten++) 
332    {
[165]333        // check tty's status
[238]334        if ((tty_address[tty_id * TTY_SPAN + TTY_STATUS] & 0x2) == 0x2) break;
335        tty_address[tty_id * TTY_SPAN + TTY_WRITE] = (unsigned int) buffer[nwritten];
[158]336    }
337    return nwritten;
338}
[228]339
[158]340//////////////////////////////////////////////////////////////////////////////
[204]341//      _tty_read()
[158]342// This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and
[165]343// the associated kernel buffer, that has been written by the ISR.
[204]344// It get the TTY terminal index from the context of the current task.
[158]345// It fetches one single character from the _tty_get_buf[tty_id] kernel
346// buffer, writes this character to the user buffer, and resets the
347// _tty_get_full[tty_id] buffer.
[204]348// The length argument is not used.
[158]349// Returns 0 if the kernel buffer is empty, 1 if the buffer is full.
350//////////////////////////////////////////////////////////////////////////////
[238]351unsigned int _tty_read(char * buffer, 
352                       unsigned int length) 
353{
354    unsigned int tty_id = _get_context_slot(CTX_TTY_ID);
[158]355
[238]356    if (_tty_get_full[tty_id] == 0) 
357    {
[189]358        return 0;
359    }
[238]360    else 
361    {
[158]362        *buffer = _tty_get_buf[tty_id];
363        _tty_get_full[tty_id] = 0;
[189]364        return 1;
[158]365    }
[228]366}
367
[158]368////////////////////////////////////////////////////////////////////////////////
[204]369//     _tty_get_char()
370// This function is used by the _isr_tty to read a character in the TTY
371// terminal defined by the tty_id argument. The character is stored
372// in requested buffer, and the IRQ is acknowledged.
373// Returns 0 if success, 1 if tty_id too large.
[158]374////////////////////////////////////////////////////////////////////////////////
[238]375unsigned int _tty_get_char(unsigned int tty_id, 
376                           unsigned char * buffer) 
377{
[204]378    // checking argument
[238]379    if (tty_id >= NB_TTY_CHANNELS) { return 1; }
[199]380
[204]381    // compute terminal base address
[228]382    unsigned int * tty_address = (unsigned int *) &seg_tty_base; 
[158]383
[228]384    *buffer = (unsigned char) tty_address[tty_id * TTY_SPAN + TTY_READ];
[204]385    return 0;
[158]386}
387
[228]388
[158]389////////////////////////////////////////////////////////////////////////////////
[238]390//     VciMultiIcu or VciXicu driver
[158]391////////////////////////////////////////////////////////////////////////////////
[238]392// This hardware component is replicated in all clusters.
[203]393// There is one vci_multi_icu (or vci_xicu) component per cluster,
394// and the number of independant ICUs is equal to NB_PROCS_MAX,
[238]395// because there is one private interrupt controler per processor.
[158]396////////////////////////////////////////////////////////////////////////////////
[238]397// The (virtual) base address of the associated segment is:
398//
399//       icu_address = seg_icu_base + cluster_id * GIET_CLUSTER_INCREMENT
400//
401// - cluster id is an explicit argument of all access functions
402// - seg_icu_base must be defined in the giet_vsegs.ld file
403// - GIET_CLUSTER_INCREMENT must be defined in the giet_config.h file
404////////////////////////////////////////////////////////////////////////////////
[158]405
406////////////////////////////////////////////////////////////////////////////////
[203]407//     _icu_set_mask()
408// This function can be used with both the vci_xicu & vci_multi_icu components.
409// It set the mask register for the ICU channel identified by the cluster index
410// and the processor index: all '1' bits are set / all '0' bits are not modified.
[158]411// Returns 0 if success, > 0 if error.
412////////////////////////////////////////////////////////////////////////////////
[238]413unsigned int _icu_set_mask( unsigned int cluster_id,
414                            unsigned int proc_id,
415                            unsigned int value,
416                            unsigned int is_timer) 
417{
[203]418    // parameters checking
[238]419    if (cluster_id >= NB_CLUSTERS) return 1; 
420    if (proc_id >= NB_PROCS_MAX)   return 1; 
[203]421
[228]422    unsigned int * icu_address = (unsigned int *) ((char *) &seg_icu_base + 
[238]423                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
[215]424#if USE_XICU
[238]425    if (is_timer) 
426    {
[228]427        icu_address[XICU_REG(XICU_MSK_PTI_ENABLE, proc_id)] = value;
428    }
[238]429    else 
430    {
[228]431        icu_address[XICU_REG(XICU_MSK_HWI_ENABLE, proc_id)] = value;
432    }
[189]433#else
[203]434    icu_address[proc_id * ICU_SPAN + ICU_MASK_SET] = value; 
435#endif
[158]436    return 0;
437}
[228]438
439
[158]440////////////////////////////////////////////////////////////////////////////////
[203]441//     _icu_get_index()
442// This function can be used with both the vci_xicu & vci_multi_icu components.
443// It returns the index of the highest priority (smaller index) active HWI.
444// The ICU channel is identified by the cluster index and the processor index.
[158]445// Returns 0 if success, > 0 if error.
446////////////////////////////////////////////////////////////////////////////////
[238]447unsigned int _icu_get_index( unsigned int cluster_id, 
448                             unsigned int proc_id, 
449                             unsigned int * buffer) 
450{
[203]451    // parameters checking
[238]452    if (cluster_id >= NB_CLUSTERS)  return 1;
453    if (proc_id >= NB_PROCS_MAX)    return 1;
[203]454
[228]455    unsigned int * icu_address = (unsigned int *) ((char *) &seg_icu_base + 
[238]456                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
[215]457#if USE_XICU
[228]458    unsigned int prio = icu_address[XICU_REG(XICU_PRIO, proc_id)];
[203]459    unsigned int pti_ok = (prio & 0x00000001);
460    unsigned int hwi_ok = (prio & 0x00000002);
461    unsigned int swi_ok = (prio & 0x00000004);
462    unsigned int pti_id = (prio & 0x00001F00) >> 8;
463    unsigned int hwi_id = (prio & 0x001F0000) >> 16;
464    unsigned int swi_id = (prio & 0x1F000000) >> 24;
[238]465    if      (pti_ok) { *buffer = pti_id; }
466    else if (hwi_ok) { *buffer = hwi_id; }
467    else if (swi_ok) { *buffer = swi_id; }
468    else             { *buffer = 32; }
[189]469#else
[203]470    *buffer = icu_address[proc_id * ICU_SPAN + ICU_IT_VECTOR]; 
471#endif
[158]472    return 0;
473}
474
[228]475
[158]476////////////////////////////////////////////////////////////////////////////////
[228]477//     VciGcd driver
[158]478////////////////////////////////////////////////////////////////////////////////
479// The Greater Dommon Divider is a -very- simple hardware coprocessor
[165]480// performing the computation of the GCD of two 32 bits integers.
[158]481// It has no DMA capability.
482////////////////////////////////////////////////////////////////////////////////
483
484////////////////////////////////////////////////////////////////////////////////
[189]485//     _gcd_write()
[158]486// Write a 32-bit word in a memory mapped register of the GCD coprocessor.
487// Returns 0 if success, > 0 if error.
488////////////////////////////////////////////////////////////////////////////////
[238]489unsigned int _gcd_write( unsigned int register_index, 
490                         unsigned int value) 
491{
[165]492    // parameters checking
[238]493    if (register_index >= GCD_END)  return 1; 
[158]494
[228]495    unsigned int * gcd_address = (unsigned int *) &seg_gcd_base;
[165]496
497    gcd_address[register_index] = value; // write word
[158]498    return 0;
499}
[228]500
501
[158]502////////////////////////////////////////////////////////////////////////////////
[189]503//     _gcd_read()
[158]504// Read a 32-bit word in a memory mapped register of the GCD coprocessor.
505// Returns 0 if success, > 0 if error.
506////////////////////////////////////////////////////////////////////////////////
[238]507unsigned int _gcd_read( unsigned int register_index, 
508                        unsigned int * buffer ) 
509{
[165]510    // parameters checking
[238]511    if (register_index >= GCD_END)  return 1;
[158]512
[228]513    unsigned int * gcd_address = (unsigned int *) &seg_gcd_base;
[165]514
515    *buffer = gcd_address[register_index]; // read word
[158]516    return 0;
517}
518
519////////////////////////////////////////////////////////////////////////////////
520// VciBlockDevice driver
521////////////////////////////////////////////////////////////////////////////////
[165]522// The VciBlockDevice is a single channel external storage contrÃŽler.
[166]523//
524// The IOMMU can be activated or not:
525//
526// 1) When the IOMMU is used, a fixed size 2Mbytes vseg is allocated to
527// the IOC peripheral, in the I/O virtual space, and the user buffer is
528// dynamically remapped in the IOMMU page table. The corresponding entry
529// in the IOMMU PT1 is defined by the kernel _ioc_iommu_ix1 variable.
530// The number of pages to be unmapped is stored in the _ioc_npages variable.
531// The number of PT2 entries is dynamically computed and stored in the
532// kernel _ioc_iommu_npages variable. It cannot be larger than 512.
533// The user buffer is unmapped by the _ioc_completed() function when
534// the transfer is completed.
535//
536// 2/ If the IOMMU is not used, we check that  the user buffer is mapped to a
537// contiguous physical buffer (this is generally true because the user space
538// page tables are statically constructed to use contiguous physical memory).
539//
540// Finally, the memory buffer must fulfill the following conditions:
541// - The user buffer must be word aligned,
542// - The user buffer must be mapped in user address space,
543// - The user buffer must be writable in case of (to_mem) access,
544// - The total number of physical pages occupied by the user buffer cannot
545//   be larger than 512 pages if the IOMMU is activated,
546// - All physical pages occupied by the user buffer must be contiguous
547//   if the IOMMU is not activated.
548// An error code is returned if these conditions are not verified.
549//
[158]550// As the IOC component can be used by several programs running in parallel,
551// the _ioc_lock variable guaranties exclusive access to the device.  The
552// _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
553// and set _ioc_lock to a non zero value.  The _ioc_write() and _ioc_read()
554// functions are blocking, polling the _ioc_lock variable until the device is
555// available.
556// When the tranfer is completed, the ISR routine activated by the IOC IRQ
557// set the _ioc_done variable to a non-zero value. Possible address errors
558// detected by the IOC peripheral are reported by the ISR in the _ioc_status
559// variable.
560// The _ioc_completed() function is polling the _ioc_done variable, waiting for
[166]561// transfer completion. When the completion is signaled, the _ioc_completed()
[158]562// function reset the _ioc_done variable to zero, and releases the _ioc_lock
563// variable.
564//
565// In a multi-processing environment, this polling policy should be replaced by
566// a descheduling policy for the requesting process.
567///////////////////////////////////////////////////////////////////////////////
568
[189]569// IOC global variables
[228]570in_unckdata volatile unsigned int _ioc_status= 0;
571in_unckdata volatile unsigned int _ioc_done = 0;
572in_unckdata unsigned int _ioc_lock = 0;
573in_unckdata unsigned int _ioc_iommu_ix1 = 0;
574in_unckdata unsigned int _ioc_iommu_npages; 
[158]575
576///////////////////////////////////////////////////////////////////////////////
[189]577//      _ioc_access()
[166]578// This function transfer data between a memory buffer and the block device.
579// The buffer lentgth is (count*block_size) bytes.
580// Arguments are:
581// - to_mem     : from external storage to memory when non 0
582// - lba        : first block index on the external storage.
583// - user_vaddr : virtual base address of the memory buffer.
584// - count      : number of blocks to be transfered.
[158]585// Returns 0 if success, > 0 if error.
586///////////////////////////////////////////////////////////////////////////////
[238]587unsigned int _ioc_access( unsigned int to_mem,
588                          unsigned int lba,
589                          unsigned int user_vaddr,
590                          unsigned int count) 
591{
592    unsigned int user_vpn_min;     // first virtuel page index in user space
593    unsigned int user_vpn_max;     // last virtual page index in user space
594    unsigned int vpn;              // current virtual page index in user space
595    unsigned int ppn;              // physical page number
596    unsigned int flags;            // page protection flags
597    unsigned int ix2;              // page index in IOMMU PT1 page table
598    unsigned int ppn_first;        // first physical page number for user buffer
599    unsigned int buf_xaddr = 0;    // user buffer virtual address in IO space (if IOMMU)
600    paddr_t      buf_paddr = 0;    // user buffer physical address (if no IOMMU),
601                               
[166]602    // check buffer alignment
[238]603    if ((unsigned int) user_vaddr & 0x3)
604    {
605        _get_lock(&_tty_put_lock);
606        _puts("[GIET ERROR] in _ioc_access() : user buffer not word aligned\n");
607        _release_lock(&_tty_put_lock);
608        return 1; 
[228]609    }
[158]610
[228]611    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;
[204]612
[228]613    unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
614    unsigned int length = count * block_size;
[158]615
[167]616    // get user space page table virtual address
[238]617    unsigned int user_pt_vbase = _get_context_slot(CTX_PTAB_ID);
[228]618
[166]619    user_vpn_min = user_vaddr >> 12;
620    user_vpn_max = (user_vaddr + length - 1) >> 12;
[158]621
[166]622    // loop on all virtual pages covering the user buffer
[238]623    for (vpn = user_vpn_min, ix2 = 0 ; 
624         vpn <= user_vpn_max ; 
625         vpn++, ix2++ ) 
626    {
[166]627        // get ppn and flags for each vpn
[238]628        unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase, 
629                                           vpn, 
630                                           &ppn, 
631                                           &flags);
[166]632        // check access rights
[238]633        if (ko)                                 
634        {
635            _get_lock(&_tty_put_lock);
636            _puts("[GIET ERROR] in _ioc_access() : user buffer unmapped\n");
637            _release_lock(&_tty_put_lock);
638            return 1; 
[228]639        }
[238]640        if ((flags & PTE_U) == 0) 
641        {
642            _get_lock(&_tty_put_lock);
643            _puts("[GIET ERROR] in _ioc_access() : user buffer not in user space\n");
644            _release_lock(&_tty_put_lock);
645            return 1; 
[228]646        }
[238]647        if (((flags & PTE_W) == 0 ) && to_mem)
648        {
649            _get_lock(&_tty_put_lock);
650            _puts("[GIET ERROR] in _ioc_access() : user buffer not writable\n");
651            _release_lock(&_tty_put_lock);
652            return 1; 
[228]653        }
[158]654
[166]655        // save first ppn value
[238]656        if (ix2 == 0) ppn_first = ppn;
[158]657
[238]658        if (IOMMU_ACTIVE) // the user buffer must be remapped in the I/0 space
659        {
[166]660            // check buffer length < 2 Mbytes
[238]661            if (ix2 > 511) 
662            {
663                _get_lock(&_tty_put_lock);
664                _puts("[GIET ERROR] in _ioc_access() : user buffer > 2 Mbytes\n");
665                _release_lock(&_tty_put_lock);
666                return 1; 
[228]667            }
[158]668
[166]669            // map the physical page in IOMMU page table
[238]670            _iommu_add_pte2( _ioc_iommu_ix1,    // PT1 index
671                             ix2,               // PT2 index
672                             ppn,               // Physical page number   
673                             flags);            // Protection flags
674
675            // compute user buffer virtual adress in IO space
676            buf_xaddr = (_ioc_iommu_ix1) << 21 | (user_vaddr & 0xFFF);
[166]677        }
[238]678        else            // No IOMMU
679        {
680            // check that physical pages are contiguous
681            if ((ppn - ppn_first) != ix2) 
682            {
683                _get_lock(&_tty_put_lock);
684                _puts("[GIET ERROR] in _ioc_access() : split physical user buffer\n");
685                _release_lock(&_tty_put_lock);
686                return 1; 
[228]687            }
[238]688
689            // compute user buffer physical adress
690            buf_paddr = (((paddr_t)ppn_first) << 12) | (user_vaddr & 0xFFF);
[166]691        }
692    } // end for vpn
[158]693
[166]694    // register the number of pages to be unmapped
695    _ioc_iommu_npages = (user_vpn_max - user_vpn_min) + 1;
[158]696
[166]697    // invalidate data cache in case of memory write
[238]698    if (to_mem) _dcache_buf_invalidate((void *) user_vaddr, length);
[158]699
[238]700#if GIET_DEBUG_IOC_DRIVER
701_get_lock(&_tty_put_lock);
702_puts("\n[GIET DEBUG]  IOC_ACCESS at cycle ");
703_putd( _proctime() );
704_puts("\n - proc_id         = ");
705_putd( _procid() );
706_puts("\n - ioc_vbase       = ");
707_putx( (unsigned int)ioc_address );
708_puts("\n - psched_vbase    = ");
709_putx( (unsigned int)_get_sched() );
710_puts("\n - pt_vbase        = ");
711_putx( user_pt_vbase );
712_puts("\n - user_buf_vbase  = ");
713_putx( user_vaddr );
714_puts("\n - user_buf_length = ");
715_putx( length );
716_puts("\n - user_buf_paddr  = ");
717_putl( buf_paddr );
718_puts("\n - user_buf_xaddr  = ");
719_putx( buf_xaddr );
720_puts("\n");
721_release_lock(&_tty_put_lock);
722#endif
[166]723
724    // get the lock on ioc device
[228]725    _get_lock(&_ioc_lock);
[158]726
[166]727    // peripheral configuration 
[238]728    if ( IOMMU_ACTIVE ) 
729    {
730        ioc_address[BLOCK_DEVICE_BUFFER] = buf_xaddr;
731    }
732    else
733    {
734        ioc_address[BLOCK_DEVICE_BUFFER]     = (unsigned int)buf_paddr;
735        ioc_address[BLOCK_DEVICE_BUFFER_EXT] = (unsigned int)(buf_paddr>>32);
736    }
[228]737    ioc_address[BLOCK_DEVICE_COUNT] = count;
738    ioc_address[BLOCK_DEVICE_LBA] = lba;
[238]739    if (to_mem == 0) 
740    {
[228]741        ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
742    }
[238]743    else 
744    {
[228]745        ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
746    }
[158]747    return 0;
748}
[228]749
[158]750/////////////////////////////////////////////////////////////////////////////////
751// _ioc_completed()
752//
753// This function checks completion of an I/O transfer and reports errors.
[166]754// As it is a blocking call, the processor is stalled.
755// If the virtual memory is activated, the pages mapped in the I/O virtual
756// space are unmapped, and the IOB TLB is cleared.
[158]757// Returns 0 if success, > 0 if error.
758/////////////////////////////////////////////////////////////////////////////////
[238]759unsigned int _ioc_completed() 
760{
[228]761    unsigned int ret;
762    unsigned int ix2;
[158]763
[166]764    // busy waiting
[238]765    while (_ioc_done == 0) { asm volatile("nop"); }
[158]766
[238]767#if GIET_DEBUG_IOC_DRIVER
768_get_lock(&_tty_put_lock);
769_puts("\n[GIET DEBUG]  IOC_COMPLETED at cycle ");
770_putd( _proctime() );
771_puts("\n - proc_id         = ");
772_putd( _procid() );
773_puts("\n");
774_release_lock(&_tty_put_lock);
775#endif
776
[166]777    // unmap the buffer from IOMMU page table if IOMMU is activated
[238]778    if (IOMMU_ACTIVE) 
779    {
[228]780        unsigned int * iob_address = (unsigned int *) &seg_iob_base;
[166]781
[238]782        for (ix2 = 0; ix2 < _ioc_iommu_npages; ix2++) 
783        {
[166]784            // unmap the page in IOMMU page table
[228]785            _iommu_inval_pte2(
786                    _ioc_iommu_ix1, // PT1 index
787                    ix2 );          // PT2 index
[166]788
789            // clear IOMMU TLB
[169]790            iob_address[IOB_INVAL_PTE] = (_ioc_iommu_ix1 << 21) | (ix2 << 12); 
[166]791        }
792    }
793
794    // test IOC status
[158]795    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
[238]796            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1; // error
797    else                                                    ret = 0; // success
[158]798
[166]799    // reset synchronization variables
[223]800    _ioc_done = 0;
[228]801    asm volatile("sync");
[223]802    _ioc_lock = 0;
[158]803
804    return ret;
805}
[228]806
807
[166]808///////////////////////////////////////////////////////////////////////////////
[189]809//     _ioc_read()
[166]810// Transfer data from the block device to a memory buffer in user space.
811// - lba    : first block index on the block device
812// - buffer : base address of the memory buffer (must be word aligned)
813// - count  : number of blocks to be transfered.
814// Returns 0 if success, > 0 if error.
815///////////////////////////////////////////////////////////////////////////////
[238]816unsigned int _ioc_read( unsigned int lba, 
817                        void * buffer, 
818                        unsigned int count) 
819{
[228]820    return _ioc_access(
821            1,        // read access
822            lba,
823            (unsigned int) buffer,
824            count);
[166]825}
[228]826
827
[166]828///////////////////////////////////////////////////////////////////////////////
[189]829//     _ioc_write()
[166]830// Transfer data from a memory buffer in user space to the block device.
831// - lba    : first block index on the block device
832// - buffer : base address of the memory buffer (must be word aligned)
833// - count  : number of blocks to be transfered.
834// Returns 0 if success, > 0 if error.
835///////////////////////////////////////////////////////////////////////////////
[238]836unsigned int _ioc_write( unsigned int lba, 
837                         const void * buffer, 
838                         unsigned int count) 
839{
[228]840    return _ioc_access(
841            0, // write access
842            lba,
843            (unsigned int) buffer,
844            count);
[166]845}
[228]846
847
[204]848///////////////////////////////////////////////////////////////////////////////
849//     _ioc_get_status()
850// This function returns the transfert status, and acknowledge the IRQ.
851// Returns 0 if success, > 0 if error.
852///////////////////////////////////////////////////////////////////////////////
[238]853unsigned int _ioc_get_status(unsigned int * status) 
854{
[204]855    // get IOC base address
[228]856    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
[166]857
[204]858    *status = ioc_address[BLOCK_DEVICE_STATUS]; // read status & reset IRQ
859    return 0;
860}
861
[228]862
[237]863///////////////////////////////////////////////////////////////////////////////
864//     _ioc_get_block_size()
865// This function returns the block_size with which the IOC has been configured.
866///////////////////////////////////////////////////////////////////////////////
[238]867unsigned int _ioc_get_block_size() 
868{
[237]869    // get IOC base address
870    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
871   
872    return  ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
873}
874
875
[158]876//////////////////////////////////////////////////////////////////////////////////
[189]877// VciMultiDma driver
878//////////////////////////////////////////////////////////////////////////////////
879// The DMA controllers are physically distributed in the clusters.
[238]880// There is  (NB_CLUSTERS * NB_DMA_CHANNELS) channels, indexed by a global index:
881//        dma_id = cluster_id * NB_DMA_CHANNELS + loc_id
[189]882//
[238]883// As a DMA channel is a private ressource allocated to a task,
884// there is no lock protecting exclusive access to the channel.
[189]885// The signalisation between the OS and the DMA uses the _dma_done[dma_id]
886// synchronisation variables  (set by the ISR, and reset by the OS).
887// The transfer status is copied by the ISR in the _dma_status[dma_id] variables.
[238]888//////////////////////////////////////////////////////////////////////////////////
889// The (virtual) base address of the associated segment is:
[189]890//
[238]891//       dma_address = seg_dma_base + cluster_id * GIET_CLUSTER_INCREMENT
892//
893// - seg_dma_base  must be defined in the giet_vsegs.ld file
894// - GIET_CLUSTER_INCREMENT  must be defined in the giet_config.h file
895////////////////////////////////////////////////////////////////////////////////
[189]896
[238]897#if NB_DMA_CHANNELS > 0
[189]898
[238]899// in_unckdata unsigned int            _dma_lock[NB_DMA_CHANNELS * NB_CLUSTERS]
900// = { [0 ... (NB_DMA_CHANNELS * NB_CLUSTERS) - 1] = 0 };
[189]901
[238]902in_unckdata volatile unsigned int    _dma_done[NB_DMA_CHANNELS * NB_CLUSTERS] 
903        = { [0 ... (NB_DMA_CHANNELS * NB_CLUSTERS) - 1] = 0 };
904in_unckdata volatile unsigned int _dma_status[NB_DMA_CHANNELS * NB_CLUSTERS];
[228]905in_unckdata unsigned int _dma_iommu_ix1 = 1;
[238]906in_unckdata unsigned int _dma_iommu_npages[NB_DMA_CHANNELS * NB_CLUSTERS];
[213]907#endif
[189]908
909//////////////////////////////////////////////////////////////////////////////////
[204]910// _dma_reset_irq()
911//////////////////////////////////////////////////////////////////////////////////
[238]912unsigned int _dma_reset_irq( unsigned int cluster_id, 
913                             unsigned int channel_id) 
914{
915#if NB_DMA_CHANNELS > 0
[204]916    // parameters checking
[238]917    if (cluster_id >= NB_CLUSTERS)  return 1;
918    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
[204]919
920    // compute DMA base address
[228]921    unsigned int * dma_address = (unsigned int *) ((char *) &seg_dma_base + 
[238]922                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
[204]923
[228]924    dma_address[channel_id * DMA_SPAN + DMA_RESET] = 0;           
[204]925    return 0;
[213]926#else
927    return -1;
928#endif
[204]929}
[218]930
[228]931
[204]932//////////////////////////////////////////////////////////////////////////////////
933// _dma_get_status()
934//////////////////////////////////////////////////////////////////////////////////
[238]935unsigned int _dma_get_status( unsigned int cluster_id, 
936                              unsigned int channel_id, 
937                              unsigned int * status) 
938{
939#if NB_DMA_CHANNELS > 0
[204]940    // parameters checking
[238]941    if (cluster_id >= NB_CLUSTERS)  return 1;
942    if (channel_id >= NB_DMA_CHANNELS)  return 1;
[204]943
944    // compute DMA base address
[228]945    unsigned int * dma_address = (unsigned int *) ((char *) &seg_dma_base + 
[238]946                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
[207]947
[228]948    *status = dma_address[channel_id * DMA_SPAN + DMA_LEN];
[204]949    return 0;
[213]950#else
951    return -1;
952#endif
[204]953}
954
[228]955
[204]956//////////////////////////////////////////////////////////////////////////////////
[218]957// _dma_transfer()
958// Transfer data between a user buffer and a device buffer using DMA.
[238]959// Only one device type is supported: Frame Buffer (dev_type == 0)
[218]960// Arguments are:
961// - dev_type     : device type.
962// - to_user      : from  device buffer to user buffer when true.
963// - offset       : offset (in bytes) in the device buffer.
964// - user_vaddr   : virtual base address of the user buffer.
965// - length       : number of bytes to be transfered.
966//
[238]967// The cluster_id and channel_id are obtained from task context (CTX_DMA_ID).
[207]968// The user buffer must be mapped in user address space and word-aligned.
[169]969// The user buffer length must be multiple of 4 bytes.
[238]970// We compute the physical base addresses for both the device buffer
[189]971// and the user buffer before programming the DMA transfer.
[207]972// The GIET being fully static, we don't need to split the transfer in 4 Kbytes
[189]973// pages, because the user buffer is contiguous in physical space.
[158]974// Returns 0 if success, > 0 if error.
975//////////////////////////////////////////////////////////////////////////////////
[238]976unsigned int _dma_transfer( unsigned int dev_type,
977                            unsigned int to_user,
978                            unsigned int offset,
979                            unsigned int user_vaddr,
980                            unsigned int length ) 
981{
982#if NB_DMA_CHANNELS > 0
[228]983    unsigned int ko;           // unsuccessfull V2P translation
[238]984    unsigned int device_vbase; // device buffer vbase address
[228]985    unsigned int flags;        // protection flags
986    unsigned int ppn;          // physical page number
[238]987    paddr_t      user_pbase;   // user buffer pbase address
988    paddr_t      device_pbase; // frame buffer pbase address
[158]989
[189]990    // check user buffer address and length alignment
[238]991    if ((user_vaddr & 0x3) || (length & 0x3)) 
992    {
[203]993        _get_lock(&_tty_put_lock);
[218]994        _puts("\n[GIET ERROR] in _dma_transfer : user buffer not word aligned\n");
[203]995        _release_lock(&_tty_put_lock);
[189]996        return 1;
997    }
[169]998
[218]999    // get DMA channel and compute DMA vbase address
[238]1000    unsigned int dma_id      = _get_context_slot(CTX_DMA_ID);
1001    if ( dma_id == 0xFFFFFFFF )
1002    {
1003        _get_lock(&_tty_put_lock);
1004        _puts("\n[GIET ERROR] in _dma_transfer : no DMA channel allocated\n");
1005        _release_lock(&_tty_put_lock);
1006        return 1;
1007    }
1008    unsigned int cluster_id  = dma_id / NB_DMA_CHANNELS;
1009    unsigned int channel_id  = dma_id % NB_DMA_CHANNELS;
1010    unsigned int * dma_vbase  = (unsigned int *) ((char *) &seg_dma_base + 
1011                                                (cluster_id * GIET_CLUSTER_INCREMENT));
[218]1012    // get page table address
[238]1013    unsigned int user_ptab = _get_context_slot(CTX_PTAB_ID);
[169]1014
[238]1015    // get devic buffer virtual address, depending on peripheral type
1016    if (dev_type == 0) 
1017    {
1018        device_vbase = (unsigned int) &seg_fbf_base + offset;
[228]1019    }
[238]1020    else 
1021    {
1022        _get_lock(&_tty_put_lock);
1023        _puts("\n[GIET ERROR] in _dma_transfer : device type not supported\n");
1024        _release_lock(&_tty_put_lock);
1025        return 1;
[228]1026    }
[189]1027
[218]1028    // get device buffer physical address
[238]1029    ko = _v2p_translate( (page_table_t*) user_ptab, 
1030                         (device_vbase >> 12), 
1031                         &ppn, 
1032                         &flags );
1033    if (ko) 
1034    {
[203]1035        _get_lock(&_tty_put_lock);
[218]1036        _puts("\n[GIET ERROR] in _dma_transfer : device buffer unmapped\n");
[203]1037        _release_lock(&_tty_put_lock);
[238]1038        return 1;
[189]1039    }
[238]1040    device_pbase = ((paddr_t)ppn << 12) | (device_vbase & 0x00000FFF);
[189]1041
[218]1042    // Compute user buffer physical address
[238]1043    ko = _v2p_translate( (page_table_t*) user_ptab, 
1044                         (user_vaddr >> 12), 
1045                         &ppn, 
1046                         &flags );
1047    if (ko) 
1048    {
[203]1049        _get_lock(&_tty_put_lock);
[218]1050        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer unmapped\n");
[203]1051        _release_lock(&_tty_put_lock);
[238]1052        return 1;
[189]1053    } 
[238]1054    if ((flags & PTE_U) == 0) 
1055    {
[203]1056        _get_lock(&_tty_put_lock);
[218]1057        _puts("[GIET ERROR] in _dma_transfer() : user buffer not in user space\n");
[203]1058        _release_lock(&_tty_put_lock);
[238]1059        return 1; 
[189]1060    }
[238]1061    if (((flags & PTE_W) == 0 ) && to_user) 
1062    {
[203]1063        _get_lock(&_tty_put_lock);
[218]1064        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer not writable\n");
[203]1065        _release_lock(&_tty_put_lock);
[238]1066        return 1;
[189]1067    }
[238]1068    user_pbase = (((paddr_t)ppn) << 12) | (user_vaddr & 0x00000FFF);
[189]1069
[238]1070/*  This is a draft for IOMMU support
[228]1071
[189]1072    // loop on all virtual pages covering the user buffer
[169]1073    unsigned int user_vpn_min = user_vaddr >> 12;
1074    unsigned int user_vpn_max = (user_vaddr + length - 1) >> 12;
1075    unsigned int ix2          = 0;
1076    unsigned int ix1          = _dma_iommu_ix1 + dma_id;
[158]1077
[169]1078    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
1079    {
[228]1080    // get ppn and flags for each vpn
1081    unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase,
1082    vpn,
1083    &ppn,
1084    &flags );
[158]1085
[228]1086    // check access rights
1087    if ( ko )                                 return 3;     // unmapped
1088    if ( (flags & PTE_U) == 0 )               return 4;     // not in user space
1089    if ( ( (flags & PTE_W) == 0 ) && to_user ) return 5;     // not writable
[158]1090
[228]1091    // save first ppn value
1092    if ( ix2 == 0 ) ppn_first = ppn;
[169]1093
[228]1094    if ( IOMMU_ACTIVE )    // the user buffer must be remapped in the I/0 space
1095    {
1096    // check buffer length < 2 Mbytes
1097    if ( ix2 > 511 ) return 2;
[169]1098
[228]1099    // map the physical page in IOMMU page table
1100    _iommu_add_pte2( ix1,        // PT1 index
1101    ix2,        // PT2 index
1102    ppn,        // physical page number
1103    flags );    // protection flags
1104    }
1105    else            // no IOMMU : check that physical pages are contiguous
1106    {
1107    if ( (ppn - ppn_first) != ix2 )       return 6;     // split physical buffer 
1108    }
[169]1109
[228]1110    // increment page index
1111    ix2++;
[169]1112    } // end for vpn
1113
[189]1114    // register the number of pages to be unmapped if iommu activated
[169]1115    _dma_iommu_npages[dma_id] = (user_vpn_max - user_vpn_min) + 1;
1116
[189]1117*/
[204]1118
[169]1119    // invalidate data cache in case of memory write
[238]1120    if (to_user) _dcache_buf_invalidate((void *) user_vaddr, length);
[228]1121
[238]1122// get the lock
1123//  _get_lock(&_dma_lock[dma_id]);
[169]1124
[238]1125#if GIET_DEBUG_DMA_DRIVER
1126_get_lock(&_tty_put_lock);
1127_puts("\n[GIET DEBUG] DMA TRANSFER at cycle ");
1128_putd( _proctime() );
1129_puts("\n - cluster_id       = ");
1130_putx( cluster_id );
1131_puts("\n - channel_id       = ");
1132_putx( channel_id );
1133_puts("\n - dma_vbase        = ");
1134_putx( (unsigned int)dma_vbase );
1135_puts("\n - device_buf_vbase = ");
1136_putx( device_vbase );
1137_puts("\n - device_buf_pbase = ");
1138_putl( device_pbase );
1139_puts("\n - user_buf_vbase   = ");
1140_putx( user_vaddr );
1141_puts("\n - user_buf_pbase   = ");
1142_putl( user_pbase );
1143_puts("\n");
1144_release_lock(&_tty_put_lock);
1145#endif
1146
[169]1147    // DMA configuration
[238]1148    if (to_user) 
1149    {
1150        dma_vbase[channel_id * DMA_SPAN + DMA_SRC]     = (unsigned int)(device_pbase);
1151        dma_vbase[channel_id * DMA_SPAN + DMA_SRC_EXT] = (unsigned int)(device_pbase>>32);
1152        dma_vbase[channel_id * DMA_SPAN + DMA_DST]     = (unsigned int)(user_pbase);
1153        dma_vbase[channel_id * DMA_SPAN + DMA_DST_EXT] = (unsigned int)(user_pbase>>32);
[169]1154    }
[238]1155    else 
1156    {
1157        dma_vbase[channel_id * DMA_SPAN + DMA_SRC]     = (unsigned int)(user_pbase);
1158        dma_vbase[channel_id * DMA_SPAN + DMA_SRC_EXT] = (unsigned int)(user_pbase>>32);
1159        dma_vbase[channel_id * DMA_SPAN + DMA_DST]     = (unsigned int)(device_pbase);
1160        dma_vbase[channel_id * DMA_SPAN + DMA_DST_EXT] = (unsigned int)(device_pbase>>32);
[169]1161    }
[238]1162    dma_vbase[channel_id * DMA_SPAN + DMA_LEN] = (unsigned int) length;
[228]1163
[158]1164    return 0;
[238]1165
1166#else // NB_DMA_CHANNELS == 0
1167    _get_lock(&_tty_put_lock);
1168    _puts("\n[GIET ERROR] in _dma_transfer() : NB_DMA_CHANNELS == 0");
1169    _release_lock(&_tty_put_lock);
1170    return 1;
[213]1171#endif
[238]1172
[218]1173}  // end _dma_transfer() 
1174
[228]1175
[169]1176//////////////////////////////////////////////////////////////////////////////////
[218]1177// _dma_completed()
1178// This function checks completion of a DMA transfer to or from a peripheral
1179// device (Frame Buffer or Multi-Nic).
1180// As it is a blocking call, the processor is busy waiting.
1181// Returns 0 if success, > 0 if error
1182// (1 == read error / 2 == DMA idle error / 3 == write error)
1183//////////////////////////////////////////////////////////////////////////////////
[238]1184unsigned int _dma_completed() 
1185{
1186#if NB_DMA_CHANNELS > 0
1187    unsigned int dma_id  = _get_context_slot(CTX_DMA_ID);
[228]1188    unsigned int dma_ret;
[218]1189
1190    // busy waiting with a pseudo random delay between bus access
[238]1191    while (_dma_done[dma_id] == 0) 
1192    {
[228]1193        unsigned int delay = (( _proctime() ^ _procid() << 4) & 0x3F) + 1;
1194        asm volatile(
1195                "move  $3,   %0                 \n"
1196                "loop_nic_completed:            \n"
1197                "addi  $3,   $3, -1             \n"
1198                "bnez  $3,   loop_nic_completed \n"
1199                "nop                            \n"
1200                :
1201                : "r" (delay)
1202                : "$3"); 
[218]1203    }
[228]1204
[238]1205#if GIET_DEBUG_DMA_DRIVER
1206_get_lock(&_tty_put_lock);
1207_puts("\n[GIET DEBUG] DMA COMPLETED at cycle ");
1208_putd( _proctime() );
1209_puts("\n - cluster_id       = ");
1210_putx( dma_id/NB_DMA_CHANNELS );
1211_puts("\n - channel_id       = ");
1212_putx( dma_id%NB_DMA_CHANNELS );
1213_puts("\n");
1214_release_lock(&_tty_put_lock);
1215#endif
[218]1216
1217    // reset synchronization variables
[223]1218    _dma_done[dma_id] = 0;
[225]1219    dma_ret = _dma_status[dma_id];
1220    asm volatile("sync\n");
[218]1221
[238]1222//    _dma_lock[dma_id] = 0;
1223
[223]1224    return dma_ret;
[218]1225
[238]1226#else // NB_DMA_CHANNELS == 0
[218]1227    return -1;
1228#endif
[238]1229
[218]1230}  // end _dma_completed
1231
[238]1232
[218]1233//////////////////////////////////////////////////////////////////////////////////
[228]1234//     VciFrameBuffer driver
[218]1235//////////////////////////////////////////////////////////////////////////////////
1236// The vci_frame_buffer device can be accessed directly by software with memcpy(),
1237// or it can be accessed through a multi-channels DMA component:
1238// 
1239// The '_fb_sync_write' and '_fb_sync_read' functions use a memcpy strategy to
1240// implement the transfer between a data buffer (user space) and the frame
1241// buffer (kernel space). They are blocking until completion of the transfer.
1242//
1243// The '_fb_write()', '_fb_read()' and '_fb_completed()' functions use the
1244// VciMultiDma components (distributed in the clusters) to transfer data
[238]1245// between the user buffer and the frame buffer. A DMA channel is
[218]1246// allocated to each task requesting it in the mapping_info data structure.
1247//////////////////////////////////////////////////////////////////////////////////
1248
1249//////////////////////////////////////////////////////////////////////////////////
1250// _fb_sync_write()
1251// Transfer data from an memory buffer to the frame_buffer device using a memcpy.
1252// - offset : offset (in bytes) in the frame buffer.
1253// - buffer : base address of the memory buffer.
1254// - length : number of bytes to be transfered.
1255//////////////////////////////////////////////////////////////////////////////////
[238]1256unsigned int _fb_sync_write( unsigned int   offset, 
1257                             const void*    buffer, 
1258                             unsigned int   length) 
1259{
1260    unsigned char* fb_address = (unsigned char *) &seg_fbf_base + offset;
[228]1261    memcpy((void *) fb_address, (void *) buffer, length);
[218]1262    return 0;
1263}
1264
[228]1265
[218]1266//////////////////////////////////////////////////////////////////////////////////
1267// _fb_sync_read()
1268// Transfer data from the frame_buffer device to a memory buffer using a memcpy.
1269// - offset : offset (in bytes) in the frame buffer.
1270// - buffer : base address of the memory buffer.
1271// - length : number of bytes to be transfered.
1272//////////////////////////////////////////////////////////////////////////////////
[238]1273unsigned int _fb_sync_read( unsigned int   offset, 
1274                            const void*    buffer, 
1275                            unsigned int   length) 
1276{
1277    unsigned char* fb_address = (unsigned char *) &seg_fbf_base + offset;
[228]1278    memcpy((void *) buffer, (void *) fb_address, length);
[218]1279    return 0;
1280}
1281
[228]1282
[218]1283//////////////////////////////////////////////////////////////////////////////////
[169]1284// _fb_write()
1285// Transfer data from a memory buffer to the frame_buffer device using  DMA.
1286// - offset : offset (in bytes) in the frame buffer.
1287// - buffer : base address of the memory buffer.
1288// - length : number of bytes to be transfered.
1289// Returns 0 if success, > 0 if error.
1290//////////////////////////////////////////////////////////////////////////////////
[238]1291unsigned int _fb_write( unsigned int   offset, 
1292                        const void*    buffer, 
1293                        unsigned int   length) 
1294{
1295    return _dma_transfer( 0,             // frame buffer
1296                          0,             // write
1297                          offset,
1298                          (unsigned int) buffer,
1299                          length );
[158]1300}
1301
[228]1302
[158]1303//////////////////////////////////////////////////////////////////////////////////
1304// _fb_read()
[169]1305// Transfer data from the frame_buffer device to a memory buffer using  DMA.
[158]1306// - offset : offset (in bytes) in the frame buffer.
1307// - buffer : base address of the memory buffer.
1308// - length : number of bytes to be transfered.
1309// Returns 0 if success, > 0 if error.
1310//////////////////////////////////////////////////////////////////////////////////
[238]1311unsigned int _fb_read( unsigned int   offset, 
1312                       const void*    buffer, 
1313                       unsigned int   length ) 
1314{
1315    return _dma_transfer( 0,    // frame buffer
1316                          1,    // read
1317                          offset,
1318                          (unsigned int) buffer,
1319                          length );
[158]1320}
1321
[228]1322
[158]1323//////////////////////////////////////////////////////////////////////////////////
1324// _fb_completed()
1325// This function checks completion of a DMA transfer to or fom the frame buffer.
[169]1326// As it is a blocking call, the processor is busy waiting.
1327// Returns 0 if success, > 0 if error
1328// (1 == read error / 2 == DMA idle error / 3 == write error)
[158]1329//////////////////////////////////////////////////////////////////////////////////
[238]1330unsigned int _fb_completed() 
1331{
[218]1332    return _dma_completed();
1333}
[158]1334
[218]1335//////////////////////////////////////////////////////////////////////////////////
[228]1336//     VciMultiNic driver
[218]1337//////////////////////////////////////////////////////////////////////////////////
1338// The VciMultiNic device can be accessed directly by software with memcpy(),
1339// or it can be accessed through a multi-channels DMA component:
1340// 
1341// The '_nic_sync_write' and '_nic_sync_read' functions use a memcpy strategy to
1342// implement the transfer between a data buffer (user space) and the NIC
1343// buffer (kernel space). They are blocking until completion of the transfer.
1344//
1345// The '_nic_write()', '_nic_read()' and '_nic_completed()' functions use the
1346// VciMultiDma components (distributed in the clusters) to transfer data
1347// between the user buffer and the NIC. A  NIDMA channel is allocated to each
1348// task requesting it in the mapping_info data structure.
1349//////////////////////////////////////////////////////////////////////////////////
[204]1350
[218]1351//////////////////////////////////////////////////////////////////////////////////
1352// _nic_sync_write()
1353// Transfer data from an memory buffer to the NIC device using a memcpy.
1354// - offset : offset (in bytes) in the frame buffer.
1355// - buffer : base address of the memory buffer.
1356// - length : number of bytes to be transfered.
1357//////////////////////////////////////////////////////////////////////////////////
[238]1358unsigned int _nic_sync_write( unsigned int   offset, 
1359                              const void*    buffer, 
1360                              unsigned int   length ) 
1361{
1362    unsigned char* nic_address = (unsigned char *) &seg_nic_base + offset;
[228]1363    memcpy((void *) nic_address, (void *) buffer, length);
[218]1364    return 0;
1365}
[158]1366
[228]1367
[218]1368//////////////////////////////////////////////////////////////////////////////////
1369// _nic_sync_read()
1370// Transfer data from the NIC device to a memory buffer using a memcpy.
1371// - offset : offset (in bytes) in the frame buffer.
1372// - buffer : base address of the memory buffer.
1373// - length : number of bytes to be transfered.
1374//////////////////////////////////////////////////////////////////////////////////
[228]1375unsigned int _nic_sync_read(unsigned int offset, const void * buffer, unsigned int length) {
1376    unsigned char *nic_address = (unsigned char *) &seg_nic_base + offset;
1377    memcpy((void *) buffer, (void *) nic_address, length);
[218]1378    return 0;
1379}
[158]1380
[228]1381
[218]1382//////////////////////////////////////////////////////////////////////////////////
1383// _nic_write()
1384// Transfer data from a memory buffer to the NIC device using  DMA.
1385// - offset : offset (in bytes) in the frame buffer.
1386// - buffer : base address of the memory buffer.
1387// - length : number of bytes to be transfered.
1388// Returns 0 if success, > 0 if error.
1389//////////////////////////////////////////////////////////////////////////////////
[228]1390unsigned int _nic_write(unsigned int offset, const void * buffer, unsigned int length) {
1391    return _dma_transfer(
1392            1,            // NIC
1393            0,            // write
1394            offset,
1395            (unsigned int) buffer,
1396            length );   
[218]1397}
[169]1398
[228]1399
[218]1400//////////////////////////////////////////////////////////////////////////////////
1401// _nic_read()
1402// Transfer data from the NIC device to a memory buffer using  DMA.
1403// - offset : offset (in bytes) in the frame buffer.
1404// - buffer : base address of the memory buffer.
1405// - length : number of bytes to be transfered.
1406// Returns 0 if success, > 0 if error.
1407//////////////////////////////////////////////////////////////////////////////////
[228]1408unsigned int _nic_read(unsigned int offset, const void * buffer, unsigned int length) {
1409    return _dma_transfer(
1410            1,            // NIC
1411            1,            // read
1412            offset,
1413            (unsigned int) buffer,
1414            length );   
[218]1415}
[189]1416
[228]1417
[218]1418//////////////////////////////////////////////////////////////////////////////////
1419// _nic_completed()
1420// This function checks completion of a DMA transfer to or fom a NIC channel.
1421// As it is a blocking call, the processor is busy waiting.
1422// Returns 0 if success, > 0 if error
1423// (1 == read error / 2 == DMA idle error / 3 == write error)
1424//////////////////////////////////////////////////////////////////////////////////
[238]1425unsigned int _nic_completed() 
1426{
[218]1427    return _dma_completed();
[158]1428}
1429
[232]1430///////////////////////////////////////////////////////////////////////////////////
1431// _heap_info()
1432// This function returns the information associated to a heap (size and vaddr)
[238]1433// It uses the global task index (CTX_GTID_ID, unique for each giet task) and the
1434// vspace index (CTX_VSID_ID) defined in the task context.
[232]1435///////////////////////////////////////////////////////////////////////////////////
[238]1436unsigned int _heap_info( unsigned int* vaddr, 
1437                         unsigned int* size ) 
1438{
[232]1439    mapping_header_t * header  = (mapping_header_t *) (&seg_mapping_base);
1440    mapping_task_t * tasks     = _get_task_base(header);
1441    mapping_vobj_t * vobjs     = _get_vobj_base(header);
1442    mapping_vspace_t * vspaces = _get_vspace_base(header);
[238]1443
1444    unsigned int taskid        = _get_context_slot(CTX_GTID_ID);
1445    unsigned int vspaceid      = _get_context_slot(CTX_VSID_ID);
1446
[232]1447    int heap_local_vobjid      = tasks[taskid].heap_vobjid;
[238]1448    if (heap_local_vobjid != -1) 
1449    {
[232]1450        unsigned int vobjheapid = heap_local_vobjid + vspaces[vspaceid].vobj_offset;
1451        *vaddr                  = vobjs[vobjheapid].vaddr;
1452        *size                   = vobjs[vobjheapid].length;
1453        return 0;
1454    }
[238]1455    else 
1456    {
[232]1457        *vaddr = 0;
1458        *size = 0;
1459        return 0;
1460    }
1461}
1462
[228]1463// Local Variables:
1464// tab-width: 4
1465// c-basic-offset: 4
1466// c-file-offsets:((innamespace . 0)(inline-open . 0))
1467// indent-tabs-mode: nil
1468// End:
1469// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1470
Note: See TracBrowser for help on using the repository browser.