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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * fcgp2.c: Framework gp2 (Safari) fcode ops 29 */ 30 #include <sys/types.h> 31 #include <sys/kmem.h> 32 #include <sys/systm.h> 33 #include <sys/pci.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/sunndi.h> 37 #include <sys/ddidmareq.h> 38 #include <sys/modctl.h> 39 #include <sys/ndi_impldefs.h> 40 #include <sys/fcode.h> 41 #include <sys/promif.h> 42 #include <sys/promimpl.h> 43 44 static int gfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 45 static int gfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 46 static int gfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 47 static int gfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); 48 static int gfc_claim_address(dev_info_t *, fco_handle_t, fc_ci_t *); 49 static int gfc_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 50 static int gfc_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 51 static int gfc_vtop(dev_info_t *, fco_handle_t, fc_ci_t *); 52 static int gfc_master_intr(dev_info_t *, fco_handle_t, fc_ci_t *); 53 54 static int gfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); 55 56 static int gfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); 57 static int gfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); 58 59 int prom_get_fcode_size(char *); 60 int prom_get_fcode(char *, char *); 61 62 int fcpci_unloadable; 63 int no_advisory_dma; 64 65 #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32)) 66 #define LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 67 #define LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo)) 68 #define PCI_4GIG_LIMIT 0xFFFFFFFFUL 69 70 71 /* 72 * Module linkage information for the kernel. 73 */ 74 static struct modlmisc modlmisc = { 75 &mod_miscops, "FCode gp2 (safari) bus functions" 76 }; 77 78 static struct modlinkage modlinkage = { 79 MODREV_1, (void *)&modlmisc, NULL 80 }; 81 82 int 83 _init(void) 84 { 85 return (mod_install(&modlinkage)); 86 } 87 88 int 89 _fini(void) 90 { 91 if (fcpci_unloadable) 92 return (mod_remove(&modlinkage)); 93 return (EBUSY); 94 } 95 96 int 97 _info(struct modinfo *modinfop) 98 { 99 return (mod_info(&modlinkage, modinfop)); 100 } 101 102 103 struct gfc_ops_v { 104 char *svc_name; 105 fc_ops_t *f; 106 }; 107 108 struct gfc_ops_v gp2_pov[] = { 109 { "map-in", gfc_map_in}, 110 { "map-out", gfc_map_out}, 111 { "rx@", gfc_register_fetch}, 112 { "rl@", gfc_register_fetch}, 113 { "rw@", gfc_register_fetch}, 114 { "rb@", gfc_register_fetch}, 115 { "rx!", gfc_register_store}, 116 { "rl!", gfc_register_store}, 117 { "rw!", gfc_register_store}, 118 { "rb!", gfc_register_store}, 119 { "claim-address", gfc_claim_address}, 120 { "master-interrupt", gfc_master_intr}, 121 { "claim-memory", gfc_claim_memory}, 122 { "release-memory", gfc_release_memory}, 123 { "vtop", gfc_vtop}, 124 { FC_CONFIG_CHILD, gfc_config_child}, 125 { FC_GET_FCODE_SIZE, gfc_get_fcode_size}, 126 { FC_GET_FCODE, gfc_get_fcode}, 127 { NULL, NULL} 128 }; 129 130 struct gfc_ops_v gp2_shared_pov[] = { 131 { NULL, NULL} 132 }; 133 134 static int gp2_map_phys(dev_info_t *, struct regspec *, caddr_t *, 135 ddi_device_acc_attr_t *, ddi_acc_handle_t *); 136 static void gp2_unmap_phys(ddi_acc_handle_t *); 137 138 fco_handle_t 139 gp2_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child, 140 void *fcode, size_t fcode_size, char *unit_address, 141 char *my_args) 142 { 143 fco_handle_t rp; 144 phandle_t h; 145 146 rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 147 rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size, 148 unit_address, NULL); 149 rp->ap = ap; 150 rp->child = child; 151 rp->fcode = fcode; 152 rp->fcode_size = fcode_size; 153 rp->my_args = my_args; 154 155 if (unit_address) { 156 char *buf; 157 158 buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP); 159 (void) strcpy(buf, unit_address); 160 rp->unit_address = buf; 161 } 162 163 /* 164 * Add the child's nodeid to our table... 165 */ 166 h = ddi_get_nodeid(rp->child); 167 fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 168 169 return (rp); 170 } 171 172 void 173 gp2_fc_ops_free_handle(fco_handle_t rp) 174 { 175 struct fc_resource *ip, *np; 176 177 ASSERT(rp); 178 179 if (rp->next_handle) 180 fc_ops_free_handle(rp->next_handle); 181 if (rp->unit_address) 182 kmem_free(rp->unit_address, strlen(rp->unit_address) + 1); 183 if (rp->my_args != NULL) 184 kmem_free(rp->my_args, strlen(rp->my_args) + 1); 185 186 /* 187 * Release all the resources from the resource list 188 */ 189 for (ip = rp->head; ip != NULL; ip = np) { 190 np = ip->next; 191 switch (ip->type) { 192 case RT_MAP: 193 FC_DEBUG1(1, CE_CONT, "gp2_fc_ops_free: " 194 " map handle - %p\n", ip->fc_map_handle); 195 break; 196 case RT_DMA: 197 /* DMA has to be freed up at exit time */ 198 cmn_err(CE_CONT, "gfc_fc_ops_free: DMA seen!\n"); 199 break; 200 case RT_CONTIGIOUS: 201 FC_DEBUG2(1, CE_CONT, "gp2_fc_ops_free: " 202 "Free claim-memory resource 0x%lx size 0x%x\n", 203 ip->fc_contig_virt, ip->fc_contig_len); 204 205 (void) ndi_ra_free(ddi_root_node(), 206 (uint64_t)ip->fc_contig_virt, 207 ip->fc_contig_len, "gptwo-contigousmem", 208 NDI_RA_PASS); 209 210 break; 211 default: 212 cmn_err(CE_CONT, "gp2_fc_ops_free: " 213 "unknown resource type %d\n", ip->type); 214 break; 215 } 216 fc_rem_resource(rp, ip); 217 kmem_free(ip, sizeof (struct fc_resource)); 218 } 219 kmem_free(rp, sizeof (struct fc_resource_list)); 220 } 221 222 int 223 gp2_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 224 { 225 struct gfc_ops_v *pv; 226 char *name = fc_cell2ptr(cp->svc_name); 227 228 ASSERT(rp); 229 230 /* 231 * First try the generic fc_ops. If the ops is a shared op, 232 * also call our local function. 233 */ 234 if (fc_ops(ap, rp->next_handle, cp) == 0) { 235 for (pv = gp2_shared_pov; pv->svc_name != NULL; ++pv) 236 if (strcmp(pv->svc_name, name) == 0) 237 return (pv->f(ap, rp, cp)); 238 return (0); 239 } 240 241 for (pv = gp2_pov; pv->svc_name != NULL; ++pv) 242 if (strcmp(pv->svc_name, name) == 0) 243 return (pv->f(ap, rp, cp)); 244 245 FC_DEBUG1(9, CE_CONT, "gp2_fc_ops: <%s> not serviced\n", name); 246 247 return (-1); 248 } 249 250 /* 251 * map-in (phys.lo phys.hi size -- virt ) 252 */ 253 static int 254 gfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 255 { 256 size_t len; 257 int error; 258 caddr_t virt; 259 struct fc_resource *ip; 260 struct regspec r; 261 ddi_device_acc_attr_t acc; 262 ddi_acc_handle_t h; 263 264 if (fc_cell2int(cp->nargs) != 3) 265 return (fc_syntax_error(cp, "nargs must be 3")); 266 267 if (fc_cell2int(cp->nresults) < 1) 268 return (fc_syntax_error(cp, "nresults must be >= 1")); 269 270 r.regspec_size = len = fc_cell2size(fc_arg(cp, 0)); 271 r.regspec_bustype = fc_cell2uint(fc_arg(cp, 1)); 272 r.regspec_addr = fc_cell2uint(fc_arg(cp, 2)); 273 274 acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 275 acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 276 acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 277 278 FC_DEBUG3(1, CE_CONT, "gfc_map_in: attempting map in " 279 "address 0x%08x.%08x length %x\n", r.regspec_bustype, 280 r.regspec_addr, r.regspec_size); 281 282 error = gp2_map_phys(rp->child, &r, &virt, &acc, &h); 283 284 if (error) { 285 FC_DEBUG3(1, CE_CONT, "gfc_map_in: map in failed - " 286 "address 0x%08x.%08x length %x\n", r.regspec_bustype, 287 r.regspec_addr, r.regspec_size); 288 289 return (fc_priv_error(cp, "gp2 map-in failed")); 290 } 291 292 FC_DEBUG1(3, CE_CONT, "gp2_map_in: returning virt %p\n", virt); 293 294 cp->nresults = fc_int2cell(1); 295 fc_result(cp, 0) = fc_ptr2cell(virt); 296 297 /* 298 * Log this resource ... 299 */ 300 ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 301 ip->type = RT_MAP; 302 ip->fc_map_virt = virt; 303 ip->fc_map_len = len; 304 ip->fc_map_handle = h; 305 fc_add_resource(rp, ip); 306 307 return (fc_success_op(ap, rp, cp)); 308 } 309 310 /* 311 * map-out ( virt size -- ) 312 */ 313 static int 314 gfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 315 { 316 caddr_t virt; 317 size_t len; 318 struct fc_resource *ip; 319 320 if (fc_cell2int(cp->nargs) != 2) 321 return (fc_syntax_error(cp, "nargs must be 2")); 322 323 virt = fc_cell2ptr(fc_arg(cp, 1)); 324 325 len = fc_cell2size(fc_arg(cp, 0)); 326 327 FC_DEBUG2(1, CE_CONT, "gp2_map_out: attempting map out %p %x\n", 328 virt, len); 329 330 /* 331 * Find if this request matches a mapping resource we set up. 332 */ 333 fc_lock_resource_list(rp); 334 for (ip = rp->head; ip != NULL; ip = ip->next) { 335 if (ip->type != RT_MAP) 336 continue; 337 if (ip->fc_map_virt != virt) 338 continue; 339 if (ip->fc_map_len == len) 340 break; 341 } 342 fc_unlock_resource_list(rp); 343 344 if (ip == NULL) 345 return (fc_priv_error(cp, "request doesn't match a " 346 "known mapping")); 347 348 gp2_unmap_phys(&ip->fc_map_handle); 349 350 /* 351 * remove the resource from the list and release it. 352 */ 353 fc_rem_resource(rp, ip); 354 kmem_free(ip, sizeof (struct fc_resource)); 355 356 cp->nresults = fc_int2cell(0); 357 return (fc_success_op(ap, rp, cp)); 358 } 359 360 static int 361 gfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 362 { 363 size_t len; 364 caddr_t virt; 365 int error = 0; 366 uint64_t x; 367 uint32_t l; 368 uint16_t w; 369 uint8_t b; 370 char *name = fc_cell2ptr(cp->svc_name); 371 struct fc_resource *ip; 372 373 if (fc_cell2int(cp->nargs) != 1) 374 return (fc_syntax_error(cp, "nargs must be 1")); 375 376 if (fc_cell2int(cp->nresults) < 1) 377 return (fc_syntax_error(cp, "nresults must be >= 1")); 378 379 virt = fc_cell2ptr(fc_arg(cp, 0)); 380 381 /* 382 * Determine the access width .. we can switch on the 2nd 383 * character of the name which is "rx@", "rl@", "rb@" or "rw@" 384 */ 385 switch (*(name + 1)) { 386 case 'x': len = sizeof (x); break; 387 case 'l': len = sizeof (l); break; 388 case 'w': len = sizeof (w); break; 389 case 'b': len = sizeof (b); break; 390 } 391 392 /* 393 * Check the alignment ... 394 */ 395 if (((intptr_t)virt & (len - 1)) != 0) 396 return (fc_priv_error(cp, "unaligned access")); 397 398 /* 399 * Find if this virt is 'within' a request we know about 400 */ 401 fc_lock_resource_list(rp); 402 for (ip = rp->head; ip != NULL; ip = ip->next) { 403 if (ip->type == RT_MAP) { 404 if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 405 ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 406 break; 407 } else if (ip->type == RT_CONTIGIOUS) { 408 if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len) 409 <= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len))) 410 break; 411 } 412 } 413 fc_unlock_resource_list(rp); 414 415 if (ip == NULL) { 416 return (fc_priv_error(cp, "request not within a " 417 "known mapping or contigious adddress")); 418 } 419 420 switch (len) { 421 case sizeof (x): 422 if (ip->type == RT_MAP) 423 error = ddi_peek64(rp->child, 424 (int64_t *)virt, (int64_t *)&x); 425 else /* RT_CONTIGIOUS */ 426 x = *(int64_t *)virt; 427 break; 428 case sizeof (l): 429 if (ip->type == RT_MAP) 430 error = ddi_peek32(rp->child, 431 (int32_t *)virt, (int32_t *)&l); 432 else /* RT_CONTIGIOUS */ 433 l = *(int32_t *)virt; 434 break; 435 case sizeof (w): 436 if (ip->type == RT_MAP) 437 error = ddi_peek16(rp->child, 438 (int16_t *)virt, (int16_t *)&w); 439 else /* RT_CONTIGIOUS */ 440 w = *(int16_t *)virt; 441 break; 442 case sizeof (b): 443 if (ip->type == RT_MAP) 444 error = ddi_peek8(rp->child, 445 (int8_t *)virt, (int8_t *)&b); 446 else /* RT_CONTIGIOUS */ 447 b = *(int8_t *)virt; 448 break; 449 } 450 451 if (error) { 452 FC_DEBUG2(1, CE_CONT, "gfc_register_fetch: access error " 453 "accessing virt %p len %d\n", virt, len); 454 return (fc_priv_error(cp, "access error")); 455 } 456 457 cp->nresults = fc_int2cell(1); 458 switch (len) { 459 case sizeof (x): fc_result(cp, 0) = x; break; 460 case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 461 case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 462 case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 463 } 464 return (fc_success_op(ap, rp, cp)); 465 } 466 467 static int 468 gfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 469 { 470 size_t len; 471 caddr_t virt; 472 uint64_t x; 473 uint32_t l; 474 uint16_t w; 475 uint8_t b; 476 char *name = fc_cell2ptr(cp->svc_name); 477 struct fc_resource *ip; 478 int error = 0; 479 480 if (fc_cell2int(cp->nargs) != 2) 481 return (fc_syntax_error(cp, "nargs must be 2")); 482 483 virt = fc_cell2ptr(fc_arg(cp, 0)); 484 485 /* 486 * Determine the access width .. we can switch on the 2nd 487 * character of the name which is "rx!", "rl!", "rb!" or "rw!" 488 */ 489 switch (*(name + 1)) { 490 case 'x': len = sizeof (x); x = fc_arg(cp, 1); break; 491 case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break; 492 case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break; 493 case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break; 494 } 495 496 /* 497 * Check the alignment ... 498 */ 499 if (((intptr_t)virt & (len - 1)) != 0) 500 return (fc_priv_error(cp, "unaligned access")); 501 502 /* 503 * Find if this virt is 'within' a request we know about 504 */ 505 fc_lock_resource_list(rp); 506 for (ip = rp->head; ip != NULL; ip = ip->next) { 507 if (ip->type == RT_MAP) { 508 if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 509 ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 510 break; 511 } else if (ip->type == RT_CONTIGIOUS) { 512 if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len) 513 <= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len))) 514 break; 515 } 516 } 517 fc_unlock_resource_list(rp); 518 519 if (ip == NULL) 520 return (fc_priv_error(cp, "request not within a " 521 "known mapping or contigious address")); 522 523 switch (len) { 524 case sizeof (x): 525 if (ip->type == RT_MAP) 526 error = ddi_poke64(rp->child, (int64_t *)virt, x); 527 else if (ip->type == RT_CONTIGIOUS) 528 *(uint64_t *)virt = x; 529 break; 530 case sizeof (l): 531 if (ip->type == RT_MAP) 532 error = ddi_poke32(rp->child, (int32_t *)virt, l); 533 else if (ip->type == RT_CONTIGIOUS) 534 *(uint32_t *)virt = l; 535 break; 536 case sizeof (w): 537 if (ip->type == RT_MAP) 538 error = ddi_poke16(rp->child, (int16_t *)virt, w); 539 else if (ip->type == RT_CONTIGIOUS) 540 *(uint16_t *)virt = w; 541 break; 542 case sizeof (b): 543 if (ip->type == RT_MAP) 544 error = ddi_poke8(rp->child, (int8_t *)virt, b); 545 else if (ip->type == RT_CONTIGIOUS) 546 *(uint8_t *)virt = b; 547 break; 548 } 549 550 if (error == DDI_FAILURE) { 551 FC_DEBUG2(1, CE_CONT, "gfc_register_store: access error " 552 "accessing virt %p len %d\n", virt, len); 553 return (fc_priv_error(cp, "access error")); 554 } 555 556 cp->nresults = fc_int2cell(0); 557 return (fc_success_op(ap, rp, cp)); 558 } 559 560 static int 561 gfc_master_intr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 562 { 563 int xt, portid; 564 565 if (fc_cell2int(cp->nargs) != 2) 566 return (fc_syntax_error(cp, "nargs must be 4")); 567 568 if (fc_cell2int(cp->nresults) < 1) 569 return (fc_syntax_error(cp, "nresults must be >= 1")); 570 571 xt = fc_cell2int(fc_arg(cp, 1)); 572 portid = fc_cell2int(fc_arg(cp, 0)); 573 574 FC_DEBUG2(1, CE_CONT, "gfc_master_intr: reset-int-xt=%x portid=%x", 575 xt, portid); 576 577 cp->nresults = fc_int2cell(1); 578 fc_result(cp, 0) = 0; 579 580 return (fc_success_op(ap, rp, cp)); 581 } 582 583 /* 584 * gfc_claim_address 585 * 586 * claim-address (size.lo size.hi type align bar portid -- base.lo base.hi ) 587 */ 588 static int 589 gfc_claim_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 590 { 591 int bar, portid; 592 uint64_t exp, slot, port, slice; 593 uint64_t paddr; 594 595 if (fc_cell2int(cp->nargs) != 6) 596 return (fc_syntax_error(cp, "nargs must be 6")); 597 598 if (fc_cell2int(cp->nresults) < 2) 599 return (fc_syntax_error(cp, "nresults must be 2")); 600 601 bar = fc_cell2int(fc_arg(cp, 1)); 602 portid = fc_cell2int(fc_arg(cp, 0)); 603 604 exp = portid >> 5; 605 slot = (0x8 & portid) >> 3; 606 port = portid & 0x1; 607 608 switch (bar) { 609 case 0: /* PCI IO Bus A */ 610 paddr = (exp << 28) | (port << 26) | (slot << 27) | 611 ((uint64_t)0x402 << 32); 612 613 break; 614 case 1: /* PCI Memory Bus A */ 615 slice = (exp * 2) + slot + 1; 616 617 paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) | 618 ((uint64_t)port << 33); 619 620 break; 621 case 2: /* PCI IO Bus B */ 622 paddr = (exp << 28) | (port << 26) | (slot << 27) | 623 ((uint64_t)0x402 << 32) | (1 << 25); 624 625 break; 626 case 3: /* PCI Memory Bus B */ 627 slice = (exp * 2) + slot + 1; 628 629 paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) | 630 ((uint64_t)port << 33); 631 632 paddr |= ((uint64_t)1 << 32); 633 634 break; 635 default: 636 cmn_err(CE_WARN, 637 "gfc_claim_address - invalid BAR=0x%x\n", bar); 638 639 return (fc_syntax_error(cp, "invalid argument")); 640 } 641 642 FC_DEBUG1(1, CE_CONT, "gfc_claim_address: returning 0x%lx\n", paddr); 643 644 cp->nresults = fc_int2cell(2); 645 fc_result(cp, 0) = LOADDR(paddr); 646 fc_result(cp, 1) = HIADDR(paddr); 647 648 return (fc_success_op(ap, rp, cp)); 649 } 650 651 /* 652 * gfc_claim_memory 653 * 654 * claim-memory ( align size vhint -- vaddr) 655 */ 656 static int 657 gfc_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 658 { 659 int align, size, vhint; 660 ndi_ra_request_t request; 661 uint64_t answer, alen; 662 struct fc_resource *ip; 663 664 if (fc_cell2int(cp->nargs) != 3) 665 return (fc_syntax_error(cp, "nargs must be 3")); 666 667 if (fc_cell2int(cp->nresults) < 1) 668 return (fc_syntax_error(cp, "nresults must be >= 1")); 669 670 vhint = fc_cell2int(fc_arg(cp, 2)); 671 size = fc_cell2int(fc_arg(cp, 1)); 672 align = fc_cell2int(fc_arg(cp, 0)); 673 674 FC_DEBUG3(1, CE_CONT, "gfc_claim_memory: align=0x%x size=0x%x " 675 "vhint=0x%x\n", align, size, vhint); 676 677 if (size == 0) { 678 cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate " 679 "contigiuos memory of size zero\n"); 680 return (fc_priv_error(cp, "allocation error")); 681 } 682 683 if (vhint) { 684 cmn_err(CE_WARN, "gfc_claim_memory - vhint is not zero " 685 "vhint=0x%x - Ignoring Argument\n", vhint); 686 } 687 688 bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 689 request.ra_flags = NDI_RA_ALLOC_BOUNDED; 690 request.ra_boundbase = 0; 691 request.ra_boundlen = 0xffffffff; 692 request.ra_len = size; 693 request.ra_align_mask = align - 1; 694 695 if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen, 696 "gptwo-contigousmem", NDI_RA_PASS) != NDI_SUCCESS) { 697 cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate " 698 "contigiuos memory\n"); 699 return (fc_priv_error(cp, "allocation error")); 700 701 } 702 703 FC_DEBUG2(1, CE_CONT, "gfc_claim_memory: address allocated=0x%lx " 704 "size=0x%x\n", answer, alen); 705 706 cp->nresults = fc_int2cell(1); 707 fc_result(cp, 0) = answer; 708 709 /* 710 * Log this resource ... 711 */ 712 ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 713 ip->type = RT_CONTIGIOUS; 714 ip->fc_contig_virt = (void *)answer; 715 ip->fc_contig_len = size; 716 fc_add_resource(rp, ip); 717 718 return (fc_success_op(ap, rp, cp)); 719 } 720 721 /* 722 * gfc_release_memory 723 * 724 * release-memory ( size vaddr -- ) 725 */ 726 static int 727 gfc_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 728 { 729 int32_t vaddr, size; 730 struct fc_resource *ip; 731 732 if (fc_cell2int(cp->nargs) != 2) 733 return (fc_syntax_error(cp, "nargs must be 2")); 734 735 if (fc_cell2int(cp->nresults) != 0) 736 return (fc_syntax_error(cp, "nresults must be 0")); 737 738 vaddr = fc_cell2int(fc_arg(cp, 1)); 739 size = fc_cell2int(fc_arg(cp, 0)); 740 741 FC_DEBUG2(1, CE_CONT, "gfc_release_memory: vaddr=0x%x size=0x%x\n", 742 vaddr, size); 743 /* 744 * Find if this request matches a mapping resource we set up. 745 */ 746 fc_lock_resource_list(rp); 747 for (ip = rp->head; ip != NULL; ip = ip->next) { 748 if (ip->type != RT_CONTIGIOUS) 749 continue; 750 if (ip->fc_contig_virt != (void *)(uintptr_t)vaddr) 751 continue; 752 if (ip->fc_contig_len == size) 753 break; 754 } 755 fc_unlock_resource_list(rp); 756 757 if (ip == NULL) 758 return (fc_priv_error(cp, "request doesn't match a " 759 "known mapping")); 760 761 (void) ndi_ra_free(ddi_root_node(), vaddr, size, 762 "gptwo-contigousmem", NDI_RA_PASS); 763 764 /* 765 * remove the resource from the list and release it. 766 */ 767 fc_rem_resource(rp, ip); 768 kmem_free(ip, sizeof (struct fc_resource)); 769 770 cp->nresults = fc_int2cell(0); 771 772 return (fc_success_op(ap, rp, cp)); 773 } 774 775 /* 776 * gfc_vtop 777 * 778 * vtop ( vaddr -- paddr.lo paddr.hi) 779 */ 780 static int 781 gfc_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 782 { 783 int vaddr; 784 uint64_t paddr; 785 struct fc_resource *ip; 786 787 if (fc_cell2int(cp->nargs) != 1) 788 return (fc_syntax_error(cp, "nargs must be 1")); 789 790 if (fc_cell2int(cp->nresults) >= 3) 791 return (fc_syntax_error(cp, "nresults must be less than 2")); 792 793 vaddr = fc_cell2int(fc_arg(cp, 0)); 794 795 /* 796 * Find if this request matches a mapping resource we set up. 797 */ 798 fc_lock_resource_list(rp); 799 for (ip = rp->head; ip != NULL; ip = ip->next) { 800 if (ip->type != RT_CONTIGIOUS) 801 continue; 802 if (ip->fc_contig_virt == (void *)(uintptr_t)vaddr) 803 break; 804 } 805 fc_unlock_resource_list(rp); 806 807 if (ip == NULL) 808 return (fc_priv_error(cp, "request doesn't match a " 809 "known mapping")); 810 811 812 paddr = va_to_pa((void *)(uintptr_t)vaddr); 813 814 FC_DEBUG2(1, CE_CONT, "gfc_vtop: vaddr=0x%x paddr=0x%x\n", 815 vaddr, paddr); 816 817 cp->nresults = fc_int2cell(2); 818 819 fc_result(cp, 0) = paddr; 820 fc_result(cp, 1) = 0; 821 822 return (fc_success_op(ap, rp, cp)); 823 } 824 825 static int 826 gfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 827 { 828 fc_phandle_t h; 829 830 if (fc_cell2int(cp->nargs) != 0) 831 return (fc_syntax_error(cp, "nargs must be 0")); 832 833 if (fc_cell2int(cp->nresults) < 1) 834 return (fc_syntax_error(cp, "nresults must be >= 1")); 835 836 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 837 838 cp->nresults = fc_int2cell(1); 839 fc_result(cp, 0) = fc_phandle2cell(h); 840 841 return (fc_success_op(ap, rp, cp)); 842 } 843 844 static int 845 gfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 846 { 847 caddr_t name_virt, fcode_virt; 848 char *name, *fcode; 849 int fcode_len, status; 850 851 if (fc_cell2int(cp->nargs) != 3) 852 return (fc_syntax_error(cp, "nargs must be 3")); 853 854 if (fc_cell2int(cp->nresults) < 1) 855 return (fc_syntax_error(cp, "nresults must be >= 1")); 856 857 name_virt = fc_cell2ptr(fc_arg(cp, 0)); 858 859 fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 860 861 fcode_len = fc_cell2int(fc_arg(cp, 2)); 862 863 name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 864 865 if (copyinstr(fc_cell2ptr(name_virt), name, 866 FC_SVC_NAME_LEN - 1, NULL)) { 867 FC_DEBUG1(1, CE_CONT, "gfc_get_fcode: " 868 "fault copying in drop in name %p\n", name_virt); 869 status = 0; 870 } else { 871 872 fcode = kmem_zalloc(fcode_len, KM_SLEEP); 873 874 if ((status = prom_get_fcode(name, fcode)) != 0) { 875 876 if (copyout((void *)fcode, (void *)fcode_virt, 877 fcode_len)) { 878 cmn_err(CE_WARN, " gfc_get_fcode: Unable " 879 "to copy out fcode image\n"); 880 status = 0; 881 } 882 } 883 884 kmem_free(fcode, fcode_len); 885 } 886 887 kmem_free(name, FC_SVC_NAME_LEN); 888 889 cp->nresults = fc_int2cell(1); 890 fc_result(cp, 0) = status; 891 892 return (fc_success_op(ap, rp, cp)); 893 } 894 895 static int 896 gfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 897 { 898 caddr_t virt; 899 char *name; 900 int len; 901 902 if (fc_cell2int(cp->nargs) != 1) 903 return (fc_syntax_error(cp, "nargs must be 1")); 904 905 if (fc_cell2int(cp->nresults) < 1) 906 return (fc_syntax_error(cp, "nresults must be >= 1")); 907 908 virt = fc_cell2ptr(fc_arg(cp, 0)); 909 910 name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 911 912 if (copyinstr(fc_cell2ptr(virt), name, 913 FC_SVC_NAME_LEN - 1, NULL)) { 914 FC_DEBUG1(1, CE_CONT, "gfc_get_fcode_size: " 915 "fault copying in drop in name %p\n", virt); 916 len = 0; 917 } else { 918 919 len = prom_get_fcode_size(name); 920 } 921 922 kmem_free(name, FC_SVC_NAME_LEN); 923 924 cp->nresults = fc_int2cell(1); 925 fc_result(cp, 0) = len; 926 927 return (fc_success_op(ap, rp, cp)); 928 } 929 930 static int 931 gp2_map_phys(dev_info_t *dip, struct regspec *phys_spec, 932 caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 933 ddi_acc_handle_t *handlep) 934 { 935 ddi_map_req_t mr; 936 ddi_acc_hdl_t *hp; 937 int result; 938 struct regspec *ph; 939 940 *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 941 hp = impl_acc_hdl_get(*handlep); 942 hp->ah_vers = VERS_ACCHDL; 943 hp->ah_dip = dip; 944 hp->ah_rnumber = 0; 945 hp->ah_offset = 0; 946 hp->ah_len = 0; 947 hp->ah_acc = *accattrp; 948 ph = kmem_zalloc(sizeof (struct regspec), KM_SLEEP); 949 *ph = *phys_spec; 950 hp->ah_bus_private = ph; /* cache a copy of the reg spec */ 951 952 mr.map_op = DDI_MO_MAP_LOCKED; 953 mr.map_type = DDI_MT_REGSPEC; 954 mr.map_obj.rp = (struct regspec *)phys_spec; 955 mr.map_prot = PROT_READ | PROT_WRITE; 956 mr.map_flags = DDI_MF_KERNEL_MAPPING; 957 mr.map_handlep = hp; 958 mr.map_vers = DDI_MAP_VERSION; 959 960 result = ddi_map(dip, &mr, 0, 0, addrp); 961 962 if (result != DDI_SUCCESS) { 963 impl_acc_hdl_free(*handlep); 964 *handlep = (ddi_acc_handle_t)NULL; 965 } else { 966 hp->ah_addr = *addrp; 967 } 968 969 return (result); 970 } 971 972 static void 973 gp2_unmap_phys(ddi_acc_handle_t *handlep) 974 { 975 ddi_map_req_t mr; 976 ddi_acc_hdl_t *hp; 977 struct regspec_t *ph; 978 979 hp = impl_acc_hdl_get(*handlep); 980 ASSERT(hp); 981 ph = hp->ah_bus_private; 982 983 mr.map_op = DDI_MO_UNMAP; 984 mr.map_type = DDI_MT_REGSPEC; 985 mr.map_obj.rp = (struct regspec *)ph; 986 mr.map_prot = PROT_READ | PROT_WRITE; 987 mr.map_flags = DDI_MF_KERNEL_MAPPING; 988 mr.map_handlep = hp; 989 mr.map_vers = DDI_MAP_VERSION; 990 991 (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 992 hp->ah_len, &hp->ah_addr); 993 994 impl_acc_hdl_free(*handlep); 995 kmem_free(ph, sizeof (struct regspec)); /* Free the cached copy */ 996 *handlep = (ddi_acc_handle_t)NULL; 997 } 998