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/acpi_defs.h> 25#include <acpi_client/acpi_client.h> 26#include <int_route/int_model.h> 27#include <int_route/int_route_client.h> 28 29#define INVALID_VECTOR ((uint64_t)-1) 30#define INVALID_VECTOR_32 ((uint32_t)-1) 31 32static struct pci_binding *pci_client = NULL; 33 34 35/* 36 * Parse the int_model= 37 */ 38static struct int_startup_argument int_arg; 39static bool int_arg_found = false; 40 41errval_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 53errval_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->rpc_tx_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 95static errval_t check_src_capability(struct capref irq_src_cap){ 96 struct capability irq_src_cap_data; 97 errval_t err; 98 err = debug_cap_identify(irq_src_cap, &irq_src_cap_data); 99 if(err_is_fail(err)){ 100 DEBUG_ERR(err, "Could not identify cap?"); 101 return err; 102 } 103 if(irq_src_cap_data.type != ObjType_IRQSrc){ 104 PCI_CLIENT_DEBUG("First cap argument ist not of type IRQSrc (is=%d)." 105 "Driver not started by kaluga?\n", irq_src_cap_data.type); 106 return SYS_ERR_IRQ_NOT_IRQ_TYPE; 107 } 108 return SYS_ERR_OK; 109} 110 111/** 112 * This function does all the interrupt routing setup. It uses the interrupt source 113 * capability passed from kaluga out of the cspace. 114 * The source capability contains a range of vectors, irq_idx is an offset into 115 * this range, making it convenient for the clients, as they don't have 116 * to care about the absolute value, but get their local view on interrupt numbers. 117 * It allocates an interrupt destination capability from the monitor. 118 * It sets up a route between these two using the interrupt routing service 119 * It registers the handler passed as an argument as handler for the int destination 120 * capability. 121 * Finally, it instructs the PCI service to activate interrupts for this card. 122 */ 123errval_t pci_setup_int_routing(int irq_idx, interrupt_handler_fn handler, 124 void *handler_arg, 125 interrupt_handler_fn reloc_handler, 126 void *reloc_handler_arg){ 127 struct capref irq_src_cap; 128 irq_src_cap.cnode = build_cnoderef(cap_argcn, CNODE_TYPE_OTHER); 129 irq_src_cap.slot = PCIARG_SLOT_INT; 130 131 return pci_setup_int_routing_with_cap(irq_idx, irq_src_cap, handler, 132 handler_arg, reloc_handler, reloc_handler_arg); 133} 134 135 136/** 137 * This function does all the interrupt routing setup. It uses the interrupt source 138 * capability passed from kaluga out of the cspace. 139 * The source capability contains a range of vectors, irq_idx is an offset into 140 * this range, making it convenient for the clients, as they don't have 141 * to care about the absolute value, but get their local view on interrupt numbers. 142 * It allocates an interrupt destination capability from the monitor. 143 * It sets up a route between these two using the interrupt routing service 144 * It registers the handler passed as an argument as handler for the int destination 145 * capability. 146 * Finally, it instructs the PCI service to activate interrupts for this card. 147 */ 148errval_t pci_setup_int_routing_with_cap(int irq_idx, 149 struct capref irq_src_cap, 150 interrupt_handler_fn handler, 151 void *handler_arg, 152 interrupt_handler_fn reloc_handler, 153 void *reloc_handler_arg){ 154 155 errval_t err; 156 errval_t msgerr; 157 err = check_src_capability(irq_src_cap); 158 if(err_is_fail(err)){ 159 USER_PANIC_ERR(err, "No interrupt capability"); 160 return err; 161 } 162 163 // For now, we just use the first vector passed to the driver. 164 uint64_t gsi = INVALID_VECTOR; 165 err = invoke_irqsrc_get_vec_start(irq_src_cap, &gsi); 166 if (err_is_fail(err)) { 167 DEBUG_ERR(err, "Could not lookup GSI vector"); 168 return err; 169 } 170 PCI_CLIENT_DEBUG("Got irqsrc cap, gsi: %"PRIu64"\n", gsi); 171 172 // Get irq_dest_cap from monitor 173 struct capref irq_dest_cap; 174 err = alloc_dest_irq_cap(&irq_dest_cap); 175 if(err_is_fail(err)){ 176 DEBUG_ERR(err, "Could not allocate dest irq cap"); 177 return err; 178 } 179 uint64_t irq_dest_vec = INVALID_VECTOR; 180 err = invoke_irqdest_get_vector(irq_dest_cap, &irq_dest_vec); 181 if (err_is_fail(err)) { 182 DEBUG_ERR(err, "Could not lookup irq vector"); 183 return err; 184 } 185 PCI_CLIENT_DEBUG("Got dest cap, vector: %"PRIu64"\n", irq_dest_vec); 186 187 188 err = int_route_client_route(irq_src_cap, irq_idx, irq_dest_cap); 189 if(err_is_fail(err)){ 190 DEBUG_ERR(err, "Could not set up route."); 191 return err; 192 } else { 193 PCI_CLIENT_DEBUG("Int route set-up success.\n"); 194 } 195 196 if(handler != NULL){ 197 err = inthandler_setup_movable_cap(irq_dest_cap, handler, handler_arg, 198 reloc_handler, reloc_handler_arg); 199 if (err_is_fail(err)) { 200 return err; 201 } 202 } 203 204 // Activate PCI interrupt 205 err = pci_client->rpc_tx_vtbl.irq_enable(pci_client, &msgerr); 206 assert(err_is_ok(err)); 207 if(err_is_fail(msgerr)){ 208 DEBUG_ERR(msgerr, "irq_enable"); 209 return msgerr; 210 } 211 return err; 212} 213 214 215/** 216 * This function is used by kaluga to retrieve the caps for the specified 217 * device. This function will malloc bars and store it in bars_out & bars_len. 218 * addr is not allowed to contain dont cares 219 */ 220errval_t pci_get_bar_caps_for_device( 221 struct pci_addr addr, 222 struct device_mem **bars_out, 223 size_t *bars_len) 224{ 225 assert(addr.bus != PCI_DONT_CARE); 226 assert(addr.device != PCI_DONT_CARE); 227 assert(addr.function != PCI_DONT_CARE); 228 assert(bars_out); 229 assert(bars_len); 230 231 uint8_t nbars = 0; 232 errval_t err, msgerr; 233 234 err = pci_client->rpc_tx_vtbl. 235 init_pci_device(pci_client, 236 PCI_DONT_CARE, PCI_DONT_CARE, PCI_DONT_CARE, 237 PCI_DONT_CARE, PCI_DONT_CARE, 238 addr.bus, addr.device, addr.function, &msgerr, 239 &nbars); 240 241 if (err_is_fail(err)) { 242 PCI_CLIENT_DEBUG("init pci device failed.\n"); 243 return err; 244 } else if (err_is_fail(msgerr)) { 245 PCI_CLIENT_DEBUG("init pci device failed.\n"); 246 return msgerr; 247 } 248 assert(nbars > 0); // otherwise we should have received an error! 249 250 struct device_mem *bars = calloc(nbars, sizeof(struct device_mem)); 251 assert(bars != NULL); 252 253 // request caps for all bars of device 254 for (int nb = 0; nb < nbars; nb++) { 255 struct device_mem *bar = &bars[nb]; 256 257 struct capref cap; 258 uint8_t type; 259 260 err = slot_alloc(&cap); 261 assert(err_is_ok(err)); 262 err = pci_client->rpc_tx_vtbl.get_bar_cap(pci_client, nb, &msgerr, &cap, 263 &type, &bar->bar_nr); 264 if (err_is_fail(err) || err_is_fail(msgerr)) { 265 if (err_is_ok(err)) { 266 err = msgerr; 267 } 268 DEBUG_ERR(err, "requesting cap for BAR %d of device", nb); 269 goto err_out; 270 } 271 272 if (type == 0) { // Frame cap BAR 273 bar->frame_cap = cap; 274 275 struct frame_identity fid = { .base = 0, .bytes = 0 }; 276 err = frame_identify(cap, &fid); 277 if (err_is_fail(err)) { 278 USER_PANIC_ERR(err, "frame identify failed."); 279 } 280 bar->paddr = fid.base; 281 bar->bits = log2ceil(fid.bytes); 282 bar->bytes = fid.bytes; 283 } else { // IO BAR 284 bar->io_cap = cap; 285 err = cap_copy(cap_io, cap); 286 if(err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) { 287 DEBUG_ERR(err, "cap_copy for IO cap"); 288 goto err_out; 289 } 290 } 291 } 292 293 // initialize the device. We have all the caps now 294 PCI_CLIENT_DEBUG("Succesfully done with pci init.\n"); 295 *bars_out = bars; 296 *bars_len = nbars; 297 return SYS_ERR_OK; 298 299 err_out: 300 free(bars); 301 return err; 302} 303 304errval_t pci_register_driver_movable_irq(pci_driver_init_fn init_func, 305 void *user_state, uint32_t class, 306 uint32_t subclass, uint32_t prog_if, 307 uint32_t vendor, uint32_t device, 308 uint32_t bus, uint32_t dev, uint32_t fun, 309 interrupt_handler_fn handler, 310 void *handler_arg, 311 interrupt_handler_fn reloc_handler, 312 void *reloc_handler_arg) 313{ 314 uint8_t nbars; 315 errval_t err, msgerr; 316 317 err = pci_client->rpc_tx_vtbl. 318 init_pci_device(pci_client, class, subclass, prog_if, vendor, 319 device, bus, dev, fun, &msgerr, 320 &nbars); 321 322 if (err_is_fail(err)) { 323 PCI_CLIENT_DEBUG("init pci device failed.\n"); 324 return err; 325 } else if (err_is_fail(msgerr)) { 326 return msgerr; 327 } 328 assert(nbars > 0); // otherwise we should have received an error! 329 330 // Set-up int routing. 331 // We use the first passed vector of the device, 332 // for backward compatibility with function interface. 333 if (handler != NULL) { 334 PCI_CLIENT_DEBUG("Calling pci_setup_int_routing\n"); 335 err = pci_setup_int_routing(0, handler, handler_arg, reloc_handler, reloc_handler_arg); 336 if(err_is_fail(err)){ 337 DEBUG_ERR(err, "Could not set up int routing. Continuing w/o interrupts"); 338 } 339 } 340 341 // FIXME: leak 342 struct device_mem *bars = calloc(nbars, sizeof(struct device_mem)); 343 assert(bars != NULL); 344 345 // request caps for all bars of device 346 for (int nb = 0; nb < nbars; nb++) { 347 struct device_mem *bar = &bars[nb]; 348 349 struct capref cap; 350 uint8_t type; 351 352 err = slot_alloc(&cap); 353 assert(err_is_ok(err)); 354 err = pci_client->rpc_tx_vtbl.get_bar_cap(pci_client, nb, &msgerr, &cap, 355 &type, &bar->bar_nr); 356 if (err_is_fail(err) || err_is_fail(msgerr)) { 357 if (err_is_ok(err)) { 358 err = msgerr; 359 } 360 DEBUG_ERR(err, "requesting cap for BAR %d of device", nb); 361 return err; 362 } 363 364 if (type == 0) { // Frame cap BAR 365 bar->frame_cap = cap; 366 struct frame_identity id = { .base = 0, .bytes = 0 }; 367 err = frame_identify(cap, &id); 368 if (err_is_fail(err)) { 369 USER_PANIC_ERR(err, "frame identify failed."); 370 } 371 bar->paddr = id.base; 372 bar->bits = log2ceil(id.bytes); 373 bar->bytes = id.bytes; 374 } else { // IO BAR 375 bar->io_cap = cap; 376 err = cap_copy(cap_io, cap); 377 if(err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) { 378 DEBUG_ERR(err, "cap_copy for IO cap"); 379 return err; 380 } 381 } 382 } 383 384 // initialize the device. We have all the caps now 385 PCI_CLIENT_DEBUG("Succesfully done with pci init.\n"); 386 if(init_func) init_func(user_state, bars, nbars); 387 388 return SYS_ERR_OK; 389} 390 391errval_t pci_register_driver_irq(pci_driver_init_fn init_func, 392 void *user_state, uint32_t class, 393 uint32_t subclass, uint32_t prog_if, 394 uint32_t vendor, uint32_t device, 395 uint32_t bus, uint32_t dev, uint32_t fun, 396 interrupt_handler_fn handler, 397 void *handler_arg) 398{ 399 return pci_register_driver_movable_irq(init_func, user_state, class, subclass, 400 prog_if, vendor, device, bus, dev, fun, handler, handler_arg, 401 NULL, NULL); 402} 403 404 405errval_t pci_register_driver_noirq(pci_driver_init_fn init_func, 406 void *user_state, uint32_t class, 407 uint32_t subclass, uint32_t prog_if, 408 uint32_t vendor, uint32_t device, 409 uint32_t bus, uint32_t dev, uint32_t fun) 410{ 411 return pci_register_driver_irq(init_func, user_state, class, subclass, 412 prog_if, vendor, device, bus, dev, fun, NULL, 413 NULL); 414} 415 416errval_t pci_register_legacy_driver_irq_cap(legacy_driver_init_fn init_func, 417 uint16_t iomin, uint16_t iomax, int irq_cap_idx, 418 interrupt_handler_fn handler, 419 void *handler_arg) { 420 errval_t err, msgerr; 421 struct capref iocap; 422 // Connect to PCI without interrupts 423 err = slot_alloc(&iocap); 424 assert(err_is_ok(err)); 425 err = pci_client->rpc_tx_vtbl.init_legacy_device(pci_client, iomin, iomax, 0, 426 disp_get_core_id(), INVALID_VECTOR_32, 427 &msgerr, &iocap); 428 if (err_is_fail(err)) { 429 DEBUG_ERR(err, "pci_client->init_legacy_device()\n"); 430 return err; 431 } else if (err_is_fail(msgerr)) { 432 DEBUG_ERR(msgerr, "pci_client->init_legacy_device()\n"); 433 return msgerr; 434 } 435 436 /* copy IO cap to default location */ 437 err = cap_copy(cap_io, iocap); 438 if (err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) { 439 DEBUG_ERR(err, "failed to copy legacy io cap to default slot\n"); 440 return err; 441 } 442 443 err = cap_destroy(iocap); 444 assert(err_is_ok(err)); 445 446 // Setup int routing 447 err = pci_setup_int_routing(irq_cap_idx, handler, handler_arg, NULL, NULL); 448 if(err_is_fail(err)){ 449 DEBUG_ERR(err, "Could not set up int routing. Continuing w/o interrupts"); 450 } else { 451 PCI_CLIENT_DEBUG("pci_setup_int_routing successful.\n"); 452 } 453 454 // Run init function 455 init_func(); 456 457 return SYS_ERR_OK; 458} 459 460errval_t pci_register_legacy_driver_irq(legacy_driver_init_fn init_func, 461 uint16_t iomin, uint16_t iomax, int irq, 462 interrupt_handler_fn handler, 463 void *handler_arg) 464{ 465 errval_t err, msgerr; 466 struct capref iocap; 467 468 debug_printf("WARNING: pci_register_legacy_driver_irq is deprecated." 469 "Make sure driver is started by Kaluga and use" 470 "pci_register_legacy_driver_irq_cap.\n"); 471 472 uint64_t vector = INVALID_VECTOR; 473 err = inthandler_setup(handler, handler_arg, &vector); 474 if (err_is_fail(err)) { 475 DEBUG_ERR(err, "inthandler_setup()\n"); 476 return err; 477 } 478 479 err = slot_alloc(&iocap); 480 assert(err_is_ok(err)); 481 err = pci_client->rpc_tx_vtbl.init_legacy_device(pci_client, iomin, iomax, irq, 482 disp_get_core_id(), vector, 483 &msgerr, &iocap); 484 if (err_is_fail(err)) { 485 DEBUG_ERR(err, "pci_client->init_legacy_device()\n"); 486 return err; 487 } else if (err_is_fail(msgerr)) { 488 DEBUG_ERR(msgerr, "pci_client->init_legacy_device()\n"); 489 return msgerr; 490 } 491 492 /* copy IO cap to default location */ 493 err = cap_copy(cap_io, iocap); 494 if (err_is_fail(err) && err_no(err) != SYS_ERR_SLOT_IN_USE) { 495 DEBUG_ERR(err, "failed to copy legacy io cap to default slot\n"); 496 } 497 498 err = cap_destroy(iocap); 499 assert(err_is_ok(err)); 500 501 /* run init func */ 502 init_func(); 503 504 return msgerr; 505} 506 507errval_t pci_setup_inthandler(interrupt_handler_fn handler, void *handler_arg, 508 uint8_t *ret_vector) 509{ 510 errval_t err; 511 uint64_t vector = INVALID_VECTOR; 512 *ret_vector = 0; 513 err = inthandler_setup(handler, handler_arg, &vector); 514 if (err_is_ok(err)) { 515 *ret_vector = vector + 32; // FIXME: HACK 516 } 517 return err; 518} 519 520errval_t pci_read_conf_header(uint32_t dword, uint32_t *val) 521{ 522 errval_t err, msgerr; 523 err = pci_client->rpc_tx_vtbl.read_conf_header(pci_client, dword, &msgerr, val); 524 return err_is_fail(err) ? err : msgerr; 525} 526 527errval_t pci_write_conf_header(uint32_t dword, uint32_t val) 528{ 529 errval_t err, msgerr; 530 err = pci_client->rpc_tx_vtbl.write_conf_header(pci_client, dword, val, &msgerr); 531 return err_is_fail(err) ? err : msgerr; 532} 533 534errval_t pci_msix_enable_addr(struct pci_addr *addr, uint16_t *count) 535{ 536 errval_t err, msgerr; 537 if (addr == NULL) { 538 err = pci_client->rpc_tx_vtbl.msix_enable(pci_client, &msgerr, count); 539 } else { 540 err = pci_client->rpc_tx_vtbl.msix_enable_addr(pci_client, addr->bus, addr->device, 541 addr->function, &msgerr, count); 542 } 543 return err_is_fail(err) ? err : msgerr; 544} 545 546errval_t pci_msix_enable(uint16_t *count) 547{ 548 return pci_msix_enable_addr(NULL, count); 549} 550 551errval_t pci_msix_vector_init_addr(struct pci_addr *addr, uint16_t idx, 552 uint8_t destination, uint8_t vector) 553{ 554 errval_t err, msgerr; 555 if (addr == NULL) { 556 err = pci_client->rpc_tx_vtbl.msix_vector_init(pci_client, idx, destination, 557 vector, &msgerr); 558 } else { 559 err = pci_client->rpc_tx_vtbl.msix_vector_init_addr(pci_client, addr->bus, 560 addr->device, addr->function, 561 idx, destination, 562 vector, &msgerr); 563 } 564 565 return err_is_fail(err) ? err : msgerr; 566} 567 568errval_t pci_msix_vector_init(uint16_t idx, uint8_t destination, 569 uint8_t vector) 570{ 571 return pci_msix_vector_init_addr(NULL, idx, destination, vector); 572} 573 574static void bind_cont(void *st, errval_t err, struct pci_binding *b) 575{ 576 errval_t *reterr = st; 577 if (err_is_ok(err)) { 578 pci_rpc_client_init(b); 579 pci_client = b; 580 } 581 *reterr = err; 582} 583 584errval_t pci_client_connect(void) 585{ 586 iref_t iref; 587 errval_t err, err2 = SYS_ERR_OK; 588 589 PCI_CLIENT_DEBUG("Connecting to acpi\n"); 590 err = connect_to_acpi(); 591 if(err_is_fail(err)){ 592 return err; 593 } 594 PCI_CLIENT_DEBUG("Connected to ACPI\n"); 595 596 /* Connect to the pci server */ 597 PCI_CLIENT_DEBUG("Looking up pci iref\n"); 598 err = nameservice_blocking_lookup("pci", &iref); 599 if (err_is_fail(err)) { 600 return err; 601 } 602 603 assert(iref != 0); 604 605 PCI_CLIENT_DEBUG("Connecting to pci\n"); 606 /* Setup flounder connection with pci server */ 607 err = pci_bind(iref, bind_cont, &err2, get_default_waitset(), 608 IDC_BIND_FLAG_RPC_CAP_TRANSFER); 609 if (err_is_fail(err)) { 610 return err; 611 } 612 613 /* XXX: Wait for connection establishment */ 614 while (pci_client == NULL && err2 == SYS_ERR_OK) { 615 messages_wait_and_handle_next(); 616 } 617 618 if(err_is_ok(err2)){ 619 PCI_CLIENT_DEBUG("PCI connection successful, connecting to int route service\n"); 620 err = int_route_client_connect(); 621 if(err_is_ok(err)){ 622 PCI_CLIENT_DEBUG("Int route service connected.\n"); 623 } else { 624 DEBUG_ERR(err, "Could not connect to int route service\n"); 625 } 626 } 627 return err2; 628} 629