1#include <pci/pci_driver_client.h>
2#include <pci/pci_driver_client_debug.h>
3#include <if/pci_driver_client_defs.h>
4#include <barrelfish/capabilities.h>
5#include <barrelfish/debug.h>
6#include <int_route/int_route_client.h>
7
8// This is only here for PCIARG defines, remove me!
9#include <pci/pci.h>
10// End
11
12const int PCI_CHANNEL_SIZE = 2048;
13
14/*
15 * Helper for constructing the pci_driver_client_frameinfo from a frame cap
16 * \param frame     an existing frame cap (>=4k)
17 * \param bind      create for bind or accept?
18 * \param fi        output
19 */
20static errval_t frame_to_frameinfo(struct capref frame, bool bind, struct pci_driver_client_frameinfo *fi){
21    struct frame_identity fid;
22    errval_t err;
23    err = invoke_frame_identify(frame, &fid);
24    if(err_is_fail(err)){
25        DEBUG_ERR(err, "invoke_frame_identify");
26        return err;
27    }
28    PDC_DEBUG("pci ep frame base=0x%lx, size=0x%lx\n", fid.base, fid.bytes);
29
30    uint8_t *msg_buf;
31    err = vspace_map_one_frame((void*)&msg_buf, fid.bytes, frame, NULL, NULL);
32    if (err_is_fail(err)) {
33        DEBUG_ERR(err, "vspace_map_one_frame");
34        return err;
35    }
36
37    fi->outbufsize = PCI_CHANNEL_SIZE;
38    fi->inbufsize = PCI_CHANNEL_SIZE;
39    if(bind){
40        fi->sendbase = (lpaddr_t)msg_buf;
41        fi->inbuf = msg_buf + PCI_CHANNEL_SIZE;
42        fi->outbuf = msg_buf;
43    } else {
44        fi->sendbase = (lpaddr_t)msg_buf + PCI_CHANNEL_SIZE;
45        fi->inbuf = msg_buf;
46        fi->outbuf = msg_buf + PCI_CHANNEL_SIZE;
47    }
48
49    return SYS_ERR_OK;
50}
51
52static void pci_bind_cont(void *st, errval_t err, struct pci_driver_client_binding *_binding) {
53    //struct pcid * pcd = (struct pcid *) st;
54}
55
56static errval_t bind_to_pci(struct capref ep, struct pcid * pdc){
57    errval_t err;
58    struct pci_driver_client_frameinfo fi;
59    err = frame_to_frameinfo(ep, true, &fi);
60    if (err_is_fail(err)) {
61        DEBUG_ERR(err, "frame_to_frameinfo");
62        return err;
63    }
64
65    err = pci_driver_client_connect(&fi, pci_bind_cont, pdc, get_default_waitset(),
66            IDC_BIND_FLAGS_DEFAULT);
67    if (err_is_fail(err)) {
68        DEBUG_ERR(err, "pci_driver_client_connect");
69        return err;
70    }
71    return SYS_ERR_OK;
72}
73
74static inline bool strbegins(char *str, char *start){
75    return strncmp(str, start, strlen(start)) == 0;
76}
77
78errval_t pcid_init(
79        struct pcid * pdc,
80        struct capref* caps,
81        size_t caps_len,
82        char** args,
83        size_t args_len,
84        struct waitset * ws)
85{
86    errval_t err;
87    pdc->ws = ws;
88
89    // all caps that are not Interrupt or PCI_EP
90    pdc->num_bars = caps_len - 2;
91
92    {
93        struct capref cnodecap;
94        err = slot_alloc_root(&cnodecap);
95        if(err_is_fail(err)){
96            DEBUG_ERR(err, "slot_alloc_root");
97            return err;
98        }
99        if(caps_len == 1) {
100            debug_printf("Not enough caps received\n");
101            return PCI_ERR_NO_CAP;
102        }
103        err = cap_copy(cnodecap, caps[0]);
104        pdc->arg_cnode = build_cnoderef(cnodecap, CNODE_TYPE_OTHER);
105    }
106
107
108    // Parse pci and int_model arguments
109    bool arg_pci_found = false;
110    bool arg_int_found = false;
111    for(int i=0; i<args_len; i++) {
112        if(strbegins(args[i], "pci=")){
113            pci_deserialize_octet(args[i] + strlen("pci="), &pdc->addr,
114                    &pdc->id, &pdc->cls);
115            arg_pci_found = true;
116        }
117        if(strbegins(args[i], "int_model=") ){
118            err = int_startup_argument_parse(args[i], &pdc->int_arg);
119            if(err_is_fail(err)){
120                DEBUG_ERR(err, "int_startup_argument_parse");
121                return err;
122            }
123            arg_int_found = true;
124        }
125    }
126
127    if(!arg_pci_found || !arg_int_found){
128        debug_printf("PCI or INT arg not found");
129        return PCI_ERR_ARG_PARSE;
130    }
131
132    // Connect to PCI endpoint
133    {
134        struct capref ep = {
135            .cnode = pdc->arg_cnode,
136            .slot = PCIARG_SLOT_PCI_EP
137        };
138        PDC_DEBUG("binding to pci ...\n");
139        err = bind_to_pci(ep, pdc);
140        assert(err_is_ok(err));
141    }
142
143    // Connect to interrupt service
144    err = int_route_client_connect();
145    if(err_is_fail(err)){
146        DEBUG_ERR(err, "int_route_client_connect");
147        return err;
148
149    }
150
151    return SYS_ERR_OK;
152}
153
154errval_t pcid_get_interrupt_cap(struct pcid* pdc, struct capref *ret) {
155
156
157    struct capref interrupt = {
158        .cnode = pdc->arg_cnode,
159        .slot = PCIARG_SLOT_INT,
160    };
161
162    *ret = interrupt;
163
164    return SYS_ERR_OK;
165}
166
167errval_t pcid_get_bar_cap(struct pcid* pdc, int bar_index, struct capref *ret) {
168
169    assert(bar_index <= pdc->num_bars);
170    struct capref bar = {
171        .cnode = pdc->arg_cnode,
172        .slot = PCIARG_SLOT_BAR0 + bar_index,
173    };
174
175    *ret = bar;
176
177    return SYS_ERR_OK;
178}
179
180size_t pcid_get_bar_num(struct pcid* pdc)
181{
182    return pdc->num_bars;
183}
184
185errval_t pcid_connect_int_with_cap(struct capref int_src, int int_index,
186                                   interrupt_handler_fn handler, void *st)
187{
188    errval_t err;
189
190    err = int_route_client_route_and_connect(int_src, int_index,
191        get_default_waitset(), handler, st);
192
193    if(err_is_fail(err)) {
194        DEBUG_ERR(err, "set-up int routing");
195    }
196
197    return err;
198}
199
200errval_t pcid_connect_int(struct pcid* pdc, int int_index,
201                          interrupt_handler_fn handler, void *st)
202{
203    errval_t err;
204    struct capref irq_cap;
205    err = pcid_get_interrupt_cap(pdc, &irq_cap);
206    if(err_is_fail(err)){
207        return err;
208    }
209
210    return pcid_connect_int_with_cap(irq_cap, int_index, handler, st);
211}
212
213errval_t pcid_enable_msix(int *num_vectors) {
214    //TODO RPC
215    return SYS_ERR_OK;
216}
217