10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * sun4 specific DDI implementation 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate #include <sys/cpuvar.h> 330Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 340Sstevel@tonic-gate #include <sys/machsystm.h> 350Sstevel@tonic-gate #include <sys/sunndi.h> 360Sstevel@tonic-gate #include <sys/sysmacros.h> 370Sstevel@tonic-gate #include <sys/ontrap.h> 380Sstevel@tonic-gate #include <vm/seg_kmem.h> 390Sstevel@tonic-gate #include <sys/membar.h> 400Sstevel@tonic-gate #include <sys/dditypes.h> 410Sstevel@tonic-gate #include <sys/ndifm.h> 420Sstevel@tonic-gate #include <sys/fm/io/ddi.h> 430Sstevel@tonic-gate #include <sys/ivintr.h> 440Sstevel@tonic-gate #include <sys/bootconf.h> 450Sstevel@tonic-gate #include <sys/conf.h> 460Sstevel@tonic-gate #include <sys/ethernet.h> 470Sstevel@tonic-gate #include <sys/idprom.h> 480Sstevel@tonic-gate #include <sys/promif.h> 490Sstevel@tonic-gate #include <sys/prom_plat.h> 500Sstevel@tonic-gate #include <sys/systeminfo.h> 510Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 520Sstevel@tonic-gate #include <sys/vm.h> 530Sstevel@tonic-gate #include <sys/fs/dv_node.h> 540Sstevel@tonic-gate #include <sys/fs/snode.h> 550Sstevel@tonic-gate #include <sys/ddi_isa.h> 560Sstevel@tonic-gate 570Sstevel@tonic-gate dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *, 580Sstevel@tonic-gate ddi_ispec_t *, ddi_ispec_t **); 590Sstevel@tonic-gate #pragma weak get_intr_parent 600Sstevel@tonic-gate 610Sstevel@tonic-gate int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 620Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 630Sstevel@tonic-gate #pragma weak process_intr_ops 640Sstevel@tonic-gate 650Sstevel@tonic-gate void cells_1275_copy(prop_1275_cell_t *, prop_1275_cell_t *, int32_t); 660Sstevel@tonic-gate prop_1275_cell_t *cells_1275_cmp(prop_1275_cell_t *, prop_1275_cell_t *, 670Sstevel@tonic-gate int32_t len); 680Sstevel@tonic-gate #pragma weak cells_1275_copy 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* 710Sstevel@tonic-gate * Wrapper for ddi_prop_lookup_int_array(). 720Sstevel@tonic-gate * This is handy because it returns the prop length in 730Sstevel@tonic-gate * bytes which is what most of the callers require. 740Sstevel@tonic-gate */ 750Sstevel@tonic-gate 760Sstevel@tonic-gate static int 770Sstevel@tonic-gate get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen) 780Sstevel@tonic-gate { 790Sstevel@tonic-gate int ret; 800Sstevel@tonic-gate 810Sstevel@tonic-gate if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di, 820Sstevel@tonic-gate DDI_PROP_DONTPASS, pname, pval, plen)) == DDI_PROP_SUCCESS) { 830Sstevel@tonic-gate *plen = (*plen) * (uint_t)sizeof (int); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate return (ret); 860Sstevel@tonic-gate } 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * SECTION: DDI Node Configuration 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * init_regspec_64: 940Sstevel@tonic-gate * 950Sstevel@tonic-gate * If the parent #size-cells is 2, convert the upa-style or 960Sstevel@tonic-gate * safari-style reg property from 2-size cells to 1 size cell 970Sstevel@tonic-gate * format, ignoring the size_hi, which must be zero for devices. 980Sstevel@tonic-gate * (It won't be zero in the memory list properties in the memory 990Sstevel@tonic-gate * nodes, but that doesn't matter here.) 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate struct ddi_parent_private_data * 1020Sstevel@tonic-gate init_regspec_64(dev_info_t *dip) 1030Sstevel@tonic-gate { 1040Sstevel@tonic-gate struct ddi_parent_private_data *pd; 1050Sstevel@tonic-gate dev_info_t *parent; 1060Sstevel@tonic-gate int size_cells; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate /* 1090Sstevel@tonic-gate * If there are no "reg"s in the child node, return. 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate pd = ddi_get_parent_data(dip); 1120Sstevel@tonic-gate if ((pd == NULL) || (pd->par_nreg == 0)) { 1130Sstevel@tonic-gate return (pd); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate parent = ddi_get_parent(dip); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 1180Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if (size_cells != 1) { 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate int n, j; 1230Sstevel@tonic-gate struct regspec *irp; 1240Sstevel@tonic-gate struct reg_64 { 1250Sstevel@tonic-gate uint_t addr_hi, addr_lo, size_hi, size_lo; 1260Sstevel@tonic-gate }; 1270Sstevel@tonic-gate struct reg_64 *r64_rp; 1280Sstevel@tonic-gate struct regspec *rp; 1290Sstevel@tonic-gate uint_t len = 0; 1300Sstevel@tonic-gate int *reg_prop; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate ASSERT(size_cells == 2); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate /* 1350Sstevel@tonic-gate * We already looked the property up once before if 1360Sstevel@tonic-gate * pd is non-NULL. 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate (void) ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 1390Sstevel@tonic-gate DDI_PROP_DONTPASS, OBP_REG, ®_prop, &len); 1400Sstevel@tonic-gate ASSERT(len != 0); 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate n = sizeof (struct reg_64) / sizeof (int); 1430Sstevel@tonic-gate n = len / n; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * We're allocating a buffer the size of the PROM's property, 1470Sstevel@tonic-gate * but we're only using a smaller portion when we assign it 1480Sstevel@tonic-gate * to a regspec. We do this so that in the 1490Sstevel@tonic-gate * impl_ddi_sunbus_removechild function, we will 1500Sstevel@tonic-gate * always free the right amount of memory. 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate irp = rp = (struct regspec *)reg_prop; 1530Sstevel@tonic-gate r64_rp = (struct reg_64 *)pd->par_reg; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate for (j = 0; j < n; ++j, ++rp, ++r64_rp) { 1560Sstevel@tonic-gate ASSERT(r64_rp->size_hi == 0); 1570Sstevel@tonic-gate rp->regspec_bustype = r64_rp->addr_hi; 1580Sstevel@tonic-gate rp->regspec_addr = r64_rp->addr_lo; 1590Sstevel@tonic-gate rp->regspec_size = r64_rp->size_lo; 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate ddi_prop_free((void *)pd->par_reg); 1630Sstevel@tonic-gate pd->par_nreg = n; 1640Sstevel@tonic-gate pd->par_reg = irp; 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate return (pd); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * Create a ddi_parent_private_data structure from the ddi properties of 1710Sstevel@tonic-gate * the dev_info node. 1720Sstevel@tonic-gate * 1730Sstevel@tonic-gate * The "reg" is required if the driver wishes to create mappings on behalf 1740Sstevel@tonic-gate * of the device. The "reg" property is assumed to be a list of at least 1750Sstevel@tonic-gate * one triplet 1760Sstevel@tonic-gate * 1770Sstevel@tonic-gate * <bustype, address, size>*1 1780Sstevel@tonic-gate * 1790Sstevel@tonic-gate * The "interrupt" property is no longer part of parent private data on 1800Sstevel@tonic-gate * sun4u. The interrupt parent is may not be the device tree parent. 1810Sstevel@tonic-gate * 1820Sstevel@tonic-gate * The "ranges" property describes the mapping of child addresses to parent 1830Sstevel@tonic-gate * addresses. 1840Sstevel@tonic-gate * 1850Sstevel@tonic-gate * N.B. struct rangespec is defined for the following default values: 1860Sstevel@tonic-gate * parent child 1870Sstevel@tonic-gate * #address-cells 2 2 1880Sstevel@tonic-gate * #size-cells 1 1 1890Sstevel@tonic-gate * This function doesn't deal with non-default cells and will not create 1900Sstevel@tonic-gate * ranges in such cases. 1910Sstevel@tonic-gate */ 1920Sstevel@tonic-gate void 1930Sstevel@tonic-gate make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd) 1940Sstevel@tonic-gate { 1950Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 1960Sstevel@tonic-gate int *reg_prop, *rng_prop; 1970Sstevel@tonic-gate uint_t reg_len = 0, rng_len = 0; 1980Sstevel@tonic-gate dev_info_t *parent; 1990Sstevel@tonic-gate int parent_addr_cells, parent_size_cells; 2000Sstevel@tonic-gate int child_addr_cells, child_size_cells; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate *ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * root node has no parent private data, so *ppd should 2060Sstevel@tonic-gate * be initialized for naming to work properly. 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate if ((parent = ddi_get_parent(child)) == NULL) 2090Sstevel@tonic-gate return; 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate /* 2120Sstevel@tonic-gate * Set reg field of parent data from "reg" property 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate if ((get_prop_int_array(child, OBP_REG, ®_prop, ®_len) 2150Sstevel@tonic-gate == DDI_PROP_SUCCESS) && (reg_len != 0)) { 2160Sstevel@tonic-gate pdptr->par_nreg = (int)(reg_len / sizeof (struct regspec)); 2170Sstevel@tonic-gate pdptr->par_reg = (struct regspec *)reg_prop; 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate /* 2210Sstevel@tonic-gate * "ranges" property ... 2220Sstevel@tonic-gate * 2230Sstevel@tonic-gate * This function does not handle cases where #address-cells != 2 2240Sstevel@tonic-gate * and * min(parent, child) #size-cells != 1 (see bugid 4211124). 2250Sstevel@tonic-gate * 2260Sstevel@tonic-gate * Nexus drivers with such exceptions (e.g. pci ranges) 2270Sstevel@tonic-gate * should either create a separate function for handling 2280Sstevel@tonic-gate * ranges or not use parent private data to store ranges. 2290Sstevel@tonic-gate */ 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* root node has no ranges */ 2320Sstevel@tonic-gate if ((parent = ddi_get_parent(child)) == NULL) 2330Sstevel@tonic-gate return; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate child_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 2360Sstevel@tonic-gate DDI_PROP_DONTPASS, "#address-cells", 2); 2370Sstevel@tonic-gate child_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 2380Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 2390Sstevel@tonic-gate parent_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 2400Sstevel@tonic-gate DDI_PROP_DONTPASS, "#address-cells", 2); 2410Sstevel@tonic-gate parent_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 2420Sstevel@tonic-gate DDI_PROP_DONTPASS, "#size-cells", 1); 2430Sstevel@tonic-gate if (child_addr_cells != 2 || parent_addr_cells != 2 || 2440Sstevel@tonic-gate (child_size_cells != 1 && parent_size_cells != 1)) { 2450Sstevel@tonic-gate NDI_CONFIG_DEBUG((CE_NOTE, "!ranges not made in parent data; " 2460Sstevel@tonic-gate "#address-cells or #size-cells have non-default value")); 2470Sstevel@tonic-gate return; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate if (get_prop_int_array(child, OBP_RANGES, &rng_prop, &rng_len) 2510Sstevel@tonic-gate == DDI_PROP_SUCCESS) { 2520Sstevel@tonic-gate pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec)); 2530Sstevel@tonic-gate pdptr->par_rng = (struct rangespec *)rng_prop; 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * Free ddi_parent_private_data structure 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate void 2610Sstevel@tonic-gate impl_free_ddi_ppd(dev_info_t *dip) 2620Sstevel@tonic-gate { 2630Sstevel@tonic-gate struct ddi_parent_private_data *pdptr = ddi_get_parent_data(dip); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate if (pdptr == NULL) 2660Sstevel@tonic-gate return; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate if (pdptr->par_nrng != 0) 2690Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_rng); 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate if (pdptr->par_nreg != 0) 2720Sstevel@tonic-gate ddi_prop_free((void *)pdptr->par_reg); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate kmem_free(pdptr, sizeof (*pdptr)); 2750Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate /* 2790Sstevel@tonic-gate * Name a child of sun busses based on the reg spec. 2800Sstevel@tonic-gate * Handles the following properties: 2810Sstevel@tonic-gate * 2820Sstevel@tonic-gate * Property value 2830Sstevel@tonic-gate * Name type 2840Sstevel@tonic-gate * 2850Sstevel@tonic-gate * reg register spec 2860Sstevel@tonic-gate * interrupts new (bus-oriented) interrupt spec 2870Sstevel@tonic-gate * ranges range spec 2880Sstevel@tonic-gate * 2890Sstevel@tonic-gate * This may be called multiple times, independent of 2900Sstevel@tonic-gate * initchild calls. 2910Sstevel@tonic-gate */ 2920Sstevel@tonic-gate static int 2930Sstevel@tonic-gate impl_sunbus_name_child(dev_info_t *child, char *name, int namelen) 2940Sstevel@tonic-gate { 2950Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 2960Sstevel@tonic-gate struct regspec *rp; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate /* 2990Sstevel@tonic-gate * Fill in parent-private data and this function returns to us 3000Sstevel@tonic-gate * an indication if it used "registers" to fill in the data. 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate if (ddi_get_parent_data(child) == NULL) { 3030Sstevel@tonic-gate make_ddi_ppd(child, &pdptr); 3040Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate /* 3080Sstevel@tonic-gate * No reg property, return null string as address 3090Sstevel@tonic-gate * (e.g. root node) 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate name[0] = '\0'; 3120Sstevel@tonic-gate if (sparc_pd_getnreg(child) == 0) { 3130Sstevel@tonic-gate return (DDI_SUCCESS); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate rp = sparc_pd_getreg(child, 0); 3170Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 3180Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr); 3190Sstevel@tonic-gate return (DDI_SUCCESS); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate /* 3240Sstevel@tonic-gate * Called from the bus_ctl op of some drivers. 3250Sstevel@tonic-gate * to implement the DDI_CTLOPS_INITCHILD operation. 3260Sstevel@tonic-gate * 3270Sstevel@tonic-gate * NEW drivers should NOT use this function, but should declare 3280Sstevel@tonic-gate * there own initchild/uninitchild handlers. (This function assumes 3290Sstevel@tonic-gate * the layout of the parent private data and the format of "reg", 3300Sstevel@tonic-gate * "ranges", "interrupts" properties and that #address-cells and 3310Sstevel@tonic-gate * #size-cells of the parent bus are defined to be default values.) 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate int 3340Sstevel@tonic-gate impl_ddi_sunbus_initchild(dev_info_t *child) 3350Sstevel@tonic-gate { 3360Sstevel@tonic-gate char name[MAXNAMELEN]; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate (void) impl_sunbus_name_child(child, name, MAXNAMELEN); 3390Sstevel@tonic-gate ddi_set_name_addr(child, name); 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * Try to merge .conf node. If successful, return failure to 3430Sstevel@tonic-gate * remove this child. 3440Sstevel@tonic-gate */ 3450Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && 3460Sstevel@tonic-gate (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) { 3470Sstevel@tonic-gate impl_ddi_sunbus_removechild(child); 3480Sstevel@tonic-gate return (DDI_FAILURE); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate return (DDI_SUCCESS); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /* 3540Sstevel@tonic-gate * A better name for this function would be impl_ddi_sunbus_uninitchild() 3550Sstevel@tonic-gate * It does not remove the child, it uninitializes it, reclaiming the 3560Sstevel@tonic-gate * resources taken by impl_ddi_sunbus_initchild. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate void 3590Sstevel@tonic-gate impl_ddi_sunbus_removechild(dev_info_t *dip) 3600Sstevel@tonic-gate { 3610Sstevel@tonic-gate impl_free_ddi_ppd(dip); 3620Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 3630Sstevel@tonic-gate /* 3640Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate impl_rem_dev_props(dip); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * SECTION: DDI Interrupt 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate void 3740Sstevel@tonic-gate cells_1275_copy(prop_1275_cell_t *from, prop_1275_cell_t *to, int32_t len) 3750Sstevel@tonic-gate { 3760Sstevel@tonic-gate int i; 3770Sstevel@tonic-gate for (i = 0; i < len; i++) 3780Sstevel@tonic-gate *to = *from; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate prop_1275_cell_t * 3820Sstevel@tonic-gate cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len) 3830Sstevel@tonic-gate { 3840Sstevel@tonic-gate prop_1275_cell_t *match_cell = 0; 3850Sstevel@tonic-gate int32_t i; 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate for (i = 0; i < len; i++) 3880Sstevel@tonic-gate if (cell1[i] != cell2[i]) { 3890Sstevel@tonic-gate match_cell = &cell1[i]; 3900Sstevel@tonic-gate break; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate return (match_cell); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * Wrapper functions used by New DDI interrupt framework. 3980Sstevel@tonic-gate */ 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /* 4010Sstevel@tonic-gate * i_ddi_handle_intr_ops: 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate int 4040Sstevel@tonic-gate i_ddi_handle_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 4050Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 4060Sstevel@tonic-gate { 4070Sstevel@tonic-gate ddi_intrspec_t ispec; 4080Sstevel@tonic-gate int ret; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 4110Sstevel@tonic-gate return (i_ddi_intr_ops(dip, rdip, op, hdlp, result)); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate i_ddi_alloc_ispec(dip, hdlp->ih_inum, &ispec); 4140Sstevel@tonic-gate if ((ddi_ispec_t *)ispec == NULL) 4150Sstevel@tonic-gate return (DDI_FAILURE); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate hdlp->ih_private = (void *)ispec; 4180Sstevel@tonic-gate ret = i_ddi_intr_ops(dip, rdip, op, hdlp, result); 4190Sstevel@tonic-gate hdlp->ih_private = NULL; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate i_ddi_free_ispec(ispec); 4220Sstevel@tonic-gate return (ret); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate /* 4260Sstevel@tonic-gate * i_ddi_intr_ops: 4270Sstevel@tonic-gate */ 4280Sstevel@tonic-gate int 4290Sstevel@tonic-gate i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 4300Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 4310Sstevel@tonic-gate { 4320Sstevel@tonic-gate ddi_ispec_t *sav_ip, *ip = NULL; 4330Sstevel@tonic-gate dev_info_t *pdip = ddi_get_parent(dip); 4340Sstevel@tonic-gate int ret = DDI_FAILURE; 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 4370Sstevel@tonic-gate return (process_intr_ops(pdip, rdip, op, hdlp, result)); 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate switch (op) { 4400Sstevel@tonic-gate case DDI_INTROP_ADDISR: 4410Sstevel@tonic-gate case DDI_INTROP_REMISR: 4420Sstevel@tonic-gate case DDI_INTROP_ENABLE: 4430Sstevel@tonic-gate case DDI_INTROP_DISABLE: 4440Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 4450Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 4460Sstevel@tonic-gate /* Save the ispec */ 4470Sstevel@tonic-gate sav_ip = (ddi_ispec_t *)hdlp->ih_private; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * If we have an ispec struct, try and determine our 4510Sstevel@tonic-gate * parent and possibly an interrupt translation. 4520Sstevel@tonic-gate * intr parent dip returned held 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate if ((pdip = get_intr_parent(pdip, dip, sav_ip, &ip)) != NULL) { 4550Sstevel@tonic-gate /* Insert the interrupt info structure */ 4560Sstevel@tonic-gate hdlp->ih_private = (void *)ip; 4570Sstevel@tonic-gate } else 4580Sstevel@tonic-gate goto done; 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate ret = process_intr_ops(pdip, rdip, op, hdlp, result); 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate done: 4640Sstevel@tonic-gate switch (op) { 4650Sstevel@tonic-gate case DDI_INTROP_ADDISR: 4660Sstevel@tonic-gate case DDI_INTROP_REMISR: 4670Sstevel@tonic-gate case DDI_INTROP_ENABLE: 4680Sstevel@tonic-gate case DDI_INTROP_DISABLE: 4690Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 4700Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 4710Sstevel@tonic-gate /* Release hold acquired in get_intr_parent() */ 4720Sstevel@tonic-gate if (pdip) 4730Sstevel@tonic-gate ndi_rele_devi(pdip); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if (ip) { 4760Sstevel@tonic-gate /* Set the PIL according to what the parent did */ 4770Sstevel@tonic-gate sav_ip->is_pil = ip->is_pil; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate /* Free the stacked ispec structure */ 4800Sstevel@tonic-gate i_ddi_free_ispec((ddi_intrspec_t)ip); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate /* Restore the interrupt info */ 4840Sstevel@tonic-gate hdlp->ih_private = (void *)sav_ip; 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate return (ret); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* 4910Sstevel@tonic-gate * process_intr_ops: 4920Sstevel@tonic-gate * 4930Sstevel@tonic-gate * Process the interrupt op via the interrupt parent. 4940Sstevel@tonic-gate */ 4950Sstevel@tonic-gate int 4960Sstevel@tonic-gate process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op, 4970Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 4980Sstevel@tonic-gate { 4990Sstevel@tonic-gate int ret = DDI_FAILURE; 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate if (NEXUS_HAS_INTR_OP(pdip)) { 5020Sstevel@tonic-gate ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops-> 5030Sstevel@tonic-gate bus_intr_op)) (pdip, rdip, op, hdlp, result); 5040Sstevel@tonic-gate } else { 5050Sstevel@tonic-gate cmn_err(CE_WARN, "Failed to process interrupt " 5060Sstevel@tonic-gate "for %s%d due to down-rev nexus driver %s%d", 5070Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 5080Sstevel@tonic-gate ddi_get_name(pdip), ddi_get_instance(pdip)); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate return (ret); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * i_ddi_add_ivintr: 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate /*ARGSUSED*/ 5180Sstevel@tonic-gate int 5190Sstevel@tonic-gate i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp) 5200Sstevel@tonic-gate { 5210Sstevel@tonic-gate /* Sanity check the entry we're about to add */ 5220Sstevel@tonic-gate if (GET_IVINTR(hdlp->ih_vector)) { 5230Sstevel@tonic-gate cmn_err(CE_WARN, "mondo 0x%x in use", hdlp->ih_vector); 5240Sstevel@tonic-gate return (DDI_FAILURE); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* 5280Sstevel@tonic-gate * If the PIL was set and is valid use it, otherwise 5290Sstevel@tonic-gate * default it to 1 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX)) 5320Sstevel@tonic-gate hdlp->ih_pri = 1; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri, 5350Sstevel@tonic-gate (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1, NULL) == 0); 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate return (DDI_SUCCESS); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* 5410Sstevel@tonic-gate * i_ddi_rem_ivintr: 5420Sstevel@tonic-gate */ 5430Sstevel@tonic-gate /*ARGSUSED*/ 5440Sstevel@tonic-gate void 5450Sstevel@tonic-gate i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp) 5460Sstevel@tonic-gate { 5470Sstevel@tonic-gate rem_ivintr(hdlp->ih_vector, NULL); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /* 5510Sstevel@tonic-gate * i_ddi_add_softint - allocate and add a soft interrupt to the system 5520Sstevel@tonic-gate */ 5530Sstevel@tonic-gate int 5540Sstevel@tonic-gate i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp) 5550Sstevel@tonic-gate { 5560Sstevel@tonic-gate uint_t rval; 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate if ((rval = (uint_t)add_softintr(hdlp->ih_pri, 5590Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1)) == 0) { 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate return (DDI_FAILURE); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate hdlp->ih_private = (void *)rval; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate return (DDI_SUCCESS); 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate void 5700Sstevel@tonic-gate i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp) 5710Sstevel@tonic-gate { 5720Sstevel@tonic-gate uint_t intr_id; 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate /* disable */ 5750Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 5760Sstevel@tonic-gate intr_id = (uint_t)hdlp->ih_private; 5770Sstevel@tonic-gate rem_softintr(intr_id); 5780Sstevel@tonic-gate hdlp->ih_private = NULL; 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate int 582*278Sgovinda i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2) 5830Sstevel@tonic-gate { 5840Sstevel@tonic-gate uint_t intr_id; 5850Sstevel@tonic-gate int ret; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate ASSERT(hdlp != NULL); 5880Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate intr_id = (uint_t)hdlp->ih_private; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* update the vector table for the 2nd arg */ 593*278Sgovinda ret = update_softint_arg2(intr_id, arg2); 5940Sstevel@tonic-gate if (ret == DDI_SUCCESS) 5950Sstevel@tonic-gate setsoftint(intr_id); 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate return (ret); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /* ARGSUSED */ 6010Sstevel@tonic-gate int 6020Sstevel@tonic-gate i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri) 6030Sstevel@tonic-gate { 6040Sstevel@tonic-gate uint_t intr_id; 6050Sstevel@tonic-gate int ret; 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate ASSERT(hdlp != NULL); 6080Sstevel@tonic-gate ASSERT(hdlp->ih_private != NULL); 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate intr_id = (uint_t)hdlp->ih_private; 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate /* update the vector table for the new priority */ 6130Sstevel@tonic-gate ret = update_softint_pri(intr_id, hdlp->ih_pri); 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate return (ret); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate /* 6190Sstevel@tonic-gate * Support routine for allocating and initializing an interrupt specification. 6200Sstevel@tonic-gate * The bus interrupt value will be allocated at the end of this structure, so 6210Sstevel@tonic-gate * the corresponding routine i_ddi_free_ispec() should be used to free the 6220Sstevel@tonic-gate * interrupt specification. 6230Sstevel@tonic-gate */ 6240Sstevel@tonic-gate void 6250Sstevel@tonic-gate i_ddi_alloc_ispec(dev_info_t *dip, uint_t inumber, ddi_intrspec_t *intrspecp) 6260Sstevel@tonic-gate { 6270Sstevel@tonic-gate int32_t intrlen, intr_cells, max_intrs; 6280Sstevel@tonic-gate prop_1275_cell_t *ip; 6290Sstevel@tonic-gate prop_1275_cell_t intr_sz; 6300Sstevel@tonic-gate ddi_ispec_t **ispecp = (ddi_ispec_t **)intrspecp; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate *ispecp = NULL; 6330Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS | 6340Sstevel@tonic-gate DDI_PROP_CANSLEEP, 6350Sstevel@tonic-gate "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 6380Sstevel@tonic-gate "#interrupt-cells", 1); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate /* adjust for number of bytes */ 6410Sstevel@tonic-gate intr_sz = CELLS_1275_TO_BYTES(intr_cells); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate /* Calculate the number of interrupts */ 6440Sstevel@tonic-gate max_intrs = intrlen / intr_sz; 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate if (inumber < max_intrs) { 6470Sstevel@tonic-gate prop_1275_cell_t *intrp = ip; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate *ispecp = kmem_zalloc( 6500Sstevel@tonic-gate (sizeof (ddi_ispec_t) + intr_sz), KM_SLEEP); 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate (*ispecp)->is_intr = 6530Sstevel@tonic-gate (uint32_t *)(*ispecp + 1); 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate /* Index into interrupt property */ 6560Sstevel@tonic-gate intrp += (inumber * intr_cells); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate cells_1275_copy(intrp, 6590Sstevel@tonic-gate (*ispecp)->is_intr, intr_cells); 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate (*ispecp)->is_intr_sz = intr_sz; 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate (*ispecp)->is_pil = i_ddi_get_intr_pri(dip, inumber); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate kmem_free(ip, intrlen); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * Analog routine to i_ddi_alloc_ispec() used to free the interrupt 6720Sstevel@tonic-gate * specification and the associated bus interrupt value. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate void 6750Sstevel@tonic-gate i_ddi_free_ispec(ddi_intrspec_t intrspecp) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate ddi_ispec_t *ispecp = (ddi_ispec_t *)intrspecp; 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate kmem_free(ispecp, sizeof (ddi_ispec_t) + (ispecp->is_intr_sz)); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate /* 6830Sstevel@tonic-gate * i_ddi_get_intr_pri - Get the interrupt-priorities property from 6840Sstevel@tonic-gate * the specified device. 6850Sstevel@tonic-gate */ 6860Sstevel@tonic-gate uint32_t 6870Sstevel@tonic-gate i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber) 6880Sstevel@tonic-gate { 6890Sstevel@tonic-gate uint32_t *intr_prio_p; 6900Sstevel@tonic-gate uint32_t pri = 0; 6910Sstevel@tonic-gate int32_t i; 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate /* 6940Sstevel@tonic-gate * Use the "interrupt-priorities" property to determine the 6950Sstevel@tonic-gate * the pil/ipl for the interrupt handler. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 6980Sstevel@tonic-gate "interrupt-priorities", (caddr_t)&intr_prio_p, 6990Sstevel@tonic-gate &i) == DDI_SUCCESS) { 7000Sstevel@tonic-gate if (inumber < (i / sizeof (int32_t))) 7010Sstevel@tonic-gate pri = intr_prio_p[inumber]; 7020Sstevel@tonic-gate kmem_free(intr_prio_p, i); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate return (pri); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* 7090Sstevel@tonic-gate * SECTION: DDI Memory/DMA 7100Sstevel@tonic-gate */ 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate static vmem_t *little_endian_arena; 7130Sstevel@tonic-gate static vmem_t *big_endian_arena; 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate static void * 7160Sstevel@tonic-gate segkmem_alloc_le(vmem_t *vmp, size_t size, int flag) 7170Sstevel@tonic-gate { 7180Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE, 7190Sstevel@tonic-gate segkmem_page_create, NULL)); 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate static void * 7230Sstevel@tonic-gate segkmem_alloc_be(vmem_t *vmp, size_t size, int flag) 7240Sstevel@tonic-gate { 7250Sstevel@tonic-gate return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE, 7260Sstevel@tonic-gate segkmem_page_create, NULL)); 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate void 7300Sstevel@tonic-gate ka_init(void) 7310Sstevel@tonic-gate { 7320Sstevel@tonic-gate little_endian_arena = vmem_create("little_endian", NULL, 0, 1, 7330Sstevel@tonic-gate segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP); 7340Sstevel@tonic-gate big_endian_arena = vmem_create("big_endian", NULL, 0, 1, 7350Sstevel@tonic-gate segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate /* 7390Sstevel@tonic-gate * Allocate from the system, aligned on a specific boundary. 7400Sstevel@tonic-gate * The alignment, if non-zero, must be a power of 2. 7410Sstevel@tonic-gate */ 7420Sstevel@tonic-gate static void * 7430Sstevel@tonic-gate kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags) 7440Sstevel@tonic-gate { 7450Sstevel@tonic-gate size_t *addr, *raddr, rsize; 7460Sstevel@tonic-gate size_t hdrsize = 4 * sizeof (size_t); /* must be power of 2 */ 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate align = MAX(align, hdrsize); 7490Sstevel@tonic-gate ASSERT((align & (align - 1)) == 0); 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate /* 7520Sstevel@tonic-gate * We need to allocate 7530Sstevel@tonic-gate * rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment) 7540Sstevel@tonic-gate * bytes to be sure we have enough freedom to satisfy the request. 7550Sstevel@tonic-gate * Since the buffer alignment depends on the request size, this is 7560Sstevel@tonic-gate * not straightforward to use directly. 7570Sstevel@tonic-gate * 7580Sstevel@tonic-gate * kmem guarantees that any allocation of a 64-byte multiple will be 7590Sstevel@tonic-gate * 64-byte aligned. Since rounding up the request could add more 7600Sstevel@tonic-gate * than we save, we compute the size with and without alignment, and 7610Sstevel@tonic-gate * use the smaller of the two. 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate rsize = size + hdrsize + align; 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate if (endian_flags == DDI_STRUCTURE_LE_ACC) { 7660Sstevel@tonic-gate raddr = vmem_alloc(little_endian_arena, rsize, 7670Sstevel@tonic-gate cansleep ? VM_SLEEP : VM_NOSLEEP); 7680Sstevel@tonic-gate } else { 7690Sstevel@tonic-gate raddr = vmem_alloc(big_endian_arena, rsize, 7700Sstevel@tonic-gate cansleep ? VM_SLEEP : VM_NOSLEEP); 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate if (raddr == NULL) 7740Sstevel@tonic-gate return (NULL); 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align); 7770Sstevel@tonic-gate ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize); 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate addr[-3] = (size_t)endian_flags; 7800Sstevel@tonic-gate addr[-2] = (size_t)raddr; 7810Sstevel@tonic-gate addr[-1] = rsize; 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate return (addr); 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate static void 7870Sstevel@tonic-gate kfreea(void *addr) 7880Sstevel@tonic-gate { 7890Sstevel@tonic-gate size_t *saddr = addr; 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate if (saddr[-3] == DDI_STRUCTURE_LE_ACC) 7920Sstevel@tonic-gate vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]); 7930Sstevel@tonic-gate else 7940Sstevel@tonic-gate vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate int 7980Sstevel@tonic-gate i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr, 7990Sstevel@tonic-gate size_t length, int cansleep, int streaming, 8000Sstevel@tonic-gate ddi_device_acc_attr_t *accattrp, 8010Sstevel@tonic-gate caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep) 8020Sstevel@tonic-gate { 8030Sstevel@tonic-gate caddr_t a; 8040Sstevel@tonic-gate int iomin, align; 8050Sstevel@tonic-gate uint_t endian_flags = DDI_NEVERSWAP_ACC; 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate #if defined(lint) 8080Sstevel@tonic-gate *handlep = *handlep; 8090Sstevel@tonic-gate #endif 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate /* 8120Sstevel@tonic-gate * Check legality of arguments 8130Sstevel@tonic-gate */ 8140Sstevel@tonic-gate if (length == 0 || kaddrp == NULL || attr == NULL) { 8150Sstevel@tonic-gate return (DDI_FAILURE); 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 || 8180Sstevel@tonic-gate (attr->dma_attr_align & (attr->dma_attr_align - 1)) || 8190Sstevel@tonic-gate (attr->dma_attr_minxfer & (attr->dma_attr_minxfer - 1))) { 8200Sstevel@tonic-gate return (DDI_FAILURE); 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * Drivers for 64-bit capable SBus devices will encode 8250Sstevel@tonic-gate * the burtsizes for 64-bit xfers in the upper 16-bits. 8260Sstevel@tonic-gate * For DMA alignment, we use the most restrictive 8270Sstevel@tonic-gate * alignment of 32-bit and 64-bit xfers. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate iomin = (attr->dma_attr_burstsizes & 0xffff) | 8300Sstevel@tonic-gate ((attr->dma_attr_burstsizes >> 16) & 0xffff); 8310Sstevel@tonic-gate /* 8320Sstevel@tonic-gate * If a driver set burtsizes to 0, we give him byte alignment. 8330Sstevel@tonic-gate * Otherwise align at the burtsizes boundary. 8340Sstevel@tonic-gate */ 8350Sstevel@tonic-gate if (iomin == 0) 8360Sstevel@tonic-gate iomin = 1; 8370Sstevel@tonic-gate else 8380Sstevel@tonic-gate iomin = 1 << (ddi_fls(iomin) - 1); 8390Sstevel@tonic-gate iomin = maxbit(iomin, attr->dma_attr_minxfer); 8400Sstevel@tonic-gate iomin = maxbit(iomin, attr->dma_attr_align); 8410Sstevel@tonic-gate iomin = ddi_iomin(dip, iomin, streaming); 8420Sstevel@tonic-gate if (iomin == 0) 8430Sstevel@tonic-gate return (DDI_FAILURE); 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate ASSERT((iomin & (iomin - 1)) == 0); 8460Sstevel@tonic-gate ASSERT(iomin >= attr->dma_attr_minxfer); 8470Sstevel@tonic-gate ASSERT(iomin >= attr->dma_attr_align); 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate length = P2ROUNDUP(length, iomin); 8500Sstevel@tonic-gate align = iomin; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate if (accattrp != NULL) 8530Sstevel@tonic-gate endian_flags = accattrp->devacc_attr_endian_flags; 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate a = kalloca(length, align, cansleep, endian_flags); 8560Sstevel@tonic-gate if ((*kaddrp = a) == 0) { 8570Sstevel@tonic-gate return (DDI_FAILURE); 8580Sstevel@tonic-gate } else { 8590Sstevel@tonic-gate if (real_length) { 8600Sstevel@tonic-gate *real_length = length; 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate if (handlep) { 8630Sstevel@tonic-gate /* 8640Sstevel@tonic-gate * assign handle information 8650Sstevel@tonic-gate */ 8660Sstevel@tonic-gate impl_acc_hdl_init(handlep); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate return (DDI_SUCCESS); 8690Sstevel@tonic-gate } 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate /* 8730Sstevel@tonic-gate * covert old DMA limits structure to DMA attribute structure 8740Sstevel@tonic-gate * and continue 8750Sstevel@tonic-gate */ 8760Sstevel@tonic-gate int 8770Sstevel@tonic-gate i_ddi_mem_alloc_lim(dev_info_t *dip, ddi_dma_lim_t *limits, 8780Sstevel@tonic-gate size_t length, int cansleep, int streaming, 8790Sstevel@tonic-gate ddi_device_acc_attr_t *accattrp, caddr_t *kaddrp, 8800Sstevel@tonic-gate uint_t *real_length, ddi_acc_hdl_t *ap) 8810Sstevel@tonic-gate { 8820Sstevel@tonic-gate ddi_dma_attr_t dma_attr, *attrp; 8830Sstevel@tonic-gate size_t rlen; 8840Sstevel@tonic-gate int ret; 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate ASSERT(limits); 8870Sstevel@tonic-gate attrp = &dma_attr; 8880Sstevel@tonic-gate attrp->dma_attr_version = DMA_ATTR_V0; 8890Sstevel@tonic-gate attrp->dma_attr_addr_lo = (uint64_t)limits->dlim_addr_lo; 8900Sstevel@tonic-gate attrp->dma_attr_addr_hi = (uint64_t)limits->dlim_addr_hi; 8910Sstevel@tonic-gate attrp->dma_attr_count_max = (uint64_t)-1; 8920Sstevel@tonic-gate attrp->dma_attr_align = 1; 8930Sstevel@tonic-gate attrp->dma_attr_burstsizes = (uint_t)limits->dlim_burstsizes; 8940Sstevel@tonic-gate attrp->dma_attr_minxfer = (uint32_t)limits->dlim_minxfer; 8950Sstevel@tonic-gate attrp->dma_attr_maxxfer = (uint64_t)-1; 8960Sstevel@tonic-gate attrp->dma_attr_seg = (uint64_t)limits->dlim_cntr_max; 8970Sstevel@tonic-gate attrp->dma_attr_sgllen = 1; 8980Sstevel@tonic-gate attrp->dma_attr_granular = 1; 8990Sstevel@tonic-gate attrp->dma_attr_flags = 0; 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate ret = i_ddi_mem_alloc(dip, attrp, length, cansleep, streaming, 9020Sstevel@tonic-gate accattrp, kaddrp, &rlen, ap); 9030Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 9040Sstevel@tonic-gate if (real_length) 9050Sstevel@tonic-gate *real_length = (uint_t)rlen; 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate return (ret); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate /* ARGSUSED */ 9110Sstevel@tonic-gate void 9120Sstevel@tonic-gate i_ddi_mem_free(caddr_t kaddr, int stream) 9130Sstevel@tonic-gate { 9140Sstevel@tonic-gate kfreea(kaddr); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate /* 9180Sstevel@tonic-gate * SECTION: DDI Data Access 9190Sstevel@tonic-gate */ 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate static uintptr_t impl_acc_hdl_id = 0; 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate /* 9240Sstevel@tonic-gate * access handle allocator 9250Sstevel@tonic-gate */ 9260Sstevel@tonic-gate ddi_acc_hdl_t * 9270Sstevel@tonic-gate impl_acc_hdl_get(ddi_acc_handle_t hdl) 9280Sstevel@tonic-gate { 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * Extract the access handle address from the DDI implemented 9310Sstevel@tonic-gate * access handle 9320Sstevel@tonic-gate */ 9330Sstevel@tonic-gate return (&((ddi_acc_impl_t *)hdl)->ahi_common); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate ddi_acc_handle_t 9370Sstevel@tonic-gate impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg) 9380Sstevel@tonic-gate { 9390Sstevel@tonic-gate ddi_acc_impl_t *hp; 9400Sstevel@tonic-gate on_trap_data_t *otp; 9410Sstevel@tonic-gate int sleepflag; 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate /* 9460Sstevel@tonic-gate * Allocate and initialize the data access handle and error status. 9470Sstevel@tonic-gate */ 9480Sstevel@tonic-gate if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL) 9490Sstevel@tonic-gate goto fail; 9500Sstevel@tonic-gate if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc( 9510Sstevel@tonic-gate sizeof (ndi_err_t), sleepflag)) == NULL) { 9520Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 9530Sstevel@tonic-gate goto fail; 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate if ((otp = (on_trap_data_t *)kmem_zalloc( 9560Sstevel@tonic-gate sizeof (on_trap_data_t), sleepflag)) == NULL) { 9570Sstevel@tonic-gate kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 9580Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 9590Sstevel@tonic-gate goto fail; 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate hp->ahi_err->err_ontrap = otp; 9620Sstevel@tonic-gate hp->ahi_common.ah_platform_private = (void *)hp; 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate return ((ddi_acc_handle_t)hp); 9650Sstevel@tonic-gate fail: 9660Sstevel@tonic-gate if ((waitfp != (int (*)())KM_SLEEP) && 9670Sstevel@tonic-gate (waitfp != (int (*)())KM_NOSLEEP)) 9680Sstevel@tonic-gate ddi_set_callback(waitfp, arg, &impl_acc_hdl_id); 9690Sstevel@tonic-gate return (NULL); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate void 9730Sstevel@tonic-gate impl_acc_hdl_free(ddi_acc_handle_t handle) 9740Sstevel@tonic-gate { 9750Sstevel@tonic-gate ddi_acc_impl_t *hp; 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /* 9780Sstevel@tonic-gate * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *), 9790Sstevel@tonic-gate * because that's what we allocated in impl_acc_hdl_alloc() above. 9800Sstevel@tonic-gate */ 9810Sstevel@tonic-gate hp = (ddi_acc_impl_t *)handle; 9820Sstevel@tonic-gate if (hp) { 9830Sstevel@tonic-gate kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t)); 9840Sstevel@tonic-gate kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 9850Sstevel@tonic-gate kmem_free(hp, sizeof (ddi_acc_impl_t)); 9860Sstevel@tonic-gate if (impl_acc_hdl_id) 9870Sstevel@tonic-gate ddi_run_callback(&impl_acc_hdl_id); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate void 9920Sstevel@tonic-gate impl_acc_err_init(ddi_acc_hdl_t *handlep) 9930Sstevel@tonic-gate { 9940Sstevel@tonic-gate int fmcap; 9950Sstevel@tonic-gate ndi_err_t *errp; 9960Sstevel@tonic-gate on_trap_data_t *otp; 9970Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep; 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate fmcap = ddi_fm_capable(handlep->ah_dip); 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 || 10020Sstevel@tonic-gate !DDI_FM_ACC_ERR_CAP(fmcap)) { 10030Sstevel@tonic-gate handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC; 10040Sstevel@tonic-gate } else if (DDI_FM_ACC_ERR_CAP(fmcap)) { 10050Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) { 10060Sstevel@tonic-gate i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP, 10070Sstevel@tonic-gate NULL, DDI_NOSLEEP); 10080Sstevel@tonic-gate } else { 10090Sstevel@tonic-gate errp = hp->ahi_err; 10100Sstevel@tonic-gate otp = (on_trap_data_t *)errp->err_ontrap; 10110Sstevel@tonic-gate otp->ot_handle = (void *)(hp); 10120Sstevel@tonic-gate otp->ot_prot = OT_DATA_ACCESS; 10130Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_access == 10140Sstevel@tonic-gate DDI_CAUTIOUS_ACC) 10150Sstevel@tonic-gate otp->ot_trampoline = 10160Sstevel@tonic-gate (uintptr_t)&i_ddi_caut_trampoline; 10170Sstevel@tonic-gate else 10180Sstevel@tonic-gate otp->ot_trampoline = 10190Sstevel@tonic-gate (uintptr_t)&i_ddi_prot_trampoline; 10200Sstevel@tonic-gate errp->err_status = DDI_FM_OK; 10210Sstevel@tonic-gate errp->err_expected = DDI_FM_ERR_UNEXPECTED; 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate void 10270Sstevel@tonic-gate impl_acc_hdl_init(ddi_acc_hdl_t *handlep) 10280Sstevel@tonic-gate { 10290Sstevel@tonic-gate ddi_acc_impl_t *hp; 10300Sstevel@tonic-gate 10310Sstevel@tonic-gate ASSERT(handlep); 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate hp = (ddi_acc_impl_t *)handlep; 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate /* 10360Sstevel@tonic-gate * check for SW byte-swapping 10370Sstevel@tonic-gate */ 10380Sstevel@tonic-gate hp->ahi_get8 = i_ddi_get8; 10390Sstevel@tonic-gate hp->ahi_put8 = i_ddi_put8; 10400Sstevel@tonic-gate hp->ahi_rep_get8 = i_ddi_rep_get8; 10410Sstevel@tonic-gate hp->ahi_rep_put8 = i_ddi_rep_put8; 10420Sstevel@tonic-gate if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) { 10430Sstevel@tonic-gate hp->ahi_get16 = i_ddi_swap_get16; 10440Sstevel@tonic-gate hp->ahi_get32 = i_ddi_swap_get32; 10450Sstevel@tonic-gate hp->ahi_get64 = i_ddi_swap_get64; 10460Sstevel@tonic-gate hp->ahi_put16 = i_ddi_swap_put16; 10470Sstevel@tonic-gate hp->ahi_put32 = i_ddi_swap_put32; 10480Sstevel@tonic-gate hp->ahi_put64 = i_ddi_swap_put64; 10490Sstevel@tonic-gate hp->ahi_rep_get16 = i_ddi_swap_rep_get16; 10500Sstevel@tonic-gate hp->ahi_rep_get32 = i_ddi_swap_rep_get32; 10510Sstevel@tonic-gate hp->ahi_rep_get64 = i_ddi_swap_rep_get64; 10520Sstevel@tonic-gate hp->ahi_rep_put16 = i_ddi_swap_rep_put16; 10530Sstevel@tonic-gate hp->ahi_rep_put32 = i_ddi_swap_rep_put32; 10540Sstevel@tonic-gate hp->ahi_rep_put64 = i_ddi_swap_rep_put64; 10550Sstevel@tonic-gate } else { 10560Sstevel@tonic-gate hp->ahi_get16 = i_ddi_get16; 10570Sstevel@tonic-gate hp->ahi_get32 = i_ddi_get32; 10580Sstevel@tonic-gate hp->ahi_get64 = i_ddi_get64; 10590Sstevel@tonic-gate hp->ahi_put16 = i_ddi_put16; 10600Sstevel@tonic-gate hp->ahi_put32 = i_ddi_put32; 10610Sstevel@tonic-gate hp->ahi_put64 = i_ddi_put64; 10620Sstevel@tonic-gate hp->ahi_rep_get16 = i_ddi_rep_get16; 10630Sstevel@tonic-gate hp->ahi_rep_get32 = i_ddi_rep_get32; 10640Sstevel@tonic-gate hp->ahi_rep_get64 = i_ddi_rep_get64; 10650Sstevel@tonic-gate hp->ahi_rep_put16 = i_ddi_rep_put16; 10660Sstevel@tonic-gate hp->ahi_rep_put32 = i_ddi_rep_put32; 10670Sstevel@tonic-gate hp->ahi_rep_put64 = i_ddi_rep_put64; 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate /* Legacy fault flags and support */ 10710Sstevel@tonic-gate hp->ahi_fault_check = i_ddi_acc_fault_check; 10720Sstevel@tonic-gate hp->ahi_fault_notify = i_ddi_acc_fault_notify; 10730Sstevel@tonic-gate hp->ahi_fault = 0; 10740Sstevel@tonic-gate impl_acc_err_init(handlep); 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate void 10780Sstevel@tonic-gate i_ddi_acc_set_fault(ddi_acc_handle_t handle) 10790Sstevel@tonic-gate { 10800Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate if (!hp->ahi_fault) { 10830Sstevel@tonic-gate hp->ahi_fault = 1; 10840Sstevel@tonic-gate (*hp->ahi_fault_notify)(hp); 10850Sstevel@tonic-gate } 10860Sstevel@tonic-gate } 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate void 10890Sstevel@tonic-gate i_ddi_acc_clr_fault(ddi_acc_handle_t handle) 10900Sstevel@tonic-gate { 10910Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate if (hp->ahi_fault) { 10940Sstevel@tonic-gate hp->ahi_fault = 0; 10950Sstevel@tonic-gate (*hp->ahi_fault_notify)(hp); 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate /* ARGSUSED */ 11000Sstevel@tonic-gate void 11010Sstevel@tonic-gate i_ddi_acc_fault_notify(ddi_acc_impl_t *hp) 11020Sstevel@tonic-gate { 11030Sstevel@tonic-gate /* Default version, does nothing */ 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate /* 11070Sstevel@tonic-gate * SECTION: Misc functions 11080Sstevel@tonic-gate */ 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate /* 11110Sstevel@tonic-gate * instance wrappers 11120Sstevel@tonic-gate */ 11130Sstevel@tonic-gate /*ARGSUSED*/ 11140Sstevel@tonic-gate uint_t 11150Sstevel@tonic-gate impl_assign_instance(dev_info_t *dip) 11160Sstevel@tonic-gate { 11170Sstevel@tonic-gate return ((uint_t)-1); 11180Sstevel@tonic-gate } 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate /*ARGSUSED*/ 11210Sstevel@tonic-gate int 11220Sstevel@tonic-gate impl_keep_instance(dev_info_t *dip) 11230Sstevel@tonic-gate { 11240Sstevel@tonic-gate return (DDI_FAILURE); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate /*ARGSUSED*/ 11280Sstevel@tonic-gate int 11290Sstevel@tonic-gate impl_free_instance(dev_info_t *dip) 11300Sstevel@tonic-gate { 11310Sstevel@tonic-gate return (DDI_FAILURE); 11320Sstevel@tonic-gate } 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate /*ARGSUSED*/ 11350Sstevel@tonic-gate int 11360Sstevel@tonic-gate impl_check_cpu(dev_info_t *devi) 11370Sstevel@tonic-gate { 11380Sstevel@tonic-gate return (DDI_SUCCESS); 11390Sstevel@tonic-gate } 11400Sstevel@tonic-gate 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate static const char *nocopydevs[] = { 11430Sstevel@tonic-gate "SUNW,ffb", 11440Sstevel@tonic-gate "SUNW,afb", 11450Sstevel@tonic-gate NULL 11460Sstevel@tonic-gate }; 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate /* 11490Sstevel@tonic-gate * Perform a copy from a memory mapped device (whose devinfo pointer is devi) 11500Sstevel@tonic-gate * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. 11510Sstevel@tonic-gate */ 11520Sstevel@tonic-gate /*ARGSUSED*/ 11530Sstevel@tonic-gate int 11540Sstevel@tonic-gate e_ddi_copyfromdev(dev_info_t *devi, 11550Sstevel@tonic-gate off_t off, const void *devaddr, void *kaddr, size_t len) 11560Sstevel@tonic-gate { 11570Sstevel@tonic-gate const char **argv; 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate for (argv = nocopydevs; *argv; argv++) 11600Sstevel@tonic-gate if (strcmp(ddi_binding_name(devi), *argv) == 0) { 11610Sstevel@tonic-gate bzero(kaddr, len); 11620Sstevel@tonic-gate return (0); 11630Sstevel@tonic-gate } 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate bcopy(devaddr, kaddr, len); 11660Sstevel@tonic-gate return (0); 11670Sstevel@tonic-gate } 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate /* 11700Sstevel@tonic-gate * Perform a copy to a memory mapped device (whose devinfo pointer is devi) 11710Sstevel@tonic-gate * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. 11720Sstevel@tonic-gate */ 11730Sstevel@tonic-gate /*ARGSUSED*/ 11740Sstevel@tonic-gate int 11750Sstevel@tonic-gate e_ddi_copytodev(dev_info_t *devi, 11760Sstevel@tonic-gate off_t off, const void *kaddr, void *devaddr, size_t len) 11770Sstevel@tonic-gate { 11780Sstevel@tonic-gate const char **argv; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate for (argv = nocopydevs; *argv; argv++) 11810Sstevel@tonic-gate if (strcmp(ddi_binding_name(devi), *argv) == 0) 11820Sstevel@tonic-gate return (1); 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate bcopy(kaddr, devaddr, len); 11850Sstevel@tonic-gate return (0); 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate /* 11890Sstevel@tonic-gate * Boot Configuration 11900Sstevel@tonic-gate */ 11910Sstevel@tonic-gate idprom_t idprom; 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate /* 11940Sstevel@tonic-gate * Configure the hardware on the system. 11950Sstevel@tonic-gate * Called before the rootfs is mounted 11960Sstevel@tonic-gate */ 11970Sstevel@tonic-gate void 11980Sstevel@tonic-gate configure(void) 11990Sstevel@tonic-gate { 12000Sstevel@tonic-gate extern void i_ddi_init_root(); 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate /* We better have released boot by this time! */ 12030Sstevel@tonic-gate ASSERT(!bootops); 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate /* 12060Sstevel@tonic-gate * Determine whether or not to use the fpu, V9 SPARC cpus 12070Sstevel@tonic-gate * always have one. Could check for existence of a fp queue, 12080Sstevel@tonic-gate * Ultra I, II and IIa do not have a fp queue. 12090Sstevel@tonic-gate */ 12100Sstevel@tonic-gate if (fpu_exists) 12110Sstevel@tonic-gate fpu_probe(); 12120Sstevel@tonic-gate else 12130Sstevel@tonic-gate cmn_err(CE_CONT, "FPU not in use\n"); 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate #if 0 /* XXXQ - not necessary for sun4u */ 12160Sstevel@tonic-gate /* 12170Sstevel@tonic-gate * This following line fixes bugid 1041296; we need to do a 12180Sstevel@tonic-gate * prom_nextnode(0) because this call ALSO patches the DMA+ 12190Sstevel@tonic-gate * bug in Campus-B and Phoenix. The prom uncaches the traptable 12200Sstevel@tonic-gate * page as a side-effect of devr_next(0) (which prom_nextnode calls), 12210Sstevel@tonic-gate * so this *must* be executed early on. (XXX This is untrue for sun4u) 12220Sstevel@tonic-gate */ 12230Sstevel@tonic-gate (void) prom_nextnode((dnode_t)0); 12240Sstevel@tonic-gate #endif 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate /* 12270Sstevel@tonic-gate * Initialize devices on the machine. 12280Sstevel@tonic-gate * Uses configuration tree built by the PROMs to determine what 12290Sstevel@tonic-gate * is present, and builds a tree of prototype dev_info nodes 12300Sstevel@tonic-gate * corresponding to the hardware which identified itself. 12310Sstevel@tonic-gate */ 12320Sstevel@tonic-gate i_ddi_init_root(); 12330Sstevel@tonic-gate 12340Sstevel@tonic-gate #ifdef DDI_PROP_DEBUG 12350Sstevel@tonic-gate (void) ddi_prop_debug(1); /* Enable property debugging */ 12360Sstevel@tonic-gate #endif /* DDI_PROP_DEBUG */ 12370Sstevel@tonic-gate } 12380Sstevel@tonic-gate 12390Sstevel@tonic-gate /* 12400Sstevel@tonic-gate * The "status" property indicates the operational status of a device. 12410Sstevel@tonic-gate * If this property is present, the value is a string indicating the 12420Sstevel@tonic-gate * status of the device as follows: 12430Sstevel@tonic-gate * 12440Sstevel@tonic-gate * "okay" operational. 12450Sstevel@tonic-gate * "disabled" not operational, but might become operational. 12460Sstevel@tonic-gate * "fail" not operational because a fault has been detected, 12470Sstevel@tonic-gate * and it is unlikely that the device will become 12480Sstevel@tonic-gate * operational without repair. no additional details 12490Sstevel@tonic-gate * are available. 12500Sstevel@tonic-gate * "fail-xxx" not operational because a fault has been detected, 12510Sstevel@tonic-gate * and it is unlikely that the device will become 12520Sstevel@tonic-gate * operational without repair. "xxx" is additional 12530Sstevel@tonic-gate * human-readable information about the particular 12540Sstevel@tonic-gate * fault condition that was detected. 12550Sstevel@tonic-gate * 12560Sstevel@tonic-gate * The absence of this property means that the operational status is 12570Sstevel@tonic-gate * unknown or okay. 12580Sstevel@tonic-gate * 12590Sstevel@tonic-gate * This routine checks the status property of the specified device node 12600Sstevel@tonic-gate * and returns 0 if the operational status indicates failure, and 1 otherwise. 12610Sstevel@tonic-gate * 12620Sstevel@tonic-gate * The property may exist on plug-in cards the existed before IEEE 1275-1994. 12630Sstevel@tonic-gate * And, in that case, the property may not even be a string. So we carefully 12640Sstevel@tonic-gate * check for the value "fail", in the beginning of the string, noting 12650Sstevel@tonic-gate * the property length. 12660Sstevel@tonic-gate */ 12670Sstevel@tonic-gate int 12680Sstevel@tonic-gate status_okay(int id, char *buf, int buflen) 12690Sstevel@tonic-gate { 12700Sstevel@tonic-gate char status_buf[OBP_MAXPROPNAME]; 12710Sstevel@tonic-gate char *bufp = buf; 12720Sstevel@tonic-gate int len = buflen; 12730Sstevel@tonic-gate int proplen; 12740Sstevel@tonic-gate static const char *status = "status"; 12750Sstevel@tonic-gate static const char *fail = "fail"; 12760Sstevel@tonic-gate size_t fail_len = strlen(fail); 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate /* 12790Sstevel@tonic-gate * Get the proplen ... if it's smaller than "fail", 12800Sstevel@tonic-gate * or doesn't exist ... then we don't care, since 12810Sstevel@tonic-gate * the value can't begin with the char string "fail". 12820Sstevel@tonic-gate * 12830Sstevel@tonic-gate * NB: proplen, if it's a string, includes the NULL in the 12840Sstevel@tonic-gate * the size of the property, and fail_len does not. 12850Sstevel@tonic-gate */ 12860Sstevel@tonic-gate proplen = prom_getproplen((dnode_t)id, (caddr_t)status); 12870Sstevel@tonic-gate if (proplen <= fail_len) /* nonexistent or uninteresting len */ 12880Sstevel@tonic-gate return (1); 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate /* 12910Sstevel@tonic-gate * if a buffer was provided, use it 12920Sstevel@tonic-gate */ 12930Sstevel@tonic-gate if ((buf == (char *)NULL) || (buflen <= 0)) { 12940Sstevel@tonic-gate bufp = status_buf; 12950Sstevel@tonic-gate len = sizeof (status_buf); 12960Sstevel@tonic-gate } 12970Sstevel@tonic-gate *bufp = (char)0; 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* 13000Sstevel@tonic-gate * Get the property into the buffer, to the extent of the buffer, 13010Sstevel@tonic-gate * and in case the buffer is smaller than the property size, 13020Sstevel@tonic-gate * NULL terminate the buffer. (This handles the case where 13030Sstevel@tonic-gate * a buffer was passed in and the caller wants to print the 13040Sstevel@tonic-gate * value, but the buffer was too small). 13050Sstevel@tonic-gate */ 13060Sstevel@tonic-gate (void) prom_bounded_getprop((dnode_t)id, (caddr_t)status, 13070Sstevel@tonic-gate (caddr_t)bufp, len); 13080Sstevel@tonic-gate *(bufp + len - 1) = (char)0; 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate /* 13110Sstevel@tonic-gate * If the value begins with the char string "fail", 13120Sstevel@tonic-gate * then it means the node is failed. We don't care 13130Sstevel@tonic-gate * about any other values. We assume the node is ok 13140Sstevel@tonic-gate * although it might be 'disabled'. 13150Sstevel@tonic-gate */ 13160Sstevel@tonic-gate if (strncmp(bufp, fail, fail_len) == 0) 13170Sstevel@tonic-gate return (0); 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate return (1); 13200Sstevel@tonic-gate } 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate /* 13240Sstevel@tonic-gate * We set the cpu type from the idprom, if we can. 13250Sstevel@tonic-gate * Note that we just read out the contents of it, for the most part. 13260Sstevel@tonic-gate */ 13270Sstevel@tonic-gate void 13280Sstevel@tonic-gate setcputype(void) 13290Sstevel@tonic-gate { 13300Sstevel@tonic-gate /* 13310Sstevel@tonic-gate * We cache the idprom info early on so that we don't 13320Sstevel@tonic-gate * rummage through the NVRAM unnecessarily later. 13330Sstevel@tonic-gate */ 13340Sstevel@tonic-gate (void) prom_getidprom((caddr_t)&idprom, sizeof (idprom)); 13350Sstevel@tonic-gate } 13360Sstevel@tonic-gate 13370Sstevel@tonic-gate /* 13380Sstevel@tonic-gate * Here is where we actually infer meanings to the members of idprom_t 13390Sstevel@tonic-gate */ 13400Sstevel@tonic-gate void 13410Sstevel@tonic-gate parse_idprom(void) 13420Sstevel@tonic-gate { 13430Sstevel@tonic-gate if (idprom.id_format == IDFORM_1) { 13440Sstevel@tonic-gate uint_t i; 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate (void) localetheraddr((struct ether_addr *)idprom.id_ether, 13470Sstevel@tonic-gate (struct ether_addr *)NULL); 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate i = idprom.id_machine << 24; 13500Sstevel@tonic-gate i = i + idprom.id_serial; 13510Sstevel@tonic-gate numtos((ulong_t)i, hw_serial); 13520Sstevel@tonic-gate } else 13530Sstevel@tonic-gate prom_printf("Invalid format code in IDprom.\n"); 13540Sstevel@tonic-gate } 13550Sstevel@tonic-gate 13560Sstevel@tonic-gate /* 13570Sstevel@tonic-gate * Allow for implementation specific correction of PROM property values. 13580Sstevel@tonic-gate */ 13590Sstevel@tonic-gate /*ARGSUSED*/ 13600Sstevel@tonic-gate void 13610Sstevel@tonic-gate impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len, 13620Sstevel@tonic-gate caddr_t buffer) 13630Sstevel@tonic-gate { 13640Sstevel@tonic-gate /* 13650Sstevel@tonic-gate * There are no adjustments needed in this implementation. 13660Sstevel@tonic-gate */ 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate /* 13700Sstevel@tonic-gate * SECTION: DDI Interrupt 13710Sstevel@tonic-gate */ 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate /* 13740Sstevel@tonic-gate * get_intr_parent() is a generic routine that process a 1275 interrupt 13750Sstevel@tonic-gate * map (imap) property. This function returns a dev_info_t structure 13760Sstevel@tonic-gate * which claims ownership of the interrupt domain. 13770Sstevel@tonic-gate * It also returns the new interrupt translation within this new domain. 13780Sstevel@tonic-gate * If an interrupt-parent or interrupt-map property are not found, 13790Sstevel@tonic-gate * then we fallback to using the device tree's parent. 13800Sstevel@tonic-gate * 13810Sstevel@tonic-gate * imap entry format: 13820Sstevel@tonic-gate * <reg>,<interrupt>,<phandle>,<translated interrupt> 13830Sstevel@tonic-gate * reg - The register specification in the interrupts domain 13840Sstevel@tonic-gate * interrupt - The interrupt specification 13850Sstevel@tonic-gate * phandle - PROM handle of the device that owns the xlated interrupt domain 13860Sstevel@tonic-gate * translated interrupt - interrupt specifier in the parents domain 13870Sstevel@tonic-gate * note: <reg>,<interrupt> - The reg and interrupt can be combined to create 13880Sstevel@tonic-gate * a unique entry called a unit interrupt specifier. 13890Sstevel@tonic-gate * 13900Sstevel@tonic-gate * Here's the processing steps: 13910Sstevel@tonic-gate * step1 - If the interrupt-parent property exists, create the ispec and 13920Sstevel@tonic-gate * return the dip of the interrupt parent. 13930Sstevel@tonic-gate * step2 - Extract the interrupt-map property and the interrupt-map-mask 13940Sstevel@tonic-gate * If these don't exist, just return the device tree parent. 13950Sstevel@tonic-gate * step3 - build up the unit interrupt specifier to match against the 13960Sstevel@tonic-gate * interrupt map property 13970Sstevel@tonic-gate * step4 - Scan the interrupt-map property until a match is found 13980Sstevel@tonic-gate * step4a - Extract the interrupt parent 13990Sstevel@tonic-gate * step4b - Compare the unit interrupt specifier 14000Sstevel@tonic-gate */ 14010Sstevel@tonic-gate dev_info_t * 14020Sstevel@tonic-gate get_intr_parent(dev_info_t *pdip, dev_info_t *dip, 14030Sstevel@tonic-gate ddi_ispec_t *child_ispecp, ddi_ispec_t **new_ispecp) 14040Sstevel@tonic-gate { 14050Sstevel@tonic-gate prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req; 14060Sstevel@tonic-gate int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz, 14070Sstevel@tonic-gate addr_cells, intr_cells, reg_len, i, j; 14080Sstevel@tonic-gate int32_t match_found = 0; 14090Sstevel@tonic-gate dev_info_t *intr_parent_dip = NULL; 14100Sstevel@tonic-gate ddi_ispec_t *ispecp; 14110Sstevel@tonic-gate uint32_t *intr = child_ispecp->is_intr; 14120Sstevel@tonic-gate uint32_t nodeid; 14130Sstevel@tonic-gate static ddi_ispec_t *dup_ispec(ddi_ispec_t *ispecp); 14140Sstevel@tonic-gate #ifdef DEBUG 14150Sstevel@tonic-gate static int debug = 0; 14160Sstevel@tonic-gate #endif 14170Sstevel@tonic-gate 14180Sstevel@tonic-gate *new_ispecp = (ddi_ispec_t *)NULL; 14190Sstevel@tonic-gate 14200Sstevel@tonic-gate /* 14210Sstevel@tonic-gate * step1 14220Sstevel@tonic-gate * If we have an interrupt-parent property, this property represents 14230Sstevel@tonic-gate * the nodeid of our interrupt parent. 14240Sstevel@tonic-gate */ 14250Sstevel@tonic-gate if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 14260Sstevel@tonic-gate "interrupt-parent", -1)) != -1) { 14270Sstevel@tonic-gate intr_parent_dip = e_ddi_nodeid_to_dip(nodeid); 14280Sstevel@tonic-gate ASSERT(intr_parent_dip); 14290Sstevel@tonic-gate /* 14300Sstevel@tonic-gate * Attach the interrupt parent. 14310Sstevel@tonic-gate * 14320Sstevel@tonic-gate * N.B. e_ddi_nodeid_to_dip() isn't safe under DR. 14330Sstevel@tonic-gate * Also, interrupt parent isn't held. This needs 14340Sstevel@tonic-gate * to be revisited if DR-capable platforms implement 14350Sstevel@tonic-gate * interrupt redirection. 14360Sstevel@tonic-gate */ 14370Sstevel@tonic-gate if (i_ddi_attach_node_hierarchy(intr_parent_dip) 14380Sstevel@tonic-gate != DDI_SUCCESS) { 14390Sstevel@tonic-gate ndi_rele_devi(intr_parent_dip); 14400Sstevel@tonic-gate return (NULL); 14410Sstevel@tonic-gate } 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate /* Create a new interrupt info struct and initialize it. */ 14440Sstevel@tonic-gate ispecp = dup_ispec(child_ispecp); 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate *new_ispecp = ispecp; 14470Sstevel@tonic-gate return (intr_parent_dip); 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate /* 14510Sstevel@tonic-gate * step2 14520Sstevel@tonic-gate * Get interrupt map structure from PROM property 14530Sstevel@tonic-gate */ 14540Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 14550Sstevel@tonic-gate "interrupt-map", (caddr_t)&imap, &imap_sz) 14560Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 14570Sstevel@tonic-gate /* 14580Sstevel@tonic-gate * If we don't have an imap property, default to using the 14590Sstevel@tonic-gate * device tree. 14600Sstevel@tonic-gate */ 14610Sstevel@tonic-gate /* Create a new interrupt info struct and initialize it. */ 14620Sstevel@tonic-gate ispecp = dup_ispec(child_ispecp); 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate *new_ispecp = ispecp; 14650Sstevel@tonic-gate ndi_hold_devi(pdip); 14660Sstevel@tonic-gate return (pdip); 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate /* Get the interrupt mask property */ 14700Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 14710Sstevel@tonic-gate "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz) 14720Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 14730Sstevel@tonic-gate /* 14740Sstevel@tonic-gate * If we don't find this property, we have to fail the request 14750Sstevel@tonic-gate * because the 1275 imap property wasn't defined correctly. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 14780Sstevel@tonic-gate goto exit2; 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate /* Get the address cell size */ 14820Sstevel@tonic-gate addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 14830Sstevel@tonic-gate "#address-cells", 2); 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate /* Get the interrupts cell size */ 14860Sstevel@tonic-gate intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 14870Sstevel@tonic-gate "#interrupt-cells", 1); 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate /* 14900Sstevel@tonic-gate * step3 14910Sstevel@tonic-gate * Now lets build up the unit interrupt specifier e.g. reg,intr 14920Sstevel@tonic-gate * and apply the imap mask. match_req will hold this when we're 14930Sstevel@tonic-gate * through. 14940Sstevel@tonic-gate */ 14950Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "reg", 14960Sstevel@tonic-gate (caddr_t)®_p, ®_len) != DDI_SUCCESS) { 14970Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 14980Sstevel@tonic-gate goto exit3; 14990Sstevel@tonic-gate } 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) + 15020Sstevel@tonic-gate CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP); 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate for (i = 0; i < addr_cells; i++) 15050Sstevel@tonic-gate match_req[i] = (reg_p[i] & imap_mask[i]); 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate for (j = 0; j < intr_cells; i++, j++) 15080Sstevel@tonic-gate match_req[i] = (intr[j] & imap_mask[i]); 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate /* Calculate the imap size in cells */ 15110Sstevel@tonic-gate imap_cells = BYTES_TO_1275_CELLS(imap_sz); 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate #ifdef DEBUG 15140Sstevel@tonic-gate if (debug) 15150Sstevel@tonic-gate prom_printf("reg cell size 0x%x, intr cell size 0x%x, " 15160Sstevel@tonic-gate "match_request 0x%x, imap 0x%x\n", addr_cells, intr_cells, 15170Sstevel@tonic-gate match_req, imap); 15180Sstevel@tonic-gate #endif 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate /* 15210Sstevel@tonic-gate * Scan the imap property looking for a match of the interrupt unit 15220Sstevel@tonic-gate * specifier. This loop is rather complex since the data within the 15230Sstevel@tonic-gate * imap property may vary in size. 15240Sstevel@tonic-gate */ 15250Sstevel@tonic-gate for (scan = imap, imap_scan_cells = i = 0; 15260Sstevel@tonic-gate imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) { 15270Sstevel@tonic-gate int new_intr_cells; 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate /* Set the index to the nodeid field */ 15300Sstevel@tonic-gate i = addr_cells + intr_cells; 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate /* 15330Sstevel@tonic-gate * step4a 15340Sstevel@tonic-gate * Translate the nodeid field to a dip 15350Sstevel@tonic-gate */ 15360Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 15370Sstevel@tonic-gate intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]); 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate ASSERT(intr_parent_dip != 0); 15400Sstevel@tonic-gate #ifdef DEBUG 15410Sstevel@tonic-gate if (debug) 15420Sstevel@tonic-gate prom_printf("scan 0x%x\n", scan); 15430Sstevel@tonic-gate #endif 15440Sstevel@tonic-gate /* 15450Sstevel@tonic-gate * The tmp_dip describes the new domain, get it's interrupt 15460Sstevel@tonic-gate * cell size 15470Sstevel@tonic-gate */ 15480Sstevel@tonic-gate new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0, 15490Sstevel@tonic-gate "#interrupts-cells", 1); 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate /* 15520Sstevel@tonic-gate * step4b 15530Sstevel@tonic-gate * See if we have a match on the interrupt unit specifier 15540Sstevel@tonic-gate */ 15550Sstevel@tonic-gate if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells) 15560Sstevel@tonic-gate == 0) { 15570Sstevel@tonic-gate ddi_ispec_t ispec; 15580Sstevel@tonic-gate uint32_t *intr; 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate /* 15610Sstevel@tonic-gate * Copy The childs ispec info excluding the interrupt 15620Sstevel@tonic-gate */ 15630Sstevel@tonic-gate ispec = *child_ispecp; 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate match_found = 1; 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate /* 15680Sstevel@tonic-gate * If we have an imap parent whose not in our device 15690Sstevel@tonic-gate * tree path, we need to hold and install that driver. 15700Sstevel@tonic-gate */ 15710Sstevel@tonic-gate if (i_ddi_attach_node_hierarchy(intr_parent_dip) 15720Sstevel@tonic-gate != DDI_SUCCESS) { 15730Sstevel@tonic-gate ndi_rele_devi(intr_parent_dip); 15740Sstevel@tonic-gate intr_parent_dip = (dev_info_t *)NULL; 15750Sstevel@tonic-gate goto exit4; 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate /* 15790Sstevel@tonic-gate * We need to handcraft an ispec along with a bus 15800Sstevel@tonic-gate * interrupt value, so we can dup it into our 15810Sstevel@tonic-gate * standard ispec structure. 15820Sstevel@tonic-gate */ 15830Sstevel@tonic-gate /* Extract the translated interrupt information */ 15840Sstevel@tonic-gate intr = kmem_alloc( 15850Sstevel@tonic-gate CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP); 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate for (j = 0; j < new_intr_cells; j++, i++) 15880Sstevel@tonic-gate intr[j] = scan[i]; 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate ispec.is_intr_sz = 15910Sstevel@tonic-gate CELLS_1275_TO_BYTES(new_intr_cells); 15920Sstevel@tonic-gate ispec.is_intr = intr; 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate ispecp = dup_ispec(&ispec); 15950Sstevel@tonic-gate 15960Sstevel@tonic-gate kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells)); 15970Sstevel@tonic-gate 15980Sstevel@tonic-gate #ifdef DEBUG 15990Sstevel@tonic-gate if (debug) 16000Sstevel@tonic-gate prom_printf("dip 0x%x, intr info 0x%x\n", 16010Sstevel@tonic-gate intr_parent_dip, ispecp); 16020Sstevel@tonic-gate #endif 16030Sstevel@tonic-gate 16040Sstevel@tonic-gate break; 16050Sstevel@tonic-gate } else { 16060Sstevel@tonic-gate #ifdef DEBUG 16070Sstevel@tonic-gate if (debug) 16080Sstevel@tonic-gate prom_printf("dip 0x%x\n", intr_parent_dip); 16090Sstevel@tonic-gate #endif 16100Sstevel@tonic-gate ndi_rele_devi(intr_parent_dip); 16110Sstevel@tonic-gate intr_parent_dip = NULL; 16120Sstevel@tonic-gate i += new_intr_cells; 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate /* 16170Sstevel@tonic-gate * If we haven't found our interrupt parent at this point, fallback 16180Sstevel@tonic-gate * to using the device tree. 16190Sstevel@tonic-gate */ 16200Sstevel@tonic-gate if (!match_found) { 16210Sstevel@tonic-gate /* Create a new interrupt info struct and initialize it. */ 16220Sstevel@tonic-gate ispecp = dup_ispec(child_ispecp); 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate ndi_hold_devi(pdip); 16250Sstevel@tonic-gate ASSERT(intr_parent_dip == NULL); 16260Sstevel@tonic-gate intr_parent_dip = pdip; 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate ASSERT(ispecp != NULL); 16300Sstevel@tonic-gate ASSERT(intr_parent_dip != NULL); 16310Sstevel@tonic-gate *new_ispecp = ispecp; 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate exit4: 16340Sstevel@tonic-gate kmem_free(reg_p, reg_len); 16350Sstevel@tonic-gate kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) + 16360Sstevel@tonic-gate CELLS_1275_TO_BYTES(intr_cells)); 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate exit3: 16390Sstevel@tonic-gate kmem_free(imap_mask, imap_mask_sz); 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate exit2: 16420Sstevel@tonic-gate kmem_free(imap, imap_sz); 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate return (intr_parent_dip); 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate /* 16480Sstevel@tonic-gate * Support routine for duplicating and initializing an interrupt specification. 16490Sstevel@tonic-gate * The bus interrupt value will be allocated at the end of this structure, so 16500Sstevel@tonic-gate * the corresponding routine i_ddi_free_ispec() should be used to free the 16510Sstevel@tonic-gate * interrupt specification. 16520Sstevel@tonic-gate */ 16530Sstevel@tonic-gate static ddi_ispec_t * 16540Sstevel@tonic-gate dup_ispec(ddi_ispec_t *ispecp) 16550Sstevel@tonic-gate { 16560Sstevel@tonic-gate ddi_ispec_t *new_ispecp; 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate new_ispecp = kmem_alloc(sizeof (ddi_ispec_t) + ispecp->is_intr_sz, 16590Sstevel@tonic-gate KM_SLEEP); 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate /* Copy the contents of the ispec */ 16620Sstevel@tonic-gate *new_ispecp = *ispecp; 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate /* Reset the intr pointer to the one just created */ 16650Sstevel@tonic-gate new_ispecp->is_intr = (uint32_t *)(new_ispecp + 1); 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate cells_1275_copy(ispecp->is_intr, new_ispecp->is_intr, 16680Sstevel@tonic-gate BYTES_TO_1275_CELLS(ispecp->is_intr_sz)); 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate return (new_ispecp); 16710Sstevel@tonic-gate } 16720Sstevel@tonic-gate 16730Sstevel@tonic-gate int 16740Sstevel@tonic-gate i_ddi_get_nintrs(dev_info_t *dip) 16750Sstevel@tonic-gate { 16760Sstevel@tonic-gate int32_t intrlen; 16770Sstevel@tonic-gate prop_1275_cell_t intr_sz; 16780Sstevel@tonic-gate prop_1275_cell_t *ip; 16790Sstevel@tonic-gate int32_t ret = 0; 16800Sstevel@tonic-gate 16810Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS | 16820Sstevel@tonic-gate DDI_PROP_CANSLEEP, 16830Sstevel@tonic-gate "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 16840Sstevel@tonic-gate 16850Sstevel@tonic-gate intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 16860Sstevel@tonic-gate "#interrupt-cells", 1); 16870Sstevel@tonic-gate /* adjust for number of bytes */ 16880Sstevel@tonic-gate intr_sz = CELLS_1275_TO_BYTES(intr_sz); 16890Sstevel@tonic-gate 16900Sstevel@tonic-gate ret = intrlen / intr_sz; 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate kmem_free(ip, intrlen); 16930Sstevel@tonic-gate } 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate return (ret); 16960Sstevel@tonic-gate } 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate /*ARGSUSED*/ 16990Sstevel@tonic-gate uint_t 17000Sstevel@tonic-gate softlevel1(caddr_t arg) 17010Sstevel@tonic-gate { 17020Sstevel@tonic-gate extern int siron_pending; 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate siron_pending = 0; 17050Sstevel@tonic-gate softint(); 17060Sstevel@tonic-gate return (1); 17070Sstevel@tonic-gate } 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate /* 17100Sstevel@tonic-gate * indirection table, to save us some large switch statements 17110Sstevel@tonic-gate * NOTE: This must agree with "INTLEVEL_foo" constants in 17120Sstevel@tonic-gate * <sys/avintr.h> 17130Sstevel@tonic-gate */ 17140Sstevel@tonic-gate struct autovec *const vectorlist[] = { 0 }; 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate /* 17170Sstevel@tonic-gate * This value is exported here for the functions in avintr.c 17180Sstevel@tonic-gate */ 17190Sstevel@tonic-gate const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0])); 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate /* 17220Sstevel@tonic-gate * Check for machine specific interrupt levels which cannot be reassigned by 17230Sstevel@tonic-gate * settrap(), sun4u version. 17240Sstevel@tonic-gate * 17250Sstevel@tonic-gate * sun4u does not support V8 SPARC "fast trap" handlers. 17260Sstevel@tonic-gate */ 17270Sstevel@tonic-gate /*ARGSUSED*/ 17280Sstevel@tonic-gate int 17290Sstevel@tonic-gate exclude_settrap(int lvl) 17300Sstevel@tonic-gate { 17310Sstevel@tonic-gate return (1); 17320Sstevel@tonic-gate } 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate /* 17350Sstevel@tonic-gate * Check for machine specific interrupt levels which cannot have interrupt 17360Sstevel@tonic-gate * handlers added. We allow levels 1 through 15; level 0 is nonsense. 17370Sstevel@tonic-gate */ 17380Sstevel@tonic-gate /*ARGSUSED*/ 17390Sstevel@tonic-gate int 17400Sstevel@tonic-gate exclude_level(int lvl) 17410Sstevel@tonic-gate { 17420Sstevel@tonic-gate return ((lvl < 1) || (lvl > 15)); 17430Sstevel@tonic-gate } 17440Sstevel@tonic-gate 17450Sstevel@tonic-gate /* 17460Sstevel@tonic-gate * The following functions ready a cautious request to go up to the nexus 17470Sstevel@tonic-gate * driver. It is up to the nexus driver to decide how to process the request. 17480Sstevel@tonic-gate * It may choose to call i_ddi_do_caut_get/put in this file, or do it 17490Sstevel@tonic-gate * differently. 17500Sstevel@tonic-gate */ 17510Sstevel@tonic-gate 17520Sstevel@tonic-gate static void 17530Sstevel@tonic-gate i_ddi_caut_getput_ctlops( 17540Sstevel@tonic-gate ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size, 17550Sstevel@tonic-gate size_t repcount, uint_t flags, ddi_ctl_enum_t cmd) 17560Sstevel@tonic-gate { 17570Sstevel@tonic-gate peekpoke_ctlops_t cautacc_ctlops_arg; 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate cautacc_ctlops_arg.size = size; 17600Sstevel@tonic-gate cautacc_ctlops_arg.dev_addr = dev_addr; 17610Sstevel@tonic-gate cautacc_ctlops_arg.host_addr = host_addr; 17620Sstevel@tonic-gate cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp; 17630Sstevel@tonic-gate cautacc_ctlops_arg.repcount = repcount; 17640Sstevel@tonic-gate cautacc_ctlops_arg.flags = flags; 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate (void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd, 17670Sstevel@tonic-gate &cautacc_ctlops_arg, NULL); 17680Sstevel@tonic-gate } 17690Sstevel@tonic-gate 17700Sstevel@tonic-gate uint8_t 17710Sstevel@tonic-gate i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr) 17720Sstevel@tonic-gate { 17730Sstevel@tonic-gate uint8_t value; 17740Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 17750Sstevel@tonic-gate sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK); 17760Sstevel@tonic-gate 17770Sstevel@tonic-gate return (value); 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate uint16_t 17810Sstevel@tonic-gate i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr) 17820Sstevel@tonic-gate { 17830Sstevel@tonic-gate uint16_t value; 17840Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 17850Sstevel@tonic-gate sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK); 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate return (value); 17880Sstevel@tonic-gate } 17890Sstevel@tonic-gate 17900Sstevel@tonic-gate uint32_t 17910Sstevel@tonic-gate i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr) 17920Sstevel@tonic-gate { 17930Sstevel@tonic-gate uint32_t value; 17940Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 17950Sstevel@tonic-gate sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK); 17960Sstevel@tonic-gate 17970Sstevel@tonic-gate return (value); 17980Sstevel@tonic-gate } 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate uint64_t 18010Sstevel@tonic-gate i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr) 18020Sstevel@tonic-gate { 18030Sstevel@tonic-gate uint64_t value; 18040Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18050Sstevel@tonic-gate sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK); 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate return (value); 18080Sstevel@tonic-gate } 18090Sstevel@tonic-gate 18100Sstevel@tonic-gate void 18110Sstevel@tonic-gate i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value) 18120Sstevel@tonic-gate { 18130Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18140Sstevel@tonic-gate sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE); 18150Sstevel@tonic-gate } 18160Sstevel@tonic-gate 18170Sstevel@tonic-gate void 18180Sstevel@tonic-gate i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value) 18190Sstevel@tonic-gate { 18200Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18210Sstevel@tonic-gate sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE); 18220Sstevel@tonic-gate } 18230Sstevel@tonic-gate 18240Sstevel@tonic-gate void 18250Sstevel@tonic-gate i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value) 18260Sstevel@tonic-gate { 18270Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18280Sstevel@tonic-gate sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE); 18290Sstevel@tonic-gate } 18300Sstevel@tonic-gate 18310Sstevel@tonic-gate void 18320Sstevel@tonic-gate i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value) 18330Sstevel@tonic-gate { 18340Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 18350Sstevel@tonic-gate sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE); 18360Sstevel@tonic-gate } 18370Sstevel@tonic-gate 18380Sstevel@tonic-gate void 18390Sstevel@tonic-gate i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 18400Sstevel@tonic-gate size_t repcount, uint_t flags) 18410Sstevel@tonic-gate { 18420Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18430Sstevel@tonic-gate sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK); 18440Sstevel@tonic-gate } 18450Sstevel@tonic-gate 18460Sstevel@tonic-gate void 18470Sstevel@tonic-gate i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr, 18480Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 18490Sstevel@tonic-gate { 18500Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18510Sstevel@tonic-gate sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK); 18520Sstevel@tonic-gate } 18530Sstevel@tonic-gate 18540Sstevel@tonic-gate void 18550Sstevel@tonic-gate i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr, 18560Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 18570Sstevel@tonic-gate { 18580Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18590Sstevel@tonic-gate sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK); 18600Sstevel@tonic-gate } 18610Sstevel@tonic-gate 18620Sstevel@tonic-gate void 18630Sstevel@tonic-gate i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr, 18640Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 18650Sstevel@tonic-gate { 18660Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18670Sstevel@tonic-gate sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK); 18680Sstevel@tonic-gate } 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate void 18710Sstevel@tonic-gate i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 18720Sstevel@tonic-gate size_t repcount, uint_t flags) 18730Sstevel@tonic-gate { 18740Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18750Sstevel@tonic-gate sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE); 18760Sstevel@tonic-gate } 18770Sstevel@tonic-gate 18780Sstevel@tonic-gate void 18790Sstevel@tonic-gate i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr, 18800Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 18810Sstevel@tonic-gate { 18820Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18830Sstevel@tonic-gate sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE); 18840Sstevel@tonic-gate } 18850Sstevel@tonic-gate 18860Sstevel@tonic-gate void 18870Sstevel@tonic-gate i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr, 18880Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 18890Sstevel@tonic-gate { 18900Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18910Sstevel@tonic-gate sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE); 18920Sstevel@tonic-gate } 18930Sstevel@tonic-gate 18940Sstevel@tonic-gate void 18950Sstevel@tonic-gate i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr, 18960Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 18970Sstevel@tonic-gate { 18980Sstevel@tonic-gate i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 18990Sstevel@tonic-gate sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE); 19000Sstevel@tonic-gate } 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate /* 19030Sstevel@tonic-gate * This is called only to process peek/poke when the DIP is NULL. 19040Sstevel@tonic-gate * Assume that this is for memory, as nexi take care of device safe accesses. 19050Sstevel@tonic-gate */ 19060Sstevel@tonic-gate int 19070Sstevel@tonic-gate peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args) 19080Sstevel@tonic-gate { 19090Sstevel@tonic-gate int err = DDI_SUCCESS; 19100Sstevel@tonic-gate on_trap_data_t otd; 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate /* Set up protected environment. */ 19130Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 19140Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 19150Sstevel@tonic-gate 19160Sstevel@tonic-gate if (cmd == DDI_CTLOPS_POKE) { 19170Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 19180Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 19190Sstevel@tonic-gate (void *)in_args->host_addr); 19200Sstevel@tonic-gate } else { 19210Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 19220Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 19230Sstevel@tonic-gate (void *)in_args->host_addr); 19240Sstevel@tonic-gate } 19250Sstevel@tonic-gate otd.ot_trampoline = tramp; 19260Sstevel@tonic-gate } else 19270Sstevel@tonic-gate err = DDI_FAILURE; 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate /* Take down protected environment. */ 19300Sstevel@tonic-gate no_trap(); 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate return (err); 19330Sstevel@tonic-gate } 1934