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

Last change on this file since 408 was 395, checked in by alain, 10 years ago

Cosmetic.

File size: 12.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// This peripheral is replicated in all clusters containing processors.
8//
9// SEG_XCU_BASE and PERI_CLUSTER_INCREMENT must be defined in hard_config.h file.
10///////////////////////////////////////////////////////////////////////////////////
11
12#include <hard_config.h>
13#include <giet_config.h>
14#include <xcu_driver.h>
15#include <tty_driver.h>
16#include <mapping_info.h>
17#include <utils.h>
18#include <io.h>
19
20#if !defined(X_SIZE)
21# error: You must define X_SIZE in the hard_config.h file
22#endif
23
24#if !defined(Y_SIZE)
25# error: You must define X_SIZE in the hard_config.h file
26#endif
27
28#if !defined(X_WIDTH)
29# error: You must define X_WIDTH in the hard_config.h file
30#endif
31
32#if !defined(Y_WIDTH)
33# error: You must define X_WIDTH in the hard_config.h file
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 !defined( USE_XCU )
41# error: You must define USE_XCU in the hard_config.h file
42#endif
43
44#if !defined( SEG_XCU_BASE )
45# error: You must define SEG_XCU_BASE in the hard_config.h file
46#endif
47
48#if !defined( PERI_CLUSTER_INCREMENT )
49# error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file
50#endif
51
52///////////////////////////////////////////////////////////////////////////////
53// This low level function returns the value contained in register "index"
54// in the XCU component contained in cluster "cluster_xy"
55///////////////////////////////////////////////////////////////////////////////
56static
57unsigned int _xcu_get_register( unsigned int cluster_xy, // cluster index
58                                unsigned int func,       // function index
59                                unsigned int index )     // register index
60{
61    unsigned int vaddr =
62        SEG_XCU_BASE + 
63        (cluster_xy * PERI_CLUSTER_INCREMENT) +
64        (XCU_REG(func, index) << 2);
65
66    return ioread32( (void*)vaddr );
67}
68
69///////////////////////////////////////////////////////////////////////////////
70// This low level function sets a new value in register "index"
71// in the XCU component contained in cluster "cluster_xy"
72///////////////////////////////////////////////////////////////////////////////
73static
74void _xcu_set_register( unsigned int cluster_xy,       // cluster index
75                        unsigned int func,             // func index
76                        unsigned int index,            // register index
77                        unsigned int value )           // value to be written
78{
79    unsigned int vaddr =
80        SEG_XCU_BASE + 
81        (cluster_xy * PERI_CLUSTER_INCREMENT) +
82        (XCU_REG(func, index) << 2);
83       
84    iowrite32( (void*)vaddr, value );
85}
86
87////////////////////////////////////////////////////////////////////////////////
88// This function set the mask register for the IRQ type defined by "irq_type",
89// and for the channel identified by the "cluster_xy" and "channel" arguments.
90// All '1' bits are set / all '0' bits are not modified.
91////////////////////////////////////////////////////////////////////////////////
92void _xcu_set_mask( unsigned int cluster_xy, 
93                    unsigned int channel, 
94                    unsigned int value,
95                    unsigned int irq_type ) 
96{
97#if USE_XCU
98    // parameters checking
99    unsigned int x = cluster_xy >> Y_WIDTH;
100    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
101    if (x >= X_SIZE)                                   _exit(); 
102    if (y >= Y_SIZE)                                   _exit(); 
103    if (channel >= (NB_PROCS_MAX * IRQ_PER_PROCESSOR)) _exit(); 
104
105    unsigned int func = 0;
106    if      (irq_type == IRQ_TYPE_PTI) func = XCU_MSK_PTI_ENABLE;
107    else if (irq_type == IRQ_TYPE_WTI) func = XCU_MSK_WTI_ENABLE;
108    else if (irq_type == IRQ_TYPE_HWI) func = XCU_MSK_HWI_ENABLE;
109    else
110    { 
111        _printf("[GIET ERROR] _xcu_set_mask() receives illegal IRQ type\n");
112        _exit();
113    }
114
115    _xcu_set_register(cluster_xy, func, channel, value);
116
117#else
118    _printf("[GIET ERROR] _xcu_set_mask() should not be used if USE_XCU not set\n");
119    _exit();
120#endif
121}
122
123////////////////////////////////////////////////////////////////////////////////
124// This function returns the index and the type of the highest priority
125// - active PTI (Timer Interrupt), then
126// - active HWI (Hardware Interrupt), then
127// - active WTI (Software Interrupt)
128// As the hardware can define more than one IRQ per processor, but the GIET
129// use only one, channel = lpid * IRQ_PER_PROCESSOR.
130////////////////////////////////////////////////////////////////////////////////
131void _xcu_get_index( unsigned int cluster_xy, 
132                     unsigned int channel,   
133                     unsigned int * index, 
134                     unsigned int * irq_type )
135{
136#if USE_XCU
137    // parameters checking
138    unsigned int x = cluster_xy >> Y_WIDTH;
139    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
140    if (x >= X_SIZE)                                   _exit(); 
141    if (y >= Y_SIZE)                                   _exit(); 
142    if (channel >= (NB_PROCS_MAX * IRQ_PER_PROCESSOR)) _exit(); 
143
144    unsigned int prio = _xcu_get_register(cluster_xy, XCU_PRIO, channel);
145    unsigned int pti_ok = (prio & 0x00000001);
146    unsigned int hwi_ok = (prio & 0x00000002);
147    unsigned int wti_ok = (prio & 0x00000004);
148    unsigned int pti_id = (prio & 0x00001F00) >> 8;
149    unsigned int hwi_id = (prio & 0x001F0000) >> 16;
150    unsigned int wti_id = (prio & 0x1F000000) >> 24;
151    if      (pti_ok)
152    {
153        *index    = pti_id;
154        *irq_type = IRQ_TYPE_PTI;
155    }
156    else if (hwi_ok)
157    {
158        *index    = hwi_id;
159        *irq_type = IRQ_TYPE_HWI;
160    }
161    else if (wti_ok) 
162    {
163        *index    = wti_id;
164        *irq_type = IRQ_TYPE_WTI;
165    }
166    else 
167    {
168        *index = 32;
169    }
170 
171#else
172    _printf("[GIET ERROR] _xcu_get_index should not be used if USE_XCU is not set\n");
173    _exit();
174#endif
175}
176
177////////////////////////////////////////////////////////////////////////////////
178// This function writes the "wdata" value in the mailbox defined
179// by the "cluster_xy" and "wti_index" arguments.
180////////////////////////////////////////////////////////////////////////////////
181void _xcu_send_wti( unsigned int cluster_xy,
182                    unsigned int wti_index,
183                    unsigned int wdata )
184{ 
185#if USE_XCU
186    // parameters checking
187    unsigned int x = cluster_xy >> Y_WIDTH;
188    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
189    if (x >= X_SIZE)               _exit(); 
190    if (y >= Y_SIZE)               _exit(); 
191    if (wti_index >= 32)           _exit(); 
192
193    _xcu_set_register(cluster_xy, XCU_WTI_REG, wti_index, wdata);
194
195#else
196    _printf("[GIET ERROR] _xcu_send_wti() should not be used if USE_XCU is not set\n");
197    _exit();
198#endif
199} 
200
201////////////////////////////////////////////////////////////////////////////////
202// This function returns the value contained in a WTI mailbox defined by
203// the cluster_xy and "wti_index" arguments. This value is written in
204// the "value" argument, and the corresponding WTI is acknowledged.
205// returns 0 if success, > 0 if error.
206////////////////////////////////////////////////////////////////////////////////
207void _xcu_get_wti_value( unsigned int   cluster_xy,
208                         unsigned int   wti_index,
209                         unsigned int * value )
210{
211#if USE_XCU
212    // parameters checking
213    unsigned int x = cluster_xy >> Y_WIDTH;
214    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
215    if (x >= X_SIZE)               _exit(); 
216    if (y >= Y_SIZE)               _exit(); 
217    if (wti_index >= 32)           _exit(); 
218 
219    *value = _xcu_get_register(cluster_xy, XCU_WTI_REG, wti_index);
220
221#else
222    _printf("[GIET ERROR] in _xcu_get_wti_value() USE_XCU is not set\n");
223    _exit();
224#endif
225}
226
227////////////////////////////////////////////////////////////////////////////////
228// This function returns the address of a WTI mailbox defined by
229// the "wti_index" argument, in the unsigned int "address" argument.
230// It is used by the GIET to configurate the IOPIC component.
231// There is no access to a specific XCU component in a specific cluster.
232// returns 0 if success, > 0 if error.
233////////////////////////////////////////////////////////////////////////////////
234void _xcu_get_wti_address( unsigned int   wti_index,
235                           unsigned int * address )
236{
237#if USE_XCU
238    if (wti_index >= 32)           _exit(); 
239 
240    *address = SEG_XCU_BASE + (XCU_REG(XCU_WTI_REG, wti_index)<<2); 
241
242#else
243    _printf("[GIET ERROR] in _xcu_get_wti_address() USE_XCU is not set\n");
244    _exit();
245#endif
246}
247
248////////////////////////////////////////////////////////////////////////////////
249// This function activates a timer contained in XCU by writing in the
250// proper register the period value.
251////////////////////////////////////////////////////////////////////////////////
252void _xcu_timer_start( unsigned int cluster_xy,
253                       unsigned int pti_index,
254                       unsigned int period )
255{
256#if USE_XCU
257    // parameters checking
258    unsigned int x = cluster_xy >> Y_WIDTH;
259    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
260    if (x >= X_SIZE)             _exit(); 
261    if (y >= Y_SIZE)             _exit(); 
262
263    _xcu_set_register(cluster_xy, XCU_PTI_PER, pti_index, period);
264
265#else
266    _printf("[GIET ERROR] in _xcu_timer_start() USE_XCU is not set\n");
267    _exit();
268#endif
269}
270
271//////////////////////////////////////////////////////////////////////////////
272// This function desactivates a timer in XCU component
273// by writing in the proper register.
274//////////////////////////////////////////////////////////////////////////////
275void _xcu_timer_stop( unsigned int cluster_xy, 
276                      unsigned int pti_index) 
277{
278#if USE_XCU
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)             _exit(); 
283    if (y >= Y_SIZE)             _exit(); 
284
285    _xcu_set_register(cluster_xy, XCU_PTI_PER, pti_index, 0);
286
287#else
288    _printf("[GIET ERROR] in _xcu_timer_stop() USE_XCU is not set\n");
289    _exit();
290#endif
291}
292
293//////////////////////////////////////////////////////////////////////////////
294// This function acknowlegge a timer interrupt in XCU
295// component by reading in the proper XCU register.
296// It can be used by both the isr_switch() for a "system" timer,
297// or by the _isr_timer() for an "user" timer.
298//////////////////////////////////////////////////////////////////////////////
299unsigned int _xcu_timer_reset_irq( unsigned int cluster_xy, 
300                                   unsigned int pti_index ) 
301{
302#if USE_XCU
303    // parameters checking
304    unsigned int x = cluster_xy >> Y_WIDTH;
305    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
306    if (x >= X_SIZE)             _exit(); 
307    if (y >= Y_SIZE)             _exit(); 
308
309    // This return value is not used / avoid a compilation warning.
310    return _xcu_get_register(cluster_xy, XCU_PTI_ACK, pti_index);
311
312#else
313    _printf("[GIET ERROR] in _xcu_timer_reset_irq() USE_XCU is not set\n");
314    _exit();
315    return 0;
316#endif
317}
318
319//////////////////////////////////////////////////////////////////////////////
320// This function resets a timer counter. To do so, we re-write the period
321// in the proper register, what causes the count to restart.
322// The period value is read from the same (TIMER_PERIOD) register,
323// this is why in appearance we do nothing useful (read a value
324// from a register and write this value in the same register).
325// This function is called during a context switch (user or preemptive)
326/////////////////////////////////////////////////////////////////////////////
327void _xcu_timer_reset_cpt( unsigned int cluster_xy, 
328                           unsigned int pti_index ) 
329{
330#if USE_XCU
331    // parameters checking
332    unsigned int x = cluster_xy >> Y_WIDTH;
333    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
334    if (x >= X_SIZE)             _exit(); 
335    if (y >= Y_SIZE)             _exit(); 
336
337    unsigned int per = _xcu_get_register(cluster_xy, XCU_PTI_PER, pti_index);
338
339    // we write 0 first because if the timer is currently running,
340    // the corresponding timer counter is not reset
341    _xcu_set_register(cluster_xy, XCU_PTI_PER, pti_index, 0);
342    _xcu_set_register(cluster_xy, XCU_PTI_PER, pti_index, per);
343
344#else
345    _printf("[GIET ERROR] in _xcu_timer_reset_cpt() USE_XCU is not set\n");
346    _exit();
347#endif
348}
349
350
351// Local Variables:
352// tab-width: 4
353// c-basic-offset: 4
354// c-file-offsets:((innamespace . 0)(inline-open . 0))
355// indent-tabs-mode: nil
356// End:
357// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
358
Note: See TracBrowser for help on using the repository browser.