17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 500d0963fSdilpreet * Common Development and Distribution License (the "License"). 600d0963fSdilpreet * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217b93957cSeota 227c478bd9Sstevel@tonic-gate /* 235679c89fSjv227347 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 26cd21e7c5SGarrett D'Amore /* 27b89e420aSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org> 28cd21e7c5SGarrett D'Amore */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * sun4 specific DDI implementation 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 347c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 357c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 367c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/ontrap.h> 397c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 407c478bd9Sstevel@tonic-gate #include <sys/membar.h> 417c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 427c478bd9Sstevel@tonic-gate #include <sys/ndifm.h> 437c478bd9Sstevel@tonic-gate #include <sys/fm/io/ddi.h> 447c478bd9Sstevel@tonic-gate #include <sys/ivintr.h> 457c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 467c478bd9Sstevel@tonic-gate #include <sys/conf.h> 477c478bd9Sstevel@tonic-gate #include <sys/ethernet.h> 487c478bd9Sstevel@tonic-gate #include <sys/idprom.h> 497c478bd9Sstevel@tonic-gate #include <sys/promif.h> 507c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h> 517c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 527c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 537c478bd9Sstevel@tonic-gate #include <sys/vm.h> 547c478bd9Sstevel@tonic-gate #include <sys/ddi_isa.h> 5525e8c5aaSvikram #include <sys/modctl.h> 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *, 58a195726fSgovinda ddi_intr_handle_impl_t *); 597c478bd9Sstevel@tonic-gate #pragma weak get_intr_parent 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 627c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 637c478bd9Sstevel@tonic-gate #pragma weak process_intr_ops 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate void cells_1275_copy(prop_1275_cell_t *, prop_1275_cell_t *, int32_t); 667c478bd9Sstevel@tonic-gate prop_1275_cell_t *cells_1275_cmp(prop_1275_cell_t *, prop_1275_cell_t *, 677c478bd9Sstevel@tonic-gate int32_t len); 687c478bd9Sstevel@tonic-gate #pragma weak cells_1275_copy 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * Wrapper for ddi_prop_lookup_int_array(). 727c478bd9Sstevel@tonic-gate * This is handy because it returns the prop length in 737c478bd9Sstevel@tonic-gate * bytes which is what most of the callers require. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static int 777c478bd9Sstevel@tonic-gate get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen) 787c478bd9Sstevel@tonic-gate { 797c478bd9Sstevel@tonic-gate int ret; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di, 827c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, pname, pval, plen)) == DDI_PROP_SUCCESS) { 837c478bd9Sstevel@tonic-gate *plen = (*plen) * (uint_t)sizeof (int); 847c478bd9Sstevel@tonic-gate } 857c478bd9Sstevel@tonic-gate return (ret); 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * SECTION: DDI Node Configuration 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * init_regspec_64: 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * If the parent #size-cells is 2, convert the upa-style or 967c478bd9Sstevel@tonic-gate * safari-style reg property from 2-size cells to 1 size cell 977c478bd9Sstevel@tonic-gate * format, ignoring the size_hi, which must be zero for devices. 987c478bd9Sstevel@tonic-gate * (It won't be zero in the memory list properties in the memory 997c478bd9Sstevel@tonic-gate * nodes, but that doesn't matter here.) 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate struct ddi_parent_private_data * 1027c478bd9Sstevel@tonic-gate init_regspec_64(dev_info_t *dip) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pd; 1057c478bd9Sstevel@tonic-gate dev_info_t *parent; 1067c478bd9Sstevel@tonic-gate int size_cells; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * If there are no "reg"s in the child node, return. 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate pd = ddi_get_parent_data(dip); 1127c478bd9Sstevel@tonic-gate if ((pd == NULL) || (pd->par_nreg == 0)) { 1137c478bd9Sstevel@tonic-gate return (pd); 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate parent = ddi_get_parent(dip); 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 1187c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if (size_cells != 1) { 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate int n, j; 1237c478bd9Sstevel@tonic-gate struct regspec *irp; 1247c478bd9Sstevel@tonic-gate struct reg_64 { 1257c478bd9Sstevel@tonic-gate uint_t addr_hi, addr_lo, size_hi, size_lo; 1267c478bd9Sstevel@tonic-gate }; 1277c478bd9Sstevel@tonic-gate struct reg_64 *r64_rp; 1287c478bd9Sstevel@tonic-gate struct regspec *rp; 1297c478bd9Sstevel@tonic-gate uint_t len = 0; 1307c478bd9Sstevel@tonic-gate int *reg_prop; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate ASSERT(size_cells == 2); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * We already looked the property up once before if 1367c478bd9Sstevel@tonic-gate * pd is non-NULL. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate (void) ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 1397c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, OBP_REG, ®_prop, &len); 1407c478bd9Sstevel@tonic-gate ASSERT(len != 0); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate n = sizeof (struct reg_64) / sizeof (int); 1437c478bd9Sstevel@tonic-gate n = len / n; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate * We're allocating a buffer the size of the PROM's property, 1477c478bd9Sstevel@tonic-gate * but we're only using a smaller portion when we assign it 1487c478bd9Sstevel@tonic-gate * to a regspec. We do this so that in the 1497c478bd9Sstevel@tonic-gate * impl_ddi_sunbus_removechild function, we will 1507c478bd9Sstevel@tonic-gate * always free the right amount of memory. 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate irp = rp = (struct regspec *)reg_prop; 1537c478bd9Sstevel@tonic-gate r64_rp = (struct reg_64 *)pd->par_reg; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate for (j = 0; j < n; ++j, ++rp, ++r64_rp) { 1567c478bd9Sstevel@tonic-gate ASSERT(r64_rp->size_hi == 0); 1577c478bd9Sstevel@tonic-gate rp->regspec_bustype = r64_rp->addr_hi; 1587c478bd9Sstevel@tonic-gate rp->regspec_addr = r64_rp->addr_lo; 1597c478bd9Sstevel@tonic-gate rp->regspec_size = r64_rp->size_lo; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate ddi_prop_free((void *)pd->par_reg); 1637c478bd9Sstevel@tonic-gate pd->par_nreg = n; 1647c478bd9Sstevel@tonic-gate pd->par_reg = irp; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate return (pd); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * Create a ddi_parent_private_data structure from the ddi properties of 1717c478bd9Sstevel@tonic-gate * the dev_info node. 1727c478bd9Sstevel@tonic-gate * 1737c478bd9Sstevel@tonic-gate * The "reg" is required if the driver wishes to create mappings on behalf 1747c478bd9Sstevel@tonic-gate * of the device. The "reg" property is assumed to be a list of at least 1757c478bd9Sstevel@tonic-gate * one triplet 1767c478bd9Sstevel@tonic-gate * 1777c478bd9Sstevel@tonic-gate * <bustype, address, size>*1 1787c478bd9Sstevel@tonic-gate * 1797c478bd9Sstevel@tonic-gate * The "interrupt" property is no longer part of parent private data on 1807c478bd9Sstevel@tonic-gate * sun4u. The interrupt parent is may not be the device tree parent. 1817c478bd9Sstevel@tonic-gate * 1827c478bd9Sstevel@tonic-gate * The "ranges" property describes the mapping of child addresses to parent 1837c478bd9Sstevel@tonic-gate * addresses. 1847c478bd9Sstevel@tonic-gate * 1857c478bd9Sstevel@tonic-gate * N.B. struct rangespec is defined for the following default values: 1867c478bd9Sstevel@tonic-gate * parent child 1877c478bd9Sstevel@tonic-gate * #address-cells 2 2 1887c478bd9Sstevel@tonic-gate * #size-cells 1 1 1897c478bd9Sstevel@tonic-gate * This function doesn't deal with non-default cells and will not create 1907c478bd9Sstevel@tonic-gate * ranges in such cases. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate void 1937c478bd9Sstevel@tonic-gate make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 1967c478bd9Sstevel@tonic-gate int *reg_prop, *rng_prop; 1977c478bd9Sstevel@tonic-gate uint_t reg_len = 0, rng_len = 0; 1987c478bd9Sstevel@tonic-gate dev_info_t *parent; 1997c478bd9Sstevel@tonic-gate int parent_addr_cells, parent_size_cells; 2007c478bd9Sstevel@tonic-gate int child_addr_cells, child_size_cells; 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate *ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate /* 2057c478bd9Sstevel@tonic-gate * root node has no parent private data, so *ppd should 2067c478bd9Sstevel@tonic-gate * be initialized for naming to work properly. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate if ((parent = ddi_get_parent(child)) == NULL) 2097c478bd9Sstevel@tonic-gate return; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * Set reg field of parent data from "reg" property 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate if ((get_prop_int_array(child, OBP_REG, ®_prop, ®_len) 2157c478bd9Sstevel@tonic-gate == DDI_PROP_SUCCESS) && (reg_len != 0)) { 2167c478bd9Sstevel@tonic-gate pdptr->par_nreg = (int)(reg_len / sizeof (struct regspec)); 2177c478bd9Sstevel@tonic-gate pdptr->par_reg = (struct regspec *)reg_prop; 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* 2217c478bd9Sstevel@tonic-gate * "ranges" property ... 2227c478bd9Sstevel@tonic-gate * 2237c478bd9Sstevel@tonic-gate * This function does not handle cases where #address-cells != 2 2247c478bd9Sstevel@tonic-gate * and * min(parent, child) #size-cells != 1 (see bugid 4211124). 2257c478bd9Sstevel@tonic-gate * 2267c478bd9Sstevel@tonic-gate * Nexus drivers with such exceptions (e.g. pci ranges) 2277c478bd9Sstevel@tonic-gate * should either create a separate function for handling 2287c478bd9Sstevel@tonic-gate * ranges or not use parent private data to store ranges. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* root node has no ranges */ 2327c478bd9Sstevel@tonic-gate if ((parent = ddi_get_parent(child)) == NULL) 2337c478bd9Sstevel@tonic-gate return; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate child_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 2367c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#address-cells", 2); 2377c478bd9Sstevel@tonic-gate child_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 2387c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 2397c478bd9Sstevel@tonic-gate parent_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 2407c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#address-cells", 2); 2417c478bd9Sstevel@tonic-gate parent_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 2427c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 2437c478bd9Sstevel@tonic-gate if (child_addr_cells != 2 || parent_addr_cells != 2 || 2447c478bd9Sstevel@tonic-gate (child_size_cells != 1 && parent_size_cells != 1)) { 2457c478bd9Sstevel@tonic-gate NDI_CONFIG_DEBUG((CE_NOTE, "!ranges not made in parent data; " 2467c478bd9Sstevel@tonic-gate "#address-cells or #size-cells have non-default value")); 2477c478bd9Sstevel@tonic-gate return; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate if (get_prop_int_array(child, OBP_RANGES, &rng_prop, &rng_len) 2517c478bd9Sstevel@tonic-gate == DDI_PROP_SUCCESS) { 2527c478bd9Sstevel@tonic-gate pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec)); 2537c478bd9Sstevel@tonic-gate pdptr->par_rng = (struct rangespec *)rng_prop; 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * Free ddi_parent_private_data structure 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate void 2617c478bd9Sstevel@tonic-gate impl_free_ddi_ppd(dev_info_t *dip) 2627c478bd9Sstevel@tonic-gate { 2637c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdptr = ddi_get_parent_data(dip); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (pdptr == NULL) 2667c478bd9Sstevel@tonic-gate return; 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate if (pdptr->par_nrng != 0) 2697c478bd9Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_rng); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate if (pdptr->par_nreg != 0) 2727c478bd9Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_reg); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate kmem_free(pdptr, sizeof (*pdptr)); 2757c478bd9Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Name a child of sun busses based on the reg spec. 2807c478bd9Sstevel@tonic-gate * Handles the following properties: 2817c478bd9Sstevel@tonic-gate * 2827c478bd9Sstevel@tonic-gate * Property value 2837c478bd9Sstevel@tonic-gate * Name type 2847c478bd9Sstevel@tonic-gate * 2857c478bd9Sstevel@tonic-gate * reg register spec 2867c478bd9Sstevel@tonic-gate * interrupts new (bus-oriented) interrupt spec 2877c478bd9Sstevel@tonic-gate * ranges range spec 2887c478bd9Sstevel@tonic-gate * 2897c478bd9Sstevel@tonic-gate * This may be called multiple times, independent of 2907c478bd9Sstevel@tonic-gate * initchild calls. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate static int 2937c478bd9Sstevel@tonic-gate impl_sunbus_name_child(dev_info_t *child, char *name, int namelen) 2947c478bd9Sstevel@tonic-gate { 2957c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 2967c478bd9Sstevel@tonic-gate struct regspec *rp; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * Fill in parent-private data and this function returns to us 3007c478bd9Sstevel@tonic-gate * an indication if it used "registers" to fill in the data. 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate if (ddi_get_parent_data(child) == NULL) { 3037c478bd9Sstevel@tonic-gate make_ddi_ppd(child, &pdptr); 3047c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * No reg property, return null string as address 3097c478bd9Sstevel@tonic-gate * (e.g. root node) 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate name[0] = '\0'; 3127c478bd9Sstevel@tonic-gate if (sparc_pd_getnreg(child) == 0) { 3137c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate rp = sparc_pd_getreg(child, 0); 3177c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 3187c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr); 3197c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * Called from the bus_ctl op of some drivers. 3257c478bd9Sstevel@tonic-gate * to implement the DDI_CTLOPS_INITCHILD operation. 3267c478bd9Sstevel@tonic-gate * 3277c478bd9Sstevel@tonic-gate * NEW drivers should NOT use this function, but should declare 3287c478bd9Sstevel@tonic-gate * there own initchild/uninitchild handlers. (This function assumes 3297c478bd9Sstevel@tonic-gate * the layout of the parent private data and the format of "reg", 3307c478bd9Sstevel@tonic-gate * "ranges", "interrupts" properties and that #address-cells and 3317c478bd9Sstevel@tonic-gate * #size-cells of the parent bus are defined to be default values.) 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate int 3347c478bd9Sstevel@tonic-gate impl_ddi_sunbus_initchild(dev_info_t *child) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate (void) impl_sunbus_name_child(child, name, MAXNAMELEN); 3397c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Try to merge .conf node. If successful, return failure to 3437c478bd9Sstevel@tonic-gate * remove this child. 3447c478bd9Sstevel@tonic-gate */ 3457c478bd9Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && 3467c478bd9Sstevel@tonic-gate (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) { 3477c478bd9Sstevel@tonic-gate impl_ddi_sunbus_removechild(child); 3487c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * A better name for this function would be impl_ddi_sunbus_uninitchild() 3557c478bd9Sstevel@tonic-gate * It does not remove the child, it uninitializes it, reclaiming the 3567c478bd9Sstevel@tonic-gate * resources taken by impl_ddi_sunbus_initchild. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate void 3597c478bd9Sstevel@tonic-gate impl_ddi_sunbus_removechild(dev_info_t *dip) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate impl_free_ddi_ppd(dip); 3627c478bd9Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 3637c478bd9Sstevel@tonic-gate /* 3647c478bd9Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate impl_rem_dev_props(dip); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * SECTION: DDI Interrupt 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate void 3747c478bd9Sstevel@tonic-gate cells_1275_copy(prop_1275_cell_t *from, prop_1275_cell_t *to, int32_t len) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate int i; 3777c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 3787c478bd9Sstevel@tonic-gate *to = *from; 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate prop_1275_cell_t * 3827c478bd9Sstevel@tonic-gate cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len) 3837c478bd9Sstevel@tonic-gate { 3847c478bd9Sstevel@tonic-gate prop_1275_cell_t *match_cell = 0; 3857c478bd9Sstevel@tonic-gate int32_t i; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 3887c478bd9Sstevel@tonic-gate if (cell1[i] != cell2[i]) { 3897c478bd9Sstevel@tonic-gate match_cell = &cell1[i]; 3907c478bd9Sstevel@tonic-gate break; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate return (match_cell); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 397a195726fSgovinda * get_intr_parent() is a generic routine that process a 1275 interrupt 398a195726fSgovinda * map (imap) property. This function returns a dev_info_t structure 399a195726fSgovinda * which claims ownership of the interrupt domain. 400a195726fSgovinda * It also returns the new interrupt translation within this new domain. 401a195726fSgovinda * If an interrupt-parent or interrupt-map property are not found, 402a195726fSgovinda * then we fallback to using the device tree's parent. 403a195726fSgovinda * 404a195726fSgovinda * imap entry format: 405a195726fSgovinda * <reg>,<interrupt>,<phandle>,<translated interrupt> 406a195726fSgovinda * reg - The register specification in the interrupts domain 407a195726fSgovinda * interrupt - The interrupt specification 408a195726fSgovinda * phandle - PROM handle of the device that owns the xlated interrupt domain 409a195726fSgovinda * translated interrupt - interrupt specifier in the parents domain 410a195726fSgovinda * note: <reg>,<interrupt> - The reg and interrupt can be combined to create 411a195726fSgovinda * a unique entry called a unit interrupt specifier. 412a195726fSgovinda * 413a195726fSgovinda * Here's the processing steps: 414a195726fSgovinda * step1 - If the interrupt-parent property exists, create the ispec and 415a195726fSgovinda * return the dip of the interrupt parent. 416a195726fSgovinda * step2 - Extract the interrupt-map property and the interrupt-map-mask 417a195726fSgovinda * If these don't exist, just return the device tree parent. 418a195726fSgovinda * step3 - build up the unit interrupt specifier to match against the 419a195726fSgovinda * interrupt map property 420a195726fSgovinda * step4 - Scan the interrupt-map property until a match is found 421a195726fSgovinda * step4a - Extract the interrupt parent 422a195726fSgovinda * step4b - Compare the unit interrupt specifier 4237c478bd9Sstevel@tonic-gate */ 424a195726fSgovinda dev_info_t * 425a195726fSgovinda get_intr_parent(dev_info_t *pdip, dev_info_t *dip, ddi_intr_handle_impl_t *hdlp) 4267c478bd9Sstevel@tonic-gate { 427a195726fSgovinda prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req; 428a195726fSgovinda int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz, 429a195726fSgovinda addr_cells, intr_cells, reg_len, i, j; 430a195726fSgovinda int32_t match_found = 0; 431a195726fSgovinda dev_info_t *intr_parent_dip = NULL; 432a195726fSgovinda uint32_t *intr = &hdlp->ih_vector; 433a195726fSgovinda uint32_t nodeid; 434a195726fSgovinda #ifdef DEBUG 435a195726fSgovinda static int debug = 0; 436a195726fSgovinda #endif 4377c478bd9Sstevel@tonic-gate 438a195726fSgovinda /* 439a195726fSgovinda * step1 440a195726fSgovinda * If we have an interrupt-parent property, this property represents 441a195726fSgovinda * the nodeid of our interrupt parent. 442a195726fSgovinda */ 443a195726fSgovinda if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 444a195726fSgovinda "interrupt-parent", -1)) != -1) { 445a195726fSgovinda intr_parent_dip = e_ddi_nodeid_to_dip(nodeid); 446a195726fSgovinda ASSERT(intr_parent_dip); 4477c478bd9Sstevel@tonic-gate 448a195726fSgovinda /* 449a195726fSgovinda * Attach the interrupt parent. 450a195726fSgovinda * 451a195726fSgovinda * N.B. e_ddi_nodeid_to_dip() isn't safe under DR. 452a195726fSgovinda * Also, interrupt parent isn't held. This needs 453a195726fSgovinda * to be revisited if DR-capable platforms implement 454a195726fSgovinda * interrupt redirection. 455a195726fSgovinda */ 456a195726fSgovinda if (i_ddi_attach_node_hierarchy(intr_parent_dip) 457a195726fSgovinda != DDI_SUCCESS) { 458a195726fSgovinda ndi_rele_devi(intr_parent_dip); 459a195726fSgovinda return (NULL); 460a195726fSgovinda } 4617c478bd9Sstevel@tonic-gate 462a195726fSgovinda return (intr_parent_dip); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 466a195726fSgovinda * step2 467a195726fSgovinda * Get interrupt map structure from PROM property 4687c478bd9Sstevel@tonic-gate */ 469a195726fSgovinda if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 470a195726fSgovinda "interrupt-map", (caddr_t)&imap, &imap_sz) 471a195726fSgovinda != DDI_PROP_SUCCESS) { 472a195726fSgovinda /* 473a195726fSgovinda * If we don't have an imap property, default to using the 474a195726fSgovinda * device tree. 475a195726fSgovinda */ 4767c478bd9Sstevel@tonic-gate 477a195726fSgovinda ndi_hold_devi(pdip); 478a195726fSgovinda return (pdip); 479a195726fSgovinda } 4807c478bd9Sstevel@tonic-gate 481a195726fSgovinda /* Get the interrupt mask property */ 482a195726fSgovinda if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 483a195726fSgovinda "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz) 484a195726fSgovinda != DDI_PROP_SUCCESS) { 485a195726fSgovinda /* 486a195726fSgovinda * If we don't find this property, we have to fail the request 487a195726fSgovinda * because the 1275 imap property wasn't defined correctly. 488a195726fSgovinda */ 489a195726fSgovinda ASSERT(intr_parent_dip == NULL); 490a195726fSgovinda goto exit2; 491a195726fSgovinda } 492a195726fSgovinda 493a195726fSgovinda /* Get the address cell size */ 494a195726fSgovinda addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 495a195726fSgovinda "#address-cells", 2); 496a195726fSgovinda 497a195726fSgovinda /* Get the interrupts cell size */ 498a195726fSgovinda intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 499a195726fSgovinda "#interrupt-cells", 1); 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 502a195726fSgovinda * step3 503a195726fSgovinda * Now lets build up the unit interrupt specifier e.g. reg,intr 504a195726fSgovinda * and apply the imap mask. match_req will hold this when we're 505a195726fSgovinda * through. 5067c478bd9Sstevel@tonic-gate */ 507a195726fSgovinda if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 508a195726fSgovinda (caddr_t)®_p, ®_len) != DDI_SUCCESS) { 509a195726fSgovinda ASSERT(intr_parent_dip == NULL); 510a195726fSgovinda goto exit3; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 513a195726fSgovinda match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) + 514a195726fSgovinda CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP); 5157c478bd9Sstevel@tonic-gate 516a195726fSgovinda for (i = 0; i < addr_cells; i++) 517a195726fSgovinda match_req[i] = (reg_p[i] & imap_mask[i]); 5187c478bd9Sstevel@tonic-gate 519a195726fSgovinda for (j = 0; j < intr_cells; i++, j++) 520a195726fSgovinda match_req[i] = (intr[j] & imap_mask[i]); 5217c478bd9Sstevel@tonic-gate 522a195726fSgovinda /* Calculate the imap size in cells */ 523a195726fSgovinda imap_cells = BYTES_TO_1275_CELLS(imap_sz); 524a195726fSgovinda 525a195726fSgovinda #ifdef DEBUG 526a195726fSgovinda if (debug) 527a195726fSgovinda prom_printf("reg cell size 0x%x, intr cell size 0x%x, " 528a195726fSgovinda "match_request 0x%p, imap 0x%p\n", addr_cells, intr_cells, 529903a11ebSrh87107 (void *)match_req, (void *)imap); 530a195726fSgovinda #endif 531a195726fSgovinda 532a195726fSgovinda /* 533a195726fSgovinda * Scan the imap property looking for a match of the interrupt unit 534a195726fSgovinda * specifier. This loop is rather complex since the data within the 535a195726fSgovinda * imap property may vary in size. 536a195726fSgovinda */ 537a195726fSgovinda for (scan = imap, imap_scan_cells = i = 0; 538a195726fSgovinda imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) { 539a195726fSgovinda int new_intr_cells; 540a195726fSgovinda 541a195726fSgovinda /* Set the index to the nodeid field */ 542a195726fSgovinda i = addr_cells + intr_cells; 543a195726fSgovinda 544a195726fSgovinda /* 545a195726fSgovinda * step4a 546a195726fSgovinda * Translate the nodeid field to a dip 547a195726fSgovinda */ 548a195726fSgovinda ASSERT(intr_parent_dip == NULL); 549a195726fSgovinda intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]); 550a195726fSgovinda 551a195726fSgovinda ASSERT(intr_parent_dip != 0); 552a195726fSgovinda #ifdef DEBUG 553a195726fSgovinda if (debug) 554903a11ebSrh87107 prom_printf("scan 0x%p\n", (void *)scan); 555a195726fSgovinda #endif 556a195726fSgovinda /* 557a195726fSgovinda * The tmp_dip describes the new domain, get it's interrupt 558a195726fSgovinda * cell size 559a195726fSgovinda */ 560a195726fSgovinda new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0, 561a195726fSgovinda "#interrupts-cells", 1); 562a195726fSgovinda 563a195726fSgovinda /* 564a195726fSgovinda * step4b 565a195726fSgovinda * See if we have a match on the interrupt unit specifier 566a195726fSgovinda */ 567a195726fSgovinda if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells) 568a195726fSgovinda == 0) { 569a195726fSgovinda uint32_t *intr; 570a195726fSgovinda 571a195726fSgovinda match_found = 1; 572a195726fSgovinda 573a195726fSgovinda /* 574a195726fSgovinda * If we have an imap parent whose not in our device 575a195726fSgovinda * tree path, we need to hold and install that driver. 576a195726fSgovinda */ 577a195726fSgovinda if (i_ddi_attach_node_hierarchy(intr_parent_dip) 578a195726fSgovinda != DDI_SUCCESS) { 579a195726fSgovinda ndi_rele_devi(intr_parent_dip); 580a195726fSgovinda intr_parent_dip = (dev_info_t *)NULL; 581a195726fSgovinda goto exit4; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 584a195726fSgovinda /* 585a195726fSgovinda * We need to handcraft an ispec along with a bus 586a195726fSgovinda * interrupt value, so we can dup it into our 587a195726fSgovinda * standard ispec structure. 588a195726fSgovinda */ 589a195726fSgovinda /* Extract the translated interrupt information */ 590a195726fSgovinda intr = kmem_alloc( 591a195726fSgovinda CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP); 592a195726fSgovinda 593a195726fSgovinda for (j = 0; j < new_intr_cells; j++, i++) 594a195726fSgovinda intr[j] = scan[i]; 595a195726fSgovinda 596a195726fSgovinda cells_1275_copy(intr, &hdlp->ih_vector, new_intr_cells); 597a195726fSgovinda 598a195726fSgovinda kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells)); 599a195726fSgovinda 600a195726fSgovinda #ifdef DEBUG 601a195726fSgovinda if (debug) 602903a11ebSrh87107 prom_printf("dip 0x%p\n", 603903a11ebSrh87107 (void *)intr_parent_dip); 604a195726fSgovinda #endif 605a195726fSgovinda break; 606a195726fSgovinda } else { 607a195726fSgovinda #ifdef DEBUG 608a195726fSgovinda if (debug) 609903a11ebSrh87107 prom_printf("dip 0x%p\n", 610903a11ebSrh87107 (void *)intr_parent_dip); 611a195726fSgovinda #endif 612a195726fSgovinda ndi_rele_devi(intr_parent_dip); 613a195726fSgovinda intr_parent_dip = NULL; 614a195726fSgovinda i += new_intr_cells; 615a195726fSgovinda } 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 618a195726fSgovinda /* 619a195726fSgovinda * If we haven't found our interrupt parent at this point, fallback 620a195726fSgovinda * to using the device tree. 621a195726fSgovinda */ 622a195726fSgovinda if (!match_found) { 623a195726fSgovinda ndi_hold_devi(pdip); 624a195726fSgovinda ASSERT(intr_parent_dip == NULL); 625a195726fSgovinda intr_parent_dip = pdip; 626a195726fSgovinda } 627a195726fSgovinda 628a195726fSgovinda ASSERT(intr_parent_dip != NULL); 629a195726fSgovinda 630a195726fSgovinda exit4: 631a195726fSgovinda kmem_free(reg_p, reg_len); 632a195726fSgovinda kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) + 633a195726fSgovinda CELLS_1275_TO_BYTES(intr_cells)); 634a195726fSgovinda 635a195726fSgovinda exit3: 636a195726fSgovinda kmem_free(imap_mask, imap_mask_sz); 637a195726fSgovinda 638a195726fSgovinda exit2: 639a195726fSgovinda kmem_free(imap, imap_sz); 640a195726fSgovinda 641a195726fSgovinda return (intr_parent_dip); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * process_intr_ops: 6467c478bd9Sstevel@tonic-gate * 6477c478bd9Sstevel@tonic-gate * Process the interrupt op via the interrupt parent. 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate int 6507c478bd9Sstevel@tonic-gate process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op, 6517c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 6527c478bd9Sstevel@tonic-gate { 6537c478bd9Sstevel@tonic-gate int ret = DDI_FAILURE; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate if (NEXUS_HAS_INTR_OP(pdip)) { 6567c478bd9Sstevel@tonic-gate ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops-> 6577c478bd9Sstevel@tonic-gate bus_intr_op)) (pdip, rdip, op, hdlp, result); 6587c478bd9Sstevel@tonic-gate } else { 6597c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Failed to process interrupt " 6607c478bd9Sstevel@tonic-gate "for %s%d due to down-rev nexus driver %s%d", 6617c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 6627c478bd9Sstevel@tonic-gate ddi_get_name(pdip), ddi_get_instance(pdip)); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate return (ret); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 668a195726fSgovinda /*ARGSUSED*/ 669a195726fSgovinda uint_t 670a195726fSgovinda softlevel1(caddr_t arg) 671a195726fSgovinda { 672a195726fSgovinda softint(); 673a195726fSgovinda return (1); 674a195726fSgovinda } 675a195726fSgovinda 676a195726fSgovinda /* 677a195726fSgovinda * indirection table, to save us some large switch statements 678a195726fSgovinda * NOTE: This must agree with "INTLEVEL_foo" constants in 679a195726fSgovinda * <sys/avintr.h> 680a195726fSgovinda */ 681a195726fSgovinda struct autovec *const vectorlist[] = { 0 }; 682a195726fSgovinda 683a195726fSgovinda /* 684a195726fSgovinda * This value is exported here for the functions in avintr.c 685a195726fSgovinda */ 686a195726fSgovinda const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0])); 687a195726fSgovinda 688a195726fSgovinda /* 689a195726fSgovinda * Check for machine specific interrupt levels which cannot be reassigned by 690a195726fSgovinda * settrap(), sun4u version. 691a195726fSgovinda * 692a195726fSgovinda * sun4u does not support V8 SPARC "fast trap" handlers. 693a195726fSgovinda */ 694a195726fSgovinda /*ARGSUSED*/ 695a195726fSgovinda int 696a195726fSgovinda exclude_settrap(int lvl) 697a195726fSgovinda { 698a195726fSgovinda return (1); 699a195726fSgovinda } 700a195726fSgovinda 701a195726fSgovinda /* 702a195726fSgovinda * Check for machine specific interrupt levels which cannot have interrupt 703a195726fSgovinda * handlers added. We allow levels 1 through 15; level 0 is nonsense. 704a195726fSgovinda */ 705a195726fSgovinda /*ARGSUSED*/ 706a195726fSgovinda int 707a195726fSgovinda exclude_level(int lvl) 708a195726fSgovinda { 709a195726fSgovinda return ((lvl < 1) || (lvl > 15)); 710a195726fSgovinda } 711a195726fSgovinda 712a195726fSgovinda /* 713a195726fSgovinda * Wrapper functions used by New DDI interrupt framework. 714a195726fSgovinda */ 715a195726fSgovinda 716a195726fSgovinda /* 717a195726fSgovinda * i_ddi_intr_ops: 718a195726fSgovinda */ 719a195726fSgovinda int 720a195726fSgovinda i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 721a195726fSgovinda ddi_intr_handle_impl_t *hdlp, void *result) 722a195726fSgovinda { 723a195726fSgovinda dev_info_t *pdip = ddi_get_parent(dip); 724a195726fSgovinda int ret = DDI_FAILURE; 725a195726fSgovinda 726a195726fSgovinda /* 727a195726fSgovinda * The following check is required to address 728a195726fSgovinda * one of the test case of ADDI test suite. 729a195726fSgovinda */ 730a195726fSgovinda if (pdip == NULL) 731a195726fSgovinda return (DDI_FAILURE); 732a195726fSgovinda 733a195726fSgovinda if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 734a195726fSgovinda return (process_intr_ops(pdip, rdip, op, hdlp, result)); 735a195726fSgovinda 736a195726fSgovinda if (hdlp->ih_vector == 0) 737a195726fSgovinda hdlp->ih_vector = i_ddi_get_inum(rdip, hdlp->ih_inum); 738a195726fSgovinda 739a195726fSgovinda if (hdlp->ih_pri == 0) 740a195726fSgovinda hdlp->ih_pri = i_ddi_get_intr_pri(rdip, hdlp->ih_inum); 741a195726fSgovinda 742a195726fSgovinda switch (op) { 743a195726fSgovinda case DDI_INTROP_ADDISR: 744a195726fSgovinda case DDI_INTROP_REMISR: 74509b1eac2SEvan Yan case DDI_INTROP_GETTARGET: 74609b1eac2SEvan Yan case DDI_INTROP_SETTARGET: 747a195726fSgovinda case DDI_INTROP_ENABLE: 748a195726fSgovinda case DDI_INTROP_DISABLE: 749a195726fSgovinda case DDI_INTROP_BLOCKENABLE: 750a195726fSgovinda case DDI_INTROP_BLOCKDISABLE: 751a195726fSgovinda /* 752a195726fSgovinda * Try and determine our parent and possibly an interrupt 753a195726fSgovinda * translation. intr parent dip returned held 754a195726fSgovinda */ 755a195726fSgovinda if ((pdip = get_intr_parent(pdip, dip, hdlp)) == NULL) 756a195726fSgovinda goto done; 757a195726fSgovinda } 758a195726fSgovinda 759a195726fSgovinda ret = process_intr_ops(pdip, rdip, op, hdlp, result); 760a195726fSgovinda 761a195726fSgovinda done: 762a195726fSgovinda switch (op) { 763a195726fSgovinda case DDI_INTROP_ADDISR: 764a195726fSgovinda case DDI_INTROP_REMISR: 765a195726fSgovinda case DDI_INTROP_ENABLE: 766a195726fSgovinda case DDI_INTROP_DISABLE: 767a195726fSgovinda case DDI_INTROP_BLOCKENABLE: 768a195726fSgovinda case DDI_INTROP_BLOCKDISABLE: 769a195726fSgovinda /* Release hold acquired in get_intr_parent() */ 770a195726fSgovinda if (pdip) 771a195726fSgovinda ndi_rele_devi(pdip); 772a195726fSgovinda } 773a195726fSgovinda 774a195726fSgovinda hdlp->ih_vector = 0; 775a195726fSgovinda 776a195726fSgovinda return (ret); 777a195726fSgovinda } 778a195726fSgovinda 7797c478bd9Sstevel@tonic-gate /* 7807c478bd9Sstevel@tonic-gate * i_ddi_add_ivintr: 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7837c478bd9Sstevel@tonic-gate int 7847c478bd9Sstevel@tonic-gate i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp) 7857c478bd9Sstevel@tonic-gate { 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * If the PIL was set and is valid use it, otherwise 7887c478bd9Sstevel@tonic-gate * default it to 1 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX)) 7917c478bd9Sstevel@tonic-gate hdlp->ih_pri = 1; 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri, 794b0fc0e77Sgovinda (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1, 795b0fc0e77Sgovinda hdlp->ih_cb_arg2, NULL) == 0); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * i_ddi_rem_ivintr: 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8047c478bd9Sstevel@tonic-gate void 8057c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp) 8067c478bd9Sstevel@tonic-gate { 807b0fc0e77Sgovinda VERIFY(rem_ivintr(hdlp->ih_vector, hdlp->ih_pri) == 0); 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate /* 811a195726fSgovinda * i_ddi_get_inum - Get the interrupt number property from the 812a195726fSgovinda * specified device. Note that this function is called only for 813a195726fSgovinda * the FIXED interrupt type. 814a195726fSgovinda */ 815a195726fSgovinda uint32_t 816a195726fSgovinda i_ddi_get_inum(dev_info_t *dip, uint_t inumber) 817a195726fSgovinda { 818a195726fSgovinda int32_t intrlen, intr_cells, max_intrs; 819a195726fSgovinda prop_1275_cell_t *ip, intr_sz; 820a195726fSgovinda uint32_t intr = 0; 821a195726fSgovinda 822a195726fSgovinda if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | 823a195726fSgovinda DDI_PROP_CANSLEEP, 824a195726fSgovinda "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 825a195726fSgovinda 826a195726fSgovinda intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 827a195726fSgovinda "#interrupt-cells", 1); 828a195726fSgovinda 829a195726fSgovinda /* adjust for number of bytes */ 830a195726fSgovinda intr_sz = CELLS_1275_TO_BYTES(intr_cells); 831a195726fSgovinda 832a195726fSgovinda /* Calculate the number of interrupts */ 833a195726fSgovinda max_intrs = intrlen / intr_sz; 834a195726fSgovinda 835a195726fSgovinda if (inumber < max_intrs) { 836a195726fSgovinda prop_1275_cell_t *intrp = ip; 837a195726fSgovinda 838a195726fSgovinda /* Index into interrupt property */ 839a195726fSgovinda intrp += (inumber * intr_cells); 840a195726fSgovinda 841a195726fSgovinda cells_1275_copy(intrp, &intr, intr_cells); 842a195726fSgovinda } 843a195726fSgovinda 844a195726fSgovinda kmem_free(ip, intrlen); 845a195726fSgovinda } 846a195726fSgovinda 847a195726fSgovinda return (intr); 848a195726fSgovinda } 849a195726fSgovinda 850a195726fSgovinda /* 851a195726fSgovinda * i_ddi_get_intr_pri - Get the interrupt-priorities property from 852a195726fSgovinda * the specified device. Note that this function is called only for 853a195726fSgovinda * the FIXED interrupt type. 854a195726fSgovinda */ 855a195726fSgovinda uint32_t 856a195726fSgovinda i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber) 857a195726fSgovinda { 858a195726fSgovinda uint32_t *intr_prio_p; 859a195726fSgovinda uint32_t pri = 0; 860a195726fSgovinda int32_t i; 861a195726fSgovinda 862a195726fSgovinda /* 863a195726fSgovinda * Use the "interrupt-priorities" property to determine the 864a195726fSgovinda * the pil/ipl for the interrupt handler. 865a195726fSgovinda */ 866a195726fSgovinda if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 867a195726fSgovinda "interrupt-priorities", (caddr_t)&intr_prio_p, 868a195726fSgovinda &i) == DDI_SUCCESS) { 869a195726fSgovinda if (inumber < (i / sizeof (int32_t))) 870a195726fSgovinda pri = intr_prio_p[inumber]; 871a195726fSgovinda kmem_free(intr_prio_p, i); 872a195726fSgovinda } 873a195726fSgovinda 874a195726fSgovinda return (pri); 875a195726fSgovinda } 876a195726fSgovinda 877a195726fSgovinda int 878a54f81fbSanish i_ddi_get_intx_nintrs(dev_info_t *dip) 879a195726fSgovinda { 880a195726fSgovinda int32_t intrlen; 881a195726fSgovinda prop_1275_cell_t intr_sz; 882a195726fSgovinda prop_1275_cell_t *ip; 883a195726fSgovinda int32_t ret = 0; 884a195726fSgovinda 885a195726fSgovinda if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | 886a195726fSgovinda DDI_PROP_CANSLEEP, 887a195726fSgovinda "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 888a195726fSgovinda 889a195726fSgovinda intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 890a195726fSgovinda "#interrupt-cells", 1); 891a195726fSgovinda /* adjust for number of bytes */ 892a195726fSgovinda intr_sz = CELLS_1275_TO_BYTES(intr_sz); 893a195726fSgovinda 894a195726fSgovinda ret = intrlen / intr_sz; 895a195726fSgovinda 896a195726fSgovinda kmem_free(ip, intrlen); 897a195726fSgovinda } 898a195726fSgovinda 899a195726fSgovinda return (ret); 900a195726fSgovinda } 901a195726fSgovinda 902a195726fSgovinda /* 903b0fc0e77Sgovinda * i_ddi_add_softint - allocate and add a software interrupt. 904b0fc0e77Sgovinda * 905b0fc0e77Sgovinda * NOTE: All software interrupts that are registered through DDI 906b0fc0e77Sgovinda * should be triggered only on a single target or CPU. 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate int 9097c478bd9Sstevel@tonic-gate i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp) 9107c478bd9Sstevel@tonic-gate { 911b0fc0e77Sgovinda if ((hdlp->ih_private = (void *)add_softintr(hdlp->ih_pri, 912b0fc0e77Sgovinda hdlp->ih_cb_func, hdlp->ih_cb_arg1, SOFTINT_ST)) == NULL) 9137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 918b0fc0e77Sgovinda /* 919b0fc0e77Sgovinda * i_ddi_remove_softint - remove and free a software interrupt. 920b0fc0e77Sgovinda */ 9217c478bd9Sstevel@tonic-gate void 9227c478bd9Sstevel@tonic-gate i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp) 9237c478bd9Sstevel@tonic-gate { 9247c478bd9Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 925a195726fSgovinda 926b0fc0e77Sgovinda if (rem_softintr((uint64_t)hdlp->ih_private) == 0) 9277c478bd9Sstevel@tonic-gate hdlp->ih_private = NULL; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 930b0fc0e77Sgovinda /* 931b0fc0e77Sgovinda * i_ddi_trigger_softint - trigger a software interrupt. 932b0fc0e77Sgovinda */ 9337c478bd9Sstevel@tonic-gate int 934b08160e2Sgovinda i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2) 9357c478bd9Sstevel@tonic-gate { 9367c478bd9Sstevel@tonic-gate int ret; 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 9397c478bd9Sstevel@tonic-gate 940b0fc0e77Sgovinda /* Update the second argument for the software interrupt */ 941b0fc0e77Sgovinda if ((ret = update_softint_arg2((uint64_t)hdlp->ih_private, arg2)) == 0) 942b0fc0e77Sgovinda setsoftint((uint64_t)hdlp->ih_private); 9437c478bd9Sstevel@tonic-gate 944b0fc0e77Sgovinda return (ret ? DDI_EPENDING : DDI_SUCCESS); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 947b0fc0e77Sgovinda /* 948b0fc0e77Sgovinda * i_ddi_set_softint_pri - change software interrupt priority. 949b0fc0e77Sgovinda */ 9507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9517c478bd9Sstevel@tonic-gate int 9527c478bd9Sstevel@tonic-gate i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri) 9537c478bd9Sstevel@tonic-gate { 9547c478bd9Sstevel@tonic-gate int ret; 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 9577c478bd9Sstevel@tonic-gate 958b0fc0e77Sgovinda /* Update the interrupt priority for the software interrupt */ 959b0fc0e77Sgovinda ret = update_softint_pri((uint64_t)hdlp->ih_private, hdlp->ih_pri); 9607c478bd9Sstevel@tonic-gate 961b0fc0e77Sgovinda return (ret ? DDI_FAILURE : DDI_SUCCESS); 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate 9647a364d25Sschwartz /*ARGSUSED*/ 9657a364d25Sschwartz void 9667a364d25Sschwartz i_ddi_alloc_intr_phdl(ddi_intr_handle_impl_t *hdlp) 9677a364d25Sschwartz { 9687a364d25Sschwartz } 9697a364d25Sschwartz 9707a364d25Sschwartz /*ARGSUSED*/ 9717a364d25Sschwartz void 9727a364d25Sschwartz i_ddi_free_intr_phdl(ddi_intr_handle_impl_t *hdlp) 9737a364d25Sschwartz { 9747a364d25Sschwartz } 9757a364d25Sschwartz 9767c478bd9Sstevel@tonic-gate /* 9777c478bd9Sstevel@tonic-gate * SECTION: DDI Memory/DMA 9787c478bd9Sstevel@tonic-gate */ 9797c478bd9Sstevel@tonic-gate 9807b93957cSeota /* set HAT endianess attributes from ddi_device_acc_attr */ 9817b93957cSeota void 9827b93957cSeota i_ddi_devacc_to_hatacc(ddi_device_acc_attr_t *devaccp, uint_t *hataccp) 9837b93957cSeota { 9847b93957cSeota if (devaccp != NULL) { 9857b93957cSeota if (devaccp->devacc_attr_endian_flags == DDI_STRUCTURE_LE_ACC) { 9867b93957cSeota *hataccp &= ~HAT_ENDIAN_MASK; 9877b93957cSeota *hataccp |= HAT_STRUCTURE_LE; 9887b93957cSeota } 9897b93957cSeota } 9907b93957cSeota } 9917b93957cSeota 9927b93957cSeota /* 9937b93957cSeota * Check if the specified cache attribute is supported on the platform. 9947b93957cSeota * This function must be called before i_ddi_cacheattr_to_hatacc(). 9957b93957cSeota */ 9967b93957cSeota boolean_t 9977b93957cSeota i_ddi_check_cache_attr(uint_t flags) 9987b93957cSeota { 9997b93957cSeota /* 10007b93957cSeota * The cache attributes are mutually exclusive. Any combination of 10017b93957cSeota * the attributes leads to a failure. 10027b93957cSeota */ 10037b93957cSeota uint_t cache_attr = IOMEM_CACHE_ATTR(flags); 1004*de710d24SJosef 'Jeff' Sipek if ((cache_attr != 0) && !ISP2(cache_attr)) 10057b93957cSeota return (B_FALSE); 10067b93957cSeota 10077b93957cSeota /* 10087b93957cSeota * On the sparc architecture, only IOMEM_DATA_CACHED is meaningful, 10097b93957cSeota * but others lead to a failure. 10107b93957cSeota */ 10117b93957cSeota if (cache_attr & IOMEM_DATA_CACHED) 10127b93957cSeota return (B_TRUE); 10137b93957cSeota else 10147b93957cSeota return (B_FALSE); 10157b93957cSeota } 10167b93957cSeota 10177b93957cSeota /* set HAT cache attributes from the cache attributes */ 10187b93957cSeota void 10197b93957cSeota i_ddi_cacheattr_to_hatacc(uint_t flags, uint_t *hataccp) 10207b93957cSeota { 10217b93957cSeota uint_t cache_attr = IOMEM_CACHE_ATTR(flags); 10227b93957cSeota static char *fname = "i_ddi_cacheattr_to_hatacc"; 10237b93957cSeota #if defined(lint) 10247b93957cSeota *hataccp = *hataccp; 10257b93957cSeota #endif 10267b93957cSeota /* 10277b93957cSeota * set HAT attrs according to the cache attrs. 10287b93957cSeota */ 10297b93957cSeota switch (cache_attr) { 10307b93957cSeota /* 10317b93957cSeota * The cache coherency is always maintained on SPARC, and 10327b93957cSeota * nothing is required. 10337b93957cSeota */ 10347b93957cSeota case IOMEM_DATA_CACHED: 10357b93957cSeota break; 10367b93957cSeota /* 10377b93957cSeota * Both IOMEM_DATA_UC_WRITE_COMBINED and IOMEM_DATA_UNCACHED are 10387b93957cSeota * not supported on SPARC -- this case must not occur because the 10397b93957cSeota * cache attribute is scrutinized before this function is called. 10407b93957cSeota */ 10417b93957cSeota case IOMEM_DATA_UNCACHED: 10427b93957cSeota case IOMEM_DATA_UC_WR_COMBINE: 10437b93957cSeota default: 10447b93957cSeota cmn_err(CE_WARN, "%s: cache_attr=0x%x is ignored.", 10457b93957cSeota fname, cache_attr); 10467b93957cSeota } 10477b93957cSeota } 10487b93957cSeota 10497c478bd9Sstevel@tonic-gate static vmem_t *little_endian_arena; 10507c478bd9Sstevel@tonic-gate static vmem_t *big_endian_arena; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate static void * 10537c478bd9Sstevel@tonic-gate segkmem_alloc_le(vmem_t *vmp, size_t size, int flag) 10547c478bd9Sstevel@tonic-gate { 10557c478bd9Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE, 10567c478bd9Sstevel@tonic-gate segkmem_page_create, NULL)); 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate static void * 10607c478bd9Sstevel@tonic-gate segkmem_alloc_be(vmem_t *vmp, size_t size, int flag) 10617c478bd9Sstevel@tonic-gate { 10627c478bd9Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE, 10637c478bd9Sstevel@tonic-gate segkmem_page_create, NULL)); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate void 10677c478bd9Sstevel@tonic-gate ka_init(void) 10687c478bd9Sstevel@tonic-gate { 10697c478bd9Sstevel@tonic-gate little_endian_arena = vmem_create("little_endian", NULL, 0, 1, 10707c478bd9Sstevel@tonic-gate segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP); 10717c478bd9Sstevel@tonic-gate big_endian_arena = vmem_create("big_endian", NULL, 0, 1, 10727c478bd9Sstevel@tonic-gate segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * Allocate from the system, aligned on a specific boundary. 10777c478bd9Sstevel@tonic-gate * The alignment, if non-zero, must be a power of 2. 10787c478bd9Sstevel@tonic-gate */ 10797c478bd9Sstevel@tonic-gate static void * 10807c478bd9Sstevel@tonic-gate kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags) 10817c478bd9Sstevel@tonic-gate { 10827c478bd9Sstevel@tonic-gate size_t *addr, *raddr, rsize; 10837c478bd9Sstevel@tonic-gate size_t hdrsize = 4 * sizeof (size_t); /* must be power of 2 */ 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate align = MAX(align, hdrsize); 10867c478bd9Sstevel@tonic-gate ASSERT((align & (align - 1)) == 0); 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * We need to allocate 10907c478bd9Sstevel@tonic-gate * rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment) 10917c478bd9Sstevel@tonic-gate * bytes to be sure we have enough freedom to satisfy the request. 10927c478bd9Sstevel@tonic-gate * Since the buffer alignment depends on the request size, this is 10937c478bd9Sstevel@tonic-gate * not straightforward to use directly. 10947c478bd9Sstevel@tonic-gate * 10957c478bd9Sstevel@tonic-gate * kmem guarantees that any allocation of a 64-byte multiple will be 10967c478bd9Sstevel@tonic-gate * 64-byte aligned. Since rounding up the request could add more 10977c478bd9Sstevel@tonic-gate * than we save, we compute the size with and without alignment, and 10987c478bd9Sstevel@tonic-gate * use the smaller of the two. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate rsize = size + hdrsize + align; 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate if (endian_flags == DDI_STRUCTURE_LE_ACC) { 11037c478bd9Sstevel@tonic-gate raddr = vmem_alloc(little_endian_arena, rsize, 11047c478bd9Sstevel@tonic-gate cansleep ? VM_SLEEP : VM_NOSLEEP); 11057c478bd9Sstevel@tonic-gate } else { 11067c478bd9Sstevel@tonic-gate raddr = vmem_alloc(big_endian_arena, rsize, 11077c478bd9Sstevel@tonic-gate cansleep ? VM_SLEEP : VM_NOSLEEP); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate if (raddr == NULL) 11117c478bd9Sstevel@tonic-gate return (NULL); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align); 11147c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate addr[-3] = (size_t)endian_flags; 11177c478bd9Sstevel@tonic-gate addr[-2] = (size_t)raddr; 11187c478bd9Sstevel@tonic-gate addr[-1] = rsize; 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate return (addr); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate static void 11247c478bd9Sstevel@tonic-gate kfreea(void *addr) 11257c478bd9Sstevel@tonic-gate { 11267c478bd9Sstevel@tonic-gate size_t *saddr = addr; 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate if (saddr[-3] == DDI_STRUCTURE_LE_ACC) 11297c478bd9Sstevel@tonic-gate vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]); 11307c478bd9Sstevel@tonic-gate else 11317c478bd9Sstevel@tonic-gate vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 1134b89e420aSGarrett D'Amore /* 1135b89e420aSGarrett D'Amore * This used to be ddi_iomin, but we were the only remaining caller, so 1136b89e420aSGarrett D'Amore * we've made it private and moved it here. 1137b89e420aSGarrett D'Amore */ 1138b89e420aSGarrett D'Amore static int 1139b89e420aSGarrett D'Amore i_ddi_iomin(dev_info_t *a, int i, int stream) 1140b89e420aSGarrett D'Amore { 1141b89e420aSGarrett D'Amore int r; 1142b89e420aSGarrett D'Amore 1143b89e420aSGarrett D'Amore /* 1144b89e420aSGarrett D'Amore * Make sure that the initial value is sane 1145b89e420aSGarrett D'Amore */ 1146*de710d24SJosef 'Jeff' Sipek if (!ISP2(i)) 1147b89e420aSGarrett D'Amore return (0); 1148b89e420aSGarrett D'Amore if (i == 0) 1149b89e420aSGarrett D'Amore i = (stream) ? 4 : 1; 1150b89e420aSGarrett D'Amore 1151b89e420aSGarrett D'Amore r = ddi_ctlops(a, a, 1152b89e420aSGarrett D'Amore DDI_CTLOPS_IOMIN, (void *)(uintptr_t)stream, (void *)&i); 1153*de710d24SJosef 'Jeff' Sipek if (r != DDI_SUCCESS || !ISP2(i)) 1154b89e420aSGarrett D'Amore return (0); 1155b89e420aSGarrett D'Amore return (i); 1156b89e420aSGarrett D'Amore } 1157b89e420aSGarrett D'Amore 11587c478bd9Sstevel@tonic-gate int 11597c478bd9Sstevel@tonic-gate i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr, 11607b93957cSeota size_t length, int cansleep, int flags, 11617c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t *accattrp, 11627c478bd9Sstevel@tonic-gate caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep) 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate caddr_t a; 11657b93957cSeota int iomin, align, streaming; 11667c478bd9Sstevel@tonic-gate uint_t endian_flags = DDI_NEVERSWAP_ACC; 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate #if defined(lint) 11697c478bd9Sstevel@tonic-gate *handlep = *handlep; 11707c478bd9Sstevel@tonic-gate #endif 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate /* 11737c478bd9Sstevel@tonic-gate * Check legality of arguments 11747c478bd9Sstevel@tonic-gate */ 11757c478bd9Sstevel@tonic-gate if (length == 0 || kaddrp == NULL || attr == NULL) { 11767c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11777c478bd9Sstevel@tonic-gate } 11787b93957cSeota 11797c478bd9Sstevel@tonic-gate if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 || 1180*de710d24SJosef 'Jeff' Sipek !ISP2(attr->dma_attr_align) || !ISP2(attr->dma_attr_minxfer)) { 11817c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* 11857b93957cSeota * check if a streaming sequential xfer is requested. 11867b93957cSeota */ 11877b93957cSeota streaming = (flags & DDI_DMA_STREAMING) ? 1 : 0; 11887b93957cSeota 11897b93957cSeota /* 11907c478bd9Sstevel@tonic-gate * Drivers for 64-bit capable SBus devices will encode 11917c478bd9Sstevel@tonic-gate * the burtsizes for 64-bit xfers in the upper 16-bits. 11927c478bd9Sstevel@tonic-gate * For DMA alignment, we use the most restrictive 11937c478bd9Sstevel@tonic-gate * alignment of 32-bit and 64-bit xfers. 11947c478bd9Sstevel@tonic-gate */ 11957c478bd9Sstevel@tonic-gate iomin = (attr->dma_attr_burstsizes & 0xffff) | 11967c478bd9Sstevel@tonic-gate ((attr->dma_attr_burstsizes >> 16) & 0xffff); 11977c478bd9Sstevel@tonic-gate /* 11987c478bd9Sstevel@tonic-gate * If a driver set burtsizes to 0, we give him byte alignment. 11997c478bd9Sstevel@tonic-gate * Otherwise align at the burtsizes boundary. 12007c478bd9Sstevel@tonic-gate */ 12017c478bd9Sstevel@tonic-gate if (iomin == 0) 12027c478bd9Sstevel@tonic-gate iomin = 1; 12037c478bd9Sstevel@tonic-gate else 12047c478bd9Sstevel@tonic-gate iomin = 1 << (ddi_fls(iomin) - 1); 12057c478bd9Sstevel@tonic-gate iomin = maxbit(iomin, attr->dma_attr_minxfer); 12067c478bd9Sstevel@tonic-gate iomin = maxbit(iomin, attr->dma_attr_align); 1207b89e420aSGarrett D'Amore iomin = i_ddi_iomin(dip, iomin, streaming); 12087c478bd9Sstevel@tonic-gate if (iomin == 0) 12097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate ASSERT((iomin & (iomin - 1)) == 0); 12127c478bd9Sstevel@tonic-gate ASSERT(iomin >= attr->dma_attr_minxfer); 12137c478bd9Sstevel@tonic-gate ASSERT(iomin >= attr->dma_attr_align); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate length = P2ROUNDUP(length, iomin); 12167c478bd9Sstevel@tonic-gate align = iomin; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate if (accattrp != NULL) 12197c478bd9Sstevel@tonic-gate endian_flags = accattrp->devacc_attr_endian_flags; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate a = kalloca(length, align, cansleep, endian_flags); 12227c478bd9Sstevel@tonic-gate if ((*kaddrp = a) == 0) { 12237c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12247c478bd9Sstevel@tonic-gate } else { 12257c478bd9Sstevel@tonic-gate if (real_length) { 12267c478bd9Sstevel@tonic-gate *real_length = length; 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate if (handlep) { 12297c478bd9Sstevel@tonic-gate /* 12307c478bd9Sstevel@tonic-gate * assign handle information 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate impl_acc_hdl_init(handlep); 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12397c478bd9Sstevel@tonic-gate void 12407b93957cSeota i_ddi_mem_free(caddr_t kaddr, ddi_acc_hdl_t *ap) 12417c478bd9Sstevel@tonic-gate { 12427c478bd9Sstevel@tonic-gate kfreea(kaddr); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * SECTION: DDI Data Access 12477c478bd9Sstevel@tonic-gate */ 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate static uintptr_t impl_acc_hdl_id = 0; 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate /* 12527c478bd9Sstevel@tonic-gate * access handle allocator 12537c478bd9Sstevel@tonic-gate */ 12547c478bd9Sstevel@tonic-gate ddi_acc_hdl_t * 12557c478bd9Sstevel@tonic-gate impl_acc_hdl_get(ddi_acc_handle_t hdl) 12567c478bd9Sstevel@tonic-gate { 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * Extract the access handle address from the DDI implemented 12597c478bd9Sstevel@tonic-gate * access handle 12607c478bd9Sstevel@tonic-gate */ 12617c478bd9Sstevel@tonic-gate return (&((ddi_acc_impl_t *)hdl)->ahi_common); 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate ddi_acc_handle_t 12657c478bd9Sstevel@tonic-gate impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg) 12667c478bd9Sstevel@tonic-gate { 12677c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp; 12687c478bd9Sstevel@tonic-gate on_trap_data_t *otp; 12697c478bd9Sstevel@tonic-gate int sleepflag; 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate /* 12747c478bd9Sstevel@tonic-gate * Allocate and initialize the data access handle and error status. 12757c478bd9Sstevel@tonic-gate */ 12767c478bd9Sstevel@tonic-gate if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL) 12777c478bd9Sstevel@tonic-gate goto fail; 12787c478bd9Sstevel@tonic-gate if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc( 12797c478bd9Sstevel@tonic-gate sizeof (ndi_err_t), sleepflag)) == NULL) { 12807c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 12817c478bd9Sstevel@tonic-gate goto fail; 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate if ((otp = (on_trap_data_t *)kmem_zalloc( 12847c478bd9Sstevel@tonic-gate sizeof (on_trap_data_t), sleepflag)) == NULL) { 12857c478bd9Sstevel@tonic-gate kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 12867c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 12877c478bd9Sstevel@tonic-gate goto fail; 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate hp->ahi_err->err_ontrap = otp; 12907c478bd9Sstevel@tonic-gate hp->ahi_common.ah_platform_private = (void *)hp; 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate return ((ddi_acc_handle_t)hp); 12937c478bd9Sstevel@tonic-gate fail: 12947c478bd9Sstevel@tonic-gate if ((waitfp != (int (*)())KM_SLEEP) && 12957c478bd9Sstevel@tonic-gate (waitfp != (int (*)())KM_NOSLEEP)) 12967c478bd9Sstevel@tonic-gate ddi_set_callback(waitfp, arg, &impl_acc_hdl_id); 12977c478bd9Sstevel@tonic-gate return (NULL); 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate void 13017c478bd9Sstevel@tonic-gate impl_acc_hdl_free(ddi_acc_handle_t handle) 13027c478bd9Sstevel@tonic-gate { 13037c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp; 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate /* 13067c478bd9Sstevel@tonic-gate * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *), 13077c478bd9Sstevel@tonic-gate * because that's what we allocated in impl_acc_hdl_alloc() above. 13087c478bd9Sstevel@tonic-gate */ 13097c478bd9Sstevel@tonic-gate hp = (ddi_acc_impl_t *)handle; 13107c478bd9Sstevel@tonic-gate if (hp) { 13117c478bd9Sstevel@tonic-gate kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t)); 13127c478bd9Sstevel@tonic-gate kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 13137c478bd9Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 13147c478bd9Sstevel@tonic-gate if (impl_acc_hdl_id) 13157c478bd9Sstevel@tonic-gate ddi_run_callback(&impl_acc_hdl_id); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 131900d0963fSdilpreet #define PCI_GET_MP_PFN(mp, page_no) ((mp)->dmai_ndvmapages == 1 ? \ 132000d0963fSdilpreet (pfn_t)(mp)->dmai_iopte:(((pfn_t *)(mp)->dmai_iopte)[page_no])) 132100d0963fSdilpreet 132200d0963fSdilpreet /* 132300d0963fSdilpreet * Function called after a dma fault occurred to find out whether the 132400d0963fSdilpreet * fault address is associated with a driver that is able to handle faults 132500d0963fSdilpreet * and recover from faults. 132600d0963fSdilpreet */ 132700d0963fSdilpreet /* ARGSUSED */ 132800d0963fSdilpreet int 132900d0963fSdilpreet impl_dma_check(dev_info_t *dip, const void *handle, const void *addr, 133000d0963fSdilpreet const void *not_used) 133100d0963fSdilpreet { 133200d0963fSdilpreet ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 133300d0963fSdilpreet pfn_t fault_pfn = mmu_btop(*(uint64_t *)addr); 133400d0963fSdilpreet pfn_t comp_pfn; 133500d0963fSdilpreet 133600d0963fSdilpreet /* 133700d0963fSdilpreet * The driver has to set DDI_DMA_FLAGERR to recover from dma faults. 133800d0963fSdilpreet */ 133900d0963fSdilpreet int page; 134000d0963fSdilpreet 134100d0963fSdilpreet ASSERT(mp); 134200d0963fSdilpreet for (page = 0; page < mp->dmai_ndvmapages; page++) { 134300d0963fSdilpreet comp_pfn = PCI_GET_MP_PFN(mp, page); 134400d0963fSdilpreet if (fault_pfn == comp_pfn) 134500d0963fSdilpreet return (DDI_FM_NONFATAL); 134600d0963fSdilpreet } 134700d0963fSdilpreet return (DDI_FM_UNKNOWN); 134800d0963fSdilpreet } 134900d0963fSdilpreet 135000d0963fSdilpreet /* 135100d0963fSdilpreet * Function used to check if a given access handle owns the failing address. 135200d0963fSdilpreet * Called by ndi_fmc_error, when we detect a PIO error. 135300d0963fSdilpreet */ 135400d0963fSdilpreet /* ARGSUSED */ 135500d0963fSdilpreet static int 135600d0963fSdilpreet impl_acc_check(dev_info_t *dip, const void *handle, const void *addr, 135700d0963fSdilpreet const void *not_used) 135800d0963fSdilpreet { 135900d0963fSdilpreet pfn_t pfn, fault_pfn; 136000d0963fSdilpreet ddi_acc_hdl_t *hp; 136100d0963fSdilpreet 136200d0963fSdilpreet hp = impl_acc_hdl_get((ddi_acc_handle_t)handle); 136300d0963fSdilpreet 136400d0963fSdilpreet ASSERT(hp); 136500d0963fSdilpreet 136600d0963fSdilpreet if (addr != NULL) { 136700d0963fSdilpreet pfn = hp->ah_pfn; 136800d0963fSdilpreet fault_pfn = mmu_btop(*(uint64_t *)addr); 136900d0963fSdilpreet if (fault_pfn >= pfn && fault_pfn < (pfn + hp->ah_pnum)) 137000d0963fSdilpreet return (DDI_FM_NONFATAL); 137100d0963fSdilpreet } 137200d0963fSdilpreet return (DDI_FM_UNKNOWN); 137300d0963fSdilpreet } 137400d0963fSdilpreet 13757c478bd9Sstevel@tonic-gate void 13767c478bd9Sstevel@tonic-gate impl_acc_err_init(ddi_acc_hdl_t *handlep) 13777c478bd9Sstevel@tonic-gate { 13787c478bd9Sstevel@tonic-gate int fmcap; 13797c478bd9Sstevel@tonic-gate ndi_err_t *errp; 13807c478bd9Sstevel@tonic-gate on_trap_data_t *otp; 13817c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep; 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate fmcap = ddi_fm_capable(handlep->ah_dip); 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 || 13867c478bd9Sstevel@tonic-gate !DDI_FM_ACC_ERR_CAP(fmcap)) { 13877c478bd9Sstevel@tonic-gate handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC; 13887c478bd9Sstevel@tonic-gate } else if (DDI_FM_ACC_ERR_CAP(fmcap)) { 13897c478bd9Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) { 1390837c1ac4SStephen Hanson if (handlep->ah_xfermodes) 1391837c1ac4SStephen Hanson return; 13927c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP, 13937c478bd9Sstevel@tonic-gate NULL, DDI_NOSLEEP); 13947c478bd9Sstevel@tonic-gate } else { 13957c478bd9Sstevel@tonic-gate errp = hp->ahi_err; 13967c478bd9Sstevel@tonic-gate otp = (on_trap_data_t *)errp->err_ontrap; 13977c478bd9Sstevel@tonic-gate otp->ot_handle = (void *)(hp); 13987c478bd9Sstevel@tonic-gate otp->ot_prot = OT_DATA_ACCESS; 13997c478bd9Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_access == 14007c478bd9Sstevel@tonic-gate DDI_CAUTIOUS_ACC) 14017c478bd9Sstevel@tonic-gate otp->ot_trampoline = 14027c478bd9Sstevel@tonic-gate (uintptr_t)&i_ddi_caut_trampoline; 14037c478bd9Sstevel@tonic-gate else 14047c478bd9Sstevel@tonic-gate otp->ot_trampoline = 14057c478bd9Sstevel@tonic-gate (uintptr_t)&i_ddi_prot_trampoline; 14067c478bd9Sstevel@tonic-gate errp->err_status = DDI_FM_OK; 14077c478bd9Sstevel@tonic-gate errp->err_expected = DDI_FM_ERR_UNEXPECTED; 140800d0963fSdilpreet errp->err_cf = impl_acc_check; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate void 14147c478bd9Sstevel@tonic-gate impl_acc_hdl_init(ddi_acc_hdl_t *handlep) 14157c478bd9Sstevel@tonic-gate { 14167c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp; 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate ASSERT(handlep); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate hp = (ddi_acc_impl_t *)handlep; 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate /* 14237c478bd9Sstevel@tonic-gate * check for SW byte-swapping 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate hp->ahi_get8 = i_ddi_get8; 14267c478bd9Sstevel@tonic-gate hp->ahi_put8 = i_ddi_put8; 14277c478bd9Sstevel@tonic-gate hp->ahi_rep_get8 = i_ddi_rep_get8; 14287c478bd9Sstevel@tonic-gate hp->ahi_rep_put8 = i_ddi_rep_put8; 14297c478bd9Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) { 14307c478bd9Sstevel@tonic-gate hp->ahi_get16 = i_ddi_swap_get16; 14317c478bd9Sstevel@tonic-gate hp->ahi_get32 = i_ddi_swap_get32; 14327c478bd9Sstevel@tonic-gate hp->ahi_get64 = i_ddi_swap_get64; 14337c478bd9Sstevel@tonic-gate hp->ahi_put16 = i_ddi_swap_put16; 14347c478bd9Sstevel@tonic-gate hp->ahi_put32 = i_ddi_swap_put32; 14357c478bd9Sstevel@tonic-gate hp->ahi_put64 = i_ddi_swap_put64; 14367c478bd9Sstevel@tonic-gate hp->ahi_rep_get16 = i_ddi_swap_rep_get16; 14377c478bd9Sstevel@tonic-gate hp->ahi_rep_get32 = i_ddi_swap_rep_get32; 14387c478bd9Sstevel@tonic-gate hp->ahi_rep_get64 = i_ddi_swap_rep_get64; 14397c478bd9Sstevel@tonic-gate hp->ahi_rep_put16 = i_ddi_swap_rep_put16; 14407c478bd9Sstevel@tonic-gate hp->ahi_rep_put32 = i_ddi_swap_rep_put32; 14417c478bd9Sstevel@tonic-gate hp->ahi_rep_put64 = i_ddi_swap_rep_put64; 14427c478bd9Sstevel@tonic-gate } else { 14437c478bd9Sstevel@tonic-gate hp->ahi_get16 = i_ddi_get16; 14447c478bd9Sstevel@tonic-gate hp->ahi_get32 = i_ddi_get32; 14457c478bd9Sstevel@tonic-gate hp->ahi_get64 = i_ddi_get64; 14467c478bd9Sstevel@tonic-gate hp->ahi_put16 = i_ddi_put16; 14477c478bd9Sstevel@tonic-gate hp->ahi_put32 = i_ddi_put32; 14487c478bd9Sstevel@tonic-gate hp->ahi_put64 = i_ddi_put64; 14497c478bd9Sstevel@tonic-gate hp->ahi_rep_get16 = i_ddi_rep_get16; 14507c478bd9Sstevel@tonic-gate hp->ahi_rep_get32 = i_ddi_rep_get32; 14517c478bd9Sstevel@tonic-gate hp->ahi_rep_get64 = i_ddi_rep_get64; 14527c478bd9Sstevel@tonic-gate hp->ahi_rep_put16 = i_ddi_rep_put16; 14537c478bd9Sstevel@tonic-gate hp->ahi_rep_put32 = i_ddi_rep_put32; 14547c478bd9Sstevel@tonic-gate hp->ahi_rep_put64 = i_ddi_rep_put64; 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate /* Legacy fault flags and support */ 14587c478bd9Sstevel@tonic-gate hp->ahi_fault_check = i_ddi_acc_fault_check; 14597c478bd9Sstevel@tonic-gate hp->ahi_fault_notify = i_ddi_acc_fault_notify; 14607c478bd9Sstevel@tonic-gate hp->ahi_fault = 0; 14617c478bd9Sstevel@tonic-gate impl_acc_err_init(handlep); 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate void 14657c478bd9Sstevel@tonic-gate i_ddi_acc_set_fault(ddi_acc_handle_t handle) 14667c478bd9Sstevel@tonic-gate { 14677c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate if (!hp->ahi_fault) { 14707c478bd9Sstevel@tonic-gate hp->ahi_fault = 1; 14717c478bd9Sstevel@tonic-gate (*hp->ahi_fault_notify)(hp); 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate void 14767c478bd9Sstevel@tonic-gate i_ddi_acc_clr_fault(ddi_acc_handle_t handle) 14777c478bd9Sstevel@tonic-gate { 14787c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate if (hp->ahi_fault) { 14817c478bd9Sstevel@tonic-gate hp->ahi_fault = 0; 14827c478bd9Sstevel@tonic-gate (*hp->ahi_fault_notify)(hp); 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14877c478bd9Sstevel@tonic-gate void 14887c478bd9Sstevel@tonic-gate i_ddi_acc_fault_notify(ddi_acc_impl_t *hp) 14897c478bd9Sstevel@tonic-gate { 14907c478bd9Sstevel@tonic-gate /* Default version, does nothing */ 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * SECTION: Misc functions 14957c478bd9Sstevel@tonic-gate */ 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate /* 14987c478bd9Sstevel@tonic-gate * instance wrappers 14997c478bd9Sstevel@tonic-gate */ 15007c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15017c478bd9Sstevel@tonic-gate uint_t 15027c478bd9Sstevel@tonic-gate impl_assign_instance(dev_info_t *dip) 15037c478bd9Sstevel@tonic-gate { 15047c478bd9Sstevel@tonic-gate return ((uint_t)-1); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15087c478bd9Sstevel@tonic-gate int 15097c478bd9Sstevel@tonic-gate impl_keep_instance(dev_info_t *dip) 15107c478bd9Sstevel@tonic-gate { 15117c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15157c478bd9Sstevel@tonic-gate int 15167c478bd9Sstevel@tonic-gate impl_free_instance(dev_info_t *dip) 15177c478bd9Sstevel@tonic-gate { 15187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15227c478bd9Sstevel@tonic-gate int 15237c478bd9Sstevel@tonic-gate impl_check_cpu(dev_info_t *devi) 15247c478bd9Sstevel@tonic-gate { 15257c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate static const char *nocopydevs[] = { 15307c478bd9Sstevel@tonic-gate "SUNW,ffb", 15317c478bd9Sstevel@tonic-gate "SUNW,afb", 15327c478bd9Sstevel@tonic-gate NULL 15337c478bd9Sstevel@tonic-gate }; 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate /* 15367c478bd9Sstevel@tonic-gate * Perform a copy from a memory mapped device (whose devinfo pointer is devi) 15377c478bd9Sstevel@tonic-gate * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. 15387c478bd9Sstevel@tonic-gate */ 15397c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15407c478bd9Sstevel@tonic-gate int 15417c478bd9Sstevel@tonic-gate e_ddi_copyfromdev(dev_info_t *devi, 15427c478bd9Sstevel@tonic-gate off_t off, const void *devaddr, void *kaddr, size_t len) 15437c478bd9Sstevel@tonic-gate { 15447c478bd9Sstevel@tonic-gate const char **argv; 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate for (argv = nocopydevs; *argv; argv++) 15477c478bd9Sstevel@tonic-gate if (strcmp(ddi_binding_name(devi), *argv) == 0) { 15487c478bd9Sstevel@tonic-gate bzero(kaddr, len); 15497c478bd9Sstevel@tonic-gate return (0); 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate bcopy(devaddr, kaddr, len); 15537c478bd9Sstevel@tonic-gate return (0); 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * Perform a copy to a memory mapped device (whose devinfo pointer is devi) 15587c478bd9Sstevel@tonic-gate * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. 15597c478bd9Sstevel@tonic-gate */ 15607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15617c478bd9Sstevel@tonic-gate int 15627c478bd9Sstevel@tonic-gate e_ddi_copytodev(dev_info_t *devi, 15637c478bd9Sstevel@tonic-gate off_t off, const void *kaddr, void *devaddr, size_t len) 15647c478bd9Sstevel@tonic-gate { 15657c478bd9Sstevel@tonic-gate const char **argv; 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate for (argv = nocopydevs; *argv; argv++) 15687c478bd9Sstevel@tonic-gate if (strcmp(ddi_binding_name(devi), *argv) == 0) 15697c478bd9Sstevel@tonic-gate return (1); 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate bcopy(kaddr, devaddr, len); 15727c478bd9Sstevel@tonic-gate return (0); 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate /* 15767c478bd9Sstevel@tonic-gate * Boot Configuration 15777c478bd9Sstevel@tonic-gate */ 15787c478bd9Sstevel@tonic-gate idprom_t idprom; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * Configure the hardware on the system. 15827c478bd9Sstevel@tonic-gate * Called before the rootfs is mounted 15837c478bd9Sstevel@tonic-gate */ 15847c478bd9Sstevel@tonic-gate void 15857c478bd9Sstevel@tonic-gate configure(void) 15867c478bd9Sstevel@tonic-gate { 15877c478bd9Sstevel@tonic-gate extern void i_ddi_init_root(); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* We better have released boot by this time! */ 15907c478bd9Sstevel@tonic-gate ASSERT(!bootops); 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate /* 15937c478bd9Sstevel@tonic-gate * Determine whether or not to use the fpu, V9 SPARC cpus 15947c478bd9Sstevel@tonic-gate * always have one. Could check for existence of a fp queue, 15957c478bd9Sstevel@tonic-gate * Ultra I, II and IIa do not have a fp queue. 15967c478bd9Sstevel@tonic-gate */ 15977c478bd9Sstevel@tonic-gate if (fpu_exists) 15987c478bd9Sstevel@tonic-gate fpu_probe(); 15997c478bd9Sstevel@tonic-gate else 16007c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "FPU not in use\n"); 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate #if 0 /* XXXQ - not necessary for sun4u */ 16037c478bd9Sstevel@tonic-gate /* 16047c478bd9Sstevel@tonic-gate * This following line fixes bugid 1041296; we need to do a 16057c478bd9Sstevel@tonic-gate * prom_nextnode(0) because this call ALSO patches the DMA+ 16067c478bd9Sstevel@tonic-gate * bug in Campus-B and Phoenix. The prom uncaches the traptable 16077c478bd9Sstevel@tonic-gate * page as a side-effect of devr_next(0) (which prom_nextnode calls), 16087c478bd9Sstevel@tonic-gate * so this *must* be executed early on. (XXX This is untrue for sun4u) 16097c478bd9Sstevel@tonic-gate */ 1610fa9e4066Sahrens (void) prom_nextnode((pnode_t)0); 16117c478bd9Sstevel@tonic-gate #endif 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate /* 16147c478bd9Sstevel@tonic-gate * Initialize devices on the machine. 16157c478bd9Sstevel@tonic-gate * Uses configuration tree built by the PROMs to determine what 16167c478bd9Sstevel@tonic-gate * is present, and builds a tree of prototype dev_info nodes 16177c478bd9Sstevel@tonic-gate * corresponding to the hardware which identified itself. 16187c478bd9Sstevel@tonic-gate */ 16197c478bd9Sstevel@tonic-gate i_ddi_init_root(); 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate #ifdef DDI_PROP_DEBUG 16227c478bd9Sstevel@tonic-gate (void) ddi_prop_debug(1); /* Enable property debugging */ 16237c478bd9Sstevel@tonic-gate #endif /* DDI_PROP_DEBUG */ 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate /* 16277c478bd9Sstevel@tonic-gate * The "status" property indicates the operational status of a device. 16287c478bd9Sstevel@tonic-gate * If this property is present, the value is a string indicating the 16297c478bd9Sstevel@tonic-gate * status of the device as follows: 16307c478bd9Sstevel@tonic-gate * 16317c478bd9Sstevel@tonic-gate * "okay" operational. 16327c478bd9Sstevel@tonic-gate * "disabled" not operational, but might become operational. 16337c478bd9Sstevel@tonic-gate * "fail" not operational because a fault has been detected, 16347c478bd9Sstevel@tonic-gate * and it is unlikely that the device will become 16357c478bd9Sstevel@tonic-gate * operational without repair. no additional details 16367c478bd9Sstevel@tonic-gate * are available. 16377c478bd9Sstevel@tonic-gate * "fail-xxx" not operational because a fault has been detected, 16387c478bd9Sstevel@tonic-gate * and it is unlikely that the device will become 16397c478bd9Sstevel@tonic-gate * operational without repair. "xxx" is additional 16407c478bd9Sstevel@tonic-gate * human-readable information about the particular 16417c478bd9Sstevel@tonic-gate * fault condition that was detected. 16427c478bd9Sstevel@tonic-gate * 16437c478bd9Sstevel@tonic-gate * The absence of this property means that the operational status is 16447c478bd9Sstevel@tonic-gate * unknown or okay. 16457c478bd9Sstevel@tonic-gate * 16467c478bd9Sstevel@tonic-gate * This routine checks the status property of the specified device node 16477c478bd9Sstevel@tonic-gate * and returns 0 if the operational status indicates failure, and 1 otherwise. 16487c478bd9Sstevel@tonic-gate * 16497c478bd9Sstevel@tonic-gate * The property may exist on plug-in cards the existed before IEEE 1275-1994. 16507c478bd9Sstevel@tonic-gate * And, in that case, the property may not even be a string. So we carefully 16517c478bd9Sstevel@tonic-gate * check for the value "fail", in the beginning of the string, noting 16527c478bd9Sstevel@tonic-gate * the property length. 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate int 16557c478bd9Sstevel@tonic-gate status_okay(int id, char *buf, int buflen) 16567c478bd9Sstevel@tonic-gate { 16577c478bd9Sstevel@tonic-gate char status_buf[OBP_MAXPROPNAME]; 16587c478bd9Sstevel@tonic-gate char *bufp = buf; 16597c478bd9Sstevel@tonic-gate int len = buflen; 16607c478bd9Sstevel@tonic-gate int proplen; 16617c478bd9Sstevel@tonic-gate static const char *status = "status"; 16627c478bd9Sstevel@tonic-gate static const char *fail = "fail"; 16637c478bd9Sstevel@tonic-gate size_t fail_len = strlen(fail); 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate /* 16667c478bd9Sstevel@tonic-gate * Get the proplen ... if it's smaller than "fail", 16677c478bd9Sstevel@tonic-gate * or doesn't exist ... then we don't care, since 16687c478bd9Sstevel@tonic-gate * the value can't begin with the char string "fail". 16697c478bd9Sstevel@tonic-gate * 16707c478bd9Sstevel@tonic-gate * NB: proplen, if it's a string, includes the NULL in the 16717c478bd9Sstevel@tonic-gate * the size of the property, and fail_len does not. 16727c478bd9Sstevel@tonic-gate */ 1673fa9e4066Sahrens proplen = prom_getproplen((pnode_t)id, (caddr_t)status); 16747c478bd9Sstevel@tonic-gate if (proplen <= fail_len) /* nonexistent or uninteresting len */ 16757c478bd9Sstevel@tonic-gate return (1); 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate /* 16787c478bd9Sstevel@tonic-gate * if a buffer was provided, use it 16797c478bd9Sstevel@tonic-gate */ 16807c478bd9Sstevel@tonic-gate if ((buf == (char *)NULL) || (buflen <= 0)) { 16817c478bd9Sstevel@tonic-gate bufp = status_buf; 16827c478bd9Sstevel@tonic-gate len = sizeof (status_buf); 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate *bufp = (char)0; 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate /* 16877c478bd9Sstevel@tonic-gate * Get the property into the buffer, to the extent of the buffer, 16887c478bd9Sstevel@tonic-gate * and in case the buffer is smaller than the property size, 16897c478bd9Sstevel@tonic-gate * NULL terminate the buffer. (This handles the case where 16907c478bd9Sstevel@tonic-gate * a buffer was passed in and the caller wants to print the 16917c478bd9Sstevel@tonic-gate * value, but the buffer was too small). 16927c478bd9Sstevel@tonic-gate */ 1693fa9e4066Sahrens (void) prom_bounded_getprop((pnode_t)id, (caddr_t)status, 16947c478bd9Sstevel@tonic-gate (caddr_t)bufp, len); 16957c478bd9Sstevel@tonic-gate *(bufp + len - 1) = (char)0; 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate /* 16987c478bd9Sstevel@tonic-gate * If the value begins with the char string "fail", 16997c478bd9Sstevel@tonic-gate * then it means the node is failed. We don't care 17007c478bd9Sstevel@tonic-gate * about any other values. We assume the node is ok 17017c478bd9Sstevel@tonic-gate * although it might be 'disabled'. 17027c478bd9Sstevel@tonic-gate */ 17037c478bd9Sstevel@tonic-gate if (strncmp(bufp, fail, fail_len) == 0) 17047c478bd9Sstevel@tonic-gate return (0); 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate return (1); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate /* 17117c478bd9Sstevel@tonic-gate * We set the cpu type from the idprom, if we can. 17127c478bd9Sstevel@tonic-gate * Note that we just read out the contents of it, for the most part. 17137c478bd9Sstevel@tonic-gate */ 17147c478bd9Sstevel@tonic-gate void 17157c478bd9Sstevel@tonic-gate setcputype(void) 17167c478bd9Sstevel@tonic-gate { 17177c478bd9Sstevel@tonic-gate /* 17187c478bd9Sstevel@tonic-gate * We cache the idprom info early on so that we don't 17197c478bd9Sstevel@tonic-gate * rummage through the NVRAM unnecessarily later. 17207c478bd9Sstevel@tonic-gate */ 17217c478bd9Sstevel@tonic-gate (void) prom_getidprom((caddr_t)&idprom, sizeof (idprom)); 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate /* 17257c478bd9Sstevel@tonic-gate * Here is where we actually infer meanings to the members of idprom_t 17267c478bd9Sstevel@tonic-gate */ 17277c478bd9Sstevel@tonic-gate void 17287c478bd9Sstevel@tonic-gate parse_idprom(void) 17297c478bd9Sstevel@tonic-gate { 17307c478bd9Sstevel@tonic-gate if (idprom.id_format == IDFORM_1) { 17317c478bd9Sstevel@tonic-gate (void) localetheraddr((struct ether_addr *)idprom.id_ether, 17327c478bd9Sstevel@tonic-gate (struct ether_addr *)NULL); 17335679c89fSjv227347 (void) snprintf(hw_serial, HW_HOSTID_LEN, "%u", 17345679c89fSjv227347 (idprom.id_machine << 24) + idprom.id_serial); 17357c478bd9Sstevel@tonic-gate } else 17367c478bd9Sstevel@tonic-gate prom_printf("Invalid format code in IDprom.\n"); 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate /* 17407c478bd9Sstevel@tonic-gate * Allow for implementation specific correction of PROM property values. 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17437c478bd9Sstevel@tonic-gate void 17447c478bd9Sstevel@tonic-gate impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len, 17457c478bd9Sstevel@tonic-gate caddr_t buffer) 17467c478bd9Sstevel@tonic-gate { 17477c478bd9Sstevel@tonic-gate /* 17487c478bd9Sstevel@tonic-gate * There are no adjustments needed in this implementation. 17497c478bd9Sstevel@tonic-gate */ 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate /* 17537c478bd9Sstevel@tonic-gate * The following functions ready a cautious request to go up to the nexus 17547c478bd9Sstevel@tonic-gate * driver. It is up to the nexus driver to decide how to process the request. 17557c478bd9Sstevel@tonic-gate * It may choose to call i_ddi_do_caut_get/put in this file, or do it 17567c478bd9Sstevel@tonic-gate * differently. 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate static void 17607c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops( 17617c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size, 17627c478bd9Sstevel@tonic-gate size_t repcount, uint_t flags, ddi_ctl_enum_t cmd) 17637c478bd9Sstevel@tonic-gate { 17647c478bd9Sstevel@tonic-gate peekpoke_ctlops_t cautacc_ctlops_arg; 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate cautacc_ctlops_arg.size = size; 17677c478bd9Sstevel@tonic-gate cautacc_ctlops_arg.dev_addr = dev_addr; 17687c478bd9Sstevel@tonic-gate cautacc_ctlops_arg.host_addr = host_addr; 17697c478bd9Sstevel@tonic-gate cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp; 17707c478bd9Sstevel@tonic-gate cautacc_ctlops_arg.repcount = repcount; 17717c478bd9Sstevel@tonic-gate cautacc_ctlops_arg.flags = flags; 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate (void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd, 17747c478bd9Sstevel@tonic-gate &cautacc_ctlops_arg, NULL); 17757c478bd9Sstevel@tonic-gate } 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate uint8_t 17787c478bd9Sstevel@tonic-gate i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr) 17797c478bd9Sstevel@tonic-gate { 17807c478bd9Sstevel@tonic-gate uint8_t value; 17817c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 17827c478bd9Sstevel@tonic-gate sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK); 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate return (value); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate uint16_t 17887c478bd9Sstevel@tonic-gate i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr) 17897c478bd9Sstevel@tonic-gate { 17907c478bd9Sstevel@tonic-gate uint16_t value; 17917c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 17927c478bd9Sstevel@tonic-gate sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK); 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate return (value); 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate uint32_t 17987c478bd9Sstevel@tonic-gate i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr) 17997c478bd9Sstevel@tonic-gate { 18007c478bd9Sstevel@tonic-gate uint32_t value; 18017c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18027c478bd9Sstevel@tonic-gate sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK); 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate return (value); 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate uint64_t 18087c478bd9Sstevel@tonic-gate i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr) 18097c478bd9Sstevel@tonic-gate { 18107c478bd9Sstevel@tonic-gate uint64_t value; 18117c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18127c478bd9Sstevel@tonic-gate sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK); 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate return (value); 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate void 18187c478bd9Sstevel@tonic-gate i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value) 18197c478bd9Sstevel@tonic-gate { 18207c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18217c478bd9Sstevel@tonic-gate sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE); 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate void 18257c478bd9Sstevel@tonic-gate i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value) 18267c478bd9Sstevel@tonic-gate { 18277c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18287c478bd9Sstevel@tonic-gate sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate void 18327c478bd9Sstevel@tonic-gate i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value) 18337c478bd9Sstevel@tonic-gate { 18347c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18357c478bd9Sstevel@tonic-gate sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate void 18397c478bd9Sstevel@tonic-gate i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value) 18407c478bd9Sstevel@tonic-gate { 18417c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18427c478bd9Sstevel@tonic-gate sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE); 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate void 18467c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 18477c478bd9Sstevel@tonic-gate size_t repcount, uint_t flags) 18487c478bd9Sstevel@tonic-gate { 18497c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18507c478bd9Sstevel@tonic-gate sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK); 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate void 18547c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr, 18557c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 18567c478bd9Sstevel@tonic-gate { 18577c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18587c478bd9Sstevel@tonic-gate sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK); 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate void 18627c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr, 18637c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 18647c478bd9Sstevel@tonic-gate { 18657c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18667c478bd9Sstevel@tonic-gate sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate void 18707c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr, 18717c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 18727c478bd9Sstevel@tonic-gate { 18737c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18747c478bd9Sstevel@tonic-gate sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK); 18757c478bd9Sstevel@tonic-gate } 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate void 18787c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 18797c478bd9Sstevel@tonic-gate size_t repcount, uint_t flags) 18807c478bd9Sstevel@tonic-gate { 18817c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18827c478bd9Sstevel@tonic-gate sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE); 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate void 18867c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr, 18877c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 18887c478bd9Sstevel@tonic-gate { 18897c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18907c478bd9Sstevel@tonic-gate sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE); 18917c478bd9Sstevel@tonic-gate } 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate void 18947c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr, 18957c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 18967c478bd9Sstevel@tonic-gate { 18977c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18987c478bd9Sstevel@tonic-gate sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE); 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate void 19027c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr, 19037c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 19047c478bd9Sstevel@tonic-gate { 19057c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 19067c478bd9Sstevel@tonic-gate sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE); 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * This is called only to process peek/poke when the DIP is NULL. 19117c478bd9Sstevel@tonic-gate * Assume that this is for memory, as nexi take care of device safe accesses. 19127c478bd9Sstevel@tonic-gate */ 19137c478bd9Sstevel@tonic-gate int 19147c478bd9Sstevel@tonic-gate peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args) 19157c478bd9Sstevel@tonic-gate { 19167c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 19177c478bd9Sstevel@tonic-gate on_trap_data_t otd; 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate /* Set up protected environment. */ 19207c478bd9Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 19217c478bd9Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate if (cmd == DDI_CTLOPS_POKE) { 19247c478bd9Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 19257c478bd9Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 19267c478bd9Sstevel@tonic-gate (void *)in_args->host_addr); 19277c478bd9Sstevel@tonic-gate } else { 19287c478bd9Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 19297c478bd9Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 19307c478bd9Sstevel@tonic-gate (void *)in_args->host_addr); 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate otd.ot_trampoline = tramp; 19337c478bd9Sstevel@tonic-gate } else 19347c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate /* Take down protected environment. */ 19377c478bd9Sstevel@tonic-gate no_trap(); 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate return (err); 19407c478bd9Sstevel@tonic-gate } 1941