Changeset 68414f4a in mainline for uspace/drv/pciintel/pci.c
- Timestamp:
- 2011-02-13T20:03:45Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- bab6388
- Parents:
- 8b1e15ac
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/pciintel/pci.c
r8b1e15ac r68414f4a 1 1 /* 2 2 * Copyright (c) 2010 Lenka Trochtova 3 * Copyright (c) 2011 Jiri Svoboda 3 4 * All rights reserved. 4 5 * … … 61 62 ((1 << 31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) 62 63 63 static hw_resource_list_t *pciintel_get_child_resources(function_t *fun) 64 { 65 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 66 67 if (fun_data == NULL) 64 /** Obtain PCI function soft-state from DDF function node */ 65 #define PCI_FUN(fnode) ((pci_fun_t *) (fnode)->driver_data) 66 67 /** Obtain PCI bus soft-state from DDF device node */ 68 #define PCI_BUS(dnode) ((pci_bus_t *) (dnode)->driver_data) 69 70 /** Obtain PCI bus soft-state from function soft-state */ 71 #define PCI_BUS_FROM_FUN(fun) (PCI_BUS(fun->fnode->dev)) 72 73 static hw_resource_list_t *pciintel_get_resources(function_t *fnode) 74 { 75 pci_fun_t *fun = PCI_FUN(fnode); 76 77 if (fun == NULL) 68 78 return NULL; 69 return &fun _data->hw_resources;70 } 71 72 static bool pciintel_enable_ child_interrupt(function_t *fun)79 return &fun->hw_resources; 80 } 81 82 static bool pciintel_enable_interrupt(function_t *fnode) 73 83 { 74 84 /* TODO */ … … 77 87 } 78 88 79 static hw_res_ops_t pciintel_ child_hw_res_ops = {80 &pciintel_get_ child_resources,81 &pciintel_enable_ child_interrupt89 static hw_res_ops_t pciintel_hw_res_ops = { 90 &pciintel_get_resources, 91 &pciintel_enable_interrupt 82 92 }; 83 93 84 static device_ops_t pci_ child_ops;94 static device_ops_t pci_fun_ops; 85 95 86 96 static int pci_add_device(device_t *); 87 97 88 /** The pci bus driver's standard operations.*/98 /** PCI bus driver standard operations */ 89 99 static driver_ops_t pci_ops = { 90 100 .add_device = &pci_add_device 91 101 }; 92 102 93 /** The pci bus driver structure.*/103 /** PCI bus driver structure */ 94 104 static driver_t pci_driver = { 95 105 .name = NAME, … … 97 107 }; 98 108 99 typedef struct pciintel_bus_data { 100 uint32_t conf_io_addr; 101 void *conf_data_port; 102 void *conf_addr_port; 103 fibril_mutex_t conf_mutex; 104 } pci_bus_data_t; 105 106 static pci_bus_data_t *create_pci_bus_data(void) 107 { 108 pci_bus_data_t *bus_data; 109 110 bus_data = (pci_bus_data_t *) malloc(sizeof(pci_bus_data_t)); 111 if (bus_data != NULL) { 112 memset(bus_data, 0, sizeof(pci_bus_data_t)); 113 fibril_mutex_initialize(&bus_data->conf_mutex); 114 } 115 116 return bus_data; 117 } 118 119 static void delete_pci_bus_data(pci_bus_data_t *bus_data) 120 { 121 free(bus_data); 122 } 123 124 static void pci_conf_read(function_t *fun, int reg, uint8_t *buf, size_t len) 125 { 126 assert(fun->dev != NULL); 127 128 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 129 pci_bus_data_t *bus_data = (pci_bus_data_t *) fun->dev->driver_data; 130 131 fibril_mutex_lock(&bus_data->conf_mutex); 109 static pci_bus_t *pci_bus_new(void) 110 { 111 pci_bus_t *bus; 112 113 bus = (pci_bus_t *) malloc(sizeof(pci_bus_t)); 114 if (bus != NULL) { 115 memset(bus, 0, sizeof(pci_bus_t)); 116 fibril_mutex_initialize(&bus->conf_mutex); 117 } 118 119 return bus; 120 } 121 122 static void pci_bus_delete(pci_bus_t *bus) 123 { 124 free(bus); 125 } 126 127 static void pci_conf_read(pci_fun_t *fun, int reg, uint8_t *buf, size_t len) 128 { 129 pci_bus_t *bus = PCI_BUS_FROM_FUN(fun); 130 131 fibril_mutex_lock(&bus->conf_mutex); 132 132 133 133 uint32_t conf_addr; 134 conf_addr = CONF_ADDR(fun _data->bus, fun_data->dev, fun_data->fn, reg);135 void *addr = bus _data->conf_data_port + (reg & 3);136 137 pio_write_32(bus _data->conf_addr_port, conf_addr);134 conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg); 135 void *addr = bus->conf_data_port + (reg & 3); 136 137 pio_write_32(bus->conf_addr_port, conf_addr); 138 138 139 139 switch (len) { … … 149 149 } 150 150 151 fibril_mutex_unlock(&bus_data->conf_mutex); 152 } 153 154 static void pci_conf_write(function_t *fun, int reg, uint8_t *buf, size_t len) 155 { 156 assert(fun->dev != NULL); 157 158 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 159 pci_bus_data_t *bus_data = (pci_bus_data_t *) fun->dev->driver_data; 160 161 fibril_mutex_lock(&bus_data->conf_mutex); 151 fibril_mutex_unlock(&bus->conf_mutex); 152 } 153 154 static void pci_conf_write(pci_fun_t *fun, int reg, uint8_t *buf, size_t len) 155 { 156 pci_bus_t *bus = PCI_BUS_FROM_FUN(fun); 157 158 fibril_mutex_lock(&bus->conf_mutex); 162 159 163 160 uint32_t conf_addr; 164 conf_addr = CONF_ADDR(fun _data->bus, fun_data->dev, fun_data->fn, reg);165 void *addr = bus _data->conf_data_port + (reg & 3);166 167 pio_write_32(bus _data->conf_addr_port, conf_addr);161 conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg); 162 void *addr = bus->conf_data_port + (reg & 3); 163 164 pio_write_32(bus->conf_addr_port, conf_addr); 168 165 169 166 switch (len) { … … 179 176 } 180 177 181 fibril_mutex_unlock(&bus _data->conf_mutex);182 } 183 184 uint8_t pci_conf_read_8( function_t *fun, int reg)178 fibril_mutex_unlock(&bus->conf_mutex); 179 } 180 181 uint8_t pci_conf_read_8(pci_fun_t *fun, int reg) 185 182 { 186 183 uint8_t res; … … 189 186 } 190 187 191 uint16_t pci_conf_read_16( function_t *fun, int reg)188 uint16_t pci_conf_read_16(pci_fun_t *fun, int reg) 192 189 { 193 190 uint16_t res; … … 196 193 } 197 194 198 uint32_t pci_conf_read_32( function_t *fun, int reg)195 uint32_t pci_conf_read_32(pci_fun_t *fun, int reg) 199 196 { 200 197 uint32_t res; … … 203 200 } 204 201 205 void pci_conf_write_8( function_t *fun, int reg, uint8_t val)202 void pci_conf_write_8(pci_fun_t *fun, int reg, uint8_t val) 206 203 { 207 204 pci_conf_write(fun, reg, (uint8_t *) &val, 1); 208 205 } 209 206 210 void pci_conf_write_16( function_t *fun, int reg, uint16_t val)207 void pci_conf_write_16(pci_fun_t *fun, int reg, uint16_t val) 211 208 { 212 209 pci_conf_write(fun, reg, (uint8_t *) &val, 2); 213 210 } 214 211 215 void pci_conf_write_32( function_t *fun, int reg, uint32_t val)212 void pci_conf_write_32(pci_fun_t *fun, int reg, uint32_t val) 216 213 { 217 214 pci_conf_write(fun, reg, (uint8_t *) &val, 4); 218 215 } 219 216 220 void create_pci_match_ids(function_t *fun) 221 { 222 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 217 void pci_fun_create_match_ids(pci_fun_t *fun) 218 { 223 219 match_id_t *match_id = NULL; 224 220 char *match_id_str; … … 227 223 if (match_id != NULL) { 228 224 asprintf(&match_id_str, "pci/ven=%04x&dev=%04x", 229 fun _data->vendor_id, fun_data->device_id);225 fun->vendor_id, fun->device_id); 230 226 match_id->id = match_id_str; 231 227 match_id->score = 90; 232 add_match_id(&fun-> match_ids, match_id);228 add_match_id(&fun->fnode->match_ids, match_id); 233 229 } 234 230 … … 236 232 } 237 233 238 void 239 pci_add_range(function_t *fun, uint64_t range_addr, size_t range_size, bool io) 240 { 241 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 242 hw_resource_list_t *hw_res_list = &fun_data->hw_resources; 234 void pci_add_range(pci_fun_t *fun, uint64_t range_addr, size_t range_size, 235 bool io) 236 { 237 hw_resource_list_t *hw_res_list = &fun->hw_resources; 243 238 hw_resource_t *hw_resources = hw_res_list->resources; 244 239 size_t count = hw_res_list->count; … … 265 260 * address add it to the devices hw resource list. 266 261 * 267 * @param dev The pci device.262 * @param fun PCI function 268 263 * @param addr The address of the BAR in the PCI configuration address space of 269 * the device .270 * @return The addr the address of the BAR which should be read next .264 * the device 265 * @return The addr the address of the BAR which should be read next 271 266 */ 272 int pci_read_bar( function_t *fun, int addr)267 int pci_read_bar(pci_fun_t *fun, int addr) 273 268 { 274 269 /* Value of the BAR */ … … 322 317 323 318 if (range_addr != 0) { 324 printf(NAME ": function %s : ", fun-> name);319 printf(NAME ": function %s : ", fun->fnode->name); 325 320 printf("address = %" PRIx64, range_addr); 326 321 printf(", size = %x\n", (unsigned int) range_size); … … 335 330 } 336 331 337 void pci_add_interrupt(function_t *fun, int irq) 338 { 339 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 340 hw_resource_list_t *hw_res_list = &fun_data->hw_resources; 332 void pci_add_interrupt(pci_fun_t *fun, int irq) 333 { 334 hw_resource_list_t *hw_res_list = &fun->hw_resources; 341 335 hw_resource_t *hw_resources = hw_res_list->resources; 342 336 size_t count = hw_res_list->count; … … 350 344 hw_res_list->count++; 351 345 352 printf(NAME ": function %s uses irq %x.\n", fun-> name, irq);353 } 354 355 void pci_read_interrupt( function_t *fun)346 printf(NAME ": function %s uses irq %x.\n", fun->fnode->name, irq); 347 } 348 349 void pci_read_interrupt(pci_fun_t *fun) 356 350 { 357 351 uint8_t irq = pci_conf_read_8(fun, PCI_BRIDGE_INT_LINE); … … 362 356 /** Enumerate (recursively) and register the devices connected to a pci bus. 363 357 * 364 * @param dev The host-to-pci bridge device.365 * @param bus_num The bus number.358 * @param bus Host-to-PCI bridge 359 * @param bus_num Bus number 366 360 */ 367 void pci_bus_scan( device_t *dev, int bus_num)368 { 369 function_t *f un= create_function();370 pci_fun_ data_t *fun_data = create_pci_fun_data();371 f un->driver_data = fun_data;361 void pci_bus_scan(pci_bus_t *bus, int bus_num) 362 { 363 function_t *fnode = create_function(); 364 pci_fun_t *fun = pci_fun_new(); 365 fnode->driver_data = fun; 372 366 373 367 int child_bus = 0; … … 377 371 378 372 /* We need this early, before registering. */ 379 fun->dev = dev; 373 fun->fnode = fnode; 374 fnode->dev = bus->dnode; 375 fnode->driver_data = fun; 380 376 381 377 for (dnum = 0; dnum < 32; dnum++) { 382 378 multi = true; 383 379 for (fnum = 0; multi && fnum < 8; fnum++) { 384 init_pci_fun_data(fun_data, bus_num, dnum, fnum);385 fun _data->vendor_id = pci_conf_read_16(fun,380 pci_fun_init(fun, bus_num, dnum, fnum); 381 fun->vendor_id = pci_conf_read_16(fun, 386 382 PCI_VENDOR_ID); 387 fun _data->device_id = pci_conf_read_16(fun,383 fun->device_id = pci_conf_read_16(fun, 388 384 PCI_DEVICE_ID); 389 if (fun _data->vendor_id == 0xffff) {385 if (fun->vendor_id == 0xffff) { 390 386 /* 391 387 * The device is not present, go on scanning the … … 406 402 header_type = header_type & 0x7F; 407 403 408 create_pci_fun_name(fun);404 pci_fun_create_name(fun); 409 405 410 406 pci_alloc_resource_list(fun); … … 412 408 pci_read_interrupt(fun); 413 409 414 f un->ftype = fun_inner;415 f un->ops = &pci_child_ops;410 fnode->ftype = fun_inner; 411 fnode->ops = &pci_fun_ops; 416 412 417 413 printf(NAME ": adding new function %s.\n", 418 f un->name);419 420 create_pci_match_ids(fun);421 422 if (register_function(f un, dev) != EOK) {414 fnode->name); 415 416 pci_fun_create_match_ids(fun); 417 418 if (register_function(fnode, bus->dnode) != EOK) { 423 419 pci_clean_resource_list(fun); 424 clean_match_ids(&f un->match_ids);425 free((char *) f un->name);426 f un->name = NULL;420 clean_match_ids(&fnode->match_ids); 421 free((char *) fnode->name); 422 fnode->name = NULL; 427 423 continue; 428 424 } … … 435 431 "secondary bus number = %d.\n", bus_num); 436 432 if (child_bus > bus_num) 437 pci_bus_scan( dev, child_bus);433 pci_bus_scan(bus, child_bus); 438 434 } 439 435 440 436 /* Alloc new aux. fun. structure. */ 441 f un= create_function();437 fnode = create_function(); 442 438 443 439 /* We need this early, before registering. */ 444 fun->dev = dev; 445 446 fun_data = create_pci_fun_data(); 447 fun->driver_data = fun_data; 440 fnode->dev = bus->dnode; 441 442 fun = pci_fun_new(); 443 fun->fnode = fnode; 444 fnode->driver_data = fun; 448 445 } 449 446 } 450 447 451 if (fun _data->vendor_id == 0xffff) {452 delete_function(f un);448 if (fun->vendor_id == 0xffff) { 449 delete_function(fnode); 453 450 /* Free the auxiliary function structure. */ 454 delete_pci_fun_data(fun_data);455 } 456 } 457 458 static int pci_add_device(device_t *d ev)451 pci_fun_delete(fun); 452 } 453 } 454 455 static int pci_add_device(device_t *dnode) 459 456 { 460 457 int rc; 461 458 462 459 printf(NAME ": pci_add_device\n"); 463 460 464 pci_bus_ data_t *bus_data = create_pci_bus_data();465 if (bus _data== NULL) {461 pci_bus_t *bus = pci_bus_new(); 462 if (bus == NULL) { 466 463 printf(NAME ": pci_add_device allocation failed.\n"); 467 464 return ENOMEM; 468 465 } 469 470 dev->parent_phone = devman_parent_device_connect(dev->handle, 466 bus->dnode = dnode; 467 dnode->driver_data = bus; 468 469 dnode->parent_phone = devman_parent_device_connect(dnode->handle, 471 470 IPC_FLAG_BLOCKING); 472 if (d ev->parent_phone < 0) {471 if (dnode->parent_phone < 0) { 473 472 printf(NAME ": pci_add_device failed to connect to the " 474 473 "parent's driver.\n"); 475 delete_pci_bus_data(bus_data);476 return d ev->parent_phone;474 pci_bus_delete(bus); 475 return dnode->parent_phone; 477 476 } 478 477 479 478 hw_resource_list_t hw_resources; 480 479 481 rc = hw_res_get_resource_list(d ev->parent_phone, &hw_resources);480 rc = hw_res_get_resource_list(dnode->parent_phone, &hw_resources); 482 481 if (rc != EOK) { 483 482 printf(NAME ": pci_add_device failed to get hw resources for " 484 483 "the device.\n"); 485 delete_pci_bus_data(bus_data);486 async_hangup(d ev->parent_phone);484 pci_bus_delete(bus); 485 async_hangup(dnode->parent_phone); 487 486 return rc; 488 487 } … … 495 494 assert(hw_resources.resources[0].res.io_range.size == 8); 496 495 497 bus _data->conf_io_addr =496 bus->conf_io_addr = 498 497 (uint32_t) hw_resources.resources[0].res.io_range.address; 499 498 500 if (pio_enable((void *)(uintptr_t)bus _data->conf_io_addr, 8,501 &bus _data->conf_addr_port)) {499 if (pio_enable((void *)(uintptr_t)bus->conf_io_addr, 8, 500 &bus->conf_addr_port)) { 502 501 printf(NAME ": failed to enable configuration ports.\n"); 503 delete_pci_bus_data(bus_data);504 async_hangup(d ev->parent_phone);502 pci_bus_delete(bus); 503 async_hangup(dnode->parent_phone); 505 504 hw_res_clean_resource_list(&hw_resources); 506 505 return EADDRNOTAVAIL; 507 506 } 508 bus_data->conf_data_port = (char *) bus_data->conf_addr_port + 4; 509 510 dev->driver_data = bus_data; 511 512 /* Make the bus device more visible. Does not do anything. */ 507 bus->conf_data_port = (char *) bus->conf_addr_port + 4; 508 509 /* Make the bus device more visible. It has no use yet. */ 513 510 printf(NAME ": adding a 'ctl' function\n"); 514 511 515 512 function_t *ctl = create_function(); 516 513 ctl->ftype = fun_exposed; 517 514 ctl->name = "ctl"; 518 register_function(ctl, d ev);519 520 /* Enumerate child devices. */515 register_function(ctl, dnode); 516 517 /* Enumerate functions. */ 521 518 printf(NAME ": scanning the bus\n"); 522 pci_bus_scan( dev, 0);519 pci_bus_scan(bus, 0); 523 520 524 521 hw_res_clean_resource_list(&hw_resources); … … 529 526 static void pciintel_init(void) 530 527 { 531 pci_ child_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_child_hw_res_ops;532 } 533 534 pci_fun_ data_t *create_pci_fun_data(void)535 { 536 pci_fun_ data_t *res = (pci_fun_data_t *) malloc(sizeof(pci_fun_data_t));528 pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops; 529 } 530 531 pci_fun_t *pci_fun_new(void) 532 { 533 pci_fun_t *res = (pci_fun_t *) malloc(sizeof(pci_fun_t)); 537 534 538 535 if (res != NULL) 539 memset(res, 0, sizeof(pci_fun_ data_t));536 memset(res, 0, sizeof(pci_fun_t)); 540 537 return res; 541 538 } 542 539 543 void init_pci_fun_data(pci_fun_data_t *fun_data, int bus, int dev, int fn) 544 { 545 fun_data->bus = bus; 546 fun_data->dev = dev; 547 fun_data->fn = fn; 548 } 549 550 void delete_pci_fun_data(pci_fun_data_t *fun_data) 551 { 552 if (fun_data != NULL) { 553 hw_res_clean_resource_list(&fun_data->hw_resources); 554 free(fun_data); 555 } 556 } 557 558 void create_pci_fun_name(function_t *fun) 559 { 560 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 540 void pci_fun_init(pci_fun_t *fun, int bus, int dev, int fn) 541 { 542 fun->bus = bus; 543 fun->dev = dev; 544 fun->fn = fn; 545 } 546 547 void pci_fun_delete(pci_fun_t *fun) 548 { 549 if (fun != NULL) { 550 hw_res_clean_resource_list(&fun->hw_resources); 551 free(fun); 552 } 553 } 554 555 void pci_fun_create_name(pci_fun_t *fun) 556 { 561 557 char *name = NULL; 562 558 563 asprintf(&name, "%02x:%02x.%01x", fun_data->bus, fun_data->dev, 564 fun_data->fn); 565 fun->name = name; 566 } 567 568 bool pci_alloc_resource_list(function_t *fun) 569 { 570 pci_fun_data_t *fun_data = (pci_fun_data_t *)fun->driver_data; 571 572 fun_data->hw_resources.resources = 559 asprintf(&name, "%02x:%02x.%01x", fun->bus, fun->dev, 560 fun->fn); 561 fun->fnode->name = name; 562 } 563 564 bool pci_alloc_resource_list(pci_fun_t *fun) 565 { 566 fun->hw_resources.resources = 573 567 (hw_resource_t *) malloc(PCI_MAX_HW_RES * sizeof(hw_resource_t)); 574 return fun_data->hw_resources.resources != NULL; 575 } 576 577 void pci_clean_resource_list(function_t *fun) 578 { 579 pci_fun_data_t *fun_data = (pci_fun_data_t *) fun->driver_data; 580 581 if (fun_data->hw_resources.resources != NULL) { 582 free(fun_data->hw_resources.resources); 583 fun_data->hw_resources.resources = NULL; 584 } 585 } 586 587 /** Read the base address registers (BARs) of the device and adds the addresses 588 * to its hw resource list. 568 return fun->hw_resources.resources != NULL; 569 } 570 571 void pci_clean_resource_list(pci_fun_t *fun) 572 { 573 if (fun->hw_resources.resources != NULL) { 574 free(fun->hw_resources.resources); 575 fun->hw_resources.resources = NULL; 576 } 577 } 578 579 /** Read the base address registers (BARs) of the function and add the addresses 580 * to its HW resource list. 589 581 * 590 * @param dev the pci device.582 * @param fun PCI function 591 583 */ 592 void pci_read_bars( function_t *fun)584 void pci_read_bars(pci_fun_t *fun) 593 585 { 594 586 /*
Note:
See TracChangeset
for help on using the changeset viewer.