1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * fcpci.c: Framework PCI fcode ops 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate #include <sys/types.h> 33*0Sstevel@tonic-gate #include <sys/kmem.h> 34*0Sstevel@tonic-gate #include <sys/systm.h> 35*0Sstevel@tonic-gate #include <sys/pci.h> 36*0Sstevel@tonic-gate #include <sys/ddi.h> 37*0Sstevel@tonic-gate #include <sys/sunddi.h> 38*0Sstevel@tonic-gate #include <sys/sunndi.h> 39*0Sstevel@tonic-gate #include <sys/ddidmareq.h> 40*0Sstevel@tonic-gate #include <sys/pci.h> 41*0Sstevel@tonic-gate #include <sys/modctl.h> 42*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 43*0Sstevel@tonic-gate #include <sys/fcode.h> 44*0Sstevel@tonic-gate #include <sys/promif.h> 45*0Sstevel@tonic-gate #include <sys/promimpl.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #define PCI_NPT_bits (PCI_RELOCAT_B | PCI_PREFETCH_B | PCI_ALIAS_B) 48*0Sstevel@tonic-gate #define PCICFG_CONF_INDIRECT_MAP 1 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate static int pfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 51*0Sstevel@tonic-gate static int pfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 52*0Sstevel@tonic-gate static int pfc_dma_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 53*0Sstevel@tonic-gate static int pfc_dma_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 54*0Sstevel@tonic-gate static int pfc_dma_sync(dev_info_t *, fco_handle_t, fc_ci_t *); 55*0Sstevel@tonic-gate static int pfc_dma_cleanup(dev_info_t *, fco_handle_t, fc_ci_t *); 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate static int pfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 58*0Sstevel@tonic-gate static int pfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); 59*0Sstevel@tonic-gate static int pfc_config_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 60*0Sstevel@tonic-gate static int pfc_config_store(dev_info_t *, fco_handle_t, fc_ci_t *); 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate static int pfc_probe_address(dev_info_t *, fco_handle_t, fc_ci_t *); 63*0Sstevel@tonic-gate static int pfc_probe_space(dev_info_t *, fco_handle_t, fc_ci_t *); 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static int pfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); 66*0Sstevel@tonic-gate static int pfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); 67*0Sstevel@tonic-gate static int pfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); 68*0Sstevel@tonic-gate int prom_get_fcode_size(char *); 69*0Sstevel@tonic-gate int prom_get_fcode(char *, char *); 70*0Sstevel@tonic-gate int pfc_update_assigned_prop(dev_info_t *, pci_regspec_t *); 71*0Sstevel@tonic-gate int pfc_remove_assigned_prop(dev_info_t *, pci_regspec_t *); 72*0Sstevel@tonic-gate int pci_alloc_resource(dev_info_t *, pci_regspec_t); 73*0Sstevel@tonic-gate int pci_free_resource(dev_info_t *, pci_regspec_t); 74*0Sstevel@tonic-gate int pci_alloc_mem_chunk(dev_info_t *, uint64_t, uint64_t *, uint64_t *); 75*0Sstevel@tonic-gate int pci_alloc_io_chunk(dev_info_t *, uint64_t, uint64_t *, uint64_t *); 76*0Sstevel@tonic-gate static int fcpci_indirect_map(dev_info_t *); 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate int fcpci_unloadable; 79*0Sstevel@tonic-gate int no_advisory_dma; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate #ifndef lint 82*0Sstevel@tonic-gate static char _depends_on[] = "misc/fcodem misc/busra"; 83*0Sstevel@tonic-gate #endif 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate #define HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32)) 86*0Sstevel@tonic-gate #define LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF)) 87*0Sstevel@tonic-gate #define LADDR(lo, hi) (((uint64_t)(hi) << 32) | (uint32_t)(lo)) 88*0Sstevel@tonic-gate #define PCI_4GIG_LIMIT 0xFFFFFFFFUL 89*0Sstevel@tonic-gate #define PCI_MEMGRAN 0x100000 90*0Sstevel@tonic-gate #define PCI_IOGRAN 0x1000 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate /* 94*0Sstevel@tonic-gate * Module linkage information for the kernel. 95*0Sstevel@tonic-gate */ 96*0Sstevel@tonic-gate static struct modlmisc modlmisc = { 97*0Sstevel@tonic-gate &mod_miscops, "FCode pci bus functions %I%" 98*0Sstevel@tonic-gate }; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 101*0Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 102*0Sstevel@tonic-gate }; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate int 105*0Sstevel@tonic-gate _init(void) 106*0Sstevel@tonic-gate { 107*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 108*0Sstevel@tonic-gate } 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate int 111*0Sstevel@tonic-gate _fini(void) 112*0Sstevel@tonic-gate { 113*0Sstevel@tonic-gate if (fcpci_unloadable) 114*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 115*0Sstevel@tonic-gate return (EBUSY); 116*0Sstevel@tonic-gate } 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate int 119*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 120*0Sstevel@tonic-gate { 121*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate struct pfc_ops_v { 126*0Sstevel@tonic-gate char *svc_name; 127*0Sstevel@tonic-gate fc_ops_t *f; 128*0Sstevel@tonic-gate }; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate static struct pfc_ops_v pov[] = { 131*0Sstevel@tonic-gate { "map-in", pfc_map_in}, 132*0Sstevel@tonic-gate { "map-out", pfc_map_out}, 133*0Sstevel@tonic-gate { "dma-map-in", pfc_dma_map_in}, 134*0Sstevel@tonic-gate { "dma-map-out", pfc_dma_map_out}, 135*0Sstevel@tonic-gate { "dma-sync", pfc_dma_sync}, 136*0Sstevel@tonic-gate { "rx@", pfc_register_fetch}, 137*0Sstevel@tonic-gate { "rl@", pfc_register_fetch}, 138*0Sstevel@tonic-gate { "rw@", pfc_register_fetch}, 139*0Sstevel@tonic-gate { "rb@", pfc_register_fetch}, 140*0Sstevel@tonic-gate { "rx!", pfc_register_store}, 141*0Sstevel@tonic-gate { "rl!", pfc_register_store}, 142*0Sstevel@tonic-gate { "rw!", pfc_register_store}, 143*0Sstevel@tonic-gate { "rb!", pfc_register_store}, 144*0Sstevel@tonic-gate { "config-l@", pfc_config_fetch}, 145*0Sstevel@tonic-gate { "config-w@", pfc_config_fetch}, 146*0Sstevel@tonic-gate { "config-b@", pfc_config_fetch}, 147*0Sstevel@tonic-gate { "config-l!", pfc_config_store}, 148*0Sstevel@tonic-gate { "config-w!", pfc_config_store}, 149*0Sstevel@tonic-gate { "config-b!", pfc_config_store}, 150*0Sstevel@tonic-gate { FC_PROBE_ADDRESS, pfc_probe_address}, 151*0Sstevel@tonic-gate { FC_PROBE_SPACE, pfc_probe_space}, 152*0Sstevel@tonic-gate { FC_SVC_EXIT, pfc_dma_cleanup}, 153*0Sstevel@tonic-gate { FC_CONFIG_CHILD, pfc_config_child}, 154*0Sstevel@tonic-gate { FC_GET_FCODE_SIZE, pfc_get_fcode_size}, 155*0Sstevel@tonic-gate { FC_GET_FCODE, pfc_get_fcode}, 156*0Sstevel@tonic-gate { NULL, NULL} 157*0Sstevel@tonic-gate }; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate static struct pfc_ops_v shared_pov[] = { 160*0Sstevel@tonic-gate { FC_SVC_EXIT, pfc_dma_cleanup}, 161*0Sstevel@tonic-gate { NULL, NULL} 162*0Sstevel@tonic-gate }; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate int pci_map_phys(dev_info_t *, pci_regspec_t *, 165*0Sstevel@tonic-gate caddr_t *, ddi_device_acc_attr_t *, ddi_acc_handle_t *); 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate void pci_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *); 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate fco_handle_t 170*0Sstevel@tonic-gate pci_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child, 171*0Sstevel@tonic-gate void *fcode, size_t fcode_size, char *unit_address, 172*0Sstevel@tonic-gate struct pci_ops_bus_args *up) 173*0Sstevel@tonic-gate { 174*0Sstevel@tonic-gate fco_handle_t rp; 175*0Sstevel@tonic-gate struct pci_ops_bus_args *bp = NULL; 176*0Sstevel@tonic-gate phandle_t h; 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 179*0Sstevel@tonic-gate rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size, 180*0Sstevel@tonic-gate unit_address, NULL); 181*0Sstevel@tonic-gate rp->ap = ap; 182*0Sstevel@tonic-gate rp->child = child; 183*0Sstevel@tonic-gate rp->fcode = fcode; 184*0Sstevel@tonic-gate rp->fcode_size = fcode_size; 185*0Sstevel@tonic-gate if (unit_address) { 186*0Sstevel@tonic-gate char *buf; 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP); 189*0Sstevel@tonic-gate (void) strcpy(buf, unit_address); 190*0Sstevel@tonic-gate rp->unit_address = buf; 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate bp = kmem_zalloc(sizeof (struct pci_ops_bus_args), KM_SLEEP); 194*0Sstevel@tonic-gate *bp = *up; 195*0Sstevel@tonic-gate rp->bus_args = bp; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * Add the child's nodeid to our table... 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate h = ddi_get_nodeid(rp->child); 201*0Sstevel@tonic-gate fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate return (rp); 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate void 207*0Sstevel@tonic-gate pci_fc_ops_free_handle(fco_handle_t rp) 208*0Sstevel@tonic-gate { 209*0Sstevel@tonic-gate struct pci_ops_bus_args *bp; 210*0Sstevel@tonic-gate struct fc_resource *ip, *np; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate ASSERT(rp); 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate if (rp->next_handle) 215*0Sstevel@tonic-gate fc_ops_free_handle(rp->next_handle); 216*0Sstevel@tonic-gate if (rp->unit_address) 217*0Sstevel@tonic-gate kmem_free(rp->unit_address, strlen(rp->unit_address) + 1); 218*0Sstevel@tonic-gate if ((bp = rp->bus_args) != NULL) 219*0Sstevel@tonic-gate kmem_free(bp, sizeof (struct pci_ops_bus_args)); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * Release all the resources from the resource list 223*0Sstevel@tonic-gate * XXX: We don't handle 'unknown' types, but we don't create them. 224*0Sstevel@tonic-gate */ 225*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = np) { 226*0Sstevel@tonic-gate np = ip->next; 227*0Sstevel@tonic-gate switch (ip->type) { 228*0Sstevel@tonic-gate case RT_MAP: 229*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "pci_fc_ops_free: " 230*0Sstevel@tonic-gate "pci_unmap_phys(%p)\n", ip->fc_map_handle); 231*0Sstevel@tonic-gate pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec); 232*0Sstevel@tonic-gate kmem_free(ip->fc_regspec, sizeof (pci_regspec_t)); 233*0Sstevel@tonic-gate break; 234*0Sstevel@tonic-gate case RT_DMA: 235*0Sstevel@tonic-gate /* DMA has to be freed up at exit time */ 236*0Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_fc_ops_free: DMA seen!\n"); 237*0Sstevel@tonic-gate break; 238*0Sstevel@tonic-gate default: 239*0Sstevel@tonic-gate cmn_err(CE_CONT, "pci_fc_ops_free: " 240*0Sstevel@tonic-gate "unknown resource type %d\n", ip->type); 241*0Sstevel@tonic-gate break; 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate fc_rem_resource(rp, ip); 244*0Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate kmem_free(rp, sizeof (struct fc_resource_list)); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate int 250*0Sstevel@tonic-gate pci_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 251*0Sstevel@tonic-gate { 252*0Sstevel@tonic-gate struct pfc_ops_v *pv; 253*0Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate ASSERT(rp); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * First try the generic fc_ops. If the ops is a shared op, 259*0Sstevel@tonic-gate * also call our local function. 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate if (fc_ops(ap, rp->next_handle, cp) == 0) { 262*0Sstevel@tonic-gate for (pv = shared_pov; pv->svc_name != NULL; ++pv) 263*0Sstevel@tonic-gate if (strcmp(pv->svc_name, name) == 0) 264*0Sstevel@tonic-gate return (pv->f(ap, rp, cp)); 265*0Sstevel@tonic-gate return (0); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate for (pv = pov; pv->svc_name != NULL; ++pv) 269*0Sstevel@tonic-gate if (strcmp(pv->svc_name, name) == 0) 270*0Sstevel@tonic-gate return (pv->f(ap, rp, cp)); 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "pci_fc_ops: <%s> not serviced\n", name); 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate return (-1); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * Create a dma mapping for a given user address. 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate static int 281*0Sstevel@tonic-gate pfc_dma_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 282*0Sstevel@tonic-gate { 283*0Sstevel@tonic-gate ddi_dma_handle_t h; 284*0Sstevel@tonic-gate int error; 285*0Sstevel@tonic-gate caddr_t virt; 286*0Sstevel@tonic-gate size_t len; 287*0Sstevel@tonic-gate uint_t flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT; 288*0Sstevel@tonic-gate struct fc_resource *ip; 289*0Sstevel@tonic-gate ddi_dma_cookie_t c; 290*0Sstevel@tonic-gate struct buf *bp; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 293*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 296*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * XXX: It's not clear what we should do with a non-cacheable request 300*0Sstevel@tonic-gate */ 301*0Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 2)); 302*0Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 1)); 303*0Sstevel@tonic-gate #ifdef notdef 304*0Sstevel@tonic-gate cacheable = fc_cell2int(fc_arg(cp, 0)); /* XXX: do what? */ 305*0Sstevel@tonic-gate #endif 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate FC_DEBUG2(6, CE_CONT, "pcf_dma_map_in: virt %p, len %d\n", virt, len); 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* 310*0Sstevel@tonic-gate * Set up the address space for physio from userland 311*0Sstevel@tonic-gate */ 312*0Sstevel@tonic-gate error = fc_physio_setup(&bp, virt, len); 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate if (error) { 315*0Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: fc_physio_setup failed " 316*0Sstevel@tonic-gate "error: %d virt: %p len %d\n", error, virt, len); 317*0Sstevel@tonic-gate return (fc_priv_error(cp, "fc_physio_setup failed")); 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate if (no_advisory_dma == 0) { 321*0Sstevel@tonic-gate /* 322*0Sstevel@tonic-gate * First try the advisory call to see if it's legal .. 323*0Sstevel@tonic-gate * for advisory dma, don't pass in a ptr to a dma handle. 324*0Sstevel@tonic-gate */ 325*0Sstevel@tonic-gate FC_DEBUG0(9, CE_CONT, "pfc_dma_map_in: advisory dma_map_in\n"); 326*0Sstevel@tonic-gate error = ddi_dma_buf_setup(ap, bp, flags, DDI_DMA_SLEEP, 327*0Sstevel@tonic-gate NULL, NULL, NULL); 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate if (error) { 330*0Sstevel@tonic-gate FC_DEBUG3(9, CE_CONT, "pfc_dma_map_in: advisory " 331*0Sstevel@tonic-gate "dma-map-in failed error: %d virt: %p len %d\n", 332*0Sstevel@tonic-gate error, virt, len); 333*0Sstevel@tonic-gate return (fc_priv_error(cp, "advisory dma-map-in " 334*0Sstevel@tonic-gate "failed")); 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: dma_map_in; bp = %p\n", bp); 339*0Sstevel@tonic-gate error = ddi_dma_buf_setup(ap, bp, flags, DDI_DMA_SLEEP, 340*0Sstevel@tonic-gate NULL, NULL, &h); 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate if (error) { 343*0Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: real dma-map-in failed " 344*0Sstevel@tonic-gate "error: %d virt: %p len %d\n", error, virt, len); 345*0Sstevel@tonic-gate return (fc_priv_error(cp, "real dma-map-in failed")); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * Now that the resource is mapped in, we need the dma cookie 350*0Sstevel@tonic-gate * so we can return it to the driver. 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate error = fc_ddi_dma_htoc(ap, h, 0, &c); 354*0Sstevel@tonic-gate if (error) { 355*0Sstevel@tonic-gate (void) fc_ddi_dma_free(ap, h); 356*0Sstevel@tonic-gate return (fc_priv_error(cp, "ddi_dma_htoc failed")); 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (c.dmac_size < len) { 360*0Sstevel@tonic-gate (void) fc_ddi_dma_free(ap, h); 361*0Sstevel@tonic-gate return (fc_priv_error(cp, "ddi_dma_htoc size < len")); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: returning devaddr %x\n", 365*0Sstevel@tonic-gate c.dmac_address); 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 368*0Sstevel@tonic-gate fc_result(cp, 0) = fc_uint32_t2cell(c.dmac_address); /* XXX size */ 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* 371*0Sstevel@tonic-gate * Now we have to log this resource saving the handle and buf header 372*0Sstevel@tonic-gate */ 373*0Sstevel@tonic-gate ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 374*0Sstevel@tonic-gate ip->type = RT_DMA; 375*0Sstevel@tonic-gate ip->fc_dma_virt = virt; 376*0Sstevel@tonic-gate ip->fc_dma_len = len; 377*0Sstevel@tonic-gate ip->fc_dma_handle = h; 378*0Sstevel@tonic-gate ip->fc_dma_devaddr = c.dmac_address; 379*0Sstevel@tonic-gate ip->fc_dma_bp = bp; 380*0Sstevel@tonic-gate fc_add_resource(rp, ip); 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate static int 386*0Sstevel@tonic-gate pfc_dma_sync(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate void *virt; 389*0Sstevel@tonic-gate size_t len; 390*0Sstevel@tonic-gate uint32_t devaddr; 391*0Sstevel@tonic-gate int error; 392*0Sstevel@tonic-gate struct fc_resource *ip; 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 395*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 2)); 398*0Sstevel@tonic-gate devaddr = fc_cell2uint32_t(fc_arg(cp, 1)); 399*0Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 0)); 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate /* 402*0Sstevel@tonic-gate * Find if this virt is 'within' a request we know about 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate fc_lock_resource_list(rp); 405*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 406*0Sstevel@tonic-gate if (ip->type != RT_DMA) 407*0Sstevel@tonic-gate continue; 408*0Sstevel@tonic-gate if (ip->fc_dma_devaddr != devaddr) 409*0Sstevel@tonic-gate continue; 410*0Sstevel@tonic-gate if (((char *)virt >= (char *)ip->fc_dma_virt) && 411*0Sstevel@tonic-gate (((char *)virt + len) <= 412*0Sstevel@tonic-gate ((char *)ip->fc_dma_virt + ip->fc_dma_len))) 413*0Sstevel@tonic-gate break; 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate fc_unlock_resource_list(rp); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate if (ip == NULL) 418*0Sstevel@tonic-gate return (fc_priv_error(cp, "request not within a " 419*0Sstevel@tonic-gate "known dma mapping")); 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate /* 422*0Sstevel@tonic-gate * We know about this request, so we trust it enough to sync it. 423*0Sstevel@tonic-gate * Unfortunately, we don't know which direction, so we'll do 424*0Sstevel@tonic-gate * both directions. 425*0Sstevel@tonic-gate */ 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate error = fc_ddi_dma_sync(ip->fc_dma_handle, 428*0Sstevel@tonic-gate (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORCPU); 429*0Sstevel@tonic-gate error |= fc_ddi_dma_sync(ip->fc_dma_handle, 430*0Sstevel@tonic-gate (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORDEV); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate if (error) 433*0Sstevel@tonic-gate return (fc_priv_error(cp, "Call to ddi_dma_sync failed")); 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 436*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate static int 440*0Sstevel@tonic-gate pfc_dma_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 441*0Sstevel@tonic-gate { 442*0Sstevel@tonic-gate void *virt; 443*0Sstevel@tonic-gate size_t len; 444*0Sstevel@tonic-gate uint32_t devaddr; 445*0Sstevel@tonic-gate struct fc_resource *ip; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 448*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 2)); 451*0Sstevel@tonic-gate devaddr = fc_cell2uint32_t(fc_arg(cp, 1)); 452*0Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 0)); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate /* 455*0Sstevel@tonic-gate * Find if this virt matches a request we know about 456*0Sstevel@tonic-gate */ 457*0Sstevel@tonic-gate fc_lock_resource_list(rp); 458*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 459*0Sstevel@tonic-gate if (ip->type != RT_DMA) 460*0Sstevel@tonic-gate continue; 461*0Sstevel@tonic-gate if (ip->fc_dma_devaddr != devaddr) 462*0Sstevel@tonic-gate continue; 463*0Sstevel@tonic-gate if (ip->fc_dma_virt != virt) 464*0Sstevel@tonic-gate continue; 465*0Sstevel@tonic-gate if (len == ip->fc_dma_len) 466*0Sstevel@tonic-gate break; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate fc_unlock_resource_list(rp); 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate if (ip == NULL) 471*0Sstevel@tonic-gate return (fc_priv_error(cp, "request doesn't match a " 472*0Sstevel@tonic-gate "known dma mapping")); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate /* 475*0Sstevel@tonic-gate * ddi_dma_free does an implied sync ... 476*0Sstevel@tonic-gate */ 477*0Sstevel@tonic-gate if (fc_ddi_dma_free(ap, ip->fc_dma_handle)) 478*0Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_dma_map_out: ddi_dma_free failed!\n"); 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate /* 481*0Sstevel@tonic-gate * Tear down the physio mappings 482*0Sstevel@tonic-gate */ 483*0Sstevel@tonic-gate fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len); 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* 486*0Sstevel@tonic-gate * remove the resource from the list and release it. 487*0Sstevel@tonic-gate */ 488*0Sstevel@tonic-gate fc_rem_resource(rp, ip); 489*0Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 492*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate static struct fc_resource * 496*0Sstevel@tonic-gate next_dma_resource(fco_handle_t rp) 497*0Sstevel@tonic-gate { 498*0Sstevel@tonic-gate struct fc_resource *ip; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate fc_lock_resource_list(rp); 501*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) 502*0Sstevel@tonic-gate if (ip->type == RT_DMA) 503*0Sstevel@tonic-gate break; 504*0Sstevel@tonic-gate fc_unlock_resource_list(rp); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate return (ip); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate static int 510*0Sstevel@tonic-gate pfc_dma_cleanup(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 511*0Sstevel@tonic-gate { 512*0Sstevel@tonic-gate struct fc_resource *ip; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate while ((ip = next_dma_resource(rp)) != NULL) { 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate FC_DEBUG2(9, CE_CONT, "pfc_dma_cleanup: virt %x len %x\n", 517*0Sstevel@tonic-gate ip->fc_dma_virt, ip->fc_dma_len); 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* 520*0Sstevel@tonic-gate * Free the dma handle 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate if (fc_ddi_dma_free(ap, ip->fc_dma_handle)) 523*0Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_dma_cleanup: " 524*0Sstevel@tonic-gate "ddi_dma_free failed!\n"); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate /* 527*0Sstevel@tonic-gate * Tear down the userland mapping and free the buf header 528*0Sstevel@tonic-gate */ 529*0Sstevel@tonic-gate fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len); 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate fc_rem_resource(rp, ip); 532*0Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 536*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate static int 540*0Sstevel@tonic-gate pfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 541*0Sstevel@tonic-gate { 542*0Sstevel@tonic-gate size_t len; 543*0Sstevel@tonic-gate int error; 544*0Sstevel@tonic-gate caddr_t virt; 545*0Sstevel@tonic-gate pci_regspec_t p, *ph; 546*0Sstevel@tonic-gate struct fc_resource *ip; 547*0Sstevel@tonic-gate ddi_device_acc_attr_t acc; 548*0Sstevel@tonic-gate ddi_acc_handle_t h; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 4) 551*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 4")); 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 554*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate p.pci_size_hi = 0; 557*0Sstevel@tonic-gate p.pci_size_low = len = fc_cell2size(fc_arg(cp, 0)); 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 1)); 560*0Sstevel@tonic-gate p.pci_phys_mid = fc_cell2uint(fc_arg(cp, 2)); 561*0Sstevel@tonic-gate p.pci_phys_low = fc_cell2uint(fc_arg(cp, 3)); 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * Fcode is expecting the bytes are not swapped. 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 569*0Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate /* 572*0Sstevel@tonic-gate * First We need to allocate the PCI Resource. 573*0Sstevel@tonic-gate */ 574*0Sstevel@tonic-gate error = pci_alloc_resource(rp->child, p); 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate if (error) { 577*0Sstevel@tonic-gate return (fc_priv_error(cp, "pci map-in failed")); 578*0Sstevel@tonic-gate } 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate error = pci_map_phys(rp->child, &p, &virt, &acc, &h); 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate if (error) { 583*0Sstevel@tonic-gate return (fc_priv_error(cp, "pci map-in failed")); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 587*0Sstevel@tonic-gate fc_result(cp, 0) = fc_ptr2cell(virt); 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate /* 590*0Sstevel@tonic-gate * Log this resource ... 591*0Sstevel@tonic-gate */ 592*0Sstevel@tonic-gate ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 593*0Sstevel@tonic-gate ip->type = RT_MAP; 594*0Sstevel@tonic-gate ip->fc_map_virt = virt; 595*0Sstevel@tonic-gate ip->fc_map_len = len; 596*0Sstevel@tonic-gate ip->fc_map_handle = h; 597*0Sstevel@tonic-gate ph = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP); 598*0Sstevel@tonic-gate *ph = p; 599*0Sstevel@tonic-gate ip->fc_regspec = ph; /* cache a copy of the reg spec */ 600*0Sstevel@tonic-gate fc_add_resource(rp, ip); 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate static int 606*0Sstevel@tonic-gate pfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 607*0Sstevel@tonic-gate { 608*0Sstevel@tonic-gate caddr_t virt; 609*0Sstevel@tonic-gate size_t len; 610*0Sstevel@tonic-gate struct fc_resource *ip; 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2) 613*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2")); 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 1)); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate len = fc_cell2size(fc_arg(cp, 0)); 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate /* 620*0Sstevel@tonic-gate * Find if this request matches a mapping resource we set up. 621*0Sstevel@tonic-gate */ 622*0Sstevel@tonic-gate fc_lock_resource_list(rp); 623*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 624*0Sstevel@tonic-gate if (ip->type != RT_MAP) 625*0Sstevel@tonic-gate continue; 626*0Sstevel@tonic-gate if (ip->fc_map_virt != virt) 627*0Sstevel@tonic-gate continue; 628*0Sstevel@tonic-gate if (ip->fc_map_len == len) 629*0Sstevel@tonic-gate break; 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate fc_unlock_resource_list(rp); 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate if (ip == NULL) 634*0Sstevel@tonic-gate return (fc_priv_error(cp, "request doesn't match a " 635*0Sstevel@tonic-gate "known mapping")); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec); 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate kmem_free(ip->fc_regspec, sizeof (pci_regspec_t)); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate /* 642*0Sstevel@tonic-gate * remove the resource from the list and release it. 643*0Sstevel@tonic-gate */ 644*0Sstevel@tonic-gate fc_rem_resource(rp, ip); 645*0Sstevel@tonic-gate kmem_free(ip, sizeof (struct fc_resource)); 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 648*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 649*0Sstevel@tonic-gate } 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate static int 652*0Sstevel@tonic-gate pfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 653*0Sstevel@tonic-gate { 654*0Sstevel@tonic-gate size_t len; 655*0Sstevel@tonic-gate caddr_t virt; 656*0Sstevel@tonic-gate int error; 657*0Sstevel@tonic-gate uint64_t x; 658*0Sstevel@tonic-gate uint32_t l; 659*0Sstevel@tonic-gate uint16_t w; 660*0Sstevel@tonic-gate uint8_t b; 661*0Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 662*0Sstevel@tonic-gate struct fc_resource *ip; 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1) 665*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1")); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 668*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 0)); 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* 673*0Sstevel@tonic-gate * Determine the access width .. we can switch on the 2nd 674*0Sstevel@tonic-gate * character of the name which is "rx@", "rl@", "rb@" or "rw@" 675*0Sstevel@tonic-gate */ 676*0Sstevel@tonic-gate switch (*(name + 1)) { 677*0Sstevel@tonic-gate case 'x': len = sizeof (x); break; 678*0Sstevel@tonic-gate case 'l': len = sizeof (l); break; 679*0Sstevel@tonic-gate case 'w': len = sizeof (w); break; 680*0Sstevel@tonic-gate case 'b': len = sizeof (b); break; 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * Check the alignment ... 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate if (((intptr_t)virt & (len - 1)) != 0) 687*0Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate /* 690*0Sstevel@tonic-gate * Find if this virt is 'within' a request we know about 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate fc_lock_resource_list(rp); 693*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 694*0Sstevel@tonic-gate if (ip->type != RT_MAP) 695*0Sstevel@tonic-gate continue; 696*0Sstevel@tonic-gate if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 697*0Sstevel@tonic-gate ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 698*0Sstevel@tonic-gate break; 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate fc_unlock_resource_list(rp); 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate if (ip == NULL) 703*0Sstevel@tonic-gate return (fc_priv_error(cp, "request not within a " 704*0Sstevel@tonic-gate "known mapping")); 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate /* 707*0Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 708*0Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 709*0Sstevel@tonic-gate * byte swapping enabled for pci register access here which 710*0Sstevel@tonic-gate * is a huge dependency on the current implementation. 711*0Sstevel@tonic-gate */ 712*0Sstevel@tonic-gate switch (len) { 713*0Sstevel@tonic-gate case sizeof (x): 714*0Sstevel@tonic-gate error = ddi_peek64(rp->child, (int64_t *)virt, (int64_t *)&x); 715*0Sstevel@tonic-gate break; 716*0Sstevel@tonic-gate case sizeof (l): 717*0Sstevel@tonic-gate error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&l); 718*0Sstevel@tonic-gate break; 719*0Sstevel@tonic-gate case sizeof (w): 720*0Sstevel@tonic-gate error = ddi_peek16(rp->child, (int16_t *)virt, (int16_t *)&w); 721*0Sstevel@tonic-gate break; 722*0Sstevel@tonic-gate case sizeof (b): 723*0Sstevel@tonic-gate error = ddi_peek8(rp->child, (int8_t *)virt, (int8_t *)&b); 724*0Sstevel@tonic-gate break; 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate if (error) { 728*0Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 732*0Sstevel@tonic-gate switch (len) { 733*0Sstevel@tonic-gate case sizeof (x): fc_result(cp, 0) = x; break; 734*0Sstevel@tonic-gate case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 735*0Sstevel@tonic-gate case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 736*0Sstevel@tonic-gate case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate static int 742*0Sstevel@tonic-gate pfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 743*0Sstevel@tonic-gate { 744*0Sstevel@tonic-gate size_t len; 745*0Sstevel@tonic-gate caddr_t virt; 746*0Sstevel@tonic-gate int error; 747*0Sstevel@tonic-gate uint64_t x; 748*0Sstevel@tonic-gate uint32_t l; 749*0Sstevel@tonic-gate uint16_t w; 750*0Sstevel@tonic-gate uint8_t b; 751*0Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 752*0Sstevel@tonic-gate struct fc_resource *ip; 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2) 755*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2")); 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 0)); 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate /* 760*0Sstevel@tonic-gate * Determine the access width .. we can switch on the 2nd 761*0Sstevel@tonic-gate * character of the name which is "rl!", "rb!" or "rw!" 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate switch (*(name + 1)) { 764*0Sstevel@tonic-gate case 'x': len = sizeof (x); x = fc_arg(cp, 1); break; 765*0Sstevel@tonic-gate case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break; 766*0Sstevel@tonic-gate case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break; 767*0Sstevel@tonic-gate case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break; 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate /* 771*0Sstevel@tonic-gate * Check the alignment ... 772*0Sstevel@tonic-gate */ 773*0Sstevel@tonic-gate if (((intptr_t)virt & (len - 1)) != 0) 774*0Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate /* 777*0Sstevel@tonic-gate * Find if this virt is 'within' a request we know about 778*0Sstevel@tonic-gate */ 779*0Sstevel@tonic-gate fc_lock_resource_list(rp); 780*0Sstevel@tonic-gate for (ip = rp->head; ip != NULL; ip = ip->next) { 781*0Sstevel@tonic-gate if (ip->type != RT_MAP) 782*0Sstevel@tonic-gate continue; 783*0Sstevel@tonic-gate if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <= 784*0Sstevel@tonic-gate ((caddr_t)ip->fc_map_virt + ip->fc_map_len))) 785*0Sstevel@tonic-gate break; 786*0Sstevel@tonic-gate } 787*0Sstevel@tonic-gate fc_unlock_resource_list(rp); 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate if (ip == NULL) 790*0Sstevel@tonic-gate return (fc_priv_error(cp, "request not within a " 791*0Sstevel@tonic-gate "known mapping")); 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate /* 794*0Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 795*0Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 796*0Sstevel@tonic-gate * byte swapping enabled for pci register access here which 797*0Sstevel@tonic-gate * is a huge dependency on the current implementation. 798*0Sstevel@tonic-gate */ 799*0Sstevel@tonic-gate switch (len) { 800*0Sstevel@tonic-gate case sizeof (x): 801*0Sstevel@tonic-gate error = ddi_poke64(rp->child, (int64_t *)virt, x); 802*0Sstevel@tonic-gate break; 803*0Sstevel@tonic-gate case sizeof (l): 804*0Sstevel@tonic-gate error = ddi_poke32(rp->child, (int32_t *)virt, l); 805*0Sstevel@tonic-gate break; 806*0Sstevel@tonic-gate case sizeof (w): 807*0Sstevel@tonic-gate error = ddi_poke16(rp->child, (int16_t *)virt, w); 808*0Sstevel@tonic-gate break; 809*0Sstevel@tonic-gate case sizeof (b): 810*0Sstevel@tonic-gate error = ddi_poke8(rp->child, (int8_t *)virt, b); 811*0Sstevel@tonic-gate break; 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate if (error) { 815*0Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate 818*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 819*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate static int 823*0Sstevel@tonic-gate pfc_config_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 824*0Sstevel@tonic-gate { 825*0Sstevel@tonic-gate caddr_t virt, v; 826*0Sstevel@tonic-gate int error, reg, flags = 0; 827*0Sstevel@tonic-gate size_t len; 828*0Sstevel@tonic-gate uint32_t l, tmp; 829*0Sstevel@tonic-gate uint16_t w; 830*0Sstevel@tonic-gate uint8_t b; 831*0Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 832*0Sstevel@tonic-gate pci_regspec_t p; 833*0Sstevel@tonic-gate ddi_device_acc_attr_t acc; 834*0Sstevel@tonic-gate ddi_acc_handle_t h; 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1) 837*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1")); 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 840*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate /* 843*0Sstevel@tonic-gate * Construct a config address pci reg property from the args. 844*0Sstevel@tonic-gate * arg[0] is the configuration address. 845*0Sstevel@tonic-gate */ 846*0Sstevel@tonic-gate p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0)); 847*0Sstevel@tonic-gate p.pci_phys_mid = p.pci_phys_low = 0; 848*0Sstevel@tonic-gate p.pci_size_hi = p.pci_size_low = 0; 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate /* 851*0Sstevel@tonic-gate * Verify that the address is a configuration space address 852*0Sstevel@tonic-gate * ss must be zero, n,p,t must be zero. 853*0Sstevel@tonic-gate */ 854*0Sstevel@tonic-gate if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) || 855*0Sstevel@tonic-gate ((p.pci_phys_hi & PCI_NPT_bits) != 0)) { 856*0Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_config_fetch: " 857*0Sstevel@tonic-gate "invalid config addr: %x\n", p.pci_phys_hi); 858*0Sstevel@tonic-gate return (fc_priv_error(cp, "non-config addr")); 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate /* 862*0Sstevel@tonic-gate * Extract the register number from the config address and 863*0Sstevel@tonic-gate * remove the register number from the physical address. 864*0Sstevel@tonic-gate */ 865*0Sstevel@tonic-gate reg = p.pci_phys_hi & PCI_REG_REG_M; 866*0Sstevel@tonic-gate p.pci_phys_hi &= ~PCI_REG_REG_M; 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate /* 869*0Sstevel@tonic-gate * Determine the access width .. we can switch on the 9th 870*0Sstevel@tonic-gate * character of the name which is "config-{l,w,b}@" 871*0Sstevel@tonic-gate */ 872*0Sstevel@tonic-gate switch (*(name + 7)) { 873*0Sstevel@tonic-gate case 'l': len = sizeof (l); break; 874*0Sstevel@tonic-gate case 'w': len = sizeof (w); break; 875*0Sstevel@tonic-gate case 'b': len = sizeof (b); break; 876*0Sstevel@tonic-gate } 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate /* 879*0Sstevel@tonic-gate * Verify that the access is properly aligned 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate if ((reg & (len - 1)) != 0) 882*0Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate /* 885*0Sstevel@tonic-gate * Map in configuration space (temporarily) 886*0Sstevel@tonic-gate */ 887*0Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 888*0Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 889*0Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate error = pci_map_phys(rp->child, &p, &virt, &acc, &h); 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate if (error) { 894*0Sstevel@tonic-gate return (fc_priv_error(cp, "pci config map-in failed")); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate if (fcpci_indirect_map(rp->child) == DDI_SUCCESS) 898*0Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 901*0Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 902*0Sstevel@tonic-gate error = DDI_SUCCESS; 903*0Sstevel@tonic-gate } else 904*0Sstevel@tonic-gate error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp); 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate if (error == DDI_SUCCESS) 907*0Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 908*0Sstevel@tonic-gate error = DDI_FAILURE; 909*0Sstevel@tonic-gate cmn_err(CE_CONT, "fcpcii: conf probe failed.l=%x", tmp); 910*0Sstevel@tonic-gate } 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate if (error != DDI_SUCCESS) { 913*0Sstevel@tonic-gate return (fc_priv_error(cp, "pci config fetch failed")); 914*0Sstevel@tonic-gate } 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate /* 918*0Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 919*0Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 920*0Sstevel@tonic-gate * byte swapping enabled for pci register access here which 921*0Sstevel@tonic-gate * is a huge dependency on the current implementation. 922*0Sstevel@tonic-gate */ 923*0Sstevel@tonic-gate v = virt + reg; 924*0Sstevel@tonic-gate switch (len) { 925*0Sstevel@tonic-gate case sizeof (l): 926*0Sstevel@tonic-gate l = (int32_t)ddi_get32(h, (uint32_t *)v); 927*0Sstevel@tonic-gate break; 928*0Sstevel@tonic-gate case sizeof (w): 929*0Sstevel@tonic-gate w = (int16_t)ddi_get16(h, (uint16_t *)v); 930*0Sstevel@tonic-gate break; 931*0Sstevel@tonic-gate case sizeof (b): 932*0Sstevel@tonic-gate b = (int8_t)ddi_get8(h, (uint8_t *)v); 933*0Sstevel@tonic-gate break; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate /* 937*0Sstevel@tonic-gate * Remove the temporary config space mapping 938*0Sstevel@tonic-gate */ 939*0Sstevel@tonic-gate pci_unmap_phys(&h, &p); 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate if (error) { 942*0Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 946*0Sstevel@tonic-gate switch (len) { 947*0Sstevel@tonic-gate case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 948*0Sstevel@tonic-gate case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 949*0Sstevel@tonic-gate case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 950*0Sstevel@tonic-gate } 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate static int 956*0Sstevel@tonic-gate pfc_config_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 957*0Sstevel@tonic-gate { 958*0Sstevel@tonic-gate caddr_t virt, v; 959*0Sstevel@tonic-gate int error, reg, flags = 0; 960*0Sstevel@tonic-gate size_t len; 961*0Sstevel@tonic-gate uint32_t l, tmp; 962*0Sstevel@tonic-gate uint16_t w; 963*0Sstevel@tonic-gate uint8_t b; 964*0Sstevel@tonic-gate char *name = fc_cell2ptr(cp->svc_name); 965*0Sstevel@tonic-gate pci_regspec_t p; 966*0Sstevel@tonic-gate ddi_device_acc_attr_t acc; 967*0Sstevel@tonic-gate ddi_acc_handle_t h; 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 2) 970*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 2")); 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate /* 973*0Sstevel@tonic-gate * Construct a config address pci reg property from the args. 974*0Sstevel@tonic-gate * arg[0] is the configuration address. arg[1] is the data. 975*0Sstevel@tonic-gate */ 976*0Sstevel@tonic-gate p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0)); 977*0Sstevel@tonic-gate p.pci_phys_mid = p.pci_phys_low = 0; 978*0Sstevel@tonic-gate p.pci_size_hi = p.pci_size_low = 0; 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate /* 981*0Sstevel@tonic-gate * Verify that the address is a configuration space address 982*0Sstevel@tonic-gate * ss must be zero, n,p,t must be zero. 983*0Sstevel@tonic-gate */ 984*0Sstevel@tonic-gate if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) || 985*0Sstevel@tonic-gate ((p.pci_phys_hi & PCI_NPT_bits) != 0)) { 986*0Sstevel@tonic-gate cmn_err(CE_CONT, "pfc_config_store: " 987*0Sstevel@tonic-gate "invalid config addr: %x\n", p.pci_phys_hi); 988*0Sstevel@tonic-gate return (fc_priv_error(cp, "non-config addr")); 989*0Sstevel@tonic-gate } 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate /* 992*0Sstevel@tonic-gate * Extract the register number from the config address and 993*0Sstevel@tonic-gate * remove the register number from the physical address. 994*0Sstevel@tonic-gate */ 995*0Sstevel@tonic-gate reg = p.pci_phys_hi & PCI_REG_REG_M; 996*0Sstevel@tonic-gate p.pci_phys_hi &= ~PCI_REG_REG_M; 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate /* 999*0Sstevel@tonic-gate * Determine the access width .. we can switch on the 8th 1000*0Sstevel@tonic-gate * character of the name which is "config-{l,w,b}@" 1001*0Sstevel@tonic-gate */ 1002*0Sstevel@tonic-gate switch (*(name + 7)) { 1003*0Sstevel@tonic-gate case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break; 1004*0Sstevel@tonic-gate case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break; 1005*0Sstevel@tonic-gate case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break; 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate /* 1009*0Sstevel@tonic-gate * Verify that the access is properly aligned 1010*0Sstevel@tonic-gate */ 1011*0Sstevel@tonic-gate if ((reg & (len - 1)) != 0) 1012*0Sstevel@tonic-gate return (fc_priv_error(cp, "unaligned access")); 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate /* 1015*0Sstevel@tonic-gate * Map in configuration space (temporarily) 1016*0Sstevel@tonic-gate */ 1017*0Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1018*0Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1019*0Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate error = pci_map_phys(rp->child, &p, &virt, &acc, &h); 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate if (error) { 1024*0Sstevel@tonic-gate return (fc_priv_error(cp, "pci config map-in failed")); 1025*0Sstevel@tonic-gate } 1026*0Sstevel@tonic-gate 1027*0Sstevel@tonic-gate if (fcpci_indirect_map(rp->child) == DDI_SUCCESS) 1028*0Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 1031*0Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 1032*0Sstevel@tonic-gate error = DDI_SUCCESS; 1033*0Sstevel@tonic-gate } else 1034*0Sstevel@tonic-gate error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp); 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate if (error == DDI_SUCCESS) 1037*0Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 1038*0Sstevel@tonic-gate error = DDI_FAILURE; 1039*0Sstevel@tonic-gate cmn_err(CE_CONT, "fcpci: conf probe failed.l=%x", tmp); 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate if (error != DDI_SUCCESS) { 1043*0Sstevel@tonic-gate return (fc_priv_error(cp, "pci config store failed")); 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate /* 1048*0Sstevel@tonic-gate * XXX: We need access handle versions of peek/poke to move 1049*0Sstevel@tonic-gate * beyond the prototype ... we assume that we have hardware 1050*0Sstevel@tonic-gate * byte swapping enabled for pci register access here which 1051*0Sstevel@tonic-gate * is a huge dependency on the current implementation. 1052*0Sstevel@tonic-gate */ 1053*0Sstevel@tonic-gate v = virt + reg; 1054*0Sstevel@tonic-gate switch (len) { 1055*0Sstevel@tonic-gate case sizeof (l): 1056*0Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, (uint32_t)l); 1057*0Sstevel@tonic-gate break; 1058*0Sstevel@tonic-gate case sizeof (w): 1059*0Sstevel@tonic-gate ddi_put16(h, (uint16_t *)v, (uint16_t)w); 1060*0Sstevel@tonic-gate break; 1061*0Sstevel@tonic-gate case sizeof (b): 1062*0Sstevel@tonic-gate ddi_put8(h, (uint8_t *)v, (uint8_t)b); 1063*0Sstevel@tonic-gate break; 1064*0Sstevel@tonic-gate } 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate /* 1067*0Sstevel@tonic-gate * Remove the temporary config space mapping 1068*0Sstevel@tonic-gate */ 1069*0Sstevel@tonic-gate pci_unmap_phys(&h, &p); 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate if (error) { 1072*0Sstevel@tonic-gate return (fc_priv_error(cp, "access error")); 1073*0Sstevel@tonic-gate } 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate cp->nresults = fc_int2cell(0); 1076*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 1077*0Sstevel@tonic-gate } 1078*0Sstevel@tonic-gate 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate static int 1081*0Sstevel@tonic-gate pfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1082*0Sstevel@tonic-gate { 1083*0Sstevel@tonic-gate caddr_t name_virt, fcode_virt; 1084*0Sstevel@tonic-gate char *name, *fcode; 1085*0Sstevel@tonic-gate int fcode_len, status; 1086*0Sstevel@tonic-gate 1087*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 3) 1088*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 3")); 1089*0Sstevel@tonic-gate 1090*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 1091*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 1092*0Sstevel@tonic-gate 1093*0Sstevel@tonic-gate name_virt = fc_cell2ptr(fc_arg(cp, 0)); 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate fcode_len = fc_cell2int(fc_arg(cp, 2)); 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate if (copyinstr(fc_cell2ptr(name_virt), name, 1102*0Sstevel@tonic-gate FC_SVC_NAME_LEN - 1, NULL)) { 1103*0Sstevel@tonic-gate status = 0; 1104*0Sstevel@tonic-gate } else { 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate fcode = kmem_zalloc(fcode_len, KM_SLEEP); 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate if ((status = prom_get_fcode(name, fcode)) != 0) { 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate if (copyout((void *)fcode, (void *)fcode_virt, 1111*0Sstevel@tonic-gate fcode_len)) { 1112*0Sstevel@tonic-gate cmn_err(CE_WARN, " pfc_get_fcode: Unable " 1113*0Sstevel@tonic-gate "to copy out fcode image\n"); 1114*0Sstevel@tonic-gate status = 0; 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate kmem_free(fcode, fcode_len); 1119*0Sstevel@tonic-gate } 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 1122*0Sstevel@tonic-gate 1123*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 1124*0Sstevel@tonic-gate fc_result(cp, 0) = status; 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 1127*0Sstevel@tonic-gate } 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate static int 1130*0Sstevel@tonic-gate pfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1131*0Sstevel@tonic-gate { 1132*0Sstevel@tonic-gate caddr_t virt; 1133*0Sstevel@tonic-gate char *name; 1134*0Sstevel@tonic-gate int len; 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 1) 1137*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 1")); 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 1140*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate virt = fc_cell2ptr(fc_arg(cp, 0)); 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate if (copyinstr(fc_cell2ptr(virt), name, 1147*0Sstevel@tonic-gate FC_SVC_NAME_LEN - 1, NULL)) { 1148*0Sstevel@tonic-gate len = 0; 1149*0Sstevel@tonic-gate } else { 1150*0Sstevel@tonic-gate len = prom_get_fcode_size(name); 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate kmem_free(name, FC_SVC_NAME_LEN); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 1156*0Sstevel@tonic-gate fc_result(cp, 0) = len; 1157*0Sstevel@tonic-gate 1158*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 1159*0Sstevel@tonic-gate } 1160*0Sstevel@tonic-gate 1161*0Sstevel@tonic-gate /* 1162*0Sstevel@tonic-gate * Return the physical probe address: lo=0, mid=0, hi-config-addr 1163*0Sstevel@tonic-gate */ 1164*0Sstevel@tonic-gate static int 1165*0Sstevel@tonic-gate pfc_probe_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1166*0Sstevel@tonic-gate { 1167*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0) 1168*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0")); 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 2) 1171*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 3")); 1172*0Sstevel@tonic-gate 1173*0Sstevel@tonic-gate cp->nresults = fc_int2cell(2); 1174*0Sstevel@tonic-gate fc_result(cp, 1) = fc_int2cell(0); /* phys.lo */ 1175*0Sstevel@tonic-gate fc_result(cp, 0) = fc_int2cell(0); /* phys.mid */ 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 1178*0Sstevel@tonic-gate } 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate /* 1181*0Sstevel@tonic-gate * Return the phys.hi component of the probe address. 1182*0Sstevel@tonic-gate */ 1183*0Sstevel@tonic-gate static int 1184*0Sstevel@tonic-gate pfc_probe_space(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1185*0Sstevel@tonic-gate { 1186*0Sstevel@tonic-gate struct pci_ops_bus_args *ba = rp->bus_args; 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate ASSERT(ba); 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0) 1191*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0")); 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 1194*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 1197*0Sstevel@tonic-gate fc_result(cp, 0) = fc_uint32_t2cell(ba->config_address); /* phys.hi */ 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 1200*0Sstevel@tonic-gate } 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate static int 1203*0Sstevel@tonic-gate pfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1204*0Sstevel@tonic-gate { 1205*0Sstevel@tonic-gate fc_phandle_t h; 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate if (fc_cell2int(cp->nargs) != 0) 1208*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nargs must be 0")); 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate if (fc_cell2int(cp->nresults) < 1) 1211*0Sstevel@tonic-gate return (fc_syntax_error(cp, "nresults must be >= 1")); 1212*0Sstevel@tonic-gate 1213*0Sstevel@tonic-gate h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate cp->nresults = fc_int2cell(1); 1216*0Sstevel@tonic-gate fc_result(cp, 0) = fc_phandle2cell(h); 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate return (fc_success_op(ap, rp, cp)); 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate 1221*0Sstevel@tonic-gate int 1222*0Sstevel@tonic-gate pci_alloc_mem_chunk(dev_info_t *dip, uint64_t mem_align, uint64_t *mem_size, 1223*0Sstevel@tonic-gate uint64_t *mem_answer) 1224*0Sstevel@tonic-gate { 1225*0Sstevel@tonic-gate ndi_ra_request_t req; 1226*0Sstevel@tonic-gate int rval; 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 1229*0Sstevel@tonic-gate req.ra_flags = NDI_RA_ALLOC_BOUNDED; 1230*0Sstevel@tonic-gate req.ra_boundbase = 0; 1231*0Sstevel@tonic-gate req.ra_boundlen = PCI_4GIG_LIMIT; 1232*0Sstevel@tonic-gate req.ra_len = *mem_size; 1233*0Sstevel@tonic-gate req.ra_align_mask = mem_align - 1; 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate rval = ndi_ra_alloc(dip, &req, mem_answer, mem_size, 1236*0Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS); 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate return (rval); 1239*0Sstevel@tonic-gate } 1240*0Sstevel@tonic-gate int 1241*0Sstevel@tonic-gate pci_alloc_io_chunk(dev_info_t *dip, uint64_t io_align, uint64_t *io_size, 1242*0Sstevel@tonic-gate uint64_t *io_answer) 1243*0Sstevel@tonic-gate { 1244*0Sstevel@tonic-gate ndi_ra_request_t req; 1245*0Sstevel@tonic-gate int rval; 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate bzero((caddr_t)&req, sizeof (ndi_ra_request_t)); 1248*0Sstevel@tonic-gate req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK); 1249*0Sstevel@tonic-gate req.ra_boundbase = 0; 1250*0Sstevel@tonic-gate req.ra_boundlen = PCI_4GIG_LIMIT; 1251*0Sstevel@tonic-gate req.ra_len = *io_size; 1252*0Sstevel@tonic-gate req.ra_align_mask = io_align - 1; 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate rval = ndi_ra_alloc(dip, &req, io_answer, io_size, 1255*0Sstevel@tonic-gate NDI_RA_TYPE_IO, NDI_RA_PASS); 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate return (rval); 1258*0Sstevel@tonic-gate } 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate int 1261*0Sstevel@tonic-gate pci_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec) 1262*0Sstevel@tonic-gate { 1263*0Sstevel@tonic-gate uint64_t answer; 1264*0Sstevel@tonic-gate uint64_t alen; 1265*0Sstevel@tonic-gate int offset, tmp; 1266*0Sstevel@tonic-gate pci_regspec_t config; 1267*0Sstevel@tonic-gate caddr_t virt, v; 1268*0Sstevel@tonic-gate ddi_device_acc_attr_t acc; 1269*0Sstevel@tonic-gate ddi_acc_handle_t h; 1270*0Sstevel@tonic-gate ndi_ra_request_t request; 1271*0Sstevel@tonic-gate pci_regspec_t *assigned; 1272*0Sstevel@tonic-gate int assigned_len, entries, i, l, flags = 0, error; 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate l = phys_spec.pci_size_low; 1275*0Sstevel@tonic-gate 1276*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 1277*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned, 1278*0Sstevel@tonic-gate &assigned_len) == DDI_PROP_SUCCESS) { 1279*0Sstevel@tonic-gate 1280*0Sstevel@tonic-gate entries = assigned_len / (sizeof (pci_regspec_t)); 1281*0Sstevel@tonic-gate 1282*0Sstevel@tonic-gate /* 1283*0Sstevel@tonic-gate * Walk through the assigned-addresses entries. If there is 1284*0Sstevel@tonic-gate * a match, there is no need to allocate the resource. 1285*0Sstevel@tonic-gate */ 1286*0Sstevel@tonic-gate for (i = 0; i < entries; i++) { 1287*0Sstevel@tonic-gate if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) { 1288*0Sstevel@tonic-gate if (assigned[i].pci_size_low >= 1289*0Sstevel@tonic-gate phys_spec.pci_size_low) { 1290*0Sstevel@tonic-gate kmem_free(assigned, assigned_len); 1291*0Sstevel@tonic-gate return (0); 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate /* 1294*0Sstevel@tonic-gate * Fcode wants to assign more than what 1295*0Sstevel@tonic-gate * probe found. 1296*0Sstevel@tonic-gate */ 1297*0Sstevel@tonic-gate (void) pci_free_resource(dip, assigned[i]); 1298*0Sstevel@tonic-gate /* 1299*0Sstevel@tonic-gate * Go on to allocate resources. 1300*0Sstevel@tonic-gate */ 1301*0Sstevel@tonic-gate break; 1302*0Sstevel@tonic-gate } 1303*0Sstevel@tonic-gate /* 1304*0Sstevel@tonic-gate * Check if Fcode wants to map using different 1305*0Sstevel@tonic-gate * NPT bits. 1306*0Sstevel@tonic-gate */ 1307*0Sstevel@tonic-gate if (PCI_REG_BDFR_G(assigned[i].pci_phys_hi) == 1308*0Sstevel@tonic-gate PCI_REG_BDFR_G(phys_spec.pci_phys_hi)) { 1309*0Sstevel@tonic-gate /* 1310*0Sstevel@tonic-gate * It is an error to change SS bits 1311*0Sstevel@tonic-gate */ 1312*0Sstevel@tonic-gate if (PCI_REG_ADDR_G(assigned[i].pci_phys_hi) != 1313*0Sstevel@tonic-gate PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 1314*0Sstevel@tonic-gate 1315*0Sstevel@tonic-gate cmn_err(CE_WARN, "Fcode changing ss " 1316*0Sstevel@tonic-gate "bits in reg %x -- %x", 1317*0Sstevel@tonic-gate assigned[i].pci_phys_hi, 1318*0Sstevel@tonic-gate phys_spec.pci_phys_hi); 1319*0Sstevel@tonic-gate 1320*0Sstevel@tonic-gate kmem_free(assigned, assigned_len); 1321*0Sstevel@tonic-gate return (1); 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate /* 1325*0Sstevel@tonic-gate * Allocate enough 1326*0Sstevel@tonic-gate */ 1327*0Sstevel@tonic-gate l = MAX(assigned[i].pci_size_low, 1328*0Sstevel@tonic-gate phys_spec.pci_size_low); 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate (void) pci_free_resource(dip, assigned[i]); 1331*0Sstevel@tonic-gate /* 1332*0Sstevel@tonic-gate * Go on to allocate resources. 1333*0Sstevel@tonic-gate */ 1334*0Sstevel@tonic-gate break; 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate } 1337*0Sstevel@tonic-gate kmem_free(assigned, assigned_len); 1338*0Sstevel@tonic-gate } 1339*0Sstevel@tonic-gate 1340*0Sstevel@tonic-gate bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 1343*0Sstevel@tonic-gate config.pci_phys_hi &= ~PCI_REG_REG_M; 1344*0Sstevel@tonic-gate config.pci_phys_mid = config.pci_phys_low = 0; 1345*0Sstevel@tonic-gate config.pci_size_hi = config.pci_size_low = 0; 1346*0Sstevel@tonic-gate 1347*0Sstevel@tonic-gate /* 1348*0Sstevel@tonic-gate * Map in configuration space (temporarily) 1349*0Sstevel@tonic-gate */ 1350*0Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1351*0Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1352*0Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1353*0Sstevel@tonic-gate 1354*0Sstevel@tonic-gate if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) { 1355*0Sstevel@tonic-gate return (1); 1356*0Sstevel@tonic-gate } 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate if (fcpci_indirect_map(dip) == DDI_SUCCESS) 1359*0Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 1362*0Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 1363*0Sstevel@tonic-gate error = DDI_SUCCESS; 1364*0Sstevel@tonic-gate } else 1365*0Sstevel@tonic-gate error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp); 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate if (error == DDI_SUCCESS) 1368*0Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 1369*0Sstevel@tonic-gate error = DDI_FAILURE; 1370*0Sstevel@tonic-gate } 1371*0Sstevel@tonic-gate 1372*0Sstevel@tonic-gate if (error != DDI_SUCCESS) { 1373*0Sstevel@tonic-gate return (1); 1374*0Sstevel@tonic-gate } 1375*0Sstevel@tonic-gate 1376*0Sstevel@tonic-gate request.ra_flags |= NDI_RA_ALIGN_SIZE; 1377*0Sstevel@tonic-gate request.ra_boundbase = 0; 1378*0Sstevel@tonic-gate request.ra_boundlen = PCI_4GIG_LIMIT; 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate v = virt + offset; 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 1385*0Sstevel@tonic-gate request.ra_len = l; 1386*0Sstevel@tonic-gate request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate /* allocate memory space from the allocator */ 1389*0Sstevel@tonic-gate 1390*0Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 1391*0Sstevel@tonic-gate &request, &answer, &alen, 1392*0Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS) 1393*0Sstevel@tonic-gate != NDI_SUCCESS) { 1394*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1395*0Sstevel@tonic-gate return (1); 1396*0Sstevel@tonic-gate } 1397*0Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, "ROM addr = [0x%x.%x] len [0x%x]\n", 1398*0Sstevel@tonic-gate HIADDR(answer), 1399*0Sstevel@tonic-gate LOADDR(answer), 1400*0Sstevel@tonic-gate alen); 1401*0Sstevel@tonic-gate 1402*0Sstevel@tonic-gate /* program the low word */ 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 1407*0Sstevel@tonic-gate phys_spec.pci_phys_mid = HIADDR(answer); 1408*0Sstevel@tonic-gate } else { 1409*0Sstevel@tonic-gate request.ra_len = l; 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 1412*0Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 1413*0Sstevel@tonic-gate request.ra_flags ^= NDI_RA_ALLOC_BOUNDED; 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate if (phys_spec.pci_phys_hi & PCI_REG_REL_M) { 1416*0Sstevel@tonic-gate /* 1417*0Sstevel@tonic-gate * If it is a non relocatable address, 1418*0Sstevel@tonic-gate * then specify the address we want. 1419*0Sstevel@tonic-gate */ 1420*0Sstevel@tonic-gate request.ra_flags = NDI_RA_ALLOC_SPECIFIED; 1421*0Sstevel@tonic-gate request.ra_addr = (uint64_t)LADDR( 1422*0Sstevel@tonic-gate phys_spec.pci_phys_low, 1423*0Sstevel@tonic-gate phys_spec.pci_phys_mid); 1424*0Sstevel@tonic-gate } 1425*0Sstevel@tonic-gate 1426*0Sstevel@tonic-gate /* allocate memory space from the allocator */ 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 1429*0Sstevel@tonic-gate &request, &answer, &alen, 1430*0Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS) 1431*0Sstevel@tonic-gate != NDI_SUCCESS) { 1432*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1433*0Sstevel@tonic-gate if (request.ra_flags == 1434*0Sstevel@tonic-gate NDI_RA_ALLOC_SPECIFIED) 1435*0Sstevel@tonic-gate cmn_err(CE_WARN, "Unable to allocate " 1436*0Sstevel@tonic-gate "non relocatable address 0x%p\n", 1437*0Sstevel@tonic-gate (void *) request.ra_addr); 1438*0Sstevel@tonic-gate return (1); 1439*0Sstevel@tonic-gate } 1440*0Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, 1441*0Sstevel@tonic-gate "64 addr = [0x%x.%x] len [0x%x]\n", 1442*0Sstevel@tonic-gate HIADDR(answer), 1443*0Sstevel@tonic-gate LOADDR(answer), 1444*0Sstevel@tonic-gate alen); 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate /* program the low word */ 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate /* program the high word with value zero */ 1451*0Sstevel@tonic-gate v += 4; 1452*0Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, HIADDR(answer)); 1453*0Sstevel@tonic-gate 1454*0Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 1455*0Sstevel@tonic-gate phys_spec.pci_phys_mid = HIADDR(answer); 1456*0Sstevel@tonic-gate 1457*0Sstevel@tonic-gate break; 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 1460*0Sstevel@tonic-gate request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate if (phys_spec.pci_phys_hi & PCI_REG_REL_M) { 1463*0Sstevel@tonic-gate /* 1464*0Sstevel@tonic-gate * If it is a non relocatable address, 1465*0Sstevel@tonic-gate * then specify the address we want. 1466*0Sstevel@tonic-gate */ 1467*0Sstevel@tonic-gate request.ra_flags = NDI_RA_ALLOC_SPECIFIED; 1468*0Sstevel@tonic-gate request.ra_addr = (uint64_t) 1469*0Sstevel@tonic-gate phys_spec.pci_phys_low; 1470*0Sstevel@tonic-gate } 1471*0Sstevel@tonic-gate 1472*0Sstevel@tonic-gate /* allocate memory space from the allocator */ 1473*0Sstevel@tonic-gate 1474*0Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 1475*0Sstevel@tonic-gate &request, &answer, &alen, 1476*0Sstevel@tonic-gate NDI_RA_TYPE_MEM, NDI_RA_PASS) 1477*0Sstevel@tonic-gate != NDI_SUCCESS) { 1478*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1479*0Sstevel@tonic-gate if (request.ra_flags == 1480*0Sstevel@tonic-gate NDI_RA_ALLOC_SPECIFIED) 1481*0Sstevel@tonic-gate cmn_err(CE_WARN, "Unable to allocate " 1482*0Sstevel@tonic-gate "non relocatable address 0x%p\n", 1483*0Sstevel@tonic-gate (void *) request.ra_addr); 1484*0Sstevel@tonic-gate return (1); 1485*0Sstevel@tonic-gate } 1486*0Sstevel@tonic-gate 1487*0Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, 1488*0Sstevel@tonic-gate "32 addr = [0x%x.%x] len [0x%x]\n", 1489*0Sstevel@tonic-gate HIADDR(answer), 1490*0Sstevel@tonic-gate LOADDR(answer), 1491*0Sstevel@tonic-gate alen); 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate /* program the low word */ 1494*0Sstevel@tonic-gate 1495*0Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate break; 1500*0Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO): 1501*0Sstevel@tonic-gate request.ra_flags |= NDI_RA_ALLOC_BOUNDED; 1502*0Sstevel@tonic-gate 1503*0Sstevel@tonic-gate if (phys_spec.pci_phys_hi & PCI_REG_REL_M) { 1504*0Sstevel@tonic-gate /* 1505*0Sstevel@tonic-gate * If it is a non relocatable address, 1506*0Sstevel@tonic-gate * then specify the address we want. 1507*0Sstevel@tonic-gate */ 1508*0Sstevel@tonic-gate request.ra_flags = NDI_RA_ALLOC_SPECIFIED; 1509*0Sstevel@tonic-gate request.ra_addr = (uint64_t) 1510*0Sstevel@tonic-gate phys_spec.pci_phys_low; 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate /* allocate I/O space from the allocator */ 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate if (ndi_ra_alloc(ddi_get_parent(dip), 1516*0Sstevel@tonic-gate &request, &answer, &alen, 1517*0Sstevel@tonic-gate NDI_RA_TYPE_IO, NDI_RA_PASS) 1518*0Sstevel@tonic-gate != NDI_SUCCESS) { 1519*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1520*0Sstevel@tonic-gate if (request.ra_flags == 1521*0Sstevel@tonic-gate NDI_RA_ALLOC_SPECIFIED) 1522*0Sstevel@tonic-gate cmn_err(CE_WARN, "Unable to allocate " 1523*0Sstevel@tonic-gate "non relocatable IO Space 0x%p\n", 1524*0Sstevel@tonic-gate (void *) request.ra_addr); 1525*0Sstevel@tonic-gate return (1); 1526*0Sstevel@tonic-gate } 1527*0Sstevel@tonic-gate FC_DEBUG3(1, CE_CONT, 1528*0Sstevel@tonic-gate "I/O addr = [0x%x.%x] len [0x%x]\n", 1529*0Sstevel@tonic-gate HIADDR(answer), 1530*0Sstevel@tonic-gate LOADDR(answer), 1531*0Sstevel@tonic-gate alen); 1532*0Sstevel@tonic-gate 1533*0Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, LOADDR(answer)); 1534*0Sstevel@tonic-gate 1535*0Sstevel@tonic-gate phys_spec.pci_phys_low = LOADDR(answer); 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate break; 1538*0Sstevel@tonic-gate default: 1539*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1540*0Sstevel@tonic-gate return (1); 1541*0Sstevel@tonic-gate } /* switch */ 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate /* 1545*0Sstevel@tonic-gate * Now that memory locations are assigned, 1546*0Sstevel@tonic-gate * update the assigned address property. 1547*0Sstevel@tonic-gate */ 1548*0Sstevel@tonic-gate if (pfc_update_assigned_prop(dip, &phys_spec)) { 1549*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1550*0Sstevel@tonic-gate return (1); 1551*0Sstevel@tonic-gate } 1552*0Sstevel@tonic-gate 1553*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1554*0Sstevel@tonic-gate 1555*0Sstevel@tonic-gate return (0); 1556*0Sstevel@tonic-gate } 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate int 1559*0Sstevel@tonic-gate pci_free_resource(dev_info_t *dip, pci_regspec_t phys_spec) 1560*0Sstevel@tonic-gate { 1561*0Sstevel@tonic-gate int offset, tmp; 1562*0Sstevel@tonic-gate pci_regspec_t config; 1563*0Sstevel@tonic-gate caddr_t virt, v; 1564*0Sstevel@tonic-gate ddi_device_acc_attr_t acc; 1565*0Sstevel@tonic-gate ddi_acc_handle_t h; 1566*0Sstevel@tonic-gate ndi_ra_request_t request; 1567*0Sstevel@tonic-gate int l, error, flags = 0; 1568*0Sstevel@tonic-gate 1569*0Sstevel@tonic-gate bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 1570*0Sstevel@tonic-gate 1571*0Sstevel@tonic-gate config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi; 1572*0Sstevel@tonic-gate config.pci_phys_hi &= ~PCI_REG_REG_M; 1573*0Sstevel@tonic-gate config.pci_phys_mid = config.pci_phys_low = 0; 1574*0Sstevel@tonic-gate config.pci_size_hi = config.pci_size_low = 0; 1575*0Sstevel@tonic-gate 1576*0Sstevel@tonic-gate /* 1577*0Sstevel@tonic-gate * Map in configuration space (temporarily) 1578*0Sstevel@tonic-gate */ 1579*0Sstevel@tonic-gate acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1580*0Sstevel@tonic-gate acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1581*0Sstevel@tonic-gate acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1582*0Sstevel@tonic-gate 1583*0Sstevel@tonic-gate if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) { 1584*0Sstevel@tonic-gate return (1); 1585*0Sstevel@tonic-gate } 1586*0Sstevel@tonic-gate if (fcpci_indirect_map(dip) == DDI_SUCCESS) 1587*0Sstevel@tonic-gate flags |= PCICFG_CONF_INDIRECT_MAP; 1588*0Sstevel@tonic-gate 1589*0Sstevel@tonic-gate if (flags & PCICFG_CONF_INDIRECT_MAP) { 1590*0Sstevel@tonic-gate tmp = (int32_t)ddi_get32(h, (uint32_t *)virt); 1591*0Sstevel@tonic-gate error = DDI_SUCCESS; 1592*0Sstevel@tonic-gate } else 1593*0Sstevel@tonic-gate error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp); 1594*0Sstevel@tonic-gate 1595*0Sstevel@tonic-gate if (error == DDI_SUCCESS) 1596*0Sstevel@tonic-gate if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) { 1597*0Sstevel@tonic-gate error = DDI_FAILURE; 1598*0Sstevel@tonic-gate } 1599*0Sstevel@tonic-gate if (error != DDI_SUCCESS) { 1600*0Sstevel@tonic-gate return (1); 1601*0Sstevel@tonic-gate } 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate 1604*0Sstevel@tonic-gate offset = PCI_REG_REG_G(phys_spec.pci_phys_hi); 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate v = virt + offset; 1607*0Sstevel@tonic-gate 1608*0Sstevel@tonic-gate /* 1609*0Sstevel@tonic-gate * Pick up the size to be freed. It may be different from 1610*0Sstevel@tonic-gate * what probe finds. 1611*0Sstevel@tonic-gate */ 1612*0Sstevel@tonic-gate l = phys_spec.pci_size_low; 1613*0Sstevel@tonic-gate 1614*0Sstevel@tonic-gate if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) { 1615*0Sstevel@tonic-gate /* free memory back to the allocator */ 1616*0Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low, 1617*0Sstevel@tonic-gate l, NDI_RA_TYPE_MEM, 1618*0Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 1619*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1620*0Sstevel@tonic-gate return (1); 1621*0Sstevel@tonic-gate } 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate /* Unmap the BAR by writing a zero */ 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gate ddi_put32(h, (uint32_t *)v, 0); 1626*0Sstevel@tonic-gate } else { 1627*0Sstevel@tonic-gate switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) { 1628*0Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM64): 1629*0Sstevel@tonic-gate /* free memory back to the allocator */ 1630*0Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), 1631*0Sstevel@tonic-gate LADDR(phys_spec.pci_phys_low, 1632*0Sstevel@tonic-gate phys_spec.pci_phys_mid), 1633*0Sstevel@tonic-gate l, NDI_RA_TYPE_MEM, 1634*0Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 1635*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1636*0Sstevel@tonic-gate return (1); 1637*0Sstevel@tonic-gate } 1638*0Sstevel@tonic-gate 1639*0Sstevel@tonic-gate break; 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_MEM32): 1642*0Sstevel@tonic-gate /* free memory back to the allocator */ 1643*0Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), 1644*0Sstevel@tonic-gate phys_spec.pci_phys_low, 1645*0Sstevel@tonic-gate l, NDI_RA_TYPE_MEM, 1646*0Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 1647*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1648*0Sstevel@tonic-gate return (1); 1649*0Sstevel@tonic-gate } 1650*0Sstevel@tonic-gate 1651*0Sstevel@tonic-gate break; 1652*0Sstevel@tonic-gate case PCI_REG_ADDR_G(PCI_ADDR_IO): 1653*0Sstevel@tonic-gate /* free I/O space back to the allocator */ 1654*0Sstevel@tonic-gate if (ndi_ra_free(ddi_get_parent(dip), 1655*0Sstevel@tonic-gate phys_spec.pci_phys_low, 1656*0Sstevel@tonic-gate l, NDI_RA_TYPE_IO, 1657*0Sstevel@tonic-gate NDI_RA_PASS) != NDI_SUCCESS) { 1658*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1659*0Sstevel@tonic-gate return (1); 1660*0Sstevel@tonic-gate } 1661*0Sstevel@tonic-gate break; 1662*0Sstevel@tonic-gate default: 1663*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1664*0Sstevel@tonic-gate return (1); 1665*0Sstevel@tonic-gate } /* switch */ 1666*0Sstevel@tonic-gate } 1667*0Sstevel@tonic-gate 1668*0Sstevel@tonic-gate /* 1669*0Sstevel@tonic-gate * Now that memory locations are assigned, 1670*0Sstevel@tonic-gate * update the assigned address property. 1671*0Sstevel@tonic-gate */ 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "updating assigned-addresss for %x\n", 1674*0Sstevel@tonic-gate phys_spec.pci_phys_hi); 1675*0Sstevel@tonic-gate 1676*0Sstevel@tonic-gate if (pfc_remove_assigned_prop(dip, &phys_spec)) { 1677*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1678*0Sstevel@tonic-gate return (1); 1679*0Sstevel@tonic-gate } 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate pci_unmap_phys(&h, &config); 1682*0Sstevel@tonic-gate 1683*0Sstevel@tonic-gate return (0); 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate int 1688*0Sstevel@tonic-gate pci_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 1689*0Sstevel@tonic-gate caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 1690*0Sstevel@tonic-gate ddi_acc_handle_t *handlep) 1691*0Sstevel@tonic-gate { 1692*0Sstevel@tonic-gate ddi_map_req_t mr; 1693*0Sstevel@tonic-gate ddi_acc_hdl_t *hp; 1694*0Sstevel@tonic-gate int result; 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 1697*0Sstevel@tonic-gate hp = impl_acc_hdl_get(*handlep); 1698*0Sstevel@tonic-gate hp->ah_vers = VERS_ACCHDL; 1699*0Sstevel@tonic-gate hp->ah_dip = dip; 1700*0Sstevel@tonic-gate hp->ah_rnumber = 0; 1701*0Sstevel@tonic-gate hp->ah_offset = 0; 1702*0Sstevel@tonic-gate hp->ah_len = 0; 1703*0Sstevel@tonic-gate hp->ah_acc = *accattrp; 1704*0Sstevel@tonic-gate 1705*0Sstevel@tonic-gate mr.map_op = DDI_MO_MAP_LOCKED; 1706*0Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 1707*0Sstevel@tonic-gate mr.map_obj.rp = (struct regspec *)phys_spec; 1708*0Sstevel@tonic-gate mr.map_prot = PROT_READ | PROT_WRITE; 1709*0Sstevel@tonic-gate mr.map_flags = DDI_MF_KERNEL_MAPPING; 1710*0Sstevel@tonic-gate mr.map_handlep = hp; 1711*0Sstevel@tonic-gate mr.map_vers = DDI_MAP_VERSION; 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate result = ddi_map(dip, &mr, 0, 0, addrp); 1714*0Sstevel@tonic-gate 1715*0Sstevel@tonic-gate if (result != DDI_SUCCESS) { 1716*0Sstevel@tonic-gate impl_acc_hdl_free(*handlep); 1717*0Sstevel@tonic-gate *handlep = (ddi_acc_handle_t)NULL; 1718*0Sstevel@tonic-gate } else { 1719*0Sstevel@tonic-gate hp->ah_addr = *addrp; 1720*0Sstevel@tonic-gate } 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate return (result); 1723*0Sstevel@tonic-gate } 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate void 1726*0Sstevel@tonic-gate pci_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 1727*0Sstevel@tonic-gate { 1728*0Sstevel@tonic-gate ddi_map_req_t mr; 1729*0Sstevel@tonic-gate ddi_acc_hdl_t *hp; 1730*0Sstevel@tonic-gate 1731*0Sstevel@tonic-gate hp = impl_acc_hdl_get(*handlep); 1732*0Sstevel@tonic-gate ASSERT(hp); 1733*0Sstevel@tonic-gate 1734*0Sstevel@tonic-gate mr.map_op = DDI_MO_UNMAP; 1735*0Sstevel@tonic-gate mr.map_type = DDI_MT_REGSPEC; 1736*0Sstevel@tonic-gate mr.map_obj.rp = (struct regspec *)ph; 1737*0Sstevel@tonic-gate mr.map_prot = PROT_READ | PROT_WRITE; 1738*0Sstevel@tonic-gate mr.map_flags = DDI_MF_KERNEL_MAPPING; 1739*0Sstevel@tonic-gate mr.map_handlep = hp; 1740*0Sstevel@tonic-gate mr.map_vers = DDI_MAP_VERSION; 1741*0Sstevel@tonic-gate 1742*0Sstevel@tonic-gate (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 1743*0Sstevel@tonic-gate hp->ah_len, &hp->ah_addr); 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate impl_acc_hdl_free(*handlep); 1746*0Sstevel@tonic-gate 1747*0Sstevel@tonic-gate 1748*0Sstevel@tonic-gate *handlep = (ddi_acc_handle_t)NULL; 1749*0Sstevel@tonic-gate } 1750*0Sstevel@tonic-gate 1751*0Sstevel@tonic-gate int 1752*0Sstevel@tonic-gate pfc_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone) 1753*0Sstevel@tonic-gate { 1754*0Sstevel@tonic-gate int alen; 1755*0Sstevel@tonic-gate pci_regspec_t *assigned; 1756*0Sstevel@tonic-gate caddr_t newreg; 1757*0Sstevel@tonic-gate uint_t status; 1758*0Sstevel@tonic-gate 1759*0Sstevel@tonic-gate status = ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 1760*0Sstevel@tonic-gate "assigned-addresses", (caddr_t)&assigned, &alen); 1761*0Sstevel@tonic-gate switch (status) { 1762*0Sstevel@tonic-gate case DDI_PROP_SUCCESS: 1763*0Sstevel@tonic-gate break; 1764*0Sstevel@tonic-gate case DDI_PROP_NO_MEMORY: 1765*0Sstevel@tonic-gate return (1); 1766*0Sstevel@tonic-gate default: 1767*0Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 1768*0Sstevel@tonic-gate "assigned-addresses", (int *)newone, 1769*0Sstevel@tonic-gate sizeof (*newone)/sizeof (int)); 1770*0Sstevel@tonic-gate return (0); 1771*0Sstevel@tonic-gate } 1772*0Sstevel@tonic-gate 1773*0Sstevel@tonic-gate /* 1774*0Sstevel@tonic-gate * Allocate memory for the existing 1775*0Sstevel@tonic-gate * assigned-addresses(s) plus one and then 1776*0Sstevel@tonic-gate * build it. 1777*0Sstevel@tonic-gate */ 1778*0Sstevel@tonic-gate 1779*0Sstevel@tonic-gate newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP); 1780*0Sstevel@tonic-gate 1781*0Sstevel@tonic-gate bcopy(assigned, newreg, alen); 1782*0Sstevel@tonic-gate bcopy(newone, newreg + alen, sizeof (*newone)); 1783*0Sstevel@tonic-gate 1784*0Sstevel@tonic-gate /* 1785*0Sstevel@tonic-gate * Write out the new "assigned-addresses" spec 1786*0Sstevel@tonic-gate */ 1787*0Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, 1788*0Sstevel@tonic-gate "assigned-addresses", (int *)newreg, 1789*0Sstevel@tonic-gate (alen + sizeof (*newone))/sizeof (int)); 1790*0Sstevel@tonic-gate 1791*0Sstevel@tonic-gate kmem_free((caddr_t)newreg, alen+sizeof (*newone)); 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate return (0); 1794*0Sstevel@tonic-gate } 1795*0Sstevel@tonic-gate int 1796*0Sstevel@tonic-gate pfc_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone) 1797*0Sstevel@tonic-gate { 1798*0Sstevel@tonic-gate int alen, new_len, num_entries, i; 1799*0Sstevel@tonic-gate pci_regspec_t *assigned; 1800*0Sstevel@tonic-gate uint_t status; 1801*0Sstevel@tonic-gate 1802*0Sstevel@tonic-gate status = ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 1803*0Sstevel@tonic-gate "assigned-addresses", (caddr_t)&assigned, &alen); 1804*0Sstevel@tonic-gate switch (status) { 1805*0Sstevel@tonic-gate case DDI_PROP_SUCCESS: 1806*0Sstevel@tonic-gate break; 1807*0Sstevel@tonic-gate case DDI_PROP_NO_MEMORY: 1808*0Sstevel@tonic-gate return (1); 1809*0Sstevel@tonic-gate default: 1810*0Sstevel@tonic-gate return (0); 1811*0Sstevel@tonic-gate } 1812*0Sstevel@tonic-gate 1813*0Sstevel@tonic-gate num_entries = alen / sizeof (pci_regspec_t); 1814*0Sstevel@tonic-gate new_len = alen - sizeof (pci_regspec_t); 1815*0Sstevel@tonic-gate 1816*0Sstevel@tonic-gate /* 1817*0Sstevel@tonic-gate * Search for the memory being removed. 1818*0Sstevel@tonic-gate */ 1819*0Sstevel@tonic-gate for (i = 0; i < num_entries; i++) { 1820*0Sstevel@tonic-gate if (assigned[i].pci_phys_hi == oldone->pci_phys_hi) { 1821*0Sstevel@tonic-gate if (new_len == 0) { 1822*0Sstevel@tonic-gate (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, 1823*0Sstevel@tonic-gate "assigned-addresses"); 1824*0Sstevel@tonic-gate break; 1825*0Sstevel@tonic-gate } 1826*0Sstevel@tonic-gate if ((new_len - (i * sizeof (pci_regspec_t))) 1827*0Sstevel@tonic-gate == 0) { 1828*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "assigned-address entry " 1829*0Sstevel@tonic-gate "%x removed from property (last entry)\n", 1830*0Sstevel@tonic-gate oldone->pci_phys_hi); 1831*0Sstevel@tonic-gate } else { 1832*0Sstevel@tonic-gate bcopy((void *)(assigned + i + 1), 1833*0Sstevel@tonic-gate (void *)(assigned + i), 1834*0Sstevel@tonic-gate (new_len - (i * sizeof (pci_regspec_t)))); 1835*0Sstevel@tonic-gate 1836*0Sstevel@tonic-gate FC_DEBUG1(1, CE_CONT, "assigned-address entry " 1837*0Sstevel@tonic-gate "%x removed from property\n", 1838*0Sstevel@tonic-gate oldone->pci_phys_hi); 1839*0Sstevel@tonic-gate } 1840*0Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, 1841*0Sstevel@tonic-gate dip, "assigned-addresses", (int *)assigned, 1842*0Sstevel@tonic-gate (new_len/sizeof (int))); 1843*0Sstevel@tonic-gate 1844*0Sstevel@tonic-gate break; 1845*0Sstevel@tonic-gate } 1846*0Sstevel@tonic-gate } 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate return (0); 1849*0Sstevel@tonic-gate } 1850*0Sstevel@tonic-gate /* 1851*0Sstevel@tonic-gate * we recognize the non transparent bridge child nodes with the 1852*0Sstevel@tonic-gate * following property. This is specific to this implementation only. 1853*0Sstevel@tonic-gate * This property is specific to AP nodes only. 1854*0Sstevel@tonic-gate */ 1855*0Sstevel@tonic-gate #define PCICFG_DEV_CONF_MAP_PROP "pci-parent-indirect" 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate /* 1858*0Sstevel@tonic-gate * If a non transparent bridge drives a hotplug/hotswap bus, then 1859*0Sstevel@tonic-gate * the following property must be defined for the node either by 1860*0Sstevel@tonic-gate * the driver or the OBP. 1861*0Sstevel@tonic-gate */ 1862*0Sstevel@tonic-gate #define PCICFG_BUS_CONF_MAP_PROP "pci-conf-indirect" 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate /* 1865*0Sstevel@tonic-gate * this function is called only for SPARC platforms, where we may have 1866*0Sstevel@tonic-gate * a mix n' match of direct vs indirectly mapped configuration space. 1867*0Sstevel@tonic-gate */ 1868*0Sstevel@tonic-gate /*ARGSUSED*/ 1869*0Sstevel@tonic-gate static int 1870*0Sstevel@tonic-gate fcpci_indirect_map(dev_info_t *dip) 1871*0Sstevel@tonic-gate { 1872*0Sstevel@tonic-gate int rc = DDI_FAILURE; 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), DDI_PROP_DONTPASS, 1875*0Sstevel@tonic-gate PCICFG_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE) 1876*0Sstevel@tonic-gate rc = DDI_SUCCESS; 1877*0Sstevel@tonic-gate else 1878*0Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), 1879*0Sstevel@tonic-gate DDI_PROP_DONTPASS, PCICFG_BUS_CONF_MAP_PROP, 1880*0Sstevel@tonic-gate DDI_FAILURE) != DDI_FAILURE) 1881*0Sstevel@tonic-gate rc = DDI_SUCCESS; 1882*0Sstevel@tonic-gate 1883*0Sstevel@tonic-gate return (rc); 1884*0Sstevel@tonic-gate } 1885