3 * \brief PCI service client-side logic
7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
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.
17 #include <barrelfish/barrelfish.h>
18 #include <barrelfish/nameservice_client.h>
19 #include <barrelfish/dispatch.h>
20 #include <barrelfish/inthandler.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>
30 #define INVALID_VECTOR ((uint64_t)-1)
31 #define INVALID_VECTOR_32 ((uint32_t)-1)
33 static struct pci_rpc_client *pci_client = NULL;
37 * Parse the int_model=
39 static struct int_startup_argument int_arg;
40 static bool int_arg_found = false;
42 errval_t pci_parse_int_arg(int argc, char ** argv) {
44 for(int i=0; i < argc; i++){
45 err = int_startup_argument_parse(argv[i], &int_arg);
51 return SYS_ERR_IRQ_INVALID;
54 errval_t pci_reregister_irq_for_device(uint32_t class, uint32_t subclass, uint32_t prog_if,
55 uint32_t vendor, uint32_t device,
56 uint32_t bus, uint32_t dev, uint32_t fun,
57 interrupt_handler_fn handler,
59 interrupt_handler_fn reloc_handler,
60 void *reloc_handler_arg)
62 uint64_t vector = INVALID_VECTOR;
65 if (handler != NULL && reloc_handler != NULL) {
66 // register movable interrupt
67 err = inthandler_setup_movable(handler, handler_arg, reloc_handler,
68 reloc_handler_arg, &vector);
69 if (err_is_fail(err)) {
73 assert(vector != INVALID_VECTOR);
74 } else if (handler != NULL) {
75 // register non-movable interrupt
76 err = inthandler_setup(handler, handler_arg, &vector);
77 if (err_is_fail(err)) {
81 assert(vector != INVALID_VECTOR);
84 err = pci_client->vtbl.
85 reregister_interrupt(pci_client, class, subclass, prog_if, vendor,
86 device, bus, dev, fun, disp_get_current_core_id(),
88 if (err_is_fail(err)) {
90 } else if (err_is_fail(msgerr)) {
96 static errval_t check_src_capability(struct capref irq_src_cap){
97 struct capability irq_src_cap_data;
99 err = debug_cap_identify(irq_src_cap, &irq_src_cap_data);
100 if(err_is_fail(err)){
101 DEBUG_ERR(err, "Could not identify cap?");
104 if(irq_src_cap_data.type != ObjType_IRQSrc){
105 PCI_CLIENT_DEBUG("First cap argument ist not of type IRQSrc (is=%d)."
106 "Driver not started by kaluga?\n", irq_src_cap_data.type);
107 return SYS_ERR_IRQ_NOT_IRQ_TYPE;
114 * This function does all the interrupt routing setup. It uses the interrupt source
115 * capability passed from kaluga out of the cspace.
116 * It allocates an interrupt destination capability from the monitor.
117 * It sets up a route between these two using the interrupt routing service
118 * It registers the handler passed as an argument as handler for the int destination
120 * Finally, it instructs the PCI service to activate interrupts for this card.
122 static errval_t setup_int_routing(int irq_idx, interrupt_handler_fn handler,
124 interrupt_handler_fn reloc_handler,
125 void *reloc_handler_arg){
126 errval_t err, msgerr;
127 // We use the first passed vector of the device,
128 // for backward compatibility with function interface.
129 struct capref irq_src_cap;
130 irq_src_cap.cnode = build_cnoderef(cap_argcn, CNODE_TYPE_OTHER);
131 irq_src_cap.slot = irq_idx;
133 err = check_src_capability(irq_src_cap);
134 if(err_is_fail(err)){
135 USER_PANIC_ERR(err, "No interrupt capability");
139 // For now, we just use the first vector passed to the driver.
140 uint64_t gsi = INVALID_VECTOR;
141 err = invoke_irqsrc_get_vec_start(irq_src_cap, &gsi);
142 if (err_is_fail(err)) {
143 DEBUG_ERR(err, "Could not lookup GSI vector");
146 PCI_CLIENT_DEBUG("Got irqsrc cap, gsi: %"PRIu64"\n", gsi);
148 // Get irq_dest_cap from monitor
149 struct capref irq_dest_cap;
150 err = alloc_dest_irq_cap(&irq_dest_cap);
151 if(err_is_fail(err)){
152 DEBUG_ERR(err, "Could not allocate dest irq cap");
155 uint64_t irq_dest_vec = INVALID_VECTOR;
156 err = invoke_irqdest_get_vector(irq_dest_cap, &irq_dest_vec);
157 if (err_is_fail(err)) {
158 DEBUG_ERR(err, "Could not lookup irq vector");
161 PCI_CLIENT_DEBUG("Got dest cap, vector: %"PRIu64"\n", irq_dest_vec);
164 err = int_route_client_route(irq_src_cap, irq_dest_cap);
165 if(err_is_fail(err)){
166 DEBUG_ERR(err, "Could not set up route.");
169 PCI_CLIENT_DEBUG("Int route set-up success.\n");
173 err = inthandler_setup_movable_cap(irq_dest_cap, handler, handler_arg,
174 reloc_handler, reloc_handler_arg);
175 if (err_is_fail(err)) {
180 // Activate PCI interrupt
181 err = pci_client->vtbl.irq_enable(pci_client, &msgerr);
182 assert(err_is_ok(err));
183 if(err_is_fail(msgerr)){
184 DEBUG_ERR(msgerr, "irq_enable");
190 errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, uint32_t class,
191 uint32_t subclass, uint32_t prog_if,
192 uint32_t vendor, uint32_t device,
193 uint32_t bus, uint32_t dev, uint32_t fun,
194 interrupt_handler_fn handler,
196 interrupt_handler_fn reloc_handler,
197 void *reloc_handler_arg)
199 pci_caps_per_bar_t caps_per_bar;
201 errval_t err, msgerr;
203 err = pci_client->vtbl.
204 init_pci_device(pci_client, class, subclass, prog_if, vendor,
205 device, bus, dev, fun, &msgerr,
206 &nbars, caps_per_bar, caps_per_bar + 1, caps_per_bar + 2,
207 caps_per_bar + 3, caps_per_bar + 4, caps_per_bar + 5);
209 if (err_is_fail(err)) {
210 PCI_CLIENT_DEBUG("init pci device failed.\n");
212 } else if (err_is_fail(msgerr)) {
216 assert(nbars > 0); // otherwise we should have received an error!
218 // Set-up int routing.
219 PCI_CLIENT_DEBUG("Calling setup_int_routing\n");
220 if (!(handler == NULL)) {
221 err = setup_int_routing(0, handler, handler_arg, reloc_handler, reloc_handler_arg);
222 if(err_is_fail(err)){
223 DEBUG_ERR(err, "Could not set up int routing. Continuing w/o interrupts");
228 struct device_mem *bars = calloc(nbars, sizeof(struct device_mem));
229 assert(bars != NULL);
231 // request caps for all bars of device
232 for (int nb = 0; nb < nbars; nb++) {
233 struct device_mem *bar = &bars[nb];
235 int ncaps = (caps_per_bar)[nb];
237 bar->nr_caps = ncaps;
238 bar->frame_cap = malloc(ncaps * sizeof(struct capref)); // FIXME: leak
239 assert(bar->frame_cap != NULL);
242 for (int nc = 0; nc < ncaps; nc++) {
246 err = slot_alloc(&cap);
247 assert(err_is_ok(err));
248 err = pci_client->vtbl.get_bar_cap(pci_client, nb, nc, &msgerr, &cap,
249 &type, &bar->bar_nr);
250 if (err_is_fail(err) || err_is_fail(msgerr)) {
251 if (err_is_ok(err)) {
254 DEBUG_ERR(err, "requesting cap %d for BAR %d of device", nc, nb);
258 if (type == 0) { // Frame cap BAR
259 bar->frame_cap[nc] = cap;
261 struct frame_identity id = { .base = 0, .bytes = 0 };
262 err = frame_identify(cap, &id);
263 if (err_is_fail(err)) {
264 USER_PANIC_ERR(err, "frame identify failed.");
266 bar->paddr = id.base;
267 bar->bits = log2ceil(id.bytes);
268 bar->bytes = id.bytes * ncaps;
272 err = cap_copy(cap_io, cap);
273 if(err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
274 DEBUG_ERR(err, "cap_copy for IO cap");
281 // initialize the device. We have all the caps now
282 PCI_CLIENT_DEBUG("Succesfully done with pci init.\n");
283 init_func(bars, nbars);
291 errval_t pci_register_driver_irq(pci_driver_init_fn init_func, uint32_t class,
292 uint32_t subclass, uint32_t prog_if,
293 uint32_t vendor, uint32_t device,
294 uint32_t bus, uint32_t dev, uint32_t fun,
295 interrupt_handler_fn handler,
298 return pci_register_driver_movable_irq(init_func, class, subclass,
299 prog_if, vendor, device, bus, dev, fun, handler, handler_arg,
304 errval_t pci_register_driver_noirq(pci_driver_init_fn init_func, uint32_t class,
305 uint32_t subclass, uint32_t prog_if,
306 uint32_t vendor, uint32_t device,
307 uint32_t bus, uint32_t dev, uint32_t fun)
309 return pci_register_driver_irq(init_func, class, subclass, prog_if, vendor,
310 device, bus, dev, fun, NULL, NULL);
313 errval_t pci_register_legacy_driver_irq_cap(legacy_driver_init_fn init_func,
314 uint16_t iomin, uint16_t iomax, int irq_cap_idx,
315 interrupt_handler_fn handler,
317 errval_t err, msgerr;
319 // Connect to PCI without interrupts
320 err = slot_alloc(&iocap);
321 assert(err_is_ok(err));
322 err = pci_client->vtbl.init_legacy_device(pci_client, iomin, iomax, 0,
323 disp_get_core_id(), INVALID_VECTOR_32,
325 if (err_is_fail(err)) {
326 DEBUG_ERR(err, "pci_client->init_legacy_device()\n");
328 } else if (err_is_fail(msgerr)) {
329 DEBUG_ERR(msgerr, "pci_client->init_legacy_device()\n");
333 /* copy IO cap to default location */
334 err = cap_copy(cap_io, iocap);
335 if (err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
336 DEBUG_ERR(err, "failed to copy legacy io cap to default slot\n");
340 err = cap_destroy(iocap);
341 assert(err_is_ok(err));
344 err = setup_int_routing(irq_cap_idx, handler, handler_arg, NULL, NULL);
345 if(err_is_fail(err)){
346 DEBUG_ERR(err, "Could not set up int routing. Continuing w/o interrupts");
348 PCI_CLIENT_DEBUG("setup_int_routing successful.\n");
357 errval_t pci_register_legacy_driver_irq(legacy_driver_init_fn init_func,
358 uint16_t iomin, uint16_t iomax, int irq,
359 interrupt_handler_fn handler,
362 errval_t err, msgerr;
365 debug_printf("WARNING: pci_register_legacy_driver_irq is deprecated."
366 "Make sure driver is started by Kaluga and use"
367 "pci_register_legacy_driver_irq_cap.\n");
369 uint64_t vector = INVALID_VECTOR;
370 err = inthandler_setup(handler, handler_arg, &vector);
371 if (err_is_fail(err)) {
372 DEBUG_ERR(err, "inthandler_setup()\n");
376 err = slot_alloc(&iocap);
377 assert(err_is_ok(err));
378 err = pci_client->vtbl.init_legacy_device(pci_client, iomin, iomax, irq,
379 disp_get_core_id(), vector,
381 if (err_is_fail(err)) {
382 DEBUG_ERR(err, "pci_client->init_legacy_device()\n");
384 } else if (err_is_fail(msgerr)) {
385 DEBUG_ERR(msgerr, "pci_client->init_legacy_device()\n");
389 /* copy IO cap to default location */
390 err = cap_copy(cap_io, iocap);
391 if (err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) {
392 DEBUG_ERR(err, "failed to copy legacy io cap to default slot\n");
395 err = cap_destroy(iocap);
396 assert(err_is_ok(err));
404 errval_t pci_setup_inthandler(interrupt_handler_fn handler, void *handler_arg,
408 uint64_t vector = INVALID_VECTOR;
410 err = inthandler_setup(handler, handler_arg, &vector);
411 if (err_is_ok(err)) {
412 *ret_vector = vector + 32; // FIXME: HACK
417 errval_t pci_read_conf_header(uint32_t dword, uint32_t *val)
419 errval_t err, msgerr;
420 err = pci_client->vtbl.read_conf_header(pci_client, dword, &msgerr, val);
421 return err_is_fail(err) ? err : msgerr;
424 errval_t pci_write_conf_header(uint32_t dword, uint32_t val)
426 errval_t err, msgerr;
427 err = pci_client->vtbl.write_conf_header(pci_client, dword, val, &msgerr);
428 return err_is_fail(err) ? err : msgerr;
431 errval_t pci_msix_enable_addr(struct pci_address *addr, uint16_t *count)
433 errval_t err, msgerr;
435 err = pci_client->vtbl.msix_enable(pci_client, &msgerr, count);
437 err = pci_client->vtbl.msix_enable_addr(pci_client, addr->bus, addr->device,
438 addr->function, &msgerr, count);
440 return err_is_fail(err) ? err : msgerr;
443 errval_t pci_msix_enable(uint16_t *count)
445 return pci_msix_enable_addr(NULL, count);
448 errval_t pci_msix_vector_init_addr(struct pci_address *addr, uint16_t idx,
449 uint8_t destination, uint8_t vector)
451 errval_t err, msgerr;
453 err = pci_client->vtbl.msix_vector_init(pci_client, idx, destination,
456 err = pci_client->vtbl.msix_vector_init_addr(pci_client, addr->bus,
457 addr->device, addr->function,
462 return err_is_fail(err) ? err : msgerr;
465 errval_t pci_msix_vector_init(uint16_t idx, uint8_t destination,
468 return pci_msix_vector_init_addr(NULL, idx, destination, vector);
471 static void bind_cont(void *st, errval_t err, struct pci_binding *b)
473 errval_t *reterr = st;
474 if (err_is_ok(err)) {
475 struct pci_rpc_client *r = malloc(sizeof(*r));
477 err = pci_rpc_client_init(r, b);
478 if (err_is_ok(err)) {
487 errval_t pci_client_connect(void)
490 errval_t err, err2 = SYS_ERR_OK;
492 PCI_CLIENT_DEBUG("Connecting to acpi\n");
493 err = connect_to_acpi();
494 if(err_is_fail(err)){
497 PCI_CLIENT_DEBUG("Connected to ACPI\n");
499 /* Connect to the pci server */
500 PCI_CLIENT_DEBUG("Looking up pci iref\n");
501 err = nameservice_blocking_lookup("pci", &iref);
502 if (err_is_fail(err)) {
508 PCI_CLIENT_DEBUG("Connecting to pci\n");
509 /* Setup flounder connection with pci server */
510 err = pci_bind(iref, bind_cont, &err2, get_default_waitset(),
511 IDC_BIND_FLAG_RPC_CAP_TRANSFER);
512 if (err_is_fail(err)) {
516 /* XXX: Wait for connection establishment */
517 while (pci_client == NULL && err2 == SYS_ERR_OK) {
518 messages_wait_and_handle_next();
522 PCI_CLIENT_DEBUG("PCI connection successful, connecting to int route service\n");
523 err = int_route_client_connect();
525 PCI_CLIENT_DEBUG("Int route service connected.\n");
527 DEBUG_ERR(err, "Could not connect to int route service\n");