1/**
2 * \file
3 * \brief Contains handler functions for server-side octopus interface RPC call.
4 */
5
6/*
7 * Copyright (c) 2009, 2010, 2012, 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 <stdio.h>
16#include <string.h>
17#include <inttypes.h>
18#include <errno.h>
19
20#include <barrelfish/barrelfish.h>
21#include <barrelfish/nameservice_client.h>
22#include <skb/skb.h> // read list
23#include <int_route/int_route_server.h>
24#include <int_route/int_route_debug.h>
25
26#include <if/int_route_service_defs.h>
27#include <if/int_route_controller_defs.h>
28
29struct controller_driver {
30   char * label; // Label used in the SKB
31   char * class; // Class used in the SKB
32   struct int_route_controller_binding * binding; //
33   struct controller_driver * next; // Linked list next
34};
35
36/* This server exports two interfaces:
37 * * RPC interface - This is RPC the interface that
38 * * Controller interface - Interrupt controllers use a
39 */
40
41struct controller_driver * controller_head;
42static int exported = 0;
43
44static struct controller_driver * add_controller(struct controller_driver * d){
45    struct controller_driver * cur;
46    if(controller_head == NULL){
47        controller_head = malloc(sizeof(struct controller_driver));
48        cur = controller_head;
49    } else if(d != NULL && d->next != NULL){
50        return add_controller(d->next);
51    } else {
52        assert(d != NULL);
53        d->next = malloc(sizeof(struct controller_driver));
54        cur = d->next;
55    }
56
57    // Initialize cur
58    cur->next = NULL;
59    cur->binding = NULL;
60    cur->label = NULL;
61    cur->class = NULL;
62    return cur;
63}
64
65/*
66 * Finds a controller for the given label/class combination.
67 * First, if a label is passed, it tries to match the label exactly, if no
68 * controller is found, it goes on to match on the class.
69 */
70static struct controller_driver *find_controller(const char *label,
71                                                 const char *class) {
72    if (label != NULL && strlen(label) > 0) {
73        for (struct controller_driver *cur = controller_head; cur != NULL;
74             cur = cur->next) {
75            if (strcmp(label, cur->label) == 0) {
76                return cur;
77            }
78        }
79    }
80    if (class != NULL && strlen(class) > 0) {
81        for (struct controller_driver *cur = controller_head; cur != NULL;
82             cur = cur->next) {
83            if (strcmp(class, cur->class) == 0) {
84                return cur;
85            }
86        }
87    }
88    return NULL;
89}
90
91struct controller_add_mapping_data {
92    char * lbl;
93    char * class;
94    int_route_controller_int_message_t in_msg;
95    int_route_controller_int_message_t out_msg;
96    struct int_route_controller_binding *binding;
97};
98
99#define INVALID_PORT -1
100#define INVALID_VECTOR ((uint64_t)-1)
101
102/**
103 * Since on ARMv7 the topolgy is easy, we don't use the SKB.
104 */
105static void driver_route_call_armv7(struct int_route_service_binding *b,
106        struct capref intsource, int irq_idx,
107        struct capref intdest){
108    INT_DEBUG("%s: enter\n", __FUNCTION__);
109
110    errval_t err;
111    uint64_t int_src_num = INVALID_VECTOR;
112    err = invoke_irqsrc_get_vec_start(intsource, &int_src_num);
113    uint64_t int_src_num_high = INVALID_VECTOR;
114    err = invoke_irqsrc_get_vec_end(intsource, &int_src_num_high);
115    if(int_src_num + irq_idx > int_src_num_high || irq_idx < 0){
116        err = SYS_ERR_IRQ_INVALID;
117        DEBUG_ERR(err, "irq_idx out of range");
118        b->tx_vtbl.route_response(b, NOP_CONT, err);
119        return;
120    }
121
122    assert(err_is_ok(err));
123    int_src_num += irq_idx;
124
125    uint64_t dest_vec = INVALID_VECTOR;
126    err = invoke_irqdest_get_vector(intdest, &dest_vec);
127    assert(err_is_ok(err));
128
129    uint64_t dest_cpu = INVALID_VECTOR;
130    err = invoke_irqdest_get_cpu(intdest, &dest_cpu);
131    assert(err_is_ok(err));
132
133    printf("Int route service: Routing request, (int=%"PRIu64") to "
134            "(cpu=%"PRIu64",vec=%"PRIu64")\n",
135            int_src_num, dest_cpu, dest_vec);
136
137
138    const char * class = "gic_dist";
139    struct controller_driver * gic_dist = find_controller(NULL, class);
140
141    if(gic_dist == NULL){
142        err = SYS_ERR_IRQ_INVALID;
143        DEBUG_ERR(err, "gic_dist controller not found!\n");
144    } else {
145        int_route_controller_int_message_t in_msg;
146        in_msg.port = int_src_num;
147        int_route_controller_int_message_t out_msg;
148        out_msg.port = dest_cpu;
149        err = int_route_controller_add_mapping__tx(gic_dist->binding,
150                BLOCKING_CONT, NULL, class, in_msg,
151                out_msg);
152    }
153
154    b->tx_vtbl.route_response(b, NOP_CONT, err);
155}
156
157static void ctrl_register_controller(struct int_route_controller_binding *_binding,
158        const char *label, const char *class) {
159    struct controller_driver * c = add_controller(controller_head);
160    c->label = malloc(strlen(label)+1);
161    assert(c->label != NULL);
162    strcpy(c->label, label);
163
164    c->class = malloc(strlen(class)+1);
165    assert(c->class != NULL);
166    strcpy(c->class, class);
167    INT_DEBUG("ctrl_register_controller, label=%s, class=%s\n",c->label, c->class);
168
169    c->binding = _binding;
170}
171
172
173static struct int_route_service_rx_vtbl driver_rx_vtbl = {
174        .route_call = driver_route_call_armv7
175
176};
177
178static struct int_route_controller_rx_vtbl ctrl_rx_vtbl = {
179        .register_controller = ctrl_register_controller
180};
181
182static errval_t driver_connect_cb(void *st, struct int_route_service_binding *b) {
183    INT_DEBUG("%s: enter\n", __FUNCTION__);
184    b->st = NULL;
185    b->rx_vtbl = driver_rx_vtbl;
186    return SYS_ERR_OK;
187
188}
189
190static errval_t ctrl_connect_cb(void *st, struct int_route_controller_binding *b) {
191    INT_DEBUG("%s: enter\n", __FUNCTION__);
192    b->st = NULL;
193    b->rx_vtbl = ctrl_rx_vtbl;
194    return SYS_ERR_OK;
195
196}
197
198static void driver_export_cb(void *st, errval_t err, iref_t iref){
199    INT_DEBUG("%s: enter\n", __FUNCTION__);
200    assert(err_is_ok(err));
201
202    err = nameservice_register("int_route_service", iref);
203    if (err_is_fail(err)) {
204        USER_PANIC_ERR(err, "nameservice_register 1 failed");
205    };
206    exported++;
207}
208
209static void ctrl_export_cb(void *st, errval_t err, iref_t iref){
210    INT_DEBUG("%s: enter\n", __FUNCTION__);
211    assert(err_is_ok(err));
212
213    err = nameservice_register("int_ctrl_service", iref);
214    if (err_is_fail(err)) {
215        USER_PANIC_ERR(err, "nameservice_register 2 failed");
216    };
217    exported++;
218}
219
220
221// The main function of this service
222int main(void) {
223    errval_t err;
224    debug_printf("Start\n");
225
226    // Export route service for PCI device drivers
227    err = int_route_service_export(NULL, driver_export_cb, driver_connect_cb,
228                                   get_default_waitset(),
229                                   IDC_EXPORT_FLAGS_DEFAULT);
230
231    if (err_is_fail(err)) {
232        USER_PANIC_ERR(err, "int_route_service_export failed");
233    }
234
235    err = int_route_controller_export(NULL, ctrl_export_cb, ctrl_connect_cb,
236                                      get_default_waitset(),
237                                      IDC_EXPORT_FLAGS_DEFAULT);
238    if (err_is_fail(err)) {
239        USER_PANIC_ERR(err, "int_route_controller_export failed");
240    }
241
242    while (true) {
243        event_dispatch(get_default_waitset());
244    }
245
246    return 0;
247}
248