]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/arm/ebsa285/v2_0/tests/test_net_realtime.h
Initial revision
[karo-tx-redboot.git] / packages / devs / eth / arm / ebsa285 / v2_0 / tests / test_net_realtime.h
1 #ifndef CYGONCE_DEVS_ETH_ARM_EBSA285_TESTS_TEST_NET_REALTIME_H
2 #define CYGONCE_DEVS_ETH_ARM_EBSA285_TESTS_TEST_NET_REALTIME_H
3 /*==========================================================================
4 //
5 //        test_net_realtime.h
6 //
7 //        Auxiliary test header file
8 //        Provide a thread that runs on EBSA only, which verifies that
9 //        realtime characteristics are preserved.
10 //
11 //==========================================================================
12 //####ECOSGPLCOPYRIGHTBEGIN####
13 // -------------------------------------------
14 // This file is part of eCos, the Embedded Configurable Operating System.
15 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
16 //
17 // eCos is free software; you can redistribute it and/or modify it under
18 // the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 or (at your option) any later version.
20 //
21 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
22 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24 // for more details.
25 //
26 // You should have received a copy of the GNU General Public License along
27 // with eCos; if not, write to the Free Software Foundation, Inc.,
28 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
29 //
30 // As a special exception, if other files instantiate templates or use macros
31 // or inline functions from this file, or you compile this file and link it
32 // with other works to produce a work based on this file, this file does not
33 // by itself cause the resulting work to be covered by the GNU General Public
34 // License. However the source code for this file must still be made available
35 // in accordance with section (3) of the GNU General Public License.
36 //
37 // This exception does not invalidate any other reasons why a work based on
38 // this file might be covered by the GNU General Public License.
39 //
40 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
41 // at http://sources.redhat.com/ecos/ecos-license/
42 // -------------------------------------------
43 //####ECOSGPLCOPYRIGHTEND####
44 //==========================================================================
45 //#####DESCRIPTIONBEGIN####
46 //
47 // Author(s):     hmt
48 // Contributors:  hmt
49 // Date:          2000-05-03
50 // Description:
51 //
52 //####DESCRIPTIONEND####
53 */
54
55 // This is the API to this file:
56
57 #define TNR_OFF() tnr_active = 0
58 #define TNR_ON()  tnr_active = 1
59 #define TNR_INIT() tnr_init()
60 #define TNR_PRINT_ACTIVITY() tnr_print_activity() 
61
62 // Tests should use these if they are defined to test that the realtime
63 // characteristics of the world are preserved during a test.
64 //
65 // It is accepted that printing stuff via diag_printf() (and the test
66 // infra) disables interrupts for a long time.  So invoke TNR_OFF/ON()
67 // either side of diagnostic prints, to prevent boguf firings of the
68 // realtime test.
69
70 // ------------------------------------------------------------------------
71
72 // This file rather assumes that the network is in use, and that therefore
73 // there is also a kernel, and so on....
74
75 #include <cyg/infra/testcase.h>         // CYG_TEST_FAIL et al
76 #include <cyg/infra/diag.h>             // diag_printf()
77 #include <cyg/kernel/kapi.h>            // Thread API
78
79 #include <cyg/hal/hal_arch.h>           // CYGNUM_HAL_STACK_SIZE_TYPICAL
80 #include <cyg/hal/hal_intr.h>           // Interrupt names
81 #include <cyg/hal/hal_ebsa285.h>        // Hardware definitions
82
83 // The EBSA has 4 hardware timers; timer 3 is the kernel's realtime clock
84 // because it is connected to a separate, indepenent 3.68MHz signal; timer
85 // 4 can be used as a watchdog.  So we have timers 1 and 2 to use.
86 // Timers 1 and 2 have an input clock of 50MHz on fclk_in.
87 // Timer 2 should be initialized for periodic interrupts per 500uS.
88 // Timer 1 should be initialized for a one-shot interrupt after 1mS (1000uS).
89 //
90 // Timer 2's ISR examines the state of timer 1; if it has expired, the test
91 // has failed.  7 out of 8 hits, timer 1 is reinitialized for the 1mS; on
92 // the 8th event, timer1 is set for 2mS.  The next timer 2 event calls its
93 // DSR, which in turn signals a semaphore which awakens a real task, which
94 // again checks and re-initializes timer1 in the same way.
95 //
96 // All this ensures that interrupts are never delayed by more than 500uS,
97 // and that signalling a real task always takes less than 1500uS.
98 //
99 // This system, once activated, will run non-intrusively along with all
100 // networking tests.
101 //
102 // Special care (aka a hack) may be needed to make it work with the
103 // diagnostic channel; that disables interrupts typically for
104 //   100[characters] * 8[bits/byte] / 38400[Baud]  [Seconds] = 20mS.
105
106 // Use the fclk_in divided-by 256 mode:
107 #if 0 // Default, really 1mS, 2mS, 500uS
108 #define TNR_TIMER1_PERIOD_1mS     ((50 * 1000)     >>8)
109 #define TNR_TIMER1_PERIOD_2mS     ((50 * 1000 * 2) >>8)
110 #define TNR_TIMER2_PERIOD_500uS   ((50 *  500)     >>8)
111 #else // pushing the envelope... 1/5 as much:
112 #define FACTOR 200 // 1000 is "normal"
113 #define TNR_TIMER1_PERIOD_1mS     ((50 * FACTOR)     >>8)
114 #define TNR_TIMER1_PERIOD_2mS     ((50 * FACTOR * 2) >>8)
115 #define TNR_TIMER2_PERIOD_500uS   ((50 * FACTOR / 2) >>8)
116 #endif
117
118 #define TNR_TIMER1_INIT   (0x88)  // Enabled, free running, fclk_in/256
119 #define TNR_TIMER2_INIT   (0xc8)  // Enabled, periodic, fclk_in/256
120
121 // This way, if timer1 is > TNR_TIMER1_PERIOD_2mS, then we know it has
122 // wrapped; its full range is 85 seconds, one would hope to get back in
123 // that time!
124
125 static volatile int tnr_active = 0;
126 static volatile int tnr_t2_counter = 0;
127
128 static  cyg_sem_t tnr_sema;
129
130 static char tnr_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
131 static cyg_thread tnr_thread_data;
132 static cyg_handle_t tnr_thread_handle;
133
134 static cyg_interrupt tnr_t1_intr, tnr_t2_intr;
135 static cyg_handle_t tnr_t1_inth, tnr_t2_inth;
136
137 struct {
138     int timer1_isr;
139     int timer2_isr;
140     int timer2_isr_active;
141     int timer2_dsr;
142     int timer2_thd;
143     int timer2_thd_active;
144 } tnr_activity_counts = { 0,0,0,0,0,0 };
145         
146
147 static cyg_uint32 tnr_timer1_isr(cyg_vector_t vector, cyg_addrword_t data)
148 {
149     tnr_activity_counts.timer1_isr++;
150
151     if ( tnr_active )
152         CYG_TEST_FAIL_EXIT( "test_net_realtime: Timer1 fired" );
153
154     *SA110_TIMER1_CLEAR = 0; // Clear any pending interrupt (Data: don't care)
155     HAL_INTERRUPT_ACKNOWLEDGE( CYGNUM_HAL_INTERRUPT_TIMER_1 );
156
157     return CYG_ISR_HANDLED;
158 }
159
160 static cyg_uint32 tnr_timer2_isr(cyg_vector_t vector, cyg_addrword_t data)
161 {
162     tnr_activity_counts.timer2_isr++;
163
164     *SA110_TIMER2_CLEAR = 0; // Clear any pending interrupt (Data: don't care)
165     HAL_INTERRUPT_ACKNOWLEDGE( CYGNUM_HAL_INTERRUPT_TIMER_2 );
166
167     if ( tnr_active ) {
168         tnr_activity_counts.timer2_isr_active++;
169         if ( (*SA110_TIMER1_VALUE) > (4 * TNR_TIMER1_PERIOD_1mS) ) {
170             // Then it has wrapped around, bad bad bad
171             CYG_TEST_FAIL_EXIT( "tnr_timer2_isr: Timer1 wrapped" );
172         }
173     }
174     tnr_t2_counter++;
175     // We go though each of the following states in turn:
176     switch ( tnr_t2_counter & 7 ) {
177     case 0:
178         // Then this is an 8th event:
179         *SA110_TIMER1_LOAD = TNR_TIMER1_PERIOD_2mS;
180         return CYG_ISR_HANDLED;
181     case 1:
182         return CYG_ISR_CALL_DSR; // See how long to call a DSR &c..
183         // without resetting timer1: 1500uS left now
184     default:
185         // Reset timer1 again.  By doing this in time every time it should
186         // never fire.
187         *SA110_TIMER1_LOAD = TNR_TIMER1_PERIOD_1mS;
188     }
189     return CYG_ISR_HANDLED;
190 }
191     
192 static void tnr_timer2_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
193 {
194     tnr_activity_counts.timer2_dsr++;
195
196     if ( CYGNUM_HAL_INTERRUPT_TIMER_2 != vector )
197         CYG_TEST_FAIL_EXIT( "tnr_timer2_dsr: Bad vector" );
198
199     cyg_semaphore_post( &tnr_sema );
200 }
201
202 static void tnr_timer2_service_thread( cyg_addrword_t param )
203 {
204     while (1) {
205         cyg_semaphore_wait( &tnr_sema );
206         tnr_activity_counts.timer2_thd++;
207         if ( tnr_active ) {
208             tnr_activity_counts.timer2_thd_active++;
209             if ( (*SA110_TIMER1_VALUE) > (4 * TNR_TIMER1_PERIOD_1mS) ) {
210                 // Then it has wrapped around, bad bad bad
211                 CYG_TEST_FAIL_EXIT( "tnr_timer2_service_thread: Timer1 wrapped" );
212             }
213         }
214         // Reset timer1 again.  By doing this in time every time it should
215         // never fire.
216         *SA110_TIMER1_LOAD = TNR_TIMER1_PERIOD_1mS;
217     }
218 }
219
220
221 static void tnr_init( void )
222 {
223     // init the semaphore
224     cyg_semaphore_init( &tnr_sema, 0 );
225
226     // create and start the thread
227     cyg_thread_create(2,                  // Priority - just a number
228                       tnr_timer2_service_thread,
229                       0,                  // entry parameter
230                       "Test Net Realtime tnr_timer2_service_thread",
231                      &tnr_stack[0],       // Stack
232                       sizeof(tnr_stack),  // Size
233                       &tnr_thread_handle, // Handle
234                       &tnr_thread_data    // Thread data structure
235         );
236     cyg_thread_resume( tnr_thread_handle );
237
238     // set up and attach the interrupts et al...
239     cyg_interrupt_create(
240         CYGNUM_HAL_INTERRUPT_TIMER_2,   /* Vector to attach to       */
241         0,                              /* Queue priority            */
242         0,                              /* Data pointer              */
243         tnr_timer2_isr,                 /* Interrupt Service Routine */
244         tnr_timer2_dsr,                 /* Deferred Service Routine  */
245         &tnr_t2_inth,                   /* returned handle           */
246         &tnr_t2_intr                    /* put interrupt here        */
247         );
248     
249     cyg_interrupt_create(
250         CYGNUM_HAL_INTERRUPT_TIMER_1,   /* Vector to attach to       */
251         0,                              /* Queue priority            */
252         0,                              /* Data pointer              */
253         tnr_timer1_isr,                 /* Interrupt Service Routine */
254         tnr_timer2_dsr, /* re-use! */   /* Deferred Service Routine  */
255         &tnr_t1_inth,                   /* returned handle           */
256         &tnr_t1_intr                    /* put interrupt here        */
257         );
258     
259     cyg_interrupt_attach( tnr_t1_inth );
260     cyg_interrupt_attach( tnr_t2_inth );
261
262     *SA110_TIMER1_CONTROL = 0;          // Disable while we are setting up
263     *SA110_TIMER1_LOAD = TNR_TIMER1_PERIOD_2mS;
264     *SA110_TIMER1_CLEAR = 0;            // Clear any pending interrupt
265     *SA110_TIMER1_CONTROL = TNR_TIMER1_INIT;
266     *SA110_TIMER1_CLEAR = 0;            // Clear any pending interrupt again
267
268     *SA110_TIMER2_CONTROL = 0;          // Disable while we are setting up
269     *SA110_TIMER2_LOAD = TNR_TIMER2_PERIOD_500uS;
270     *SA110_TIMER2_CLEAR = 0;            // Clear any pending interrupt
271     *SA110_TIMER2_CONTROL = TNR_TIMER2_INIT;
272     *SA110_TIMER2_CLEAR = 0;            // Clear any pending interrupt again
273
274     cyg_interrupt_unmask( CYGNUM_HAL_INTERRUPT_TIMER_2 );
275     cyg_interrupt_unmask( CYGNUM_HAL_INTERRUPT_TIMER_1 );
276 }
277
278 static void tnr_print_activity( void )
279 {
280     int tmp = tnr_active;
281     tnr_active = 0;
282     diag_printf( "Test-net-realtime: interrupt activity log:\n" );
283     diag_printf( "    timer1_isr %10d\n", tnr_activity_counts.timer1_isr );
284     diag_printf( "    timer2_isr %10d\n", tnr_activity_counts.timer2_isr );
285     diag_printf( "      (active) %10d\n", tnr_activity_counts.timer2_isr_active );
286     diag_printf( "    timer2_dsr %10d\n", tnr_activity_counts.timer2_dsr );
287     diag_printf( "    timer2_thd %10d\n", tnr_activity_counts.timer2_thd );
288     diag_printf( "      (active) %10d\n", tnr_activity_counts.timer2_thd_active );
289     tnr_active = tmp;
290 }
291
292 #endif /* ifndef CYGONCE_DEVS_ETH_ARM_EBSA285_TESTS_TEST_NET_REALTIME_H */
293
294 /* EOF test_net_realtime.h */