fe0b7f7403f4c78662987ee028c24264ee9e420e
[barrelfish] / usr / tests / irqtest / irqtest.c
1 /**
2  * \file
3  * \brief A simple test for checking if lpc_timer works
4  * It tests periodic timers implemented by timer library.
5  * test_A: When no arguments are given, then timer_test will run test_A
6  * which starts two periodic timers and stops them after 100 callbacks
7  * from each of them.
8  *
9  * test_B: When there are command line arguments given, then timer_test
10  * will run test_B.  This test registers three periodic timer and stops
11  * when 100 callbacks are received from all three timers.
12  *
13  * It is advised to run both test_A and test_B at same time.  It can be
14  * done by inserting following lines into the menu.lst
15  * module       /x86_64/sbin/lpc_timer core=1
16  * module       /x86_64/sbin/timer_test core=2
17  * module       /x86_64/sbin/timer_test core=3 B
18  *
19  */
20
21 /*
22  * Copyright (c) 2007, 2008, ETH Zurich.
23  * All rights reserved.
24  *
25  * This file is distributed under the terms in the attached LICENSE file.
26  * If you do not find this file, copies can be found by writing to:
27  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <barrelfish/barrelfish.h>
34 #include <barrelfish/nameservice_client.h>
35 #include <barrelfish/waitset.h>
36 #include <pci/pci.h>
37 #include "irqtest_debug.h"
38 #include "e1000n.h"
39 #include "stdint.h"
40
41 /*****************************************************************
42  * Local states:
43  *****************************************************************/
44 static uint32_t class = PCI_CLASS_ETHERNET;
45 static uint32_t subclass = PCI_DONT_CARE;
46 static uint32_t bus = PCI_DONT_CARE;
47 static uint32_t device = PCI_DONT_CARE;
48 static uint32_t function = PCI_DONT_CARE;
49 //static uint32_t deviceid = 0x1079; //sbrinz1/2
50 static uint32_t deviceid = 0x107d; //appenzeller
51 static uint32_t vendor = PCI_VENDOR_INTEL;
52 static uint32_t program_interface = PCI_DONT_CARE;
53 static e1000_mac_type_t mac_type = e1000_undefined;
54
55 /*****************************************************************
56  * Local states:
57  *****************************************************************/
58 static uint64_t minbase = -1;
59 static uint64_t maxbase = -1;
60
61 /*****************************************************************
62  * e1000 states:
63  *****************************************************************/
64 static e1000_t e1000;
65 static e1000_device_t e1000_device;
66 static bool e1000_initialized = false;
67 static uint8_t mac_address[MAC_ADDRESS_LEN]; /* buffers the card's MAC address upon card reset */
68
69 /*****************************************************************
70  * Receive and transmit
71  *****************************************************************/
72 static e1000_rx_bsize_t receive_buffer_size = bsize_16384;
73 static volatile struct tx_desc *transmit_ring;
74
75 //receive
76 static volatile union rx_desc *receive_ring;
77
78
79 //static uint32_t receive_bufptr = 0;
80
81 static void **receive_opaque = NULL;
82
83
84 #define DRIVER_RECEIVE_BUFFERS      (1024 * 8)
85 #define DRIVER_TRANSMIT_BUFFERS     (1024 * 8)
86
87 #define PACKET_SIZE_LIMIT       1073741824      /* 1 Gigabyte */
88
89
90
91
92
93
94
95 static void setup_internal_memory(void)
96 {
97     receive_opaque = calloc(sizeof(void *), DRIVER_RECEIVE_BUFFERS);
98     assert(receive_opaque != NULL );
99 }
100
101
102
103
104 static void e1000_init_fn(struct device_mem *bar_info, int nr_allocated_bars)
105 {
106     IRQ_DEBUG("Starting hardware initialization.\n");
107     e1000_hwinit(&e1000_device, bar_info, nr_allocated_bars, &transmit_ring,
108                  &receive_ring, DRIVER_RECEIVE_BUFFERS, DRIVER_TRANSMIT_BUFFERS,
109                  mac_address, false, 1);
110
111     // Disable interrupt throttling
112     e1000_itr_interval_wrf(e1000_device.device, 0);
113     e1000_eitr_interval_wrf(e1000_device.device, 0, 0);
114
115     e1000_initialized = true;
116     IRQ_DEBUG("Hardware initialization complete.\n");
117
118     setup_internal_memory();
119
120 }
121
122 /*****************************************************************
123  * e1000 interrupt handler
124  *
125  ****************************************************************/
126 static int64_t interrupt_counter = 0;
127 static int64_t int_trigger_counter = 0;
128 static void e1000_interrupt_handler_fn(void *arg)
129 {
130     /* Read interrupt cause, this also acknowledges the interrupt */
131     e1000_intreg_t icr = e1000_icr_rd(e1000_device.device);
132
133     printf("#### interrupt handler called: %"PRIi64"\n", interrupt_counter);
134     ++interrupt_counter;
135
136     if (e1000_intreg_rxt0_extract(icr) == 0) {
137         return;
138     }
139 }
140
141 static void e1000_reregister_handler(void *arg)
142 {
143     errval_t err;
144     printf("%s:%s:%d:\n", __FILE__, __FUNCTION__, __LINE__);
145     err = pci_reregister_irq_for_device(
146             class, subclass, program_interface,
147             vendor, deviceid, bus, device, function,
148             e1000_interrupt_handler_fn, NULL,
149             e1000_reregister_handler, NULL);
150     if (err_is_fail(err)) {
151         DEBUG_ERR(err, "pci_reregister_irq_for_device");
152     }
153
154     return;
155 }
156
157
158 int main(int argc, char **argv)
159 {
160     errval_t err;
161
162     /** Parse command line arguments. */
163     IRQ_DEBUG("irq test started.\n");
164
165     IRQ_DEBUG("argc = %d\n", argc);
166
167     err = pci_parse_int_arg(argc,argv);
168     if(err_is_fail(err)){
169         IRQ_DEBUG("Could not parse int argument");
170     }
171
172     for (int i = 1; i < argc; i++) {
173         IRQ_DEBUG("arg %d = %s\n", i, argv[i]);
174         if (strcmp(argv[i], "auto") == 0) {
175             continue;
176         }
177         if (strncmp(argv[i], "affinitymin=", strlen("affinitymin=")) == 0) {
178             minbase = atol(argv[i] + strlen("affinitymin="));
179             IRQ_DEBUG("minbase = %lu\n", minbase);
180         } else if (strncmp(argv[i], "affinitymax=", strlen("affinitymax="))
181                  == 0) {
182             maxbase = atol(argv[i] + strlen("affinitymax="));
183             IRQ_DEBUG("maxbase = %lu\n", maxbase);
184         } else if(strncmp(argv[i],"bus=",strlen("bus=")-1)==0) {
185             bus = atol(argv[i] + strlen("bus="));
186             IRQ_DEBUG("bus = %ul\n", bus);
187         } else if (strncmp(argv[i], "device=", strlen("device=")) == 0) {
188             device = atol(argv[i] + strlen("device="));
189             IRQ_DEBUG("device = %ul\n", device);
190         } else if (strncmp(argv[i], "function=", strlen("function=")) == 0) {
191             function = atol(argv[i] + strlen("function="));
192             IRQ_DEBUG("function = %u\n", function);
193         } else if (strncmp(argv[i], "deviceid=", strlen("deviceid=")) == 0) {
194             deviceid = strtoul(argv[i] + strlen("deviceid="), NULL, 0);
195             IRQ_DEBUG("deviceid = %u\n", deviceid);
196         } else if (strcmp(argv[i], "-h") == 0 ||
197                  strcmp(argv[i], "--help") == 0) {
198             //exit_help(argv[0]);
199         } else {
200             IRQ_DEBUG("Parsed Kaluga device address %s.\n", argv[i]);
201         }
202     } // end for :
203
204     if ((minbase != -1) && (maxbase != -1)) {
205         IRQ_DEBUG("set memory affinity [%lx, %lx]\n", minbase, maxbase);
206         ram_set_affinity(minbase, maxbase);
207     }
208
209
210     IRQ_DEBUG("Starting standalone driver.\n");
211
212     /* Check if forced device id and vendor is known to be supported. */
213     mac_type = e1000_get_mac_type(vendor, deviceid);
214     if(mac_type == e1000_undefined){
215         IRQ_DEBUG("WARNING: Passed deviceid unknown.\n");
216     }
217
218
219     /* Setup known device info */
220     e1000_device.device = &e1000;
221     e1000_device.mac_type = mac_type;
222     e1000_device.device_id = deviceid;
223     if (e1000_device.mac_type == e1000_82575
224         || e1000_device.mac_type == e1000_82576
225         || e1000_device.mac_type == e1000_I210
226         || e1000_device.mac_type == e1000_I350) {
227         // These cards do not have a bsex reg entry
228         // therefore, we can't use 16384 buffer size.
229         // If we use smaller buffers than 2048 bytes the
230         // eop bit on received packets might not be set in case the package
231         // is biger than the receive buffer size and we don't handle these
232         // cases currently.
233         e1000_device.rx_bsize = bsize_2048;
234     } else {
235         e1000_device.rx_bsize = receive_buffer_size;
236     }
237     e1000_device.media_type = e1000_media_type_undefined;
238
239
240     IRQ_DEBUG("Connecting to PCI.\n");
241
242     err = pci_client_connect();
243     assert(err_is_ok(err));
244
245     err = pci_register_driver_movable_irq(e1000_init_fn, class, subclass, program_interface,
246                                           vendor, deviceid, bus, device, function,
247                                           e1000_interrupt_handler_fn, NULL,
248                                           e1000_reregister_handler,
249                                           NULL);
250     IRQ_DEBUG("########### Driver with interrupts ###########\n");
251
252
253     if (err_is_fail(err)) {
254         E1000_PRINT_ERROR("Error: %u, pci_register_driver failed\n", (unsigned int)err);
255         exit(err);
256     }
257
258     IRQ_DEBUG("Registered driver.\n");
259
260     IRQ_DEBUG("#### starting dispatch loop.\n");
261     uint64_t ticks_per_msec, current_tick;
262     uint64_t last_int_trigger_ticks = 0;
263     sys_debug_get_tsc_per_ms(&ticks_per_msec);
264     IRQ_DEBUG("Ticks per msec: %"PRIu64".\n", ticks_per_msec);
265     assert(err_is_ok(err));
266
267     while(true){
268         err = event_dispatch_non_block(get_default_waitset());
269         if(!err_is_ok(err) && err != LIB_ERR_NO_EVENT) {
270             IRQ_DEBUG("Error in event_dispatch_non_block, returned %s\n",
271                     err_getstring(err));
272         }
273
274         if(int_trigger_counter >= 20){
275             if(abs(int_trigger_counter - interrupt_counter) < 3){
276                 printf("triggerred: %"PRIi64" and received %"PRIi64" interrupts. (+-2 is okay).\n",
277                         int_trigger_counter, interrupt_counter);
278                 printf("TEST SUCCESS\n");
279             }
280             else {
281                 printf("triggerred: %"PRIi64" and received %"PRIi64" interrupts. (+-2 is okay).\n",
282                         int_trigger_counter, interrupt_counter);
283                 printf("TEST FAILURE\n");
284             }
285             exit(0);
286         }
287         if(e1000_initialized){
288             current_tick = rdtsc();
289             if(last_int_trigger_ticks + ticks_per_msec*100 < current_tick){
290                 last_int_trigger_ticks = current_tick;
291                 IRQ_DEBUG("Creating Link change interrupt...\n");
292
293                 // Cause an (artificial) interrupt
294                 e1000_intreg_t ics = 0;
295                 ics = e1000_intreg_lsc_insert(ics, 1);
296                 e1000_ics_wr(e1000_device.device, ics);
297                 int_trigger_counter++;
298             }
299         }
300     }
301
302     return 1;
303 }