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 2006 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/conf.h> 30 #include <sys/ddi.h> 31 #include <sys/sunddi.h> 32 #include <sys/autoconf.h> 33 #include <sys/ddi_impldefs.h> 34 #include <sys/ddi_subrdefs.h> 35 #include <sys/cmn_err.h> 36 #include <sys/errno.h> 37 #include <sys/kmem.h> 38 #include <sys/debug.h> 39 #include <sys/sysmacros.h> 40 #include <sys/spl.h> 41 #include <sys/async.h> 42 #include <sys/dvma.h> 43 #include <sys/upa64s.h> 44 #include <sys/machsystm.h> 45 46 /* 47 * driver global data: 48 */ 49 static void *per_upa64s_state; /* soft state pointer */ 50 51 /* 52 * function prototypes for bus ops routines: 53 */ 54 static int 55 upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 56 off_t offset, off_t len, caddr_t *addrp); 57 static int 58 upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip, 59 ddi_ctl_enum_t op, void *arg, void *result); 60 static int 61 upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 62 ddi_intr_handle_impl_t *hdlp, void *result); 63 static int 64 upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 65 ddi_intr_handle_impl_t *hdlp); 66 static int 67 upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 68 ddi_intr_handle_impl_t *hdlp); 69 70 /* 71 * function prototypes for dev ops routines: 72 */ 73 static int upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 74 static int upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 75 static int upa64s_power(dev_info_t *dip, int component, int level); 76 77 /* 78 * bus ops and dev ops structures: 79 */ 80 static struct bus_ops upa64s_bus_ops = { 81 BUSO_REV, 82 upa64s_map, 83 0, 84 0, 85 0, 86 i_ddi_map_fault, 87 ddi_no_dma_map, 88 ddi_no_dma_allochdl, 89 ddi_no_dma_freehdl, 90 ddi_no_dma_bindhdl, 91 ddi_no_dma_unbindhdl, 92 ddi_no_dma_flush, 93 ddi_no_dma_win, 94 ddi_no_dma_mctl, 95 upa64s_ctlops, 96 ddi_bus_prop_op, 97 0, 98 0, 99 0, 100 0, 101 0, 102 0, 103 0, 104 0, 105 0, 106 0, 107 0, 108 0, 109 upa64_intr_ops 110 }; 111 112 static struct dev_ops upa64s_ops = { 113 DEVO_REV, 114 0, 115 ddi_no_info, 116 nulldev, 117 0, 118 upa64s_attach, 119 upa64s_detach, 120 nodev, 121 (struct cb_ops *)0, 122 &upa64s_bus_ops, 123 upa64s_power 124 }; 125 126 /* 127 * module definitions: 128 */ 129 #include <sys/modctl.h> 130 extern struct mod_ops mod_driverops; 131 132 static struct modldrv modldrv = { 133 &mod_driverops, /* type of module */ 134 "UPA64S nexus driver %I%", /* name of module */ 135 &upa64s_ops, /* driver ops */ 136 }; 137 138 static struct modlinkage modlinkage = { 139 MODREV_1, (void *)&modldrv, NULL 140 }; 141 142 int 143 _init(void) 144 { 145 int e; 146 147 /* 148 * Initialize per instance bus soft state pointer. 149 */ 150 if (e = ddi_soft_state_init(&per_upa64s_state, 151 sizeof (upa64s_devstate_t), 2)) 152 return (e); 153 /* 154 * Install the module. 155 */ 156 if (e = mod_install(&modlinkage)) 157 ddi_soft_state_fini(&per_upa64s_state); 158 return (e); 159 } 160 161 int 162 _fini(void) 163 { 164 int e = mod_remove(&modlinkage); 165 if (e) 166 return (e); 167 ddi_soft_state_fini(&per_upa64s_state); 168 return (e); 169 } 170 171 int 172 _info(struct modinfo *modinfop) 173 { 174 return (mod_info(&modlinkage, modinfop)); 175 } 176 177 178 /* 179 * forward declarations: 180 */ 181 static void upa64s_intrdist(void *arg); 182 static int init_child(dev_info_t *child); 183 static int report_dev(dev_info_t *dip); 184 static int get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip); 185 static void save_state(upa64s_devstate_t *upa64s_p); 186 static void restore_state(upa64s_devstate_t *upa64s_p); 187 static int xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *upa64s_rp, 188 off_t off, off_t len, struct regspec *rp); 189 static int get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber, 190 off_t off, off_t len, struct regspec *rp); 191 static off_t get_reg_set_size(dev_info_t *child, int rnumber); 192 static uint_t get_nreg_set(dev_info_t *child); 193 194 195 /* device driver entry points */ 196 197 /* 198 * attach entry point: 199 */ 200 static int 201 upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 202 { 203 upa64s_devstate_t *upa64s_p; /* per upa64s state pointer */ 204 ddi_device_acc_attr_t attr; 205 int instance; 206 char *pmc[] = { "NAME=Framebuffer Power", "0=Off", "1=On", NULL }; 207 208 switch (cmd) { 209 case DDI_ATTACH: 210 /* 211 * Allocate and get the per instance soft state structure. 212 */ 213 instance = ddi_get_instance(dip); 214 if (alloc_upa64s_soft_state(instance) != DDI_SUCCESS) { 215 cmn_err(CE_WARN, "%s%d: can't allocate upa64s state", 216 ddi_get_name(dip), instance); 217 return (DDI_FAILURE); 218 } 219 upa64s_p = get_upa64s_soft_state(instance); 220 upa64s_p->dip = dip; 221 222 /* 223 * Get key properties of the bridge node. 224 */ 225 if (get_properties(upa64s_p, dip) != DDI_SUCCESS) 226 goto fail; 227 228 /* 229 * Create "pm-components" property for the purpose of 230 * doing Power Management. 231 */ 232 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 233 "pm-components", pmc, ((sizeof (pmc)/sizeof (char *)) - 1)) 234 != DDI_PROP_SUCCESS) { 235 cmn_err(CE_WARN, "%s%d: failed to create pm-components " 236 "property.", ddi_get_name(dip), instance); 237 goto fail; 238 } 239 240 /* Map in the UPA's registers */ 241 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 242 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 243 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 244 if (ddi_regs_map_setup(dip, 0, 245 (caddr_t *)&upa64s_p->config_base, 0, 0, &attr, 246 &upa64s_p->config_base_ah) != DDI_SUCCESS) { 247 cmn_err(CE_WARN, "%s%d: failed to map reg1.", 248 ddi_get_name(dip), instance); 249 goto fail; 250 } 251 252 upa64s_p->upa0_config = (uint64_t *)(upa64s_p->config_base + 253 UPA64S_UPA0_CONFIG_OFFSET); 254 upa64s_p->upa1_config = (uint64_t *)(upa64s_p->config_base + 255 UPA64S_UPA1_CONFIG_OFFSET); 256 upa64s_p->if_config = (uint64_t *)(upa64s_p->config_base + 257 UPA64S_IF_CONFIG_OFFSET); 258 upa64s_p->estar = (uint64_t *)(upa64s_p->config_base + 259 UPA64S_ESTAR_OFFSET); 260 261 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&upa64s_p->imr[0], 262 0, 0, &attr, &upa64s_p->imr_ah[0]) != DDI_SUCCESS) { 263 cmn_err(CE_WARN, "%s%d: failed to map reg2.", 264 ddi_get_name(dip), instance); 265 goto fail1; 266 } 267 268 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&upa64s_p->imr[1], 269 0, 0, &attr, &upa64s_p->imr_ah[1]) != DDI_SUCCESS) { 270 cmn_err(CE_WARN, "%s%d: failed to map reg3.", 271 ddi_get_name(dip), instance); 272 goto fail2; 273 } 274 275 /* 276 * Power level of a component is unknown at attach time. 277 * Bring the power level to what is needed for normal operation. 278 */ 279 upa64s_p->power_level = UPA64S_PM_UNKNOWN; 280 if (pm_raise_power(dip, UPA64S_PM_COMP, UPA64S_PM_NORMOP) != 281 DDI_SUCCESS) { 282 cmn_err(CE_WARN, "%s%d: failed to raise the power.", 283 ddi_get_name(dip), instance); 284 goto fail3; 285 } 286 287 intr_dist_add(upa64s_intrdist, dip); 288 289 ddi_report_dev(dip); 290 return (DDI_SUCCESS); 291 292 case DDI_RESUME: 293 294 upa64s_p = get_upa64s_soft_state(ddi_get_instance(dip)); 295 DBG(D_ATTACH, dip, "DDI_RESUME\n"); 296 restore_state(upa64s_p); 297 298 /* 299 * Power level of a component is unknown at resume time. 300 * Bring the power level to what it was before suspend. 301 */ 302 upa64s_p->power_level = UPA64S_PM_UNKNOWN; 303 if (pm_raise_power(dip, UPA64S_PM_COMP, 304 upa64s_p->saved_power_level) != DDI_SUCCESS) 305 cmn_err(CE_WARN, "%s%d: failed to change power level " 306 "during resume!", ddi_get_name(dip), instance); 307 308 return (DDI_SUCCESS); 309 310 default: 311 return (DDI_FAILURE); 312 } 313 314 fail3: 315 ddi_regs_map_free(&upa64s_p->imr_ah[1]); 316 fail2: 317 ddi_regs_map_free(&upa64s_p->imr_ah[0]); 318 fail1: 319 ddi_regs_map_free(&upa64s_p->config_base_ah); 320 fail: 321 free_upa64s_soft_state(instance); 322 return (DDI_FAILURE); 323 } 324 325 326 /* 327 * detach entry point: 328 */ 329 static int 330 upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 331 { 332 int instance = ddi_get_instance(dip); 333 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 334 335 switch (cmd) { 336 case DDI_DETACH: 337 338 DBG(D_DETACH, dip, "DDI_DETACH\n"); 339 340 /* 341 * Power down the device. 342 */ 343 if (pm_lower_power(dip, UPA64S_PM_COMP, UPA64S_PM_RESET) != 344 DDI_SUCCESS) 345 DBG(D_DETACH, dip, "failed to power off!\n"); 346 347 intr_dist_rem(upa64s_intrdist, dip); 348 349 ddi_regs_map_free(&upa64s_p->config_base_ah); 350 ddi_regs_map_free(&upa64s_p->imr_ah[0]); 351 ddi_regs_map_free(&upa64s_p->imr_ah[1]); 352 free_upa64s_soft_state(instance); 353 return (DDI_SUCCESS); 354 355 case DDI_SUSPEND: 356 357 DBG(D_DETACH, dip, "DDI_SUSPEND\n"); 358 save_state(upa64s_p); 359 upa64s_p->saved_power_level = upa64s_p->power_level; 360 return (DDI_SUCCESS); 361 } 362 363 return (DDI_FAILURE); 364 } 365 366 /* 367 * power entry point: 368 * 369 * This entry point is called by Power Management framework to 370 * reset upa bus and slow down/speed up the upa interface of 371 * Schizo chip. 372 */ 373 static int 374 upa64s_power(dev_info_t *dip, int component, int level) 375 { 376 int instance = ddi_get_instance(dip); 377 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 378 volatile uint64_t uint64_data; 379 380 DBG2(D_POWER, dip, "component=%d, level=%d\n", component, level); 381 if (component != UPA64S_PM_COMP || 382 level < UPA64S_PM_RESET || level > UPA64S_PM_NORMOP) 383 return (DDI_FAILURE); 384 385 /* 386 * We can't set the hardware to the state that it is 387 * already in. So if the power state is not known, inquire the 388 * state of the hardware. If it is already in that state, 389 * record and return, otherwise make the state change. 390 */ 391 if (upa64s_p->power_level == UPA64S_PM_UNKNOWN) { 392 uint64_data = ddi_get64(upa64s_p->config_base_ah, 393 upa64s_p->if_config); 394 if ((level == UPA64S_PM_RESET && 395 uint64_data == UPA64S_NOT_POK_RST_L) || 396 (level == UPA64S_PM_NORMOP && 397 uint64_data == UPA64S_POK_NOT_RST_L)) { 398 upa64s_p->power_level = level; 399 return (DDI_SUCCESS); 400 } 401 } 402 403 if (level == upa64s_p->power_level) { 404 DBG1(D_POWER, dip, "device is already at power level %d\n", 405 level); 406 return (DDI_SUCCESS); 407 } 408 409 410 if (level == UPA64S_PM_RESET) { 411 /* 412 * Assert UPA64S_RESET 413 */ 414 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 415 UPA64S_POK_RST_L); 416 417 /* 418 * Deassert UPA64S_POK. Flush the store buffer. 419 */ 420 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 421 UPA64S_NOT_POK_RST_L); 422 uint64_data = ddi_get64(upa64s_p->config_base_ah, 423 upa64s_p->if_config); 424 425 /* 426 * Internal UPA clock to 1/2 speed 427 */ 428 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 429 UPA64S_1_2_SPEED); 430 431 /* 432 * Internal UPA clock to 1/64 speed. Flush the store buffer. 433 */ 434 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 435 UPA64S_1_64_SPEED); 436 uint64_data = ddi_get64(upa64s_p->config_base_ah, 437 upa64s_p->estar); 438 } else { 439 /* 440 * Internal UPA clock to 1/2 speed 441 */ 442 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 443 UPA64S_1_2_SPEED); 444 445 /* 446 * Internal UPA clock to full speed. Flush the store buffer. 447 */ 448 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 449 UPA64S_FULL_SPEED); 450 uint64_data = ddi_get64(upa64s_p->config_base_ah, 451 upa64s_p->estar); 452 453 /* 454 * Assert UPA64S_POK. Flush the store buffer before 455 * the wait delay. 456 */ 457 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 458 UPA64S_POK_RST_L); 459 uint64_data = ddi_get64(upa64s_p->config_base_ah, 460 upa64s_p->if_config); 461 462 /* 463 * Delay 20 milliseconds for the signals to settle down. 464 */ 465 delay(drv_usectohz(20*1000)); 466 467 /* 468 * Deassert UPA64S_RESET. Flush the store buffer. 469 */ 470 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 471 UPA64S_POK_NOT_RST_L); 472 uint64_data = ddi_get64(upa64s_p->config_base_ah, 473 upa64s_p->if_config); 474 } 475 upa64s_p->power_level = level; 476 477 return (DDI_SUCCESS); 478 } 479 480 /* bus driver entry points */ 481 482 /* 483 * bus map entry point: 484 * 485 * if map request is for an rnumber 486 * get the corresponding regspec from device node 487 * build a new regspec in our parent's format 488 * build a new map_req with the new regspec 489 * call up the tree to complete the mapping 490 */ 491 static int 492 upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 493 off_t off, off_t len, caddr_t *addrp) 494 { 495 struct regspec regspec; 496 ddi_map_req_t p_map_request; 497 int rnumber, rval; 498 499 DBG4(D_MAP, dip, "upa64s_map() mp=%x.%x addrp=%x.%08x\n", 500 HI32(mp), LO32(mp), HI32(addrp), LO32(addrp)); 501 502 /* 503 * User level mappings are not supported yet. 504 */ 505 if (mp->map_flags & DDI_MF_USER_MAPPING) { 506 DBG2(D_MAP, dip, "rdip=%s%d: no user level mappings yet!\n", 507 ddi_get_name(rdip), ddi_get_instance(rdip)); 508 return (DDI_ME_UNIMPLEMENTED); 509 } 510 511 /* 512 * Now handle the mapping according to its type. 513 */ 514 switch (mp->map_type) { 515 case DDI_MT_REGSPEC: 516 517 /* 518 * We assume the register specification is in PCI format. 519 * We must convert it into a regspec of our parent's 520 * and pass the request to our parent. 521 */ 522 DBG3(D_MAP, dip, "rdip=%s%d: REGSPEC - handlep=%x\n", 523 ddi_get_name(rdip), ddi_get_instance(rdip), 524 mp->map_handlep); 525 rval = xlate_reg_prop(dip, (upa64s_regspec_t *)mp->map_obj.rp, 526 off, len, ®spec); 527 break; 528 529 case DDI_MT_RNUMBER: 530 531 /* 532 * Get the "reg" property from the device node and convert 533 * it to our parent's format. 534 */ 535 DBG4(D_MAP, dip, "rdip=%s%d: rnumber=%x handlep=%x\n", 536 ddi_get_name(rdip), ddi_get_instance(rdip), 537 mp->map_obj.rnumber, mp->map_handlep); 538 rnumber = mp->map_obj.rnumber; 539 if (rnumber < 0) 540 return (DDI_ME_RNUMBER_RANGE); 541 rval = get_reg_set(dip, rdip, rnumber, off, len, ®spec); 542 break; 543 544 default: 545 return (DDI_ME_INVAL); 546 547 } 548 if (rval != DDI_SUCCESS) { 549 DBG(D_MAP, dip, "failed on regspec\n\n"); 550 return (rval); 551 } 552 553 /* 554 * Now we have a copy of the upa64s regspec converted to our parent's 555 * format. Build a new map request based on this regspec and pass 556 * it to our parent. 557 */ 558 p_map_request = *mp; 559 p_map_request.map_type = DDI_MT_REGSPEC; 560 p_map_request.map_obj.rp = ®spec; 561 rval = ddi_map(dip, &p_map_request, 0, 0, addrp); 562 DBG3(D_MAP, dip, "ddi_map returns: rval=%x addrp=%x.%08x\n\n", 563 rval, HI32(*addrp), LO32(*addrp)); 564 return (rval); 565 } 566 567 /* 568 * Translate the UPA devices interrupt property. This is the only case I 569 * know of where the interrupts property is meaningless. As a result, we 570 * just use UPA_BASE_INO as our interrupt value and add to it the upa port id. 571 * UPA portid is returned too. 572 */ 573 #define UPA_BASE_INO 0x2a 574 575 static int 576 upa64s_xlate_intr(dev_info_t *rdip, int32_t safariport, uint32_t *intr) 577 { 578 uint32_t ino = UPA_BASE_INO; 579 int32_t portid; 580 581 /* Clear the ffb's interrupts property, it's meaningless */ 582 *intr = 0; 583 584 if ((portid = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 585 "upa-portid", -1)) == -1) 586 return (-1); 587 588 ino += portid; 589 590 *intr = UPA64S_MAKE_MONDO(safariport, ino); 591 592 DBG5(D_A_ISPEC, rdip, "upa64s_xlate_intr: rdip=%s%d: upa portid %d " 593 "ino=%x mondo 0x%x\n", ddi_get_name(rdip), ddi_get_instance(rdip), 594 portid, ino, *intr); 595 596 return (portid); 597 } 598 599 /* 600 * bus add intrspec entry point: 601 */ 602 static int 603 upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 604 ddi_intr_handle_impl_t *hdlp) 605 { 606 int upaport, instance = ddi_get_instance(dip); 607 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 608 #ifdef DEBUG 609 uint_t (*int_handler)(caddr_t, caddr_t) = hdlp->ih_cb_func; 610 caddr_t int_handler_arg1 = hdlp->ih_cb_arg1; 611 #endif /* DEBUG */ 612 uint_t cpu_id; 613 volatile uint64_t imr_data; 614 615 upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, 616 (uint32_t *)&hdlp->ih_vector); 617 618 if (hdlp->ih_vector == 0) 619 return (DDI_FAILURE); 620 621 DBG3(D_A_ISPEC, dip, 622 "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n", 623 ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector); 624 625 /* 626 * Make sure an interrupt handler isn't already installed. 627 */ 628 if (upa64s_p->ino_state[upaport] != INO_FREE) { 629 return (DDI_FAILURE); 630 } 631 632 /* 633 * Install the handler in the system table. 634 */ 635 #ifdef DEBUG 636 DBG2(D_A_ISPEC, dip, "i_ddi_add_ivintr: hdlr=%p arg=%p\n", 637 int_handler, int_handler_arg1); 638 #endif 639 if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS) 640 return (DDI_FAILURE); 641 642 cpu_id = intr_dist_cpuid(); 643 644 /* 645 * Enable the interrupt through its interrupt mapping register. 646 */ 647 imr_data = UPA64S_CPUID_TO_IMR(cpu_id); 648 imr_data = UPA64S_GET_MAP_REG(hdlp->ih_vector, imr_data); 649 650 DBG4(D_A_ISPEC, dip, "IMR [upaport=%d mapping reg 0x%p] = %x.%x\n", 651 upaport, upa64s_p->imr[upaport], HI32(imr_data), LO32(imr_data)); 652 653 ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], imr_data); 654 /* Read the data back to flush store buffers. */ 655 imr_data = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]); 656 upa64s_p->ino_state[upaport] = INO_INUSE; 657 658 DBG(D_A_ISPEC, dip, "add_intr success!\n"); 659 return (DDI_SUCCESS); 660 } 661 662 663 /* 664 * bus remove intrspec entry point 665 */ 666 static int 667 upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 668 ddi_intr_handle_impl_t *hdlp) 669 { 670 upa64s_devstate_t *upa64s_p = 671 get_upa64s_soft_state(ddi_get_instance(dip)); 672 int upaport; 673 #ifndef lint 674 volatile uint64_t tmp; 675 #endif 676 677 /* 678 * Make sure the mondo is valid. 679 */ 680 upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, 681 (uint32_t *)&hdlp->ih_vector); 682 683 if (hdlp->ih_vector == 0) 684 return (DDI_FAILURE); 685 686 DBG3(D_R_ISPEC, dip, 687 "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n", 688 ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector); 689 690 if (upa64s_p->ino_state[upaport] != INO_INUSE) { 691 return (DDI_FAILURE); 692 } 693 694 /* Call up to our parent to handle the removal */ 695 i_ddi_rem_ivintr(hdlp); 696 697 ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], 0); 698 #ifndef lint 699 /* Flush store buffers */ 700 tmp = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]); 701 #endif 702 703 upa64s_p->ino_state[upaport] = INO_FREE; 704 return (DDI_SUCCESS); 705 } 706 707 708 /* new intr_ops structure */ 709 static int 710 upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 711 ddi_intr_handle_impl_t *hdlp, void *result) 712 { 713 int ret = DDI_SUCCESS; 714 715 switch (intr_op) { 716 case DDI_INTROP_GETCAP: 717 *(int *)result = DDI_INTR_FLAG_EDGE; 718 break; 719 case DDI_INTROP_ALLOC: 720 *(int *)result = hdlp->ih_scratch1; 721 break; 722 case DDI_INTROP_FREE: 723 break; 724 case DDI_INTROP_GETPRI: 725 /* 726 * We only have slave UPA devices so force the PIL to 5. 727 * this is done since all slave UPA devices have historically 728 * had their PILs set to 5. Only do it if the PIL is not 729 * being preset. 730 */ 731 *(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 5; 732 break; 733 case DDI_INTROP_SETPRI: 734 break; 735 case DDI_INTROP_ADDISR: 736 ret = upa64s_add_intr_impl(dip, rdip, hdlp); 737 break; 738 case DDI_INTROP_REMISR: 739 ret = upa64s_remove_intr_impl(dip, rdip, hdlp); 740 break; 741 case DDI_INTROP_ENABLE: 742 case DDI_INTROP_DISABLE: 743 break; 744 case DDI_INTROP_NINTRS: 745 case DDI_INTROP_NAVAIL: 746 *(int *)result = i_ddi_get_intx_nintrs(rdip); 747 break; 748 case DDI_INTROP_SETCAP: 749 case DDI_INTROP_SETMASK: 750 case DDI_INTROP_CLRMASK: 751 case DDI_INTROP_GETPENDING: 752 ret = DDI_ENOTSUP; 753 break; 754 case DDI_INTROP_SUPPORTED_TYPES: 755 /* only support fixed interrupts */ 756 *(int *)result = i_ddi_get_intx_nintrs(rdip) ? 757 DDI_INTR_TYPE_FIXED : 0; 758 break; 759 default: 760 ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result); 761 break; 762 } 763 764 return (ret); 765 } 766 767 #ifdef DEBUG 768 uint_t upa64s_debug_flags = (uint_t)0; 769 770 extern void prom_printf(const char *, ...); 771 #endif 772 773 /* 774 * control ops entry point: 775 * 776 * Requests handled completely: 777 * DDI_CTLOPS_INITCHILD see init_child() for details 778 * DDI_CTLOPS_UNINITCHILD 779 * DDI_CTLOPS_REPORTDEV see report_dev() for details 780 * DDI_CTLOPS_REGSIZE 781 * DDI_CTLOPS_NREGS 782 * 783 * All others passed to parent. 784 */ 785 static int 786 upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip, 787 ddi_ctl_enum_t op, void *arg, void *result) 788 { 789 DBG5(D_CTLOPS, dip, "dip=%x.%x rdip=%x.%x op=%x", 790 HI32(dip), LO32(dip), HI32(rdip), LO32(rdip), op); 791 DBG4(D_CTLOPS|D_CONT, dip, " arg=%x.%x result=%x.%x\n", 792 HI32(arg), LO32(arg), HI32(result), LO32(result)); 793 794 switch (op) { 795 case DDI_CTLOPS_INITCHILD: 796 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n", 797 ddi_get_name(rdip), ddi_get_instance(rdip)); 798 return (init_child((dev_info_t *)arg)); 799 800 case DDI_CTLOPS_UNINITCHILD: 801 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n", 802 ddi_get_name(rdip), ddi_get_instance(rdip)); 803 ddi_set_name_addr((dev_info_t *)arg, NULL); 804 ddi_remove_minor_node((dev_info_t *)arg, NULL); 805 impl_rem_dev_props((dev_info_t *)arg); 806 return (DDI_SUCCESS); 807 808 case DDI_CTLOPS_REPORTDEV: 809 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n", 810 ddi_get_name(rdip), ddi_get_instance(rdip)); 811 return (report_dev(rdip)); 812 813 case DDI_CTLOPS_REGSIZE: 814 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n", 815 ddi_get_name(rdip), ddi_get_instance(rdip)); 816 *((off_t *)result) = get_reg_set_size(rdip, *((int *)arg)); 817 return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS); 818 819 case DDI_CTLOPS_NREGS: 820 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_NREGS: rdip=%s%d\n", 821 ddi_get_name(rdip), ddi_get_instance(rdip)); 822 *((uint_t *)result) = get_nreg_set(rdip); 823 return (DDI_SUCCESS); 824 } 825 826 /* 827 * Now pass the request up to our parent. 828 */ 829 DBG3(D_CTLOPS, dip, "passing request to parent: rdip=%s%d op=%x\n\n", 830 ddi_get_name(rdip), ddi_get_instance(rdip), op); 831 return (ddi_ctlops(dip, rdip, op, arg, result)); 832 } 833 834 835 /* support routines */ 836 837 /* 838 * get_properties 839 * 840 * This function is called from the attach routine to get the key 841 * properties of the upa64s node. 842 * 843 * used by: upa64s_attach() 844 * 845 * return value: none 846 */ 847 static int 848 get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip) 849 { 850 int safari_id; 851 852 /* 853 * Get the device's safari id. 854 */ 855 safari_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 856 "portid", -1); 857 if (safari_id == -1) { 858 int instance = ddi_get_instance(dip); 859 panic("%s%d: no portid property", ddi_get_name(dip), instance); 860 } 861 upa64s_p->safari_id = safari_id; 862 863 return (DDI_SUCCESS); 864 } 865 866 867 /* 868 * save_state 869 * 870 * This routine saves a copy of the upa64s register state. 871 * 872 * used by: upa64s_detach() on a suspend operation 873 */ 874 static void 875 save_state(upa64s_devstate_t *upa64s_p) 876 { 877 upa64s_p->imr_data[0] = ddi_get64(upa64s_p->imr_ah[0], 878 upa64s_p->imr[0]); 879 upa64s_p->imr_data[1] = ddi_get64(upa64s_p->imr_ah[1], 880 upa64s_p->imr[1]); 881 } 882 883 884 /* 885 * restore_state 886 * 887 * This routine restores a copy of the upa64s register state. 888 * 889 * used by: upa64s_attach() on a resume operation 890 */ 891 static void 892 restore_state(upa64s_devstate_t *upa64s_p) 893 { 894 #ifndef lint 895 volatile uint64_t tmp; 896 #endif 897 ddi_put64(upa64s_p->imr_ah[0], upa64s_p->imr[0], 898 upa64s_p->imr_data[0]); 899 ddi_put64(upa64s_p->imr_ah[1], upa64s_p->imr[1], 900 upa64s_p->imr_data[1]); 901 #ifndef lint 902 /* Flush the store buffer */ 903 tmp = ddi_get64(upa64s_p->imr_ah[0], upa64s_p->imr[0]); 904 tmp = ddi_get64(upa64s_p->imr_ah[1], upa64s_p->imr[1]); 905 #endif 906 } 907 908 909 /* 910 * get_reg_set 911 * 912 * This routine will get a upa64s format regspec for a given 913 * device node and register number. 914 * 915 * used by: upa64s_map() 916 * 917 * return value: 918 * 919 * DDI_SUCCESS - on success 920 * DDI_ME_INVAL - regspec is invalid 921 * DDI_ME_RNUMBER_RANGE - rnumber out of range 922 */ 923 static int 924 get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber, 925 off_t off, off_t len, struct regspec *rp) 926 { 927 upa64s_regspec_t *upa64s_rp; 928 int i, n, rval; 929 930 /* 931 * Get child device "reg" property 932 */ 933 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 934 (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS) 935 return (DDI_ME_RNUMBER_RANGE); 936 937 n = i / (int)sizeof (upa64s_regspec_t); 938 if (rnumber >= n) { 939 kmem_free(upa64s_rp, i); 940 return (DDI_ME_RNUMBER_RANGE); 941 } 942 943 /* 944 * Convert each the upa64s format register specification to 945 * out parent format. 946 */ 947 rval = xlate_reg_prop(dip, &upa64s_rp[rnumber], off, len, rp); 948 kmem_free(upa64s_rp, i); 949 return (rval); 950 } 951 952 953 /* 954 * xlate_reg_prop 955 * 956 * This routine converts a upa64s format regspec to a standard 957 * regspec containing the corresponding system address. 958 * 959 * used by: upa64s_map() 960 * 961 * return value: 962 * 963 * DDI_SUCCESS 964 * DDI_FAILURE - off + len is beyond device address range 965 * DDI_ME_INVAL - regspec is invalid 966 */ 967 static int 968 xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *child_rp, off_t off, 969 off_t len, struct regspec *rp) 970 { 971 int n_ranges, ranges_len, i; 972 uint64_t child_beg, child_end; 973 upa64s_ranges_t *range_p, *rng_p; 974 975 DBG4(D_MAP, dip, "upa64s regspec - ((%x,%x) (%x,%x))\n", 976 HI32(child_rp->upa64s_phys), LO32(child_rp->upa64s_phys), 977 HI32(child_rp->upa64s_size), LO32(child_rp->upa64s_size)); 978 DBG2(D_MAP, dip, "upa64s xlate_reg_prp - off=%lx len=%lx\n", off, len); 979 #if 0 980 /* 981 * both FFB and AFB have broken "reg" properties, all mapping 982 * requests are done through reg-0 with very long offsets. 983 * Hence this safety check is always violated. 984 */ 985 if (off + len > child_rp->upa64s_size) { 986 DBG(D_MAP, dip, "upa64s xlate_reg_prp: bad off + len\n"); 987 return (DDI_FAILURE); 988 } 989 #endif 990 /* 991 * current "struct regspec" only supports 32-bit sizes. 992 */ 993 if (child_rp->upa64s_size >= (1ull << 32)) 994 panic("upa64s: reg size must be less than 4 Gb"); 995 996 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 997 "ranges", (caddr_t)&range_p, &ranges_len) != DDI_SUCCESS) { 998 ranges_len = 0; 999 cmn_err(CE_WARN, "%s%d: no ranges property", 1000 ddi_get_name(dip), ddi_get_instance(dip)); 1001 } 1002 1003 n_ranges = ranges_len / sizeof (upa64s_regspec_t); 1004 child_beg = child_rp->upa64s_phys; 1005 #if 0 1006 /* 1007 * again, this safety checking can not be performed. 1008 * Hack by adding a pratical max child reg bank length. 1009 */ 1010 child_end = child_beg + child_rp->upa64s_size; 1011 #else 1012 #define UPA64S_MAX_CHILD_LEN 0xe000000 1013 child_end = child_beg + UPA64S_MAX_CHILD_LEN; 1014 #endif 1015 for (i = 0, rng_p = range_p; i < n_ranges; i++, rng_p++) { 1016 uint64_t rng_beg = rng_p->upa64s_child; 1017 uint64_t rng_end = rng_beg + rng_p->upa64s_size; 1018 if ((rng_beg <= child_beg) && (rng_end >= child_end)) { 1019 uint64_t addr = child_beg - rng_beg + off; 1020 addr += rng_p->upa64s_parent; 1021 rp->regspec_bustype = HI32(addr); 1022 rp->regspec_addr = LO32(addr); 1023 rp->regspec_size = len ? len : child_rp->upa64s_size; 1024 break; 1025 } 1026 } 1027 if (ranges_len) 1028 kmem_free(range_p, ranges_len); 1029 DBG4(D_MAP, dip, "regspec (%x,%x,%x) i=%x\n", 1030 rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, i); 1031 return (i < n_ranges? DDI_SUCCESS : DDI_ME_INVAL); 1032 } 1033 1034 1035 /* 1036 * report_dev 1037 * 1038 * This function is called from our control ops routine on a 1039 * DDI_CTLOPS_REPORTDEV request. 1040 */ 1041 static int 1042 report_dev(dev_info_t *dip) 1043 { 1044 if (dip == (dev_info_t *)0) 1045 return (DDI_FAILURE); 1046 cmn_err(CE_CONT, "?UPA64S-device: %s@%s, %s #%d\n", 1047 ddi_node_name(dip), ddi_get_name_addr(dip), 1048 ddi_major_to_name(ddi_name_to_major(ddi_get_name(dip))), 1049 ddi_get_instance(dip)); 1050 return (DDI_SUCCESS); 1051 } 1052 1053 1054 /* 1055 * init_child 1056 * 1057 * This function is called from our control ops routine on a 1058 * DDI_CTLOPS_INITCHILD request. It builds and sets the device's 1059 * parent private data area. 1060 * 1061 * used by: upa64s_ctlops() 1062 * 1063 * return value: none 1064 */ 1065 static int 1066 init_child(dev_info_t *child) 1067 { 1068 upa64s_regspec_t *child_rp; 1069 int i; 1070 char addr[256]; 1071 int32_t portid; 1072 1073 if ((portid = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 1074 "upa-portid", -1)) == -1) 1075 return (DDI_FAILURE); 1076 1077 /* 1078 * Set the address portion of the node name based on 1079 * the function and device number. 1080 */ 1081 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 1082 (caddr_t)&child_rp, &i) != DDI_SUCCESS) { 1083 return (DDI_FAILURE); 1084 } 1085 1086 (void) sprintf(addr, "%x,%x", portid, LO32(child_rp->upa64s_phys)); 1087 ddi_set_name_addr(child, addr); 1088 1089 ddi_set_parent_data(child, NULL); 1090 kmem_free(child_rp, i); 1091 return (DDI_SUCCESS); 1092 } 1093 1094 1095 /* 1096 * get_reg_set_size 1097 * 1098 * Given a dev info pointer to a child and a register number, this 1099 * routine returns the size element of that reg set property. 1100 * 1101 * used by: upa64s_ctlops() - DDI_CTLOPS_REGSIZE 1102 * 1103 * return value: size of reg set on success, -1 on error 1104 */ 1105 static off_t 1106 get_reg_set_size(dev_info_t *child, int rnumber) 1107 { 1108 upa64s_regspec_t *upa64s_rp; 1109 uint_t size; 1110 int i; 1111 1112 if (rnumber < 0) 1113 return (-1); 1114 1115 /* 1116 * Get the reg property for the device. 1117 */ 1118 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 1119 (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS) 1120 return (-1); 1121 1122 if (rnumber >= (i / (int)sizeof (upa64s_regspec_t))) { 1123 kmem_free(upa64s_rp, i); 1124 return (-1); 1125 } 1126 1127 /* >4G reg size not supported */ 1128 size = (uint32_t)upa64s_rp[rnumber].upa64s_size; 1129 kmem_free(upa64s_rp, i); 1130 return (size); 1131 } 1132 1133 1134 /* 1135 * get_nreg_set 1136 * 1137 * Given a dev info pointer to a child, this routine returns the 1138 * number of sets in its "reg" property. 1139 * 1140 * used by: upa64s_ctlops() - DDI_CTLOPS_NREGS 1141 * 1142 * return value: # of reg sets on success, zero on error 1143 */ 1144 static uint_t 1145 get_nreg_set(dev_info_t *child) 1146 { 1147 upa64s_regspec_t *upa64s_rp; 1148 int i, n; 1149 1150 /* 1151 * Get the reg property for the device. 1152 */ 1153 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 1154 (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS) 1155 return (0); 1156 1157 n = i / (int)sizeof (upa64s_regspec_t); 1158 kmem_free(upa64s_rp, i); 1159 return (n); 1160 } 1161 1162 1163 /* 1164 * upa64s_intrdist 1165 * 1166 * The following routine is the callback function for this nexus driver 1167 * to support interrupt distribution on sun4u systems. When this 1168 * function is called by the interrupt distribution framework, it will 1169 * reprogram all the active the mondo registers. 1170 */ 1171 static void 1172 upa64s_intrdist(void *arg) 1173 { 1174 dev_info_t *dip = (dev_info_t *)arg; 1175 int instance = ddi_get_instance(dip); 1176 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 1177 uint_t upaport; 1178 1179 for (upaport = 0; upaport < UPA64S_PORTS; upaport++) { 1180 volatile uint64_t *imr; 1181 volatile uint64_t imr_dat; 1182 uint_t mondo; 1183 uint32_t cpuid; 1184 1185 if (upa64s_p->ino_state[upaport] != INO_INUSE) 1186 continue; 1187 1188 imr = upa64s_p->imr[upaport]; 1189 mondo = UPA64S_IMR_TO_MONDO(*imr); 1190 cpuid = intr_dist_cpuid(); 1191 imr_dat = UPA64S_CPUID_TO_IMR(cpuid); 1192 imr_dat = UPA64S_GET_MAP_REG(mondo, imr_dat); 1193 1194 /* Check and re-program cpu target if necessary */ 1195 DBG2(D_INTRDIST, dip, "mondo=%x cpuid=%x\n", mondo, cpuid); 1196 if (UPA64S_IMR_TO_CPUID(*imr) == cpuid) { 1197 DBG(D_INTRDIST, dip, "same cpuid\n"); 1198 continue; 1199 } 1200 ddi_put64(upa64s_p->imr_ah[upaport], (uint64_t *)imr, imr_dat); 1201 imr_dat = ddi_get64(upa64s_p->imr_ah[upaport], (uint64_t *)imr); 1202 } 1203 } 1204 1205 1206 #ifdef DEBUG 1207 static void 1208 upa64s_debug(uint_t flag, dev_info_t *dip, char *fmt, 1209 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) 1210 { 1211 char *s = NULL; 1212 uint_t cont = 0; 1213 if (flag & D_CONT) { 1214 flag &= ~D_CONT; 1215 cont = 1; 1216 } 1217 if (!(upa64s_debug_flags & flag)) 1218 return; 1219 1220 switch (flag) { 1221 case D_ATTACH: s = "attach"; break; 1222 case D_DETACH: s = "detach"; break; 1223 case D_POWER: s = "power"; break; 1224 case D_MAP: s = "map"; break; 1225 case D_CTLOPS: s = "ctlops"; break; 1226 case D_G_ISPEC: s = "get_intrspec"; break; 1227 case D_A_ISPEC: s = "add_intrspec"; break; 1228 case D_R_ISPEC: s = "remove_intrspec"; break; 1229 case D_INIT_CLD: s = "init_child"; break; 1230 case D_INTRDIST: s = "intrdist"; break; 1231 } 1232 1233 if (s && cont == 0) { 1234 prom_printf("%s(%d): %s: ", ddi_get_name(dip), 1235 ddi_get_instance(dip), s); 1236 } 1237 prom_printf(fmt, a1, a2, a3, a4, a5); 1238 } 1239 #endif 1240