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

Last change on this file since 281 was 281, checked in by cfuguet, 10 years ago

Modifications in GIET_VM:

  • Supporting platforms with more than one IRQ per processor from the XICU.

When this is the case, the IRQ per processor can be signalled
by the XCU peripheric number of channels on the XML file.

The xml_parser will generate a constant on the hard_config.h
file, called IRQ_PER_PROCESSOR and this constant will be use
by the GIET_VM to create accordingly the irq masks on the
ICU

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