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