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