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

Last change on this file since 252 was 249, checked in by alain, 11 years ago

Various modifications to support IO Bridge,
and MEMC configuration interface.

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