10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51106Smrj * Common Development and Distribution License (the "License"). 61106Smrj * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211106Smrj 220Sstevel@tonic-gate /* 231248Smrj * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * fcpci.c: Framework PCI fcode ops 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/kmem.h> 340Sstevel@tonic-gate #include <sys/systm.h> 350Sstevel@tonic-gate #include <sys/pci.h> 360Sstevel@tonic-gate #include <sys/ddi.h> 370Sstevel@tonic-gate #include <sys/sunddi.h> 380Sstevel@tonic-gate #include <sys/sunndi.h> 390Sstevel@tonic-gate #include <sys/ddidmareq.h> 400Sstevel@tonic-gate #include <sys/pci.h> 410Sstevel@tonic-gate #include <sys/modctl.h> 420Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 430Sstevel@tonic-gate #include <sys/fcode.h> 440Sstevel@tonic-gate #include <sys/promif.h> 450Sstevel@tonic-gate #include <sys/promimpl.h> 461106Smrj #include <sys/ddi_implfuncs.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate #define PCI_NPT_bits (PCI_RELOCAT_B | PCI_PREFETCH_B | PCI_ALIAS_B) 490Sstevel@tonic-gate #define PCICFG_CONF_INDIRECT_MAP 1 500Sstevel@tonic-gate 510Sstevel@tonic-gate static int pfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 520Sstevel@tonic-gate static int pfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 530Sstevel@tonic-gate static int pfc_dma_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 540Sstevel@tonic-gate static int pfc_dma_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 550Sstevel@tonic-gate static int pfc_dma_sync(dev_info_t *, fco_handle_t, fc_ci_t *); 560Sstevel@tonic-gate static int pfc_dma_cleanup(dev_info_t *, fco_handle_t, fc_ci_t *); 570Sstevel@tonic-gate 580Sstevel@tonic-gate static int pfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 590Sstevel@tonic-gate static int pfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); 600Sstevel@tonic-gate static int pfc_config_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 610Sstevel@tonic-gate static int pfc_config_store(dev_info_t *, fco_handle_t, fc_ci_t *); 620Sstevel@tonic-gate 630Sstevel@tonic-gate static int pfc_probe_address(dev_info_t *, fco_handle_t, fc_ci_t *); 640Sstevel@tonic-gate static int pfc_probe_space(dev_info_t *, fco_handle_t, fc_ci_t *); 650Sstevel@tonic-gate 660Sstevel@tonic-gate static int pfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); 670Sstevel@tonic-gate static int pfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); 680Sstevel@tonic-gate static int pfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); 690Sstevel@tonic-gate int prom_get_fcode_size(char *); 700Sstevel@tonic-gate int prom_get_fcode(char *, char *); 710Sstevel@tonic-gate int pfc_update_assigned_prop(dev_info_t *, pci_regspec_t *); 720Sstevel@tonic-gate int pfc_remove_assigned_prop(dev_info_t *, pci_regspec_t *); 730Sstevel@tonic-gate int pci_alloc_resource(dev_info_t *, pci_regspec_t); 740Sstevel@tonic-gate int pci_free_resource(dev_info_t *, pci_regspec_t); 750Sstevel@tonic-gate int pci_alloc_mem_chunk(dev_info_t *, uint64_t, uint64_t *, uint64_t *); 760Sstevel@tonic-gate int pci_alloc_io_chunk(dev_info_t *, uint64_t, uint64_t *, uint64_t *); 770Sstevel@tonic-gate static int fcpci_indirect_map(dev_info_t *); 780Sstevel@tonic-gate 790Sstevel@tonic-gate int fcpci_unloadable; 800Sstevel@tonic-gate 811248Smrj static ddi_dma_attr_t fcpci_dma_attr = { 821248Smrj DMA_ATTR_V0, /* version number */ 831248Smrj 0x0, /* lowest usable address */ 841248Smrj 0xFFFFFFFFull, /* high DMA address range */ 851248Smrj 0xFFFFFFFFull, /* DMA counter register */ 861248Smrj 1, /* DMA address alignment */ 871248Smrj 1, /* DMA burstsizes */ 881248Smrj 1, /* min effective DMA size */ 891248Smrj 0xFFFFFFFFull, /* max DMA xfer size */ 901248Smrj 0xFFFFFFFFull, /* segment boundary */ 911248Smrj 1, /* s/g list length */ 921248Smrj 1, /* granularity of device */ 931248Smrj 0 /* DMA transfer flags */ 941248Smrj }; 951248Smrj 960Sstevel@tonic-gate #ifndef lint 971366Spetede char _depends_on[] = "misc/fcodem misc/busra"; 980Sstevel@tonic-gate #endif 990Sstevel@tonic-gate 1000Sstevel@tonic-gate #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32)) 1010Sstevel@tonic-gate #define LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 1020Sstevel@tonic-gate #define LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo)) 1030Sstevel@tonic-gate #define PCI_4GIG_LIMIT 0xFFFFFFFFUL 1040Sstevel@tonic-gate #define PCI_MEMGRAN 0x100000 1050Sstevel@tonic-gate #define PCI_IOGRAN 0x1000 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate /* 1090Sstevel@tonic-gate * Module linkage information for the kernel. 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate static struct modlmisc modlmisc = { 1120Sstevel@tonic-gate &mod_miscops, "FCode pci bus functions %I%" 1130Sstevel@tonic-gate }; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate static struct modlinkage modlinkage = { 1160Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 1170Sstevel@tonic-gate }; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate int 1200Sstevel@tonic-gate _init(void) 1210Sstevel@tonic-gate { 1220Sstevel@tonic-gate return (mod_install(&modlinkage)); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate int 1260Sstevel@tonic-gate _fini(void) 1270Sstevel@tonic-gate { 1280Sstevel@tonic-gate if (fcpci_unloadable) 1290Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1300Sstevel@tonic-gate return (EBUSY); 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate int 1340Sstevel@tonic-gate _info(struct modinfo *modinfop) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate struct pfc_ops_v { 1410Sstevel@tonic-gate char *svc_name; 1420Sstevel@tonic-gate fc_ops_t *f; 1430Sstevel@tonic-gate }; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate static struct pfc_ops_v pov[] = { 1460Sstevel@tonic-gate { "map-in", pfc_map_in}, 1470Sstevel@tonic-gate { "map-out", pfc_map_out}, 1480Sstevel@tonic-gate { "dma-map-in", pfc_dma_map_in}, 1490Sstevel@tonic-gate { "dma-map-out", pfc_dma_map_out}, 1500Sstevel@tonic-gate { "dma-sync", pfc_dma_sync}, 1510Sstevel@tonic-gate { "rx@", pfc_register_fetch}, 1520Sstevel@tonic-gate { "rl@", pfc_register_fetch}, 1530Sstevel@tonic-gate { "rw@", pfc_register_fetch}, 1540Sstevel@tonic-gate { "rb@", pfc_register_fetch}, 1550Sstevel@tonic-gate { "rx!", pfc_register_store}, 1560Sstevel@tonic-gate { "rl!", pfc_register_store}, 1570Sstevel@tonic-gate { "rw!", pfc_register_store}, 1580Sstevel@tonic-gate { "rb!", pfc_register_store}, 1590Sstevel@tonic-gate { "config-l@", pfc_config_fetch}, 1600Sstevel@tonic-gate { "config-w@", pfc_config_fetch}, 1610Sstevel@tonic-gate { "config-b@", pfc_config_fetch}, 1620Sstevel@tonic-gate { "config-l!", pfc_config_store}, 1630Sstevel@tonic-gate { "config-w!", pfc_config_store}, 1640Sstevel@tonic-gate { "config-b!", pfc_config_store}, 1650Sstevel@tonic-gate { FC_PROBE_ADDRESS, pfc_probe_address}, 1660Sstevel@tonic-gate { FC_PROBE_SPACE, pfc_probe_space}, 1670Sstevel@tonic-gate { FC_SVC_EXIT, pfc_dma_cleanup}, 1680Sstevel@tonic-gate { FC_CONFIG_CHILD, pfc_config_child}, 1690Sstevel@tonic-gate { FC_GET_FCODE_SIZE, pfc_get_fcode_size}, 1700Sstevel@tonic-gate { FC_GET_FCODE, pfc_get_fcode}, 1710Sstevel@tonic-gate { NULL, NULL} 1720Sstevel@tonic-gate }; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static struct pfc_ops_v shared_pov[] = { 1750Sstevel@tonic-gate { FC_SVC_EXIT, pfc_dma_cleanup}, 1760Sstevel@tonic-gate { NULL, NULL} 1770Sstevel@tonic-gate }; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate int pci_map_phys(dev_info_t *, pci_regspec_t *, 1800Sstevel@tonic-gate caddr_t *, ddi_device_acc_attr_t *, ddi_acc_handle_t *); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate void pci_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate fco_handle_t 1850Sstevel@tonic-gate pci_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child, 1860Sstevel@tonic-gate void *fcode, size_t fcode_size, char *unit_address, 1870Sstevel@tonic-gate struct pci_ops_bus_args *up) 1880Sstevel@tonic-gate { 1890Sstevel@tonic-gate fco_handle_t rp; 1900Sstevel@tonic-gate struct pci_ops_bus_args *bp = NULL; 1910Sstevel@tonic-gate phandle_t h; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 1940Sstevel@tonic-gate rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size, 1950Sstevel@tonic-gate unit_address, NULL); 1960Sstevel@tonic-gate rp->ap = ap; 1970Sstevel@tonic-gate rp->child = child; 1980Sstevel@tonic-gate rp->fcode = fcode; 1990Sstevel@tonic-gate rp->fcode_size = fcode_size; 2000Sstevel@tonic-gate if (unit_address) { 2010Sstevel@tonic-gate char *buf; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP); 2040Sstevel@tonic-gate (void) strcpy(buf, unit_address); 2050Sstevel@tonic-gate rp->unit_address = buf; 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate bp = kmem_zalloc(sizeof (struct pci_ops_bus_args), KM_SLEEP); 2090Sstevel@tonic-gate *bp = *up; 2100Sstevel@tonic-gate rp->bus_args = bp; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* 2130Sstevel@tonic-gate * Add the child's nodeid to our table... 2140Sstevel@tonic-gate */ 2150Sstevel@tonic-gate h = ddi_get_nodeid(rp->child); 2160Sstevel@tonic-gate fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate return (rp); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate void 2220Sstevel@tonic-gate pci_fc_ops_free_handle(fco_handle_t rp) 2230Sstevel@tonic-gate { 2240Sstevel@tonic-gate struct pci_ops_bus_args *bp; 2250Sstevel@tonic-gate struct fc_resource *ip, *np; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate ASSERT(rp); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate if (rp->next_handle) 2300Sstevel@tonic-gate fc_ops_free_handle(rp->next_handle); 2310Sstevel@tonic-gate if (rp->unit_address) 2320Sstevel@tonic-gate kmem_free(rp->unit_address, strlen(rp->unit_address) + 1); 2330Sstevel@tonic-gate if ((bp = rp->bus_args) != NULL) 2340Sstevel@tonic-gate kmem_free(bp, sizeof (struct pci_ops_bus_args)); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /* 2370Sstevel@tonic-gate * Release all the resources from the resource list 2380Sstevel@tonic-gate * XXX: We don't handle 'unknown' types, but we don't create them. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = np) { 2410Sstevel@tonic-gate np = ip->next; 2420Sstevel@tonic-gate switch (ip->type) { 2430Sstevel@tonic-gate case RT_MAP: 2440Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "pci_fc_ops_free: " 2450Sstevel@tonic-gate "pci_unmap_phys(%p)\n", ip->fc_map_handle); 2460Sstevel@tonic-gate pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec); 2470Sstevel@tonic-gate kmem_free(ip->fc_regspec, sizeof (pci_regspec_t)); 2480Sstevel@tonic-gate break; 2490Sstevel@tonic-gate case RT_DMA: 2500Sstevel@tonic-gate /* DMA has to be freed up at exit time */ 2510Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_fc_ops_free: DMA seen!\n"); 2520Sstevel@tonic-gate break; 2530Sstevel@tonic-gate default: 2540Sstevel@tonic-gate cmn_err(CE_CONT, "pci_fc_ops_free: " 2550Sstevel@tonic-gate "unknown resource type %d\n", ip->type); 2560Sstevel@tonic-gate break; 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate fc_rem_resource(rp, ip); 2590Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate kmem_free(rp, sizeof (struct fc_resource_list)); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate int 2650Sstevel@tonic-gate pci_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 2660Sstevel@tonic-gate { 2670Sstevel@tonic-gate struct pfc_ops_v *pv; 2680Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate ASSERT(rp); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* 2730Sstevel@tonic-gate * First try the generic fc_ops. If the ops is a shared op, 2740Sstevel@tonic-gate * also call our local function. 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate if (fc_ops(ap, rp->next_handle, cp) == 0) { 2770Sstevel@tonic-gate for (pv = shared_pov; pv->svc_name != NULL; ++pv) 2780Sstevel@tonic-gate if (strcmp(pv->svc_name, name) == 0) 2790Sstevel@tonic-gate return (pv->f(ap, rp, cp)); 2800Sstevel@tonic-gate return (0); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate for (pv = pov; pv->svc_name != NULL; ++pv) 2840Sstevel@tonic-gate if (strcmp(pv->svc_name, name) == 0) 2850Sstevel@tonic-gate return (pv->f(ap, rp, cp)); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "pci_fc_ops: <%s> not serviced\n", name); 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate return (-1); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate /* 2930Sstevel@tonic-gate * Create a dma mapping for a given user address. 2940Sstevel@tonic-gate */ 2950Sstevel@tonic-gate static int 2960Sstevel@tonic-gate pfc_dma_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 2970Sstevel@tonic-gate { 2980Sstevel@tonic-gate ddi_dma_handle_t h; 2990Sstevel@tonic-gate int error; 3000Sstevel@tonic-gate caddr_t virt; 3010Sstevel@tonic-gate size_t len; 3020Sstevel@tonic-gate uint_t flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT; 3030Sstevel@tonic-gate struct fc_resource *ip; 3040Sstevel@tonic-gate ddi_dma_cookie_t c; 3050Sstevel@tonic-gate struct buf *bp; 3061106Smrj uint_t ccnt; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 3090Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 3120Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * XXX: It's not clear what we should do with a non-cacheable request 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 2)); 3180Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 1)); 3190Sstevel@tonic-gate #ifdef notdef 3200Sstevel@tonic-gate cacheable = fc_cell2int(fc_arg(cp, 0)); /* XXX: do what? */ 3210Sstevel@tonic-gate #endif 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate FC_DEBUG2(6, CE_CONT, "pcf_dma_map_in: virt %p, len %d\n", virt, len); 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * Set up the address space for physio from userland 3270Sstevel@tonic-gate */ 3280Sstevel@tonic-gate error = fc_physio_setup(&bp, virt, len); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (error) { 3310Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: fc_physio_setup failed " 3320Sstevel@tonic-gate "error: %d virt: %p len %d\n", error, virt, len); 3330Sstevel@tonic-gate return (fc_priv_error(cp, "fc_physio_setup failed")); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: dma_map_in; bp = %p\n", bp); 3371248Smrj error = fc_ddi_dma_alloc_handle(ap, &fcpci_dma_attr, DDI_DMA_SLEEP, 3381248Smrj NULL, &h); 3391106Smrj if (error != DDI_SUCCESS) { 3400Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: real dma-map-in failed " 3410Sstevel@tonic-gate "error: %d virt: %p len %d\n", error, virt, len); 3420Sstevel@tonic-gate return (fc_priv_error(cp, "real dma-map-in failed")); 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3451106Smrj error = fc_ddi_dma_buf_bind_handle(h, bp, flags, DDI_DMA_SLEEP, NULL, 3461106Smrj &c, &ccnt); 3471106Smrj if ((error != DDI_DMA_MAPPED) || (ccnt != 1)) { 3481106Smrj fc_ddi_dma_free_handle(&h); 3491106Smrj FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: real dma-map-in failed " 3501106Smrj "error: %d virt: %p len %d\n", error, virt, len); 3511106Smrj return (fc_priv_error(cp, "real dma-map-in failed")); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (c.dmac_size < len) { 3551106Smrj error = fc_ddi_dma_unbind_handle(h); 3561106Smrj if (error != DDI_SUCCESS) { 3571106Smrj return (fc_priv_error(cp, "ddi_dma_unbind error")); 3581106Smrj } 3591106Smrj fc_ddi_dma_free_handle(&h); 3601106Smrj return (fc_priv_error(cp, "ddi_dma_buf_bind size < len")); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: returning devaddr %x\n", 3640Sstevel@tonic-gate c.dmac_address); 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 3670Sstevel@tonic-gate fc_result(cp, 0) = fc_uint32_t2cell(c.dmac_address); /* XXX size */ 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * Now we have to log this resource saving the handle and buf header 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 3730Sstevel@tonic-gate ip->type = RT_DMA; 3740Sstevel@tonic-gate ip->fc_dma_virt = virt; 3750Sstevel@tonic-gate ip->fc_dma_len = len; 3760Sstevel@tonic-gate ip->fc_dma_handle = h; 3770Sstevel@tonic-gate ip->fc_dma_devaddr = c.dmac_address; 3780Sstevel@tonic-gate ip->fc_dma_bp = bp; 3790Sstevel@tonic-gate fc_add_resource(rp, ip); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate static int 3850Sstevel@tonic-gate pfc_dma_sync(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 3860Sstevel@tonic-gate { 3870Sstevel@tonic-gate void *virt; 3880Sstevel@tonic-gate size_t len; 3890Sstevel@tonic-gate uint32_t devaddr; 3900Sstevel@tonic-gate int error; 3910Sstevel@tonic-gate struct fc_resource *ip; 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 3940Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 2)); 3970Sstevel@tonic-gate devaddr = fc_cell2uint32_t(fc_arg(cp, 1)); 3980Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 0)); 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /* 4010Sstevel@tonic-gate * Find if this virt is 'within' a request we know about 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate fc_lock_resource_list(rp); 4040Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 4050Sstevel@tonic-gate if (ip->type != RT_DMA) 4060Sstevel@tonic-gate continue; 4070Sstevel@tonic-gate if (ip->fc_dma_devaddr != devaddr) 4080Sstevel@tonic-gate continue; 4090Sstevel@tonic-gate if (((char *)virt >= (char *)ip->fc_dma_virt) && 4100Sstevel@tonic-gate (((char *)virt + len) <= 4110Sstevel@tonic-gate ((char *)ip->fc_dma_virt + ip->fc_dma_len))) 4120Sstevel@tonic-gate break; 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate fc_unlock_resource_list(rp); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate if (ip == NULL) 4170Sstevel@tonic-gate return (fc_priv_error(cp, "request not within a " 4180Sstevel@tonic-gate "known dma mapping")); 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate /* 4210Sstevel@tonic-gate * We know about this request, so we trust it enough to sync it. 4220Sstevel@tonic-gate * Unfortunately, we don't know which direction, so we'll do 4230Sstevel@tonic-gate * both directions. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate error = fc_ddi_dma_sync(ip->fc_dma_handle, 4270Sstevel@tonic-gate (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORCPU); 4280Sstevel@tonic-gate error |= fc_ddi_dma_sync(ip->fc_dma_handle, 4290Sstevel@tonic-gate (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORDEV); 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate if (error) 4320Sstevel@tonic-gate return (fc_priv_error(cp, "Call to ddi_dma_sync failed")); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 4350Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate static int 4390Sstevel@tonic-gate pfc_dma_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 4400Sstevel@tonic-gate { 4410Sstevel@tonic-gate void *virt; 4420Sstevel@tonic-gate size_t len; 4430Sstevel@tonic-gate uint32_t devaddr; 4440Sstevel@tonic-gate struct fc_resource *ip; 4451106Smrj int e; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 4480Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 2)); 4510Sstevel@tonic-gate devaddr = fc_cell2uint32_t(fc_arg(cp, 1)); 4520Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 0)); 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate /* 4550Sstevel@tonic-gate * Find if this virt matches a request we know about 4560Sstevel@tonic-gate */ 4570Sstevel@tonic-gate fc_lock_resource_list(rp); 4580Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 4590Sstevel@tonic-gate if (ip->type != RT_DMA) 4600Sstevel@tonic-gate continue; 4610Sstevel@tonic-gate if (ip->fc_dma_devaddr != devaddr) 4620Sstevel@tonic-gate continue; 4630Sstevel@tonic-gate if (ip->fc_dma_virt != virt) 4640Sstevel@tonic-gate continue; 4650Sstevel@tonic-gate if (len == ip->fc_dma_len) 4660Sstevel@tonic-gate break; 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate fc_unlock_resource_list(rp); 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate if (ip == NULL) 4710Sstevel@tonic-gate return (fc_priv_error(cp, "request doesn't match a " 4720Sstevel@tonic-gate "known dma mapping")); 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* 4751106Smrj * ddi_dma_unbind_handle does an implied sync ... 4760Sstevel@tonic-gate */ 4771106Smrj e = fc_ddi_dma_unbind_handle(ip->fc_dma_handle); 4781106Smrj if (e != DDI_SUCCESS) { 4791106Smrj cmn_err(CE_CONT, "pfc_dma_map_out: ddi_dma_unbind failed!\n"); 4801106Smrj } 4811106Smrj fc_ddi_dma_free_handle(&ip->fc_dma_handle); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate /* 4840Sstevel@tonic-gate * Tear down the physio mappings 4850Sstevel@tonic-gate */ 4860Sstevel@tonic-gate fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len); 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* 4890Sstevel@tonic-gate * remove the resource from the list and release it. 4900Sstevel@tonic-gate */ 4910Sstevel@tonic-gate fc_rem_resource(rp, ip); 4920Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 4950Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate static struct fc_resource * 4990Sstevel@tonic-gate next_dma_resource(fco_handle_t rp) 5000Sstevel@tonic-gate { 5010Sstevel@tonic-gate struct fc_resource *ip; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate fc_lock_resource_list(rp); 5040Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) 5050Sstevel@tonic-gate if (ip->type == RT_DMA) 5060Sstevel@tonic-gate break; 5070Sstevel@tonic-gate fc_unlock_resource_list(rp); 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate return (ip); 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate static int 5130Sstevel@tonic-gate pfc_dma_cleanup(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 5140Sstevel@tonic-gate { 5150Sstevel@tonic-gate struct fc_resource *ip; 5161106Smrj int e; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate while ((ip = next_dma_resource(rp)) != NULL) { 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate FC_DEBUG2(9, CE_CONT, "pfc_dma_cleanup: virt %x len %x\n", 5210Sstevel@tonic-gate ip->fc_dma_virt, ip->fc_dma_len); 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate /* 5240Sstevel@tonic-gate * Free the dma handle 5250Sstevel@tonic-gate */ 5261106Smrj e = fc_ddi_dma_unbind_handle(ip->fc_dma_handle); 5271106Smrj if (e != DDI_SUCCESS) { 5280Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_dma_cleanup: " 5291106Smrj "ddi_dma_unbind failed!\n"); 5301106Smrj } 5311106Smrj fc_ddi_dma_free_handle(&ip->fc_dma_handle); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate /* 5340Sstevel@tonic-gate * Tear down the userland mapping and free the buf header 5350Sstevel@tonic-gate */ 5360Sstevel@tonic-gate fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate fc_rem_resource(rp, ip); 5390Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 5430Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate static int 5470Sstevel@tonic-gate pfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 5480Sstevel@tonic-gate { 5490Sstevel@tonic-gate size_t len; 5500Sstevel@tonic-gate int error; 5510Sstevel@tonic-gate caddr_t virt; 5520Sstevel@tonic-gate pci_regspec_t p, *ph; 5530Sstevel@tonic-gate struct fc_resource *ip; 5540Sstevel@tonic-gate ddi_device_acc_attr_t acc; 5550Sstevel@tonic-gate ddi_acc_handle_t h; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 4) 5580Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 4")); 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 5610Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate p.pci_size_hi = 0; 5640Sstevel@tonic-gate p.pci_size_low = len = fc_cell2size(fc_arg(cp, 0)); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 1)); 5670Sstevel@tonic-gate p.pci_phys_mid = fc_cell2uint(fc_arg(cp, 2)); 5680Sstevel@tonic-gate p.pci_phys_low = fc_cell2uint(fc_arg(cp, 3)); 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* 5730Sstevel@tonic-gate * Fcode is expecting the bytes are not swapped. 5740Sstevel@tonic-gate */ 5750Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 5760Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /* 5790Sstevel@tonic-gate * First We need to allocate the PCI Resource. 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate error = pci_alloc_resource(rp->child, p); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (error) { 5840Sstevel@tonic-gate return (fc_priv_error(cp, "pci map-in failed")); 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate error = pci_map_phys(rp->child, &p, &virt, &acc, &h); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate if (error) { 5900Sstevel@tonic-gate return (fc_priv_error(cp, "pci map-in failed")); 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 5940Sstevel@tonic-gate fc_result(cp, 0) = fc_ptr2cell(virt); 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 5970Sstevel@tonic-gate * Log this resource ... 5980Sstevel@tonic-gate */ 5990Sstevel@tonic-gate ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 6000Sstevel@tonic-gate ip->type = RT_MAP; 6010Sstevel@tonic-gate ip->fc_map_virt = virt; 6020Sstevel@tonic-gate ip->fc_map_len = len; 6030Sstevel@tonic-gate ip->fc_map_handle = h; 6040Sstevel@tonic-gate ph = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP); 6050Sstevel@tonic-gate *ph = p; 6060Sstevel@tonic-gate ip->fc_regspec = ph; /* cache a copy of the reg spec */ 6070Sstevel@tonic-gate fc_add_resource(rp, ip); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate static int 6130Sstevel@tonic-gate pfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 6140Sstevel@tonic-gate { 6150Sstevel@tonic-gate caddr_t virt; 6160Sstevel@tonic-gate size_t len; 6170Sstevel@tonic-gate struct fc_resource *ip; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2) 6200Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2")); 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 1)); 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 0)); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * Find if this request matches a mapping resource we set up. 6280Sstevel@tonic-gate */ 6290Sstevel@tonic-gate fc_lock_resource_list(rp); 6300Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 6310Sstevel@tonic-gate if (ip->type != RT_MAP) 6320Sstevel@tonic-gate continue; 6330Sstevel@tonic-gate if (ip->fc_map_virt != virt) 6340Sstevel@tonic-gate continue; 6350Sstevel@tonic-gate if (ip->fc_map_len == len) 6360Sstevel@tonic-gate break; 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate fc_unlock_resource_list(rp); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate if (ip == NULL) 6410Sstevel@tonic-gate return (fc_priv_error(cp, "request doesn't match a " 6420Sstevel@tonic-gate "known mapping")); 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec); 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate kmem_free(ip->fc_regspec, sizeof (pci_regspec_t)); 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate /* 6490Sstevel@tonic-gate * remove the resource from the list and release it. 6500Sstevel@tonic-gate */ 6510Sstevel@tonic-gate fc_rem_resource(rp, ip); 6520Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 6550Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate static int 6590Sstevel@tonic-gate pfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 6600Sstevel@tonic-gate { 6610Sstevel@tonic-gate size_t len; 6620Sstevel@tonic-gate caddr_t virt; 6630Sstevel@tonic-gate int error; 6640Sstevel@tonic-gate uint64_t x; 6650Sstevel@tonic-gate uint32_t l; 6660Sstevel@tonic-gate uint16_t w; 6670Sstevel@tonic-gate uint8_t b; 6680Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 6690Sstevel@tonic-gate struct fc_resource *ip; 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1) 6720Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1")); 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 6750Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 0)); 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate /* 6800Sstevel@tonic-gate * Determine the access width .. we can switch on the 2nd 6810Sstevel@tonic-gate * character of the name which is "rx@", "rl@", "rb@" or "rw@" 6820Sstevel@tonic-gate */ 6830Sstevel@tonic-gate switch (*(name + 1)) { 6840Sstevel@tonic-gate case 'x': len = sizeof (x); break; 6850Sstevel@tonic-gate case 'l': len = sizeof (l); break; 6860Sstevel@tonic-gate case 'w': len = sizeof (w); break; 6870Sstevel@tonic-gate case 'b': len = sizeof (b); break; 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate /* 6910Sstevel@tonic-gate * Check the alignment ... 6920Sstevel@tonic-gate */ 6930Sstevel@tonic-gate if (((intptr_t)virt & (len - 1)) != 0) 6940Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate /* 6970Sstevel@tonic-gate * Find if this virt is 'within' a request we know about 6980Sstevel@tonic-gate */ 6990Sstevel@tonic-gate fc_lock_resource_list(rp); 7000Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 7010Sstevel@tonic-gate if (ip->type != RT_MAP) 7020Sstevel@tonic-gate continue; 7030Sstevel@tonic-gate if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 7040Sstevel@tonic-gate ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 7050Sstevel@tonic-gate break; 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate fc_unlock_resource_list(rp); 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate if (ip == NULL) 7100Sstevel@tonic-gate return (fc_priv_error(cp, "request not within a " 7110Sstevel@tonic-gate "known mapping")); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* 7140Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 7150Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 7160Sstevel@tonic-gate * byte swapping enabled for pci register access here which 7170Sstevel@tonic-gate * is a huge dependency on the current implementation. 7180Sstevel@tonic-gate */ 7190Sstevel@tonic-gate switch (len) { 7200Sstevel@tonic-gate case sizeof (x): 7210Sstevel@tonic-gate error = ddi_peek64(rp->child, (int64_t *)virt, (int64_t *)&x); 7220Sstevel@tonic-gate break; 7230Sstevel@tonic-gate case sizeof (l): 7240Sstevel@tonic-gate error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&l); 7250Sstevel@tonic-gate break; 7260Sstevel@tonic-gate case sizeof (w): 7270Sstevel@tonic-gate error = ddi_peek16(rp->child, (int16_t *)virt, (int16_t *)&w); 7280Sstevel@tonic-gate break; 7290Sstevel@tonic-gate case sizeof (b): 7300Sstevel@tonic-gate error = ddi_peek8(rp->child, (int8_t *)virt, (int8_t *)&b); 7310Sstevel@tonic-gate break; 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate if (error) { 7350Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 7390Sstevel@tonic-gate switch (len) { 7400Sstevel@tonic-gate case sizeof (x): fc_result(cp, 0) = x; break; 7410Sstevel@tonic-gate case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 7420Sstevel@tonic-gate case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 7430Sstevel@tonic-gate case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate static int 7490Sstevel@tonic-gate pfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 7500Sstevel@tonic-gate { 7510Sstevel@tonic-gate size_t len; 7520Sstevel@tonic-gate caddr_t virt; 7530Sstevel@tonic-gate int error; 7540Sstevel@tonic-gate uint64_t x; 7550Sstevel@tonic-gate uint32_t l; 7560Sstevel@tonic-gate uint16_t w; 7570Sstevel@tonic-gate uint8_t b; 7580Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 7590Sstevel@tonic-gate struct fc_resource *ip; 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2) 7620Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2")); 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 0)); 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate /* 7670Sstevel@tonic-gate * Determine the access width .. we can switch on the 2nd 7680Sstevel@tonic-gate * character of the name which is "rl!", "rb!" or "rw!" 7690Sstevel@tonic-gate */ 7700Sstevel@tonic-gate switch (*(name + 1)) { 7710Sstevel@tonic-gate case 'x': len = sizeof (x); x = fc_arg(cp, 1); break; 7720Sstevel@tonic-gate case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break; 7730Sstevel@tonic-gate case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break; 7740Sstevel@tonic-gate case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break; 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate /* 7780Sstevel@tonic-gate * Check the alignment ... 7790Sstevel@tonic-gate */ 7800Sstevel@tonic-gate if (((intptr_t)virt & (len - 1)) != 0) 7810Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate /* 7840Sstevel@tonic-gate * Find if this virt is 'within' a request we know about 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate fc_lock_resource_list(rp); 7870Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 7880Sstevel@tonic-gate if (ip->type != RT_MAP) 7890Sstevel@tonic-gate continue; 7900Sstevel@tonic-gate if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 7910Sstevel@tonic-gate ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 7920Sstevel@tonic-gate break; 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate fc_unlock_resource_list(rp); 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate if (ip == NULL) 7970Sstevel@tonic-gate return (fc_priv_error(cp, "request not within a " 7980Sstevel@tonic-gate "known mapping")); 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate /* 8010Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 8020Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 8030Sstevel@tonic-gate * byte swapping enabled for pci register access here which 8040Sstevel@tonic-gate * is a huge dependency on the current implementation. 8050Sstevel@tonic-gate */ 8060Sstevel@tonic-gate switch (len) { 8070Sstevel@tonic-gate case sizeof (x): 8080Sstevel@tonic-gate error = ddi_poke64(rp->child, (int64_t *)virt, x); 8090Sstevel@tonic-gate break; 8100Sstevel@tonic-gate case sizeof (l): 8110Sstevel@tonic-gate error = ddi_poke32(rp->child, (int32_t *)virt, l); 8120Sstevel@tonic-gate break; 8130Sstevel@tonic-gate case sizeof (w): 8140Sstevel@tonic-gate error = ddi_poke16(rp->child, (int16_t *)virt, w); 8150Sstevel@tonic-gate break; 8160Sstevel@tonic-gate case sizeof (b): 8170Sstevel@tonic-gate error = ddi_poke8(rp->child, (int8_t *)virt, b); 8180Sstevel@tonic-gate break; 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate if (error) { 8220Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 8260Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate static int 8300Sstevel@tonic-gate pfc_config_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 8310Sstevel@tonic-gate { 8320Sstevel@tonic-gate caddr_t virt, v; 8330Sstevel@tonic-gate int error, reg, flags = 0; 8340Sstevel@tonic-gate size_t len; 8350Sstevel@tonic-gate uint32_t l, tmp; 8360Sstevel@tonic-gate uint16_t w; 8370Sstevel@tonic-gate uint8_t b; 8380Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 8390Sstevel@tonic-gate pci_regspec_t p; 8400Sstevel@tonic-gate ddi_device_acc_attr_t acc; 8410Sstevel@tonic-gate ddi_acc_handle_t h; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1) 8440Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1")); 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 8470Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate /* 8500Sstevel@tonic-gate * Construct a config address pci reg property from the args. 8510Sstevel@tonic-gate * arg[0] is the configuration address. 8520Sstevel@tonic-gate */ 8530Sstevel@tonic-gate p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0)); 8540Sstevel@tonic-gate p.pci_phys_mid = p.pci_phys_low = 0; 8550Sstevel@tonic-gate p.pci_size_hi = p.pci_size_low = 0; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate /* 8580Sstevel@tonic-gate * Verify that the address is a configuration space address 8590Sstevel@tonic-gate * ss must be zero, n,p,t must be zero. 8600Sstevel@tonic-gate */ 8610Sstevel@tonic-gate if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) || 8620Sstevel@tonic-gate ((p.pci_phys_hi & PCI_NPT_bits) != 0)) { 8630Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_config_fetch: " 8640Sstevel@tonic-gate "invalid config addr: %x\n", p.pci_phys_hi); 8650Sstevel@tonic-gate return (fc_priv_error(cp, "non-config addr")); 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* 8690Sstevel@tonic-gate * Extract the register number from the config address and 8700Sstevel@tonic-gate * remove the register number from the physical address. 8710Sstevel@tonic-gate */ 8720Sstevel@tonic-gate reg = p.pci_phys_hi & PCI_REG_REG_M; 8730Sstevel@tonic-gate p.pci_phys_hi &= ~PCI_REG_REG_M; 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* 8760Sstevel@tonic-gate * Determine the access width .. we can switch on the 9th 8770Sstevel@tonic-gate * character of the name which is "config-{l,w,b}@" 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate switch (*(name + 7)) { 8800Sstevel@tonic-gate case 'l': len = sizeof (l); break; 8810Sstevel@tonic-gate case 'w': len = sizeof (w); break; 8820Sstevel@tonic-gate case 'b': len = sizeof (b); break; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate /* 8860Sstevel@tonic-gate * Verify that the access is properly aligned 8870Sstevel@tonic-gate */ 8880Sstevel@tonic-gate if ((reg & (len - 1)) != 0) 8890Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate /* 8920Sstevel@tonic-gate * Map in configuration space (temporarily) 8930Sstevel@tonic-gate */ 8940Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 8950Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 8960Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate error = pci_map_phys(rp->child, &p, &virt, &acc, &h); 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate if (error) { 9010Sstevel@tonic-gate return (fc_priv_error(cp, "pci config map-in failed")); 9020Sstevel@tonic-gate } 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate if (fcpci_indirect_map(rp->child) == DDI_SUCCESS) 9050Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 9080Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 9090Sstevel@tonic-gate error = DDI_SUCCESS; 9100Sstevel@tonic-gate } else 9110Sstevel@tonic-gate error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate if (error == DDI_SUCCESS) 9140Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 9150Sstevel@tonic-gate error = DDI_FAILURE; 9160Sstevel@tonic-gate cmn_err(CE_CONT, "fcpcii: conf probe failed.l=%x", tmp); 9170Sstevel@tonic-gate } 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate if (error != DDI_SUCCESS) { 9200Sstevel@tonic-gate return (fc_priv_error(cp, "pci config fetch failed")); 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate /* 9250Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 9260Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 9270Sstevel@tonic-gate * byte swapping enabled for pci register access here which 9280Sstevel@tonic-gate * is a huge dependency on the current implementation. 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate v = virt + reg; 9310Sstevel@tonic-gate switch (len) { 9320Sstevel@tonic-gate case sizeof (l): 9330Sstevel@tonic-gate l = (int32_t)ddi_get32(h, (uint32_t *)v); 9340Sstevel@tonic-gate break; 9350Sstevel@tonic-gate case sizeof (w): 9360Sstevel@tonic-gate w = (int16_t)ddi_get16(h, (uint16_t *)v); 9370Sstevel@tonic-gate break; 9380Sstevel@tonic-gate case sizeof (b): 9390Sstevel@tonic-gate b = (int8_t)ddi_get8(h, (uint8_t *)v); 9400Sstevel@tonic-gate break; 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate /* 9440Sstevel@tonic-gate * Remove the temporary config space mapping 9450Sstevel@tonic-gate */ 9460Sstevel@tonic-gate pci_unmap_phys(&h, &p); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if (error) { 9490Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 9530Sstevel@tonic-gate switch (len) { 9540Sstevel@tonic-gate case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 9550Sstevel@tonic-gate case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 9560Sstevel@tonic-gate case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate static int 9630Sstevel@tonic-gate pfc_config_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 9640Sstevel@tonic-gate { 9650Sstevel@tonic-gate caddr_t virt, v; 9660Sstevel@tonic-gate int error, reg, flags = 0; 9670Sstevel@tonic-gate size_t len; 9680Sstevel@tonic-gate uint32_t l, tmp; 9690Sstevel@tonic-gate uint16_t w; 9700Sstevel@tonic-gate uint8_t b; 9710Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 9720Sstevel@tonic-gate pci_regspec_t p; 9730Sstevel@tonic-gate ddi_device_acc_attr_t acc; 9740Sstevel@tonic-gate ddi_acc_handle_t h; 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2) 9770Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2")); 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate /* 9800Sstevel@tonic-gate * Construct a config address pci reg property from the args. 9810Sstevel@tonic-gate * arg[0] is the configuration address. arg[1] is the data. 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0)); 9840Sstevel@tonic-gate p.pci_phys_mid = p.pci_phys_low = 0; 9850Sstevel@tonic-gate p.pci_size_hi = p.pci_size_low = 0; 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate /* 9880Sstevel@tonic-gate * Verify that the address is a configuration space address 9890Sstevel@tonic-gate * ss must be zero, n,p,t must be zero. 9900Sstevel@tonic-gate */ 9910Sstevel@tonic-gate if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) || 9920Sstevel@tonic-gate ((p.pci_phys_hi & PCI_NPT_bits) != 0)) { 9930Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_config_store: " 9940Sstevel@tonic-gate "invalid config addr: %x\n", p.pci_phys_hi); 9950Sstevel@tonic-gate return (fc_priv_error(cp, "non-config addr")); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate /* 9990Sstevel@tonic-gate * Extract the register number from the config address and 10000Sstevel@tonic-gate * remove the register number from the physical address. 10010Sstevel@tonic-gate */ 10020Sstevel@tonic-gate reg = p.pci_phys_hi & PCI_REG_REG_M; 10030Sstevel@tonic-gate p.pci_phys_hi &= ~PCI_REG_REG_M; 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate /* 10060Sstevel@tonic-gate * Determine the access width .. we can switch on the 8th 10070Sstevel@tonic-gate * character of the name which is "config-{l,w,b}@" 10080Sstevel@tonic-gate */ 10090Sstevel@tonic-gate switch (*(name + 7)) { 10100Sstevel@tonic-gate case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break; 10110Sstevel@tonic-gate case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break; 10120Sstevel@tonic-gate case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break; 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate /* 10160Sstevel@tonic-gate * Verify that the access is properly aligned 10170Sstevel@tonic-gate */ 10180Sstevel@tonic-gate if ((reg & (len - 1)) != 0) 10190Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate /* 10220Sstevel@tonic-gate * Map in configuration space (temporarily) 10230Sstevel@tonic-gate */ 10240Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 10250Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 10260Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate error = pci_map_phys(rp->child, &p, &virt, &acc, &h); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate if (error) { 10310Sstevel@tonic-gate return (fc_priv_error(cp, "pci config map-in failed")); 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate if (fcpci_indirect_map(rp->child) == DDI_SUCCESS) 10350Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 10380Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 10390Sstevel@tonic-gate error = DDI_SUCCESS; 10400Sstevel@tonic-gate } else 10410Sstevel@tonic-gate error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp); 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate if (error == DDI_SUCCESS) 10440Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 10450Sstevel@tonic-gate error = DDI_FAILURE; 10460Sstevel@tonic-gate cmn_err(CE_CONT, "fcpci: conf probe failed.l=%x", tmp); 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate if (error != DDI_SUCCESS) { 10500Sstevel@tonic-gate return (fc_priv_error(cp, "pci config store failed")); 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate /* 10550Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 10560Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 10570Sstevel@tonic-gate * byte swapping enabled for pci register access here which 10580Sstevel@tonic-gate * is a huge dependency on the current implementation. 10590Sstevel@tonic-gate */ 10600Sstevel@tonic-gate v = virt + reg; 10610Sstevel@tonic-gate switch (len) { 10620Sstevel@tonic-gate case sizeof (l): 10630Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, (uint32_t)l); 10640Sstevel@tonic-gate break; 10650Sstevel@tonic-gate case sizeof (w): 10660Sstevel@tonic-gate ddi_put16(h, (uint16_t *)v, (uint16_t)w); 10670Sstevel@tonic-gate break; 10680Sstevel@tonic-gate case sizeof (b): 10690Sstevel@tonic-gate ddi_put8(h, (uint8_t *)v, (uint8_t)b); 10700Sstevel@tonic-gate break; 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate /* 10740Sstevel@tonic-gate * Remove the temporary config space mapping 10750Sstevel@tonic-gate */ 10760Sstevel@tonic-gate pci_unmap_phys(&h, &p); 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate if (error) { 10790Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 10800Sstevel@tonic-gate } 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 10830Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate static int 10880Sstevel@tonic-gate pfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 10890Sstevel@tonic-gate { 10900Sstevel@tonic-gate caddr_t name_virt, fcode_virt; 10910Sstevel@tonic-gate char *name, *fcode; 10920Sstevel@tonic-gate int fcode_len, status; 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 10950Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 10980Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate name_virt = fc_cell2ptr(fc_arg(cp, 0)); 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate fcode_len = fc_cell2int(fc_arg(cp, 2)); 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate if (copyinstr(fc_cell2ptr(name_virt), name, 11090Sstevel@tonic-gate FC_SVC_NAME_LEN - 1, NULL)) { 11100Sstevel@tonic-gate status = 0; 11110Sstevel@tonic-gate } else { 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate fcode = kmem_zalloc(fcode_len, KM_SLEEP); 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate if ((status = prom_get_fcode(name, fcode)) != 0) { 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate if (copyout((void *)fcode, (void *)fcode_virt, 11180Sstevel@tonic-gate fcode_len)) { 11190Sstevel@tonic-gate cmn_err(CE_WARN, " pfc_get_fcode: Unable " 11200Sstevel@tonic-gate "to copy out fcode image\n"); 11210Sstevel@tonic-gate status = 0; 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate } 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate kmem_free(fcode, fcode_len); 11260Sstevel@tonic-gate } 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 11310Sstevel@tonic-gate fc_result(cp, 0) = status; 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate static int 11370Sstevel@tonic-gate pfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 11380Sstevel@tonic-gate { 11390Sstevel@tonic-gate caddr_t virt; 11400Sstevel@tonic-gate char *name; 11410Sstevel@tonic-gate int len; 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1) 11440Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1")); 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 11470Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 0)); 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate if (copyinstr(fc_cell2ptr(virt), name, 11540Sstevel@tonic-gate FC_SVC_NAME_LEN - 1, NULL)) { 11550Sstevel@tonic-gate len = 0; 11560Sstevel@tonic-gate } else { 11570Sstevel@tonic-gate len = prom_get_fcode_size(name); 11580Sstevel@tonic-gate } 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 11630Sstevel@tonic-gate fc_result(cp, 0) = len; 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate /* 11690Sstevel@tonic-gate * Return the physical probe address: lo=0, mid=0, hi-config-addr 11700Sstevel@tonic-gate */ 11710Sstevel@tonic-gate static int 11720Sstevel@tonic-gate pfc_probe_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 11730Sstevel@tonic-gate { 11740Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0) 11750Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0")); 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 2) 11780Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 3")); 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate cp->nresults = fc_int2cell(2); 11810Sstevel@tonic-gate fc_result(cp, 1) = fc_int2cell(0); /* phys.lo */ 11820Sstevel@tonic-gate fc_result(cp, 0) = fc_int2cell(0); /* phys.mid */ 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate /* 11880Sstevel@tonic-gate * Return the phys.hi component of the probe address. 11890Sstevel@tonic-gate */ 11900Sstevel@tonic-gate static int 11910Sstevel@tonic-gate pfc_probe_space(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 11920Sstevel@tonic-gate { 11930Sstevel@tonic-gate struct pci_ops_bus_args *ba = rp->bus_args; 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate ASSERT(ba); 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0) 11980Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0")); 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 12010Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 12040Sstevel@tonic-gate fc_result(cp, 0) = fc_uint32_t2cell(ba->config_address); /* phys.hi */ 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate static int 12100Sstevel@tonic-gate pfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 12110Sstevel@tonic-gate { 12120Sstevel@tonic-gate fc_phandle_t h; 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0) 12150Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0")); 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 12180Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 12230Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h); 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 12260Sstevel@tonic-gate } 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate int 12290Sstevel@tonic-gate pci_alloc_mem_chunk(dev_info_t *dip, uint64_t mem_align, uint64_t *mem_size, 12300Sstevel@tonic-gate uint64_t *mem_answer) 12310Sstevel@tonic-gate { 12320Sstevel@tonic-gate ndi_ra_request_t req; 12330Sstevel@tonic-gate int rval; 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 12360Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_BOUNDED; 12370Sstevel@tonic-gate req.ra_boundbase = 0; 12380Sstevel@tonic-gate req.ra_boundlen = PCI_4GIG_LIMIT; 12390Sstevel@tonic-gate req.ra_len = *mem_size; 12400Sstevel@tonic-gate req.ra_align_mask = mem_align - 1; 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate rval = ndi_ra_alloc(dip, &req, mem_answer, mem_size, 12430Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS); 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate return (rval); 12460Sstevel@tonic-gate } 12470Sstevel@tonic-gate int 12480Sstevel@tonic-gate pci_alloc_io_chunk(dev_info_t *dip, uint64_t io_align, uint64_t *io_size, 12490Sstevel@tonic-gate uint64_t *io_answer) 12500Sstevel@tonic-gate { 12510Sstevel@tonic-gate ndi_ra_request_t req; 12520Sstevel@tonic-gate int rval; 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 12550Sstevel@tonic-gate req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 12560Sstevel@tonic-gate req.ra_boundbase = 0; 12570Sstevel@tonic-gate req.ra_boundlen = PCI_4GIG_LIMIT; 12580Sstevel@tonic-gate req.ra_len = *io_size; 12590Sstevel@tonic-gate req.ra_align_mask = io_align - 1; 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate rval = ndi_ra_alloc(dip, &req, io_answer, io_size, 12620Sstevel@tonic-gate NDI_RA_TYPE_IO, NDI_RA_PASS); 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate return (rval); 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate int 12680Sstevel@tonic-gate pci_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec) 12690Sstevel@tonic-gate { 12700Sstevel@tonic-gate uint64_t answer; 12710Sstevel@tonic-gate uint64_t alen; 12720Sstevel@tonic-gate int offset, tmp; 12730Sstevel@tonic-gate pci_regspec_t config; 12740Sstevel@tonic-gate caddr_t virt, v; 12750Sstevel@tonic-gate ddi_device_acc_attr_t acc; 12760Sstevel@tonic-gate ddi_acc_handle_t h; 12770Sstevel@tonic-gate ndi_ra_request_t request; 12780Sstevel@tonic-gate pci_regspec_t *assigned; 12790Sstevel@tonic-gate int assigned_len, entries, i, l, flags = 0, error; 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate l = phys_spec.pci_size_low; 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 12840Sstevel@tonic-gate DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 12850Sstevel@tonic-gate &assigned_len) == DDI_PROP_SUCCESS) { 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate entries = assigned_len / (sizeof (pci_regspec_t)); 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate /* 12900Sstevel@tonic-gate * Walk through the assigned-addresses entries. If there is 12910Sstevel@tonic-gate * a match, there is no need to allocate the resource. 12920Sstevel@tonic-gate */ 12930Sstevel@tonic-gate for (i = 0; i < entries; i++) { 12940Sstevel@tonic-gate if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) { 12950Sstevel@tonic-gate if (assigned[i].pci_size_low >= 12960Sstevel@tonic-gate phys_spec.pci_size_low) { 12970Sstevel@tonic-gate kmem_free(assigned, assigned_len); 12980Sstevel@tonic-gate return (0); 12990Sstevel@tonic-gate } 13000Sstevel@tonic-gate /* 13010Sstevel@tonic-gate * Fcode wants to assign more than what 13020Sstevel@tonic-gate * probe found. 13030Sstevel@tonic-gate */ 13040Sstevel@tonic-gate (void) pci_free_resource(dip, assigned[i]); 13050Sstevel@tonic-gate /* 13060Sstevel@tonic-gate * Go on to allocate resources. 13070Sstevel@tonic-gate */ 13080Sstevel@tonic-gate break; 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate /* 13110Sstevel@tonic-gate * Check if Fcode wants to map using different 13120Sstevel@tonic-gate * NPT bits. 13130Sstevel@tonic-gate */ 13140Sstevel@tonic-gate if (PCI_REG_BDFR_G(assigned[i].pci_phys_hi) == 13150Sstevel@tonic-gate PCI_REG_BDFR_G(phys_spec.pci_phys_hi)) { 13160Sstevel@tonic-gate /* 13170Sstevel@tonic-gate * It is an error to change SS bits 13180Sstevel@tonic-gate */ 13190Sstevel@tonic-gate if (PCI_REG_ADDR_G(assigned[i].pci_phys_hi) != 13200Sstevel@tonic-gate PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 13210Sstevel@tonic-gate 1322*1983Sjj156685 FC_DEBUG2(2, CE_WARN, "Fcode changing " 1323*1983Sjj156685 "ss bits in reg %x -- %x", 13240Sstevel@tonic-gate assigned[i].pci_phys_hi, 13250Sstevel@tonic-gate phys_spec.pci_phys_hi); 13260Sstevel@tonic-gate } 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate /* 13290Sstevel@tonic-gate * Allocate enough 13300Sstevel@tonic-gate */ 13310Sstevel@tonic-gate l = MAX(assigned[i].pci_size_low, 13320Sstevel@tonic-gate phys_spec.pci_size_low); 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate (void) pci_free_resource(dip, assigned[i]); 13350Sstevel@tonic-gate /* 13360Sstevel@tonic-gate * Go on to allocate resources. 13370Sstevel@tonic-gate */ 13380Sstevel@tonic-gate break; 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate kmem_free(assigned, assigned_len); 13420Sstevel@tonic-gate } 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 13470Sstevel@tonic-gate config.pci_phys_hi &= ~PCI_REG_REG_M; 13480Sstevel@tonic-gate config.pci_phys_mid = config.pci_phys_low = 0; 13490Sstevel@tonic-gate config.pci_size_hi = config.pci_size_low = 0; 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate /* 13520Sstevel@tonic-gate * Map in configuration space (temporarily) 13530Sstevel@tonic-gate */ 13540Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 13550Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 13560Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 13570Sstevel@tonic-gate 13580Sstevel@tonic-gate if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) { 13590Sstevel@tonic-gate return (1); 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate if (fcpci_indirect_map(dip) == DDI_SUCCESS) 13630Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 13660Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 13670Sstevel@tonic-gate error = DDI_SUCCESS; 13680Sstevel@tonic-gate } else 13690Sstevel@tonic-gate error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp); 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate if (error == DDI_SUCCESS) 13720Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 13730Sstevel@tonic-gate error = DDI_FAILURE; 13740Sstevel@tonic-gate } 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate if (error != DDI_SUCCESS) { 13770Sstevel@tonic-gate return (1); 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate request.ra_flags |= NDI_RA_ALIGN_SIZE; 13810Sstevel@tonic-gate request.ra_boundbase = 0; 13820Sstevel@tonic-gate request.ra_boundlen = PCI_4GIG_LIMIT; 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate v = virt + offset; 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 13890Sstevel@tonic-gate request.ra_len = l; 13900Sstevel@tonic-gate request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate /* allocate memory space from the allocator */ 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 13950Sstevel@tonic-gate &request, &answer, &alen, 13960Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS) 13970Sstevel@tonic-gate != NDI_SUCCESS) { 13980Sstevel@tonic-gate pci_unmap_phys(&h, &config); 13990Sstevel@tonic-gate return (1); 14000Sstevel@tonic-gate } 14010Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, "ROM addr = [0x%x.%x] len [0x%x]\n", 14020Sstevel@tonic-gate HIADDR(answer), 14030Sstevel@tonic-gate LOADDR(answer), 14040Sstevel@tonic-gate alen); 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate /* program the low word */ 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 14110Sstevel@tonic-gate phys_spec.pci_phys_mid = HIADDR(answer); 14120Sstevel@tonic-gate } else { 14130Sstevel@tonic-gate request.ra_len = l; 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 14160Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 14170Sstevel@tonic-gate request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 14180Sstevel@tonic-gate 14190Sstevel@tonic-gate if (phys_spec.pci_phys_hi & PCI_REG_REL_M) { 14200Sstevel@tonic-gate /* 14210Sstevel@tonic-gate * If it is a non relocatable address, 14220Sstevel@tonic-gate * then specify the address we want. 14230Sstevel@tonic-gate */ 14240Sstevel@tonic-gate request.ra_flags = NDI_RA_ALLOC_SPECIFIED; 14250Sstevel@tonic-gate request.ra_addr = (uint64_t)LADDR( 14260Sstevel@tonic-gate phys_spec.pci_phys_low, 14270Sstevel@tonic-gate phys_spec.pci_phys_mid); 14280Sstevel@tonic-gate } 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate /* allocate memory space from the allocator */ 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 14330Sstevel@tonic-gate &request, &answer, &alen, 14340Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS) 14350Sstevel@tonic-gate != NDI_SUCCESS) { 14360Sstevel@tonic-gate pci_unmap_phys(&h, &config); 14370Sstevel@tonic-gate if (request.ra_flags == 14380Sstevel@tonic-gate NDI_RA_ALLOC_SPECIFIED) 14390Sstevel@tonic-gate cmn_err(CE_WARN, "Unable to allocate " 14400Sstevel@tonic-gate "non relocatable address 0x%p\n", 14410Sstevel@tonic-gate (void *) request.ra_addr); 14420Sstevel@tonic-gate return (1); 14430Sstevel@tonic-gate } 14440Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, 14450Sstevel@tonic-gate "64 addr = [0x%x.%x] len [0x%x]\n", 14460Sstevel@tonic-gate HIADDR(answer), 14470Sstevel@tonic-gate LOADDR(answer), 14480Sstevel@tonic-gate alen); 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate /* program the low word */ 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate /* program the high word with value zero */ 14550Sstevel@tonic-gate v += 4; 14560Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, HIADDR(answer)); 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 14590Sstevel@tonic-gate phys_spec.pci_phys_mid = HIADDR(answer); 1460*1983Sjj156685 /* 1461*1983Sjj156685 * currently support 32b address space 1462*1983Sjj156685 * assignments only. 1463*1983Sjj156685 */ 1464*1983Sjj156685 phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^ 1465*1983Sjj156685 PCI_ADDR_MEM32; 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate break; 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 14700Sstevel@tonic-gate request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 14710Sstevel@tonic-gate 14720Sstevel@tonic-gate if (phys_spec.pci_phys_hi & PCI_REG_REL_M) { 14730Sstevel@tonic-gate /* 14740Sstevel@tonic-gate * If it is a non relocatable address, 14750Sstevel@tonic-gate * then specify the address we want. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate request.ra_flags = NDI_RA_ALLOC_SPECIFIED; 14780Sstevel@tonic-gate request.ra_addr = (uint64_t) 14790Sstevel@tonic-gate phys_spec.pci_phys_low; 14800Sstevel@tonic-gate } 14810Sstevel@tonic-gate 14820Sstevel@tonic-gate /* allocate memory space from the allocator */ 14830Sstevel@tonic-gate 14840Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 14850Sstevel@tonic-gate &request, &answer, &alen, 14860Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS) 14870Sstevel@tonic-gate != NDI_SUCCESS) { 14880Sstevel@tonic-gate pci_unmap_phys(&h, &config); 14890Sstevel@tonic-gate if (request.ra_flags == 14900Sstevel@tonic-gate NDI_RA_ALLOC_SPECIFIED) 14910Sstevel@tonic-gate cmn_err(CE_WARN, "Unable to allocate " 14920Sstevel@tonic-gate "non relocatable address 0x%p\n", 14930Sstevel@tonic-gate (void *) request.ra_addr); 14940Sstevel@tonic-gate return (1); 14950Sstevel@tonic-gate } 14960Sstevel@tonic-gate 14970Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, 14980Sstevel@tonic-gate "32 addr = [0x%x.%x] len [0x%x]\n", 14990Sstevel@tonic-gate HIADDR(answer), 15000Sstevel@tonic-gate LOADDR(answer), 15010Sstevel@tonic-gate alen); 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate /* program the low word */ 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate break; 15100Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO): 15110Sstevel@tonic-gate request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate if (phys_spec.pci_phys_hi & PCI_REG_REL_M) { 15140Sstevel@tonic-gate /* 15150Sstevel@tonic-gate * If it is a non relocatable address, 15160Sstevel@tonic-gate * then specify the address we want. 15170Sstevel@tonic-gate */ 15180Sstevel@tonic-gate request.ra_flags = NDI_RA_ALLOC_SPECIFIED; 15190Sstevel@tonic-gate request.ra_addr = (uint64_t) 15200Sstevel@tonic-gate phys_spec.pci_phys_low; 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate /* allocate I/O space from the allocator */ 15240Sstevel@tonic-gate 15250Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 15260Sstevel@tonic-gate &request, &answer, &alen, 15270Sstevel@tonic-gate NDI_RA_TYPE_IO, NDI_RA_PASS) 15280Sstevel@tonic-gate != NDI_SUCCESS) { 15290Sstevel@tonic-gate pci_unmap_phys(&h, &config); 15300Sstevel@tonic-gate if (request.ra_flags == 15310Sstevel@tonic-gate NDI_RA_ALLOC_SPECIFIED) 15320Sstevel@tonic-gate cmn_err(CE_WARN, "Unable to allocate " 15330Sstevel@tonic-gate "non relocatable IO Space 0x%p\n", 15340Sstevel@tonic-gate (void *) request.ra_addr); 15350Sstevel@tonic-gate return (1); 15360Sstevel@tonic-gate } 15370Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, 15380Sstevel@tonic-gate "I/O addr = [0x%x.%x] len [0x%x]\n", 15390Sstevel@tonic-gate HIADDR(answer), 15400Sstevel@tonic-gate LOADDR(answer), 15410Sstevel@tonic-gate alen); 15420Sstevel@tonic-gate 15430Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate break; 15480Sstevel@tonic-gate default: 15490Sstevel@tonic-gate pci_unmap_phys(&h, &config); 15500Sstevel@tonic-gate return (1); 15510Sstevel@tonic-gate } /* switch */ 15520Sstevel@tonic-gate } 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate /* 15550Sstevel@tonic-gate * Now that memory locations are assigned, 15560Sstevel@tonic-gate * update the assigned address property. 15570Sstevel@tonic-gate */ 15580Sstevel@tonic-gate if (pfc_update_assigned_prop(dip, &phys_spec)) { 15590Sstevel@tonic-gate pci_unmap_phys(&h, &config); 15600Sstevel@tonic-gate return (1); 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate pci_unmap_phys(&h, &config); 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate return (0); 15660Sstevel@tonic-gate } 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate int 15690Sstevel@tonic-gate pci_free_resource(dev_info_t *dip, pci_regspec_t phys_spec) 15700Sstevel@tonic-gate { 15710Sstevel@tonic-gate int offset, tmp; 15720Sstevel@tonic-gate pci_regspec_t config; 15730Sstevel@tonic-gate caddr_t virt, v; 15740Sstevel@tonic-gate ddi_device_acc_attr_t acc; 15750Sstevel@tonic-gate ddi_acc_handle_t h; 15760Sstevel@tonic-gate ndi_ra_request_t request; 15770Sstevel@tonic-gate int l, error, flags = 0; 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 15820Sstevel@tonic-gate config.pci_phys_hi &= ~PCI_REG_REG_M; 15830Sstevel@tonic-gate config.pci_phys_mid = config.pci_phys_low = 0; 15840Sstevel@tonic-gate config.pci_size_hi = config.pci_size_low = 0; 15850Sstevel@tonic-gate 15860Sstevel@tonic-gate /* 15870Sstevel@tonic-gate * Map in configuration space (temporarily) 15880Sstevel@tonic-gate */ 15890Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 15900Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 15910Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) { 15940Sstevel@tonic-gate return (1); 15950Sstevel@tonic-gate } 15960Sstevel@tonic-gate if (fcpci_indirect_map(dip) == DDI_SUCCESS) 15970Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 16000Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 16010Sstevel@tonic-gate error = DDI_SUCCESS; 16020Sstevel@tonic-gate } else 16030Sstevel@tonic-gate error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp); 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate if (error == DDI_SUCCESS) 16060Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 16070Sstevel@tonic-gate error = DDI_FAILURE; 16080Sstevel@tonic-gate } 16090Sstevel@tonic-gate if (error != DDI_SUCCESS) { 16100Sstevel@tonic-gate return (1); 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate v = virt + offset; 16170Sstevel@tonic-gate 16180Sstevel@tonic-gate /* 16190Sstevel@tonic-gate * Pick up the size to be freed. It may be different from 16200Sstevel@tonic-gate * what probe finds. 16210Sstevel@tonic-gate */ 16220Sstevel@tonic-gate l = phys_spec.pci_size_low; 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 16250Sstevel@tonic-gate /* free memory back to the allocator */ 16260Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low, 16270Sstevel@tonic-gate l, NDI_RA_TYPE_MEM, 16280Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 16290Sstevel@tonic-gate pci_unmap_phys(&h, &config); 16300Sstevel@tonic-gate return (1); 16310Sstevel@tonic-gate } 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate /* Unmap the BAR by writing a zero */ 16340Sstevel@tonic-gate 16350Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, 0); 16360Sstevel@tonic-gate } else { 16370Sstevel@tonic-gate switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 16380Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 16390Sstevel@tonic-gate /* free memory back to the allocator */ 16400Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), 16410Sstevel@tonic-gate LADDR(phys_spec.pci_phys_low, 16420Sstevel@tonic-gate phys_spec.pci_phys_mid), 16430Sstevel@tonic-gate l, NDI_RA_TYPE_MEM, 16440Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 16450Sstevel@tonic-gate pci_unmap_phys(&h, &config); 16460Sstevel@tonic-gate return (1); 16470Sstevel@tonic-gate } 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate break; 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 16520Sstevel@tonic-gate /* free memory back to the allocator */ 16530Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), 16540Sstevel@tonic-gate phys_spec.pci_phys_low, 16550Sstevel@tonic-gate l, NDI_RA_TYPE_MEM, 16560Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 16570Sstevel@tonic-gate pci_unmap_phys(&h, &config); 16580Sstevel@tonic-gate return (1); 16590Sstevel@tonic-gate } 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate break; 16620Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO): 16630Sstevel@tonic-gate /* free I/O space back to the allocator */ 16640Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), 16650Sstevel@tonic-gate phys_spec.pci_phys_low, 16660Sstevel@tonic-gate l, NDI_RA_TYPE_IO, 16670Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 16680Sstevel@tonic-gate pci_unmap_phys(&h, &config); 16690Sstevel@tonic-gate return (1); 16700Sstevel@tonic-gate } 16710Sstevel@tonic-gate break; 16720Sstevel@tonic-gate default: 16730Sstevel@tonic-gate pci_unmap_phys(&h, &config); 16740Sstevel@tonic-gate return (1); 16750Sstevel@tonic-gate } /* switch */ 16760Sstevel@tonic-gate } 16770Sstevel@tonic-gate 16780Sstevel@tonic-gate /* 16790Sstevel@tonic-gate * Now that memory locations are assigned, 16800Sstevel@tonic-gate * update the assigned address property. 16810Sstevel@tonic-gate */ 16820Sstevel@tonic-gate 16830Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "updating assigned-addresss for %x\n", 16840Sstevel@tonic-gate phys_spec.pci_phys_hi); 16850Sstevel@tonic-gate 16860Sstevel@tonic-gate if (pfc_remove_assigned_prop(dip, &phys_spec)) { 16870Sstevel@tonic-gate pci_unmap_phys(&h, &config); 16880Sstevel@tonic-gate return (1); 16890Sstevel@tonic-gate } 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate pci_unmap_phys(&h, &config); 16920Sstevel@tonic-gate 16930Sstevel@tonic-gate return (0); 16940Sstevel@tonic-gate } 16950Sstevel@tonic-gate 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate int 16980Sstevel@tonic-gate pci_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 16990Sstevel@tonic-gate caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 17000Sstevel@tonic-gate ddi_acc_handle_t *handlep) 17010Sstevel@tonic-gate { 17020Sstevel@tonic-gate ddi_map_req_t mr; 17030Sstevel@tonic-gate ddi_acc_hdl_t *hp; 17040Sstevel@tonic-gate int result; 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 17070Sstevel@tonic-gate hp = impl_acc_hdl_get(*handlep); 17080Sstevel@tonic-gate hp->ah_vers = VERS_ACCHDL; 17090Sstevel@tonic-gate hp->ah_dip = dip; 17100Sstevel@tonic-gate hp->ah_rnumber = 0; 17110Sstevel@tonic-gate hp->ah_offset = 0; 17120Sstevel@tonic-gate hp->ah_len = 0; 17130Sstevel@tonic-gate hp->ah_acc = *accattrp; 17140Sstevel@tonic-gate 17150Sstevel@tonic-gate mr.map_op = DDI_MO_MAP_LOCKED; 17160Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 17170Sstevel@tonic-gate mr.map_obj.rp = (struct regspec *)phys_spec; 17180Sstevel@tonic-gate mr.map_prot = PROT_READ | PROT_WRITE; 17190Sstevel@tonic-gate mr.map_flags = DDI_MF_KERNEL_MAPPING; 17200Sstevel@tonic-gate mr.map_handlep = hp; 17210Sstevel@tonic-gate mr.map_vers = DDI_MAP_VERSION; 17220Sstevel@tonic-gate 17230Sstevel@tonic-gate result = ddi_map(dip, &mr, 0, 0, addrp); 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate if (result != DDI_SUCCESS) { 17260Sstevel@tonic-gate impl_acc_hdl_free(*handlep); 17270Sstevel@tonic-gate *handlep = (ddi_acc_handle_t)NULL; 17280Sstevel@tonic-gate } else { 17290Sstevel@tonic-gate hp->ah_addr = *addrp; 17300Sstevel@tonic-gate } 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate return (result); 17330Sstevel@tonic-gate } 17340Sstevel@tonic-gate 17350Sstevel@tonic-gate void 17360Sstevel@tonic-gate pci_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 17370Sstevel@tonic-gate { 17380Sstevel@tonic-gate ddi_map_req_t mr; 17390Sstevel@tonic-gate ddi_acc_hdl_t *hp; 17400Sstevel@tonic-gate 17410Sstevel@tonic-gate hp = impl_acc_hdl_get(*handlep); 17420Sstevel@tonic-gate ASSERT(hp); 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate mr.map_op = DDI_MO_UNMAP; 17450Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 17460Sstevel@tonic-gate mr.map_obj.rp = (struct regspec *)ph; 17470Sstevel@tonic-gate mr.map_prot = PROT_READ | PROT_WRITE; 17480Sstevel@tonic-gate mr.map_flags = DDI_MF_KERNEL_MAPPING; 17490Sstevel@tonic-gate mr.map_handlep = hp; 17500Sstevel@tonic-gate mr.map_vers = DDI_MAP_VERSION; 17510Sstevel@tonic-gate 17520Sstevel@tonic-gate (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 17530Sstevel@tonic-gate hp->ah_len, &hp->ah_addr); 17540Sstevel@tonic-gate 17550Sstevel@tonic-gate impl_acc_hdl_free(*handlep); 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate *handlep = (ddi_acc_handle_t)NULL; 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate int 17620Sstevel@tonic-gate pfc_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone) 17630Sstevel@tonic-gate { 17640Sstevel@tonic-gate int alen; 17650Sstevel@tonic-gate pci_regspec_t *assigned; 17660Sstevel@tonic-gate caddr_t newreg; 17670Sstevel@tonic-gate uint_t status; 17680Sstevel@tonic-gate 1769506Scth status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 17700Sstevel@tonic-gate "assigned-addresses", (caddr_t)&assigned, &alen); 17710Sstevel@tonic-gate switch (status) { 17720Sstevel@tonic-gate case DDI_PROP_SUCCESS: 17730Sstevel@tonic-gate break; 17740Sstevel@tonic-gate case DDI_PROP_NO_MEMORY: 17750Sstevel@tonic-gate return (1); 17760Sstevel@tonic-gate default: 17770Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 17780Sstevel@tonic-gate "assigned-addresses", (int *)newone, 17790Sstevel@tonic-gate sizeof (*newone)/sizeof (int)); 17800Sstevel@tonic-gate return (0); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate /* 17840Sstevel@tonic-gate * Allocate memory for the existing 17850Sstevel@tonic-gate * assigned-addresses(s) plus one and then 17860Sstevel@tonic-gate * build it. 17870Sstevel@tonic-gate */ 17880Sstevel@tonic-gate 17890Sstevel@tonic-gate newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP); 17900Sstevel@tonic-gate 17910Sstevel@tonic-gate bcopy(assigned, newreg, alen); 17920Sstevel@tonic-gate bcopy(newone, newreg + alen, sizeof (*newone)); 17930Sstevel@tonic-gate 17940Sstevel@tonic-gate /* 17950Sstevel@tonic-gate * Write out the new "assigned-addresses" spec 17960Sstevel@tonic-gate */ 17970Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 17980Sstevel@tonic-gate "assigned-addresses", (int *)newreg, 17990Sstevel@tonic-gate (alen + sizeof (*newone))/sizeof (int)); 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate kmem_free((caddr_t)newreg, alen+sizeof (*newone)); 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate return (0); 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate int 18060Sstevel@tonic-gate pfc_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone) 18070Sstevel@tonic-gate { 18080Sstevel@tonic-gate int alen, new_len, num_entries, i; 18090Sstevel@tonic-gate pci_regspec_t *assigned; 18100Sstevel@tonic-gate uint_t status; 18110Sstevel@tonic-gate 1812506Scth status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 18130Sstevel@tonic-gate "assigned-addresses", (caddr_t)&assigned, &alen); 18140Sstevel@tonic-gate switch (status) { 18150Sstevel@tonic-gate case DDI_PROP_SUCCESS: 18160Sstevel@tonic-gate break; 18170Sstevel@tonic-gate case DDI_PROP_NO_MEMORY: 18180Sstevel@tonic-gate return (1); 18190Sstevel@tonic-gate default: 18200Sstevel@tonic-gate return (0); 18210Sstevel@tonic-gate } 18220Sstevel@tonic-gate 18230Sstevel@tonic-gate num_entries = alen / sizeof (pci_regspec_t); 18240Sstevel@tonic-gate new_len = alen - sizeof (pci_regspec_t); 18250Sstevel@tonic-gate 18260Sstevel@tonic-gate /* 18270Sstevel@tonic-gate * Search for the memory being removed. 18280Sstevel@tonic-gate */ 18290Sstevel@tonic-gate for (i = 0; i < num_entries; i++) { 18300Sstevel@tonic-gate if (assigned[i].pci_phys_hi == oldone->pci_phys_hi) { 18310Sstevel@tonic-gate if (new_len == 0) { 18320Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, 18330Sstevel@tonic-gate "assigned-addresses"); 18340Sstevel@tonic-gate break; 18350Sstevel@tonic-gate } 18360Sstevel@tonic-gate if ((new_len - (i * sizeof (pci_regspec_t))) 18370Sstevel@tonic-gate == 0) { 18380Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "assigned-address entry " 18390Sstevel@tonic-gate "%x removed from property (last entry)\n", 18400Sstevel@tonic-gate oldone->pci_phys_hi); 18410Sstevel@tonic-gate } else { 18420Sstevel@tonic-gate bcopy((void *)(assigned + i + 1), 18430Sstevel@tonic-gate (void *)(assigned + i), 18440Sstevel@tonic-gate (new_len - (i * sizeof (pci_regspec_t)))); 18450Sstevel@tonic-gate 18460Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "assigned-address entry " 18470Sstevel@tonic-gate "%x removed from property\n", 18480Sstevel@tonic-gate oldone->pci_phys_hi); 18490Sstevel@tonic-gate } 18500Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 18510Sstevel@tonic-gate dip, "assigned-addresses", (int *)assigned, 18520Sstevel@tonic-gate (new_len/sizeof (int))); 18530Sstevel@tonic-gate 18540Sstevel@tonic-gate break; 18550Sstevel@tonic-gate } 18560Sstevel@tonic-gate } 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate return (0); 18590Sstevel@tonic-gate } 18600Sstevel@tonic-gate /* 18610Sstevel@tonic-gate * we recognize the non transparent bridge child nodes with the 18620Sstevel@tonic-gate * following property. This is specific to this implementation only. 18630Sstevel@tonic-gate * This property is specific to AP nodes only. 18640Sstevel@tonic-gate */ 18650Sstevel@tonic-gate #define PCICFG_DEV_CONF_MAP_PROP "pci-parent-indirect" 18660Sstevel@tonic-gate 18670Sstevel@tonic-gate /* 18680Sstevel@tonic-gate * If a non transparent bridge drives a hotplug/hotswap bus, then 18690Sstevel@tonic-gate * the following property must be defined for the node either by 18700Sstevel@tonic-gate * the driver or the OBP. 18710Sstevel@tonic-gate */ 18720Sstevel@tonic-gate #define PCICFG_BUS_CONF_MAP_PROP "pci-conf-indirect" 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate /* 18750Sstevel@tonic-gate * this function is called only for SPARC platforms, where we may have 18760Sstevel@tonic-gate * a mix n' match of direct vs indirectly mapped configuration space. 18770Sstevel@tonic-gate */ 18780Sstevel@tonic-gate /*ARGSUSED*/ 18790Sstevel@tonic-gate static int 18800Sstevel@tonic-gate fcpci_indirect_map(dev_info_t *dip) 18810Sstevel@tonic-gate { 18820Sstevel@tonic-gate int rc = DDI_FAILURE; 18830Sstevel@tonic-gate 1884*1983Sjj156685 if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), 0, 18850Sstevel@tonic-gate PCICFG_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE) 18860Sstevel@tonic-gate rc = DDI_SUCCESS; 18870Sstevel@tonic-gate else 18880Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), 1889*1983Sjj156685 0, PCICFG_BUS_CONF_MAP_PROP, 18900Sstevel@tonic-gate DDI_FAILURE) != DDI_FAILURE) 18910Sstevel@tonic-gate rc = DDI_SUCCESS; 18920Sstevel@tonic-gate 18930Sstevel@tonic-gate return (rc); 18940Sstevel@tonic-gate } 1895