388ef1dd15589ab177e090d0630d843621a51cdd
[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 <skb/skb.h>
24
25 #include "kaluga.h"
26
27 static void pci_change_event(octopus_mode_t mode, char* device_record, void* st);
28
29 static void spawnd_up_event(octopus_mode_t mode, char* spawnd_record, void* st)
30 {
31     assert(mode & DIST_ON_SET);
32     uint64_t iref;
33     errval_t err = oct_read(spawnd_record, "_ { iref: %d }", &iref);
34     if (err_is_fail(err)) {
35         USER_PANIC_ERR(err, "Failed to read iref from spawnd record?");
36     }
37
38     // Pass the iref as state, this tells pci_change_event that we
39     // don't need to look again for the spawnd iref
40     pci_change_event(DIST_ON_SET, st, (void*)iref);
41     free(spawnd_record);
42 }
43
44 static errval_t wait_for_spawnd(coreid_t core, void* state)
45 {
46     // Check if the core we're spawning on is already up...
47     struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
48     char* iref_record = NULL;
49     octopus_trigger_id_t tid;
50     errval_t error_code;
51     octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD,
52             octopus_BINDING_EVENT, DIST_ON_SET, spawnd_up_event, state);
53
54     // Construct service name
55     static char* format = "spawn.%hhu { iref: _ }";
56     int length = snprintf(NULL, 0, format, core);
57     char* query = malloc(length+1);
58     snprintf(query, length+1, format, core);
59
60     errval_t err = cl->call_seq.get(cl, query, t, &iref_record, &tid, &error_code);
61     free(query);
62     free(iref_record);
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 & DIST_ON_SET) {
75         uint64_t vendor_id, device_id;
76         err = oct_read(device_record, "_ { vendor: %d, device_id: %d }",
77                 &vendor_id, &device_id);
78         if (err_is_fail(err)) {
79             USER_PANIC_ERR(err, "Got malformed device record?");
80         }
81
82         // Ask the SKB which binary and where to start it...
83         static char* query = "find_pci_driver(pci_card(%lu, %lu, _, _, _), Driver),"
84                              "writeln(Driver).";
85         err = skb_execute_query(query, vendor_id, device_id);
86         if (err_no(err) == SKB_ERR_EXECUTION) {
87             KALUGA_DEBUG("No PCI driver found for: VendorId=0x%lx, "
88                          "DeviceId=0x%lx\n",
89                     vendor_id, device_id);
90             goto out;
91         }
92         else if (err_is_fail(err)) {
93             DEBUG_ERR(err, "Failed to query SKB.\n");
94             goto out;
95         }
96
97         // XXX: Find better way to parse binary name from SKB
98         char* binary_name = malloc(strlen(skb_get_output()));
99         coreid_t core;
100         skb_read_output("driver(%hhu, %s)", &core, binary_name);
101         *strrchr(binary_name, ')') = '\0';
102
103         struct module_info* mi = find_module(binary_name);
104         free(binary_name);
105         if (mi == NULL) {
106             KALUGA_DEBUG("Driver %s not loaded. Ignore.", binary_name);
107             goto out;
108         }
109
110         // Wait until the core where we start the driver
111         // is ready
112         if (st == NULL && core != my_core_id) {
113             err = wait_for_spawnd(core, device_record);
114             if (err_no(err) == OCT_ERR_NO_RECORD) {
115                 KALUGA_DEBUG("Core where driver %s runs is not up yet.\n",
116                         mi->binary);
117                 // Don't want to free device record yet...
118                 return;
119             }
120             else if (err_is_fail(err)) {
121                 DEBUG_ERR(err, "Waiting for core %d failed?\n", core);
122                 goto out;
123             }
124         }
125
126         // If we've come here the core where we spawn the driver
127         // is already up
128         err = mi->start_function(core, mi, device_record);
129         switch (err_no(err)) {
130         case SYS_ERR_OK:
131             KALUGA_DEBUG("Spawned PCI driver: %s\n", mi->binary);
132             break;
133
134         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
135             KALUGA_DEBUG("%s already running.\n", mi->binary);
136             break;
137
138         case KALUGA_ERR_DRIVER_NOT_AUTO:
139             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
140             break;
141
142         default:
143             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
144             break;
145         }
146     }
147
148 out:
149     free(device_record);
150 }
151
152 errval_t watch_for_pci_devices(void)
153 {
154     static char* pci_device  = "r'hw\\.pci\\.device\\.[0-9]+' { "
155                                " bus: _, device: _, function: _, vendor: _,"
156                                " device_id: _, class: _, subclass: _, "
157                                " prog_if: _ }";
158     octopus_trigger_id_t tid;
159     return trigger_existing_and_watch(pci_device, pci_change_event, NULL, &tid);
160 }
161
162 static void bridge_change_event(octopus_mode_t mode, char* bridge_record, void* st)
163 {
164     if (mode & DIST_ON_SET) {
165         // No need to ask the SKB as we always start pci for
166         // in case we find a root bridge
167         struct module_info* mi = find_module("pci");
168         if (mi == NULL) {
169             KALUGA_DEBUG("PCI driver not found or not declared as auto.");
170             goto out;
171         }
172
173         // XXX: always spawn on my_core_id; otherwise we need to check that
174         // the other core is already up
175         errval_t err = mi->start_function(my_core_id, mi, bridge_record);
176         switch (err_no(err)) {
177         case SYS_ERR_OK:
178             KALUGA_DEBUG("Spawned PCI bus driver: %s\n", mi->binary);
179             break;
180
181         case KALUGA_ERR_DRIVER_ALREADY_STARTED:
182             KALUGA_DEBUG("%s already running.\n", mi->binary);
183             break;
184
185         case KALUGA_ERR_DRIVER_NOT_AUTO:
186             KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
187             break;
188
189         default:
190             DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
191             break;
192         }
193     }
194
195 out:
196     free(bridge_record);
197 }
198
199 errval_t watch_for_pci_root_bridge(void)
200 {
201     static char* root_bridge = "r'hw\\.pci\\.rootbridge\\.[0-9]+' { "
202                                " bus: _, device: _, function: _, maxbus: _,"
203                                " acpi_node: _ }";
204     octopus_trigger_id_t tid;
205     return trigger_existing_and_watch(root_bridge, bridge_change_event,
206             NULL, &tid);
207 }