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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/conf.h> 317c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 327c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 337c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 347c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 357c478bd9Sstevel@tonic-gate #include <sys/pci.h> 367c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 387c478bd9Sstevel@tonic-gate #include <sys/errno.h> 397c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 407c478bd9Sstevel@tonic-gate #include <sys/debug.h> 417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 427c478bd9Sstevel@tonic-gate #include <sys/pmubus.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <sys/nexusdebug.h> 457c478bd9Sstevel@tonic-gate /* Bitfield debugging definitions for this file */ 467c478bd9Sstevel@tonic-gate #define PMUBUS_MAP_DEBUG 0x1 477c478bd9Sstevel@tonic-gate #define PMUBUS_REGACCESS_DEBUG 0x2 487c478bd9Sstevel@tonic-gate #define PMUBUS_RW_DEBUG 0x4 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * The pmubus nexus is used to manage a shared register space. Rather 527c478bd9Sstevel@tonic-gate * than having several driver's physically alias register mappings and 537c478bd9Sstevel@tonic-gate * have potential problems with register collisions, this nexus will 547c478bd9Sstevel@tonic-gate * serialize the access to this space. 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * There are two types of sharing going on here: 577c478bd9Sstevel@tonic-gate * 1) Registers within the address space may be shared, however the registers 587c478bd9Sstevel@tonic-gate * themselves are unique. The upper bit of the child's high address being zero 597c478bd9Sstevel@tonic-gate * signifies this register type. 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * 2) The second type of register is one where a device may only own a few 627c478bd9Sstevel@tonic-gate * bits in the register. I'll term this as "bit lane" access. This is a more 637c478bd9Sstevel@tonic-gate * complicated scenario. The drivers themselves are responsible for knowing 647c478bd9Sstevel@tonic-gate * which bit lanes in the register they own. The read of a register only 657c478bd9Sstevel@tonic-gate * guarantees that those bits the driver is interested in are valid. If a 667c478bd9Sstevel@tonic-gate * driver needs to set bits in a register, a read must be done first to 677c478bd9Sstevel@tonic-gate * identify the state of the drivers bits. Depending on which way a bit needs 687c478bd9Sstevel@tonic-gate * to be driven, the driver will write a 1 to the bit to toggle it. If a bit 697c478bd9Sstevel@tonic-gate * is to remain unchanged, a 0 is written to the bit. So the access to the 707c478bd9Sstevel@tonic-gate * bit lane is an xor operation. 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * Function prototypes for busops routines: 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate static int pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 767c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp); 777c478bd9Sstevel@tonic-gate static int pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 787c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * function prototypes for dev ops routines: 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate static int pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 847c478bd9Sstevel@tonic-gate static int pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * general function prototypes: 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * bus ops and dev ops structures: 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate static struct bus_ops pmubus_bus_ops = { 947c478bd9Sstevel@tonic-gate BUSO_REV, 957c478bd9Sstevel@tonic-gate pmubus_map, 967c478bd9Sstevel@tonic-gate NULL, 977c478bd9Sstevel@tonic-gate NULL, 987c478bd9Sstevel@tonic-gate NULL, 997c478bd9Sstevel@tonic-gate i_ddi_map_fault, 1007c478bd9Sstevel@tonic-gate ddi_dma_map, 1017c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 1027c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 1037c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 1047c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 1057c478bd9Sstevel@tonic-gate ddi_dma_flush, 1067c478bd9Sstevel@tonic-gate ddi_dma_win, 1077c478bd9Sstevel@tonic-gate ddi_dma_mctl, 1087c478bd9Sstevel@tonic-gate pmubus_ctlops, 1097c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 1107c478bd9Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 1117c478bd9Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 1127c478bd9Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 1137c478bd9Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 1147c478bd9Sstevel@tonic-gate 0, /* interrupt control */ 1157c478bd9Sstevel@tonic-gate 0, /* bus_config */ 1167c478bd9Sstevel@tonic-gate 0, /* bus_unconfig */ 1177c478bd9Sstevel@tonic-gate 0, /* bus_fm_init */ 1187c478bd9Sstevel@tonic-gate 0, /* bus_fm_fini */ 1197c478bd9Sstevel@tonic-gate 0, /* bus_fm_access_enter */ 1207c478bd9Sstevel@tonic-gate 0, /* bus_fm_access_exit */ 1217c478bd9Sstevel@tonic-gate 0, /* bus_power */ 1227c478bd9Sstevel@tonic-gate i_ddi_intr_ops /* bus_intr_op */ 1237c478bd9Sstevel@tonic-gate }; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate static struct dev_ops pmubus_ops = { 1267c478bd9Sstevel@tonic-gate DEVO_REV, 1277c478bd9Sstevel@tonic-gate 0, 1287c478bd9Sstevel@tonic-gate ddi_no_info, 1297c478bd9Sstevel@tonic-gate nulldev, 1307c478bd9Sstevel@tonic-gate 0, 1317c478bd9Sstevel@tonic-gate pmubus_attach, 1327c478bd9Sstevel@tonic-gate pmubus_detach, 1337c478bd9Sstevel@tonic-gate nodev, 1347c478bd9Sstevel@tonic-gate (struct cb_ops *)0, 1357c478bd9Sstevel@tonic-gate &pmubus_bus_ops 1367c478bd9Sstevel@tonic-gate }; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * module definitions: 1407c478bd9Sstevel@tonic-gate */ 1417c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1427c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1457c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 1467c478bd9Sstevel@tonic-gate "pmubus nexus driver", /* Name of module. */ 1477c478bd9Sstevel@tonic-gate &pmubus_ops, /* driver ops */ 1487c478bd9Sstevel@tonic-gate }; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1517c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1527c478bd9Sstevel@tonic-gate }; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * driver global data: 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate static void *per_pmubus_state; /* per-pmubus soft state pointer */ 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate int 1607c478bd9Sstevel@tonic-gate _init(void) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate int e; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Initialize per-pmubus soft state pointer. 1667c478bd9Sstevel@tonic-gate */ 1677c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&per_pmubus_state, 1687c478bd9Sstevel@tonic-gate sizeof (pmubus_devstate_t), 1); 1697c478bd9Sstevel@tonic-gate if (e != 0) 1707c478bd9Sstevel@tonic-gate return (e); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate /* 1737c478bd9Sstevel@tonic-gate * Install the module. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate e = mod_install(&modlinkage); 1767c478bd9Sstevel@tonic-gate if (e != 0) 1777c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pmubus_state); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate return (e); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate int 1837c478bd9Sstevel@tonic-gate _fini(void) 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate int e; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * Remove the module. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate e = mod_remove(&modlinkage); 1917c478bd9Sstevel@tonic-gate if (e != 0) 1927c478bd9Sstevel@tonic-gate return (e); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* 1957c478bd9Sstevel@tonic-gate * Free the soft state info. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pmubus_state); 1987c478bd9Sstevel@tonic-gate return (e); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate int 2027c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* device driver entry points */ 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate /* 2107c478bd9Sstevel@tonic-gate * attach entry point: 2117c478bd9Sstevel@tonic-gate * 2127c478bd9Sstevel@tonic-gate * normal attach: 2137c478bd9Sstevel@tonic-gate * 2147c478bd9Sstevel@tonic-gate * create soft state structure (dip, reg, nreg and state fields) 2157c478bd9Sstevel@tonic-gate * map in configuration header 2167c478bd9Sstevel@tonic-gate * make sure device is properly configured 2177c478bd9Sstevel@tonic-gate * report device 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate static int 2207c478bd9Sstevel@tonic-gate pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate pmubus_devstate_t *pmubusp; /* per pmubus state pointer */ 2237c478bd9Sstevel@tonic-gate int32_t instance; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate switch (cmd) { 2267c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * Allocate soft state for this instance. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 2317c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(per_pmubus_state, instance) != 2327c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 2337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't allocate soft " 2347c478bd9Sstevel@tonic-gate "state.\n"); 2357c478bd9Sstevel@tonic-gate goto fail_exit; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate pmubusp = ddi_get_soft_state(per_pmubus_state, instance); 2397c478bd9Sstevel@tonic-gate pmubusp->pmubus_dip = dip; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* Cache our register property */ 242*a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2437c478bd9Sstevel@tonic-gate "reg", (caddr_t)&pmubusp->pmubus_regp, 2447c478bd9Sstevel@tonic-gate &pmubusp->pmubus_reglen) != DDI_SUCCESS) { 2457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't acquire reg " 2467c478bd9Sstevel@tonic-gate "property.\n"); 2477c478bd9Sstevel@tonic-gate goto fail_get_regs; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* Cache our ranges property */ 251*a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2527c478bd9Sstevel@tonic-gate "ranges", (caddr_t)&pmubusp->pmubus_rangep, 2537c478bd9Sstevel@tonic-gate &pmubusp->pmubus_rnglen) != DDI_SUCCESS) { 2547c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't acquire the " 2557c478bd9Sstevel@tonic-gate "ranges property.\n"); 2567c478bd9Sstevel@tonic-gate goto fail_get_ranges; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* Calculate the number of ranges */ 2617c478bd9Sstevel@tonic-gate pmubusp->pmubus_nranges = 2627c478bd9Sstevel@tonic-gate pmubusp->pmubus_rnglen / sizeof (pmu_rangespec_t); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* Set up the mapping to our registers */ 2657c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &pmubusp->pmubus_reghdl) != 2667c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 2677c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't map in " 2687c478bd9Sstevel@tonic-gate "register space.\n"); 2697c478bd9Sstevel@tonic-gate goto fail_map_regs; 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* Initialize our register access mutex */ 2737c478bd9Sstevel@tonic-gate mutex_init(&pmubusp->pmubus_reg_access_lock, NULL, 2747c478bd9Sstevel@tonic-gate MUTEX_DRIVER, NULL); 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 2777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate case DDI_RESUME: 2807c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate fail_map_regs: 2847c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate fail_get_ranges: 2877c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate fail_get_regs: 2907c478bd9Sstevel@tonic-gate ddi_soft_state_free(per_pmubus_state, instance); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate fail_exit: 2937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * detach entry point: 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate static int 3007c478bd9Sstevel@tonic-gate pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3017c478bd9Sstevel@tonic-gate { 3027c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 3037c478bd9Sstevel@tonic-gate pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 3047c478bd9Sstevel@tonic-gate instance); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate switch (cmd) { 3077c478bd9Sstevel@tonic-gate case DDI_DETACH: 3087c478bd9Sstevel@tonic-gate mutex_destroy(&pmubusp->pmubus_reg_access_lock); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* Tear down our register mappings */ 3117c478bd9Sstevel@tonic-gate pci_config_teardown(&pmubusp->pmubus_reghdl); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* Free our ranges property */ 3147c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* Free the register property */ 3177c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate ddi_soft_state_free(per_pmubus_state, instance); 3207c478bd9Sstevel@tonic-gate break; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 3237c478bd9Sstevel@tonic-gate default: 3247c478bd9Sstevel@tonic-gate break; 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3317c478bd9Sstevel@tonic-gate void 3327c478bd9Sstevel@tonic-gate pmubus_norep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, 3337c478bd9Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3387c478bd9Sstevel@tonic-gate void 3397c478bd9Sstevel@tonic-gate pmubus_norep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, 3407c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3457c478bd9Sstevel@tonic-gate void 3467c478bd9Sstevel@tonic-gate pmubus_norep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, 3477c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3527c478bd9Sstevel@tonic-gate void 3537c478bd9Sstevel@tonic-gate pmubus_norep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, 3547c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 3557c478bd9Sstevel@tonic-gate { 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3597c478bd9Sstevel@tonic-gate void 3607c478bd9Sstevel@tonic-gate pmubus_norep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, 3617c478bd9Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 3627c478bd9Sstevel@tonic-gate { 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3667c478bd9Sstevel@tonic-gate void 3677c478bd9Sstevel@tonic-gate pmubus_norep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, 3687c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 3697c478bd9Sstevel@tonic-gate { 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3737c478bd9Sstevel@tonic-gate void 3747c478bd9Sstevel@tonic-gate pmubus_norep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, 3757c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3807c478bd9Sstevel@tonic-gate void 3817c478bd9Sstevel@tonic-gate pmubus_norep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, 3827c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 3837c478bd9Sstevel@tonic-gate { 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3877c478bd9Sstevel@tonic-gate uint8_t 3887c478bd9Sstevel@tonic-gate pmubus_get8(ddi_acc_impl_t *hdlp, uint8_t *addr) 3897c478bd9Sstevel@tonic-gate { 3907c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 3917c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 3927c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 3937c478bd9Sstevel@tonic-gate off_t offset; 3947c478bd9Sstevel@tonic-gate uint8_t value; 3957c478bd9Sstevel@tonic-gate uint8_t mask; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 3987c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 4017c478bd9Sstevel@tonic-gate if (addr != 0 || 4027c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 4037c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_get8: load discarded, " 4047c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 4057c478bd9Sstevel@tonic-gate return ((uint8_t)-1); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate mask = pmubus_mapreqp->mapreq_mask; 4087c478bd9Sstevel@tonic-gate } else { 4097c478bd9Sstevel@tonic-gate mask = (uint8_t)-1; 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* gets are simple, we just issue them no locking necessary */ 4137c478bd9Sstevel@tonic-gate value = pci_config_get8(softsp->pmubus_reghdl, offset) & mask; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get8: addr=%p offset=%x value=%x " 4167c478bd9Sstevel@tonic-gate "mask=%lx\n", addr, offset, value, mask)); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate return (value); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4237c478bd9Sstevel@tonic-gate uint16_t 4247c478bd9Sstevel@tonic-gate pmubus_noget16(ddi_acc_impl_t *hdlp, uint16_t *addr) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate return ((uint16_t)-1); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4307c478bd9Sstevel@tonic-gate uint32_t 4317c478bd9Sstevel@tonic-gate pmubus_get32(ddi_acc_impl_t *hdlp, uint32_t *addr) 4327c478bd9Sstevel@tonic-gate { 4337c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 4347c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 4357c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 4367c478bd9Sstevel@tonic-gate off_t offset = (uintptr_t)addr & PMUBUS_REGOFFSET; 4377c478bd9Sstevel@tonic-gate uint32_t value; 4387c478bd9Sstevel@tonic-gate uint32_t mask; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 4417c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 4447c478bd9Sstevel@tonic-gate if (addr != 0 || 4457c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 4467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_get32: load discarded, " 4477c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 4487c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate mask = pmubus_mapreqp->mapreq_mask; 4517c478bd9Sstevel@tonic-gate } else { 4527c478bd9Sstevel@tonic-gate mask = (uint32_t)-1; 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* gets are simple, we just issue them no locking necessary */ 4567c478bd9Sstevel@tonic-gate value = pci_config_get32(softsp->pmubus_reghdl, offset) & mask; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get32: addr=%p offset=%x value=%x " 4597c478bd9Sstevel@tonic-gate "mask=%lx\n", addr, offset, value, mask)); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate return (value); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4657c478bd9Sstevel@tonic-gate uint64_t 4667c478bd9Sstevel@tonic-gate pmubus_noget64(ddi_acc_impl_t *hdlp, uint64_t *addr) 4677c478bd9Sstevel@tonic-gate { 4687c478bd9Sstevel@tonic-gate return ((uint64_t)-1); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4727c478bd9Sstevel@tonic-gate void 4737c478bd9Sstevel@tonic-gate pmubus_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 4747c478bd9Sstevel@tonic-gate { 4757c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 4767c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 4777c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 4787c478bd9Sstevel@tonic-gate off_t offset; 4797c478bd9Sstevel@tonic-gate uint8_t tmp; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 4827c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * Process "bit lane" register 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%x " 4897c478bd9Sstevel@tonic-gate "value=%x mask=%lx\n", addr, offset, value, 4907c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate if (addr != 0 || 4937c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 4947c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_put8: store discarded, " 4957c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 4967c478bd9Sstevel@tonic-gate return; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate mutex_enter(&softsp->pmubus_reg_access_lock); 5007c478bd9Sstevel@tonic-gate tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 5017c478bd9Sstevel@tonic-gate tmp &= ~pmubus_mapreqp->mapreq_mask; 5027c478bd9Sstevel@tonic-gate value &= pmubus_mapreqp->mapreq_mask; 5037c478bd9Sstevel@tonic-gate tmp |= value; 5047c478bd9Sstevel@tonic-gate pci_config_put8(softsp->pmubus_reghdl, offset, tmp); 5057c478bd9Sstevel@tonic-gate mutex_exit(&softsp->pmubus_reg_access_lock); 5067c478bd9Sstevel@tonic-gate } else { 5077c478bd9Sstevel@tonic-gate /* 5087c478bd9Sstevel@tonic-gate * Process shared register 5097c478bd9Sstevel@tonic-gate */ 5107c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%x " 5117c478bd9Sstevel@tonic-gate "value=%x\n", addr, offset, value)); 5127c478bd9Sstevel@tonic-gate pci_config_put8(softsp->pmubus_reghdl, offset, value); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* Flush store buffers XXX Should let drivers do this. */ 5167c478bd9Sstevel@tonic-gate tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5207c478bd9Sstevel@tonic-gate void 5217c478bd9Sstevel@tonic-gate pmubus_noput16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5267c478bd9Sstevel@tonic-gate void 5277c478bd9Sstevel@tonic-gate pmubus_put32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 5307c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 5317c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 5327c478bd9Sstevel@tonic-gate off_t offset; 5337c478bd9Sstevel@tonic-gate uint32_t tmp; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 5367c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * Process "bit lane" register 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%x " 5437c478bd9Sstevel@tonic-gate "value=%x mask=%lx\n", addr, offset, value, 5447c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate if (addr != 0 || 5477c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 5487c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_put32: store discarded, " 5497c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 5507c478bd9Sstevel@tonic-gate return; 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate mutex_enter(&softsp->pmubus_reg_access_lock); 5547c478bd9Sstevel@tonic-gate tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 5557c478bd9Sstevel@tonic-gate tmp &= ~pmubus_mapreqp->mapreq_mask; 5567c478bd9Sstevel@tonic-gate value &= pmubus_mapreqp->mapreq_mask; 5577c478bd9Sstevel@tonic-gate tmp |= value; 5587c478bd9Sstevel@tonic-gate pci_config_put32(softsp->pmubus_reghdl, offset, tmp); 5597c478bd9Sstevel@tonic-gate mutex_exit(&softsp->pmubus_reg_access_lock); 5607c478bd9Sstevel@tonic-gate } else { 5617c478bd9Sstevel@tonic-gate /* 5627c478bd9Sstevel@tonic-gate * Process shared register 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%x " 5657c478bd9Sstevel@tonic-gate "value=%x\n", addr, offset, value)); 5667c478bd9Sstevel@tonic-gate pci_config_put32(softsp->pmubus_reghdl, offset, value); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* Flush store buffers XXX Should let drivers do this. */ 5707c478bd9Sstevel@tonic-gate tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5747c478bd9Sstevel@tonic-gate void 5757c478bd9Sstevel@tonic-gate pmubus_noput64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 5767c478bd9Sstevel@tonic-gate { 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate /* 5807c478bd9Sstevel@tonic-gate * This routine is used to translate our children's register properties. 5817c478bd9Sstevel@tonic-gate * The return value specifies which type of register has been translated. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5847c478bd9Sstevel@tonic-gate int 5857c478bd9Sstevel@tonic-gate pmubus_apply_range(pmubus_devstate_t *pmubusp, dev_info_t *rdip, 5867c478bd9Sstevel@tonic-gate pmubus_regspec_t *regp, pci_regspec_t *pci_regp) 5877c478bd9Sstevel@tonic-gate { 5887c478bd9Sstevel@tonic-gate pmu_rangespec_t *rangep; 5897c478bd9Sstevel@tonic-gate int nranges = pmubusp->pmubus_nranges; 5907c478bd9Sstevel@tonic-gate int i; 5917c478bd9Sstevel@tonic-gate off_t offset; 5927c478bd9Sstevel@tonic-gate int ret = DDI_ME_REGSPEC_RANGE; 5937c478bd9Sstevel@tonic-gate uint64_t addr; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate addr = regp->reg_addr & ~MAPPING_SHARED_BITS_MASK; 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* Scan the ranges for a match */ 5987c478bd9Sstevel@tonic-gate for (i = 0, rangep = pmubusp->pmubus_rangep; i < nranges; i++, rangep++) 5997c478bd9Sstevel@tonic-gate if ((rangep->rng_child <= addr) && 6007c478bd9Sstevel@tonic-gate ((addr + regp->reg_size) <= 6017c478bd9Sstevel@tonic-gate (rangep->rng_child + rangep->rng_size))) { 6027c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 6037c478bd9Sstevel@tonic-gate break; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 6077c478bd9Sstevel@tonic-gate return (ret); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /* Get the translated register */ 6107c478bd9Sstevel@tonic-gate offset = addr - rangep->rng_child; 6117c478bd9Sstevel@tonic-gate pci_regp->pci_phys_hi = rangep->rng_parent_hi; 6127c478bd9Sstevel@tonic-gate pci_regp->pci_phys_mid = rangep->rng_parent_mid; 6137c478bd9Sstevel@tonic-gate pci_regp->pci_phys_low = rangep->rng_parent_low + offset; 6147c478bd9Sstevel@tonic-gate pci_regp->pci_size_hi = 0; 6157c478bd9Sstevel@tonic-gate pci_regp->pci_size_low = MIN(regp->reg_size, rangep->rng_size); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* Figure out the type of reg space we have */ 6187c478bd9Sstevel@tonic-gate if (pci_regp->pci_phys_hi == pmubusp->pmubus_regp->pci_phys_hi) { 6197c478bd9Sstevel@tonic-gate ret = MAPREQ_SHARED_REG; 6207c478bd9Sstevel@tonic-gate if (regp->reg_addr & MAPPING_SHARED_BITS_MASK) 6217c478bd9Sstevel@tonic-gate ret |= MAPREQ_SHARED_BITS; 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate return (ret); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate static uint64_t 6287c478bd9Sstevel@tonic-gate pmubus_mask(pmubus_obpregspec_t *regs, int32_t rnumber, 6297c478bd9Sstevel@tonic-gate uint64_t *masks) 6307c478bd9Sstevel@tonic-gate { 6317c478bd9Sstevel@tonic-gate int i; 6327c478bd9Sstevel@tonic-gate long n = -1; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate for (i = 0; i <= rnumber; i++) 6357c478bd9Sstevel@tonic-gate if (regs[i].reg_addr_hi & 0x80000000) 6367c478bd9Sstevel@tonic-gate n++; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate if (n == -1) { 6397c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_mask: missing mask"); 6407c478bd9Sstevel@tonic-gate return (0); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate return (masks[n]); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * The pmubus_map routine determines if it's child is attempting to map a 6487c478bd9Sstevel@tonic-gate * shared reg. If it is, it installs it's own vectors and bus private pointer. 6497c478bd9Sstevel@tonic-gate */ 6507c478bd9Sstevel@tonic-gate static int 6517c478bd9Sstevel@tonic-gate pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 6527c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 6537c478bd9Sstevel@tonic-gate { 6547c478bd9Sstevel@tonic-gate pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 6557c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 6567c478bd9Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent; 6577c478bd9Sstevel@tonic-gate pmubus_regspec_t pmubus_rp; 6587c478bd9Sstevel@tonic-gate pmubus_obpregspec_t *pmubus_regs = NULL; 6597c478bd9Sstevel@tonic-gate int pmubus_regs_size; 6607c478bd9Sstevel@tonic-gate uint64_t *pmubus_regmask = NULL; 6617c478bd9Sstevel@tonic-gate int pmubus_regmask_size; 6627c478bd9Sstevel@tonic-gate pci_regspec_t pci_reg; 6637c478bd9Sstevel@tonic-gate int32_t rnumber = mp->map_obj.rnumber; 6647c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp; 6657c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 6667c478bd9Sstevel@tonic-gate char *map_fail1 = "Map Type Unknown"; 6677c478bd9Sstevel@tonic-gate char *map_fail2 = "DDI_MT_REGSPEC"; 6687c478bd9Sstevel@tonic-gate char *s = map_fail1; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate *addrp = NULL; 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * Handle the mapping according to its type. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: off=%x len=%x\n", 6767c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), off, len)); 6777c478bd9Sstevel@tonic-gate switch (mp->map_type) { 6787c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: { 6797c478bd9Sstevel@tonic-gate int n; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * Get the "reg" property from the device node and convert 6837c478bd9Sstevel@tonic-gate * it to our parent's format. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 6867c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: rnumber=%x " 6877c478bd9Sstevel@tonic-gate "handlep=%x\n", ddi_get_name(rdip), ddi_get_instance(rdip), 6887c478bd9Sstevel@tonic-gate rnumber, mp->map_handlep)); 6897c478bd9Sstevel@tonic-gate 690*a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 6917c478bd9Sstevel@tonic-gate "reg", (caddr_t)&pmubus_regs, &pmubus_regs_size) != 6927c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 6937c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("can't get reg " 6947c478bd9Sstevel@tonic-gate "property\n")); 6957c478bd9Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 6967c478bd9Sstevel@tonic-gate goto done; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate n = pmubus_regs_size / sizeof (pmubus_obpregspec_t); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate if (rnumber < 0 || rnumber >= n) { 7017c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber out of range\n")); 7027c478bd9Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 7037c478bd9Sstevel@tonic-gate goto done; 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate pmubus_rp.reg_addr = ((uint64_t) 7077c478bd9Sstevel@tonic-gate pmubus_regs[rnumber].reg_addr_hi << 32) | 7087c478bd9Sstevel@tonic-gate (uint64_t)pmubus_regs[rnumber].reg_addr_lo; 7097c478bd9Sstevel@tonic-gate pmubus_rp.reg_size = pmubus_regs[rnumber].reg_size; 7107c478bd9Sstevel@tonic-gate 711*a3282898Scth (void) ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 7127c478bd9Sstevel@tonic-gate "register-mask", (caddr_t)&pmubus_regmask, 7137c478bd9Sstevel@tonic-gate &pmubus_regmask_size); 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* Create our own mapping private structure */ 7167c478bd9Sstevel@tonic-gate break; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * This bus has no bus children that have to map in an address 7227c478bd9Sstevel@tonic-gate * space, so we can assume that we'll never see an 7237c478bd9Sstevel@tonic-gate * DDI_MT_REGSPEC request 7247c478bd9Sstevel@tonic-gate */ 7257c478bd9Sstevel@tonic-gate s = map_fail2; 7267c478bd9Sstevel@tonic-gate ret = DDI_ME_REGSPEC_RANGE; 7277c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate default: 7307c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) 7317c478bd9Sstevel@tonic-gate ret = DDI_ME_INVAL; 7327c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: pmubus_map: " 7337c478bd9Sstevel@tonic-gate "%s is an invalid map type.\nmap request handlep=0x%p\n", 7347c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), s, mp)); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 7377c478bd9Sstevel@tonic-gate goto done; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* Adjust our reg property with offset and length */ 7417c478bd9Sstevel@tonic-gate if ((pmubus_rp.reg_addr + off) > 7427c478bd9Sstevel@tonic-gate (pmubus_rp.reg_addr + pmubus_rp.reg_size)) { 7437c478bd9Sstevel@tonic-gate ret = DDI_ME_INVAL; 7447c478bd9Sstevel@tonic-gate goto done; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate pmubus_rp.reg_addr += off; 7487c478bd9Sstevel@tonic-gate if (len && (len < pmubus_rp.reg_size)) 7497c478bd9Sstevel@tonic-gate pmubus_rp.reg_size = len; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* Translate our child regspec into our parents address domain */ 7527c478bd9Sstevel@tonic-gate ret = pmubus_apply_range(pmubusp, rdip, &pmubus_rp, &pci_reg); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* Check if the apply range failed */ 7557c478bd9Sstevel@tonic-gate if (ret < DDI_SUCCESS) 7567c478bd9Sstevel@tonic-gate goto done; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate /* 7597c478bd9Sstevel@tonic-gate * If our childs xlated address falls into our shared address range, 7607c478bd9Sstevel@tonic-gate * setup our mapping handle. 7617c478bd9Sstevel@tonic-gate */ 7627c478bd9Sstevel@tonic-gate if (ret > DDI_SUCCESS) { 7637c478bd9Sstevel@tonic-gate /* Figure out if we're mapping or unmapping */ 7647c478bd9Sstevel@tonic-gate switch (mp->map_op) { 7657c478bd9Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: { 7667c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate pmubus_mapreqp = kmem_alloc(sizeof (*pmubus_mapreqp), 7697c478bd9Sstevel@tonic-gate KM_SLEEP); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_flags = ret; 7727c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_softsp = pmubusp; 7737c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_addr = pmubus_rp.reg_addr; 7747c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size = pmubus_rp.reg_size; 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate if (ret & MAPREQ_SHARED_BITS) { 7777c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask = 7787c478bd9Sstevel@tonic-gate pmubus_mask(pmubus_regs, rnumber, 7797c478bd9Sstevel@tonic-gate pmubus_regmask); 7807c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber=%d " 7817c478bd9Sstevel@tonic-gate "mask=%llx\n", rnumber, 7827c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 7837c478bd9Sstevel@tonic-gate if (pmubus_mapreqp->mapreq_mask == 0) { 7847c478bd9Sstevel@tonic-gate kmem_free(pmubus_mapreqp, 7857c478bd9Sstevel@tonic-gate sizeof (pmubus_mapreq_t)); 7867c478bd9Sstevel@tonic-gate ret = DDI_ME_INVAL; 7877c478bd9Sstevel@tonic-gate break; 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate hp->ahi_common.ah_bus_private = pmubus_mapreqp; 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate /* Initialize the access vectors */ 7947c478bd9Sstevel@tonic-gate hp->ahi_get8 = pmubus_get8; 7957c478bd9Sstevel@tonic-gate hp->ahi_get16 = pmubus_noget16; 7967c478bd9Sstevel@tonic-gate hp->ahi_get32 = pmubus_get32; 7977c478bd9Sstevel@tonic-gate hp->ahi_get64 = pmubus_noget64; 7987c478bd9Sstevel@tonic-gate hp->ahi_put8 = pmubus_put8; 7997c478bd9Sstevel@tonic-gate hp->ahi_put16 = pmubus_noput16; 8007c478bd9Sstevel@tonic-gate hp->ahi_put32 = pmubus_put32; 8017c478bd9Sstevel@tonic-gate hp->ahi_put64 = pmubus_noput64; 8027c478bd9Sstevel@tonic-gate hp->ahi_rep_get8 = pmubus_norep_get8; 8037c478bd9Sstevel@tonic-gate hp->ahi_rep_get16 = pmubus_norep_get16; 8047c478bd9Sstevel@tonic-gate hp->ahi_rep_get32 = pmubus_norep_get32; 8057c478bd9Sstevel@tonic-gate hp->ahi_rep_get64 = pmubus_norep_get64; 8067c478bd9Sstevel@tonic-gate hp->ahi_rep_put8 = pmubus_norep_put8; 8077c478bd9Sstevel@tonic-gate hp->ahi_rep_put16 = pmubus_norep_put16; 8087c478bd9Sstevel@tonic-gate hp->ahi_rep_put32 = pmubus_norep_put32; 8097c478bd9Sstevel@tonic-gate hp->ahi_rep_put64 = pmubus_norep_put64; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 8127c478bd9Sstevel@tonic-gate break; 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: { 8167c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate pmubus_mapreqp = hp->ahi_common.ah_bus_private; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* Free the our map request struct */ 8217c478bd9Sstevel@tonic-gate kmem_free(pmubus_mapreqp, sizeof (pmubus_mapreq_t)); 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 8247c478bd9Sstevel@tonic-gate break; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate default: 8287c478bd9Sstevel@tonic-gate ret = DDI_ME_UNSUPPORTED; 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate } else { 8317c478bd9Sstevel@tonic-gate /* Prepare the map request struct for a call to our parent */ 8327c478bd9Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 8337c478bd9Sstevel@tonic-gate mp->map_obj.rp = (struct regspec *)&pci_reg; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* Pass the mapping operation up the device tree */ 8367c478bd9Sstevel@tonic-gate ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 8377c478bd9Sstevel@tonic-gate (pdip, rdip, mp, off, len, addrp); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate done: 8417c478bd9Sstevel@tonic-gate if (pmubus_regs != NULL) 8427c478bd9Sstevel@tonic-gate kmem_free(pmubus_regs, pmubus_regs_size); 8437c478bd9Sstevel@tonic-gate if (pmubus_regmask != NULL) 8447c478bd9Sstevel@tonic-gate kmem_free(pmubus_regmask, pmubus_regmask_size); 8457c478bd9Sstevel@tonic-gate return (ret); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate static int 8497c478bd9Sstevel@tonic-gate pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 8507c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 8517c478bd9Sstevel@tonic-gate { 8527c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 8537c478bd9Sstevel@tonic-gate pmubus_obpregspec_t *pmubus_rp; 8547c478bd9Sstevel@tonic-gate char name[9]; 8557c478bd9Sstevel@tonic-gate int reglen; 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate switch (op) { 8587c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 8597c478bd9Sstevel@tonic-gate 860*a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, 8617c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)&pmubus_rp, 8627c478bd9Sstevel@tonic-gate ®len) != DDI_SUCCESS) { 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate if ((reglen % sizeof (pmubus_obpregspec_t)) != 0) { 8687c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8697c478bd9Sstevel@tonic-gate "pmubus: reg property not well-formed for " 8707c478bd9Sstevel@tonic-gate "%s size=%d\n", ddi_node_name(child), reglen); 8717c478bd9Sstevel@tonic-gate kmem_free(pmubus_rp, reglen); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "%x,%x", 8767c478bd9Sstevel@tonic-gate pmubus_rp->reg_addr_hi, pmubus_rp->reg_addr_lo); 8777c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 8787c478bd9Sstevel@tonic-gate kmem_free(pmubus_rp, reglen); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 8857c478bd9Sstevel@tonic-gate ddi_remove_minor_node(child, NULL); 8867c478bd9Sstevel@tonic-gate impl_rem_dev_props(child); 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8897c478bd9Sstevel@tonic-gate default: 8907c478bd9Sstevel@tonic-gate break; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 8947c478bd9Sstevel@tonic-gate } 895