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