IRQ: Kaluga start driver with IRQ caps.
[barrelfish] / lib / pci / pci_client.c
1 /**
2  * \file
3  * \brief PCI service client-side logic
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2011, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <barrelfish/barrelfish.h>
18 #include <barrelfish/nameservice_client.h>
19 #include <barrelfish/dispatch.h>
20 #include <barrelfish/inthandler.h>
21 #include <pci/pci.h>
22 #include <pci/pci_client_debug.h>
23 #include <if/pci_defs.h>
24 #include <if/pci_rpcclient_defs.h>
25 #include <if/acpi_rpcclient_defs.h>
26 #include <acpi_client/acpi_client.h>
27 #include <int_route/int_model.h>
28 #include <int_route/int_route_client.h>
29
30 #define INVALID_VECTOR ((uint64_t)-1)
31
32 static struct pci_rpc_client *pci_client = NULL;
33
34
35 /*
36  * Parse the int_model=
37  */
38 static struct int_startup_argument int_arg;
39 static bool int_arg_found = false;
40
41 errval_t pci_parse_int_arg(int argc, char ** argv) {
42     errval_t err;
43     for(int i=0; i < argc; i++){
44         err = int_startup_argument_parse(argv[i], &int_arg);
45         if(err_is_ok(err)){
46             int_arg_found = true;
47             return err;
48         }
49     }
50     return SYS_ERR_IRQ_INVALID;
51 }
52
53 errval_t pci_reregister_irq_for_device(uint32_t class, uint32_t subclass, uint32_t prog_if,
54                                        uint32_t vendor, uint32_t device,
55                                        uint32_t bus, uint32_t dev, uint32_t fun,
56                                        interrupt_handler_fn handler,
57                                        void *handler_arg,
58                                        interrupt_handler_fn reloc_handler,
59                                        void *reloc_handler_arg)
60 {
61     uint64_t vector = INVALID_VECTOR;
62     errval_t err, msgerr;
63
64     if (handler != NULL && reloc_handler != NULL) {
65         // register movable interrupt
66         err = inthandler_setup_movable(handler, handler_arg, reloc_handler,
67                 reloc_handler_arg, &vector);
68         if (err_is_fail(err)) {
69             return err;
70         }
71
72         assert(vector != INVALID_VECTOR);
73     } else if (handler != NULL) {
74         // register non-movable interrupt
75         err = inthandler_setup(handler, handler_arg, &vector);
76         if (err_is_fail(err)) {
77             return err;
78         }
79
80         assert(vector != INVALID_VECTOR);
81     }
82
83     err = pci_client->vtbl.
84         reregister_interrupt(pci_client, class, subclass, prog_if, vendor,
85                 device, bus, dev, fun, disp_get_current_core_id(),
86                 vector, &msgerr);
87     if (err_is_fail(err)) {
88         return err;
89     } else if (err_is_fail(msgerr)) {
90         return msgerr;
91     }
92     return SYS_ERR_OK;
93 }
94
95 errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, uint32_t class,
96                                          uint32_t subclass, uint32_t prog_if,
97                                          uint32_t vendor, uint32_t device,
98                                          uint32_t bus, uint32_t dev, uint32_t fun,
99                                          interrupt_handler_fn handler,
100                                          void *handler_arg,
101                                          interrupt_handler_fn reloc_handler,
102                                          void *reloc_handler_arg)
103 {
104     pci_caps_per_bar_t caps_per_bar;
105     uint8_t nbars;
106     errval_t err, msgerr;
107
108     err = pci_client->vtbl.
109         init_pci_device(pci_client, class, subclass, prog_if, vendor,
110                         device, bus, dev, fun, &msgerr,
111                         &nbars, caps_per_bar, caps_per_bar + 1, caps_per_bar + 2,
112                         caps_per_bar + 3, caps_per_bar + 4, caps_per_bar + 5);
113     if (err_is_fail(err)) {
114         PCI_CLIENT_DEBUG("init pci device failed.\n");
115         return err;
116     } else if (err_is_fail(msgerr)) {
117         return msgerr;
118     }
119
120
121     // Check for cap argument
122     struct capability cap_argcn_data;
123     err = debug_cap_identify(cap_argcn, &cap_argcn_data);
124     if(err_is_fail(err) || cap_argcn_data.type == ObjType_Null){
125         PCI_CLIENT_DEBUG("No capabilites passed as argument. Driver not started by kaluga?");
126     }
127
128     // We use the first passed vector of the device,
129     // for backward compatibility with function interface.
130     struct capref irq_src_cap;
131     struct capability irq_src_cap_data;
132     irq_src_cap.cnode = build_cnoderef(cap_argcn, DEFAULT_CNODE_BITS);
133     irq_src_cap.slot = 0;
134     err = debug_cap_identify(irq_src_cap, &irq_src_cap_data);
135     if(err_is_fail(err)){
136         DEBUG_ERR(err, "Could not identify cap?");
137     }
138     if(irq_src_cap_data.type != ObjType_IRQSrc){
139         PCI_CLIENT_DEBUG("First cap argument ist not of type IRQSrc (is=%d)."
140                 "Driver not started by kaluga?\n", cap_argcn_data.type);
141     }
142
143     uint64_t gsi = INVALID_VECTOR;
144     err = invoke_irqsrc_get_vector(irq_src_cap, &gsi);
145     if (err_is_fail(err)) {
146         DEBUG_ERR(err, "Could not lookup GSI vector");
147         return err;
148     }
149     PCI_CLIENT_DEBUG("Got irqsrc cap, gsi: %"PRIu64"\n", gsi);
150
151     // Get irq_dest_cap from monitor
152     struct capref irq_dest_cap;
153     err = alloc_dest_irq_cap(&irq_dest_cap);
154     if(err_is_fail(err)){
155         DEBUG_ERR(err, "Could not allocate dest irq cap");
156         goto out;
157     }
158     uint64_t irq_dest_vec = INVALID_VECTOR;
159     err = invoke_irqdest_get_vector(irq_dest_cap, &irq_dest_vec);
160     if (err_is_fail(err)) {
161         DEBUG_ERR(err, "Could not lookup irq vector");
162         return err;
163     }
164     PCI_CLIENT_DEBUG("Got dest cap, vector: %"PRIu64"\n", irq_dest_vec);
165
166
167     err = int_route_client_route(irq_src_cap, irq_dest_cap);
168     if(err_is_fail(err)){
169         DEBUG_ERR(err, "Could not set up route.");
170         return err;
171     } else {
172         PCI_CLIENT_DEBUG("Int route set-up success.\n");
173     }
174
175     //// Setup routing
176     //// TODO: Instead of getting the vectors of each cap and set up routing,
177     //// pass both to a routing service and let the service handle the setup.
178     //struct acpi_rpc_client* cl = get_acpi_rpc_client();
179     //errval_t ret_error;
180     //err = cl->vtbl.enable_and_route_interrupt(cl, gsi, disp_get_core_id(), irq_dest_vec, &ret_error);
181     //assert(err_is_ok(err));
182     //if (err_is_fail(ret_error)) {
183     //    DEBUG_ERR(ret_error, "failed to route interrupt %d -> %d\n", gsi, irq_dest_vec);
184     //    return err_push(ret_error, PCI_ERR_ROUTING_IRQ);
185     //}
186
187     // Connect endpoint to handler
188     if(handler != NULL){
189         err = inthandler_setup_movable_cap(irq_dest_cap, handler, handler_arg,
190                 reloc_handler, reloc_handler_arg);
191         if (err_is_fail(err)) {
192             return err;
193         }
194     }
195
196
197     assert(nbars > 0); // otherwise we should have received an error!
198
199     // FIXME: leak
200     struct device_mem *bars = calloc(nbars, sizeof(struct device_mem));
201     assert(bars != NULL);
202
203     // request caps for all bars of device
204     for (int nb = 0; nb < nbars; nb++) {
205         struct device_mem *bar = &bars[nb];
206
207         int ncaps = (caps_per_bar)[nb];
208         if (ncaps != 0) {
209             bar->nr_caps = ncaps;
210             bar->frame_cap = malloc(ncaps * sizeof(struct capref)); // FIXME: leak
211             assert(bar->frame_cap != NULL);
212         }
213
214         for (int nc = 0; nc < ncaps; nc++) {
215             struct capref cap;
216             uint8_t type;
217
218             err = pci_client->vtbl.get_bar_cap(pci_client, nb, nc, &msgerr, &cap,
219                                            &type, &bar->bar_nr);
220             if (err_is_fail(err) || err_is_fail(msgerr)) {
221                 if (err_is_ok(err)) {
222                     err = msgerr;
223                 }
224                 DEBUG_ERR(err, "requesting cap %d for BAR %d of device", nc, nb);
225                 goto out;
226             }
227
228             if (type == 0) { // Frame cap BAR
229                 bar->frame_cap[nc] = cap;
230                 if (nc == 0) {
231                     struct frame_identity id = { .base = 0, .bytes = 0 };
232                     err = invoke_frame_identify(cap, &id);
233                     if (err_is_fail(err)) {
234                         USER_PANIC_ERR(err, "frame identify failed.");
235                     }
236                     bar->paddr = id.base;
237                     bar->bits = log2ceil(id.bytes);
238                     bar->bytes = id.bytes * ncaps;
239                 }
240             } else { // IO BAR
241                 bar->io_cap = cap;
242                 err = cap_copy(cap_io, cap);
243                 if(err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
244                     DEBUG_ERR(err, "cap_copy for IO cap");
245                     goto out;
246                 }
247             }
248         }
249     }
250
251     // initialize the device. We have all the caps now
252     PCI_CLIENT_DEBUG("Succesfully done with pci init.\n");
253     init_func(bars, nbars);
254
255     err = SYS_ERR_OK;
256
257  out:
258     return err;
259 }
260
261 errval_t pci_register_driver_irq(pci_driver_init_fn init_func, uint32_t class,
262                                  uint32_t subclass, uint32_t prog_if,
263                                  uint32_t vendor, uint32_t device,
264                                  uint32_t bus, uint32_t dev, uint32_t fun,
265                                  interrupt_handler_fn handler,
266                                  void *handler_arg)
267 {
268      return pci_register_driver_movable_irq(init_func, class, subclass,
269              prog_if, vendor, device, bus, dev, fun, handler, handler_arg,
270              NULL, NULL);
271 }
272
273
274 errval_t pci_register_driver_noirq(pci_driver_init_fn init_func, uint32_t class,
275                                    uint32_t subclass, uint32_t prog_if,
276                                    uint32_t vendor, uint32_t device,
277                                    uint32_t bus, uint32_t dev, uint32_t fun)
278 {
279     return pci_register_driver_irq(init_func, class, subclass, prog_if, vendor,
280                                    device, bus, dev, fun, NULL, NULL);
281 }
282
283 errval_t pci_register_legacy_driver_irq(legacy_driver_init_fn init_func,
284                                         uint16_t iomin, uint16_t iomax, int irq,
285                                         interrupt_handler_fn handler,
286                                         void *handler_arg)
287 {
288     errval_t err, msgerr;
289     struct capref iocap;
290
291     uint64_t vector = INVALID_VECTOR;
292     err = inthandler_setup(handler, handler_arg, &vector);
293     if (err_is_fail(err)) {
294         DEBUG_ERR(err, "inthandler_setup()\n");
295         return err;
296     }
297
298     err = pci_client->vtbl.init_legacy_device(pci_client, iomin, iomax, irq,
299                                               disp_get_core_id(), vector,
300                                               &msgerr, &iocap);
301     if (err_is_fail(err)) {
302         DEBUG_ERR(err, "pci_client->init_legacy_device()\n");
303         return err;
304     } else if (err_is_fail(msgerr)) {
305         DEBUG_ERR(msgerr, "pci_client->init_legacy_device()\n");
306         return msgerr;
307     }
308
309     /* copy IO cap to default location */
310     err = cap_copy(cap_io, iocap);
311     if (err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
312         DEBUG_ERR(err, "failed to copy legacy io cap to default slot\n");
313     }
314
315     err = cap_destroy(iocap);
316     assert(err_is_ok(err));
317
318     /* run init func */
319     init_func();
320
321     return msgerr;
322 }
323
324 errval_t pci_setup_inthandler(interrupt_handler_fn handler, void *handler_arg,
325                                       uint8_t *ret_vector)
326 {
327     errval_t err;
328     uint64_t vector = INVALID_VECTOR;
329     *ret_vector = 0;
330     err = inthandler_setup(handler, handler_arg, &vector);
331     if (err_is_ok(err)) {
332         *ret_vector = vector + 32; // FIXME: HACK
333     }
334     return err;
335 }
336
337 errval_t pci_read_conf_header(uint32_t dword, uint32_t *val)
338 {
339     errval_t err, msgerr;
340     err = pci_client->vtbl.read_conf_header(pci_client, dword, &msgerr, val);
341     return err_is_fail(err) ? err : msgerr;
342 }
343
344 errval_t pci_write_conf_header(uint32_t dword, uint32_t val)
345 {
346     errval_t err, msgerr;
347     err = pci_client->vtbl.write_conf_header(pci_client, dword, val, &msgerr);
348     return err_is_fail(err) ? err : msgerr;
349 }
350
351 errval_t pci_msix_enable_addr(struct pci_address *addr, uint16_t *count)
352 {
353     errval_t err, msgerr;
354     if (addr == NULL) {
355         err = pci_client->vtbl.msix_enable(pci_client, &msgerr, count);
356     } else {
357         err = pci_client->vtbl.msix_enable_addr(pci_client, addr->bus, addr->device,
358                                                 addr->function, &msgerr, count);
359     }
360     return err_is_fail(err) ? err : msgerr;
361 }
362
363 errval_t pci_msix_enable(uint16_t *count)
364 {
365     return pci_msix_enable_addr(NULL, count);
366 }
367
368 errval_t pci_msix_vector_init_addr(struct pci_address *addr, uint16_t idx,
369                                    uint8_t destination, uint8_t vector)
370 {
371     errval_t err, msgerr;
372     if (addr == NULL) {
373         err = pci_client->vtbl.msix_vector_init(pci_client, idx, destination,
374                                                     vector, &msgerr);
375     } else {
376         err = pci_client->vtbl.msix_vector_init_addr(pci_client, addr->bus,
377                                                      addr->device, addr->function,
378                                                      idx, destination,
379                                                      vector, &msgerr);
380     }
381
382     return err_is_fail(err) ? err : msgerr;
383 }
384
385 errval_t pci_msix_vector_init(uint16_t idx, uint8_t destination,
386                               uint8_t vector)
387 {
388     return pci_msix_vector_init_addr(NULL, idx, destination, vector);
389 }
390
391 static void bind_cont(void *st, errval_t err, struct pci_binding *b)
392 {
393     errval_t *reterr = st;
394     if (err_is_ok(err)) {
395         struct pci_rpc_client *r = malloc(sizeof(*r));
396         assert(r != NULL);
397         err = pci_rpc_client_init(r, b);
398         if (err_is_ok(err)) {
399             pci_client = r;
400         } else {
401             free(r);
402         }
403     }
404     *reterr = err;
405 }
406
407 errval_t pci_client_connect(void)
408 {
409     iref_t iref;
410     errval_t err, err2 = SYS_ERR_OK;
411
412     PCI_CLIENT_DEBUG("Connecting to acpi\n");
413     err = connect_to_acpi();
414     if(err_is_fail(err)){
415         return err;
416     }
417     PCI_CLIENT_DEBUG("Connected to ACPI\n");
418
419     /* Connect to the pci server */
420     PCI_CLIENT_DEBUG("Looking up pci iref\n");
421     err = nameservice_blocking_lookup("pci", &iref);
422     if (err_is_fail(err)) {
423         return err;
424     }
425
426     assert(iref != 0);
427
428     PCI_CLIENT_DEBUG("Connecting to pci\n");
429     /* Setup flounder connection with pci server */
430     err = pci_bind(iref, bind_cont, &err2, get_default_waitset(),
431                    IDC_BIND_FLAG_RPC_CAP_TRANSFER);
432     if (err_is_fail(err)) {
433         return err;
434     }
435
436     /* XXX: Wait for connection establishment */
437     while (pci_client == NULL && err2 == SYS_ERR_OK) {
438         messages_wait_and_handle_next();
439     }
440
441     if(err_is_ok(err2)){
442         PCI_CLIENT_DEBUG("PCI connection successful, connecting to int route service\n");
443         err = int_route_client_connect();
444         if(err_is_ok(err)){
445             PCI_CLIENT_DEBUG("Int route service connected.\n");
446         } else {
447             DEBUG_ERR(err, "Could not connect to int route service\n");
448         }
449     }
450     return err2;
451 }