1#include <barrelfish/barrelfish.h>
2#include <barrelfish/nameservice_client.h>
3#include <int_route/msix_ctrl.h>
4#include <int_route/int_model.h>
5#include <if/int_route_controller_defs.h>
6#include <dev/msix_e1000_dev.h>
7
8#include "debug.h"
9
10struct msix_ctrl_state {
11    int bound;
12    msix_e1000_t dev;     // Mackerel state
13    struct int_startup_argument * arg; // Contains name etc.
14};
15
16
17static void add_mapping(struct int_route_controller_binding *b,
18        const char *label,
19        const char *class,
20        int_route_controller_int_message_t from,
21        int_route_controller_int_message_t to) {
22
23    struct msix_ctrl_state * st = b->st;
24    CTRL_DEBUG("msix add_mapping: label:%s, class:%s (%"PRIu64", %"PRIu64") to "
25            "(%"PRIu64", %"PRIu64")\n", label, class, from.addr, from.msg, to.addr, to.msg);
26
27
28    CTRL_DEBUG("Setting MSIx port=%"PRIu64" to (addr=0x%"PRIx64",msg=0x%"PRIx64")\n",
29            from.port, to.addr, to.msg);
30
31    int vec_num = from.addr; //TODO make sure this is correct
32    msix_e1000_vec_control_wr(&st->dev, vec_num, 0);
33    msix_e1000_msg_data_wr(&st->dev, vec_num, to.msg);
34    msix_e1000_msg_addr_wr(&st->dev, vec_num, to.addr);
35};
36
37static void msix_ctrl_bind_cb(void *stin, errval_t err, struct int_route_controller_binding *b) {
38    struct msix_ctrl_state * st = stin;
39    if(!err_is_ok(err)){
40        debug_err(__FILE__,__FUNCTION__,__LINE__, err, "Bind failure\n");
41        return;
42    }
43
44    b->rx_vtbl.add_mapping = add_mapping;
45
46    // Register this binding for name=msix_ctrl_name and class msix
47    b->tx_vtbl.register_controller(b, BLOCKING_CONT, st->arg->msix_ctrl_name, "msix");
48
49    // Store state in binding
50    b->st = st;
51
52    st->bound = true;
53}
54
55errval_t msix_client_init_by_args(int argc, char **argv, void* msix_tab) {
56    struct int_startup_argument *arg = malloc(sizeof(struct int_startup_argument));
57    if(!arg) return LIB_ERR_MALLOC_FAIL;
58
59    errval_t err = SYS_ERR_IRQ_NO_ARG;
60    for(int i=0; i<argc; i++){
61        err = int_startup_argument_parse(argv[i], arg);
62        if(err_is_ok(err)) break;
63    }
64    if(!err_is_ok(err)) return err;
65    if(arg->model != INT_MODEL_MSIX) {
66        return SYS_ERR_IRQ_INVALID;
67    }
68    return msix_client_init(arg, msix_tab);
69};
70
71errval_t msix_client_init(struct int_startup_argument *arg, void* msix_tab) {
72    // Allocate state. Need to think about this.
73    struct msix_ctrl_state * st = malloc(sizeof(struct msix_ctrl_state));
74    st->bound = false;
75    st->arg = arg;
76    CTRL_DEBUG("Instantiating MSIx ctrl driver (name=%s)\n",
77            arg->msix_ctrl_name);
78
79    // Connect to int route service
80    iref_t int_route_service;
81    errval_t err;
82    err = nameservice_blocking_lookup("int_ctrl_service", &int_route_service);
83    if(!err_is_ok(err)){
84        debug_err(__FILE__,__FUNCTION__,__LINE__, err,
85                "Could not lookup int_route_service\n");
86        return err;
87    }
88
89    err = int_route_controller_bind(int_route_service, msix_ctrl_bind_cb, st,
90            get_default_waitset(), IDC_BIND_FLAGS_DEFAULT);
91
92    if(!err_is_ok(err)){
93        debug_err(__FILE__,__FUNCTION__,__LINE__, err,
94                "Could not bind int_route_service\n");
95        return err;
96    }
97
98    while(!st->bound) event_dispatch(get_default_waitset());
99
100
101    msix_e1000_initialize(&st->dev, msix_tab);
102
103    return SYS_ERR_OK;
104};
105