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
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///////////////////////////////////////////////////////////////////////
252// _timer_reset_irq_cpt()
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    }
270
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)];
274
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
290/////////////////////////////////////////////////////////////////////////////////
291//     VciMultiTty driver
292/////////////////////////////////////////////////////////////////////////////////
293// There is only one multi_tty controler in the architecture.
294// The total number of TTYs is defined by the configuration parameter NB_TTY_CHANNELS.
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/////////////////////////////////////////////////////////////////////////////////
301
302// TTY variables
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 };
306in_unckdata unsigned int _tty_put_lock = 0;  // protect kernel TTY[0]
307
308////////////////////////////////////////////////////////////////////////////////
309//      _tty_error()
310////////////////////////////////////////////////////////////////////////////////
311void _tty_error(unsigned int tty_id, unsigned int task_id) 
312{
313    unsigned int proc_id = _procid();
314
315    _get_lock(&_tty_put_lock);
316    if (tty_id == 0xFFFFFFFF) {
317        _puts("\n[GIET ERROR] no TTY assigned to the task ");
318    }
319    else {
320        _puts("\n[GIET ERROR] TTY index too large for task ");
321    }
322    _putd(task_id);
323    _puts(" on processor ");
324    _putd(proc_id);
325    _puts("\n");
326    _release_lock(&_tty_put_lock);
327}
328
329
330/////////////////////////////////////////////////////////////////////////////////
331//      _tty_write()
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.
338/////////////////////////////////////////////////////////////////////////////////
339unsigned int _tty_write(const char * buffer, 
340                        unsigned int length) 
341{
342    unsigned int nwritten;
343    unsigned int tty_id = _get_context_slot(CTX_TTY_ID);
344    unsigned int* tty_address = (unsigned int *) &seg_tty_base;
345
346    for (nwritten = 0; nwritten < length; nwritten++) 
347    {
348        // check tty's status
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];
351    }
352    return nwritten;
353}
354
355//////////////////////////////////////////////////////////////////////////////
356//      _tty_read()
357// This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and
358// the associated kernel buffer, that has been written by the ISR.
359// It get the TTY terminal index from the context of the current task.
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.
363// The length argument is not used.
364// Returns 0 if the kernel buffer is empty, 1 if the buffer is full.
365//////////////////////////////////////////////////////////////////////////////
366unsigned int _tty_read(char * buffer, 
367                       unsigned int length) 
368{
369    unsigned int tty_id = _get_context_slot(CTX_TTY_ID);
370
371    if (_tty_get_full[tty_id] == 0) 
372    {
373        return 0;
374    }
375    else 
376    {
377        *buffer = _tty_get_buf[tty_id];
378        _tty_get_full[tty_id] = 0;
379        return 1;
380    }
381}
382
383////////////////////////////////////////////////////////////////////////////////
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.
389////////////////////////////////////////////////////////////////////////////////
390unsigned int _tty_get_char(unsigned int tty_id, 
391                           unsigned char * buffer) 
392{
393    // checking argument
394    if (tty_id >= NB_TTY_CHANNELS) { return 1; }
395
396    // compute terminal base address
397    unsigned int * tty_address = (unsigned int *) &seg_tty_base; 
398
399    *buffer = (unsigned char) tty_address[tty_id * TTY_SPAN + TTY_READ];
400    return 0;
401}
402
403
404////////////////////////////////////////////////////////////////////////////////
405//     VciMultiIcu or VciXicu driver
406////////////////////////////////////////////////////////////////////////////////
407// This hardware component is replicated in all clusters.
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,
410// because there is one private interrupt controler per processor.
411////////////////////////////////////////////////////////////////////////////////
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////////////////////////////////////////////////////////////////////////////////
420
421////////////////////////////////////////////////////////////////////////////////
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.
426// Returns 0 if success, > 0 if error.
427////////////////////////////////////////////////////////////////////////////////
428unsigned int _icu_set_mask( unsigned int cluster_id,
429                            unsigned int proc_id,
430                            unsigned int value,
431                            unsigned int is_timer) 
432{
433    // parameters checking
434    if (cluster_id >= NB_CLUSTERS) return 1; 
435    if (proc_id >= NB_PROCS_MAX)   return 1; 
436
437    unsigned int * icu_address = (unsigned int *) ((char *) &seg_icu_base + 
438                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
439#if USE_XICU
440    if (is_timer) 
441    {
442        icu_address[XICU_REG(XICU_MSK_PTI_ENABLE, proc_id)] = value;
443    }
444    else 
445    {
446        icu_address[XICU_REG(XICU_MSK_HWI_ENABLE, proc_id)] = value;
447    }
448#else
449    icu_address[proc_id * ICU_SPAN + ICU_MASK_SET] = value; 
450#endif
451    return 0;
452}
453
454
455////////////////////////////////////////////////////////////////////////////////
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.
460// Returns 0 if success, > 0 if error.
461////////////////////////////////////////////////////////////////////////////////
462unsigned int _icu_get_index( unsigned int cluster_id, 
463                             unsigned int proc_id, 
464                             unsigned int * buffer) 
465{
466    // parameters checking
467    if (cluster_id >= NB_CLUSTERS)  return 1;
468    if (proc_id >= NB_PROCS_MAX)    return 1;
469
470    unsigned int * icu_address = (unsigned int *) ((char *) &seg_icu_base + 
471                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
472#if USE_XICU
473    unsigned int prio = icu_address[XICU_REG(XICU_PRIO, proc_id)];
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;
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; }
484#else
485    *buffer = icu_address[proc_id * ICU_SPAN + ICU_IT_VECTOR]; 
486#endif
487    return 0;
488}
489
490
491////////////////////////////////////////////////////////////////////////////////
492//     VciGcd driver
493////////////////////////////////////////////////////////////////////////////////
494// The Greater Dommon Divider is a -very- simple hardware coprocessor
495// performing the computation of the GCD of two 32 bits integers.
496// It has no DMA capability.
497////////////////////////////////////////////////////////////////////////////////
498
499////////////////////////////////////////////////////////////////////////////////
500//     _gcd_write()
501// Write a 32-bit word in a memory mapped register of the GCD coprocessor.
502// Returns 0 if success, > 0 if error.
503////////////////////////////////////////////////////////////////////////////////
504unsigned int _gcd_write( unsigned int register_index, 
505                         unsigned int value) 
506{
507    // parameters checking
508    if (register_index >= GCD_END)  return 1; 
509
510    unsigned int * gcd_address = (unsigned int *) &seg_gcd_base;
511
512    gcd_address[register_index] = value; // write word
513    return 0;
514}
515
516
517////////////////////////////////////////////////////////////////////////////////
518//     _gcd_read()
519// Read a 32-bit word in a memory mapped register of the GCD coprocessor.
520// Returns 0 if success, > 0 if error.
521////////////////////////////////////////////////////////////////////////////////
522unsigned int _gcd_read( unsigned int register_index, 
523                        unsigned int * buffer ) 
524{
525    // parameters checking
526    if (register_index >= GCD_END)  return 1;
527
528    unsigned int * gcd_address = (unsigned int *) &seg_gcd_base;
529
530    *buffer = gcd_address[register_index]; // read word
531    return 0;
532}
533
534////////////////////////////////////////////////////////////////////////////////
535// VciBlockDevice driver
536////////////////////////////////////////////////////////////////////////////////
537// The VciBlockDevice is a single channel external storage contrÃŽler.
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//
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
576// transfer completion. When the completion is signaled, the _ioc_completed()
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
584// IOC global variables
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; 
590
591///////////////////////////////////////////////////////////////////////////////
592//      _ioc_access()
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.
600// Returns 0 if success, > 0 if error.
601///////////////////////////////////////////////////////////////////////////////
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),
616
617    // check buffer alignment
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; 
624    }
625
626    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base ;
627
628    unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
629    unsigned int length = count * block_size;
630
631    // get user space page table virtual address
632    unsigned int user_pt_vbase = _get_context_slot(CTX_PTAB_ID);
633
634    user_vpn_min = user_vaddr >> 12;
635    user_vpn_max = (user_vaddr + length - 1) >> 12;
636
637    // loop on all virtual pages covering the user buffer
638    for (vpn = user_vpn_min, ix2 = 0 ; 
639         vpn <= user_vpn_max ; 
640         vpn++, ix2++ ) 
641    {
642        // get ppn and flags for each vpn
643        unsigned int ko = _v2p_translate((page_table_t *) user_pt_vbase,
644                                          vpn,
645                                          &ppn,
646                                          &flags);
647        // check access rights
648        if (ko)
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; 
654        }
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; 
661        }
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; 
668        }
669
670        // save first ppn value
671        if (ix2 == 0) ppn_first = ppn;
672
673        if (IOMMU_ACTIVE) // the user buffer must be remapped in the I/0 space
674        {
675            // check buffer length < 2 Mbytes
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; 
682            }
683
684            // map the physical page in IOMMU page table
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);
692        }
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; 
702            }
703
704            // compute user buffer physical adress
705            buf_paddr = (((paddr_t)ppn_first) << 12) | (user_vaddr & 0xFFF);
706        }
707    } // end for vpn
708
709    // register the number of pages to be unmapped
710    _ioc_iommu_npages = (user_vpn_max - user_vpn_min) + 1;
711
712    // invalidate data cache in case of memory write
713    if (to_mem) _dcache_buf_invalidate((void *) user_vaddr, length);
714
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
738
739    // get the lock on ioc device
740    _get_lock(&_ioc_lock);
741
742    // peripheral configuration 
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    }
752    ioc_address[BLOCK_DEVICE_COUNT] = count;
753    ioc_address[BLOCK_DEVICE_LBA] = lba;
754    if (to_mem == 0) 
755    {
756        ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
757    }
758    else 
759    {
760        ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
761    }
762    return 0;
763}
764
765/////////////////////////////////////////////////////////////////////////////////
766// _ioc_completed()
767//
768// This function checks completion of an I/O transfer and reports errors.
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.
772// Returns 0 if success, > 0 if error.
773/////////////////////////////////////////////////////////////////////////////////
774unsigned int _ioc_completed() 
775{
776    unsigned int ret;
777    unsigned int ix2;
778
779    // busy waiting
780    while (_ioc_done == 0) { asm volatile("nop"); }
781
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
792    // unmap the buffer from IOMMU page table if IOMMU is activated
793    if (IOMMU_ACTIVE) 
794    {
795        unsigned int * iob_address = (unsigned int *) &seg_iob_base;
796
797        for (ix2 = 0; ix2 < _ioc_iommu_npages; ix2++) 
798        {
799            // unmap the page in IOMMU page table
800            _iommu_inval_pte2(
801                    _ioc_iommu_ix1, // PT1 index
802                    ix2 );          // PT2 index
803
804            // clear IOMMU TLB
805            iob_address[IOB_INVAL_PTE] = (_ioc_iommu_ix1 << 21) | (ix2 << 12); 
806        }
807    }
808
809    // test IOC status
810    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
811            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1; // error
812    else                                                    ret = 0; // success
813
814    // reset synchronization variables
815    _ioc_done = 0;
816    asm volatile("sync");
817    _ioc_lock = 0;
818
819    return ret;
820}
821
822
823///////////////////////////////////////////////////////////////////////////////
824//     _ioc_read()
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///////////////////////////////////////////////////////////////////////////////
831unsigned int _ioc_read( unsigned int lba, 
832                        void * buffer, 
833                        unsigned int count) 
834{
835    return _ioc_access(
836            1,        // read access
837            lba,
838            (unsigned int) buffer,
839            count);
840}
841
842
843///////////////////////////////////////////////////////////////////////////////
844//     _ioc_write()
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///////////////////////////////////////////////////////////////////////////////
851unsigned int _ioc_write( unsigned int lba, 
852                         const void * buffer, 
853                         unsigned int count) 
854{
855    return _ioc_access(
856            0, // write access
857            lba,
858            (unsigned int) buffer,
859            count);
860}
861
862
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///////////////////////////////////////////////////////////////////////////////
868unsigned int _ioc_get_status(unsigned int * status) 
869{
870    // get IOC base address
871    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
872
873    *status = ioc_address[BLOCK_DEVICE_STATUS]; // read status & reset IRQ
874    return 0;
875}
876
877
878///////////////////////////////////////////////////////////////////////////////
879//     _ioc_get_block_size()
880// This function returns the block_size with which the IOC has been configured.
881///////////////////////////////////////////////////////////////////////////////
882unsigned int _ioc_get_block_size() 
883{
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
891//////////////////////////////////////////////////////////////////////////////////
892// VciMultiDma driver
893//////////////////////////////////////////////////////////////////////////////////
894// The DMA controllers are physically distributed in the clusters.
895// There is  (NB_CLUSTERS * NB_DMA_CHANNELS) channels, indexed by a global index:
896//        dma_id = cluster_id * NB_DMA_CHANNELS + loc_id
897//
898// As a DMA channel is a private ressource allocated to a task,
899// there is no lock protecting exclusive access to the channel.
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.
903//////////////////////////////////////////////////////////////////////////////////
904// The (virtual) base address of the associated segment is:
905//
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////////////////////////////////////////////////////////////////////////////////
911
912#if NB_DMA_CHANNELS > 0
913
914// in_unckdata unsigned int            _dma_lock[NB_DMA_CHANNELS * NB_CLUSTERS]
915// = { [0 ... (NB_DMA_CHANNELS * NB_CLUSTERS) - 1] = 0 };
916
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];
920in_unckdata unsigned int _dma_iommu_ix1 = 1;
921in_unckdata unsigned int _dma_iommu_npages[NB_DMA_CHANNELS * NB_CLUSTERS];
922#endif
923
924//////////////////////////////////////////////////////////////////////////////////
925// _dma_reset_irq()
926//////////////////////////////////////////////////////////////////////////////////
927unsigned int _dma_reset_irq( unsigned int cluster_id, 
928                             unsigned int channel_id) 
929{
930#if NB_DMA_CHANNELS > 0
931    // parameters checking
932    if (cluster_id >= NB_CLUSTERS)  return 1;
933    if (channel_id >= NB_DMA_CHANNELS)  return 1; 
934
935    // compute DMA base address
936    unsigned int * dma_address = (unsigned int *) ((char *) &seg_dma_base + 
937                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
938
939    dma_address[channel_id * DMA_SPAN + DMA_RESET] = 0;           
940    return 0;
941#else
942    return -1;
943#endif
944}
945
946
947//////////////////////////////////////////////////////////////////////////////////
948// _dma_get_status()
949//////////////////////////////////////////////////////////////////////////////////
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
955    // parameters checking
956    if (cluster_id >= NB_CLUSTERS)  return 1;
957    if (channel_id >= NB_DMA_CHANNELS)  return 1;
958
959    // compute DMA base address
960    unsigned int * dma_address = (unsigned int *) ((char *) &seg_dma_base + 
961                                                   (cluster_id * GIET_CLUSTER_INCREMENT));
962
963    *status = dma_address[channel_id * DMA_SPAN + DMA_LEN];
964    return 0;
965#else
966    return -1;
967#endif
968}
969
970
971//////////////////////////////////////////////////////////////////////////////////
972// _dma_transfer()
973// Transfer data between a user buffer and a device buffer using DMA.
974// Only one device type is supported: Frame Buffer (dev_type == 0)
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//
982// The cluster_id and channel_id are obtained from task context (CTX_DMA_ID).
983// The user buffer must be mapped in user address space and word-aligned.
984// The user buffer length must be multiple of 4 bytes.
985// We compute the physical base addresses for both the device buffer
986// and the user buffer before programming the DMA transfer.
987// The GIET being fully static, we don't need to split the transfer in 4 Kbytes
988// pages, because the user buffer is contiguous in physical space.
989// Returns 0 if success, > 0 if error.
990//////////////////////////////////////////////////////////////////////////////////
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
998    unsigned int ko;           // unsuccessfull V2P translation
999    unsigned int device_vbase; // device buffer vbase address
1000    unsigned int flags;        // protection flags
1001    unsigned int ppn;          // physical page number
1002    paddr_t      user_pbase;   // user buffer pbase address
1003    paddr_t      device_pbase; // frame buffer pbase address
1004
1005    // check user buffer address and length alignment
1006    if ((user_vaddr & 0x3) || (length & 0x3)) 
1007    {
1008        _get_lock(&_tty_put_lock);
1009        _puts("\n[GIET ERROR] in _dma_transfer : user buffer not word aligned\n");
1010        _release_lock(&_tty_put_lock);
1011        return 1;
1012    }
1013
1014    // get DMA channel and compute DMA vbase address
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));
1027    // get page table address
1028    unsigned int user_ptab = _get_context_slot(CTX_PTAB_ID);
1029
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;
1034    }
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;
1041    }
1042
1043    // get device buffer physical address
1044    ko = _v2p_translate( (page_table_t*) user_ptab, 
1045                         (device_vbase >> 12), 
1046                         &ppn, 
1047                         &flags );
1048    if (ko) 
1049    {
1050        _get_lock(&_tty_put_lock);
1051        _puts("\n[GIET ERROR] in _dma_transfer : device buffer unmapped\n");
1052        _release_lock(&_tty_put_lock);
1053        return 1;
1054    }
1055    device_pbase = ((paddr_t)ppn << 12) | (device_vbase & 0x00000FFF);
1056
1057    // Compute user buffer physical address
1058    ko = _v2p_translate( (page_table_t*) user_ptab, 
1059                         (user_vaddr >> 12), 
1060                         &ppn, 
1061                         &flags );
1062    if (ko) 
1063    {
1064        _get_lock(&_tty_put_lock);
1065        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer unmapped\n");
1066        _release_lock(&_tty_put_lock);
1067        return 1;
1068    } 
1069    if ((flags & PTE_U) == 0) 
1070    {
1071        _get_lock(&_tty_put_lock);
1072        _puts("[GIET ERROR] in _dma_transfer() : user buffer not in user space\n");
1073        _release_lock(&_tty_put_lock);
1074        return 1; 
1075    }
1076    if (((flags & PTE_W) == 0 ) && to_user) 
1077    {
1078        _get_lock(&_tty_put_lock);
1079        _puts("\n[GIET ERROR] in _dma_transfer() : user buffer not writable\n");
1080        _release_lock(&_tty_put_lock);
1081        return 1;
1082    }
1083    user_pbase = (((paddr_t)ppn) << 12) | (user_vaddr & 0x00000FFF);
1084
1085/*  This is a draft for IOMMU support
1086
1087    // loop on all virtual pages covering the user buffer
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;
1092
1093    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
1094    {
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 );
1100
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
1105
1106    // save first ppn value
1107    if ( ix2 == 0 ) ppn_first = ppn;
1108
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;
1113
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    }
1124
1125    // increment page index
1126    ix2++;
1127    } // end for vpn
1128
1129    // register the number of pages to be unmapped if iommu activated
1130    _dma_iommu_npages[dma_id] = (user_vpn_max - user_vpn_min) + 1;
1131
1132*/
1133
1134    // invalidate data cache in case of memory write
1135    if (to_user) _dcache_buf_invalidate((void *) user_vaddr, length);
1136
1137// get the lock
1138//  _get_lock(&_dma_lock[dma_id]);
1139
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
1162    // DMA configuration
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);
1169    }
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);
1176    }
1177    dma_vbase[channel_id * DMA_SPAN + DMA_LEN] = (unsigned int) length;
1178
1179    return 0;
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;
1186#endif
1187
1188}  // end _dma_transfer() 
1189
1190
1191//////////////////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////////////////////////////////////////
1199unsigned int _dma_completed() 
1200{
1201#if NB_DMA_CHANNELS > 0
1202    unsigned int dma_id  = _get_context_slot(CTX_DMA_ID);
1203    unsigned int dma_ret;
1204
1205    // busy waiting with a pseudo random delay between bus access
1206    while (_dma_done[dma_id] == 0) 
1207    {
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"); 
1218    }
1219
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
1231
1232    // reset synchronization variables
1233    _dma_done[dma_id] = 0;
1234    dma_ret = _dma_status[dma_id];
1235    asm volatile("sync\n");
1236
1237//    _dma_lock[dma_id] = 0;
1238
1239    return dma_ret;
1240
1241#else // NB_DMA_CHANNELS == 0
1242    return -1;
1243#endif
1244
1245}  // end _dma_completed
1246
1247
1248//////////////////////////////////////////////////////////////////////////////////
1249//     VciFrameBuffer driver
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
1260// between the user buffer and the frame buffer. A DMA channel is
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//////////////////////////////////////////////////////////////////////////////////
1271
1272unsigned int _fb_sync_write(unsigned int offset, 
1273                            const void * buffer, 
1274                            unsigned int length) 
1275{
1276    unsigned char * fb_address = (unsigned char *) &seg_fbf_base + offset;
1277    memcpy((void *) fb_address, (void *) buffer, length);
1278    return 0;
1279}
1280
1281
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//////////////////////////////////////////////////////////////////////////////////
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;
1294    memcpy((void *) buffer, (void *) fb_address, length);
1295    return 0;
1296}
1297
1298
1299//////////////////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////////////////////////////////////////
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 );
1316}
1317
1318
1319//////////////////////////////////////////////////////////////////////////////////
1320// _fb_read()
1321// Transfer data from the frame_buffer device to a memory buffer using  DMA.
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//////////////////////////////////////////////////////////////////////////////////
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 );
1336}
1337
1338
1339//////////////////////////////////////////////////////////////////////////////////
1340// _fb_completed()
1341// This function checks completion of a DMA transfer to or fom the frame buffer.
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)
1345//////////////////////////////////////////////////////////////////////////////////
1346unsigned int _fb_completed() 
1347{
1348    return _dma_completed();
1349}
1350
1351//////////////////////////////////////////////////////////////////////////////////
1352//     VciMultiNic driver
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//////////////////////////////////////////////////////////////////////////////////
1366
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//////////////////////////////////////////////////////////////////////////////////
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;
1379    memcpy((void *) nic_address, (void *) buffer, length);
1380    return 0;
1381}
1382
1383
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//////////////////////////////////////////////////////////////////////////////////
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);
1394    return 0;
1395}
1396
1397
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//////////////////////////////////////////////////////////////////////////////////
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 );   
1413}
1414
1415
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//////////////////////////////////////////////////////////////////////////////////
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 );   
1431}
1432
1433
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//////////////////////////////////////////////////////////////////////////////////
1441unsigned int _nic_completed() 
1442{
1443    return _dma_completed();
1444}
1445
1446///////////////////////////////////////////////////////////////////////////////////
1447// _heap_info()
1448// This function returns the information associated to a heap (size and vaddr)
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.
1451///////////////////////////////////////////////////////////////////////////////////
1452unsigned int _heap_info( unsigned int* vaddr, 
1453                         unsigned int* size ) 
1454{
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);
1459
1460    unsigned int taskid        = _get_context_slot(CTX_GTID_ID);
1461    unsigned int vspaceid      = _get_context_slot(CTX_VSID_ID);
1462
1463    int heap_local_vobjid      = tasks[taskid].heap_vobjid;
1464    if (heap_local_vobjid != -1) 
1465    {
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    }
1471    else 
1472    {
1473        *vaddr = 0;
1474        *size = 0;
1475        return 0;
1476    }
1477}
1478
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.