11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
23*7799SRichard.Bean@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel /*
281708Sstevel * fcgp2.c: Framework gp2 (Safari) fcode ops
291708Sstevel */
301708Sstevel #include <sys/types.h>
311708Sstevel #include <sys/kmem.h>
321708Sstevel #include <sys/systm.h>
331708Sstevel #include <sys/pci.h>
341708Sstevel #include <sys/ddi.h>
351708Sstevel #include <sys/sunddi.h>
361708Sstevel #include <sys/sunndi.h>
371708Sstevel #include <sys/ddidmareq.h>
381708Sstevel #include <sys/modctl.h>
391708Sstevel #include <sys/ndi_impldefs.h>
401708Sstevel #include <sys/fcode.h>
411708Sstevel #include <sys/promif.h>
421708Sstevel #include <sys/promimpl.h>
431708Sstevel
441708Sstevel static int gfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
451708Sstevel static int gfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
461708Sstevel static int gfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
471708Sstevel static int gfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *);
481708Sstevel static int gfc_claim_address(dev_info_t *, fco_handle_t, fc_ci_t *);
491708Sstevel static int gfc_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
501708Sstevel static int gfc_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
511708Sstevel static int gfc_vtop(dev_info_t *, fco_handle_t, fc_ci_t *);
521708Sstevel static int gfc_master_intr(dev_info_t *, fco_handle_t, fc_ci_t *);
531708Sstevel
541708Sstevel static int gfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *);
551708Sstevel
561708Sstevel static int gfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *);
571708Sstevel static int gfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *);
581708Sstevel
591708Sstevel int prom_get_fcode_size(char *);
601708Sstevel int prom_get_fcode(char *, char *);
611708Sstevel
621708Sstevel int fcpci_unloadable;
631708Sstevel int no_advisory_dma;
641708Sstevel
651708Sstevel #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
661708Sstevel #define LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
671708Sstevel #define LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo))
681708Sstevel #define PCI_4GIG_LIMIT 0xFFFFFFFFUL
691708Sstevel
701708Sstevel
711708Sstevel /*
721708Sstevel * Module linkage information for the kernel.
731708Sstevel */
741708Sstevel static struct modlmisc modlmisc = {
75*7799SRichard.Bean@Sun.COM &mod_miscops, "FCode gp2 (safari) bus functions"
761708Sstevel };
771708Sstevel
781708Sstevel static struct modlinkage modlinkage = {
791708Sstevel MODREV_1, (void *)&modlmisc, NULL
801708Sstevel };
811708Sstevel
821708Sstevel int
_init(void)831708Sstevel _init(void)
841708Sstevel {
851708Sstevel return (mod_install(&modlinkage));
861708Sstevel }
871708Sstevel
881708Sstevel int
_fini(void)891708Sstevel _fini(void)
901708Sstevel {
911708Sstevel if (fcpci_unloadable)
921708Sstevel return (mod_remove(&modlinkage));
931708Sstevel return (EBUSY);
941708Sstevel }
951708Sstevel
961708Sstevel int
_info(struct modinfo * modinfop)971708Sstevel _info(struct modinfo *modinfop)
981708Sstevel {
991708Sstevel return (mod_info(&modlinkage, modinfop));
1001708Sstevel }
1011708Sstevel
1021708Sstevel
1031708Sstevel struct gfc_ops_v {
1041708Sstevel char *svc_name;
1051708Sstevel fc_ops_t *f;
1061708Sstevel };
1071708Sstevel
1081708Sstevel struct gfc_ops_v gp2_pov[] = {
1091708Sstevel { "map-in", gfc_map_in},
1101708Sstevel { "map-out", gfc_map_out},
1111708Sstevel { "rx@", gfc_register_fetch},
1121708Sstevel { "rl@", gfc_register_fetch},
1131708Sstevel { "rw@", gfc_register_fetch},
1141708Sstevel { "rb@", gfc_register_fetch},
1151708Sstevel { "rx!", gfc_register_store},
1161708Sstevel { "rl!", gfc_register_store},
1171708Sstevel { "rw!", gfc_register_store},
1181708Sstevel { "rb!", gfc_register_store},
1191708Sstevel { "claim-address", gfc_claim_address},
1201708Sstevel { "master-interrupt", gfc_master_intr},
1211772Sjl139090 { "claim-memory", gfc_claim_memory},
1221772Sjl139090 { "release-memory", gfc_release_memory},
1231772Sjl139090 { "vtop", gfc_vtop},
1241708Sstevel { FC_CONFIG_CHILD, gfc_config_child},
1251708Sstevel { FC_GET_FCODE_SIZE, gfc_get_fcode_size},
1261708Sstevel { FC_GET_FCODE, gfc_get_fcode},
1271708Sstevel { NULL, NULL}
1281708Sstevel };
1291708Sstevel
1301708Sstevel struct gfc_ops_v gp2_shared_pov[] = {
1311708Sstevel { NULL, NULL}
1321708Sstevel };
1331708Sstevel
1341708Sstevel static int gp2_map_phys(dev_info_t *, struct regspec *, caddr_t *,
1351708Sstevel ddi_device_acc_attr_t *, ddi_acc_handle_t *);
1361708Sstevel static void gp2_unmap_phys(ddi_acc_handle_t *);
1371708Sstevel
1381708Sstevel fco_handle_t
gp2_fc_ops_alloc_handle(dev_info_t * ap,dev_info_t * child,void * fcode,size_t fcode_size,char * unit_address,char * my_args)1391708Sstevel gp2_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child,
1401708Sstevel void *fcode, size_t fcode_size, char *unit_address,
1411708Sstevel char *my_args)
1421708Sstevel {
1431708Sstevel fco_handle_t rp;
1441708Sstevel phandle_t h;
1451708Sstevel
1461708Sstevel rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
1471708Sstevel rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size,
1481708Sstevel unit_address, NULL);
1491708Sstevel rp->ap = ap;
1501708Sstevel rp->child = child;
1511708Sstevel rp->fcode = fcode;
1521708Sstevel rp->fcode_size = fcode_size;
1531708Sstevel rp->my_args = my_args;
1541708Sstevel
1551708Sstevel if (unit_address) {
1561708Sstevel char *buf;
1571708Sstevel
1581708Sstevel buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP);
1591708Sstevel (void) strcpy(buf, unit_address);
1601708Sstevel rp->unit_address = buf;
1611708Sstevel }
1621708Sstevel
1631708Sstevel /*
1641708Sstevel * Add the child's nodeid to our table...
1651708Sstevel */
1661708Sstevel h = ddi_get_nodeid(rp->child);
1671708Sstevel fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h);
1681708Sstevel
1691708Sstevel return (rp);
1701708Sstevel }
1711708Sstevel
1721708Sstevel void
gp2_fc_ops_free_handle(fco_handle_t rp)1731708Sstevel gp2_fc_ops_free_handle(fco_handle_t rp)
1741708Sstevel {
1751708Sstevel struct fc_resource *ip, *np;
1761708Sstevel
1771708Sstevel ASSERT(rp);
1781708Sstevel
1791708Sstevel if (rp->next_handle)
1801708Sstevel fc_ops_free_handle(rp->next_handle);
1811708Sstevel if (rp->unit_address)
1821708Sstevel kmem_free(rp->unit_address, strlen(rp->unit_address) + 1);
1831708Sstevel if (rp->my_args != NULL)
1841708Sstevel kmem_free(rp->my_args, strlen(rp->my_args) + 1);
1851708Sstevel
1861708Sstevel /*
1871708Sstevel * Release all the resources from the resource list
1881708Sstevel */
1891708Sstevel for (ip = rp->head; ip != NULL; ip = np) {
1901708Sstevel np = ip->next;
1911708Sstevel switch (ip->type) {
1921708Sstevel case RT_MAP:
1931708Sstevel FC_DEBUG1(1, CE_CONT, "gp2_fc_ops_free: "
1941708Sstevel " map handle - %p\n", ip->fc_map_handle);
1951708Sstevel break;
1961708Sstevel case RT_DMA:
1971708Sstevel /* DMA has to be freed up at exit time */
1981708Sstevel cmn_err(CE_CONT, "gfc_fc_ops_free: DMA seen!\n");
1991708Sstevel break;
2001708Sstevel case RT_CONTIGIOUS:
2011708Sstevel FC_DEBUG2(1, CE_CONT, "gp2_fc_ops_free: "
2021708Sstevel "Free claim-memory resource 0x%lx size 0x%x\n",
2031708Sstevel ip->fc_contig_virt, ip->fc_contig_len);
2041708Sstevel
2051708Sstevel (void) ndi_ra_free(ddi_root_node(),
2061708Sstevel (uint64_t)ip->fc_contig_virt,
2071708Sstevel ip->fc_contig_len, "gptwo-contigousmem",
2081708Sstevel NDI_RA_PASS);
2091708Sstevel
2101708Sstevel break;
2111708Sstevel default:
2121708Sstevel cmn_err(CE_CONT, "gp2_fc_ops_free: "
2131708Sstevel "unknown resource type %d\n", ip->type);
2141708Sstevel break;
2151708Sstevel }
2161708Sstevel fc_rem_resource(rp, ip);
2171708Sstevel kmem_free(ip, sizeof (struct fc_resource));
2181708Sstevel }
2191708Sstevel kmem_free(rp, sizeof (struct fc_resource_list));
2201708Sstevel }
2211708Sstevel
2221708Sstevel int
gp2_fc_ops(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)2231708Sstevel gp2_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2241708Sstevel {
2251708Sstevel struct gfc_ops_v *pv;
2261708Sstevel char *name = fc_cell2ptr(cp->svc_name);
2271708Sstevel
2281708Sstevel ASSERT(rp);
2291708Sstevel
2301708Sstevel /*
2311708Sstevel * First try the generic fc_ops. If the ops is a shared op,
2321708Sstevel * also call our local function.
2331708Sstevel */
2341708Sstevel if (fc_ops(ap, rp->next_handle, cp) == 0) {
2351708Sstevel for (pv = gp2_shared_pov; pv->svc_name != NULL; ++pv)
2361708Sstevel if (strcmp(pv->svc_name, name) == 0)
2371708Sstevel return (pv->f(ap, rp, cp));
2381708Sstevel return (0);
2391708Sstevel }
2401708Sstevel
2411708Sstevel for (pv = gp2_pov; pv->svc_name != NULL; ++pv)
2421708Sstevel if (strcmp(pv->svc_name, name) == 0)
2431708Sstevel return (pv->f(ap, rp, cp));
2441708Sstevel
2451708Sstevel FC_DEBUG1(9, CE_CONT, "gp2_fc_ops: <%s> not serviced\n", name);
2461708Sstevel
2471708Sstevel return (-1);
2481708Sstevel }
2491708Sstevel
2501708Sstevel /*
2511708Sstevel * map-in (phys.lo phys.hi size -- virt )
2521708Sstevel */
2531708Sstevel static int
gfc_map_in(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)2541708Sstevel gfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2551708Sstevel {
2561708Sstevel size_t len;
2571708Sstevel int error;
2581708Sstevel caddr_t virt;
2591708Sstevel struct fc_resource *ip;
2601708Sstevel struct regspec r;
2611708Sstevel ddi_device_acc_attr_t acc;
2621708Sstevel ddi_acc_handle_t h;
2631708Sstevel
2641708Sstevel if (fc_cell2int(cp->nargs) != 3)
2651708Sstevel return (fc_syntax_error(cp, "nargs must be 3"));
2661708Sstevel
2671708Sstevel if (fc_cell2int(cp->nresults) < 1)
2681708Sstevel return (fc_syntax_error(cp, "nresults must be >= 1"));
2691708Sstevel
2701708Sstevel r.regspec_size = len = fc_cell2size(fc_arg(cp, 0));
2711708Sstevel r.regspec_bustype = fc_cell2uint(fc_arg(cp, 1));
2721708Sstevel r.regspec_addr = fc_cell2uint(fc_arg(cp, 2));
2731708Sstevel
2741708Sstevel acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2751708Sstevel acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
2761708Sstevel acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2771708Sstevel
2781708Sstevel FC_DEBUG3(1, CE_CONT, "gfc_map_in: attempting map in "
2791708Sstevel "address 0x%08x.%08x length %x\n", r.regspec_bustype,
2801708Sstevel r.regspec_addr, r.regspec_size);
2811708Sstevel
2821708Sstevel error = gp2_map_phys(rp->child, &r, &virt, &acc, &h);
2831708Sstevel
2841708Sstevel if (error) {
2851708Sstevel FC_DEBUG3(1, CE_CONT, "gfc_map_in: map in failed - "
2861708Sstevel "address 0x%08x.%08x length %x\n", r.regspec_bustype,
2871708Sstevel r.regspec_addr, r.regspec_size);
2881708Sstevel
2891708Sstevel return (fc_priv_error(cp, "gp2 map-in failed"));
2901708Sstevel }
2911708Sstevel
2921708Sstevel FC_DEBUG1(3, CE_CONT, "gp2_map_in: returning virt %p\n", virt);
2931708Sstevel
2941708Sstevel cp->nresults = fc_int2cell(1);
2951708Sstevel fc_result(cp, 0) = fc_ptr2cell(virt);
2961708Sstevel
2971708Sstevel /*
2981708Sstevel * Log this resource ...
2991708Sstevel */
3001708Sstevel ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
3011708Sstevel ip->type = RT_MAP;
3021708Sstevel ip->fc_map_virt = virt;
3031708Sstevel ip->fc_map_len = len;
3041708Sstevel ip->fc_map_handle = h;
3051708Sstevel fc_add_resource(rp, ip);
3061708Sstevel
3071708Sstevel return (fc_success_op(ap, rp, cp));
3081708Sstevel }
3091708Sstevel
3101708Sstevel /*
3111708Sstevel * map-out ( virt size -- )
3121708Sstevel */
3131708Sstevel static int
gfc_map_out(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3141708Sstevel gfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3151708Sstevel {
3161708Sstevel caddr_t virt;
3171708Sstevel size_t len;
3181708Sstevel struct fc_resource *ip;
3191708Sstevel
3201708Sstevel if (fc_cell2int(cp->nargs) != 2)
3211708Sstevel return (fc_syntax_error(cp, "nargs must be 2"));
3221708Sstevel
3231708Sstevel virt = fc_cell2ptr(fc_arg(cp, 1));
3241708Sstevel
3251708Sstevel len = fc_cell2size(fc_arg(cp, 0));
3261708Sstevel
3271708Sstevel FC_DEBUG2(1, CE_CONT, "gp2_map_out: attempting map out %p %x\n",
3281708Sstevel virt, len);
3291708Sstevel
3301708Sstevel /*
3311708Sstevel * Find if this request matches a mapping resource we set up.
3321708Sstevel */
3331708Sstevel fc_lock_resource_list(rp);
3341708Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) {
3351708Sstevel if (ip->type != RT_MAP)
3361708Sstevel continue;
3371708Sstevel if (ip->fc_map_virt != virt)
3381708Sstevel continue;
3391708Sstevel if (ip->fc_map_len == len)
3401708Sstevel break;
3411708Sstevel }
3421708Sstevel fc_unlock_resource_list(rp);
3431708Sstevel
3441708Sstevel if (ip == NULL)
3451708Sstevel return (fc_priv_error(cp, "request doesn't match a "
3461708Sstevel "known mapping"));
3471708Sstevel
3481708Sstevel gp2_unmap_phys(&ip->fc_map_handle);
3491708Sstevel
3501708Sstevel /*
3511708Sstevel * remove the resource from the list and release it.
3521708Sstevel */
3531708Sstevel fc_rem_resource(rp, ip);
3541708Sstevel kmem_free(ip, sizeof (struct fc_resource));
3551708Sstevel
3561708Sstevel cp->nresults = fc_int2cell(0);
3571708Sstevel return (fc_success_op(ap, rp, cp));
3581708Sstevel }
3591708Sstevel
3601708Sstevel static int
gfc_register_fetch(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3611708Sstevel gfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3621708Sstevel {
3631708Sstevel size_t len;
3641708Sstevel caddr_t virt;
3651708Sstevel int error = 0;
3661708Sstevel uint64_t x;
3671708Sstevel uint32_t l;
3681708Sstevel uint16_t w;
3691708Sstevel uint8_t b;
3701708Sstevel char *name = fc_cell2ptr(cp->svc_name);
3711708Sstevel struct fc_resource *ip;
3721708Sstevel
3731708Sstevel if (fc_cell2int(cp->nargs) != 1)
3741708Sstevel return (fc_syntax_error(cp, "nargs must be 1"));
3751708Sstevel
3761708Sstevel if (fc_cell2int(cp->nresults) < 1)
3771708Sstevel return (fc_syntax_error(cp, "nresults must be >= 1"));
3781708Sstevel
3791708Sstevel virt = fc_cell2ptr(fc_arg(cp, 0));
3801708Sstevel
3811708Sstevel /*
3821708Sstevel * Determine the access width .. we can switch on the 2nd
3831708Sstevel * character of the name which is "rx@", "rl@", "rb@" or "rw@"
3841708Sstevel */
3851708Sstevel switch (*(name + 1)) {
3861708Sstevel case 'x': len = sizeof (x); break;
3871708Sstevel case 'l': len = sizeof (l); break;
3881708Sstevel case 'w': len = sizeof (w); break;
3891708Sstevel case 'b': len = sizeof (b); break;
3901708Sstevel }
3911708Sstevel
3921708Sstevel /*
3931708Sstevel * Check the alignment ...
3941708Sstevel */
3951708Sstevel if (((intptr_t)virt & (len - 1)) != 0)
3961708Sstevel return (fc_priv_error(cp, "unaligned access"));
3971708Sstevel
3981708Sstevel /*
3991708Sstevel * Find if this virt is 'within' a request we know about
4001708Sstevel */
4011708Sstevel fc_lock_resource_list(rp);
4021708Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) {
4031708Sstevel if (ip->type == RT_MAP) {
4041708Sstevel if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
4051708Sstevel ((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
4061708Sstevel break;
4071708Sstevel } else if (ip->type == RT_CONTIGIOUS) {
4081708Sstevel if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len)
4091708Sstevel <= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len)))
4101708Sstevel break;
4111708Sstevel }
4121708Sstevel }
4131708Sstevel fc_unlock_resource_list(rp);
4141708Sstevel
4151708Sstevel if (ip == NULL) {
4161708Sstevel return (fc_priv_error(cp, "request not within a "
4171708Sstevel "known mapping or contigious adddress"));
4181708Sstevel }
4191708Sstevel
4201708Sstevel switch (len) {
4211708Sstevel case sizeof (x):
4221708Sstevel if (ip->type == RT_MAP)
4231708Sstevel error = ddi_peek64(rp->child,
4241708Sstevel (int64_t *)virt, (int64_t *)&x);
4251708Sstevel else /* RT_CONTIGIOUS */
4261708Sstevel x = *(int64_t *)virt;
4271708Sstevel break;
4281708Sstevel case sizeof (l):
4291708Sstevel if (ip->type == RT_MAP)
4301708Sstevel error = ddi_peek32(rp->child,
4311708Sstevel (int32_t *)virt, (int32_t *)&l);
4321708Sstevel else /* RT_CONTIGIOUS */
4331708Sstevel l = *(int32_t *)virt;
4341708Sstevel break;
4351708Sstevel case sizeof (w):
4361708Sstevel if (ip->type == RT_MAP)
4371708Sstevel error = ddi_peek16(rp->child,
4381708Sstevel (int16_t *)virt, (int16_t *)&w);
4391708Sstevel else /* RT_CONTIGIOUS */
4401708Sstevel w = *(int16_t *)virt;
4411708Sstevel break;
4421708Sstevel case sizeof (b):
4431708Sstevel if (ip->type == RT_MAP)
4441708Sstevel error = ddi_peek8(rp->child,
4451708Sstevel (int8_t *)virt, (int8_t *)&b);
4461708Sstevel else /* RT_CONTIGIOUS */
4471708Sstevel b = *(int8_t *)virt;
4481708Sstevel break;
4491708Sstevel }
4501708Sstevel
4511708Sstevel if (error) {
4521708Sstevel FC_DEBUG2(1, CE_CONT, "gfc_register_fetch: access error "
4531708Sstevel "accessing virt %p len %d\n", virt, len);
4541708Sstevel return (fc_priv_error(cp, "access error"));
4551708Sstevel }
4561708Sstevel
4571708Sstevel cp->nresults = fc_int2cell(1);
4581708Sstevel switch (len) {
4591708Sstevel case sizeof (x): fc_result(cp, 0) = x; break;
4601708Sstevel case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
4611708Sstevel case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
4621708Sstevel case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
4631708Sstevel }
4641708Sstevel return (fc_success_op(ap, rp, cp));
4651708Sstevel }
4661708Sstevel
4671708Sstevel static int
gfc_register_store(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)4681708Sstevel gfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
4691708Sstevel {
4701708Sstevel size_t len;
4711708Sstevel caddr_t virt;
4721708Sstevel uint64_t x;
4731708Sstevel uint32_t l;
4741708Sstevel uint16_t w;
4751708Sstevel uint8_t b;
4761708Sstevel char *name = fc_cell2ptr(cp->svc_name);
4771708Sstevel struct fc_resource *ip;
4781708Sstevel int error = 0;
4791708Sstevel
4801708Sstevel if (fc_cell2int(cp->nargs) != 2)
4811708Sstevel return (fc_syntax_error(cp, "nargs must be 2"));
4821708Sstevel
4831708Sstevel virt = fc_cell2ptr(fc_arg(cp, 0));
4841708Sstevel
4851708Sstevel /*
4861708Sstevel * Determine the access width .. we can switch on the 2nd
4871708Sstevel * character of the name which is "rx!", "rl!", "rb!" or "rw!"
4881708Sstevel */
4891708Sstevel switch (*(name + 1)) {
4901708Sstevel case 'x': len = sizeof (x); x = fc_arg(cp, 1); break;
4911708Sstevel case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
4921708Sstevel case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
4931708Sstevel case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
4941708Sstevel }
4951708Sstevel
4961708Sstevel /*
4971708Sstevel * Check the alignment ...
4981708Sstevel */
4991708Sstevel if (((intptr_t)virt & (len - 1)) != 0)
5001708Sstevel return (fc_priv_error(cp, "unaligned access"));
5011708Sstevel
5021708Sstevel /*
5031708Sstevel * Find if this virt is 'within' a request we know about
5041708Sstevel */
5051708Sstevel fc_lock_resource_list(rp);
5061708Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) {
5071708Sstevel if (ip->type == RT_MAP) {
5081708Sstevel if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
5091708Sstevel ((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
5101708Sstevel break;
5111708Sstevel } else if (ip->type == RT_CONTIGIOUS) {
5121708Sstevel if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len)
5131708Sstevel <= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len)))
5141708Sstevel break;
5151708Sstevel }
5161708Sstevel }
5171708Sstevel fc_unlock_resource_list(rp);
5181708Sstevel
5191708Sstevel if (ip == NULL)
5201708Sstevel return (fc_priv_error(cp, "request not within a "
5211708Sstevel "known mapping or contigious address"));
5221708Sstevel
5231708Sstevel switch (len) {
5241708Sstevel case sizeof (x):
5251708Sstevel if (ip->type == RT_MAP)
5261708Sstevel error = ddi_poke64(rp->child, (int64_t *)virt, x);
5271708Sstevel else if (ip->type == RT_CONTIGIOUS)
5281708Sstevel *(uint64_t *)virt = x;
5291708Sstevel break;
5301708Sstevel case sizeof (l):
5311708Sstevel if (ip->type == RT_MAP)
5321708Sstevel error = ddi_poke32(rp->child, (int32_t *)virt, l);
5331708Sstevel else if (ip->type == RT_CONTIGIOUS)
5341708Sstevel *(uint32_t *)virt = l;
5351708Sstevel break;
5361708Sstevel case sizeof (w):
5371708Sstevel if (ip->type == RT_MAP)
5381708Sstevel error = ddi_poke16(rp->child, (int16_t *)virt, w);
5391708Sstevel else if (ip->type == RT_CONTIGIOUS)
5401708Sstevel *(uint16_t *)virt = w;
5411708Sstevel break;
5421708Sstevel case sizeof (b):
5431708Sstevel if (ip->type == RT_MAP)
5441708Sstevel error = ddi_poke8(rp->child, (int8_t *)virt, b);
5451708Sstevel else if (ip->type == RT_CONTIGIOUS)
5461708Sstevel *(uint8_t *)virt = b;
5471708Sstevel break;
5481708Sstevel }
5491708Sstevel
5501708Sstevel if (error == DDI_FAILURE) {
5511708Sstevel FC_DEBUG2(1, CE_CONT, "gfc_register_store: access error "
5521708Sstevel "accessing virt %p len %d\n", virt, len);
5531708Sstevel return (fc_priv_error(cp, "access error"));
5541708Sstevel }
5551708Sstevel
5561708Sstevel cp->nresults = fc_int2cell(0);
5571708Sstevel return (fc_success_op(ap, rp, cp));
5581708Sstevel }
5591708Sstevel
5601708Sstevel static int
gfc_master_intr(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)5611708Sstevel gfc_master_intr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
5621708Sstevel {
5631708Sstevel int xt, portid;
5641708Sstevel
5651708Sstevel if (fc_cell2int(cp->nargs) != 2)
5661708Sstevel return (fc_syntax_error(cp, "nargs must be 4"));
5671708Sstevel
5681708Sstevel if (fc_cell2int(cp->nresults) < 1)
5691708Sstevel return (fc_syntax_error(cp, "nresults must be >= 1"));
5701708Sstevel
5711708Sstevel xt = fc_cell2int(fc_arg(cp, 1));
5721708Sstevel portid = fc_cell2int(fc_arg(cp, 0));
5731708Sstevel
5741708Sstevel FC_DEBUG2(1, CE_CONT, "gfc_master_intr: reset-int-xt=%x portid=%x",
5751708Sstevel xt, portid);
5761708Sstevel
5771708Sstevel cp->nresults = fc_int2cell(1);
5781708Sstevel fc_result(cp, 0) = 0;
5791708Sstevel
5801708Sstevel return (fc_success_op(ap, rp, cp));
5811708Sstevel }
5821708Sstevel
5831708Sstevel /*
5841708Sstevel * gfc_claim_address
5851708Sstevel *
5861708Sstevel * claim-address (size.lo size.hi type align bar portid -- base.lo base.hi )
5871708Sstevel */
5881708Sstevel static int
gfc_claim_address(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)5891708Sstevel gfc_claim_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
5901708Sstevel {
5911708Sstevel int bar, portid;
5921708Sstevel uint64_t exp, slot, port, slice;
5931708Sstevel uint64_t paddr;
5941708Sstevel
5951708Sstevel if (fc_cell2int(cp->nargs) != 6)
5961708Sstevel return (fc_syntax_error(cp, "nargs must be 6"));
5971708Sstevel
5981708Sstevel if (fc_cell2int(cp->nresults) < 2)
5991708Sstevel return (fc_syntax_error(cp, "nresults must be 2"));
6001708Sstevel
6011708Sstevel bar = fc_cell2int(fc_arg(cp, 1));
6021708Sstevel portid = fc_cell2int(fc_arg(cp, 0));
6031708Sstevel
6041708Sstevel exp = portid >> 5;
6051708Sstevel slot = (0x8 & portid) >> 3;
6061708Sstevel port = portid & 0x1;
6071708Sstevel
6081708Sstevel switch (bar) {
6091708Sstevel case 0: /* PCI IO Bus A */
6101708Sstevel paddr = (exp << 28) | (port << 26) | (slot << 27) |
6111708Sstevel ((uint64_t)0x402 << 32);
6121708Sstevel
6131708Sstevel break;
6141708Sstevel case 1: /* PCI Memory Bus A */
6151708Sstevel slice = (exp * 2) + slot + 1;
6161708Sstevel
6171708Sstevel paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) |
6181708Sstevel ((uint64_t)port << 33);
6191708Sstevel
6201708Sstevel break;
6211708Sstevel case 2: /* PCI IO Bus B */
6221708Sstevel paddr = (exp << 28) | (port << 26) | (slot << 27) |
6231708Sstevel ((uint64_t)0x402 << 32) | (1 << 25);
6241708Sstevel
6251708Sstevel break;
6261708Sstevel case 3: /* PCI Memory Bus B */
6271708Sstevel slice = (exp * 2) + slot + 1;
6281708Sstevel
6291708Sstevel paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) |
6301708Sstevel ((uint64_t)port << 33);
6311708Sstevel
6321708Sstevel paddr |= ((uint64_t)1 << 32);
6331708Sstevel
6341708Sstevel break;
6351708Sstevel default:
6361708Sstevel cmn_err(CE_WARN,
6371708Sstevel "gfc_claim_address - invalid BAR=0x%x\n", bar);
6381708Sstevel
6391708Sstevel return (fc_syntax_error(cp, "invalid argument"));
6401708Sstevel }
6411708Sstevel
6421708Sstevel FC_DEBUG1(1, CE_CONT, "gfc_claim_address: returning 0x%lx\n", paddr);
6431708Sstevel
6441708Sstevel cp->nresults = fc_int2cell(2);
6451708Sstevel fc_result(cp, 0) = LOADDR(paddr);
6461708Sstevel fc_result(cp, 1) = HIADDR(paddr);
6471708Sstevel
6481708Sstevel return (fc_success_op(ap, rp, cp));
6491708Sstevel }
6501708Sstevel
6511708Sstevel /*
6521708Sstevel * gfc_claim_memory
6531708Sstevel *
6541772Sjl139090 * claim-memory ( align size vhint -- vaddr)
6551708Sstevel */
6561708Sstevel static int
gfc_claim_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)6571708Sstevel gfc_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
6581708Sstevel {
6591708Sstevel int align, size, vhint;
6601708Sstevel ndi_ra_request_t request;
6611708Sstevel uint64_t answer, alen;
6621708Sstevel struct fc_resource *ip;
6631708Sstevel
6641708Sstevel if (fc_cell2int(cp->nargs) != 3)
6651708Sstevel return (fc_syntax_error(cp, "nargs must be 3"));
6661708Sstevel
6671708Sstevel if (fc_cell2int(cp->nresults) < 1)
6681708Sstevel return (fc_syntax_error(cp, "nresults must be >= 1"));
6691708Sstevel
6701708Sstevel vhint = fc_cell2int(fc_arg(cp, 2));
6711708Sstevel size = fc_cell2int(fc_arg(cp, 1));
6721708Sstevel align = fc_cell2int(fc_arg(cp, 0));
6731708Sstevel
6741708Sstevel FC_DEBUG3(1, CE_CONT, "gfc_claim_memory: align=0x%x size=0x%x "
6751708Sstevel "vhint=0x%x\n", align, size, vhint);
6761708Sstevel
6771708Sstevel if (size == 0) {
6781708Sstevel cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate "
6791708Sstevel "contigiuos memory of size zero\n");
6801708Sstevel return (fc_priv_error(cp, "allocation error"));
6811708Sstevel }
6821708Sstevel
6831708Sstevel if (vhint) {
6841708Sstevel cmn_err(CE_WARN, "gfc_claim_memory - vhint is not zero "
6851708Sstevel "vhint=0x%x - Ignoring Argument\n", vhint);
6861708Sstevel }
6871708Sstevel
6881708Sstevel bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
6891708Sstevel request.ra_flags = NDI_RA_ALLOC_BOUNDED;
6901708Sstevel request.ra_boundbase = 0;
6911708Sstevel request.ra_boundlen = 0xffffffff;
6921708Sstevel request.ra_len = size;
6931708Sstevel request.ra_align_mask = align - 1;
6941708Sstevel
6951708Sstevel if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen,
6961708Sstevel "gptwo-contigousmem", NDI_RA_PASS) != NDI_SUCCESS) {
6971708Sstevel cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate "
6981708Sstevel "contigiuos memory\n");
6991708Sstevel return (fc_priv_error(cp, "allocation error"));
7001708Sstevel
7011708Sstevel }
7021708Sstevel
7031708Sstevel FC_DEBUG2(1, CE_CONT, "gfc_claim_memory: address allocated=0x%lx "
7041708Sstevel "size=0x%x\n", answer, alen);
7051708Sstevel
7061708Sstevel cp->nresults = fc_int2cell(1);
7071708Sstevel fc_result(cp, 0) = answer;
7081708Sstevel
7091708Sstevel /*
7101708Sstevel * Log this resource ...
7111708Sstevel */
7121708Sstevel ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
7131708Sstevel ip->type = RT_CONTIGIOUS;
7141708Sstevel ip->fc_contig_virt = (void *)answer;
7151708Sstevel ip->fc_contig_len = size;
7161708Sstevel fc_add_resource(rp, ip);
7171708Sstevel
7181708Sstevel return (fc_success_op(ap, rp, cp));
7191708Sstevel }
7201708Sstevel
7211708Sstevel /*
7221708Sstevel * gfc_release_memory
7231708Sstevel *
7241772Sjl139090 * release-memory ( size vaddr -- )
7251708Sstevel */
7261708Sstevel static int
gfc_release_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)7271708Sstevel gfc_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
7281708Sstevel {
7291708Sstevel int32_t vaddr, size;
7301708Sstevel struct fc_resource *ip;
7311708Sstevel
7321708Sstevel if (fc_cell2int(cp->nargs) != 2)
7331708Sstevel return (fc_syntax_error(cp, "nargs must be 2"));
7341708Sstevel
7351708Sstevel if (fc_cell2int(cp->nresults) != 0)
7361708Sstevel return (fc_syntax_error(cp, "nresults must be 0"));
7371708Sstevel
7381708Sstevel vaddr = fc_cell2int(fc_arg(cp, 1));
7391708Sstevel size = fc_cell2int(fc_arg(cp, 0));
7401708Sstevel
7411708Sstevel FC_DEBUG2(1, CE_CONT, "gfc_release_memory: vaddr=0x%x size=0x%x\n",
7421708Sstevel vaddr, size);
7431708Sstevel /*
7441708Sstevel * Find if this request matches a mapping resource we set up.
7451708Sstevel */
7461708Sstevel fc_lock_resource_list(rp);
7471708Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) {
7481708Sstevel if (ip->type != RT_CONTIGIOUS)
7491708Sstevel continue;
7501708Sstevel if (ip->fc_contig_virt != (void *)(uintptr_t)vaddr)
7511708Sstevel continue;
7521708Sstevel if (ip->fc_contig_len == size)
7531708Sstevel break;
7541708Sstevel }
7551708Sstevel fc_unlock_resource_list(rp);
7561708Sstevel
7571708Sstevel if (ip == NULL)
7581708Sstevel return (fc_priv_error(cp, "request doesn't match a "
7591708Sstevel "known mapping"));
7601708Sstevel
7611708Sstevel (void) ndi_ra_free(ddi_root_node(), vaddr, size,
7621708Sstevel "gptwo-contigousmem", NDI_RA_PASS);
7631708Sstevel
7641708Sstevel /*
7651708Sstevel * remove the resource from the list and release it.
7661708Sstevel */
7671708Sstevel fc_rem_resource(rp, ip);
7681708Sstevel kmem_free(ip, sizeof (struct fc_resource));
7691708Sstevel
7701708Sstevel cp->nresults = fc_int2cell(0);
7711708Sstevel
7721708Sstevel return (fc_success_op(ap, rp, cp));
7731708Sstevel }
7741708Sstevel
7751708Sstevel /*
7761708Sstevel * gfc_vtop
7771708Sstevel *
7781772Sjl139090 * vtop ( vaddr -- paddr.lo paddr.hi)
7791708Sstevel */
7801708Sstevel static int
gfc_vtop(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)7811708Sstevel gfc_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
7821708Sstevel {
7831708Sstevel int vaddr;
7841708Sstevel uint64_t paddr;
7851708Sstevel struct fc_resource *ip;
7861708Sstevel
7871708Sstevel if (fc_cell2int(cp->nargs) != 1)
7881708Sstevel return (fc_syntax_error(cp, "nargs must be 1"));
7891708Sstevel
7901708Sstevel if (fc_cell2int(cp->nresults) >= 3)
7911708Sstevel return (fc_syntax_error(cp, "nresults must be less than 2"));
7921708Sstevel
7931708Sstevel vaddr = fc_cell2int(fc_arg(cp, 0));
7941708Sstevel
7951708Sstevel /*
7961708Sstevel * Find if this request matches a mapping resource we set up.
7971708Sstevel */
7981708Sstevel fc_lock_resource_list(rp);
7991708Sstevel for (ip = rp->head; ip != NULL; ip = ip->next) {
8001708Sstevel if (ip->type != RT_CONTIGIOUS)
8011708Sstevel continue;
8021708Sstevel if (ip->fc_contig_virt == (void *)(uintptr_t)vaddr)
8031708Sstevel break;
8041708Sstevel }
8051708Sstevel fc_unlock_resource_list(rp);
8061708Sstevel
8071708Sstevel if (ip == NULL)
8081708Sstevel return (fc_priv_error(cp, "request doesn't match a "
8091708Sstevel "known mapping"));
8101708Sstevel
8111708Sstevel
8121708Sstevel paddr = va_to_pa((void *)(uintptr_t)vaddr);
8131708Sstevel
8141708Sstevel FC_DEBUG2(1, CE_CONT, "gfc_vtop: vaddr=0x%x paddr=0x%x\n",
8151708Sstevel vaddr, paddr);
8161708Sstevel
8171708Sstevel cp->nresults = fc_int2cell(2);
8181708Sstevel
8191708Sstevel fc_result(cp, 0) = paddr;
8201708Sstevel fc_result(cp, 1) = 0;
8211708Sstevel
8221708Sstevel return (fc_success_op(ap, rp, cp));
8231708Sstevel }
8241708Sstevel
8251708Sstevel static int
gfc_config_child(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8261708Sstevel gfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8271708Sstevel {
8281708Sstevel fc_phandle_t h;
8291708Sstevel
8301708Sstevel if (fc_cell2int(cp->nargs) != 0)
8311708Sstevel return (fc_syntax_error(cp, "nargs must be 0"));
8321708Sstevel
8331708Sstevel if (fc_cell2int(cp->nresults) < 1)
8341708Sstevel return (fc_syntax_error(cp, "nresults must be >= 1"));
8351708Sstevel
8361708Sstevel h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child);
8371708Sstevel
8381708Sstevel cp->nresults = fc_int2cell(1);
8391708Sstevel fc_result(cp, 0) = fc_phandle2cell(h);
8401708Sstevel
8411708Sstevel return (fc_success_op(ap, rp, cp));
8421708Sstevel }
8431708Sstevel
8441708Sstevel static int
gfc_get_fcode(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8451708Sstevel gfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8461708Sstevel {
8471708Sstevel caddr_t name_virt, fcode_virt;
8481708Sstevel char *name, *fcode;
8491708Sstevel int fcode_len, status;
8501708Sstevel
8511708Sstevel if (fc_cell2int(cp->nargs) != 3)
8521708Sstevel return (fc_syntax_error(cp, "nargs must be 3"));
8531708Sstevel
8541708Sstevel if (fc_cell2int(cp->nresults) < 1)
8551708Sstevel return (fc_syntax_error(cp, "nresults must be >= 1"));
8561708Sstevel
8571708Sstevel name_virt = fc_cell2ptr(fc_arg(cp, 0));
8581708Sstevel
8591708Sstevel fcode_virt = fc_cell2ptr(fc_arg(cp, 1));
8601708Sstevel
8611708Sstevel fcode_len = fc_cell2int(fc_arg(cp, 2));
8621708Sstevel
8631708Sstevel name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
8641708Sstevel
8651708Sstevel if (copyinstr(fc_cell2ptr(name_virt), name,
8661708Sstevel FC_SVC_NAME_LEN - 1, NULL)) {
8671708Sstevel FC_DEBUG1(1, CE_CONT, "gfc_get_fcode: "
8681708Sstevel "fault copying in drop in name %p\n", name_virt);
8691708Sstevel status = 0;
8701708Sstevel } else {
8711708Sstevel
8721708Sstevel fcode = kmem_zalloc(fcode_len, KM_SLEEP);
8731708Sstevel
8741708Sstevel if ((status = prom_get_fcode(name, fcode)) != 0) {
8751708Sstevel
8761708Sstevel if (copyout((void *)fcode, (void *)fcode_virt,
8771708Sstevel fcode_len)) {
8781708Sstevel cmn_err(CE_WARN, " gfc_get_fcode: Unable "
8791708Sstevel "to copy out fcode image\n");
8801708Sstevel status = 0;
8811708Sstevel }
8821708Sstevel }
8831708Sstevel
8841708Sstevel kmem_free(fcode, fcode_len);
8851708Sstevel }
8861708Sstevel
8871708Sstevel kmem_free(name, FC_SVC_NAME_LEN);
8881708Sstevel
8891708Sstevel cp->nresults = fc_int2cell(1);
8901708Sstevel fc_result(cp, 0) = status;
8911708Sstevel
8921708Sstevel return (fc_success_op(ap, rp, cp));
8931708Sstevel }
8941708Sstevel
8951708Sstevel static int
gfc_get_fcode_size(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8961708Sstevel gfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8971708Sstevel {
8981708Sstevel caddr_t virt;
8991708Sstevel char *name;
9001708Sstevel int len;
9011708Sstevel
9021708Sstevel if (fc_cell2int(cp->nargs) != 1)
9031708Sstevel return (fc_syntax_error(cp, "nargs must be 1"));
9041708Sstevel
9051708Sstevel if (fc_cell2int(cp->nresults) < 1)
9061708Sstevel return (fc_syntax_error(cp, "nresults must be >= 1"));
9071708Sstevel
9081708Sstevel virt = fc_cell2ptr(fc_arg(cp, 0));
9091708Sstevel
9101708Sstevel name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
9111708Sstevel
9121708Sstevel if (copyinstr(fc_cell2ptr(virt), name,
9131708Sstevel FC_SVC_NAME_LEN - 1, NULL)) {
9141708Sstevel FC_DEBUG1(1, CE_CONT, "gfc_get_fcode_size: "
9151708Sstevel "fault copying in drop in name %p\n", virt);
9161708Sstevel len = 0;
9171708Sstevel } else {
9181708Sstevel
9191708Sstevel len = prom_get_fcode_size(name);
9201708Sstevel }
9211708Sstevel
9221708Sstevel kmem_free(name, FC_SVC_NAME_LEN);
9231708Sstevel
9241708Sstevel cp->nresults = fc_int2cell(1);
9251708Sstevel fc_result(cp, 0) = len;
9261708Sstevel
9271708Sstevel return (fc_success_op(ap, rp, cp));
9281708Sstevel }
9291708Sstevel
9301708Sstevel static int
gp2_map_phys(dev_info_t * dip,struct regspec * phys_spec,caddr_t * addrp,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handlep)9311708Sstevel gp2_map_phys(dev_info_t *dip, struct regspec *phys_spec,
9321708Sstevel caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
9331708Sstevel ddi_acc_handle_t *handlep)
9341708Sstevel {
9351708Sstevel ddi_map_req_t mr;
9361708Sstevel ddi_acc_hdl_t *hp;
9371708Sstevel int result;
9381708Sstevel struct regspec *ph;
9391708Sstevel
9401708Sstevel *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
9411708Sstevel hp = impl_acc_hdl_get(*handlep);
9421708Sstevel hp->ah_vers = VERS_ACCHDL;
9431708Sstevel hp->ah_dip = dip;
9441708Sstevel hp->ah_rnumber = 0;
9451708Sstevel hp->ah_offset = 0;
9461708Sstevel hp->ah_len = 0;
9471708Sstevel hp->ah_acc = *accattrp;
9481708Sstevel ph = kmem_zalloc(sizeof (struct regspec), KM_SLEEP);
9491708Sstevel *ph = *phys_spec;
9501708Sstevel hp->ah_bus_private = ph; /* cache a copy of the reg spec */
9511708Sstevel
9521708Sstevel mr.map_op = DDI_MO_MAP_LOCKED;
9531708Sstevel mr.map_type = DDI_MT_REGSPEC;
9541708Sstevel mr.map_obj.rp = (struct regspec *)phys_spec;
9551708Sstevel mr.map_prot = PROT_READ | PROT_WRITE;
9561708Sstevel mr.map_flags = DDI_MF_KERNEL_MAPPING;
9571708Sstevel mr.map_handlep = hp;
9581708Sstevel mr.map_vers = DDI_MAP_VERSION;
9591708Sstevel
9601708Sstevel result = ddi_map(dip, &mr, 0, 0, addrp);
9611708Sstevel
9621708Sstevel if (result != DDI_SUCCESS) {
9631708Sstevel impl_acc_hdl_free(*handlep);
9641708Sstevel *handlep = (ddi_acc_handle_t)NULL;
9651708Sstevel } else {
9661708Sstevel hp->ah_addr = *addrp;
9671708Sstevel }
9681708Sstevel
9691708Sstevel return (result);
9701708Sstevel }
9711708Sstevel
9721708Sstevel static void
gp2_unmap_phys(ddi_acc_handle_t * handlep)9731708Sstevel gp2_unmap_phys(ddi_acc_handle_t *handlep)
9741708Sstevel {
9751708Sstevel ddi_map_req_t mr;
9761708Sstevel ddi_acc_hdl_t *hp;
9771708Sstevel struct regspec_t *ph;
9781708Sstevel
9791708Sstevel hp = impl_acc_hdl_get(*handlep);
9801708Sstevel ASSERT(hp);
9811708Sstevel ph = hp->ah_bus_private;
9821708Sstevel
9831708Sstevel mr.map_op = DDI_MO_UNMAP;
9841708Sstevel mr.map_type = DDI_MT_REGSPEC;
9851708Sstevel mr.map_obj.rp = (struct regspec *)ph;
9861708Sstevel mr.map_prot = PROT_READ | PROT_WRITE;
9871708Sstevel mr.map_flags = DDI_MF_KERNEL_MAPPING;
9881708Sstevel mr.map_handlep = hp;
9891708Sstevel mr.map_vers = DDI_MAP_VERSION;
9901708Sstevel
9911708Sstevel (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
9921708Sstevel hp->ah_len, &hp->ah_addr);
9931708Sstevel
9941708Sstevel impl_acc_hdl_free(*handlep);
9951708Sstevel kmem_free(ph, sizeof (struct regspec)); /* Free the cached copy */
9961708Sstevel *handlep = (ddi_acc_handle_t)NULL;
9971708Sstevel }
998