1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <sys/cpuvar.h> 31 #include <sys/kmem.h> 32 #include <sys/sunddi.h> 33 #include <sys/hotplug/pci/pcihp.h> 34 #include "px_obj.h" 35 #include <sys/pci_tools.h> 36 #include "px_tools_ext.h" 37 #include "px_tools_var.h" 38 39 /* 40 * PCI Space definitions. 41 */ 42 #define PCI_CONFIG_SPACE (PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) 43 #define PCI_IO_SPACE (PCI_REG_ADDR_G(PCI_ADDR_IO)) 44 #define PCI_MEM32_SPACE (PCI_REG_ADDR_G(PCI_ADDR_MEM32)) 45 #define PCI_MEM64_SPACE (PCI_REG_ADDR_G(PCI_ADDR_MEM64)) 46 47 /* 48 * Config space range for a device. IEEE 1275 spec defines for PCI. 49 * Space for PCI-express is multiplied by PX_PCI_BDF_OFFSET_DELTA 50 */ 51 #define DEV_CFG_SPACE_SIZE \ 52 (1 << (PCI_REG_FUNC_SHIFT + PX_PCI_BDF_OFFSET_DELTA)) 53 54 /* 55 * Offsets of BARS in config space. First entry of 0 means config space. 56 * Entries here correlate to pcitool_bars_t enumerated type. 57 */ 58 uint8_t pci_bars[] = { 59 0x0, 60 PCI_CONF_BASE0, 61 PCI_CONF_BASE1, 62 PCI_CONF_BASE2, 63 PCI_CONF_BASE3, 64 PCI_CONF_BASE4, 65 PCI_CONF_BASE5, 66 PCI_CONF_ROM 67 }; 68 69 int pci_num_bars = sizeof (pci_bars) / sizeof (pci_bars[0]); 70 71 /* 72 * Validate the cpu_id passed in. 73 * A value of 1 will be returned for success and zero for failure. 74 */ 75 static int 76 pxtool_validate_cpuid(uint32_t cpuid) 77 { 78 extern const int _ncpu; 79 extern cpu_t *cpu[]; 80 81 ASSERT(mutex_owned(&cpu_lock)); 82 83 return ((cpuid < _ncpu) && (cpu[cpuid] && cpu_is_online(cpu[cpuid]))); 84 } 85 86 87 static int 88 pxtool_intr_get_max_ino(uint32_t *arg, int mode) 89 { 90 if (ddi_copyout(&pxtool_num_inos, arg, sizeof (uint32_t), mode) != 91 DDI_SUCCESS) 92 return (EFAULT); 93 else 94 return (SUCCESS); 95 } 96 /* 97 * Get interrupt information for a given ino. 98 * Returns info only for inos mapped to devices. 99 * 100 * Returned info is valid only when iget.num_devs is returned > 0. 101 * If ino is not enabled or is not mapped to a device, 102 * iget.num_devs will be returned as = 0. 103 */ 104 /*ARGSUSED*/ 105 static int 106 pxtool_get_intr(dev_info_t *dip, void *arg, int mode) 107 { 108 /* Array part isn't used here, but oh well... */ 109 pcitool_intr_get_t partial_iget; 110 uint32_t ino; 111 uint8_t num_devs_ret; 112 int copyout_rval; 113 sysino_t sysino; 114 intr_valid_state_t intr_valid_state; 115 cpuid_t old_cpu_id; 116 px_t *px_p = DIP_TO_STATE(dip); 117 pcitool_intr_get_t *iget = &partial_iget; 118 size_t iget_kmem_alloc_size = 0; 119 int rval = SUCCESS; 120 121 /* Read in just the header part, no array section. */ 122 if (ddi_copyin(arg, &partial_iget, PCITOOL_IGET_SIZE(0), mode) != 123 DDI_SUCCESS) 124 return (EFAULT); 125 126 ino = partial_iget.ino; 127 num_devs_ret = partial_iget.num_devs_ret; 128 129 partial_iget.num_devs_ret = 0; /* Assume error for now. */ 130 partial_iget.status = PCITOOL_INVALID_INO; 131 rval = EINVAL; 132 133 /* Validate argument. */ 134 if (partial_iget.ino > pxtool_num_inos) { 135 goto done_get_intr; 136 } 137 138 /* Caller wants device information returned. */ 139 if (num_devs_ret > 0) { 140 141 /* 142 * Allocate room. 143 * Note if num_devs == 0 iget remains pointing to 144 * partial_iget. 145 */ 146 iget_kmem_alloc_size = PCITOOL_IGET_SIZE(num_devs_ret); 147 iget = kmem_alloc(iget_kmem_alloc_size, KM_SLEEP); 148 149 /* Read in whole structure to verify there's room. */ 150 if (ddi_copyin(arg, iget, iget_kmem_alloc_size, mode) != 151 SUCCESS) { 152 153 /* Be consistent and just return EFAULT here. */ 154 kmem_free(iget, iget_kmem_alloc_size); 155 156 return (EFAULT); 157 } 158 } 159 160 bzero(iget, PCITOOL_IGET_SIZE(num_devs_ret)); 161 iget->ino = ino; 162 iget->num_devs_ret = num_devs_ret; 163 164 /* Convert leaf-wide intr to system-wide intr */ 165 if (px_lib_intr_devino_to_sysino(dip, iget->ino, &sysino) == 166 DDI_FAILURE) { 167 iget->status = PCITOOL_IO_ERROR; 168 rval = EIO; 169 goto done_get_intr; 170 } 171 172 /* Operate only on inos which are already enabled. */ 173 if (px_lib_intr_getvalid(dip, sysino, &intr_valid_state) == 174 DDI_FAILURE) { 175 iget->status = PCITOOL_IO_ERROR; 176 rval = EIO; 177 goto done_get_intr; 178 } 179 180 /* 181 * Consider all valid inos: those mapped to the root complex itself 182 * as well as those mapped to devices. 183 */ 184 if (intr_valid_state == INTR_VALID) { 185 186 /* 187 * The following looks up the px_ino and returns 188 * info of devices mapped to this ino. 189 */ 190 iget->num_devs = pxtool_ib_get_ino_devs( 191 px_p, ino, &iget->num_devs_ret, iget->dev); 192 193 if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) == 194 DDI_FAILURE) { 195 iget->status = PCITOOL_IO_ERROR; 196 rval = EIO; 197 goto done_get_intr; 198 } 199 iget->cpu_id = old_cpu_id; 200 } 201 202 iget->status = PCITOOL_SUCCESS; 203 rval = SUCCESS; 204 205 done_get_intr: 206 copyout_rval = 207 ddi_copyout(iget, arg, PCITOOL_IGET_SIZE(num_devs_ret), mode); 208 209 if (iget_kmem_alloc_size > 0) 210 kmem_free(iget, iget_kmem_alloc_size); 211 212 if (copyout_rval != DDI_SUCCESS) 213 rval = EFAULT; 214 215 return (rval); 216 } 217 218 219 /* 220 * Associate a new CPU with a given ino. 221 * 222 * Operate only on inos which are already mapped to devices. 223 */ 224 static int 225 pxtool_set_intr(dev_info_t *dip, void *arg, int mode) 226 { 227 pcitool_intr_set_t iset; 228 cpuid_t old_cpu_id; 229 sysino_t sysino; 230 px_t *px_p = DIP_TO_STATE(dip); 231 px_ib_t *ib_p = px_p->px_ib_p; 232 uint8_t zero = 0; 233 int rval = SUCCESS; 234 235 if (ddi_copyin(arg, &iset, sizeof (pcitool_intr_set_t), mode) != 236 DDI_SUCCESS) 237 return (EFAULT); 238 239 iset.status = PCITOOL_INVALID_INO; 240 rval = EINVAL; 241 242 /* Validate input argument. */ 243 if (iset.ino > pxtool_num_inos) 244 goto done_set_intr; 245 246 /* Validate that ino given belongs to a device. */ 247 if (pxtool_ib_get_ino_devs(px_p, iset.ino, &zero, NULL) == 0) 248 goto done_set_intr; 249 250 /* 251 * Get lock, validate cpu and write new mapreg value. 252 * Return original cpu value to caller via iset.cpu. 253 */ 254 mutex_enter(&cpu_lock); 255 if (pxtool_validate_cpuid(iset.cpu_id)) { 256 257 DBG(DBG_TOOLS, dip, "Enabling CPU %d\n", iset.cpu_id); 258 259 if (px_lib_intr_devino_to_sysino(dip, iset.ino, &sysino) == 260 DDI_FAILURE) 261 goto done_set_intr; 262 263 if (px_lib_intr_gettarget(dip, sysino, &old_cpu_id) == 264 DDI_FAILURE) 265 goto done_set_intr; 266 267 px_ib_intr_dist_en(dip, iset.cpu_id, iset.ino, B_TRUE); 268 269 px_ib_log_new_cpu(ib_p, old_cpu_id, iset.cpu_id, iset.ino); 270 271 iset.cpu_id = old_cpu_id; 272 iset.status = PCITOOL_SUCCESS; 273 rval = SUCCESS; 274 275 } else { /* Invalid cpu. Restore original register image. */ 276 277 DBG(DBG_TOOLS, dip, 278 "Invalid cpuid: writing orig mapreg value\n"); 279 280 iset.status = PCITOOL_INVALID_CPUID; 281 rval = EINVAL; 282 } 283 mutex_exit(&cpu_lock); 284 285 done_set_intr: 286 if (ddi_copyout(&iset, arg, sizeof (pcitool_intr_set_t), mode) != 287 DDI_SUCCESS) 288 rval = EFAULT; 289 290 return (rval); 291 } 292 293 294 /* Main function for handling interrupt CPU binding requests and queries. */ 295 int 296 pxtool_intr(dev_info_t *dip, void *arg, int cmd, int mode) 297 { 298 int rval = SUCCESS; 299 300 switch (cmd) { 301 302 /* Return the number of interrupts supported by a PCI bus. */ 303 case PCITOOL_DEVICE_NUM_INTR: 304 rval = pxtool_intr_get_max_ino(arg, mode); 305 break; 306 307 /* Get interrupt information for a given ino. */ 308 case PCITOOL_DEVICE_GET_INTR: 309 rval = pxtool_get_intr(dip, arg, mode); 310 break; 311 312 /* Associate a new CPU with a given ino. */ 313 case PCITOOL_DEVICE_SET_INTR: 314 rval = pxtool_set_intr(dip, arg, mode); 315 break; 316 317 default: 318 rval = ENOTTY; 319 } 320 321 return (rval); 322 } 323 324 325 static int 326 pxtool_validate_barnum_bdf(pcitool_reg_t *prg) 327 { 328 int rval = SUCCESS; 329 330 if (prg->barnum >= (sizeof (pci_bars) / sizeof (pci_bars[0]))) { 331 prg->status = PCITOOL_OUT_OF_RANGE; 332 rval = EINVAL; 333 334 /* Validate address arguments of bus / dev / func */ 335 } else if (((prg->bus_no & 336 (PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT)) != prg->bus_no) || 337 ((prg->dev_no & 338 (PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT)) != prg->dev_no) || 339 ((prg->func_no & 340 (PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT)) != prg->func_no)) { 341 prg->status = PCITOOL_INVALID_ADDRESS; 342 rval = EINVAL; 343 } 344 345 return (rval); 346 } 347 348 /* 349 * px_p defines which leaf, space defines which space in that leaf, offset 350 * defines the offset within the specified space. 351 * 352 * This returns the physical address of the corresponding location. 353 */ 354 static uintptr_t 355 pxtool_get_phys_addr(px_t *px_p, int space, uint64_t offset) 356 { 357 uint64_t range_base; 358 int rval; 359 pci_regspec_t dev_regspec; 360 struct regspec xlated_regspec; 361 dev_info_t *dip = px_p->px_dip; 362 363 /* 364 * Assume that requested entity is small enough to be on the same page. 365 * PCItool checks alignment so that this will be true for single 366 * accesses. 367 */ 368 dev_regspec.pci_phys_hi = space << PCI_REG_ADDR_SHIFT; 369 if (space == PCI_CONFIG_SPACE) { 370 dev_regspec.pci_phys_hi += 371 (offset & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)); 372 dev_regspec.pci_phys_low = offset & PCI_REG_REG_M; 373 dev_regspec.pci_phys_mid = 0; /* Not used */ 374 } else { 375 dev_regspec.pci_phys_mid = offset >> 32; 376 dev_regspec.pci_phys_low = offset & 0xffffffff; 377 } 378 dev_regspec.pci_size_hi = 0; /* Not used. */ 379 380 /* Note: object is guaranteed to be within a page. */ 381 dev_regspec.pci_size_low = 4; 382 383 rval = px_xlate_reg(px_p, &dev_regspec, &xlated_regspec); 384 385 DBG(DBG_TOOLS, dip, 386 "space:0x%d, offset:0x%" PRIx64 "\n", space, offset); 387 388 if (rval != DDI_SUCCESS) 389 return (NULL); 390 391 /* Bustype here returns the high order address bits. */ 392 xlated_regspec.regspec_bustype &= px_get_rng_parent_hi_mask(px_p); 393 394 range_base = (((uint64_t)xlated_regspec.regspec_bustype) << 32) + 395 xlated_regspec.regspec_addr; 396 DBG(DBG_TOOLS, dip, 397 "regspec: hi:0x%x, lo:0x%x, sz:0x%x, range base:0x%" PRIx64 "\n", 398 xlated_regspec.regspec_bustype, xlated_regspec.regspec_addr, 399 xlated_regspec.regspec_size, range_base); 400 401 return ((uintptr_t)range_base); 402 } 403 404 405 static int 406 pxtool_get_bar(px_t *px_p, pcitool_reg_t *prg_p, uint64_t *bar_p, 407 uint32_t *space_p) 408 { 409 int rval; 410 uint64_t off_in_space; 411 pcitool_reg_t cfg_prg = *prg_p; /* Make local copy. */ 412 dev_info_t *dip = px_p->px_dip; 413 414 *space_p = PCI_MEM32_SPACE; 415 *bar_p = 0; 416 417 /* 418 * Translate BAR number into offset of the BAR in 419 * the device's config space. 420 */ 421 cfg_prg.acc_attr = 422 PCITOOL_ACC_ATTR_SIZE_4 | PCITOOL_ACC_ATTR_ENDN_LTL; 423 424 /* 425 * Note: sun4u acc function uses phys_addr which includes offset. 426 * sun4v acc function doesn't use phys_addr but uses cfg_prg.offset. 427 */ 428 cfg_prg.offset = PCI_BAR_OFFSET((*prg_p)); 429 off_in_space = PX_GET_BDF(prg_p) + cfg_prg.offset; 430 cfg_prg.phys_addr = pxtool_get_phys_addr(px_p, PCI_CONFIG_SPACE, 431 off_in_space); 432 433 DBG(DBG_TOOLS, dip, 434 "off_in_space:0x%" PRIx64 ", phys_addr:0x%" PRIx64 ", barnum:%d\n", 435 off_in_space, cfg_prg.phys_addr, cfg_prg.barnum); 436 437 /* 438 * Get Bus Address Register (BAR) from config space. 439 * cfg_prg.offset is the offset into config space of the 440 * BAR desired. prg_p->status is modified on error. 441 */ 442 rval = pxtool_pcicfg_access(px_p, &cfg_prg, bar_p, PX_ISREAD); 443 444 if (rval != SUCCESS) { 445 prg_p->status = cfg_prg.status; 446 return (rval); 447 } 448 449 DBG(DBG_TOOLS, dip, "bar returned is 0x%" PRIx64 "\n", *bar_p); 450 451 /* 452 * BAR has bits saying this space is IO space, unless 453 * this is the ROM address register. 454 */ 455 if (((PCI_BASE_SPACE_M & *bar_p) == PCI_BASE_SPACE_IO) && 456 (cfg_prg.offset != PCI_CONF_ROM)) { 457 *space_p = PCI_IO_SPACE; 458 *bar_p &= PCI_BASE_IO_ADDR_M; 459 460 /* 461 * BAR has bits saying this space is 64 bit memory 462 * space, unless this is the ROM address register. 463 * 464 * The 64 bit address stored in two BAR cells is not 465 * necessarily aligned on an 8-byte boundary. 466 * Need to keep the first 4 bytes read, 467 * and do a separate read of the high 4 bytes. 468 */ 469 } else if ((PCI_BASE_TYPE_ALL & *bar_p) && 470 (cfg_prg.offset != PCI_CONF_ROM)) { 471 472 uint32_t low_bytes = (uint32_t)(*bar_p & ~PCI_BASE_TYPE_ALL); 473 474 /* Don't try to read the next 4 bytes past the end of BARs. */ 475 if (cfg_prg.offset >= PCI_CONF_BASE5) { 476 prg_p->status = PCITOOL_OUT_OF_RANGE; 477 return (EIO); 478 } 479 480 /* Access device. prg_p->status is modified on error. */ 481 cfg_prg.phys_addr += sizeof (uint32_t); 482 cfg_prg.offset += sizeof (uint32_t); 483 484 rval = pxtool_pcicfg_access(px_p, &cfg_prg, bar_p, PX_ISREAD); 485 if (rval != SUCCESS) { 486 prg_p->status = cfg_prg.status; 487 return (rval); 488 } 489 490 /* 491 * Honor the 64 bit BAR as such, only when the upper 32 bits 492 * store a non-zero value. 493 */ 494 if (*bar_p) { 495 *space_p = PCI_MEM64_SPACE; 496 *bar_p = (*bar_p << 32) | low_bytes; 497 } else 498 *bar_p = low_bytes; 499 500 } else if (cfg_prg.offset == PCI_CONF_ROM) { /* ROM requested */ 501 502 /* 503 * ROM enabled. Filter ROM enable bit from the BAR. 504 * Treat as Mem32 henceforth. 505 */ 506 if (!(*bar_p & PCI_BASE_ROM_ENABLE)) 507 *bar_p ^= PCI_BASE_ROM_ENABLE; 508 509 else { /* ROM disabled. */ 510 prg_p->status = PCITOOL_ROM_DISABLED; 511 return (EIO); 512 } 513 } 514 515 /* Accept a bar of 0 only for IO space. */ 516 if ((*space_p != PCI_IO_SPACE) && (!(*bar_p))) { 517 prg_p->status = PCITOOL_INVALID_ADDRESS; 518 return (EINVAL); 519 } 520 521 return (SUCCESS); 522 } 523 524 525 /* Perform register accesses on PCI leaf devices. */ 526 int 527 pxtool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode) 528 { 529 pcitool_reg_t prg; 530 uint64_t bar; 531 uint32_t space; 532 uint64_t off_in_space; 533 boolean_t write_flag = B_FALSE; 534 px_t *px_p = DIP_TO_STATE(dip); 535 int rval = 0; 536 537 if (cmd == PCITOOL_DEVICE_SET_REG) 538 write_flag = B_TRUE; 539 540 DBG(DBG_TOOLS, dip, "pxtool_dev_reg_ops set/get reg\n"); 541 if (ddi_copyin(arg, &prg, sizeof (pcitool_reg_t), 542 mode) != DDI_SUCCESS) { 543 DBG(DBG_TOOLS, dip, "Error reading arguments\n"); 544 return (EFAULT); 545 } 546 547 if ((rval = pxtool_dev_reg_ops_platchk(dip, &prg)) != SUCCESS) { 548 goto done_reg; 549 } 550 551 DBG(DBG_TOOLS, dip, "raw bus:0x%x, dev:0x%x, func:0x%x\n", 552 prg.bus_no, prg.dev_no, prg.func_no); 553 DBG(DBG_TOOLS, dip, "barnum:0x%x, offset:0x%" PRIx64 ", acc:0x%x\n", 554 prg.barnum, prg.offset, prg.acc_attr); 555 556 if ((rval = pxtool_validate_barnum_bdf(&prg)) != SUCCESS) 557 goto done_reg; 558 559 if (prg.barnum == 0) { /* Proper config space desired. */ 560 561 /* Enforce offset limits. */ 562 if (prg.offset >= DEV_CFG_SPACE_SIZE) { 563 DBG(DBG_TOOLS, dip, 564 "Config space offset 0x%" PRIx64 " out of range\n", 565 prg.offset); 566 prg.status = PCITOOL_OUT_OF_RANGE; 567 rval = EINVAL; 568 goto done_reg; 569 } 570 571 /* 572 * For sun4v, config space base won't be known. 573 * pxtool_get_phys_addr will return zero. 574 * Note that for sun4v, phys_addr isn't 575 * used for making config space accesses. 576 * 577 * For sun4u, assume that phys_addr will come back valid. 578 */ 579 /* 580 * Accessed entity is assumed small enough to be on one page. 581 * 582 * Since config space is less than a page and is aligned to 583 * 0x1000, a device's entire config space will be on a single 584 * page. Pass the device's base config space address here, 585 * then add the offset within that space later. This works 586 * around an issue in px_xlate_reg (called by 587 * pxtool_get_phys_addr) which accepts only a 256 byte 588 * range within a device. 589 */ 590 off_in_space = PX_GET_BDF(&prg); 591 prg.phys_addr = 592 pxtool_get_phys_addr(px_p, PCI_CONFIG_SPACE, off_in_space); 593 prg.phys_addr += prg.offset; 594 595 DBG(DBG_TOOLS, dip, 596 "off_in_space:0x%" PRIx64 ", phys_addr:0x%" PRIx64 ", " 597 "end:%s\n", off_in_space, prg.phys_addr, 598 PCITOOL_ACC_IS_BIG_ENDIAN(prg.acc_attr) ? "big":"ltl"); 599 600 /* 601 * Access device. pr.status is modified. 602 * BDF is assumed valid at this point. 603 */ 604 rval = pxtool_pcicfg_access(px_p, &prg, &prg.data, write_flag); 605 goto done_reg; 606 } 607 608 /* IO/ MEM/ MEM64 space. */ 609 610 if ((rval = pxtool_get_bar(px_p, &prg, &bar, &space)) != SUCCESS) 611 goto done_reg; 612 613 switch (space) { 614 case PCI_MEM32_SPACE: 615 616 DBG(DBG_TOOLS, dip, "32 bit mem space\n"); 617 618 /* Can't write to ROM */ 619 if ((PCI_BAR_OFFSET(prg) == PCI_CONF_ROM) && (write_flag)) { 620 prg.status = PCITOOL_ROM_WRITE; 621 rval = EIO; 622 goto done_reg; 623 } 624 break; 625 626 case PCI_IO_SPACE: 627 DBG(DBG_TOOLS, dip, "IO space\n"); 628 break; 629 630 case PCI_MEM64_SPACE: 631 DBG(DBG_TOOLS, dip, 632 "64 bit mem space. 64-bit bar is 0x%" PRIx64 "\n", bar); 633 break; 634 635 default: 636 DBG(DBG_TOOLS, dip, "Unknown space!\n"); 637 prg.status = PCITOOL_IO_ERROR; 638 rval = EIO; 639 goto done_reg; 640 } 641 642 /* 643 * Common code for all IO/MEM range spaces. 644 * 645 * Use offset provided by caller to index into desired space. 646 * Note that prg.status is modified on error. 647 */ 648 off_in_space = bar + prg.offset; 649 prg.phys_addr = pxtool_get_phys_addr(px_p, space, off_in_space); 650 651 DBG(DBG_TOOLS, dip, 652 "addr in bar:0x%" PRIx64 ", offset:0x%" PRIx64 ", " 653 "phys_addr:0x%" PRIx64 "\n", bar, prg.offset, prg.phys_addr); 654 655 rval = pxtool_pciiomem_access(px_p, &prg, &prg.data, write_flag); 656 657 done_reg: 658 if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), 659 mode) != DDI_SUCCESS) { 660 DBG(DBG_TOOLS, dip, "Error returning arguments.\n"); 661 rval = EFAULT; 662 } 663 return (rval); 664 } 665 666 667 int 668 pxtool_init(dev_info_t *dip) 669 { 670 int instance = ddi_get_instance(dip); 671 672 if (ddi_create_minor_node(dip, PCI_MINOR_REG, S_IFCHR, 673 PCIHP_AP_MINOR_NUM(instance, PCI_TOOL_REG_MINOR_NUM), 674 DDI_NT_REGACC, 0) != DDI_SUCCESS) { 675 return (DDI_FAILURE); 676 } 677 678 if (ddi_create_minor_node(dip, PCI_MINOR_INTR, S_IFCHR, 679 PCIHP_AP_MINOR_NUM(instance, PCI_TOOL_INTR_MINOR_NUM), 680 DDI_NT_INTRCTL, 0) != DDI_SUCCESS) { 681 ddi_remove_minor_node(dip, PCI_MINOR_REG); 682 return (DDI_FAILURE); 683 } 684 685 return (DDI_SUCCESS); 686 } 687 688 689 void 690 pxtool_uninit(dev_info_t *dip) 691 { 692 ddi_remove_minor_node(dip, PCI_MINOR_REG); 693 ddi_remove_minor_node(dip, PCI_MINOR_INTR); 694 } 695