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

Last change on this file since 246 was 246, checked in by meunier, 11 years ago

Cosmétique + gestion du reset de l'irq du timer ou de l'xicu lors d'un task_switch

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