flounder: making const pointers in receiving handlers, using CONST_CAST as a temporar...
[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 struct capref all_irq_cap;
30
31 static void pci_change_event(octopus_mode_t mode, const char* device_record,
32                              void* st);
33
34 static void spawnd_up_event(octopus_mode_t mode, const char* spawnd_record,
35                             void* st)
36 {
37     assert(mode & OCT_ON_SET);
38     uint64_t iref;
39     errval_t err = oct_read(spawnd_record, "_ { iref: %d }", &iref);
40     if (err_is_fail(err)) {
41         USER_PANIC_ERR(err, "Failed to read iref from spawnd record?");
42     }
43
44     // Pass the iref as state, this tells pci_change_event that we
45     // don't need to look again for the spawnd iref
46     // XXX: Pointer
47     pci_change_event(OCT_ON_SET, st, (void*)(uintptr_t)iref);
48 }
49
50 static errval_t wait_for_spawnd(coreid_t core, void* state)
51 {
52     // Check if the core we're spawning on is already up...
53     struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
54     errval_t error_code;
55     octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD,
56             octopus_BINDING_EVENT, OCT_ON_SET, spawnd_up_event, state);
57
58     // Construct service name
59     static char* format = "spawn.%"PRIuCOREID" { iref: _ }";
60     int length = snprintf(NULL, 0, format, core);
61     char* query = malloc(length+1);
62     snprintf(query, length+1, format, core);
63
64     errval_t err = cl->call_seq.get(cl, query, t, NULL, NULL, &error_code);
65     free(query);
66
67     if (err_is_fail(err)) {
68         return err;
69     }
70
71     return error_code;
72 }
73
74 static void pci_change_event(octopus_mode_t mode, const char* device_record,
75                              void* st)
76 {
77     errval_t err;
78     char intcaps_debug_msg[100];
79     char *binary_name = NULL;
80     strcpy(intcaps_debug_msg, "none");
81     if (mode & OCT_ON_SET) {
82         KALUGA_DEBUG("pci_change_event: device_record: %s\n", device_record);
83         uint64_t vendor_id, device_id, bus, dev, fun;
84         err = oct_read(device_record, "_ { vendor: %d, device_id: %d, bus: %d, device: %d,"
85                 " function: %d }",
86                 &vendor_id, &device_id, &bus, &dev, &fun);
87         if (err_is_fail(err)) {
88             USER_PANIC_ERR(err, "Got malformed device record?");
89         }
90         
91         /* duplicate device record as we may need it for later */
92         device_record = strdup(device_record);
93         assert(device_record);
94         
95
96         // Ask the SKB which binary and where to start it...
97         static char* query = "find_pci_driver(pci_card(%"PRIu64", %"PRIu64", _, _, _), Driver),"
98                              "writeln(Driver).";
99         err = skb_execute_query(query, vendor_id, device_id);
100         if (err_no(err) == SKB_ERR_EXECUTION) {
101             KALUGA_DEBUG("No PCI driver found for: VendorId=0x%"PRIx64", "
102                          "DeviceId=0x%"PRIx64"\n",
103                     vendor_id, device_id);
104             goto out;
105         }
106         else if (err_is_fail(err)) {
107             DEBUG_SKB_ERR(err, "Failed to query SKB.\n");
108             goto out;
109         }
110
111         // XXX: Find better way to parse binary name from SKB
112         binary_name = malloc(strlen(skb_get_output()));
113         coreid_t core;
114         uint8_t multi;
115         uint8_t int_model_in;
116         struct int_startup_argument int_arg;
117         int_arg.int_range_start = 1000;
118         int_arg.int_range_end = 1004;
119         coreid_t offset;
120         err = skb_read_output("driver(%"SCNu8", %"SCNu8", %"SCNu8", %[^,], "
121                 "%"SCNu8")", &core, &multi, &offset, binary_name, &int_model_in);
122         if(err_is_fail(err)){
123             USER_PANIC_SKB_ERR(err, "Could not parse SKB output.\n");
124         }
125         int_arg.model = int_model_in;
126
127         struct driver_argument driver_arg;
128         driver_arg.int_arg = int_arg;
129         // TODO: every driver should specify the int_model in device_db
130         // until then, we treat them like legacy, so they can use the standard
131         // pci client functionality.
132         if(int_arg.model == INT_MODEL_LEGACY || int_arg.model == INT_MODEL_NONE){
133             KALUGA_DEBUG("Starting driver (%s) with legacy interrupts\n", binary_name);
134             // No controller has to instantiated, but we need to get caps for the int numbers
135             err = skb_execute_query("get_pci_legacy_int_range(addr(%"PRIu64",%"PRIu64",%"PRIu64"),Li),"
136                     "writeln(Li).", bus, dev, fun);
137             KALUGA_DEBUG("(Driver=%s,bus=%"PRIu64",dev=%"PRIu64",fun=%"PRIu64") "
138                     "int_range skb reply: %s\n",
139                     binary_name, bus, dev, fun, skb_get_output() );
140
141             // For debugging
142             strncpy(intcaps_debug_msg, skb_get_output(), sizeof(intcaps_debug_msg));
143             char * nl = strchr(intcaps_debug_msg, '\n');
144             if(nl) *nl = '\0';
145             intcaps_debug_msg[99] = '\0';
146
147             uint64_t start=0, end=0;
148             err = skb_read_output("%"SCNu64", %"SCNu64, &start, &end);
149             if(err_is_fail(err)){
150                 DEBUG_SKB_ERR(err, "Could not parse SKB output. Not starting driver.\n");
151                 goto out;
152             }
153
154             struct cnoderef argnode_ref;
155             err = cnode_create_l2(&driver_arg.arg_caps, &argnode_ref);
156             if(err_is_fail(err)){
157                 USER_PANIC_ERR(err, "Could not cnode_create_l2");
158             }
159
160             struct capref cap;
161             cap.cnode = argnode_ref;
162             cap.slot = 0;
163             //err = sys_debug_create_irq_src_cap(cap, start, end);
164             err = cap_retype(cap, all_irq_cap, start, ObjType_IRQSrc,
165                     end, 1);
166             if(err_is_fail(err)){
167                 USER_PANIC_ERR(err, "Could not create int_src cap");
168             }
169         } else if(int_arg.model == INT_MODEL_MSI){
170             KALUGA_DEBUG("Starting driver (%s) with MSI interrupts\n", binary_name);
171             // TODO instantiate controller
172         } else if(int_arg.model == INT_MODEL_MSIX){
173             KALUGA_DEBUG("Starting driver (%s) with MSI-x interrupts\n", binary_name);
174             // TODO instantiate controller
175         } else {
176             KALUGA_DEBUG("No interrupt model specified for %s. No interrupts for this driver.\n",
177                     binary_name);
178         }
179
180         struct module_info* mi = find_module(binary_name);
181         if (mi == NULL) {
182             KALUGA_DEBUG("Driver %s not loaded. Ignore.\n", binary_name);
183             goto out;
184         }
185
186         set_multi_instance(mi, multi);
187         set_core_id_offset(mi, offset);
188
189         // Wait until the core where we start the driver
190         // is ready
191         if (st == NULL && core != my_core_id) {
192             err = wait_for_spawnd(core, (CONST_CAST)device_record);
193             if (err_no(err) == OCT_ERR_NO_RECORD) {
194                 KALUGA_DEBUG("Core where driver %s runs is not up yet.\n",
195                         mi->binary);
196                 // Don't want to free device record yet...
197                 return;
198             }
199             else if (err_is_fail(err)) {
200                 DEBUG_ERR(err, "Waiting for core %d failed?\n", core);
201                 goto out;
202             }
203         }
204
205         // If we've come here the core where we spawn the driver
206         // is already up
207         printf("Kaluga: Starting \"%s\" for (bus=%"PRIu64",dev=%"PRIu64",fun=%"PRIu64")"
208                ", intcaps: %s, on core %"PRIuCOREID"\n",
209                binary_name, bus, dev, fun, intcaps_debug_msg, core);
210
211         err = mi->start_function(core, mi, (CONST_CAST)device_record, &driver_arg);
212         switch (err_no(err)) {
213         case SYS_ERR_OK:
214             KALUGA_DEBUG("Spawned PCI driver: %s\n", mi->binary);
215             set_started(mi);
216             break;
217
218         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
219             KALUGA_DEBUG("%s already running.\n", mi->binary);
220             break;
221
222         case KALUGA_ERR_DRIVER_NOT_AUTO:
223             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
224             break;
225
226         default:
227             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
228             break;
229         }
230     }
231
232 out:
233     free(binary_name);
234 }
235
236 errval_t watch_for_pci_devices(void)
237 {
238     static char* pci_device  = "r'hw\\.pci\\.device\\.[0-9]+' { "
239                                " bus: _, device: _, function: _, vendor: _,"
240                                " device_id: _, class: _, subclass: _, "
241                                " prog_if: _ }";
242     octopus_trigger_id_t tid;
243     return oct_trigger_existing_and_watch(pci_device, pci_change_event, NULL, &tid);
244 }
245
246 static void bridge_change_event(octopus_mode_t mode, const char* bridge_record,
247                                 void* st)
248 {
249     if (mode & OCT_ON_SET) {
250         // No need to ask the SKB as we always start pci for
251         // in case we find a root bridge
252         struct module_info* mi = find_module("pci");
253         if (mi == NULL) {
254             KALUGA_DEBUG("PCI driver not found or not declared as auto.");
255             return;
256         }
257
258         // XXX: always spawn on my_core_id; otherwise we need to check that
259         // the other core is already up
260         errval_t err = mi->start_function(my_core_id, mi, (CONST_CAST)bridge_record, NULL);
261         switch (err_no(err)) {
262         case SYS_ERR_OK:
263             KALUGA_DEBUG("Spawned PCI bus driver: %s\n", mi->binary);
264             set_started(mi);
265             break;
266
267         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
268             KALUGA_DEBUG("%s already running.\n", mi->binary);
269             break;
270
271         case KALUGA_ERR_DRIVER_NOT_AUTO:
272             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
273             break;
274
275         default:
276             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
277             break;
278         }
279     }
280 }
281
282 errval_t watch_for_pci_root_bridge(void)
283 {
284
285 #if !defined(__ARM_ARCH_8A__)
286     // TODO: Get all_irq_cap from somewhere and remove sys_debug call
287     errval_t err;
288     err = slot_alloc(&all_irq_cap);
289     assert(err_is_ok(err));
290     err = sys_debug_create_irq_src_cap(all_irq_cap, 0, 65536);
291     assert(err_is_ok(err));
292     
293 #endif
294     static char* root_bridge = "r'hw\\.pci\\.rootbridge\\.[0-9]+' { "
295                                " bus: _, device: _, function: _, maxbus: _,"
296                                " acpi_node: _ }";
297     octopus_trigger_id_t tid;
298     return oct_trigger_existing_and_watch(root_bridge, bridge_change_event,
299             NULL, &tid);
300 }