xref: /titanic_51/usr/src/uts/sun4u/starcat/io/fcgp2.c (revision f500b19684bd0346ac05bec02a50af07f369da1a)
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