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 <if/octopus_defs.h>
23#include <if/octopus_thc.h>
24
25//Manual channel setup includes
26#include <if/pci_defs.h>
27#include <flounder/flounder_txqueue.h>
28//END
29#include <pci/pci.h>
30
31#include <octopus/octopus.h>
32#include <octopus/trigger.h>
33
34#include <skb/skb.h>
35#include <thc/thc.h>
36
37#include "kaluga.h"
38#include <acpi_client/acpi_client.h>
39
40
41static void pci_change_event(octopus_mode_t mode, const char* device_record,
42                             void* st);
43
44static void spawnd_up_event(octopus_mode_t mode, const char* spawnd_record,
45                            void* st)
46{
47    assert(mode & OCT_ON_SET);
48    uint64_t iref;
49    errval_t err = oct_read(spawnd_record, "_ { iref: %d }", &iref);
50    if (err_is_fail(err)) {
51        USER_PANIC_ERR(err, "Failed to read iref from spawnd record?");
52    }
53
54    // Pass the iref as state, this tells pci_change_event that we
55    // don't need to look again for the spawnd iref
56    // XXX: Pointer
57    pci_change_event(OCT_ON_SET, st, (void*)(uintptr_t)iref);
58}
59
60static errval_t wait_for_spawnd(coreid_t core, void* state)
61{
62    // Check if the core we're spawning on is already up...
63    struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
64    errval_t error_code;
65    octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD,
66            octopus_BINDING_EVENT, OCT_ON_SET, spawnd_up_event, state);
67
68    // Construct service name
69    static char* format = "spawn.%"PRIuCOREID" { iref: _ }";
70    int length = snprintf(NULL, 0, format, core);
71    char* query = malloc(length+1);
72    snprintf(query, length+1, format, core);
73
74    errval_t err = cl->call_seq.get(cl, query, t, NULL, NULL, &error_code);
75    free(query);
76
77    if (err_is_fail(err)) {
78        return err;
79    }
80
81    return error_code;
82};
83
84
85
86static void init_pci_device_handler(struct pci_binding *b,
87                                    uint32_t class_code, uint32_t sub_class,
88                                    uint32_t prog_if, uint32_t vendor_id,
89                                    uint32_t device_id,
90                                    uint32_t bus, uint32_t dev, uint32_t fun)
91{
92
93    KALUGA_DEBUG("init_pci_device_handler!!! %"PRIu32", %"PRIu32","
94            "%"PRIu32"\n", bus, dev, fun);
95
96}
97struct pci_rx_vtbl pci_rx_vtbl = {
98    .init_pci_device_call = init_pci_device_handler
99};
100
101/**
102 * \brief callback when the PCI client connects
103 *
104 * \param st    state pointer
105 * \param err   status of the connect
106 * \param _b    created PCI binding
107 */
108static void pci_accept_cb(void *st,
109                                  errval_t err,
110                                  struct pci_binding *_b)
111{
112    KALUGA_DEBUG("connection accepted.");
113    _b->rx_vtbl = pci_rx_vtbl;
114}
115
116const int PCI_CHANNEL_SIZE = 2048;
117
118static errval_t frame_to_pci_frameinfo(struct capref frame, struct pci_frameinfo *fi){
119    struct frame_identity fid;
120    errval_t err;
121    err = invoke_frame_identify(frame, &fid);
122    if(err_is_fail(err)){
123        DEBUG_ERR(err, "invoke_frame_identify");
124        return err;
125    }
126    KALUGA_DEBUG("pci ep frame base=0x%lx, size=0x%lx\n", fid.base, fid.bytes);
127
128    void *msg_buf;
129    err = vspace_map_one_frame(&msg_buf, fid.bytes, frame,
130                               NULL, NULL);
131    if (err_is_fail(err)) {
132        DEBUG_ERR(err, "vspace_map_one_frame");
133        return err;
134    }
135
136    *fi = (struct pci_frameinfo) {
137        .sendbase = (lpaddr_t)msg_buf + PCI_CHANNEL_SIZE,
138        .inbuf = msg_buf,
139        .inbufsize = PCI_CHANNEL_SIZE,
140        .outbuf = ((uint8_t *) msg_buf) + PCI_CHANNEL_SIZE,
141        .outbufsize = PCI_CHANNEL_SIZE
142    };
143
144    return SYS_ERR_OK;
145}
146
147static errval_t start_pci_ump_accept(struct capref out_frame){
148    assert(!capref_is_null(out_frame));
149
150    size_t msg_frame_size;
151    errval_t err;
152    //err = frame_alloc(out_frame, 2 * PCI_CHANNEL_SIZE, &msg_frame_size);
153    err = frame_create(out_frame, 2 * PCI_CHANNEL_SIZE, &msg_frame_size);
154    if (err_is_fail(err)) {
155        DEBUG_ERR(err, "frame_create");
156        return err;
157    }
158
159    struct pci_frameinfo fi;
160    err = frame_to_pci_frameinfo(out_frame, &fi);
161    if (err_is_fail(err)) {
162        DEBUG_ERR(err, "frame_to_frameinfo");
163        return err;
164    }
165
166    KALUGA_DEBUG("creating channel on %p\n", fi.inbuf);
167
168    err = pci_accept(&fi, NULL, pci_accept_cb,
169                      get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
170
171    if (err_is_fail(err)) {
172        DEBUG_ERR(err, "pci_accept");
173        return err;
174    }
175    return SYS_ERR_OK;
176}
177
178/**
179 * For device at addr, finds and stores the interrupt arguments and caps
180 * into driver_arg.
181 */
182static errval_t add_pci_ep(struct pci_addr addr, struct driver_argument
183        *driver_arg)
184{
185    errval_t err;
186
187    struct capref cap = {
188        .cnode = driver_arg->argnode_ref,
189        .slot = PCIARG_SLOT_PCI_EP
190    };
191
192    err = start_pci_ump_accept(cap);
193    if(err_is_fail(err)){
194        DEBUG_ERR(err, "start_pci_ump_accept");
195        return err;
196    }
197
198    return err;
199};
200
201/**
202 * For device at addr, finds and stores the interrupt arguments and caps
203 * into driver_arg.
204 */
205static errval_t add_mem_args(struct pci_addr addr, struct driver_argument
206        *driver_arg, char *debug)
207{
208    errval_t err;
209
210    struct device_mem *bars;
211    size_t bars_len;
212
213    //NOT VERY BEAUTIFUL
214    static bool pci_init=false;
215    if(!pci_init){
216        pci_client_connect();
217        pci_init = true;
218    }
219    //
220
221    err = pci_get_bar_caps_for_device(addr, &bars, &bars_len);
222    if(err_is_fail(err)){
223        DEBUG_ERR(err, "pci_get_caps_for_device");
224        return err;
225    }
226
227    // Copy the caps into the argument cnode
228    for(int i=0; i<bars_len; i++){
229        struct capref cap = {
230            .cnode = driver_arg->argnode_ref,
231            .slot = PCIARG_SLOT_BAR0 + i
232        };
233
234        if(bars[i].type == 0){
235            cap_copy(cap, bars[i].frame_cap);
236        } else {
237            return KALUGA_ERR_CAP_ACQUIRE;
238        }
239
240    }
241
242    KALUGA_DEBUG("Received %zu bars\n", bars_len);
243    return SYS_ERR_OK;
244};
245
246/**
247 * For device at addr, finds and stores the interrupt arguments and caps
248 * into driver_arg.
249 */
250static errval_t add_int_args(struct pci_addr addr, struct driver_argument *driver_arg, char *debug){
251    errval_t err = SYS_ERR_OK;
252    char debug_msg[100];
253    strcpy(debug_msg, "none");
254    // TODO: every driver should specify the int_model in device_db
255    // until then, we treat them like legacy, so they can use the standard
256    // pci client functionality.
257    if(driver_arg->int_arg.model == INT_MODEL_LEGACY ||
258       driver_arg->int_arg.model == INT_MODEL_NONE) {
259        KALUGA_DEBUG("Starting driver with legacy interrupts\n");
260        // No controller has to instantiated, but we need to get caps for the int numbers
261        //err = skb_execute_query("get_pci_legacy_int_range(addr(%"PRIu8",%"PRIu8",%"PRIu8"),Li),"
262        //        "writeln(Li).", addr.bus, addr.device, addr.function);
263        err = skb_execute_query(
264                "add_pci_controller(Lbl, addr(%"PRIu8",%"PRIu8",%"PRIu8")),"
265                "write('\n'), print_int_controller(Lbl).",
266                addr.bus, addr.device, addr.function);
267        if(err_is_fail(err)) DEBUG_SKB_ERR(err, "add/print pci controller");
268
269    } else if(driver_arg->int_arg.model == INT_MODEL_MSI){
270        printf("Kaluga: Starting driver with MSI interrupts\n");
271        printf("Kaluga: MSI interrupts are not supported.\n");
272        // TODO instantiate controller
273    } else if(driver_arg->int_arg.model == INT_MODEL_MSIX){
274        KALUGA_DEBUG("Starting driver with MSI-x interrupts\n");
275
276        // TODO need to determine number of MSIx interrupts
277
278        // Add the pci_msix and msix controller
279        err = skb_execute_query(
280                "add_pci_msix_controller(PciMsixLbl, MsixLbl, addr(%"PRIu8",%"PRIu8",%"PRIu8"))"
281                ",write('\n'),"
282                "print_int_controller(PciMsixLbl),"
283                "write(MsixLbl).",
284                addr.bus, addr.device, addr.function);
285        if(err_is_fail(err)) DEBUG_SKB_ERR(err, "add/print msix controller");
286        char * lines[8];
287        lines[0] = skb_get_output();
288        for(int i=0; i<7; i++){
289            if(lines[i] == NULL) break;
290            lines[i+1] = strstr(lines[i], "\n");
291            if(lines[i+1] != NULL) lines[i+1]++;
292        }
293        strncpy(driver_arg->int_arg.msix_ctrl_name, lines[2],
294                sizeof(driver_arg->int_arg.msix_ctrl_name));
295        KALUGA_DEBUG("Set msix_ctrl_name for (%d,%d,%d) to %s",
296                add.bus, addr.dev, addr.function, driver_arg->int_arg.msix_ctrl_name);
297
298    } else {
299        KALUGA_DEBUG("No interrupt model specified. No interrupts"
300                " for this driver.\n");
301    }
302
303    if(err_is_fail(err)) return err;
304
305    // For debugging
306    strncpy(debug_msg, skb_get_output(), sizeof(debug_msg));
307    char * nl = strchr(debug_msg, '\n');
308    if(nl) *nl = '\0';
309    debug_msg[sizeof(debug_msg)-1] = '\0';
310
311    uint64_t start=0, end=0;
312    char ctrl_label[64];
313    // Format is: Lbl,Class,InLo,InHi,....
314    err = skb_read_output("%*[^\n]\n%64[^,],%*[^,],%"SCNu64",%"SCNu64,
315            ctrl_label,
316            &start, &end);
317    if(err_is_fail(err)) DEBUG_SKB_ERR(err, "read response");
318
319    driver_arg->int_arg.int_range_start = start;
320    driver_arg->int_arg.int_range_end = end;
321
322    //Debug message
323    snprintf(debug_msg, sizeof(debug_msg),
324            "lbl=%s,lo=%"PRIu64",hi=%"PRIu64,
325            driver_arg->int_arg.msix_ctrl_name,
326            start, end);
327
328    err = store_int_cap(start, end, driver_arg);
329    if(err_is_fail(err)){
330        USER_PANIC_ERR(err, "store_int_cap");
331    }
332    if(debug) strcpy(debug, debug_msg);
333    return SYS_ERR_OK;
334}
335
336static void pci_change_event(octopus_mode_t mode, const char* device_record,
337                             void* st)
338{
339    errval_t err;
340    char *binary_name = NULL;
341    if (mode & OCT_ON_SET) {
342        KALUGA_DEBUG("pci_change_event: device_record: %s\n", device_record);
343        struct pci_addr addr;
344        struct pci_id id;
345        {
346            uint64_t vendor_id, device_id, bus, dev, fun;
347            err = oct_read(device_record, "_ { vendor: %d, device_id: %d, bus: %d, device: %d,"
348                    " function: %d }",
349                    &vendor_id, &device_id, &bus, &dev, &fun);
350            if (err_is_fail(err)) {
351                USER_PANIC_ERR(err, "Got malformed device record?");
352            }
353            addr = (struct pci_addr) {
354                .bus = bus,
355                .device = dev,
356                .function = fun
357            };
358
359            id = (struct pci_id) {
360                .device = device_id,
361                .vendor = vendor_id
362            };
363        }
364
365        /* duplicate device record as we may need it for later */
366        device_record = strdup(device_record);
367        assert(device_record);
368
369
370        // Ask the SKB which binary and where to start it...
371        static char* query = "find_pci_driver(pci_card(%"PRIu16", %"PRIu16", _, _, _), Driver),"
372                             "writeln(Driver).";
373        err = skb_execute_query(query, id.vendor, id.device);
374        if (err_no(err) == SKB_ERR_EXECUTION) {
375            KALUGA_DEBUG("No PCI driver found for: VendorId=0x%"PRIx16", "
376                         "DeviceId=0x%"PRIx16"\n",
377                    id.vendor, id.device);
378            goto out;
379        }
380        else if (err_is_fail(err)) {
381            DEBUG_SKB_ERR(err, "Failed to query SKB.\n");
382            goto out;
383        }
384
385        // XXX: Find better way to parse binary name from SKB
386        binary_name = malloc(strlen(skb_get_output()));
387        coreid_t core;
388        uint8_t multi;
389        uint8_t int_model_in;
390
391        struct driver_argument driver_arg;
392        err = init_driver_argument(&driver_arg);
393        if(err_is_fail(err)){
394            USER_PANIC_ERR(err, "Could not initialize driver argument.\n");
395        }
396        coreid_t offset;
397        err = skb_read_output("driver(%"SCNu8", %"SCNu8", %"SCNu8", %[^,], "
398                "%"SCNu8")", &core, &multi, &offset, binary_name, &int_model_in);
399        if(err_is_fail(err)){
400            USER_PANIC_SKB_ERR(err, "Could not parse SKB output.\n");
401        }
402
403        driver_arg.int_arg.model = int_model_in;
404
405        static int irqtests_started = 0;
406        if(strstr(binary_name, "irqtest") != NULL){
407            if(irqtests_started++ > 0){
408                debug_printf("Not starting multiple instances of irqtest\n");
409                goto out;
410            }
411        }
412
413        struct module_info* mi = find_module(binary_name);
414        if (mi == NULL) {
415            KALUGA_DEBUG("Driver %s not loaded. Ignore.\n", binary_name);
416            goto out;
417        }
418
419        set_multi_instance(mi, multi);
420        set_core_id_offset(mi, offset);
421
422        // Build up the driver argument
423        err = add_pci_ep(addr, &driver_arg);
424        assert(err_is_ok(err));
425
426        char intcaps_debug_msg[100];
427        err = add_int_args(addr, &driver_arg, intcaps_debug_msg);
428        assert(err_is_ok(err));
429
430        char memcaps_debug_msg[100];
431        err = add_mem_args(addr, &driver_arg, memcaps_debug_msg);
432        assert(err_is_ok(err));
433
434
435        // Wait until the core where we start the driver
436        // is ready
437        if (st == NULL && core != my_core_id) {
438            err = wait_for_spawnd(core, (CONST_CAST)device_record);
439            if (err_no(err) == OCT_ERR_NO_RECORD) {
440                KALUGA_DEBUG("Core where driver %s runs is not up yet.\n",
441                        mi->binary);
442                // Don't want to free device record yet...
443                return;
444            }
445            else if (err_is_fail(err)) {
446                DEBUG_ERR(err, "Waiting for core %d failed?\n", core);
447                goto out;
448            }
449        }
450
451        // If we've come here the core where we spawn the driver
452        // is already up
453        printf("Kaluga: Starting \"%s\" for (bus=%"PRIu16",dev=%"PRIu16",fun=%"PRIu16")"
454               ", int: %s, on core %"PRIuCOREID"\n",
455               binary_name, addr.bus, addr.device, addr.function, intcaps_debug_msg, core);
456
457        err = mi->start_function(core, mi, (CONST_CAST)device_record, &driver_arg);
458        switch (err_no(err)) {
459        case SYS_ERR_OK:
460            KALUGA_DEBUG("Spawned PCI driver: %s\n", mi->binary);
461            set_started(mi);
462            break;
463
464        case KALUGA_ERR_DRIVER_ALREADY_STARTED:
465            KALUGA_DEBUG("%s already running.\n", mi->binary);
466            break;
467
468        case KALUGA_ERR_DRIVER_NOT_AUTO:
469            KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
470            break;
471
472        default:
473            DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
474            break;
475        }
476    }
477
478out:
479    free(binary_name);
480}
481
482errval_t watch_for_pci_devices(void)
483{
484    static char* pci_device  = "r'hw\\.pci\\.device\\.[0-9]+' { "
485                               " bus: _, device: _, function: _, vendor: _,"
486                               " device_id: _, class: _, subclass: _, "
487                               " prog_if: _ }";
488    octopus_trigger_id_t tid;
489    return oct_trigger_existing_and_watch(pci_device, pci_change_event, NULL, &tid);
490}
491
492static void bridge_change_event(octopus_mode_t mode, const char* bridge_record,
493                                void* st)
494{
495    if (mode & OCT_ON_SET) {
496        // No need to ask the SKB as we always start pci for
497        // in case we find a root bridge
498        struct module_info* mi = find_module("pci");
499        if (mi == NULL) {
500            KALUGA_DEBUG("PCI driver not found or not declared as auto.");
501            return;
502        }
503
504        // XXX: always spawn on my_core_id; otherwise we need to check that
505        // the other core is already up
506        errval_t err = mi->start_function(my_core_id, mi, (CONST_CAST)bridge_record, NULL);
507        switch (err_no(err)) {
508        case SYS_ERR_OK:
509            KALUGA_DEBUG("Spawned PCI bus driver: %s\n", mi->binary);
510            set_started(mi);
511            break;
512
513        case KALUGA_ERR_DRIVER_ALREADY_STARTED:
514            KALUGA_DEBUG("%s already running.\n", mi->binary);
515            break;
516
517        case KALUGA_ERR_DRIVER_NOT_AUTO:
518            KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
519            break;
520
521        default:
522            DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
523            break;
524        }
525    }
526}
527
528errval_t watch_for_pci_root_bridge(void)
529{
530    static char* root_bridge = "r'hw\\.pci\\.rootbridge\\.[0-9]+' { "
531                               " bus: _, device: _, function: _, maxbus: _,"
532                               " acpi_node: _ }";
533    octopus_trigger_id_t tid;
534    return oct_trigger_existing_and_watch(root_bridge, bridge_change_event,
535            NULL, &tid);
536}
537