source: soft/giet_vm/giet_drivers/xcu_driver.c @ 260

Last change on this file since 260 was 258, checked in by alain, 11 years ago

This is a major release, including a deep restructuration of code.
The main evolutions are

  • use of the Tsar preloader to load the GIET boot-loader from disk
  • introduction of a FAT32 file system library,
  • use of this fat32 library by the boot-loader to load the map.bin data structure, and the various .elf files
  • reorganisation of drivers (one file per peripheral).
  • introduction of drivers for new peripherals: vci_chbuf_dma and vci_multi_ahci.
  • introduction of a new physical memory allocator in the boot code.

This release has been tested on the tsar_generic_iob architecture,
for the two following mappings: 4c_1p_iob_four.xml and 4c_1p_iob_sort.xml

File size: 10.4 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : xcu_driver.c
3// Date     : 23/05/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The xcu_driver.c and xcu_driver.h files are part ot the GIET-VM nano-kernel.
8// This driver supports the SoCLib vci_xicu, that is a vectorised interrupt
9// controler supporting IPI (Inter Processor Interrupts) and integrated timers.
10//
11// It can exist several interrupt controller unit in the architecture
12// (one per cluster), and each one can contain several channels.
13// The number of XICU channels is equal to NB_PROCS_MAX, because there is
14// one private XICU channel per processor in a cluster.
15////////////////////////////////////////////////////////////////////////////////
16// The virtual base address of the segment associated to the component is:
17//
18//      seg_xcu_base + cluster_id * vseg_cluster_increment
19//
20// The seg_xcu_base and vseg_cluster_increment values must be defined
21// in giet_vsegs.ld file.
22////////////////////////////////////////////////////////////////////////////////
23
24#include <giet_config.h>
25#include <xcu_driver.h>
26#include <utils.h>
27
28#if !defined(NB_CLUSTERS)
29# error: You must define NB_CLUSTERS in the hard_config.h file
30#endif
31
32#if (NB_CLUSTERS > 256)
33# error: NB_CLUSTERS cannot be larger than 256!
34#endif
35
36#if !defined(NB_PROCS_MAX)
37# error: You must define NB_PROCS_MAX in the hard_config.h file
38#endif
39
40#if (NB_PROCS_MAX > 8)
41# error: NB_PROCS_MAX cannot be larger than 8!
42#endif
43
44#if !defined( USE_XICU )
45# error: You must define USE_XICU in the hard_config.h file
46#endif
47
48////////////////////////////////////////////////////////////////////////////////
49//     _xcu_set_mask()
50// This function set the mask register for the XICU channel identified
51// by the cluster index and the processor index.
52// All '1' bits are set / all '0' bits are not modified.
53// Returns 0 if success, > 0 if error.
54////////////////////////////////////////////////////////////////////////////////
55unsigned int _xcu_set_mask( unsigned int cluster_id, unsigned int proc_id,
56                            unsigned int value,
57                            unsigned int is_PTI) 
58{
59    // parameters checking
60    if (cluster_id >= NB_CLUSTERS) return 1; 
61    if (proc_id >= NB_PROCS_MAX)   return 1; 
62
63#if USE_XICU
64    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
65                                (cluster_id * (unsigned int)&vseg_cluster_increment));
66    if (is_PTI) 
67        xcu_address[XICU_REG(XICU_MSK_PTI_ENABLE, proc_id)] = value;
68    else 
69        xcu_address[XICU_REG(XICU_MSK_HWI_ENABLE, proc_id)] = value;
70    return 0;
71#else
72    _tty_get_lock( 0 );
73    _puts("[GIET ERROR] _xcu_set_mask should not be used if USE_XICU is not set\n");
74    _tty_release_lock( 0 );
75    return 1;
76#endif
77}
78
79////////////////////////////////////////////////////////////////////////////////
80//     _xcu_get_index()
81// This function returns the index of the highest priority (smaller index)
82// - active HWI (Hardware Interrupt), or
83// - active PTI (Timer Interrupt), or
84// - active SWI (Software Interrupt).
85// The ICU channel is identified by the cluster index and the processor index.
86// Returns 0 if success, > 0 if error.
87////////////////////////////////////////////////////////////////////////////////
88unsigned int _xcu_get_index( unsigned int cluster_id, 
89                             unsigned int proc_id, 
90                             unsigned int * buffer) 
91{
92    // parameters checking
93    if (cluster_id >= NB_CLUSTERS)  return 1;
94    if (proc_id >= NB_PROCS_MAX)    return 1;
95
96#if USE_XICU
97    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
98                                (cluster_id * (unsigned int)&vseg_cluster_increment));
99
100    unsigned int prio = xcu_address[XICU_REG(XICU_PRIO, proc_id)];
101    unsigned int pti_ok = (prio & 0x00000001);
102    unsigned int hwi_ok = (prio & 0x00000002);
103    unsigned int swi_ok = (prio & 0x00000004);
104    unsigned int pti_id = (prio & 0x00001F00) >> 8;
105    unsigned int hwi_id = (prio & 0x001F0000) >> 16;
106    unsigned int swi_id = (prio & 0x1F000000) >> 24;
107    if      (pti_ok)  *buffer = pti_id;
108    else if (hwi_ok)  *buffer = hwi_id;
109    else if (swi_ok)  *buffer = swi_id; 
110    else              *buffer = 32; 
111    return 0;
112#else
113    _tty_get_lock( 0 );
114    _puts("[GIET ERROR] _xcu_get_index should not be used if USE_XICU is not set\n");
115    _tty_release_lock( 0 );
116    return 1;
117#endif
118}
119
120////////////////////////////////////////////////////////////////////////////////
121//     _xcu_send_ipi()
122// This function can be used only in an architecture using  XICU components.
123// It writes the "wdata" value in the mailbox defined by the cluster index
124// and the processor index.
125// Returns 0 if success, > 0 if error.
126////////////////////////////////////////////////////////////////////////////////
127unsigned int _xcu_send_ipi( unsigned int cluster_id,
128                            unsigned int proc_id,
129                            unsigned int wdata )
130{ 
131    // parameters checking
132    if (cluster_id >= NB_CLUSTERS)  return 1;
133    if (proc_id >= NB_PROCS_MAX)    return 1;
134
135#if USE_XICU
136    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
137                                 (cluster_id * (unsigned int)&vseg_cluster_increment));
138    xcu_address[XICU_REG(XICU_WTI_REG, proc_id)] = wdata;
139    return 0; 
140#else
141    _tty_get_lock( 0 );
142    _puts("[GIET ERROR] _xcu_send_ipi should not be used if USE_XICU is not set\n");
143    _tty_release_lock( 0 );
144    return 1;
145#endif
146} 
147
148////////////////////////////////////////////////////////////////////////////////
149//    _xcu_timer_start()
150// This function activates a timer contained in XICU by writing in the
151// proper register the period value.
152// Returns 0 if success, > 0 if error.
153////////////////////////////////////////////////////////////////////////////////
154unsigned int _xcu_timer_start( unsigned int cluster_id,
155                               unsigned int local_id,
156                               unsigned int period )
157{
158    // parameters checking
159    if (cluster_id >= NB_CLUSTERS)    return 1;
160    if (local_id >= NB_TIM_CHANNELS)  return 1;
161
162#if USE_XICU
163    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
164                                (cluster_id * (unsigned int)&vseg_cluster_increment));
165    xcu_address[XICU_REG(XICU_PTI_PER, local_id)] = period;
166    return 0;
167#else
168    _tty_get_lock( 0 );
169    _puts("[GIET ERROR] _xcu_timer_start should not be used if USE_XICU is not set\n");
170    _tty_release_lock( 0 );
171    return 1;
172#endif
173}
174
175//////////////////////////////////////////////////////////////////////////////
176//     _xcu_timer_stop()
177// This function desactivates a timer in XICU component
178// by writing in the proper register.
179// Returns 0 if success, > 0 if error.
180//////////////////////////////////////////////////////////////////////////////
181unsigned int _xcu_timer_stop( unsigned int cluster_id, 
182                              unsigned int local_id) 
183{
184    // parameters checking
185    if (cluster_id >= NB_CLUSTERS)    return 1;
186    if (local_id >= NB_TIM_CHANNELS)  return 1;
187
188#if USE_XICU
189    unsigned int * xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
190                                 (cluster_id * (unsigned int)&vseg_cluster_increment));
191    xcu_address[XICU_REG(XICU_PTI_PER, local_id)] = 0;
192    return 0;
193#else
194    _tty_get_lock( 0 );
195    _puts("[GIET ERROR] _xcu_timer_stop should not be used if USE_XICU is not set\n");
196    _tty_release_lock( 0 );
197    return 1;
198#endif
199}
200
201//////////////////////////////////////////////////////////////////////////////
202//     _xcu_timer_reset_irq()
203// This function acknowlegge a timer interrupt in XICU
204// component by reading in the proper register.
205// It can be used by both the isr_switch() for a "system" timer,
206// or by the _isr_timer() for an "user" timer.
207// Returns 0 if success, > 0 if error.
208//////////////////////////////////////////////////////////////////////////////
209unsigned int _xcu_timer_reset_irq( unsigned int cluster_id, 
210                                   unsigned int local_id ) 
211{
212    // parameters checking
213    if (cluster_id >= NB_CLUSTERS)    return 1;
214    if (local_id >= NB_TIM_CHANNELS)  return 1;
215
216#if USE_XICU
217    unsigned int * xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base +
218                                 (cluster_id * (unsigned int)&vseg_cluster_increment));
219
220    unsigned int bloup = xcu_address[XICU_REG(XICU_PTI_ACK, local_id)];
221    bloup++; // to avoid a warning
222    return 0;
223#else
224    _tty_get_lock( 0 );
225    _puts("[GIET ERROR] _xcu_timer_reset_irq should not be used if USE_XICU is not set\n");
226    _tty_release_lock( 0 );
227    return 1;
228#endif
229}
230
231//////////////////////////////////////////////////////////////////////////////
232//     _xcu_timer_reset_cpt()
233// This function resets a timer counter. To do so, we re-write the period
234// in the proper register, what causes the count to restart.
235// The period value is read from the same (TIMER_PERIOD) register,
236// this is why in appearance we do nothing useful (read a value
237// from a register and write this value in the same register)
238// This function is called during a context switch (user or preemptive)
239/////////////////////////////////////////////////////////////////////////////
240unsigned int _xcu_timer_reset_cpt( unsigned int cluster_id, 
241                                   unsigned int local_id ) 
242{
243    // parameters checking
244    if (cluster_id >= NB_CLUSTERS)   return 1;
245    if (local_id >= NB_TIM_CHANNELS) return 1;
246
247#if USE_XICU
248    unsigned int * xcu_address = (unsigned int *) ((unsigned int) &seg_xcu_base + 
249                                 (cluster_id * (unsigned int)&vseg_cluster_increment));
250
251    unsigned int period = xcu_address[XICU_REG(XICU_PTI_PER, local_id)];
252
253    // we write 0 first because if the timer is currently running,
254    // the corresponding timer counter is not reset
255    xcu_address[XICU_REG(XICU_PTI_PER, local_id)] = 0;
256    xcu_address[XICU_REG(XICU_PTI_PER, local_id)] = period;
257    return 0;
258#else
259    _tty_get_lock( 0 );
260    _puts("[GIET ERROR] _xcu_timer_reset_irq should not be used if USE_XICU is not set\n");
261    _tty_release_lock( 0 );
262    return 1;
263#endif
264}
265
266
267// Local Variables:
268// tab-width: 4
269// c-basic-offset: 4
270// c-file-offsets:((innamespace . 0)(inline-open . 0))
271// indent-tabs-mode: nil
272// End:
273// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
274
Note: See TracBrowser for help on using the repository browser.