1#include <stdio.h>
2
3#include <pci/pci_types.h>
4#include <barrelfish/barrelfish.h>
5#include <barrelfish/barrelfish.h>
6#include <barrelfish/cpu_arch.h>
7#include <barrelfish/nameservice_client.h>
8#include <if/int_route_controller_defs.h>
9#include <skb/skb.h>
10
11#include "pci_int_ctrl.h"
12#include "pci_debug.h"
13#include "pci.h"
14
15/*
16 *  This file contains interrupt controller clients for the classes 'pci'
17 *  and 'pci_msix'. Both enable interrupts in the PCI conf space. The
18 *  first does so for legacy interrupts, while the later is doing if for MSI-x
19 */
20
21
22static void add_mapping(struct int_route_controller_binding *b,
23        const char *label,
24        const char *class,
25        int_route_controller_int_message_t from,
26        int_route_controller_int_message_t to) {
27
28    errval_t err = SYS_ERR_OK;
29
30    PCI_DEBUG("pci add_mapping: label:%s, class:%s (%"PRIu64", %"PRIu64") to "
31            "(%"PRIu64", %"PRIu64")\n", label, class, from.addr, from.msg, to.addr, to.msg);
32
33    assert(strcmp(class, "pci") == 0 || strcmp(class, "pci_msix") == 0);
34
35
36    struct pci_addr addr;
37    char s_pcie[5];
38    bool pcie;
39    // Get pcilnk acpiName from SKB
40    err = skb_execute_query("pci_lbl_addr(%s, addr(Bus,Dev,Fun)),"
41            "device(PCIE,addr(Bus,Dev,Fun), _, _, _, _, _, _),"
42            "write((Bus,Dev,Fun,PCIE)).", label);
43    if(err_is_fail(err)){
44        DEBUG_SKB_ERR(err, "get pci addr");
45        return;
46    }
47
48
49    err = skb_read_output("%d,%d,%d,%s", &addr.bus, &addr.device,
50            &addr.function, s_pcie);
51    if(err_is_fail(err)){
52        DEBUG_SKB_ERR(err, "parse pci addr");
53        return;
54    }
55    if(strncmp(s_pcie, "pcie", strlen("pcie")) == 0) {
56        pcie = true;
57    } else {
58        pcie = false;
59    }
60
61    PCI_DEBUG("add_mapping: pcie=%d, bus=%"PRIu32", dev=%"PRIu32", fun=%"PRIu32"\n",
62            pcie, addr.bus, addr.device, addr.function);
63
64    if(strncmp(label, "pci_msix", strlen("pci_msix")) == 0){
65        //MSI-X
66        struct pci_address address = {
67            .bus = addr.bus,
68            .device = addr.device,
69            .function = addr.function
70        };
71        err = pci_msix_enable_confspace(&address, 1);
72        if(err_is_fail(err)){
73            USER_PANIC_ERR(err, "msix enable");
74        }
75    } else {
76        //Legacy
77        pci_enable_interrupt_for_device(addr.bus, addr.device, addr.function, pcie);
78    }
79
80}
81
82static void bind_cb(void *st, errval_t err, struct int_route_controller_binding *b) {
83    if(!err_is_ok(err)){
84        debug_err(__FILE__,__FUNCTION__,__LINE__, err, "Bind failure\n");
85        return;
86    }
87
88    b->rx_vtbl.add_mapping = add_mapping;
89
90    // Register this binding for all controllers with class pci
91    const char * label = "";
92    const char * ctrl_class = "pci";
93    b->tx_vtbl.register_controller(b, NOP_CONT, label, ctrl_class);
94
95    // Register this binding for all controllers with class pci_msix
96    const char * ctrl_class_msix = "pci_msix";
97    b->tx_vtbl.register_controller(b, NOP_CONT, label, ctrl_class_msix);
98
99}
100
101errval_t pci_int_ctrl_init(void) {
102    // Connect to int route service
103    iref_t int_route_service;
104    errval_t err;
105    err = nameservice_blocking_lookup("int_ctrl_service", &int_route_service);
106    if(!err_is_ok(err)){
107        debug_err(__FILE__,__FUNCTION__,__LINE__, err, "Could not lookup int_route_service\n");
108        return err;
109    }
110
111    err = int_route_controller_bind(int_route_service,
112            bind_cb, NULL, get_default_waitset(),
113            IDC_BIND_FLAGS_DEFAULT);
114
115    if(!err_is_ok(err)){
116        debug_err(__FILE__,__FUNCTION__,__LINE__, err, "Could not bind int_route_service\n");
117        return err;
118    }
119
120    return SYS_ERR_OK;
121}
122