103831d35Sstevel /* 203831d35Sstevel * CDDL HEADER START 303831d35Sstevel * 403831d35Sstevel * The contents of this file are subject to the terms of the 503831d35Sstevel * Common Development and Distribution License (the "License"). 603831d35Sstevel * You may not use this file except in compliance with the License. 703831d35Sstevel * 803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 903831d35Sstevel * or http://www.opensolaris.org/os/licensing. 1003831d35Sstevel * See the License for the specific language governing permissions 1103831d35Sstevel * and limitations under the License. 1203831d35Sstevel * 1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 1803831d35Sstevel * 1903831d35Sstevel * CDDL HEADER END 2003831d35Sstevel */ 2103831d35Sstevel 2203831d35Sstevel /* 23*f500b196SRichard Bean * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2403831d35Sstevel * Use is subject to license terms. 2503831d35Sstevel */ 2603831d35Sstevel 2703831d35Sstevel /* 2803831d35Sstevel * fcgp2.c: Framework gp2 (Safari) fcode ops 2903831d35Sstevel */ 3003831d35Sstevel #include <sys/types.h> 3103831d35Sstevel #include <sys/kmem.h> 3203831d35Sstevel #include <sys/systm.h> 3303831d35Sstevel #include <sys/pci.h> 3403831d35Sstevel #include <sys/ddi.h> 3503831d35Sstevel #include <sys/sunddi.h> 3603831d35Sstevel #include <sys/sunndi.h> 3703831d35Sstevel #include <sys/ddidmareq.h> 3803831d35Sstevel #include <sys/modctl.h> 3903831d35Sstevel #include <sys/ndi_impldefs.h> 4003831d35Sstevel #include <sys/fcode.h> 4103831d35Sstevel #include <sys/promif.h> 4203831d35Sstevel #include <sys/promimpl.h> 4303831d35Sstevel 4403831d35Sstevel static int gfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 4503831d35Sstevel static int gfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 4603831d35Sstevel static int gfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 4703831d35Sstevel static int gfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); 4803831d35Sstevel static int gfc_claim_address(dev_info_t *, fco_handle_t, fc_ci_t *); 4903831d35Sstevel static int gfc_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 5003831d35Sstevel static int gfc_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 5103831d35Sstevel static int gfc_vtop(dev_info_t *, fco_handle_t, fc_ci_t *); 5203831d35Sstevel static int gfc_master_intr(dev_info_t *, fco_handle_t, fc_ci_t *); 5303831d35Sstevel 5403831d35Sstevel static int gfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); 5503831d35Sstevel 5603831d35Sstevel static int gfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); 5703831d35Sstevel static int gfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); 5803831d35Sstevel 5903831d35Sstevel int prom_get_fcode_size(char *); 6003831d35Sstevel int prom_get_fcode(char *, char *); 6103831d35Sstevel 6203831d35Sstevel int fcpci_unloadable; 6303831d35Sstevel int no_advisory_dma; 6403831d35Sstevel 6503831d35Sstevel #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32)) 6603831d35Sstevel #define LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 6703831d35Sstevel #define LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo)) 6803831d35Sstevel #define PCI_4GIG_LIMIT 0xFFFFFFFFUL 6903831d35Sstevel 7003831d35Sstevel 7103831d35Sstevel /* 7203831d35Sstevel * Module linkage information for the kernel. 7303831d35Sstevel */ 7403831d35Sstevel static struct modlmisc modlmisc = { 75*f500b196SRichard Bean &mod_miscops, "FCode gp2 (safari) bus functions" 7603831d35Sstevel }; 7703831d35Sstevel 7803831d35Sstevel static struct modlinkage modlinkage = { 7903831d35Sstevel MODREV_1, (void *)&modlmisc, NULL 8003831d35Sstevel }; 8103831d35Sstevel 8203831d35Sstevel int 8303831d35Sstevel _init(void) 8403831d35Sstevel { 8503831d35Sstevel return (mod_install(&modlinkage)); 8603831d35Sstevel } 8703831d35Sstevel 8803831d35Sstevel int 8903831d35Sstevel _fini(void) 9003831d35Sstevel { 9103831d35Sstevel if (fcpci_unloadable) 9203831d35Sstevel return (mod_remove(&modlinkage)); 9303831d35Sstevel return (EBUSY); 9403831d35Sstevel } 9503831d35Sstevel 9603831d35Sstevel int 9703831d35Sstevel _info(struct modinfo *modinfop) 9803831d35Sstevel { 9903831d35Sstevel return (mod_info(&modlinkage, modinfop)); 10003831d35Sstevel } 10103831d35Sstevel 10203831d35Sstevel 10303831d35Sstevel struct gfc_ops_v { 10403831d35Sstevel char *svc_name; 10503831d35Sstevel fc_ops_t *f; 10603831d35Sstevel }; 10703831d35Sstevel 10803831d35Sstevel struct gfc_ops_v gp2_pov[] = { 10903831d35Sstevel { "map-in", gfc_map_in}, 11003831d35Sstevel { "map-out", gfc_map_out}, 11103831d35Sstevel { "rx@", gfc_register_fetch}, 11203831d35Sstevel { "rl@", gfc_register_fetch}, 11303831d35Sstevel { "rw@", gfc_register_fetch}, 11403831d35Sstevel { "rb@", gfc_register_fetch}, 11503831d35Sstevel { "rx!", gfc_register_store}, 11603831d35Sstevel { "rl!", gfc_register_store}, 11703831d35Sstevel { "rw!", gfc_register_store}, 11803831d35Sstevel { "rb!", gfc_register_store}, 11903831d35Sstevel { "claim-address", gfc_claim_address}, 12003831d35Sstevel { "master-interrupt", gfc_master_intr}, 12125cf1a30Sjl139090 { "claim-memory", gfc_claim_memory}, 12225cf1a30Sjl139090 { "release-memory", gfc_release_memory}, 12325cf1a30Sjl139090 { "vtop", gfc_vtop}, 12403831d35Sstevel { FC_CONFIG_CHILD, gfc_config_child}, 12503831d35Sstevel { FC_GET_FCODE_SIZE, gfc_get_fcode_size}, 12603831d35Sstevel { FC_GET_FCODE, gfc_get_fcode}, 12703831d35Sstevel { NULL, NULL} 12803831d35Sstevel }; 12903831d35Sstevel 13003831d35Sstevel struct gfc_ops_v gp2_shared_pov[] = { 13103831d35Sstevel { NULL, NULL} 13203831d35Sstevel }; 13303831d35Sstevel 13403831d35Sstevel static int gp2_map_phys(dev_info_t *, struct regspec *, caddr_t *, 13503831d35Sstevel ddi_device_acc_attr_t *, ddi_acc_handle_t *); 13603831d35Sstevel static void gp2_unmap_phys(ddi_acc_handle_t *); 13703831d35Sstevel 13803831d35Sstevel fco_handle_t 13903831d35Sstevel gp2_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child, 14003831d35Sstevel void *fcode, size_t fcode_size, char *unit_address, 14103831d35Sstevel char *my_args) 14203831d35Sstevel { 14303831d35Sstevel fco_handle_t rp; 14403831d35Sstevel phandle_t h; 14503831d35Sstevel 14603831d35Sstevel rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 14703831d35Sstevel rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size, 14803831d35Sstevel unit_address, NULL); 14903831d35Sstevel rp->ap = ap; 15003831d35Sstevel rp->child = child; 15103831d35Sstevel rp->fcode = fcode; 15203831d35Sstevel rp->fcode_size = fcode_size; 15303831d35Sstevel rp->my_args = my_args; 15403831d35Sstevel 15503831d35Sstevel if (unit_address) { 15603831d35Sstevel char *buf; 15703831d35Sstevel 15803831d35Sstevel buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP); 15903831d35Sstevel (void) strcpy(buf, unit_address); 16003831d35Sstevel rp->unit_address = buf; 16103831d35Sstevel } 16203831d35Sstevel 16303831d35Sstevel /* 16403831d35Sstevel * Add the child's nodeid to our table... 16503831d35Sstevel */ 16603831d35Sstevel h = ddi_get_nodeid(rp->child); 16703831d35Sstevel fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 16803831d35Sstevel 16903831d35Sstevel return (rp); 17003831d35Sstevel } 17103831d35Sstevel 17203831d35Sstevel void 17303831d35Sstevel gp2_fc_ops_free_handle(fco_handle_t rp) 17403831d35Sstevel { 17503831d35Sstevel struct fc_resource *ip, *np; 17603831d35Sstevel 17703831d35Sstevel ASSERT(rp); 17803831d35Sstevel 17903831d35Sstevel if (rp->next_handle) 18003831d35Sstevel fc_ops_free_handle(rp->next_handle); 18103831d35Sstevel if (rp->unit_address) 18203831d35Sstevel kmem_free(rp->unit_address, strlen(rp->unit_address) + 1); 18303831d35Sstevel if (rp->my_args != NULL) 18403831d35Sstevel kmem_free(rp->my_args, strlen(rp->my_args) + 1); 18503831d35Sstevel 18603831d35Sstevel /* 18703831d35Sstevel * Release all the resources from the resource list 18803831d35Sstevel */ 18903831d35Sstevel for (ip = rp->head; ip != NULL; ip = np) { 19003831d35Sstevel np = ip->next; 19103831d35Sstevel switch (ip->type) { 19203831d35Sstevel case RT_MAP: 19303831d35Sstevel FC_DEBUG1(1, CE_CONT, "gp2_fc_ops_free: " 19403831d35Sstevel " map handle - %p\n", ip->fc_map_handle); 19503831d35Sstevel break; 19603831d35Sstevel case RT_DMA: 19703831d35Sstevel /* DMA has to be freed up at exit time */ 19803831d35Sstevel cmn_err(CE_CONT, "gfc_fc_ops_free: DMA seen!\n"); 19903831d35Sstevel break; 20003831d35Sstevel case RT_CONTIGIOUS: 20103831d35Sstevel FC_DEBUG2(1, CE_CONT, "gp2_fc_ops_free: " 20203831d35Sstevel "Free claim-memory resource 0x%lx size 0x%x\n", 20303831d35Sstevel ip->fc_contig_virt, ip->fc_contig_len); 20403831d35Sstevel 20503831d35Sstevel (void) ndi_ra_free(ddi_root_node(), 20603831d35Sstevel (uint64_t)ip->fc_contig_virt, 20703831d35Sstevel ip->fc_contig_len, "gptwo-contigousmem", 20803831d35Sstevel NDI_RA_PASS); 20903831d35Sstevel 21003831d35Sstevel break; 21103831d35Sstevel default: 21203831d35Sstevel cmn_err(CE_CONT, "gp2_fc_ops_free: " 21303831d35Sstevel "unknown resource type %d\n", ip->type); 21403831d35Sstevel break; 21503831d35Sstevel } 21603831d35Sstevel fc_rem_resource(rp, ip); 21703831d35Sstevel kmem_free(ip, sizeof (struct fc_resource)); 21803831d35Sstevel } 21903831d35Sstevel kmem_free(rp, sizeof (struct fc_resource_list)); 22003831d35Sstevel } 22103831d35Sstevel 22203831d35Sstevel int 22303831d35Sstevel gp2_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 22403831d35Sstevel { 22503831d35Sstevel struct gfc_ops_v *pv; 22603831d35Sstevel char *name = fc_cell2ptr(cp->svc_name); 22703831d35Sstevel 22803831d35Sstevel ASSERT(rp); 22903831d35Sstevel 23003831d35Sstevel /* 23103831d35Sstevel * First try the generic fc_ops. If the ops is a shared op, 23203831d35Sstevel * also call our local function. 23303831d35Sstevel */ 23403831d35Sstevel if (fc_ops(ap, rp->next_handle, cp) == 0) { 23503831d35Sstevel for (pv = gp2_shared_pov; pv->svc_name != NULL; ++pv) 23603831d35Sstevel if (strcmp(pv->svc_name, name) == 0) 23703831d35Sstevel return (pv->f(ap, rp, cp)); 23803831d35Sstevel return (0); 23903831d35Sstevel } 24003831d35Sstevel 24103831d35Sstevel for (pv = gp2_pov; pv->svc_name != NULL; ++pv) 24203831d35Sstevel if (strcmp(pv->svc_name, name) == 0) 24303831d35Sstevel return (pv->f(ap, rp, cp)); 24403831d35Sstevel 24503831d35Sstevel FC_DEBUG1(9, CE_CONT, "gp2_fc_ops: <%s> not serviced\n", name); 24603831d35Sstevel 24703831d35Sstevel return (-1); 24803831d35Sstevel } 24903831d35Sstevel 25003831d35Sstevel /* 25103831d35Sstevel * map-in (phys.lo phys.hi size -- virt ) 25203831d35Sstevel */ 25303831d35Sstevel static int 25403831d35Sstevel gfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 25503831d35Sstevel { 25603831d35Sstevel size_t len; 25703831d35Sstevel int error; 25803831d35Sstevel caddr_t virt; 25903831d35Sstevel struct fc_resource *ip; 26003831d35Sstevel struct regspec r; 26103831d35Sstevel ddi_device_acc_attr_t acc; 26203831d35Sstevel ddi_acc_handle_t h; 26303831d35Sstevel 26403831d35Sstevel if (fc_cell2int(cp->nargs) != 3) 26503831d35Sstevel return (fc_syntax_error(cp, "nargs must be 3")); 26603831d35Sstevel 26703831d35Sstevel if (fc_cell2int(cp->nresults) < 1) 26803831d35Sstevel return (fc_syntax_error(cp, "nresults must be >= 1")); 26903831d35Sstevel 27003831d35Sstevel r.regspec_size = len = fc_cell2size(fc_arg(cp, 0)); 27103831d35Sstevel r.regspec_bustype = fc_cell2uint(fc_arg(cp, 1)); 27203831d35Sstevel r.regspec_addr = fc_cell2uint(fc_arg(cp, 2)); 27303831d35Sstevel 27403831d35Sstevel acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 27503831d35Sstevel acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 27603831d35Sstevel acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 27703831d35Sstevel 27803831d35Sstevel FC_DEBUG3(1, CE_CONT, "gfc_map_in: attempting map in " 27903831d35Sstevel "address 0x%08x.%08x length %x\n", r.regspec_bustype, 28003831d35Sstevel r.regspec_addr, r.regspec_size); 28103831d35Sstevel 28203831d35Sstevel error = gp2_map_phys(rp->child, &r, &virt, &acc, &h); 28303831d35Sstevel 28403831d35Sstevel if (error) { 28503831d35Sstevel FC_DEBUG3(1, CE_CONT, "gfc_map_in: map in failed - " 28603831d35Sstevel "address 0x%08x.%08x length %x\n", r.regspec_bustype, 28703831d35Sstevel r.regspec_addr, r.regspec_size); 28803831d35Sstevel 28903831d35Sstevel return (fc_priv_error(cp, "gp2 map-in failed")); 29003831d35Sstevel } 29103831d35Sstevel 29203831d35Sstevel FC_DEBUG1(3, CE_CONT, "gp2_map_in: returning virt %p\n", virt); 29303831d35Sstevel 29403831d35Sstevel cp->nresults = fc_int2cell(1); 29503831d35Sstevel fc_result(cp, 0) = fc_ptr2cell(virt); 29603831d35Sstevel 29703831d35Sstevel /* 29803831d35Sstevel * Log this resource ... 29903831d35Sstevel */ 30003831d35Sstevel ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 30103831d35Sstevel ip->type = RT_MAP; 30203831d35Sstevel ip->fc_map_virt = virt; 30303831d35Sstevel ip->fc_map_len = len; 30403831d35Sstevel ip->fc_map_handle = h; 30503831d35Sstevel fc_add_resource(rp, ip); 30603831d35Sstevel 30703831d35Sstevel return (fc_success_op(ap, rp, cp)); 30803831d35Sstevel } 30903831d35Sstevel 31003831d35Sstevel /* 31103831d35Sstevel * map-out ( virt size -- ) 31203831d35Sstevel */ 31303831d35Sstevel static int 31403831d35Sstevel gfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 31503831d35Sstevel { 31603831d35Sstevel caddr_t virt; 31703831d35Sstevel size_t len; 31803831d35Sstevel struct fc_resource *ip; 31903831d35Sstevel 32003831d35Sstevel if (fc_cell2int(cp->nargs) != 2) 32103831d35Sstevel return (fc_syntax_error(cp, "nargs must be 2")); 32203831d35Sstevel 32303831d35Sstevel virt = fc_cell2ptr(fc_arg(cp, 1)); 32403831d35Sstevel 32503831d35Sstevel len = fc_cell2size(fc_arg(cp, 0)); 32603831d35Sstevel 32703831d35Sstevel FC_DEBUG2(1, CE_CONT, "gp2_map_out: attempting map out %p %x\n", 32803831d35Sstevel virt, len); 32903831d35Sstevel 33003831d35Sstevel /* 33103831d35Sstevel * Find if this request matches a mapping resource we set up. 33203831d35Sstevel */ 33303831d35Sstevel fc_lock_resource_list(rp); 33403831d35Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) { 33503831d35Sstevel if (ip->type != RT_MAP) 33603831d35Sstevel continue; 33703831d35Sstevel if (ip->fc_map_virt != virt) 33803831d35Sstevel continue; 33903831d35Sstevel if (ip->fc_map_len == len) 34003831d35Sstevel break; 34103831d35Sstevel } 34203831d35Sstevel fc_unlock_resource_list(rp); 34303831d35Sstevel 34403831d35Sstevel if (ip == NULL) 34503831d35Sstevel return (fc_priv_error(cp, "request doesn't match a " 34603831d35Sstevel "known mapping")); 34703831d35Sstevel 34803831d35Sstevel gp2_unmap_phys(&ip->fc_map_handle); 34903831d35Sstevel 35003831d35Sstevel /* 35103831d35Sstevel * remove the resource from the list and release it. 35203831d35Sstevel */ 35303831d35Sstevel fc_rem_resource(rp, ip); 35403831d35Sstevel kmem_free(ip, sizeof (struct fc_resource)); 35503831d35Sstevel 35603831d35Sstevel cp->nresults = fc_int2cell(0); 35703831d35Sstevel return (fc_success_op(ap, rp, cp)); 35803831d35Sstevel } 35903831d35Sstevel 36003831d35Sstevel static int 36103831d35Sstevel gfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 36203831d35Sstevel { 36303831d35Sstevel size_t len; 36403831d35Sstevel caddr_t virt; 36503831d35Sstevel int error = 0; 36603831d35Sstevel uint64_t x; 36703831d35Sstevel uint32_t l; 36803831d35Sstevel uint16_t w; 36903831d35Sstevel uint8_t b; 37003831d35Sstevel char *name = fc_cell2ptr(cp->svc_name); 37103831d35Sstevel struct fc_resource *ip; 37203831d35Sstevel 37303831d35Sstevel if (fc_cell2int(cp->nargs) != 1) 37403831d35Sstevel return (fc_syntax_error(cp, "nargs must be 1")); 37503831d35Sstevel 37603831d35Sstevel if (fc_cell2int(cp->nresults) < 1) 37703831d35Sstevel return (fc_syntax_error(cp, "nresults must be >= 1")); 37803831d35Sstevel 37903831d35Sstevel virt = fc_cell2ptr(fc_arg(cp, 0)); 38003831d35Sstevel 38103831d35Sstevel /* 38203831d35Sstevel * Determine the access width .. we can switch on the 2nd 38303831d35Sstevel * character of the name which is "rx@", "rl@", "rb@" or "rw@" 38403831d35Sstevel */ 38503831d35Sstevel switch (*(name + 1)) { 38603831d35Sstevel case 'x': len = sizeof (x); break; 38703831d35Sstevel case 'l': len = sizeof (l); break; 38803831d35Sstevel case 'w': len = sizeof (w); break; 38903831d35Sstevel case 'b': len = sizeof (b); break; 39003831d35Sstevel } 39103831d35Sstevel 39203831d35Sstevel /* 39303831d35Sstevel * Check the alignment ... 39403831d35Sstevel */ 39503831d35Sstevel if (((intptr_t)virt & (len - 1)) != 0) 39603831d35Sstevel return (fc_priv_error(cp, "unaligned access")); 39703831d35Sstevel 39803831d35Sstevel /* 39903831d35Sstevel * Find if this virt is 'within' a request we know about 40003831d35Sstevel */ 40103831d35Sstevel fc_lock_resource_list(rp); 40203831d35Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) { 40303831d35Sstevel if (ip->type == RT_MAP) { 40403831d35Sstevel if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 40503831d35Sstevel ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 40603831d35Sstevel break; 40703831d35Sstevel } else if (ip->type == RT_CONTIGIOUS) { 40803831d35Sstevel if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len) 40903831d35Sstevel <= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len))) 41003831d35Sstevel break; 41103831d35Sstevel } 41203831d35Sstevel } 41303831d35Sstevel fc_unlock_resource_list(rp); 41403831d35Sstevel 41503831d35Sstevel if (ip == NULL) { 41603831d35Sstevel return (fc_priv_error(cp, "request not within a " 41703831d35Sstevel "known mapping or contigious adddress")); 41803831d35Sstevel } 41903831d35Sstevel 42003831d35Sstevel switch (len) { 42103831d35Sstevel case sizeof (x): 42203831d35Sstevel if (ip->type == RT_MAP) 42303831d35Sstevel error = ddi_peek64(rp->child, 42403831d35Sstevel (int64_t *)virt, (int64_t *)&x); 42503831d35Sstevel else /* RT_CONTIGIOUS */ 42603831d35Sstevel x = *(int64_t *)virt; 42703831d35Sstevel break; 42803831d35Sstevel case sizeof (l): 42903831d35Sstevel if (ip->type == RT_MAP) 43003831d35Sstevel error = ddi_peek32(rp->child, 43103831d35Sstevel (int32_t *)virt, (int32_t *)&l); 43203831d35Sstevel else /* RT_CONTIGIOUS */ 43303831d35Sstevel l = *(int32_t *)virt; 43403831d35Sstevel break; 43503831d35Sstevel case sizeof (w): 43603831d35Sstevel if (ip->type == RT_MAP) 43703831d35Sstevel error = ddi_peek16(rp->child, 43803831d35Sstevel (int16_t *)virt, (int16_t *)&w); 43903831d35Sstevel else /* RT_CONTIGIOUS */ 44003831d35Sstevel w = *(int16_t *)virt; 44103831d35Sstevel break; 44203831d35Sstevel case sizeof (b): 44303831d35Sstevel if (ip->type == RT_MAP) 44403831d35Sstevel error = ddi_peek8(rp->child, 44503831d35Sstevel (int8_t *)virt, (int8_t *)&b); 44603831d35Sstevel else /* RT_CONTIGIOUS */ 44703831d35Sstevel b = *(int8_t *)virt; 44803831d35Sstevel break; 44903831d35Sstevel } 45003831d35Sstevel 45103831d35Sstevel if (error) { 45203831d35Sstevel FC_DEBUG2(1, CE_CONT, "gfc_register_fetch: access error " 45303831d35Sstevel "accessing virt %p len %d\n", virt, len); 45403831d35Sstevel return (fc_priv_error(cp, "access error")); 45503831d35Sstevel } 45603831d35Sstevel 45703831d35Sstevel cp->nresults = fc_int2cell(1); 45803831d35Sstevel switch (len) { 45903831d35Sstevel case sizeof (x): fc_result(cp, 0) = x; break; 46003831d35Sstevel case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 46103831d35Sstevel case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 46203831d35Sstevel case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 46303831d35Sstevel } 46403831d35Sstevel return (fc_success_op(ap, rp, cp)); 46503831d35Sstevel } 46603831d35Sstevel 46703831d35Sstevel static int 46803831d35Sstevel gfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 46903831d35Sstevel { 47003831d35Sstevel size_t len; 47103831d35Sstevel caddr_t virt; 47203831d35Sstevel uint64_t x; 47303831d35Sstevel uint32_t l; 47403831d35Sstevel uint16_t w; 47503831d35Sstevel uint8_t b; 47603831d35Sstevel char *name = fc_cell2ptr(cp->svc_name); 47703831d35Sstevel struct fc_resource *ip; 47803831d35Sstevel int error = 0; 47903831d35Sstevel 48003831d35Sstevel if (fc_cell2int(cp->nargs) != 2) 48103831d35Sstevel return (fc_syntax_error(cp, "nargs must be 2")); 48203831d35Sstevel 48303831d35Sstevel virt = fc_cell2ptr(fc_arg(cp, 0)); 48403831d35Sstevel 48503831d35Sstevel /* 48603831d35Sstevel * Determine the access width .. we can switch on the 2nd 48703831d35Sstevel * character of the name which is "rx!", "rl!", "rb!" or "rw!" 48803831d35Sstevel */ 48903831d35Sstevel switch (*(name + 1)) { 49003831d35Sstevel case 'x': len = sizeof (x); x = fc_arg(cp, 1); break; 49103831d35Sstevel case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break; 49203831d35Sstevel case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break; 49303831d35Sstevel case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break; 49403831d35Sstevel } 49503831d35Sstevel 49603831d35Sstevel /* 49703831d35Sstevel * Check the alignment ... 49803831d35Sstevel */ 49903831d35Sstevel if (((intptr_t)virt & (len - 1)) != 0) 50003831d35Sstevel return (fc_priv_error(cp, "unaligned access")); 50103831d35Sstevel 50203831d35Sstevel /* 50303831d35Sstevel * Find if this virt is 'within' a request we know about 50403831d35Sstevel */ 50503831d35Sstevel fc_lock_resource_list(rp); 50603831d35Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) { 50703831d35Sstevel if (ip->type == RT_MAP) { 50803831d35Sstevel if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 50903831d35Sstevel ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 51003831d35Sstevel break; 51103831d35Sstevel } else if (ip->type == RT_CONTIGIOUS) { 51203831d35Sstevel if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len) 51303831d35Sstevel <= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len))) 51403831d35Sstevel break; 51503831d35Sstevel } 51603831d35Sstevel } 51703831d35Sstevel fc_unlock_resource_list(rp); 51803831d35Sstevel 51903831d35Sstevel if (ip == NULL) 52003831d35Sstevel return (fc_priv_error(cp, "request not within a " 52103831d35Sstevel "known mapping or contigious address")); 52203831d35Sstevel 52303831d35Sstevel switch (len) { 52403831d35Sstevel case sizeof (x): 52503831d35Sstevel if (ip->type == RT_MAP) 52603831d35Sstevel error = ddi_poke64(rp->child, (int64_t *)virt, x); 52703831d35Sstevel else if (ip->type == RT_CONTIGIOUS) 52803831d35Sstevel *(uint64_t *)virt = x; 52903831d35Sstevel break; 53003831d35Sstevel case sizeof (l): 53103831d35Sstevel if (ip->type == RT_MAP) 53203831d35Sstevel error = ddi_poke32(rp->child, (int32_t *)virt, l); 53303831d35Sstevel else if (ip->type == RT_CONTIGIOUS) 53403831d35Sstevel *(uint32_t *)virt = l; 53503831d35Sstevel break; 53603831d35Sstevel case sizeof (w): 53703831d35Sstevel if (ip->type == RT_MAP) 53803831d35Sstevel error = ddi_poke16(rp->child, (int16_t *)virt, w); 53903831d35Sstevel else if (ip->type == RT_CONTIGIOUS) 54003831d35Sstevel *(uint16_t *)virt = w; 54103831d35Sstevel break; 54203831d35Sstevel case sizeof (b): 54303831d35Sstevel if (ip->type == RT_MAP) 54403831d35Sstevel error = ddi_poke8(rp->child, (int8_t *)virt, b); 54503831d35Sstevel else if (ip->type == RT_CONTIGIOUS) 54603831d35Sstevel *(uint8_t *)virt = b; 54703831d35Sstevel break; 54803831d35Sstevel } 54903831d35Sstevel 55003831d35Sstevel if (error == DDI_FAILURE) { 55103831d35Sstevel FC_DEBUG2(1, CE_CONT, "gfc_register_store: access error " 55203831d35Sstevel "accessing virt %p len %d\n", virt, len); 55303831d35Sstevel return (fc_priv_error(cp, "access error")); 55403831d35Sstevel } 55503831d35Sstevel 55603831d35Sstevel cp->nresults = fc_int2cell(0); 55703831d35Sstevel return (fc_success_op(ap, rp, cp)); 55803831d35Sstevel } 55903831d35Sstevel 56003831d35Sstevel static int 56103831d35Sstevel gfc_master_intr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 56203831d35Sstevel { 56303831d35Sstevel int xt, portid; 56403831d35Sstevel 56503831d35Sstevel if (fc_cell2int(cp->nargs) != 2) 56603831d35Sstevel return (fc_syntax_error(cp, "nargs must be 4")); 56703831d35Sstevel 56803831d35Sstevel if (fc_cell2int(cp->nresults) < 1) 56903831d35Sstevel return (fc_syntax_error(cp, "nresults must be >= 1")); 57003831d35Sstevel 57103831d35Sstevel xt = fc_cell2int(fc_arg(cp, 1)); 57203831d35Sstevel portid = fc_cell2int(fc_arg(cp, 0)); 57303831d35Sstevel 57403831d35Sstevel FC_DEBUG2(1, CE_CONT, "gfc_master_intr: reset-int-xt=%x portid=%x", 57503831d35Sstevel xt, portid); 57603831d35Sstevel 57703831d35Sstevel cp->nresults = fc_int2cell(1); 57803831d35Sstevel fc_result(cp, 0) = 0; 57903831d35Sstevel 58003831d35Sstevel return (fc_success_op(ap, rp, cp)); 58103831d35Sstevel } 58203831d35Sstevel 58303831d35Sstevel /* 58403831d35Sstevel * gfc_claim_address 58503831d35Sstevel * 58603831d35Sstevel * claim-address (size.lo size.hi type align bar portid -- base.lo base.hi ) 58703831d35Sstevel */ 58803831d35Sstevel static int 58903831d35Sstevel gfc_claim_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 59003831d35Sstevel { 59103831d35Sstevel int bar, portid; 59203831d35Sstevel uint64_t exp, slot, port, slice; 59303831d35Sstevel uint64_t paddr; 59403831d35Sstevel 59503831d35Sstevel if (fc_cell2int(cp->nargs) != 6) 59603831d35Sstevel return (fc_syntax_error(cp, "nargs must be 6")); 59703831d35Sstevel 59803831d35Sstevel if (fc_cell2int(cp->nresults) < 2) 59903831d35Sstevel return (fc_syntax_error(cp, "nresults must be 2")); 60003831d35Sstevel 60103831d35Sstevel bar = fc_cell2int(fc_arg(cp, 1)); 60203831d35Sstevel portid = fc_cell2int(fc_arg(cp, 0)); 60303831d35Sstevel 60403831d35Sstevel exp = portid >> 5; 60503831d35Sstevel slot = (0x8 & portid) >> 3; 60603831d35Sstevel port = portid & 0x1; 60703831d35Sstevel 60803831d35Sstevel switch (bar) { 60903831d35Sstevel case 0: /* PCI IO Bus A */ 61003831d35Sstevel paddr = (exp << 28) | (port << 26) | (slot << 27) | 61103831d35Sstevel ((uint64_t)0x402 << 32); 61203831d35Sstevel 61303831d35Sstevel break; 61403831d35Sstevel case 1: /* PCI Memory Bus A */ 61503831d35Sstevel slice = (exp * 2) + slot + 1; 61603831d35Sstevel 61703831d35Sstevel paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) | 61803831d35Sstevel ((uint64_t)port << 33); 61903831d35Sstevel 62003831d35Sstevel break; 62103831d35Sstevel case 2: /* PCI IO Bus B */ 62203831d35Sstevel paddr = (exp << 28) | (port << 26) | (slot << 27) | 62303831d35Sstevel ((uint64_t)0x402 << 32) | (1 << 25); 62403831d35Sstevel 62503831d35Sstevel break; 62603831d35Sstevel case 3: /* PCI Memory Bus B */ 62703831d35Sstevel slice = (exp * 2) + slot + 1; 62803831d35Sstevel 62903831d35Sstevel paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) | 63003831d35Sstevel ((uint64_t)port << 33); 63103831d35Sstevel 63203831d35Sstevel paddr |= ((uint64_t)1 << 32); 63303831d35Sstevel 63403831d35Sstevel break; 63503831d35Sstevel default: 63603831d35Sstevel cmn_err(CE_WARN, 63703831d35Sstevel "gfc_claim_address - invalid BAR=0x%x\n", bar); 63803831d35Sstevel 63903831d35Sstevel return (fc_syntax_error(cp, "invalid argument")); 64003831d35Sstevel } 64103831d35Sstevel 64203831d35Sstevel FC_DEBUG1(1, CE_CONT, "gfc_claim_address: returning 0x%lx\n", paddr); 64303831d35Sstevel 64403831d35Sstevel cp->nresults = fc_int2cell(2); 64503831d35Sstevel fc_result(cp, 0) = LOADDR(paddr); 64603831d35Sstevel fc_result(cp, 1) = HIADDR(paddr); 64703831d35Sstevel 64803831d35Sstevel return (fc_success_op(ap, rp, cp)); 64903831d35Sstevel } 65003831d35Sstevel 65103831d35Sstevel /* 65203831d35Sstevel * gfc_claim_memory 65303831d35Sstevel * 65425cf1a30Sjl139090 * claim-memory ( align size vhint -- vaddr) 65503831d35Sstevel */ 65603831d35Sstevel static int 65703831d35Sstevel gfc_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 65803831d35Sstevel { 65903831d35Sstevel int align, size, vhint; 66003831d35Sstevel ndi_ra_request_t request; 66103831d35Sstevel uint64_t answer, alen; 66203831d35Sstevel struct fc_resource *ip; 66303831d35Sstevel 66403831d35Sstevel if (fc_cell2int(cp->nargs) != 3) 66503831d35Sstevel return (fc_syntax_error(cp, "nargs must be 3")); 66603831d35Sstevel 66703831d35Sstevel if (fc_cell2int(cp->nresults) < 1) 66803831d35Sstevel return (fc_syntax_error(cp, "nresults must be >= 1")); 66903831d35Sstevel 67003831d35Sstevel vhint = fc_cell2int(fc_arg(cp, 2)); 67103831d35Sstevel size = fc_cell2int(fc_arg(cp, 1)); 67203831d35Sstevel align = fc_cell2int(fc_arg(cp, 0)); 67303831d35Sstevel 67403831d35Sstevel FC_DEBUG3(1, CE_CONT, "gfc_claim_memory: align=0x%x size=0x%x " 67503831d35Sstevel "vhint=0x%x\n", align, size, vhint); 67603831d35Sstevel 67703831d35Sstevel if (size == 0) { 67803831d35Sstevel cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate " 67903831d35Sstevel "contigiuos memory of size zero\n"); 68003831d35Sstevel return (fc_priv_error(cp, "allocation error")); 68103831d35Sstevel } 68203831d35Sstevel 68303831d35Sstevel if (vhint) { 68403831d35Sstevel cmn_err(CE_WARN, "gfc_claim_memory - vhint is not zero " 68503831d35Sstevel "vhint=0x%x - Ignoring Argument\n", vhint); 68603831d35Sstevel } 68703831d35Sstevel 68803831d35Sstevel bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 68903831d35Sstevel request.ra_flags = NDI_RA_ALLOC_BOUNDED; 69003831d35Sstevel request.ra_boundbase = 0; 69103831d35Sstevel request.ra_boundlen = 0xffffffff; 69203831d35Sstevel request.ra_len = size; 69303831d35Sstevel request.ra_align_mask = align - 1; 69403831d35Sstevel 69503831d35Sstevel if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen, 69603831d35Sstevel "gptwo-contigousmem", NDI_RA_PASS) != NDI_SUCCESS) { 69703831d35Sstevel cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate " 69803831d35Sstevel "contigiuos memory\n"); 69903831d35Sstevel return (fc_priv_error(cp, "allocation error")); 70003831d35Sstevel 70103831d35Sstevel } 70203831d35Sstevel 70303831d35Sstevel FC_DEBUG2(1, CE_CONT, "gfc_claim_memory: address allocated=0x%lx " 70403831d35Sstevel "size=0x%x\n", answer, alen); 70503831d35Sstevel 70603831d35Sstevel cp->nresults = fc_int2cell(1); 70703831d35Sstevel fc_result(cp, 0) = answer; 70803831d35Sstevel 70903831d35Sstevel /* 71003831d35Sstevel * Log this resource ... 71103831d35Sstevel */ 71203831d35Sstevel ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 71303831d35Sstevel ip->type = RT_CONTIGIOUS; 71403831d35Sstevel ip->fc_contig_virt = (void *)answer; 71503831d35Sstevel ip->fc_contig_len = size; 71603831d35Sstevel fc_add_resource(rp, ip); 71703831d35Sstevel 71803831d35Sstevel return (fc_success_op(ap, rp, cp)); 71903831d35Sstevel } 72003831d35Sstevel 72103831d35Sstevel /* 72203831d35Sstevel * gfc_release_memory 72303831d35Sstevel * 72425cf1a30Sjl139090 * release-memory ( size vaddr -- ) 72503831d35Sstevel */ 72603831d35Sstevel static int 72703831d35Sstevel gfc_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 72803831d35Sstevel { 72903831d35Sstevel int32_t vaddr, size; 73003831d35Sstevel struct fc_resource *ip; 73103831d35Sstevel 73203831d35Sstevel if (fc_cell2int(cp->nargs) != 2) 73303831d35Sstevel return (fc_syntax_error(cp, "nargs must be 2")); 73403831d35Sstevel 73503831d35Sstevel if (fc_cell2int(cp->nresults) != 0) 73603831d35Sstevel return (fc_syntax_error(cp, "nresults must be 0")); 73703831d35Sstevel 73803831d35Sstevel vaddr = fc_cell2int(fc_arg(cp, 1)); 73903831d35Sstevel size = fc_cell2int(fc_arg(cp, 0)); 74003831d35Sstevel 74103831d35Sstevel FC_DEBUG2(1, CE_CONT, "gfc_release_memory: vaddr=0x%x size=0x%x\n", 74203831d35Sstevel vaddr, size); 74303831d35Sstevel /* 74403831d35Sstevel * Find if this request matches a mapping resource we set up. 74503831d35Sstevel */ 74603831d35Sstevel fc_lock_resource_list(rp); 74703831d35Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) { 74803831d35Sstevel if (ip->type != RT_CONTIGIOUS) 74903831d35Sstevel continue; 75003831d35Sstevel if (ip->fc_contig_virt != (void *)(uintptr_t)vaddr) 75103831d35Sstevel continue; 75203831d35Sstevel if (ip->fc_contig_len == size) 75303831d35Sstevel break; 75403831d35Sstevel } 75503831d35Sstevel fc_unlock_resource_list(rp); 75603831d35Sstevel 75703831d35Sstevel if (ip == NULL) 75803831d35Sstevel return (fc_priv_error(cp, "request doesn't match a " 75903831d35Sstevel "known mapping")); 76003831d35Sstevel 76103831d35Sstevel (void) ndi_ra_free(ddi_root_node(), vaddr, size, 76203831d35Sstevel "gptwo-contigousmem", NDI_RA_PASS); 76303831d35Sstevel 76403831d35Sstevel /* 76503831d35Sstevel * remove the resource from the list and release it. 76603831d35Sstevel */ 76703831d35Sstevel fc_rem_resource(rp, ip); 76803831d35Sstevel kmem_free(ip, sizeof (struct fc_resource)); 76903831d35Sstevel 77003831d35Sstevel cp->nresults = fc_int2cell(0); 77103831d35Sstevel 77203831d35Sstevel return (fc_success_op(ap, rp, cp)); 77303831d35Sstevel } 77403831d35Sstevel 77503831d35Sstevel /* 77603831d35Sstevel * gfc_vtop 77703831d35Sstevel * 77825cf1a30Sjl139090 * vtop ( vaddr -- paddr.lo paddr.hi) 77903831d35Sstevel */ 78003831d35Sstevel static int 78103831d35Sstevel gfc_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 78203831d35Sstevel { 78303831d35Sstevel int vaddr; 78403831d35Sstevel uint64_t paddr; 78503831d35Sstevel struct fc_resource *ip; 78603831d35Sstevel 78703831d35Sstevel if (fc_cell2int(cp->nargs) != 1) 78803831d35Sstevel return (fc_syntax_error(cp, "nargs must be 1")); 78903831d35Sstevel 79003831d35Sstevel if (fc_cell2int(cp->nresults) >= 3) 79103831d35Sstevel return (fc_syntax_error(cp, "nresults must be less than 2")); 79203831d35Sstevel 79303831d35Sstevel vaddr = fc_cell2int(fc_arg(cp, 0)); 79403831d35Sstevel 79503831d35Sstevel /* 79603831d35Sstevel * Find if this request matches a mapping resource we set up. 79703831d35Sstevel */ 79803831d35Sstevel fc_lock_resource_list(rp); 79903831d35Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) { 80003831d35Sstevel if (ip->type != RT_CONTIGIOUS) 80103831d35Sstevel continue; 80203831d35Sstevel if (ip->fc_contig_virt == (void *)(uintptr_t)vaddr) 80303831d35Sstevel break; 80403831d35Sstevel } 80503831d35Sstevel fc_unlock_resource_list(rp); 80603831d35Sstevel 80703831d35Sstevel if (ip == NULL) 80803831d35Sstevel return (fc_priv_error(cp, "request doesn't match a " 80903831d35Sstevel "known mapping")); 81003831d35Sstevel 81103831d35Sstevel 81203831d35Sstevel paddr = va_to_pa((void *)(uintptr_t)vaddr); 81303831d35Sstevel 81403831d35Sstevel FC_DEBUG2(1, CE_CONT, "gfc_vtop: vaddr=0x%x paddr=0x%x\n", 81503831d35Sstevel vaddr, paddr); 81603831d35Sstevel 81703831d35Sstevel cp->nresults = fc_int2cell(2); 81803831d35Sstevel 81903831d35Sstevel fc_result(cp, 0) = paddr; 82003831d35Sstevel fc_result(cp, 1) = 0; 82103831d35Sstevel 82203831d35Sstevel return (fc_success_op(ap, rp, cp)); 82303831d35Sstevel } 82403831d35Sstevel 82503831d35Sstevel static int 82603831d35Sstevel gfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 82703831d35Sstevel { 82803831d35Sstevel fc_phandle_t h; 82903831d35Sstevel 83003831d35Sstevel if (fc_cell2int(cp->nargs) != 0) 83103831d35Sstevel return (fc_syntax_error(cp, "nargs must be 0")); 83203831d35Sstevel 83303831d35Sstevel if (fc_cell2int(cp->nresults) < 1) 83403831d35Sstevel return (fc_syntax_error(cp, "nresults must be >= 1")); 83503831d35Sstevel 83603831d35Sstevel h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 83703831d35Sstevel 83803831d35Sstevel cp->nresults = fc_int2cell(1); 83903831d35Sstevel fc_result(cp, 0) = fc_phandle2cell(h); 84003831d35Sstevel 84103831d35Sstevel return (fc_success_op(ap, rp, cp)); 84203831d35Sstevel } 84303831d35Sstevel 84403831d35Sstevel static int 84503831d35Sstevel gfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 84603831d35Sstevel { 84703831d35Sstevel caddr_t name_virt, fcode_virt; 84803831d35Sstevel char *name, *fcode; 84903831d35Sstevel int fcode_len, status; 85003831d35Sstevel 85103831d35Sstevel if (fc_cell2int(cp->nargs) != 3) 85203831d35Sstevel return (fc_syntax_error(cp, "nargs must be 3")); 85303831d35Sstevel 85403831d35Sstevel if (fc_cell2int(cp->nresults) < 1) 85503831d35Sstevel return (fc_syntax_error(cp, "nresults must be >= 1")); 85603831d35Sstevel 85703831d35Sstevel name_virt = fc_cell2ptr(fc_arg(cp, 0)); 85803831d35Sstevel 85903831d35Sstevel fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 86003831d35Sstevel 86103831d35Sstevel fcode_len = fc_cell2int(fc_arg(cp, 2)); 86203831d35Sstevel 86303831d35Sstevel name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 86403831d35Sstevel 86503831d35Sstevel if (copyinstr(fc_cell2ptr(name_virt), name, 86603831d35Sstevel FC_SVC_NAME_LEN - 1, NULL)) { 86703831d35Sstevel FC_DEBUG1(1, CE_CONT, "gfc_get_fcode: " 86803831d35Sstevel "fault copying in drop in name %p\n", name_virt); 86903831d35Sstevel status = 0; 87003831d35Sstevel } else { 87103831d35Sstevel 87203831d35Sstevel fcode = kmem_zalloc(fcode_len, KM_SLEEP); 87303831d35Sstevel 87403831d35Sstevel if ((status = prom_get_fcode(name, fcode)) != 0) { 87503831d35Sstevel 87603831d35Sstevel if (copyout((void *)fcode, (void *)fcode_virt, 87703831d35Sstevel fcode_len)) { 87803831d35Sstevel cmn_err(CE_WARN, " gfc_get_fcode: Unable " 87903831d35Sstevel "to copy out fcode image\n"); 88003831d35Sstevel status = 0; 88103831d35Sstevel } 88203831d35Sstevel } 88303831d35Sstevel 88403831d35Sstevel kmem_free(fcode, fcode_len); 88503831d35Sstevel } 88603831d35Sstevel 88703831d35Sstevel kmem_free(name, FC_SVC_NAME_LEN); 88803831d35Sstevel 88903831d35Sstevel cp->nresults = fc_int2cell(1); 89003831d35Sstevel fc_result(cp, 0) = status; 89103831d35Sstevel 89203831d35Sstevel return (fc_success_op(ap, rp, cp)); 89303831d35Sstevel } 89403831d35Sstevel 89503831d35Sstevel static int 89603831d35Sstevel gfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 89703831d35Sstevel { 89803831d35Sstevel caddr_t virt; 89903831d35Sstevel char *name; 90003831d35Sstevel int len; 90103831d35Sstevel 90203831d35Sstevel if (fc_cell2int(cp->nargs) != 1) 90303831d35Sstevel return (fc_syntax_error(cp, "nargs must be 1")); 90403831d35Sstevel 90503831d35Sstevel if (fc_cell2int(cp->nresults) < 1) 90603831d35Sstevel return (fc_syntax_error(cp, "nresults must be >= 1")); 90703831d35Sstevel 90803831d35Sstevel virt = fc_cell2ptr(fc_arg(cp, 0)); 90903831d35Sstevel 91003831d35Sstevel name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 91103831d35Sstevel 91203831d35Sstevel if (copyinstr(fc_cell2ptr(virt), name, 91303831d35Sstevel FC_SVC_NAME_LEN - 1, NULL)) { 91403831d35Sstevel FC_DEBUG1(1, CE_CONT, "gfc_get_fcode_size: " 91503831d35Sstevel "fault copying in drop in name %p\n", virt); 91603831d35Sstevel len = 0; 91703831d35Sstevel } else { 91803831d35Sstevel 91903831d35Sstevel len = prom_get_fcode_size(name); 92003831d35Sstevel } 92103831d35Sstevel 92203831d35Sstevel kmem_free(name, FC_SVC_NAME_LEN); 92303831d35Sstevel 92403831d35Sstevel cp->nresults = fc_int2cell(1); 92503831d35Sstevel fc_result(cp, 0) = len; 92603831d35Sstevel 92703831d35Sstevel return (fc_success_op(ap, rp, cp)); 92803831d35Sstevel } 92903831d35Sstevel 93003831d35Sstevel static int 93103831d35Sstevel gp2_map_phys(dev_info_t *dip, struct regspec *phys_spec, 93203831d35Sstevel caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 93303831d35Sstevel ddi_acc_handle_t *handlep) 93403831d35Sstevel { 93503831d35Sstevel ddi_map_req_t mr; 93603831d35Sstevel ddi_acc_hdl_t *hp; 93703831d35Sstevel int result; 93803831d35Sstevel struct regspec *ph; 93903831d35Sstevel 94003831d35Sstevel *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 94103831d35Sstevel hp = impl_acc_hdl_get(*handlep); 94203831d35Sstevel hp->ah_vers = VERS_ACCHDL; 94303831d35Sstevel hp->ah_dip = dip; 94403831d35Sstevel hp->ah_rnumber = 0; 94503831d35Sstevel hp->ah_offset = 0; 94603831d35Sstevel hp->ah_len = 0; 94703831d35Sstevel hp->ah_acc = *accattrp; 94803831d35Sstevel ph = kmem_zalloc(sizeof (struct regspec), KM_SLEEP); 94903831d35Sstevel *ph = *phys_spec; 95003831d35Sstevel hp->ah_bus_private = ph; /* cache a copy of the reg spec */ 95103831d35Sstevel 95203831d35Sstevel mr.map_op = DDI_MO_MAP_LOCKED; 95303831d35Sstevel mr.map_type = DDI_MT_REGSPEC; 95403831d35Sstevel mr.map_obj.rp = (struct regspec *)phys_spec; 95503831d35Sstevel mr.map_prot = PROT_READ | PROT_WRITE; 95603831d35Sstevel mr.map_flags = DDI_MF_KERNEL_MAPPING; 95703831d35Sstevel mr.map_handlep = hp; 95803831d35Sstevel mr.map_vers = DDI_MAP_VERSION; 95903831d35Sstevel 96003831d35Sstevel result = ddi_map(dip, &mr, 0, 0, addrp); 96103831d35Sstevel 96203831d35Sstevel if (result != DDI_SUCCESS) { 96303831d35Sstevel impl_acc_hdl_free(*handlep); 96403831d35Sstevel *handlep = (ddi_acc_handle_t)NULL; 96503831d35Sstevel } else { 96603831d35Sstevel hp->ah_addr = *addrp; 96703831d35Sstevel } 96803831d35Sstevel 96903831d35Sstevel return (result); 97003831d35Sstevel } 97103831d35Sstevel 97203831d35Sstevel static void 97303831d35Sstevel gp2_unmap_phys(ddi_acc_handle_t *handlep) 97403831d35Sstevel { 97503831d35Sstevel ddi_map_req_t mr; 97603831d35Sstevel ddi_acc_hdl_t *hp; 97703831d35Sstevel struct regspec_t *ph; 97803831d35Sstevel 97903831d35Sstevel hp = impl_acc_hdl_get(*handlep); 98003831d35Sstevel ASSERT(hp); 98103831d35Sstevel ph = hp->ah_bus_private; 98203831d35Sstevel 98303831d35Sstevel mr.map_op = DDI_MO_UNMAP; 98403831d35Sstevel mr.map_type = DDI_MT_REGSPEC; 98503831d35Sstevel mr.map_obj.rp = (struct regspec *)ph; 98603831d35Sstevel mr.map_prot = PROT_READ | PROT_WRITE; 98703831d35Sstevel mr.map_flags = DDI_MF_KERNEL_MAPPING; 98803831d35Sstevel mr.map_handlep = hp; 98903831d35Sstevel mr.map_vers = DDI_MAP_VERSION; 99003831d35Sstevel 99103831d35Sstevel (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 99203831d35Sstevel hp->ah_len, &hp->ah_addr); 99303831d35Sstevel 99403831d35Sstevel impl_acc_hdl_free(*handlep); 99503831d35Sstevel kmem_free(ph, sizeof (struct regspec)); /* Free the cached copy */ 99603831d35Sstevel *handlep = (ddi_acc_handle_t)NULL; 99703831d35Sstevel } 998