IRQ: Kaluga start driver with IRQ caps.
[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     IRQ_DEBUG("Printing Caps:\n");
163     debug_my_cspace();
164     IRQ_DEBUG("Printing Caps Done\n");
165
166     /** Parse command line arguments. */
167     IRQ_DEBUG("irq test started.\n");
168
169     IRQ_DEBUG("argc = %d\n", argc);
170
171     err = pci_parse_int_arg(argc,argv);
172     if(err_is_fail(err)){
173         IRQ_DEBUG("Could not parse int argument");
174     }
175
176     if (argc > 1) {
177         uint32_t parsed = sscanf(argv[argc - 1], "%x:%x:%x:%x:%x", &vendor,
178                                  &deviceid, &bus, &device, &function);
179         if (parsed != 5) {
180             IRQ_DEBUG("Driver seems not to be started by Kaluga.\n");
181             vendor = PCI_DONT_CARE;
182             deviceid = PCI_DONT_CARE;
183             bus = PCI_DONT_CARE;
184             device = PCI_DONT_CARE;
185             function = PCI_DONT_CARE;
186         } else {
187             IRQ_DEBUG("Parsed Kaluga argument: PCI Device (%u, %u, %u) Vendor: 0x%04x, Device 0x%04x\n",
188                         bus, device, function, vendor, deviceid);
189             // remove the last argument
190             argc--;
191         }
192     }
193
194     for (int i = 1; i < argc; i++) {
195         IRQ_DEBUG("arg %d = %s\n", i, argv[i]);
196         if (strcmp(argv[i], "auto") == 0) {
197             continue;
198         }
199         if (strncmp(argv[i], "affinitymin=", strlen("affinitymin=")) == 0) {
200             minbase = atol(argv[i] + strlen("affinitymin="));
201             IRQ_DEBUG("minbase = %lu\n", minbase);
202         } else if (strncmp(argv[i], "affinitymax=", strlen("affinitymax="))
203                  == 0) {
204             maxbase = atol(argv[i] + strlen("affinitymax="));
205             IRQ_DEBUG("maxbase = %lu\n", maxbase);
206         } else if(strncmp(argv[i],"bus=",strlen("bus=")-1)==0) {
207             bus = atol(argv[i] + strlen("bus="));
208             IRQ_DEBUG("bus = %ul\n", bus);
209         } else if (strncmp(argv[i], "device=", strlen("device=")) == 0) {
210             device = atol(argv[i] + strlen("device="));
211             IRQ_DEBUG("device = %ul\n", device);
212         } else if (strncmp(argv[i], "function=", strlen("function=")) == 0) {
213             function = atol(argv[i] + strlen("function="));
214             IRQ_DEBUG("function = %u\n", function);
215         } else if (strncmp(argv[i], "deviceid=", strlen("deviceid=")) == 0) {
216             deviceid = strtoul(argv[i] + strlen("deviceid="), NULL, 0);
217             IRQ_DEBUG("deviceid = %u\n", deviceid);
218         } else if (strcmp(argv[i], "-h") == 0 ||
219                  strcmp(argv[i], "--help") == 0) {
220             //exit_help(argv[0]);
221         } else {
222             IRQ_DEBUG("Ignoring %s.\n", argv[i]);
223         }
224     } // end for :
225
226     if ((minbase != -1) && (maxbase != -1)) {
227         IRQ_DEBUG("set memory affinity [%lx, %lx]\n", minbase, maxbase);
228         ram_set_affinity(minbase, maxbase);
229     }
230
231
232     IRQ_DEBUG("Starting standalone driver.\n");
233
234     /* Check if forced device id and vendor is known to be supported. */
235     mac_type = e1000_get_mac_type(vendor, deviceid);
236     if(mac_type == e1000_undefined){
237         IRQ_DEBUG("WARNING: Passed deviceid unknown.\n");
238     }
239
240
241     /* Setup known device info */
242     e1000_device.device = &e1000;
243     e1000_device.mac_type = mac_type;
244     e1000_device.device_id = deviceid;
245     if (e1000_device.mac_type == e1000_82575
246         || e1000_device.mac_type == e1000_82576
247         || e1000_device.mac_type == e1000_I210
248         || e1000_device.mac_type == e1000_I350) {
249         // These cards do not have a bsex reg entry
250         // therefore, we can't use 16384 buffer size.
251         // If we use smaller buffers than 2048 bytes the
252         // eop bit on received packets might not be set in case the package
253         // is biger than the receive buffer size and we don't handle these
254         // cases currently.
255         e1000_device.rx_bsize = bsize_2048;
256     } else {
257         e1000_device.rx_bsize = receive_buffer_size;
258     }
259     e1000_device.media_type = e1000_media_type_undefined;
260
261
262     IRQ_DEBUG("Connecting to PCI.\n");
263     err = pci_client_connect();
264     assert(err_is_ok(err));
265
266     IRQ_DEBUG("########### Driver with interrupts ###########\n");
267     err = pci_register_driver_movable_irq(e1000_init_fn, class, subclass, program_interface,
268                                           vendor, deviceid, bus, device, function,
269                                           e1000_interrupt_handler_fn, NULL,
270                                           e1000_reregister_handler,
271                                           NULL);
272
273
274     if (err_is_fail(err)) {
275         E1000_PRINT_ERROR("Error: %u, pci_register_driver failed\n", (unsigned int)err);
276         exit(err);
277     }
278
279     IRQ_DEBUG("Registered driver.\n");
280
281     IRQ_DEBUG("#### starting dispatch loop.\n");
282     uint64_t ticks_per_msec, current_tick;
283     uint64_t last_int_trigger_ticks = 0;
284     sys_debug_get_tsc_per_ms(&ticks_per_msec);
285     IRQ_DEBUG("Ticks per msec: %"PRIu64".\n", ticks_per_msec);
286     assert(err_is_ok(err));
287
288     while(true){
289         err = event_dispatch_non_block(get_default_waitset());
290         if(!err_is_ok(err) && err != LIB_ERR_NO_EVENT) {
291             IRQ_DEBUG("Error in event_dispatch_non_block, returned %s\n",
292                     err_getstring(err));
293         }
294
295         if(int_trigger_counter >= 20){
296             if(abs(int_trigger_counter - interrupt_counter) < 3){
297                 printf("triggerred: %"PRIi64" and received %"PRIi64" interrupts. (+-2 is okay).\n",
298                         int_trigger_counter, interrupt_counter);
299                 printf("TEST SUCCESS\n");
300             }
301             else {
302                 printf("triggerred: %"PRIi64" and received %"PRIi64" interrupts. (+-2 is okay).\n",
303                         int_trigger_counter, interrupt_counter);
304                 printf("TEST FAILURE\n");
305             }
306             exit(0);
307         }
308         if(e1000_initialized){
309             current_tick = rdtsc();
310             if(last_int_trigger_ticks + ticks_per_msec*100 < current_tick){
311                 last_int_trigger_ticks = current_tick;
312                 IRQ_DEBUG("Creating Link change interrupt...\n");
313
314                 // Cause an (artificial) interrupt
315                 e1000_intreg_t ics = 0;
316                 ics = e1000_intreg_lsc_insert(ics, 1);
317                 e1000_ics_wr(e1000_device.device, ics);
318                 int_trigger_counter++;
319             }
320         }
321     }
322
323     return 1;
324 }