155a73acd578cbd78c4146e7392f5e6c62021bf7
[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         if(int_arg.model == INT_MODEL_LEGACY){
119             KALUGA_DEBUG("Starting driver with legacy interrupts\n");
120             // No controller has to instantiated, but we need to get caps for the int numbers
121             err = skb_execute_query("get_pci_legacy_int_range(addr(%"PRIu64",%"PRIu64",%"PRIu64"),Li),"
122                     "writeln(Li).", bus, dev, fun);
123             KALUGA_DEBUG("int_range skb reply: %s\n", skb_get_output() );
124             if(err_is_fail(err)){
125                 USER_PANIC_ERR(err, "Could not parse SKB output: %s\n", skb_get_output());
126             }
127             struct list_parser_status pa_sta;
128             skb_read_list_init(&pa_sta);
129             int int_num;
130             while(skb_read_list(&pa_sta, "int(%d)", &int_num)){
131                 //Works
132                 KALUGA_DEBUG("Interrupt for driver: %d\n", int_num);
133             }
134         } else if(int_arg.model == INT_MODEL_MSI){
135             KALUGA_DEBUG("Starting driver with MSI interrupts");
136             // TODO instantiate controller
137         } else if(int_arg.model == INT_MODEL_MSIX){
138             KALUGA_DEBUG("Starting driver with MSI-x interrupts");
139             // TODO instantiate controller
140         } else {
141             KALUGA_DEBUG("No interrupt model specified for %s. No interrupts for this driver.\n",
142                     binary_name);
143         }
144
145         struct module_info* mi = find_module(binary_name);
146         free(binary_name);
147         if (mi == NULL) {
148             KALUGA_DEBUG("Driver %s not loaded. Ignore.\n", binary_name);
149             goto out;
150         }
151
152         set_multi_instance(mi, multi);
153         set_core_id_offset(mi, offset);
154
155         // Wait until the core where we start the driver
156         // is ready
157         if (st == NULL && core != my_core_id) {
158             err = wait_for_spawnd(core, device_record);
159             if (err_no(err) == OCT_ERR_NO_RECORD) {
160                 KALUGA_DEBUG("Core where driver %s runs is not up yet.\n",
161                         mi->binary);
162                 // Don't want to free device record yet...
163                 return;
164             }
165             else if (err_is_fail(err)) {
166                 DEBUG_ERR(err, "Waiting for core %d failed?\n", core);
167                 goto out;
168             }
169         }
170
171         // If we've come here the core where we spawn the driver
172         // is already up
173         err = mi->start_function(core, mi, device_record, &int_arg);
174         switch (err_no(err)) {
175         case SYS_ERR_OK:
176             KALUGA_DEBUG("Spawned PCI driver: %s\n", mi->binary);
177             set_started(mi);
178             break;
179
180         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
181             KALUGA_DEBUG("%s already running.\n", mi->binary);
182             break;
183
184         case KALUGA_ERR_DRIVER_NOT_AUTO:
185             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
186             break;
187
188         default:
189             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
190             break;
191         }
192     }
193
194 out:
195     free(device_record);
196 }
197
198 errval_t watch_for_pci_devices(void)
199 {
200     static char* pci_device  = "r'hw\\.pci\\.device\\.[0-9]+' { "
201                                " bus: _, device: _, function: _, vendor: _,"
202                                " device_id: _, class: _, subclass: _, "
203                                " prog_if: _ }";
204     octopus_trigger_id_t tid;
205     return oct_trigger_existing_and_watch(pci_device, pci_change_event, NULL, &tid);
206 }
207
208 static void bridge_change_event(octopus_mode_t mode, char* bridge_record, void* st)
209 {
210     if (mode & OCT_ON_SET) {
211         // No need to ask the SKB as we always start pci for
212         // in case we find a root bridge
213         struct module_info* mi = find_module("pci");
214         if (mi == NULL) {
215             KALUGA_DEBUG("PCI driver not found or not declared as auto.");
216             return;
217         }
218
219         // XXX: always spawn on my_core_id; otherwise we need to check that
220         // the other core is already up
221         errval_t err = mi->start_function(my_core_id, mi, bridge_record, NULL);
222         switch (err_no(err)) {
223         case SYS_ERR_OK:
224             KALUGA_DEBUG("Spawned PCI bus driver: %s\n", mi->binary);
225             set_started(mi);
226             break;
227
228         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
229             KALUGA_DEBUG("%s already running.\n", mi->binary);
230             break;
231
232         case KALUGA_ERR_DRIVER_NOT_AUTO:
233             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
234             break;
235
236         default:
237             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
238             break;
239         }
240     }
241 }
242
243 errval_t watch_for_pci_root_bridge(void)
244 {
245     static char* root_bridge = "r'hw\\.pci\\.rootbridge\\.[0-9]+' { "
246                                " bus: _, device: _, function: _, maxbus: _,"
247                                " acpi_node: _ }";
248     octopus_trigger_id_t tid;
249     return oct_trigger_existing_and_watch(root_bridge, bridge_change_event,
250             NULL, &tid);
251 }