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

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

Adding a syscall to allow a user to know the block size with which the block device has been configured.

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