1/**
2 * \file
3 * \brief Driverkit module implementation.
4 *
5 * Contians helper functions to iterate over driver modules in a domain
6 * and create driver instances from driver modules.
7 */
8/*
9 * Copyright (c) 2016, ETH Zurich.
10 * All rights reserved.
11 *
12 * This file is distributed under the terms in the attached LICENSE file.
13 * If you do not find this file, copies can be found by writing to:
14 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
15 */
16#include <stdlib.h>
17
18#include <barrelfish/barrelfish.h>
19#include <driverkit/driverkit.h>
20#include <collections/hash_table.h>
21
22
23#include "debug.h"
24
25#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
26
27///< Points to start of the ELF section where the bfdriver structs are.
28extern struct bfdriver bfdrivers_start[];
29///< Points to the end of the ELF section where the bfdriver structs are.
30extern struct bfdriver bfdrivers_end[];
31
32static collections_listnode* instances = NULL;
33
34/**
35 * Initializes a pointer to point to the list of all bfdrivers.
36 *
37 * The driver structs are stored in a special ELF section (called .bfdrivers).
38 * The custom link script of the driver domain makes sure there is a bfdrivers_start
39 * and bfdrivers_end symbol at the beginning and end of that section.
40 *
41 * \param[out] start Initialized to point to the first bfdriver instance.
42 * \param[out] num   How many drivers there are.
43 */
44void driverkit_list(struct bfdriver** start, size_t* num) {
45    *start = (struct bfdriver*) bfdrivers_start;
46    *num = ((ptrdiff_t)bfdrivers_end - (ptrdiff_t)bfdrivers_start) / sizeof(struct bfdriver);
47}
48
49/**
50 * Finds a driver instance linked with the driver domain:
51 * \param  name The name of the driver we're interested in.
52 * \return      bfdriver instance with matching name or NULL in case not found.
53 */
54struct bfdriver* driverkit_lookup_cls(const char* name) {
55    assert(name != NULL);
56
57    size_t drivers = 0;
58    struct bfdriver* cur = NULL;
59    driverkit_list(&cur, &drivers);
60
61    for (size_t i=0; i<drivers; i++) {
62        if (strcmp(name, cur->name) == 0) {
63            return cur;
64        }
65        cur += 1;
66    }
67
68    return NULL; // not found
69}
70
71/**
72 * Frees a bfdriver instance. Callers need to make sure
73 * that bfi->destroy was called beforehand to clean up
74 * state that is owned by the driver.
75 *
76 * \param arg bfdriver instance.
77 */
78static void free_driver_instance(void* arg) {
79    assert (arg != NULL);
80    struct bfdriver_instance* bfi = (struct bfdriver_instance*) arg;
81    free(bfi);
82}
83
84/**
85 * Compare driver instance name with supplied argument.
86 *
87 * Helper function for collection_list_* data-structure.
88 *
89 * \param[in]  elem   bfdriver instance
90 * \param[in]  name   String
91 * \retval True   iff name == bfi->name
92 * \retval False  iff name != bfi->name
93 */
94static int32_t match_name(void* elem, void* name) {
95    assert(elem != NULL);
96    assert(name != NULL);
97
98    struct bfdriver_instance* bfi = (struct bfdriver_instance*) elem;
99    assert (bfi->name != NULL);
100    assert (name != NULL);
101    if (strcmp((char*)name, bfi->name) == 0) {
102        return 1;
103    }
104    else {
105        return 0;
106    }
107}
108
109/**
110 * Destroys a driver instances identified by its name.
111 * \todo various tricky service clean-up issues are simply ignored here.
112 *
113 * \param  name Name of the instance
114 * \retval SYS_ER_OK Driver successfully destroyed.
115 * \retval DRIVERKIT_ERR_DRIVER_DETACH detaching failed.
116 */
117errval_t driverkit_destroy(const char* name) {
118    assert(name != NULL);
119    if (instances == NULL) {
120        collections_list_create(&instances, free_driver_instance);
121    }
122
123    void* namearg = (void*) name; // Get rid of the const because collections_* API is not specific enough...
124    struct bfdriver_instance* bfi = collections_list_find_if(instances, match_name, namearg);
125    errval_t err = bfi->driver->destroy(bfi);
126    if (err_is_ok(err)) {
127        struct bfdriver_instance* bfi2 = (struct bfdriver_instance*) collections_list_remove_if(instances, match_name, namearg);
128        free_driver_instance(bfi2);
129    }
130    else {
131        err = err_push(err, DRIVERKIT_ERR_DRIVER_DETACH);
132    }
133
134    return err;
135}
136
137/**
138 * Destroys a driver instances identified by its name.
139 * \todo various tricky service clean-up issues are simply ignored here.
140 *
141 * \param  name Name of the instance
142 * \retval SYS_ER_OK Driver successfully destroyed.
143 * \retval DRIVERKIT_ERR_DRIVER_DETACH detaching failed.
144 */
145/*
146errval_t driverkit_get_ep(const char* name) {
147    assert(name != NULL);
148    if (instances == NULL) {
149        collections_list_create(&instances, free_driver_instance);
150    }
151
152    void* namearg = (void*) name; // Get rid of the const because collections_* API is not specific enough...
153    struct bfdriver_instance* bfi = collections_list_find_if(instances, match_name, namearg);
154    errval_t err = bfi->driver->destroy(bfi);
155    if (err_is_ok(err)) {
156        struct bfdriver_instance* bfi2 = (struct bfdriver_instance*) collections_list_remove_if(instances, match_name, namearg);
157        free_driver_instance(bfi2);
158    }
159    else {
160        err = err_push(err, DRIVERKIT_ERR_DRIVER_DETACH);
161    }
162
163    return err;
164}
165*/
166
167/**
168 * Create a driver instance within the driver domain.
169 *
170 * \param[in]   cls     The class of driver (found in bfdriver).
171 * \param[in]   name    The name of the driver instance.
172 * \param[in]   caps    Caps provided to the driver's init function.
173 * \param[in]   flags   Flags provided to the driver's init function.
174 * \param[out]  device  iref of the device interface (as created by the device).
175 * \param[out]  control endpoint cap of the control interface (created as part of this function).
176 * \return      Error status of driver creation.
177 */
178errval_t driverkit_create_driver(const char* cls, struct bfdriver_instance *inst,
179                                 uint64_t flags, iref_t* device, struct capref* control)
180{
181    assert(cls != NULL);
182    assert(device != NULL);
183    assert(inst != NULL);
184
185    errval_t err = SYS_ERR_OK;
186
187    struct bfdriver* drv = driverkit_lookup_cls(cls);
188    if (drv == NULL) {
189        return DRIVERKIT_ERR_NO_DRIVER_FOUND;
190    }
191    DRIVERKIT_DEBUG("Using driver %s for class %s\n", drv->name, cls);
192
193#if defined(ENABLE_DRIVERKIT_DEBUG)
194    {
195        char caps[1024];
196        for(int i=0; i<16; i++){
197            struct capref cc = {
198                .cnode = inst->argcn,
199                .slot = i
200            };
201            debug_print_cap_at_capref(caps, sizeof(caps), cc);
202            debug_printf("[dkit] cap %d = %s\n", i, caps);
203        }
204    }
205#endif
206
207    inst->driver = drv;
208
209    err = drv->init(inst, flags, device);
210    if (err_is_fail(err)) {
211        //DRIVERKIT_DEBUG("Init returned error...\n");
212        DEBUG_ERR(err, "Can't initialize the device");
213        free_driver_instance(inst);
214        return err_push(err, DRIVERKIT_ERR_DRIVER_INIT);
215    }
216
217    // Since Kaluga always has to be on core 0, we can do this ...
218    err = dcontrol_service_init(inst, NULL, (disp_get_core_id() == 0), control);
219    if (err_is_fail(err)) {
220        DEBUG_ERR(err, "Can't set-up control interface for device.");
221        free_driver_instance(inst);
222        return err_push(err, DRIVERKIT_ERR_CONTROL_SERVICE_INIT);
223    }
224
225    DRIVERKIT_DEBUG("Driver class %s initialized.\n", drv->name);
226    if (instances == NULL) {
227        collections_list_create(&instances, free_driver_instance);
228    }
229    collections_list_insert(instances, inst);
230
231    return err;
232}
233
234
235errval_t driverkit_local_service_register(char* name, void* tbl)
236{
237
238    return SYS_ERR_OK;
239}
240
241void* driverkit_local_service_lookup(char* name)
242{
243
244    return NULL;
245}
246
247static errval_t get_cap(struct bfdriver_instance *bfi, cslot_t slot, struct capref *cap)
248{
249    if (slot >= DRIVERKIT_ARGCN_SLOT_MAX) {
250        return DRIVERKIT_ERR_CAP_CAPACITY;
251    }
252
253    struct capref dest = {
254        .cnode = bfi->argcn,
255        .slot = slot
256    };
257
258    *cap = dest;
259
260    return SYS_ERR_OK;
261}
262
263errval_t driverkit_get_interrupt_cap(struct bfdriver_instance *bfi, struct capref *cap)
264{
265    return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_INT, cap);
266}
267
268errval_t driverkit_get_iommu_cap(struct bfdriver_instance *bfi, struct capref *cap)
269{
270    return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_IOMMU, cap);
271}
272
273errval_t driverkit_get_pci_cap(struct bfdriver_instance *bfi, struct capref *cap)
274{
275    return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_PCI_EP, cap);
276}
277
278errval_t driverkit_get_bar_cap(struct bfdriver_instance *bfi, uint8_t idx,
279                               struct capref *cap)
280{
281    if (idx >= 6) {
282        return DRIVERKIT_ERR_CAP_CAPACITY;
283    }
284    return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_BAR0 + idx, cap);
285}
286