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

Last change on this file since 238 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
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : drivers.c
3// Date     : 23/05/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The drivers.c and drivers.h files are part ot the GIET-VM nano kernel.
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
13// - vci_xicu & vci_multi_icu
14// - vci_gcd
15// - vci_frame_buffer
16// - vci_block_device
17//
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:
26// - NB_CLUSTERS   
27// - NB_PROCS_MAX 
28// - NB_TIM_CHANNELS   
29// - NB_DMA_CHANNELS     
30// - NB_TTY_CHANNELS_MAX   
31//
32// The following virtual base addresses must be defined in the giet_vsegs.ld file:
33// - seg_icu_base
34// - seg_tim_base
35// - seg_dma_base
36// - seg_tty_base
37// - seg_gcd_base
38// - seg_fbf_base
39// - seg_ioc_base
40// - seg_nic_base
41// - seg_cma_base
42// - seg_iob_base
43//
44///////////////////////////////////////////////////////////////////////////////////
45
46#include <vm_handler.h>
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)
56# error: You must define NB_CLUSTERS in the hard_config.h file
57#endif
58
59#if !defined(NB_PROCS_MAX)
60# error: You must define NB_PROCS_MAX in the hard_config.h file
61#endif
62
63#if (NB_PROCS_MAX > 8)
64# error: NB_PROCS_MAX cannot be larger than 8!
65#endif
66
67#if !defined(GIET_CLUSTER_INCREMENT)
68# error: You must define GIET_CLUSTER_INCREMENT in the giet_config.h file
69#endif
70
71#if !defined(NB_TTY_CHANNELS)
72# error: You must define NB_TTY_CHANNELS in the hard_config.h file
73#endif
74
75#if (NB_TTY_CHANNELS < 1)
76# error: NB_TTY_CHANNELS cannot be smaller than 1!
77#endif
78
79#if !defined(NB_DMA_CHANNELS)
80# error: You must define NB_DMA_CHANNELS in the hard_config.h file
81#endif
82
83#if (NB_DMA_CHANNELS > 8)
84# error: NB_DMA_CHANNELS cannot be smaller than 8!
85#endif
86
87#if !defined(NB_TIM_CHANNELS)
88#define NB_TIM_CHANNELS 0
89#endif
90
91#if ( (NB_TIM_CHANNELS + NB_PROC_MAX) > 32 )
92# error: NB_TIM_CHANNELS + NB_PROCS_MAX cannot be larger than 32
93#endif
94
95#if !defined(NB_IOC_CHANNELS)
96# error: You must define NB_IOC_CHANNELS in the hard_config.h file
97#endif
98
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
119#if !defined( USE_XICU )
120# error: You must define USE_XICU in the hard_config.h file
121#endif
122
123#if !defined( IOMMU_ACTIVE )
124# error: You must define IOMMU_ACTIVE in the hard_config.h file
125#endif
126
127
128#define in_unckdata __attribute__((section (".unckdata")))
129
130//////////////////////////////////////////////////////////////////////////////
131//     Timers driver
132//////////////////////////////////////////////////////////////////////////////
133// This peripheral is replicated in all clusters.
134// The timers can be implemented in a vci_timer component or in a vci_xicu
135// component (depending on the USE_XICU parameter).
136// There is one timer (or xicu) component per cluster.
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.
141//   For each user timer, the timer_id is stored in the context of the task.
142// The global index is cluster_id * (NB_PROCS_MAX+NB_TIM_CHANNELS) + local_id
143//////////////////////////////////////////////////////////////////////////////
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////////////////////////////////////////////////////////////////////////////////
152
153// User Timer signaling variables
154
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 };
158#endif
159
160//////////////////////////////////////////////////////////////////////////////
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,
165// or by a task (through a system call) to configure an "user" timer.
166// Returns 0 if success, > 0 if error.
167//////////////////////////////////////////////////////////////////////////////
168unsigned int _timer_start( unsigned int cluster_id, 
169                           unsigned int local_id, 
170                           unsigned int period) 
171{
172    // parameters checking
173    if (cluster_id >= NB_CLUSTERS)  return 1;
174    if (local_id >= NB_TIM_CHANNELS)  return 2;
175
176#if USE_XICU
177    unsigned int * timer_address = (unsigned int *) ((char *) &seg_icu_base + 
178                                                     (cluster_id * GIET_CLUSTER_INCREMENT));
179
180    timer_address[XICU_REG(XICU_PTI_PER, local_id)] = period;
181#else
182    unsigned int* timer_address = (unsigned int *) ((char *) &seg_tim_base + 
183                                                    (cluster_id * GIET_CLUSTER_INCREMENT));
184
185    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period;
186    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0x3;
187#endif
188    return 0;
189}
190
191//////////////////////////////////////////////////////////////////////////////
192//     _timer_stop()
193// This function desactivates a timer in the vci_timer (or vci_xicu) component
194// by writing in the proper register.
195// Returns 0 if success, > 0 if error.
196//////////////////////////////////////////////////////////////////////////////
197unsigned int _timer_stop( unsigned int cluster_id, 
198                          unsigned int local_id) 
199{
200    // parameters checking
201    if (cluster_id >= NB_CLUSTERS)  return 1;
202    if (local_id >= NB_TIM_CHANNELS)  return 2;
203
204#if USE_XICU
205    unsigned int * timer_address = (unsigned int *) ((char *) &seg_icu_base + 
206                                                     (cluster_id * GIET_CLUSTER_INCREMENT));
207
208    timer_address[XICU_REG(XICU_PTI_PER, local_id)] = 0;
209#else
210    unsigned int* timer_address = (unsigned int *) ((char *) &seg_tim_base + 
211                                                    (cluster_id * GIET_CLUSTER_INCREMENT));
212
213    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0;
214#endif
215    return 0;
216}
217
218
219//////////////////////////////////////////////////////////////////////////////
220//     _timer_reset_irq()
221// This function acknowlegge a timer interrupt in the vci_timer (or vci_xicu)
222// component by reading/writing in the proper register.
223// It can be used by both the isr_switch() for a "system" timer,
224// or by the _isr_timer() for an "user" timer.
225// Returns 0 if success, > 0 if error.
226//////////////////////////////////////////////////////////////////////////////
227unsigned int _timer_reset_irq( unsigned int cluster_id, 
228                               unsigned int local_id ) 
229{
230    // parameters checking
231    if (cluster_id >= NB_CLUSTERS)  return 1;
232    if (local_id >= NB_TIM_CHANNELS)  return 2;
233
234#if USE_XICU
235    unsigned int * timer_address = (unsigned int *) ((char *) &seg_icu_base +
236                                                     (cluster_id * GIET_CLUSTER_INCREMENT));
237
238    unsigned int bloup = timer_address[XICU_REG(XICU_PTI_ACK, local_id)];
239    bloup++; // to avoid a warning
240#else
241    unsigned int * timer_address = (unsigned int *) ((char *) &seg_tim_base + 
242            (cluster_id * GIET_CLUSTER_INCREMENT));
243
244    timer_address[local_id * TIMER_SPAN + TIMER_RESETIRQ] = 0;
245#endif
246    return 0;
247}
248
249
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
255//    if (cluster_id >= NB_CLUSTERS) {
256//        return 1;
257//    }
258//    if (local_id >= NB_TIM_CHANNELS) {
259//        return 2;
260//    }
261//
262//#if USE_XICU
263//#error // not implemented
264//#else
265//    unsigned int * timer_address = (unsigned int *) ((char *) &seg_tim_base + (cluster_id * GIET_CLUSTER_INCREMENT));
266//    unsigned int timer_period = timer_address[local_id * TIMER_SPAN + TIMER_PERIOD];
267//
268//    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = timer_period;
269//#endif
270//
271//    return 0;
272//}
273
274
275/////////////////////////////////////////////////////////////////////////////////
276//     VciMultiTty driver
277/////////////////////////////////////////////////////////////////////////////////
278// There is only one multi_tty controler in the architecture.
279// The total number of TTYs is defined by the configuration parameter NB_TTY_CHANNELS.
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/////////////////////////////////////////////////////////////////////////////////
286
287// TTY variables
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 };
291in_unckdata unsigned int _tty_put_lock = 0;  // protect kernel TTY[0]
292
293////////////////////////////////////////////////////////////////////////////////
294//      _tty_error()
295////////////////////////////////////////////////////////////////////////////////
296void _tty_error(unsigned int tty_id, unsigned int task_id) 
297{
298    unsigned int proc_id = _procid();
299
300    _get_lock(&_tty_put_lock);
301    if (tty_id == 0xFFFFFFFF) {
302        _puts("\n[GIET ERROR] no TTY assigned to the task ");
303    }
304    else {
305        _puts("\n[GIET ERROR] TTY index too large for task ");
306    }
307    _putd(task_id);
308    _puts(" on processor ");
309    _putd(proc_id);
310    _puts("\n");
311    _release_lock(&_tty_put_lock);
312}
313
314
315/////////////////////////////////////////////////////////////////////////////////
316//      _tty_write()
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.
323/////////////////////////////////////////////////////////////////////////////////
324unsigned int _tty_write(const char * buffer, 
325                        unsigned int length) 
326{
327    unsigned int nwritten;
328    unsigned int tty_id = _get_context_slot(CTX_TTY_ID);
329    unsigned int* tty_address = (unsigned int *) &seg_tty_base;
330
331    for (nwritten = 0; nwritten < length; nwritten++) 
332    {
333        // check tty's status
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];
336    }
337    return nwritten;
338}
339
340//////////////////////////////////////////////////////////////////////////////
341//      _tty_read()
342// This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and
343// the associated kernel buffer, that has been written by the ISR.
344// It get the TTY terminal index from the context of the current task.
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.
348// The length argument is not used.
349// Returns 0 if the kernel buffer is empty, 1 if the buffer is full.
350//////////////////////////////////////////////////////////////////////////////
351unsigned int _tty_read(char * buffer, 
352                       unsigned int length) 
353{
354    unsigned int tty_id = _get_context_slot(CTX_TTY_ID);
355
356    if (_tty_get_full[tty_id] == 0) 
357    {
358        return 0;
359    }
360    else 
361    {
362        *buffer = _tty_get_buf[tty_id];
363        _tty_get_full[tty_id] = 0;
364        return 1;
365    }
366}
367
368////////////////////////////////////////////////////////////////////////////////
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.
374////////////////////////////////////////////////////////////////////////////////
375unsigned int _tty_get_char(unsigned int tty_id, 
376                           unsigned char * buffer) 
377{
378    // checking argument
379    if (tty_id >= NB_TTY_CHANNELS) { return 1; }
380
381    // compute terminal base address
382    unsigned int * tty_address = (unsigned int *) &seg_tty_base; 
383
384    *buffer = (unsigned char) tty_address[tty_id * TTY_SPAN + TTY_READ];
385    return 0;
386}
387
388
389////////////////////////////////////////////////////////////////////////////////
390//     VciMultiIcu or VciXicu driver
391////////////////////////////////////////////////////////////////////////////////
392// This hardware component is replicated in all clusters.
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,
395// because there is one private interrupt controler per processor.
396////////////////////////////////////////////////////////////////////////////////
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////////////////////////////////////////////////////////////////////////////////
405
406////////////////////////////////////////////////////////////////////////////////
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.
411// Returns 0 if success, > 0 if error.
412////////////////////////////////////////////////////////////////////////////////
413unsigned int _icu_set_mask( unsigned int cluster_id,
414                            unsigned int proc_id,
415                            unsigned int value,
416                            unsigned int is_timer) 
417{
418    // parameters checking
419    if (cluster_id >= NB_CLUSTERS) return 1; 
420    if (proc_id >= NB_PROCS_MAX)   return 1; 
421
422    unsigned int * icu_address = (unsigned int *) ((char *) &seg_icu_base + 
423                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
424#if USE_XICU
425    if (is_timer) 
426    {
427        icu_address[XICU_REG(XICU_MSK_PTI_ENABLE, proc_id)] = value;
428    }
429    else 
430    {
431        icu_address[XICU_REG(XICU_MSK_HWI_ENABLE, proc_id)] = value;
432    }
433#else
434    icu_address[proc_id * ICU_SPAN + ICU_MASK_SET] = value; 
435#endif
436    return 0;
437}
438
439
440////////////////////////////////////////////////////////////////////////////////
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.
445// Returns 0 if success, > 0 if error.
446////////////////////////////////////////////////////////////////////////////////
447unsigned int _icu_get_index( unsigned int cluster_id, 
448                             unsigned int proc_id, 
449                             unsigned int * buffer) 
450{
451    // parameters checking
452    if (cluster_id >= NB_CLUSTERS)  return 1;
453    if (proc_id >= NB_PROCS_MAX)    return 1;
454
455    unsigned int * icu_address = (unsigned int *) ((char *) &seg_icu_base + 
456                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
457#if USE_XICU
458    unsigned int prio = icu_address[XICU_REG(XICU_PRIO, proc_id)];
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;
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; }
469#else
470    *buffer = icu_address[proc_id * ICU_SPAN + ICU_IT_VECTOR]; 
471#endif
472    return 0;
473}
474
475
476////////////////////////////////////////////////////////////////////////////////
477//     VciGcd driver
478////////////////////////////////////////////////////////////////////////////////
479// The Greater Dommon Divider is a -very- simple hardware coprocessor
480// performing the computation of the GCD of two 32 bits integers.
481// It has no DMA capability.
482////////////////////////////////////////////////////////////////////////////////
483
484////////////////////////////////////////////////////////////////////////////////
485//     _gcd_write()
486// Write a 32-bit word in a memory mapped register of the GCD coprocessor.
487// Returns 0 if success, > 0 if error.
488////////////////////////////////////////////////////////////////////////////////
489unsigned int _gcd_write( unsigned int register_index, 
490                         unsigned int value) 
491{
492    // parameters checking
493    if (register_index >= GCD_END)  return 1; 
494
495    unsigned int * gcd_address = (unsigned int *) &seg_gcd_base;
496
497    gcd_address[register_index] = value; // write word
498    return 0;
499}
500
501
502////////////////////////////////////////////////////////////////////////////////
503//     _gcd_read()
504// Read a 32-bit word in a memory mapped register of the GCD coprocessor.
505// Returns 0 if success, > 0 if error.
506////////////////////////////////////////////////////////////////////////////////
507unsigned int _gcd_read( unsigned int register_index, 
508                        unsigned int * buffer ) 
509{
510    // parameters checking
511    if (register_index >= GCD_END)  return 1;
512
513    unsigned int * gcd_address = (unsigned int *) &seg_gcd_base;
514
515    *buffer = gcd_address[register_index]; // read word
516    return 0;
517}
518
519////////////////////////////////////////////////////////////////////////////////
520// VciBlockDevice driver
521////////////////////////////////////////////////////////////////////////////////
522// The VciBlockDevice is a single channel external storage contrÃŽler.
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//
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
561// transfer completion. When the completion is signaled, the _ioc_completed()
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
569// IOC global variables
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; 
575
576///////////////////////////////////////////////////////////////////////////////
577//      _ioc_access()
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.
585// Returns 0 if success, > 0 if error.
586///////////////////////////////////////////////////////////////////////////////
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                               
602    // check buffer alignment
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; 
609    }
610
611    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;
612
613    unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
614    unsigned int length = count * block_size;
615
616    // get user space page table virtual address
617    unsigned int user_pt_vbase = _get_context_slot(CTX_PTAB_ID);
618
619    user_vpn_min = user_vaddr >> 12;
620    user_vpn_max = (user_vaddr + length - 1) >> 12;
621
622    // loop on all virtual pages covering the user buffer
623    for (vpn = user_vpn_min, ix2 = 0 ; 
624         vpn <= user_vpn_max ; 
625         vpn++, ix2++ ) 
626    {
627        // get ppn and flags for each vpn
628        unsigned int ko = _v2p_translate( (page_table_t*)user_pt_vbase, 
629                                           vpn, 
630                                           &ppn, 
631                                           &flags);
632        // check access rights
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; 
639        }
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; 
646        }
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; 
653        }
654
655        // save first ppn value
656        if (ix2 == 0) ppn_first = ppn;
657
658        if (IOMMU_ACTIVE) // the user buffer must be remapped in the I/0 space
659        {
660            // check buffer length < 2 Mbytes
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; 
667            }
668
669            // map the physical page in IOMMU page table
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);
677        }
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; 
687            }
688
689            // compute user buffer physical adress
690            buf_paddr = (((paddr_t)ppn_first) << 12) | (user_vaddr & 0xFFF);
691        }
692    } // end for vpn
693
694    // register the number of pages to be unmapped
695    _ioc_iommu_npages = (user_vpn_max - user_vpn_min) + 1;
696
697    // invalidate data cache in case of memory write
698    if (to_mem) _dcache_buf_invalidate((void *) user_vaddr, length);
699
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
723
724    // get the lock on ioc device
725    _get_lock(&_ioc_lock);
726
727    // peripheral configuration 
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    }
737    ioc_address[BLOCK_DEVICE_COUNT] = count;
738    ioc_address[BLOCK_DEVICE_LBA] = lba;
739    if (to_mem == 0) 
740    {
741        ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
742    }
743    else 
744    {
745        ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
746    }
747    return 0;
748}
749
750/////////////////////////////////////////////////////////////////////////////////
751// _ioc_completed()
752//
753// This function checks completion of an I/O transfer and reports errors.
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.
757// Returns 0 if success, > 0 if error.
758/////////////////////////////////////////////////////////////////////////////////
759unsigned int _ioc_completed() 
760{
761    unsigned int ret;
762    unsigned int ix2;
763
764    // busy waiting
765    while (_ioc_done == 0) { asm volatile("nop"); }
766
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
777    // unmap the buffer from IOMMU page table if IOMMU is activated
778    if (IOMMU_ACTIVE) 
779    {
780        unsigned int * iob_address = (unsigned int *) &seg_iob_base;
781
782        for (ix2 = 0; ix2 < _ioc_iommu_npages; ix2++) 
783        {
784            // unmap the page in IOMMU page table
785            _iommu_inval_pte2(
786                    _ioc_iommu_ix1, // PT1 index
787                    ix2 );          // PT2 index
788
789            // clear IOMMU TLB
790            iob_address[IOB_INVAL_PTE] = (_ioc_iommu_ix1 << 21) | (ix2 << 12); 
791        }
792    }
793
794    // test IOC status
795    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
796            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1; // error
797    else                                                    ret = 0; // success
798
799    // reset synchronization variables
800    _ioc_done = 0;
801    asm volatile("sync");
802    _ioc_lock = 0;
803
804    return ret;
805}
806
807
808///////////////////////////////////////////////////////////////////////////////
809//     _ioc_read()
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///////////////////////////////////////////////////////////////////////////////
816unsigned int _ioc_read( unsigned int lba, 
817                        void * buffer, 
818                        unsigned int count) 
819{
820    return _ioc_access(
821            1,        // read access
822            lba,
823            (unsigned int) buffer,
824            count);
825}
826
827
828///////////////////////////////////////////////////////////////////////////////
829//     _ioc_write()
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///////////////////////////////////////////////////////////////////////////////
836unsigned int _ioc_write( unsigned int lba, 
837                         const void * buffer, 
838                         unsigned int count) 
839{
840    return _ioc_access(
841            0, // write access
842            lba,
843            (unsigned int) buffer,
844            count);
845}
846
847
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///////////////////////////////////////////////////////////////////////////////
853unsigned int _ioc_get_status(unsigned int * status) 
854{
855    // get IOC base address
856    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
857
858    *status = ioc_address[BLOCK_DEVICE_STATUS]; // read status & reset IRQ
859    return 0;
860}
861
862
863///////////////////////////////////////////////////////////////////////////////
864//     _ioc_get_block_size()
865// This function returns the block_size with which the IOC has been configured.
866///////////////////////////////////////////////////////////////////////////////
867unsigned int _ioc_get_block_size() 
868{
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
876//////////////////////////////////////////////////////////////////////////////////
877// VciMultiDma driver
878//////////////////////////////////////////////////////////////////////////////////
879// The DMA controllers are physically distributed in the clusters.
880// There is  (NB_CLUSTERS * NB_DMA_CHANNELS) channels, indexed by a global index:
881//        dma_id = cluster_id * NB_DMA_CHANNELS + loc_id
882//
883// As a DMA channel is a private ressource allocated to a task,
884// there is no lock protecting exclusive access to the channel.
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.
888//////////////////////////////////////////////////////////////////////////////////
889// The (virtual) base address of the associated segment is:
890//
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////////////////////////////////////////////////////////////////////////////////
896
897#if NB_DMA_CHANNELS > 0
898
899// in_unckdata unsigned int            _dma_lock[NB_DMA_CHANNELS * NB_CLUSTERS]
900// = { [0 ... (NB_DMA_CHANNELS * NB_CLUSTERS) - 1] = 0 };
901
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];
905in_unckdata unsigned int _dma_iommu_ix1 = 1;
906in_unckdata unsigned int _dma_iommu_npages[NB_DMA_CHANNELS * NB_CLUSTERS];
907#endif
908
909//////////////////////////////////////////////////////////////////////////////////
910// _dma_reset_irq()
911//////////////////////////////////////////////////////////////////////////////////
912unsigned int _dma_reset_irq( unsigned int cluster_id, 
913                             unsigned int channel_id) 
914{
915#if NB_DMA_CHANNELS > 0
916    // parameters checking
917    if (cluster_id >= NB_CLUSTERS)  return 1;
918    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
919
920    // compute DMA base address
921    unsigned int * dma_address = (unsigned int *) ((char *) &seg_dma_base + 
922                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
923
924    dma_address[channel_id * DMA_SPAN + DMA_RESET] = 0;           
925    return 0;
926#else
927    return -1;
928#endif
929}
930
931
932//////////////////////////////////////////////////////////////////////////////////
933// _dma_get_status()
934//////////////////////////////////////////////////////////////////////////////////
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
940    // parameters checking
941    if (cluster_id >= NB_CLUSTERS)  return 1;
942    if (channel_id >= NB_DMA_CHANNELS)  return 1;
943
944    // compute DMA base address
945    unsigned int * dma_address = (unsigned int *) ((char *) &seg_dma_base + 
946                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
947
948    *status = dma_address[channel_id * DMA_SPAN + DMA_LEN];
949    return 0;
950#else
951    return -1;
952#endif
953}
954
955
956//////////////////////////////////////////////////////////////////////////////////
957// _dma_transfer()
958// Transfer data between a user buffer and a device buffer using DMA.
959// Only one device type is supported: Frame Buffer (dev_type == 0)
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//
967// The cluster_id and channel_id are obtained from task context (CTX_DMA_ID).
968// The user buffer must be mapped in user address space and word-aligned.
969// The user buffer length must be multiple of 4 bytes.
970// We compute the physical base addresses for both the device buffer
971// and the user buffer before programming the DMA transfer.
972// The GIET being fully static, we don't need to split the transfer in 4 Kbytes
973// pages, because the user buffer is contiguous in physical space.
974// Returns 0 if success, > 0 if error.
975//////////////////////////////////////////////////////////////////////////////////
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
983    unsigned int ko;           // unsuccessfull V2P translation
984    unsigned int device_vbase; // device buffer vbase address
985    unsigned int flags;        // protection flags
986    unsigned int ppn;          // physical page number
987    paddr_t      user_pbase;   // user buffer pbase address
988    paddr_t      device_pbase; // frame buffer pbase address
989
990    // check user buffer address and length alignment
991    if ((user_vaddr & 0x3) || (length & 0x3)) 
992    {
993        _get_lock(&_tty_put_lock);
994        _puts("\n[GIET ERROR] in _dma_transfer : user buffer not word aligned\n");
995        _release_lock(&_tty_put_lock);
996        return 1;
997    }
998
999    // get DMA channel and compute DMA vbase address
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));
1012    // get page table address
1013    unsigned int user_ptab = _get_context_slot(CTX_PTAB_ID);
1014
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;
1019    }
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;
1026    }
1027
1028    // get device buffer physical address
1029    ko = _v2p_translate( (page_table_t*) user_ptab, 
1030                         (device_vbase >> 12), 
1031                         &ppn, 
1032                         &flags );
1033    if (ko) 
1034    {
1035        _get_lock(&_tty_put_lock);
1036        _puts("\n[GIET ERROR] in _dma_transfer : device buffer unmapped\n");
1037        _release_lock(&_tty_put_lock);
1038        return 1;
1039    }
1040    device_pbase = ((paddr_t)ppn << 12) | (device_vbase & 0x00000FFF);
1041
1042    // Compute user buffer physical address
1043    ko = _v2p_translate( (page_table_t*) user_ptab, 
1044                         (user_vaddr >> 12), 
1045                         &ppn, 
1046                         &flags );
1047    if (ko) 
1048    {
1049        _get_lock(&_tty_put_lock);
1050        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer unmapped\n");
1051        _release_lock(&_tty_put_lock);
1052        return 1;
1053    } 
1054    if ((flags & PTE_U) == 0) 
1055    {
1056        _get_lock(&_tty_put_lock);
1057        _puts("[GIET ERROR] in _dma_transfer() : user buffer not in user space\n");
1058        _release_lock(&_tty_put_lock);
1059        return 1; 
1060    }
1061    if (((flags & PTE_W) == 0 ) && to_user) 
1062    {
1063        _get_lock(&_tty_put_lock);
1064        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer not writable\n");
1065        _release_lock(&_tty_put_lock);
1066        return 1;
1067    }
1068    user_pbase = (((paddr_t)ppn) << 12) | (user_vaddr & 0x00000FFF);
1069
1070/*  This is a draft for IOMMU support
1071
1072    // loop on all virtual pages covering the user buffer
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;
1077
1078    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
1079    {
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 );
1085
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
1090
1091    // save first ppn value
1092    if ( ix2 == 0 ) ppn_first = ppn;
1093
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;
1098
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    }
1109
1110    // increment page index
1111    ix2++;
1112    } // end for vpn
1113
1114    // register the number of pages to be unmapped if iommu activated
1115    _dma_iommu_npages[dma_id] = (user_vpn_max - user_vpn_min) + 1;
1116
1117*/
1118
1119    // invalidate data cache in case of memory write
1120    if (to_user) _dcache_buf_invalidate((void *) user_vaddr, length);
1121
1122// get the lock
1123//  _get_lock(&_dma_lock[dma_id]);
1124
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
1147    // DMA configuration
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);
1154    }
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);
1161    }
1162    dma_vbase[channel_id * DMA_SPAN + DMA_LEN] = (unsigned int) length;
1163
1164    return 0;
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;
1171#endif
1172
1173}  // end _dma_transfer() 
1174
1175
1176//////////////////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////////////////////////////////////////
1184unsigned int _dma_completed() 
1185{
1186#if NB_DMA_CHANNELS > 0
1187    unsigned int dma_id  = _get_context_slot(CTX_DMA_ID);
1188    unsigned int dma_ret;
1189
1190    // busy waiting with a pseudo random delay between bus access
1191    while (_dma_done[dma_id] == 0) 
1192    {
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"); 
1203    }
1204
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
1216
1217    // reset synchronization variables
1218    _dma_done[dma_id] = 0;
1219    dma_ret = _dma_status[dma_id];
1220    asm volatile("sync\n");
1221
1222//    _dma_lock[dma_id] = 0;
1223
1224    return dma_ret;
1225
1226#else // NB_DMA_CHANNELS == 0
1227    return -1;
1228#endif
1229
1230}  // end _dma_completed
1231
1232
1233//////////////////////////////////////////////////////////////////////////////////
1234//     VciFrameBuffer driver
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
1245// between the user buffer and the frame buffer. A DMA channel is
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//////////////////////////////////////////////////////////////////////////////////
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;
1261    memcpy((void *) fb_address, (void *) buffer, length);
1262    return 0;
1263}
1264
1265
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//////////////////////////////////////////////////////////////////////////////////
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;
1278    memcpy((void *) buffer, (void *) fb_address, length);
1279    return 0;
1280}
1281
1282
1283//////////////////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////////////////////////////////////////
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 );
1300}
1301
1302
1303//////////////////////////////////////////////////////////////////////////////////
1304// _fb_read()
1305// Transfer data from the frame_buffer device to a memory buffer using  DMA.
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//////////////////////////////////////////////////////////////////////////////////
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 );
1320}
1321
1322
1323//////////////////////////////////////////////////////////////////////////////////
1324// _fb_completed()
1325// This function checks completion of a DMA transfer to or fom the frame buffer.
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)
1329//////////////////////////////////////////////////////////////////////////////////
1330unsigned int _fb_completed() 
1331{
1332    return _dma_completed();
1333}
1334
1335//////////////////////////////////////////////////////////////////////////////////
1336//     VciMultiNic driver
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//////////////////////////////////////////////////////////////////////////////////
1350
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//////////////////////////////////////////////////////////////////////////////////
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;
1363    memcpy((void *) nic_address, (void *) buffer, length);
1364    return 0;
1365}
1366
1367
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//////////////////////////////////////////////////////////////////////////////////
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);
1378    return 0;
1379}
1380
1381
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//////////////////////////////////////////////////////////////////////////////////
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 );   
1397}
1398
1399
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//////////////////////////////////////////////////////////////////////////////////
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 );   
1415}
1416
1417
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//////////////////////////////////////////////////////////////////////////////////
1425unsigned int _nic_completed() 
1426{
1427    return _dma_completed();
1428}
1429
1430///////////////////////////////////////////////////////////////////////////////////
1431// _heap_info()
1432// This function returns the information associated to a heap (size and vaddr)
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.
1435///////////////////////////////////////////////////////////////////////////////////
1436unsigned int _heap_info( unsigned int* vaddr, 
1437                         unsigned int* size ) 
1438{
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);
1443
1444    unsigned int taskid        = _get_context_slot(CTX_GTID_ID);
1445    unsigned int vspaceid      = _get_context_slot(CTX_VSID_ID);
1446
1447    int heap_local_vobjid      = tasks[taskid].heap_vobjid;
1448    if (heap_local_vobjid != -1) 
1449    {
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    }
1455    else 
1456    {
1457        *vaddr = 0;
1458        *size = 0;
1459        return 0;
1460    }
1461}
1462
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.