1/**
2 * \file
3 * \brief Code responsible for starting devices discovered from decoding nets
4 */
5
6/*
7 * Copyright (c) 2016 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <barrelfish/barrelfish.h>
16
17#include <skb/skb.h>
18
19#include <if/octopus_defs.h>
20
21#include <octopus/getset.h>
22#include <octopus/trigger.h>
23
24#include <maps/omap44xx_map.h>
25#include <arch/arm/omap44xx/device_registers.h>
26
27#include <bitmacros.h>
28
29#include "kaluga.h"
30
31#define DRIVER_CORE 0
32
33static void start_driver_for_device(struct domain_instance *inst, char* device) {
34
35    errval_t err = skb_execute_query("find_dn_driver('%s',R),write(R)", device);
36    if (err == SKB_ERR_EXECUTION) {
37        KALUGA_DEBUG("No driver found for device %s\n", device);
38        return;
39    } else if (err_is_fail(err)) {
40        DEBUG_SKB_ERR(err, "Getting driver info");
41        return;
42    }
43    // Save driver info for later
44    char *driver_info = strdup(skb_get_output());
45
46    char *name = malloc(strlen(driver_info));
47    int start_on_discovery = 0;
48    err = skb_read_output_at(driver_info, "driver(%[^,],%d", name, &start_on_discovery);
49    if (err_is_fail(err)) {
50        USER_PANIC_SKB_ERR(err, "SKB parse error while getting driver info.");
51    }
52    else if (!start_on_discovery && inst == NULL) {
53        KALUGA_DEBUG("Driver start deferred until other driver depends on it.\n");
54        goto out;
55    }
56    KALUGA_DEBUG("Driver module name: %s\n", name);
57
58    if (inst == NULL) {
59        // XXX: for now we start all drivers on core 0
60        inst = instantiate_driver_domain(DRIVER_CORE);
61    }
62
63    struct driver_instance *drv = ddomain_create_driver_instance(name, name);
64
65    // Start driver dependencies
66    struct list_parser_status status;
67    skb_read_list_init_offset(&status, driver_info, 0);
68
69    char *dep = malloc(strlen(driver_info));
70
71    while(skb_read_list(&status, "drv_dep(%[^)]", dep)) {
72        KALUGA_DEBUG("Driver %s dependency %s\n", name, dep);
73        start_driver_for_device(inst, dep);
74    }
75    free(dep);
76
77    // Give memory caps to driver by using decoding net
78    err = skb_execute_query("dn_driver{module:\"%s\",device_regions:D},"
79                                    "driver_register_regions(%d,D,R),write(R)", name, DRIVER_CORE);
80    if (err_is_fail(err)) {
81        USER_PANIC_SKB_ERR(err, "Could not get device regions");
82    }
83    KALUGA_DEBUG("Register region list %s\n", skb_get_output());
84
85    lpaddr_t addr, size;
86
87    skb_read_list_init(&status);
88    while(skb_read_list(&status, "reg(%" SCNuLPADDR",%" SCNuLPADDR ")", &addr, &size)) {
89        KALUGA_DEBUG("Get cap for registers: %"PRIxLPADDR", %"PRIxLPADDR"\n", addr, size);
90
91        struct capref device_frame;
92        err = get_device_cap(ROUND_DOWN(addr, BASE_PAGE_SIZE), ROUND_UP(size, BASE_PAGE_SIZE), &device_frame);
93        assert(err_is_ok(err));
94
95        KALUGA_DEBUG("get_device_cap worked\n");
96        err = ddomain_driver_add_cap(drv, device_frame);
97    }
98
99    // Give interrupt source caps to driver by using decoding net
100    err = skb_execute_query("dn_driver{module:\"%s\",device_interrupts:Ids},"
101                                    "driver_interrupt_enum(Ids,I),write(I)", name);
102    KALUGA_DEBUG("Interrupt enum list %s\n", skb_get_output());
103
104    skb_read_list_init(&status);
105    uint32_t base, limit;
106    while(skb_read_list(&status, "int(%d,%d)", &base, &limit)) {
107        KALUGA_DEBUG("Get interrupt cap for range: base=%"PRIu32", "
108                "limit=%"PRIu32"\n", base, limit);
109    }
110
111    ddomain_instantiate_driver(inst, drv);
112
113    KALUGA_DEBUG("Driver %s started\n", name);
114
115    out:
116    free(name);
117    free(driver_info);
118}
119
120static void decnet_change_event(octopus_mode_t mode, const char* device_record,
121                                void* st)
122{
123    KALUGA_DEBUG("Decoding net record: %s\n", device_record);
124
125    if (mode & OCT_ON_SET) {
126        char *device = NULL;
127
128        errval_t err = oct_read(device_record, "_ { device: %s }", &device);
129        if (err_is_fail(err)) {
130            USER_PANIC_ERR(err, "Got malformed device record?");
131        }
132
133        KALUGA_DEBUG("Found decoding net device %s\n", device);
134
135        start_driver_for_device(NULL, device);
136    }
137}
138
139errval_t watch_for_decnet_devices(void)
140{
141    static char* decnet_device  = "r'hw\\.dn\\.device\\.[0-9]+' { "
142            " device: _ }";
143    octopus_trigger_id_t tid;
144    return oct_trigger_existing_and_watch(decnet_device, decnet_change_event, NULL, &tid);
145}
146