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