IRQ: Kaluga start driver with IRQ caps.
[barrelfish] / usr / kaluga / start_pci.c
1 /**
2  * \file
3  * \brief Code responsible for booting application cores
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <assert.h>
19
20 #include <barrelfish/barrelfish.h>
21
22 #include <octopus/octopus.h>
23 #include <if/octopus_thc.h>
24 #include <skb/skb.h>
25 #include <thc/thc.h>
26
27 #include "kaluga.h"
28
29 static void pci_change_event(octopus_mode_t mode, char* device_record, void* st);
30
31 static void spawnd_up_event(octopus_mode_t mode, char* spawnd_record, void* st)
32 {
33     assert(mode & OCT_ON_SET);
34     uint64_t iref;
35     errval_t err = oct_read(spawnd_record, "_ { iref: %d }", &iref);
36     if (err_is_fail(err)) {
37         USER_PANIC_ERR(err, "Failed to read iref from spawnd record?");
38     }
39
40     // Pass the iref as state, this tells pci_change_event that we
41     // don't need to look again for the spawnd iref
42     // XXX: Pointer
43     pci_change_event(OCT_ON_SET, st, (void*)(uintptr_t)iref);
44     free(spawnd_record);
45 }
46
47 static errval_t wait_for_spawnd(coreid_t core, void* state)
48 {
49     // Check if the core we're spawning on is already up...
50     struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
51     errval_t error_code;
52     octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD,
53             octopus_BINDING_EVENT, OCT_ON_SET, spawnd_up_event, state);
54
55     // Construct service name
56     static char* format = "spawn.%"PRIuCOREID" { iref: _ }";
57     int length = snprintf(NULL, 0, format, core);
58     char* query = malloc(length+1);
59     snprintf(query, length+1, format, core);
60
61     errval_t err = cl->call_seq.get(cl, query, t, NULL, NULL, &error_code);
62     free(query);
63
64     if (err_is_fail(err)) {
65         return err;
66     }
67
68     return error_code;
69 }
70
71 static void pci_change_event(octopus_mode_t mode, char* device_record, void* st)
72 {
73     errval_t err;
74     if (mode & OCT_ON_SET) {
75         uint64_t vendor_id, device_id, bus, dev, fun;
76         err = oct_read(device_record, "_ { vendor: %d, device_id: %d, bus: %d, device: %d,"
77                 " function: %d }",
78                 &vendor_id, &device_id, &bus, &dev, &fun);
79         if (err_is_fail(err)) {
80             USER_PANIC_ERR(err, "Got malformed device record?");
81         }
82         
83         /* duplicate device record as we may need it for later */
84         device_record = strdup(device_record);
85         assert(device_record);
86         
87
88         // Ask the SKB which binary and where to start it...
89         static char* query = "find_pci_driver(pci_card(%"PRIu64", %"PRIu64", _, _, _), Driver),"
90                              "writeln(Driver).";
91         err = skb_execute_query(query, vendor_id, device_id);
92         if (err_no(err) == SKB_ERR_EXECUTION) {
93             KALUGA_DEBUG("No PCI driver found for: VendorId=0x%"PRIx64", "
94                          "DeviceId=0x%"PRIx64"\n",
95                     vendor_id, device_id);
96             goto out;
97         }
98         else if (err_is_fail(err)) {
99             DEBUG_ERR(err, "Failed to query SKB.\n");
100             goto out;
101         }
102
103         // XXX: Find better way to parse binary name from SKB
104         char* binary_name = malloc(strlen(skb_get_output()));
105         coreid_t core;
106         uint8_t multi;
107         uint8_t int_model_in;
108         struct int_startup_argument int_arg;
109         int_arg.int_range_start = 1000;
110         int_arg.int_range_end = 1004;
111         coreid_t offset;
112         err = skb_read_output("driver(%"SCNu8", %"SCNu8", %"SCNu8", %[^,], %"SCNu8")", &core, &multi, &offset,
113                 binary_name, &int_model_in);
114         if(err_is_fail(err)){
115             USER_PANIC_ERR(err, "Could not parse SKB output: %s\n", skb_get_output());
116         }
117         int_arg.model = int_model_in;
118
119         struct driver_argument driver_arg;
120         driver_arg.int_arg = int_arg;
121         if(int_arg.model == INT_MODEL_LEGACY){
122             KALUGA_DEBUG("Starting driver with legacy interrupts\n");
123             // No controller has to instantiated, but we need to get caps for the int numbers
124             err = skb_execute_query("get_pci_legacy_int_range(addr(%"PRIu64",%"PRIu64",%"PRIu64"),Li),"
125                     "writeln(Li).", bus, dev, fun);
126             KALUGA_DEBUG("int_range skb reply: %s\n", skb_get_output() );
127             if(err_is_fail(err)){
128                 USER_PANIC_ERR(err, "Could not parse SKB output: %s\n", skb_get_output());
129             }
130             struct list_parser_status pa_sta;
131             skb_read_list_init(&pa_sta);
132             int int_num;
133             struct cnoderef argnode_ref;
134             err = cnode_create(&driver_arg.arg_caps, &argnode_ref,
135                                DEFAULT_CNODE_SLOTS, NULL);
136
137             if(err_is_fail(err)){
138                 USER_PANIC_ERR(err, "Could not create int_src cap");
139             }
140
141             for(int i=0; skb_read_list(&pa_sta, "int(%d)", &int_num); i++){
142                 //Works
143                 KALUGA_DEBUG("Interrupt for driver: %d\n", int_num);
144                 struct capref cap;
145                 cap.cnode = argnode_ref;
146                 cap.slot = i;
147                 err = sys_debug_create_irq_src_cap(cap, int_num);
148
149                 if(err_is_fail(err)){
150                     USER_PANIC_ERR(err, "Could not create int_src cap");
151                 }
152             }
153         } else if(int_arg.model == INT_MODEL_MSI){
154             KALUGA_DEBUG("Starting driver with MSI interrupts");
155             // TODO instantiate controller
156         } else if(int_arg.model == INT_MODEL_MSIX){
157             KALUGA_DEBUG("Starting driver with MSI-x interrupts");
158             // TODO instantiate controller
159         } else {
160             KALUGA_DEBUG("No interrupt model specified for %s. No interrupts for this driver.\n",
161                     binary_name);
162         }
163
164         struct module_info* mi = find_module(binary_name);
165         free(binary_name);
166         if (mi == NULL) {
167             KALUGA_DEBUG("Driver %s not loaded. Ignore.\n", binary_name);
168             goto out;
169         }
170
171         set_multi_instance(mi, multi);
172         set_core_id_offset(mi, offset);
173
174         // Wait until the core where we start the driver
175         // is ready
176         if (st == NULL && core != my_core_id) {
177             err = wait_for_spawnd(core, device_record);
178             if (err_no(err) == OCT_ERR_NO_RECORD) {
179                 KALUGA_DEBUG("Core where driver %s runs is not up yet.\n",
180                         mi->binary);
181                 // Don't want to free device record yet...
182                 return;
183             }
184             else if (err_is_fail(err)) {
185                 DEBUG_ERR(err, "Waiting for core %d failed?\n", core);
186                 goto out;
187             }
188         }
189
190         // If we've come here the core where we spawn the driver
191         // is already up
192         err = mi->start_function(core, mi, device_record, &driver_arg);
193         switch (err_no(err)) {
194         case SYS_ERR_OK:
195             KALUGA_DEBUG("Spawned PCI driver: %s\n", mi->binary);
196             set_started(mi);
197             break;
198
199         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
200             KALUGA_DEBUG("%s already running.\n", mi->binary);
201             break;
202
203         case KALUGA_ERR_DRIVER_NOT_AUTO:
204             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
205             break;
206
207         default:
208             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
209             break;
210         }
211     }
212
213 out:
214     free(device_record);
215 }
216
217 errval_t watch_for_pci_devices(void)
218 {
219     static char* pci_device  = "r'hw\\.pci\\.device\\.[0-9]+' { "
220                                " bus: _, device: _, function: _, vendor: _,"
221                                " device_id: _, class: _, subclass: _, "
222                                " prog_if: _ }";
223     octopus_trigger_id_t tid;
224     return oct_trigger_existing_and_watch(pci_device, pci_change_event, NULL, &tid);
225 }
226
227 static void bridge_change_event(octopus_mode_t mode, char* bridge_record, void* st)
228 {
229     if (mode & OCT_ON_SET) {
230         // No need to ask the SKB as we always start pci for
231         // in case we find a root bridge
232         struct module_info* mi = find_module("pci");
233         if (mi == NULL) {
234             KALUGA_DEBUG("PCI driver not found or not declared as auto.");
235             return;
236         }
237
238         // XXX: always spawn on my_core_id; otherwise we need to check that
239         // the other core is already up
240         errval_t err = mi->start_function(my_core_id, mi, bridge_record, NULL);
241         switch (err_no(err)) {
242         case SYS_ERR_OK:
243             KALUGA_DEBUG("Spawned PCI bus driver: %s\n", mi->binary);
244             set_started(mi);
245             break;
246
247         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
248             KALUGA_DEBUG("%s already running.\n", mi->binary);
249             break;
250
251         case KALUGA_ERR_DRIVER_NOT_AUTO:
252             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
253             break;
254
255         default:
256             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
257             break;
258         }
259     }
260 }
261
262 errval_t watch_for_pci_root_bridge(void)
263 {
264     static char* root_bridge = "r'hw\\.pci\\.rootbridge\\.[0-9]+' { "
265                                " bus: _, device: _, function: _, maxbus: _,"
266                                " acpi_node: _ }";
267     octopus_trigger_id_t tid;
268     return oct_trigger_existing_and_watch(root_bridge, bridge_change_event,
269             NULL, &tid);
270 }