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

Last change on this file since 271 was 271, checked in by cfuguet, 10 years ago
  • Bugfix: The ISR_SWITCH index should be NB_PROCS_MAX + local_pid. This is because the first NB_PROCS_MAX indexes on the XICU in each cluster are used for the WAKEUP software interrupts.
  • Relocating the memcpy and memset functions into the giet_libs/stdlib.* files.
  • Modification of the sort application to used 8 threads instead of
    1. Modifying the mapping files to distribute the 8 threads on the available processors. (Ex. When using 4 processors, each one executes 2 threads)
File size: 11.3 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_xy * 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 <tty_driver.h>
27#include <mapping_info.h>
28#include <utils.h>
29
30#if !defined(X_SIZE)
31# error: You must define X_SIZE in the hard_config.h file
32#endif
33
34#if !defined(Y_SIZE)
35# error: You must define X_SIZE in the hard_config.h file
36#endif
37
38#if !defined(X_WIDTH)
39# error: You must define X_WIDTH in the hard_config.h file
40#endif
41
42#if !defined(Y_WIDTH)
43# error: You must define X_WIDTH in the hard_config.h file
44#endif
45
46#if !defined(NB_PROCS_MAX)
47# error: You must define NB_PROCS_MAX in the hard_config.h file
48#endif
49
50#if !defined( USE_XICU )
51# error: You must define USE_XICU in the hard_config.h file
52#endif
53
54////////////////////////////////////////////////////////////////////////////////
55//     _xcu_set_mask()
56// This function set the mask register for the XICU channel identified
57// by the cluster index and the processor index.
58// All '1' bits are set / all '0' bits are not modified.
59// Returns 0 if success, > 0 if error.
60////////////////////////////////////////////////////////////////////////////////
61unsigned int _xcu_set_mask( unsigned int cluster_xy, 
62                            unsigned int proc_id,
63                            unsigned int value,
64                            unsigned int irq_type ) 
65{
66    // parameters checking
67    unsigned int x = cluster_xy >> Y_WIDTH;
68    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
69    if (x >= X_SIZE)             return 1; 
70    if (y >= Y_SIZE)             return 1; 
71    if (proc_id >= NB_PROCS_MAX) return 1; 
72
73#if USE_XICU
74    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
75                                (cluster_xy * (unsigned int)&vseg_cluster_increment));
76    unsigned int func;
77    if      (irq_type == IRQ_TYPE_PTI) func = XICU_MSK_PTI_ENABLE;
78    else if (irq_type == IRQ_TYPE_SWI) func = XICU_MSK_WTI_ENABLE;
79    else                               func = XICU_MSK_HWI_ENABLE;
80    xcu_address[XICU_REG(func,proc_id)] = value;
81    return 0;
82#else
83    _tty_get_lock( 0 );
84    _puts("[GIET ERROR] _xcu_set_mask should not be used if USE_XICU is not set\n");
85    _tty_release_lock( 0 );
86    return 1;
87#endif
88}
89
90////////////////////////////////////////////////////////////////////////////////
91//     _xcu_get_index()
92// This function returns the index of the highest priority (smaller index)
93// - active HWI (Hardware Interrupt), or
94// - active PTI (Timer Interrupt), or
95// - active SWI (Software Interrupt).
96// The ICU channel is identified by the cluster index and the processor index.
97// Returns 0 if success, > 0 if error.
98////////////////////////////////////////////////////////////////////////////////
99unsigned int _xcu_get_index( unsigned int cluster_xy, 
100                             unsigned int proc_id, 
101                             unsigned int * buffer) 
102{
103    // parameters checking
104    unsigned int x = cluster_xy >> Y_WIDTH;
105    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
106    if (x >= X_SIZE)             return 1; 
107    if (y >= Y_SIZE)             return 1; 
108    if (proc_id >= NB_PROCS_MAX) return 1; 
109
110#if USE_XICU
111    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
112                                (cluster_xy * (unsigned int)&vseg_cluster_increment));
113
114    unsigned int prio = xcu_address[XICU_REG(XICU_PRIO, proc_id)];
115    unsigned int pti_ok = (prio & 0x00000001);
116    unsigned int hwi_ok = (prio & 0x00000002);
117    unsigned int swi_ok = (prio & 0x00000004);
118    unsigned int pti_id = (prio & 0x00001F00) >> 8;
119    unsigned int hwi_id = (prio & 0x001F0000) >> 16;
120    unsigned int swi_id = (prio & 0x1F000000) >> 24;
121    if      (pti_ok)  *buffer = pti_id;
122    else if (hwi_ok)  *buffer = hwi_id;
123    else if (swi_ok)  *buffer = swi_id; 
124    else              *buffer = 32; 
125    return 0;
126#else
127    _tty_get_lock( 0 );
128    _puts("[GIET ERROR] _xcu_get_index should not be used if USE_XICU is not set\n");
129    _tty_release_lock( 0 );
130    return 1;
131#endif
132}
133
134////////////////////////////////////////////////////////////////////////////////
135//     _xcu_send_ipi()
136// This function can be used only in an architecture using  XICU components.
137// It writes the "wdata" value in the mailbox defined by the cluster index
138// and the processor index.
139// Returns 0 if success, > 0 if error.
140////////////////////////////////////////////////////////////////////////////////
141unsigned int _xcu_send_ipi( unsigned int cluster_xy,
142                            unsigned int proc_id,
143                            unsigned int wdata )
144{ 
145    // parameters checking
146    unsigned int x = cluster_xy >> Y_WIDTH;
147    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
148    if (x >= X_SIZE)             return 1; 
149    if (y >= Y_SIZE)             return 1; 
150    if (proc_id >= NB_PROCS_MAX) return 1; 
151
152#if USE_XICU
153    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
154                                 (cluster_xy * (unsigned int)&vseg_cluster_increment));
155    xcu_address[XICU_REG(XICU_WTI_REG, proc_id)] = wdata;
156    return 0; 
157#else
158    _tty_get_lock( 0 );
159    _puts("[GIET ERROR] _xcu_send_ipi should not be used if USE_XICU is not set\n");
160    _tty_release_lock( 0 );
161    return 1;
162#endif
163} 
164
165////////////////////////////////////////////////////////////////////////////////
166//    _xcu_timer_start()
167// This function activates a timer contained in XICU by writing in the
168// proper register the period value.
169// Returns 0 if success, > 0 if error.
170////////////////////////////////////////////////////////////////////////////////
171unsigned int _xcu_timer_start( unsigned int cluster_xy,
172                               unsigned int pti_index,
173                               unsigned int period )
174{
175    // parameters checking
176    unsigned int x = cluster_xy >> Y_WIDTH;
177    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
178    if (x >= X_SIZE)             return 1; 
179    if (y >= Y_SIZE)             return 1; 
180
181#if USE_XICU
182    unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
183                                (cluster_xy * (unsigned int)&vseg_cluster_increment));
184    xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = period;
185    return 0;
186#else
187    _tty_get_lock( 0 );
188    _puts("[GIET ERROR] _xcu_timer_start should not be used if USE_XICU is not set\n");
189    _tty_release_lock( 0 );
190    return 1;
191#endif
192}
193
194//////////////////////////////////////////////////////////////////////////////
195//     _xcu_timer_stop()
196// This function desactivates a timer in XICU component
197// by writing in the proper register.
198// Returns 0 if success, > 0 if error.
199//////////////////////////////////////////////////////////////////////////////
200unsigned int _xcu_timer_stop( unsigned int cluster_xy, 
201                              unsigned int pti_index) 
202{
203    // parameters checking
204    unsigned int x = cluster_xy >> Y_WIDTH;
205    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
206    if (x >= X_SIZE)             return 1; 
207    if (y >= Y_SIZE)             return 1; 
208
209#if USE_XICU
210    unsigned int * xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + 
211                                 (cluster_xy * (unsigned int)&vseg_cluster_increment));
212    xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = 0;
213    return 0;
214#else
215    _tty_get_lock( 0 );
216    _puts("[GIET ERROR] _xcu_timer_stop should not be used if USE_XICU is not set\n");
217    _tty_release_lock( 0 );
218    return 1;
219#endif
220}
221
222//////////////////////////////////////////////////////////////////////////////
223//     _xcu_timer_reset_irq()
224// This function acknowlegge a timer interrupt in XICU
225// component by reading in the proper register.
226// It can be used by both the isr_switch() for a "system" timer,
227// or by the _isr_timer() for an "user" timer.
228// Returns 0 if success, > 0 if error.
229//////////////////////////////////////////////////////////////////////////////
230unsigned int _xcu_timer_reset_irq( unsigned int cluster_xy, 
231                                   unsigned int pti_index ) 
232{
233    // parameters checking
234    unsigned int x = cluster_xy >> Y_WIDTH;
235    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
236    if (x >= X_SIZE)             return 1; 
237    if (y >= Y_SIZE)             return 1; 
238
239#if USE_XICU
240    volatile unsigned int * xcu_address =
241        (unsigned int *) ((unsigned int)&seg_xcu_base +
242        (cluster_xy * (unsigned int)&vseg_cluster_increment));
243
244    xcu_address[XICU_REG(XICU_PTI_ACK, pti_index)];
245    return 0;
246#else
247    _tty_get_lock( 0 );
248    _puts("[GIET ERROR] _xcu_timer_reset_irq should not be used if USE_XICU is not set\n");
249    _tty_release_lock( 0 );
250    return 1;
251#endif
252}
253
254//////////////////////////////////////////////////////////////////////////////
255//     _xcu_timer_reset_cpt()
256// This function resets a timer counter. To do so, we re-write the period
257// in the proper register, what causes the count to restart.
258// The period value is read from the same (TIMER_PERIOD) register,
259// this is why in appearance we do nothing useful (read a value
260// from a register and write this value in the same register)
261// This function is called during a context switch (user or preemptive)
262/////////////////////////////////////////////////////////////////////////////
263unsigned int _xcu_timer_reset_cpt( unsigned int cluster_xy, 
264                                   unsigned int pti_index ) 
265{
266    // parameters checking
267    unsigned int x = cluster_xy >> Y_WIDTH;
268    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
269    if (x >= X_SIZE)             return 1; 
270    if (y >= Y_SIZE)             return 1; 
271
272#if USE_XICU
273    unsigned int * xcu_address = (unsigned int *) ((unsigned int) &seg_xcu_base + 
274                                 (cluster_xy * (unsigned int)&vseg_cluster_increment));
275
276    unsigned int period = xcu_address[XICU_REG(XICU_PTI_PER, pti_index)];
277
278    // we write 0 first because if the timer is currently running,
279    // the corresponding timer counter is not reset
280    xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = 0;
281    xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = period;
282    return 0;
283#else
284    _tty_get_lock( 0 );
285    _puts("[GIET ERROR] _xcu_timer_reset_irq should not be used if USE_XICU is not set\n");
286    _tty_release_lock( 0 );
287    return 1;
288#endif
289}
290
291
292// Local Variables:
293// tab-width: 4
294// c-basic-offset: 4
295// c-file-offsets:((innamespace . 0)(inline-open . 0))
296// indent-tabs-mode: nil
297// End:
298// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
299
Note: See TracBrowser for help on using the repository browser.