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/autoconf.h> 347c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 357c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/errno.h> 387c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 397c478bd9Sstevel@tonic-gate #include <sys/debug.h> 407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #include <sys/spl.h> 427c478bd9Sstevel@tonic-gate #include <sys/async.h> 437c478bd9Sstevel@tonic-gate #include <sys/dvma.h> 447c478bd9Sstevel@tonic-gate #include <sys/upa64s.h> 457c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* 487c478bd9Sstevel@tonic-gate * driver global data: 497c478bd9Sstevel@tonic-gate */ 507c478bd9Sstevel@tonic-gate static void *per_upa64s_state; /* soft state pointer */ 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * function prototypes for bus ops routines: 547c478bd9Sstevel@tonic-gate */ 557c478bd9Sstevel@tonic-gate static int 567c478bd9Sstevel@tonic-gate upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 577c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *addrp); 587c478bd9Sstevel@tonic-gate static int 597c478bd9Sstevel@tonic-gate upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip, 607c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 617c478bd9Sstevel@tonic-gate static int 627c478bd9Sstevel@tonic-gate upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 637c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result); 647c478bd9Sstevel@tonic-gate static int 657c478bd9Sstevel@tonic-gate upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 667c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp); 677c478bd9Sstevel@tonic-gate static int 687c478bd9Sstevel@tonic-gate upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 697c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp); 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * function prototypes for dev ops routines: 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate static int upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 757c478bd9Sstevel@tonic-gate static int upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 767c478bd9Sstevel@tonic-gate static int upa64s_power(dev_info_t *dip, int component, int level); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * bus ops and dev ops structures: 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate static struct bus_ops upa64s_bus_ops = { 827c478bd9Sstevel@tonic-gate BUSO_REV, 837c478bd9Sstevel@tonic-gate upa64s_map, 847c478bd9Sstevel@tonic-gate 0, 857c478bd9Sstevel@tonic-gate 0, 867c478bd9Sstevel@tonic-gate 0, 877c478bd9Sstevel@tonic-gate i_ddi_map_fault, 887c478bd9Sstevel@tonic-gate ddi_no_dma_map, 897c478bd9Sstevel@tonic-gate ddi_no_dma_allochdl, 907c478bd9Sstevel@tonic-gate ddi_no_dma_freehdl, 917c478bd9Sstevel@tonic-gate ddi_no_dma_bindhdl, 927c478bd9Sstevel@tonic-gate ddi_no_dma_unbindhdl, 937c478bd9Sstevel@tonic-gate ddi_no_dma_flush, 947c478bd9Sstevel@tonic-gate ddi_no_dma_win, 957c478bd9Sstevel@tonic-gate ddi_no_dma_mctl, 967c478bd9Sstevel@tonic-gate upa64s_ctlops, 977c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 987c478bd9Sstevel@tonic-gate 0, 997c478bd9Sstevel@tonic-gate 0, 1007c478bd9Sstevel@tonic-gate 0, 1017c478bd9Sstevel@tonic-gate 0, 1027c478bd9Sstevel@tonic-gate 0, 1037c478bd9Sstevel@tonic-gate 0, 1047c478bd9Sstevel@tonic-gate 0, 1057c478bd9Sstevel@tonic-gate 0, 1067c478bd9Sstevel@tonic-gate 0, 1077c478bd9Sstevel@tonic-gate 0, 1087c478bd9Sstevel@tonic-gate 0, 1097c478bd9Sstevel@tonic-gate 0, 1107c478bd9Sstevel@tonic-gate upa64_intr_ops 1117c478bd9Sstevel@tonic-gate }; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static struct dev_ops upa64s_ops = { 1147c478bd9Sstevel@tonic-gate DEVO_REV, 1157c478bd9Sstevel@tonic-gate 0, 1167c478bd9Sstevel@tonic-gate ddi_no_info, 1177c478bd9Sstevel@tonic-gate nulldev, 1187c478bd9Sstevel@tonic-gate 0, 1197c478bd9Sstevel@tonic-gate upa64s_attach, 1207c478bd9Sstevel@tonic-gate upa64s_detach, 1217c478bd9Sstevel@tonic-gate nodev, 1227c478bd9Sstevel@tonic-gate (struct cb_ops *)0, 1237c478bd9Sstevel@tonic-gate &upa64s_bus_ops, 1247c478bd9Sstevel@tonic-gate upa64s_power 1257c478bd9Sstevel@tonic-gate }; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * module definitions: 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1317c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1347c478bd9Sstevel@tonic-gate &mod_driverops, /* type of module */ 1357c478bd9Sstevel@tonic-gate "UPA64S nexus driver %I%", /* name of module */ 1367c478bd9Sstevel@tonic-gate &upa64s_ops, /* driver ops */ 1377c478bd9Sstevel@tonic-gate }; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1407c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1417c478bd9Sstevel@tonic-gate }; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate int 1447c478bd9Sstevel@tonic-gate _init(void) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate int e; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Initialize per instance bus soft state pointer. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate if (e = ddi_soft_state_init(&per_upa64s_state, 1527c478bd9Sstevel@tonic-gate sizeof (upa64s_devstate_t), 2)) 1537c478bd9Sstevel@tonic-gate return (e); 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * Install the module. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate if (e = mod_install(&modlinkage)) 1587c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_upa64s_state); 1597c478bd9Sstevel@tonic-gate return (e); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate int 1637c478bd9Sstevel@tonic-gate _fini(void) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate int e = mod_remove(&modlinkage); 1667c478bd9Sstevel@tonic-gate if (e) 1677c478bd9Sstevel@tonic-gate return (e); 1687c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_upa64s_state); 1697c478bd9Sstevel@tonic-gate return (e); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate int 1737c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * forward declarations: 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate static void upa64s_intrdist(void *arg); 1837c478bd9Sstevel@tonic-gate static int init_child(dev_info_t *child); 1847c478bd9Sstevel@tonic-gate static int report_dev(dev_info_t *dip); 1857c478bd9Sstevel@tonic-gate static int get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip); 1867c478bd9Sstevel@tonic-gate static void save_state(upa64s_devstate_t *upa64s_p); 1877c478bd9Sstevel@tonic-gate static void restore_state(upa64s_devstate_t *upa64s_p); 1887c478bd9Sstevel@tonic-gate static int xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *upa64s_rp, 1897c478bd9Sstevel@tonic-gate off_t off, off_t len, struct regspec *rp); 1907c478bd9Sstevel@tonic-gate static int get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber, 1917c478bd9Sstevel@tonic-gate off_t off, off_t len, struct regspec *rp); 1927c478bd9Sstevel@tonic-gate static off_t get_reg_set_size(dev_info_t *child, int rnumber); 1937c478bd9Sstevel@tonic-gate static uint_t get_nreg_set(dev_info_t *child); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* device driver entry points */ 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * attach entry point: 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate static int 2027c478bd9Sstevel@tonic-gate upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate upa64s_devstate_t *upa64s_p; /* per upa64s state pointer */ 2057c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 2067c478bd9Sstevel@tonic-gate int instance; 2077c478bd9Sstevel@tonic-gate char *pmc[] = { "NAME=Framebuffer Power", "0=Off", "1=On", NULL }; 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate switch (cmd) { 2107c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * Allocate and get the per instance soft state structure. 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 2157c478bd9Sstevel@tonic-gate if (alloc_upa64s_soft_state(instance) != DDI_SUCCESS) { 2167c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can't allocate upa64s state", 2177c478bd9Sstevel@tonic-gate ddi_get_name(dip), instance); 2187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate upa64s_p = get_upa64s_soft_state(instance); 2217c478bd9Sstevel@tonic-gate upa64s_p->dip = dip; 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate /* 2247c478bd9Sstevel@tonic-gate * Get key properties of the bridge node. 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate if (get_properties(upa64s_p, dip) != DDI_SUCCESS) 2277c478bd9Sstevel@tonic-gate goto fail; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * Create "pm-components" property for the purpose of 2317c478bd9Sstevel@tonic-gate * doing Power Management. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 2347c478bd9Sstevel@tonic-gate "pm-components", pmc, ((sizeof (pmc)/sizeof (char *)) - 1)) 2357c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 2367c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to create pm-components " 2377c478bd9Sstevel@tonic-gate "property.", ddi_get_name(dip), instance); 2387c478bd9Sstevel@tonic-gate goto fail; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* Map in the UPA's registers */ 2427c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 2437c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 2447c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 2457c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0, 2467c478bd9Sstevel@tonic-gate (caddr_t *)&upa64s_p->config_base, 0, 0, &attr, 2477c478bd9Sstevel@tonic-gate &upa64s_p->config_base_ah) != DDI_SUCCESS) { 2487c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to map reg1.", 2497c478bd9Sstevel@tonic-gate ddi_get_name(dip), instance); 2507c478bd9Sstevel@tonic-gate goto fail; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate upa64s_p->upa0_config = (uint64_t *)(upa64s_p->config_base + 2547c478bd9Sstevel@tonic-gate UPA64S_UPA0_CONFIG_OFFSET); 2557c478bd9Sstevel@tonic-gate upa64s_p->upa1_config = (uint64_t *)(upa64s_p->config_base + 2567c478bd9Sstevel@tonic-gate UPA64S_UPA1_CONFIG_OFFSET); 2577c478bd9Sstevel@tonic-gate upa64s_p->if_config = (uint64_t *)(upa64s_p->config_base + 2587c478bd9Sstevel@tonic-gate UPA64S_IF_CONFIG_OFFSET); 2597c478bd9Sstevel@tonic-gate upa64s_p->estar = (uint64_t *)(upa64s_p->config_base + 2607c478bd9Sstevel@tonic-gate UPA64S_ESTAR_OFFSET); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, (caddr_t *)&upa64s_p->imr[0], 2637c478bd9Sstevel@tonic-gate 0, 0, &attr, &upa64s_p->imr_ah[0]) != DDI_SUCCESS) { 2647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to map reg2.", 2657c478bd9Sstevel@tonic-gate ddi_get_name(dip), instance); 2667c478bd9Sstevel@tonic-gate goto fail1; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 2, (caddr_t *)&upa64s_p->imr[1], 2707c478bd9Sstevel@tonic-gate 0, 0, &attr, &upa64s_p->imr_ah[1]) != DDI_SUCCESS) { 2717c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to map reg3.", 2727c478bd9Sstevel@tonic-gate ddi_get_name(dip), instance); 2737c478bd9Sstevel@tonic-gate goto fail2; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /* 2777c478bd9Sstevel@tonic-gate * Power level of a component is unknown at attach time. 2787c478bd9Sstevel@tonic-gate * Bring the power level to what is needed for normal operation. 2797c478bd9Sstevel@tonic-gate */ 2807c478bd9Sstevel@tonic-gate upa64s_p->power_level = UPA64S_PM_UNKNOWN; 2817c478bd9Sstevel@tonic-gate if (pm_raise_power(dip, UPA64S_PM_COMP, UPA64S_PM_NORMOP) != 2827c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 2837c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to raise the power.", 2847c478bd9Sstevel@tonic-gate ddi_get_name(dip), instance); 2857c478bd9Sstevel@tonic-gate goto fail3; 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate intr_dist_add(upa64s_intrdist, dip); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 2917c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate case DDI_RESUME: 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate upa64s_p = get_upa64s_soft_state(ddi_get_instance(dip)); 2967c478bd9Sstevel@tonic-gate DBG(D_ATTACH, dip, "DDI_RESUME\n"); 2977c478bd9Sstevel@tonic-gate restore_state(upa64s_p); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* 3007c478bd9Sstevel@tonic-gate * Power level of a component is unknown at resume time. 3017c478bd9Sstevel@tonic-gate * Bring the power level to what it was before suspend. 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate upa64s_p->power_level = UPA64S_PM_UNKNOWN; 3047c478bd9Sstevel@tonic-gate if (pm_raise_power(dip, UPA64S_PM_COMP, 3057c478bd9Sstevel@tonic-gate upa64s_p->saved_power_level) != DDI_SUCCESS) 3067c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to change power level " 3077c478bd9Sstevel@tonic-gate "during resume!", ddi_get_name(dip), instance); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate default: 3127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate fail3: 3167c478bd9Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[1]); 3177c478bd9Sstevel@tonic-gate fail2: 3187c478bd9Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[0]); 3197c478bd9Sstevel@tonic-gate fail1: 3207c478bd9Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->config_base_ah); 3217c478bd9Sstevel@tonic-gate fail: 3227c478bd9Sstevel@tonic-gate free_upa64s_soft_state(instance); 3237c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * detach entry point: 3297c478bd9Sstevel@tonic-gate */ 3307c478bd9Sstevel@tonic-gate static int 3317c478bd9Sstevel@tonic-gate upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3327c478bd9Sstevel@tonic-gate { 3337c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 3347c478bd9Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate switch (cmd) { 3377c478bd9Sstevel@tonic-gate case DDI_DETACH: 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate DBG(D_DETACH, dip, "DDI_DETACH\n"); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Power down the device. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate if (pm_lower_power(dip, UPA64S_PM_COMP, UPA64S_PM_RESET) != 3457c478bd9Sstevel@tonic-gate DDI_SUCCESS) 3467c478bd9Sstevel@tonic-gate DBG(D_DETACH, dip, "failed to power off!\n"); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate intr_dist_rem(upa64s_intrdist, dip); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->config_base_ah); 3517c478bd9Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[0]); 3527c478bd9Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[1]); 3537c478bd9Sstevel@tonic-gate free_upa64s_soft_state(instance); 3547c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate DBG(D_DETACH, dip, "DDI_SUSPEND\n"); 3597c478bd9Sstevel@tonic-gate save_state(upa64s_p); 3607c478bd9Sstevel@tonic-gate upa64s_p->saved_power_level = upa64s_p->power_level; 3617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * power entry point: 3697c478bd9Sstevel@tonic-gate * 3707c478bd9Sstevel@tonic-gate * This entry point is called by Power Management framework to 3717c478bd9Sstevel@tonic-gate * reset upa bus and slow down/speed up the upa interface of 3727c478bd9Sstevel@tonic-gate * Schizo chip. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate static int 3757c478bd9Sstevel@tonic-gate upa64s_power(dev_info_t *dip, int component, int level) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 3787c478bd9Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 3797c478bd9Sstevel@tonic-gate volatile uint64_t uint64_data; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate DBG2(D_POWER, dip, "component=%d, level=%d\n", component, level); 3827c478bd9Sstevel@tonic-gate if (component != UPA64S_PM_COMP || 3837c478bd9Sstevel@tonic-gate level < UPA64S_PM_RESET || level > UPA64S_PM_NORMOP) 3847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * We can't set the hardware to the state that it is 3887c478bd9Sstevel@tonic-gate * already in. So if the power state is not known, inquire the 3897c478bd9Sstevel@tonic-gate * state of the hardware. If it is already in that state, 3907c478bd9Sstevel@tonic-gate * record and return, otherwise make the state change. 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate if (upa64s_p->power_level == UPA64S_PM_UNKNOWN) { 3937c478bd9Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah, 3947c478bd9Sstevel@tonic-gate upa64s_p->if_config); 3957c478bd9Sstevel@tonic-gate if ((level == UPA64S_PM_RESET && 3967c478bd9Sstevel@tonic-gate uint64_data == UPA64S_NOT_POK_RST_L) || 3977c478bd9Sstevel@tonic-gate (level == UPA64S_PM_NORMOP && 3987c478bd9Sstevel@tonic-gate uint64_data == UPA64S_POK_NOT_RST_L)) { 3997c478bd9Sstevel@tonic-gate upa64s_p->power_level = level; 4007c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate if (level == upa64s_p->power_level) { 4057c478bd9Sstevel@tonic-gate DBG1(D_POWER, dip, "device is already at power level %d\n", 4067c478bd9Sstevel@tonic-gate level); 4077c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (level == UPA64S_PM_RESET) { 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * Assert UPA64S_RESET 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 4167c478bd9Sstevel@tonic-gate UPA64S_POK_RST_L); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Deassert UPA64S_POK. Flush the store buffer. 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 4227c478bd9Sstevel@tonic-gate UPA64S_NOT_POK_RST_L); 4237c478bd9Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah, 4247c478bd9Sstevel@tonic-gate upa64s_p->if_config); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Internal UPA clock to 1/2 speed 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 4307c478bd9Sstevel@tonic-gate UPA64S_1_2_SPEED); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * Internal UPA clock to 1/64 speed. Flush the store buffer. 4347c478bd9Sstevel@tonic-gate */ 4357c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 4367c478bd9Sstevel@tonic-gate UPA64S_1_64_SPEED); 4377c478bd9Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah, 4387c478bd9Sstevel@tonic-gate upa64s_p->estar); 4397c478bd9Sstevel@tonic-gate } else { 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * Internal UPA clock to 1/2 speed 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 4447c478bd9Sstevel@tonic-gate UPA64S_1_2_SPEED); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Internal UPA clock to full speed. Flush the store buffer. 4487c478bd9Sstevel@tonic-gate */ 4497c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar, 4507c478bd9Sstevel@tonic-gate UPA64S_FULL_SPEED); 4517c478bd9Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah, 4527c478bd9Sstevel@tonic-gate upa64s_p->estar); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Assert UPA64S_POK. Flush the store buffer before 4567c478bd9Sstevel@tonic-gate * the wait delay. 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 4597c478bd9Sstevel@tonic-gate UPA64S_POK_RST_L); 4607c478bd9Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah, 4617c478bd9Sstevel@tonic-gate upa64s_p->if_config); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * Delay 20 milliseconds for the signals to settle down. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate delay(drv_usectohz(20*1000)); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Deassert UPA64S_RESET. Flush the store buffer. 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config, 4727c478bd9Sstevel@tonic-gate UPA64S_POK_NOT_RST_L); 4737c478bd9Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah, 4747c478bd9Sstevel@tonic-gate upa64s_p->if_config); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate upa64s_p->power_level = level; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* bus driver entry points */ 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * bus map entry point: 4857c478bd9Sstevel@tonic-gate * 4867c478bd9Sstevel@tonic-gate * if map request is for an rnumber 4877c478bd9Sstevel@tonic-gate * get the corresponding regspec from device node 4887c478bd9Sstevel@tonic-gate * build a new regspec in our parent's format 4897c478bd9Sstevel@tonic-gate * build a new map_req with the new regspec 4907c478bd9Sstevel@tonic-gate * call up the tree to complete the mapping 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate static int 4937c478bd9Sstevel@tonic-gate upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 4947c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 4957c478bd9Sstevel@tonic-gate { 4967c478bd9Sstevel@tonic-gate struct regspec regspec; 4977c478bd9Sstevel@tonic-gate ddi_map_req_t p_map_request; 4987c478bd9Sstevel@tonic-gate int rnumber, rval; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate DBG4(D_MAP, dip, "upa64s_map() mp=%x.%x addrp=%x.%08x\n", 5017c478bd9Sstevel@tonic-gate HI32(mp), LO32(mp), HI32(addrp), LO32(addrp)); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate * User level mappings are not supported yet. 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate if (mp->map_flags & DDI_MF_USER_MAPPING) { 5077c478bd9Sstevel@tonic-gate DBG2(D_MAP, dip, "rdip=%s%d: no user level mappings yet!\n", 5087c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 5097c478bd9Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * Now handle the mapping according to its type. 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate switch (mp->map_type) { 5167c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* 5197c478bd9Sstevel@tonic-gate * We assume the register specification is in PCI format. 5207c478bd9Sstevel@tonic-gate * We must convert it into a regspec of our parent's 5217c478bd9Sstevel@tonic-gate * and pass the request to our parent. 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate DBG3(D_MAP, dip, "rdip=%s%d: REGSPEC - handlep=%x\n", 5247c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 5257c478bd9Sstevel@tonic-gate mp->map_handlep); 5267c478bd9Sstevel@tonic-gate rval = xlate_reg_prop(dip, (upa64s_regspec_t *)mp->map_obj.rp, 5277c478bd9Sstevel@tonic-gate off, len, ®spec); 5287c478bd9Sstevel@tonic-gate break; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * Get the "reg" property from the device node and convert 5347c478bd9Sstevel@tonic-gate * it to our parent's format. 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate DBG4(D_MAP, dip, "rdip=%s%d: rnumber=%x handlep=%x\n", 5377c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 5387c478bd9Sstevel@tonic-gate mp->map_obj.rnumber, mp->map_handlep); 5397c478bd9Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 5407c478bd9Sstevel@tonic-gate if (rnumber < 0) 5417c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 5427c478bd9Sstevel@tonic-gate rval = get_reg_set(dip, rdip, rnumber, off, len, ®spec); 5437c478bd9Sstevel@tonic-gate break; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate default: 5467c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 5507c478bd9Sstevel@tonic-gate DBG(D_MAP, dip, "failed on regspec\n\n"); 5517c478bd9Sstevel@tonic-gate return (rval); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * Now we have a copy of the upa64s regspec converted to our parent's 5567c478bd9Sstevel@tonic-gate * format. Build a new map request based on this regspec and pass 5577c478bd9Sstevel@tonic-gate * it to our parent. 5587c478bd9Sstevel@tonic-gate */ 5597c478bd9Sstevel@tonic-gate p_map_request = *mp; 5607c478bd9Sstevel@tonic-gate p_map_request.map_type = DDI_MT_REGSPEC; 5617c478bd9Sstevel@tonic-gate p_map_request.map_obj.rp = ®spec; 5627c478bd9Sstevel@tonic-gate rval = ddi_map(dip, &p_map_request, 0, 0, addrp); 5637c478bd9Sstevel@tonic-gate DBG3(D_MAP, dip, "ddi_map returns: rval=%x addrp=%x.%08x\n\n", 5647c478bd9Sstevel@tonic-gate rval, HI32(*addrp), LO32(*addrp)); 5657c478bd9Sstevel@tonic-gate return (rval); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * Translate the UPA devices interrupt property. This is the only case I 5707c478bd9Sstevel@tonic-gate * know of where the interrupts property is meaningless. As a result, we 5717c478bd9Sstevel@tonic-gate * just use UPA_BASE_INO as our interrupt value and add to it the upa port id. 5727c478bd9Sstevel@tonic-gate * UPA portid is returned too. 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate #define UPA_BASE_INO 0x2a 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate static int 577*a195726fSgovinda upa64s_xlate_intr(dev_info_t *rdip, int32_t safariport, uint32_t *intr) 5787c478bd9Sstevel@tonic-gate { 5797c478bd9Sstevel@tonic-gate uint32_t ino = UPA_BASE_INO; 5807c478bd9Sstevel@tonic-gate int32_t portid; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* Clear the ffb's interrupts property, it's meaningless */ 583*a195726fSgovinda *intr = 0; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate if ((portid = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 5867c478bd9Sstevel@tonic-gate "upa-portid", -1)) == -1) 5877c478bd9Sstevel@tonic-gate return (-1); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate ino += portid; 5907c478bd9Sstevel@tonic-gate 591*a195726fSgovinda *intr = UPA64S_MAKE_MONDO(safariport, ino); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate DBG5(D_A_ISPEC, rdip, "upa64s_xlate_intr: rdip=%s%d: upa portid %d " 5947c478bd9Sstevel@tonic-gate "ino=%x mondo 0x%x\n", ddi_get_name(rdip), ddi_get_instance(rdip), 595*a195726fSgovinda portid, ino, *intr); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate return (portid); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 6017c478bd9Sstevel@tonic-gate * bus add intrspec entry point: 6027c478bd9Sstevel@tonic-gate */ 6037c478bd9Sstevel@tonic-gate static int 6047c478bd9Sstevel@tonic-gate upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, 6057c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 6067c478bd9Sstevel@tonic-gate { 6077c478bd9Sstevel@tonic-gate int upaport, instance = ddi_get_instance(dip); 6087c478bd9Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 6097c478bd9Sstevel@tonic-gate #ifdef DEBUG 6107c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t, caddr_t) = hdlp->ih_cb_func; 6117c478bd9Sstevel@tonic-gate caddr_t int_handler_arg1 = hdlp->ih_cb_arg1; 6127c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 6137c478bd9Sstevel@tonic-gate uint_t cpu_id; 6147c478bd9Sstevel@tonic-gate volatile uint64_t imr_data; 6157c478bd9Sstevel@tonic-gate 616*a195726fSgovinda upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, 617*a195726fSgovinda (uint32_t *)&hdlp->ih_vector); 6187c478bd9Sstevel@tonic-gate 619*a195726fSgovinda if (hdlp->ih_vector == 0) 6207c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate DBG3(D_A_ISPEC, dip, 6237c478bd9Sstevel@tonic-gate "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n", 624*a195726fSgovinda ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate * Make sure an interrupt handler isn't already installed. 6287c478bd9Sstevel@tonic-gate */ 6297c478bd9Sstevel@tonic-gate if (upa64s_p->ino_state[upaport] != INO_FREE) { 6307c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * Install the handler in the system table. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate #ifdef DEBUG 6377c478bd9Sstevel@tonic-gate DBG2(D_A_ISPEC, dip, "i_ddi_add_ivintr: hdlr=%p arg=%p\n", 6387c478bd9Sstevel@tonic-gate int_handler, int_handler_arg1); 6397c478bd9Sstevel@tonic-gate #endif 6407c478bd9Sstevel@tonic-gate if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS) 6417c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate cpu_id = intr_dist_cpuid(); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* 6467c478bd9Sstevel@tonic-gate * Enable the interrupt through its interrupt mapping register. 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate imr_data = UPA64S_CPUID_TO_IMR(cpu_id); 6497c478bd9Sstevel@tonic-gate imr_data = UPA64S_GET_MAP_REG(hdlp->ih_vector, imr_data); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate DBG4(D_A_ISPEC, dip, "IMR [upaport=%d mapping reg 0x%p] = %x.%x\n", 6527c478bd9Sstevel@tonic-gate upaport, upa64s_p->imr[upaport], HI32(imr_data), LO32(imr_data)); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], imr_data); 6557c478bd9Sstevel@tonic-gate /* Read the data back to flush store buffers. */ 6567c478bd9Sstevel@tonic-gate imr_data = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]); 6577c478bd9Sstevel@tonic-gate upa64s_p->ino_state[upaport] = INO_INUSE; 6587c478bd9Sstevel@tonic-gate 659*a195726fSgovinda DBG(D_A_ISPEC, dip, "add_intr success!\n"); 6607c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * bus remove intrspec entry point 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate static int 6687c478bd9Sstevel@tonic-gate upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, 6697c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = 6727c478bd9Sstevel@tonic-gate get_upa64s_soft_state(ddi_get_instance(dip)); 6737c478bd9Sstevel@tonic-gate int upaport; 6747c478bd9Sstevel@tonic-gate #ifndef lint 6757c478bd9Sstevel@tonic-gate volatile uint64_t tmp; 6767c478bd9Sstevel@tonic-gate #endif 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * Make sure the mondo is valid. 6807c478bd9Sstevel@tonic-gate */ 681*a195726fSgovinda upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, 682*a195726fSgovinda (uint32_t *)&hdlp->ih_vector); 6837c478bd9Sstevel@tonic-gate 684*a195726fSgovinda if (hdlp->ih_vector == 0) 6857c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate DBG3(D_R_ISPEC, dip, 6887c478bd9Sstevel@tonic-gate "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n", 689*a195726fSgovinda ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate if (upa64s_p->ino_state[upaport] != INO_INUSE) { 6927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate /* Call up to our parent to handle the removal */ 6967c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], 0); 6997c478bd9Sstevel@tonic-gate #ifndef lint 7007c478bd9Sstevel@tonic-gate /* Flush store buffers */ 7017c478bd9Sstevel@tonic-gate tmp = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]); 7027c478bd9Sstevel@tonic-gate #endif 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate upa64s_p->ino_state[upaport] = INO_FREE; 7057c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* new intr_ops structure */ 7107c478bd9Sstevel@tonic-gate static int 7117c478bd9Sstevel@tonic-gate upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 7127c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 7137c478bd9Sstevel@tonic-gate { 7147c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate switch (intr_op) { 7177c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 718*a195726fSgovinda *(int *)result = DDI_INTR_FLAG_EDGE; 7197c478bd9Sstevel@tonic-gate break; 7207c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 7217c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 7227c478bd9Sstevel@tonic-gate break; 7237c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 7247c478bd9Sstevel@tonic-gate break; 7257c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 7267c478bd9Sstevel@tonic-gate /* 7277c478bd9Sstevel@tonic-gate * We only have slave UPA devices so force the PIL to 5. 7287c478bd9Sstevel@tonic-gate * this is done since all slave UPA devices have historically 7297c478bd9Sstevel@tonic-gate * had their PILs set to 5. Only do it if the PIL is not 7307c478bd9Sstevel@tonic-gate * being preset. 7317c478bd9Sstevel@tonic-gate */ 732*a195726fSgovinda *(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 5; 7337c478bd9Sstevel@tonic-gate break; 7347c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 7357c478bd9Sstevel@tonic-gate break; 7367c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 7377c478bd9Sstevel@tonic-gate ret = upa64s_add_intr_impl(dip, rdip, hdlp); 7387c478bd9Sstevel@tonic-gate break; 7397c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 7407c478bd9Sstevel@tonic-gate ret = upa64s_remove_intr_impl(dip, rdip, hdlp); 7417c478bd9Sstevel@tonic-gate break; 7427c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 7437c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 7447c478bd9Sstevel@tonic-gate break; 7457c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 7467c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 7477c478bd9Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip); 7487c478bd9Sstevel@tonic-gate break; 7497c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 7507c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 7517c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 7527c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 7537c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 7547c478bd9Sstevel@tonic-gate break; 7557c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 7567c478bd9Sstevel@tonic-gate /* only support fixed interrupts */ 7577c478bd9Sstevel@tonic-gate *(int *)result = i_ddi_get_nintrs(rdip) ? 7587c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0; 7597c478bd9Sstevel@tonic-gate break; 7607c478bd9Sstevel@tonic-gate default: 7617c478bd9Sstevel@tonic-gate ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result); 7627c478bd9Sstevel@tonic-gate break; 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate return (ret); 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate #ifdef DEBUG 7697c478bd9Sstevel@tonic-gate uint_t upa64s_debug_flags = (uint_t)0; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...); 7727c478bd9Sstevel@tonic-gate #endif 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * control ops entry point: 7767c478bd9Sstevel@tonic-gate * 7777c478bd9Sstevel@tonic-gate * Requests handled completely: 7787c478bd9Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD see init_child() for details 7797c478bd9Sstevel@tonic-gate * DDI_CTLOPS_UNINITCHILD 7807c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV see report_dev() for details 7817c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REGSIZE 7827c478bd9Sstevel@tonic-gate * DDI_CTLOPS_NREGS 7837c478bd9Sstevel@tonic-gate * 7847c478bd9Sstevel@tonic-gate * All others passed to parent. 7857c478bd9Sstevel@tonic-gate */ 7867c478bd9Sstevel@tonic-gate static int 7877c478bd9Sstevel@tonic-gate upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip, 7887c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate DBG5(D_CTLOPS, dip, "dip=%x.%x rdip=%x.%x op=%x", 7917c478bd9Sstevel@tonic-gate HI32(dip), LO32(dip), HI32(rdip), LO32(rdip), op); 7927c478bd9Sstevel@tonic-gate DBG4(D_CTLOPS|D_CONT, dip, " arg=%x.%x result=%x.%x\n", 7937c478bd9Sstevel@tonic-gate HI32(arg), LO32(arg), HI32(result), LO32(result)); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate switch (op) { 7967c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 7977c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n", 7987c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 7997c478bd9Sstevel@tonic-gate return (init_child((dev_info_t *)arg)); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 8027c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n", 8037c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8047c478bd9Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, NULL); 8057c478bd9Sstevel@tonic-gate ddi_remove_minor_node((dev_info_t *)arg, NULL); 8067c478bd9Sstevel@tonic-gate impl_rem_dev_props((dev_info_t *)arg); 8077c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 8107c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n", 8117c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8127c478bd9Sstevel@tonic-gate return (report_dev(rdip)); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 8157c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n", 8167c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8177c478bd9Sstevel@tonic-gate *((off_t *)result) = get_reg_set_size(rdip, *((int *)arg)); 8187c478bd9Sstevel@tonic-gate return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 8217c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_NREGS: rdip=%s%d\n", 8227c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8237c478bd9Sstevel@tonic-gate *((uint_t *)result) = get_nreg_set(rdip); 8247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * Now pass the request up to our parent. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate DBG3(D_CTLOPS, dip, "passing request to parent: rdip=%s%d op=%x\n\n", 8317c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), op); 8327c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* support routines */ 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * get_properties 8407c478bd9Sstevel@tonic-gate * 8417c478bd9Sstevel@tonic-gate * This function is called from the attach routine to get the key 8427c478bd9Sstevel@tonic-gate * properties of the upa64s node. 8437c478bd9Sstevel@tonic-gate * 8447c478bd9Sstevel@tonic-gate * used by: upa64s_attach() 8457c478bd9Sstevel@tonic-gate * 8467c478bd9Sstevel@tonic-gate * return value: none 8477c478bd9Sstevel@tonic-gate */ 8487c478bd9Sstevel@tonic-gate static int 8497c478bd9Sstevel@tonic-gate get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip) 8507c478bd9Sstevel@tonic-gate { 8517c478bd9Sstevel@tonic-gate int safari_id; 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate /* 8547c478bd9Sstevel@tonic-gate * Get the device's safari id. 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate safari_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 8577c478bd9Sstevel@tonic-gate "portid", -1); 8587c478bd9Sstevel@tonic-gate if (safari_id == -1) { 8597c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 8607c478bd9Sstevel@tonic-gate panic("%s%d: no portid property", ddi_get_name(dip), instance); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate upa64s_p->safari_id = safari_id; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * save_state 8707c478bd9Sstevel@tonic-gate * 8717c478bd9Sstevel@tonic-gate * This routine saves a copy of the upa64s register state. 8727c478bd9Sstevel@tonic-gate * 8737c478bd9Sstevel@tonic-gate * used by: upa64s_detach() on a suspend operation 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate static void 8767c478bd9Sstevel@tonic-gate save_state(upa64s_devstate_t *upa64s_p) 8777c478bd9Sstevel@tonic-gate { 8787c478bd9Sstevel@tonic-gate upa64s_p->imr_data[0] = ddi_get64(upa64s_p->imr_ah[0], 8797c478bd9Sstevel@tonic-gate upa64s_p->imr[0]); 8807c478bd9Sstevel@tonic-gate upa64s_p->imr_data[1] = ddi_get64(upa64s_p->imr_ah[1], 8817c478bd9Sstevel@tonic-gate upa64s_p->imr[1]); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* 8867c478bd9Sstevel@tonic-gate * restore_state 8877c478bd9Sstevel@tonic-gate * 8887c478bd9Sstevel@tonic-gate * This routine restores a copy of the upa64s register state. 8897c478bd9Sstevel@tonic-gate * 8907c478bd9Sstevel@tonic-gate * used by: upa64s_attach() on a resume operation 8917c478bd9Sstevel@tonic-gate */ 8927c478bd9Sstevel@tonic-gate static void 8937c478bd9Sstevel@tonic-gate restore_state(upa64s_devstate_t *upa64s_p) 8947c478bd9Sstevel@tonic-gate { 8957c478bd9Sstevel@tonic-gate #ifndef lint 8967c478bd9Sstevel@tonic-gate volatile uint64_t tmp; 8977c478bd9Sstevel@tonic-gate #endif 8987c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[0], upa64s_p->imr[0], 8997c478bd9Sstevel@tonic-gate upa64s_p->imr_data[0]); 9007c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[1], upa64s_p->imr[1], 9017c478bd9Sstevel@tonic-gate upa64s_p->imr_data[1]); 9027c478bd9Sstevel@tonic-gate #ifndef lint 9037c478bd9Sstevel@tonic-gate /* Flush the store buffer */ 9047c478bd9Sstevel@tonic-gate tmp = ddi_get64(upa64s_p->imr_ah[0], upa64s_p->imr[0]); 9057c478bd9Sstevel@tonic-gate tmp = ddi_get64(upa64s_p->imr_ah[1], upa64s_p->imr[1]); 9067c478bd9Sstevel@tonic-gate #endif 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate /* 9117c478bd9Sstevel@tonic-gate * get_reg_set 9127c478bd9Sstevel@tonic-gate * 9137c478bd9Sstevel@tonic-gate * This routine will get a upa64s format regspec for a given 9147c478bd9Sstevel@tonic-gate * device node and register number. 9157c478bd9Sstevel@tonic-gate * 9167c478bd9Sstevel@tonic-gate * used by: upa64s_map() 9177c478bd9Sstevel@tonic-gate * 9187c478bd9Sstevel@tonic-gate * return value: 9197c478bd9Sstevel@tonic-gate * 9207c478bd9Sstevel@tonic-gate * DDI_SUCCESS - on success 9217c478bd9Sstevel@tonic-gate * DDI_ME_INVAL - regspec is invalid 9227c478bd9Sstevel@tonic-gate * DDI_ME_RNUMBER_RANGE - rnumber out of range 9237c478bd9Sstevel@tonic-gate */ 9247c478bd9Sstevel@tonic-gate static int 9257c478bd9Sstevel@tonic-gate get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber, 9267c478bd9Sstevel@tonic-gate off_t off, off_t len, struct regspec *rp) 9277c478bd9Sstevel@tonic-gate { 9287c478bd9Sstevel@tonic-gate upa64s_regspec_t *upa64s_rp; 9297c478bd9Sstevel@tonic-gate int i, n, rval; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate /* 9327c478bd9Sstevel@tonic-gate * Get child device "reg" property 9337c478bd9Sstevel@tonic-gate */ 934a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 9357c478bd9Sstevel@tonic-gate (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS) 9367c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate n = i / (int)sizeof (upa64s_regspec_t); 9397c478bd9Sstevel@tonic-gate if (rnumber >= n) { 9407c478bd9Sstevel@tonic-gate kmem_free(upa64s_rp, i); 9417c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* 9457c478bd9Sstevel@tonic-gate * Convert each the upa64s format register specification to 9467c478bd9Sstevel@tonic-gate * out parent format. 9477c478bd9Sstevel@tonic-gate */ 9487c478bd9Sstevel@tonic-gate rval = xlate_reg_prop(dip, &upa64s_rp[rnumber], off, len, rp); 9497c478bd9Sstevel@tonic-gate kmem_free(upa64s_rp, i); 9507c478bd9Sstevel@tonic-gate return (rval); 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * xlate_reg_prop 9567c478bd9Sstevel@tonic-gate * 9577c478bd9Sstevel@tonic-gate * This routine converts a upa64s format regspec to a standard 9587c478bd9Sstevel@tonic-gate * regspec containing the corresponding system address. 9597c478bd9Sstevel@tonic-gate * 9607c478bd9Sstevel@tonic-gate * used by: upa64s_map() 9617c478bd9Sstevel@tonic-gate * 9627c478bd9Sstevel@tonic-gate * return value: 9637c478bd9Sstevel@tonic-gate * 9647c478bd9Sstevel@tonic-gate * DDI_SUCCESS 9657c478bd9Sstevel@tonic-gate * DDI_FAILURE - off + len is beyond device address range 9667c478bd9Sstevel@tonic-gate * DDI_ME_INVAL - regspec is invalid 9677c478bd9Sstevel@tonic-gate */ 9687c478bd9Sstevel@tonic-gate static int 9697c478bd9Sstevel@tonic-gate xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *child_rp, off_t off, 9707c478bd9Sstevel@tonic-gate off_t len, struct regspec *rp) 9717c478bd9Sstevel@tonic-gate { 9727c478bd9Sstevel@tonic-gate int n_ranges, ranges_len, i; 9737c478bd9Sstevel@tonic-gate uint64_t child_beg, child_end; 9747c478bd9Sstevel@tonic-gate upa64s_ranges_t *range_p, *rng_p; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate DBG4(D_MAP, dip, "upa64s regspec - ((%x,%x) (%x,%x))\n", 9777c478bd9Sstevel@tonic-gate HI32(child_rp->upa64s_phys), LO32(child_rp->upa64s_phys), 9787c478bd9Sstevel@tonic-gate HI32(child_rp->upa64s_size), LO32(child_rp->upa64s_size)); 9797c478bd9Sstevel@tonic-gate DBG2(D_MAP, dip, "upa64s xlate_reg_prp - off=%lx len=%lx\n", off, len); 9807c478bd9Sstevel@tonic-gate #if 0 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * both FFB and AFB have broken "reg" properties, all mapping 9837c478bd9Sstevel@tonic-gate * requests are done through reg-0 with very long offsets. 9847c478bd9Sstevel@tonic-gate * Hence this safety check is always violated. 9857c478bd9Sstevel@tonic-gate */ 9867c478bd9Sstevel@tonic-gate if (off + len > child_rp->upa64s_size) { 9877c478bd9Sstevel@tonic-gate DBG(D_MAP, dip, "upa64s xlate_reg_prp: bad off + len\n"); 9887c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate #endif 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * current "struct regspec" only supports 32-bit sizes. 9937c478bd9Sstevel@tonic-gate */ 9947c478bd9Sstevel@tonic-gate if (child_rp->upa64s_size >= (1ull << 32)) 9957c478bd9Sstevel@tonic-gate panic("upa64s: reg size must be less than 4 Gb"); 9967c478bd9Sstevel@tonic-gate 997a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 9987c478bd9Sstevel@tonic-gate "ranges", (caddr_t)&range_p, &ranges_len) != DDI_SUCCESS) { 9997c478bd9Sstevel@tonic-gate ranges_len = 0; 10007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no ranges property", 10017c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip)); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate n_ranges = ranges_len / sizeof (upa64s_regspec_t); 10057c478bd9Sstevel@tonic-gate child_beg = child_rp->upa64s_phys; 10067c478bd9Sstevel@tonic-gate #if 0 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * again, this safety checking can not be performed. 10097c478bd9Sstevel@tonic-gate * Hack by adding a pratical max child reg bank length. 10107c478bd9Sstevel@tonic-gate */ 10117c478bd9Sstevel@tonic-gate child_end = child_beg + child_rp->upa64s_size; 10127c478bd9Sstevel@tonic-gate #else 10137c478bd9Sstevel@tonic-gate #define UPA64S_MAX_CHILD_LEN 0xe000000 10147c478bd9Sstevel@tonic-gate child_end = child_beg + UPA64S_MAX_CHILD_LEN; 10157c478bd9Sstevel@tonic-gate #endif 10167c478bd9Sstevel@tonic-gate for (i = 0, rng_p = range_p; i < n_ranges; i++, rng_p++) { 10177c478bd9Sstevel@tonic-gate uint64_t rng_beg = rng_p->upa64s_child; 10187c478bd9Sstevel@tonic-gate uint64_t rng_end = rng_beg + rng_p->upa64s_size; 10197c478bd9Sstevel@tonic-gate if ((rng_beg <= child_beg) && (rng_end >= child_end)) { 10207c478bd9Sstevel@tonic-gate uint64_t addr = child_beg - rng_beg + off; 10217c478bd9Sstevel@tonic-gate addr += rng_p->upa64s_parent; 10227c478bd9Sstevel@tonic-gate rp->regspec_bustype = HI32(addr); 10237c478bd9Sstevel@tonic-gate rp->regspec_addr = LO32(addr); 10247c478bd9Sstevel@tonic-gate rp->regspec_size = len ? len : child_rp->upa64s_size; 10257c478bd9Sstevel@tonic-gate break; 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate if (ranges_len) 10297c478bd9Sstevel@tonic-gate kmem_free(range_p, ranges_len); 10307c478bd9Sstevel@tonic-gate DBG4(D_MAP, dip, "regspec (%x,%x,%x) i=%x\n", 10317c478bd9Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, i); 10327c478bd9Sstevel@tonic-gate return (i < n_ranges? DDI_SUCCESS : DDI_ME_INVAL); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * report_dev 10387c478bd9Sstevel@tonic-gate * 10397c478bd9Sstevel@tonic-gate * This function is called from our control ops routine on a 10407c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV request. 10417c478bd9Sstevel@tonic-gate */ 10427c478bd9Sstevel@tonic-gate static int 10437c478bd9Sstevel@tonic-gate report_dev(dev_info_t *dip) 10447c478bd9Sstevel@tonic-gate { 10457c478bd9Sstevel@tonic-gate if (dip == (dev_info_t *)0) 10467c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10477c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?UPA64S-device: %s@%s, %s #%d\n", 10487c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_name_addr(dip), 10497c478bd9Sstevel@tonic-gate ddi_major_to_name(ddi_name_to_major(ddi_get_name(dip))), 10507c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 10517c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* 10567c478bd9Sstevel@tonic-gate * init_child 10577c478bd9Sstevel@tonic-gate * 10587c478bd9Sstevel@tonic-gate * This function is called from our control ops routine on a 10597c478bd9Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD request. It builds and sets the device's 10607c478bd9Sstevel@tonic-gate * parent private data area. 10617c478bd9Sstevel@tonic-gate * 10627c478bd9Sstevel@tonic-gate * used by: upa64s_ctlops() 10637c478bd9Sstevel@tonic-gate * 10647c478bd9Sstevel@tonic-gate * return value: none 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate static int 10677c478bd9Sstevel@tonic-gate init_child(dev_info_t *child) 10687c478bd9Sstevel@tonic-gate { 10697c478bd9Sstevel@tonic-gate upa64s_regspec_t *child_rp; 10707c478bd9Sstevel@tonic-gate int i; 10717c478bd9Sstevel@tonic-gate char addr[256]; 10727c478bd9Sstevel@tonic-gate int32_t portid; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if ((portid = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 10757c478bd9Sstevel@tonic-gate "upa-portid", -1)) == -1) 10767c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate /* 10797c478bd9Sstevel@tonic-gate * Set the address portion of the node name based on 10807c478bd9Sstevel@tonic-gate * the function and device number. 10817c478bd9Sstevel@tonic-gate */ 1082a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 10837c478bd9Sstevel@tonic-gate (caddr_t)&child_rp, &i) != DDI_SUCCESS) { 10847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate (void) sprintf(addr, "%x,%x", portid, LO32(child_rp->upa64s_phys)); 10887c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, addr); 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 10917c478bd9Sstevel@tonic-gate kmem_free(child_rp, i); 10927c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * get_reg_set_size 10987c478bd9Sstevel@tonic-gate * 10997c478bd9Sstevel@tonic-gate * Given a dev info pointer to a child and a register number, this 11007c478bd9Sstevel@tonic-gate * routine returns the size element of that reg set property. 11017c478bd9Sstevel@tonic-gate * 11027c478bd9Sstevel@tonic-gate * used by: upa64s_ctlops() - DDI_CTLOPS_REGSIZE 11037c478bd9Sstevel@tonic-gate * 11047c478bd9Sstevel@tonic-gate * return value: size of reg set on success, -1 on error 11057c478bd9Sstevel@tonic-gate */ 11067c478bd9Sstevel@tonic-gate static off_t 11077c478bd9Sstevel@tonic-gate get_reg_set_size(dev_info_t *child, int rnumber) 11087c478bd9Sstevel@tonic-gate { 11097c478bd9Sstevel@tonic-gate upa64s_regspec_t *upa64s_rp; 11107c478bd9Sstevel@tonic-gate uint_t size; 11117c478bd9Sstevel@tonic-gate int i; 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate if (rnumber < 0) 11147c478bd9Sstevel@tonic-gate return (-1); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate /* 11177c478bd9Sstevel@tonic-gate * Get the reg property for the device. 11187c478bd9Sstevel@tonic-gate */ 1119a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 11207c478bd9Sstevel@tonic-gate (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS) 11217c478bd9Sstevel@tonic-gate return (-1); 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if (rnumber >= (i / (int)sizeof (upa64s_regspec_t))) { 11247c478bd9Sstevel@tonic-gate kmem_free(upa64s_rp, i); 11257c478bd9Sstevel@tonic-gate return (-1); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate /* >4G reg size not supported */ 11297c478bd9Sstevel@tonic-gate size = (uint32_t)upa64s_rp[rnumber].upa64s_size; 11307c478bd9Sstevel@tonic-gate kmem_free(upa64s_rp, i); 11317c478bd9Sstevel@tonic-gate return (size); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * get_nreg_set 11377c478bd9Sstevel@tonic-gate * 11387c478bd9Sstevel@tonic-gate * Given a dev info pointer to a child, this routine returns the 11397c478bd9Sstevel@tonic-gate * number of sets in its "reg" property. 11407c478bd9Sstevel@tonic-gate * 11417c478bd9Sstevel@tonic-gate * used by: upa64s_ctlops() - DDI_CTLOPS_NREGS 11427c478bd9Sstevel@tonic-gate * 11437c478bd9Sstevel@tonic-gate * return value: # of reg sets on success, zero on error 11447c478bd9Sstevel@tonic-gate */ 11457c478bd9Sstevel@tonic-gate static uint_t 11467c478bd9Sstevel@tonic-gate get_nreg_set(dev_info_t *child) 11477c478bd9Sstevel@tonic-gate { 11487c478bd9Sstevel@tonic-gate upa64s_regspec_t *upa64s_rp; 11497c478bd9Sstevel@tonic-gate int i, n; 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate /* 11527c478bd9Sstevel@tonic-gate * Get the reg property for the device. 11537c478bd9Sstevel@tonic-gate */ 1154a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 11557c478bd9Sstevel@tonic-gate (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS) 11567c478bd9Sstevel@tonic-gate return (0); 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate n = i / (int)sizeof (upa64s_regspec_t); 11597c478bd9Sstevel@tonic-gate kmem_free(upa64s_rp, i); 11607c478bd9Sstevel@tonic-gate return (n); 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * upa64s_intrdist 11667c478bd9Sstevel@tonic-gate * 11677c478bd9Sstevel@tonic-gate * The following routine is the callback function for this nexus driver 11687c478bd9Sstevel@tonic-gate * to support interrupt distribution on sun4u systems. When this 11697c478bd9Sstevel@tonic-gate * function is called by the interrupt distribution framework, it will 11707c478bd9Sstevel@tonic-gate * reprogram all the active the mondo registers. 11717c478bd9Sstevel@tonic-gate */ 11727c478bd9Sstevel@tonic-gate static void 11737c478bd9Sstevel@tonic-gate upa64s_intrdist(void *arg) 11747c478bd9Sstevel@tonic-gate { 11757c478bd9Sstevel@tonic-gate dev_info_t *dip = (dev_info_t *)arg; 11767c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 11777c478bd9Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance); 11787c478bd9Sstevel@tonic-gate uint_t upaport; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate for (upaport = 0; upaport < UPA64S_PORTS; upaport++) { 11817c478bd9Sstevel@tonic-gate volatile uint64_t *imr; 11827c478bd9Sstevel@tonic-gate volatile uint64_t imr_dat; 11837c478bd9Sstevel@tonic-gate uint_t mondo; 11847c478bd9Sstevel@tonic-gate uint32_t cpuid; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate if (upa64s_p->ino_state[upaport] != INO_INUSE) 11877c478bd9Sstevel@tonic-gate continue; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate imr = upa64s_p->imr[upaport]; 11907c478bd9Sstevel@tonic-gate mondo = UPA64S_IMR_TO_MONDO(*imr); 11917c478bd9Sstevel@tonic-gate cpuid = intr_dist_cpuid(); 11927c478bd9Sstevel@tonic-gate imr_dat = UPA64S_CPUID_TO_IMR(cpuid); 11937c478bd9Sstevel@tonic-gate imr_dat = UPA64S_GET_MAP_REG(mondo, imr_dat); 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate /* Check and re-program cpu target if necessary */ 11967c478bd9Sstevel@tonic-gate DBG2(D_INTRDIST, dip, "mondo=%x cpuid=%x\n", mondo, cpuid); 11977c478bd9Sstevel@tonic-gate if (UPA64S_IMR_TO_CPUID(*imr) == cpuid) { 11987c478bd9Sstevel@tonic-gate DBG(D_INTRDIST, dip, "same cpuid\n"); 11997c478bd9Sstevel@tonic-gate continue; 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[upaport], (uint64_t *)imr, imr_dat); 12027c478bd9Sstevel@tonic-gate imr_dat = ddi_get64(upa64s_p->imr_ah[upaport], (uint64_t *)imr); 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate #ifdef DEBUG 12087c478bd9Sstevel@tonic-gate static void 12097c478bd9Sstevel@tonic-gate upa64s_debug(uint_t flag, dev_info_t *dip, char *fmt, 12107c478bd9Sstevel@tonic-gate uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) 12117c478bd9Sstevel@tonic-gate { 12127c478bd9Sstevel@tonic-gate char *s = NULL; 12137c478bd9Sstevel@tonic-gate uint_t cont = 0; 12147c478bd9Sstevel@tonic-gate if (flag & D_CONT) { 12157c478bd9Sstevel@tonic-gate flag &= ~D_CONT; 12167c478bd9Sstevel@tonic-gate cont = 1; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate if (!(upa64s_debug_flags & flag)) 12197c478bd9Sstevel@tonic-gate return; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate switch (flag) { 12227c478bd9Sstevel@tonic-gate case D_ATTACH: s = "attach"; break; 12237c478bd9Sstevel@tonic-gate case D_DETACH: s = "detach"; break; 12247c478bd9Sstevel@tonic-gate case D_POWER: s = "power"; break; 12257c478bd9Sstevel@tonic-gate case D_MAP: s = "map"; break; 12267c478bd9Sstevel@tonic-gate case D_CTLOPS: s = "ctlops"; break; 12277c478bd9Sstevel@tonic-gate case D_G_ISPEC: s = "get_intrspec"; break; 12287c478bd9Sstevel@tonic-gate case D_A_ISPEC: s = "add_intrspec"; break; 12297c478bd9Sstevel@tonic-gate case D_R_ISPEC: s = "remove_intrspec"; break; 12307c478bd9Sstevel@tonic-gate case D_INIT_CLD: s = "init_child"; break; 12317c478bd9Sstevel@tonic-gate case D_INTRDIST: s = "intrdist"; break; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate if (s && cont == 0) { 12357c478bd9Sstevel@tonic-gate prom_printf("%s(%d): %s: ", ddi_get_name(dip), 12367c478bd9Sstevel@tonic-gate ddi_get_instance(dip), s); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate prom_printf(fmt, a1, a2, a3, a4, a5); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate #endif 1241