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