10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52580Sanish * Common Development and Distribution License (the "License").
62580Sanish * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
227656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/conf.h>
290Sstevel@tonic-gate #include <sys/ddi.h>
300Sstevel@tonic-gate #include <sys/sunddi.h>
310Sstevel@tonic-gate #include <sys/autoconf.h>
320Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
330Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
340Sstevel@tonic-gate #include <sys/cmn_err.h>
350Sstevel@tonic-gate #include <sys/errno.h>
360Sstevel@tonic-gate #include <sys/kmem.h>
370Sstevel@tonic-gate #include <sys/debug.h>
380Sstevel@tonic-gate #include <sys/sysmacros.h>
390Sstevel@tonic-gate #include <sys/spl.h>
400Sstevel@tonic-gate #include <sys/async.h>
410Sstevel@tonic-gate #include <sys/dvma.h>
420Sstevel@tonic-gate #include <sys/upa64s.h>
430Sstevel@tonic-gate #include <sys/machsystm.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate * driver global data:
470Sstevel@tonic-gate */
480Sstevel@tonic-gate static void *per_upa64s_state; /* soft state pointer */
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * function prototypes for bus ops routines:
520Sstevel@tonic-gate */
530Sstevel@tonic-gate static int
540Sstevel@tonic-gate upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
550Sstevel@tonic-gate off_t offset, off_t len, caddr_t *addrp);
560Sstevel@tonic-gate static int
570Sstevel@tonic-gate upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
580Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result);
590Sstevel@tonic-gate static int
600Sstevel@tonic-gate upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
610Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result);
620Sstevel@tonic-gate static int
630Sstevel@tonic-gate upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
640Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp);
650Sstevel@tonic-gate static int
660Sstevel@tonic-gate upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
670Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp);
680Sstevel@tonic-gate
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate * function prototypes for dev ops routines:
710Sstevel@tonic-gate */
720Sstevel@tonic-gate static int upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
730Sstevel@tonic-gate static int upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
740Sstevel@tonic-gate static int upa64s_power(dev_info_t *dip, int component, int level);
750Sstevel@tonic-gate
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate * bus ops and dev ops structures:
780Sstevel@tonic-gate */
790Sstevel@tonic-gate static struct bus_ops upa64s_bus_ops = {
800Sstevel@tonic-gate BUSO_REV,
810Sstevel@tonic-gate upa64s_map,
820Sstevel@tonic-gate 0,
830Sstevel@tonic-gate 0,
840Sstevel@tonic-gate 0,
850Sstevel@tonic-gate i_ddi_map_fault,
860Sstevel@tonic-gate ddi_no_dma_map,
870Sstevel@tonic-gate ddi_no_dma_allochdl,
880Sstevel@tonic-gate ddi_no_dma_freehdl,
890Sstevel@tonic-gate ddi_no_dma_bindhdl,
900Sstevel@tonic-gate ddi_no_dma_unbindhdl,
910Sstevel@tonic-gate ddi_no_dma_flush,
920Sstevel@tonic-gate ddi_no_dma_win,
930Sstevel@tonic-gate ddi_no_dma_mctl,
940Sstevel@tonic-gate upa64s_ctlops,
950Sstevel@tonic-gate ddi_bus_prop_op,
960Sstevel@tonic-gate 0,
970Sstevel@tonic-gate 0,
980Sstevel@tonic-gate 0,
990Sstevel@tonic-gate 0,
1000Sstevel@tonic-gate 0,
1010Sstevel@tonic-gate 0,
1020Sstevel@tonic-gate 0,
1030Sstevel@tonic-gate 0,
1040Sstevel@tonic-gate 0,
1050Sstevel@tonic-gate 0,
1060Sstevel@tonic-gate 0,
1070Sstevel@tonic-gate 0,
1080Sstevel@tonic-gate upa64_intr_ops
1090Sstevel@tonic-gate };
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate static struct dev_ops upa64s_ops = {
1120Sstevel@tonic-gate DEVO_REV,
1130Sstevel@tonic-gate 0,
1140Sstevel@tonic-gate ddi_no_info,
1150Sstevel@tonic-gate nulldev,
1160Sstevel@tonic-gate 0,
1170Sstevel@tonic-gate upa64s_attach,
1180Sstevel@tonic-gate upa64s_detach,
1190Sstevel@tonic-gate nodev,
1200Sstevel@tonic-gate (struct cb_ops *)0,
1210Sstevel@tonic-gate &upa64s_bus_ops,
1227656SSherry.Moore@Sun.COM upa64s_power,
1237656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
1240Sstevel@tonic-gate };
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate * module definitions:
1280Sstevel@tonic-gate */
1290Sstevel@tonic-gate #include <sys/modctl.h>
1300Sstevel@tonic-gate extern struct mod_ops mod_driverops;
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate static struct modldrv modldrv = {
1330Sstevel@tonic-gate &mod_driverops, /* type of module */
1347656SSherry.Moore@Sun.COM "UPA64S nexus driver", /* name of module */
1350Sstevel@tonic-gate &upa64s_ops, /* driver ops */
1360Sstevel@tonic-gate };
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate static struct modlinkage modlinkage = {
1390Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL
1400Sstevel@tonic-gate };
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate int
_init(void)1430Sstevel@tonic-gate _init(void)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate int e;
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * Initialize per instance bus soft state pointer.
1490Sstevel@tonic-gate */
1500Sstevel@tonic-gate if (e = ddi_soft_state_init(&per_upa64s_state,
1510Sstevel@tonic-gate sizeof (upa64s_devstate_t), 2))
1520Sstevel@tonic-gate return (e);
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate * Install the module.
1550Sstevel@tonic-gate */
1560Sstevel@tonic-gate if (e = mod_install(&modlinkage))
1570Sstevel@tonic-gate ddi_soft_state_fini(&per_upa64s_state);
1580Sstevel@tonic-gate return (e);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate int
_fini(void)1620Sstevel@tonic-gate _fini(void)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate int e = mod_remove(&modlinkage);
1650Sstevel@tonic-gate if (e)
1660Sstevel@tonic-gate return (e);
1670Sstevel@tonic-gate ddi_soft_state_fini(&per_upa64s_state);
1680Sstevel@tonic-gate return (e);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1720Sstevel@tonic-gate _info(struct modinfo *modinfop)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate /*
1790Sstevel@tonic-gate * forward declarations:
1800Sstevel@tonic-gate */
1810Sstevel@tonic-gate static void upa64s_intrdist(void *arg);
1820Sstevel@tonic-gate static int init_child(dev_info_t *child);
1830Sstevel@tonic-gate static int report_dev(dev_info_t *dip);
1840Sstevel@tonic-gate static int get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip);
1850Sstevel@tonic-gate static void save_state(upa64s_devstate_t *upa64s_p);
1860Sstevel@tonic-gate static void restore_state(upa64s_devstate_t *upa64s_p);
1870Sstevel@tonic-gate static int xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *upa64s_rp,
1880Sstevel@tonic-gate off_t off, off_t len, struct regspec *rp);
1890Sstevel@tonic-gate static int get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
1900Sstevel@tonic-gate off_t off, off_t len, struct regspec *rp);
1910Sstevel@tonic-gate static off_t get_reg_set_size(dev_info_t *child, int rnumber);
1920Sstevel@tonic-gate static uint_t get_nreg_set(dev_info_t *child);
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /* device driver entry points */
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate * attach entry point:
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate static int
upa64s_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2010Sstevel@tonic-gate upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate upa64s_devstate_t *upa64s_p; /* per upa64s state pointer */
2040Sstevel@tonic-gate ddi_device_acc_attr_t attr;
2050Sstevel@tonic-gate int instance;
2060Sstevel@tonic-gate char *pmc[] = { "NAME=Framebuffer Power", "0=Off", "1=On", NULL };
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate switch (cmd) {
2090Sstevel@tonic-gate case DDI_ATTACH:
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate * Allocate and get the per instance soft state structure.
2120Sstevel@tonic-gate */
2130Sstevel@tonic-gate instance = ddi_get_instance(dip);
2140Sstevel@tonic-gate if (alloc_upa64s_soft_state(instance) != DDI_SUCCESS) {
2150Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can't allocate upa64s state",
2160Sstevel@tonic-gate ddi_get_name(dip), instance);
2170Sstevel@tonic-gate return (DDI_FAILURE);
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate upa64s_p = get_upa64s_soft_state(instance);
2200Sstevel@tonic-gate upa64s_p->dip = dip;
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate * Get key properties of the bridge node.
2240Sstevel@tonic-gate */
2250Sstevel@tonic-gate if (get_properties(upa64s_p, dip) != DDI_SUCCESS)
2260Sstevel@tonic-gate goto fail;
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * Create "pm-components" property for the purpose of
2300Sstevel@tonic-gate * doing Power Management.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
2330Sstevel@tonic-gate "pm-components", pmc, ((sizeof (pmc)/sizeof (char *)) - 1))
2340Sstevel@tonic-gate != DDI_PROP_SUCCESS) {
2350Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to create pm-components "
2360Sstevel@tonic-gate "property.", ddi_get_name(dip), instance);
2370Sstevel@tonic-gate goto fail;
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /* Map in the UPA's registers */
2410Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2420Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2430Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
2440Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0,
2450Sstevel@tonic-gate (caddr_t *)&upa64s_p->config_base, 0, 0, &attr,
2460Sstevel@tonic-gate &upa64s_p->config_base_ah) != DDI_SUCCESS) {
2470Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to map reg1.",
2480Sstevel@tonic-gate ddi_get_name(dip), instance);
2490Sstevel@tonic-gate goto fail;
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate upa64s_p->upa0_config = (uint64_t *)(upa64s_p->config_base +
2530Sstevel@tonic-gate UPA64S_UPA0_CONFIG_OFFSET);
2540Sstevel@tonic-gate upa64s_p->upa1_config = (uint64_t *)(upa64s_p->config_base +
2550Sstevel@tonic-gate UPA64S_UPA1_CONFIG_OFFSET);
2560Sstevel@tonic-gate upa64s_p->if_config = (uint64_t *)(upa64s_p->config_base +
2570Sstevel@tonic-gate UPA64S_IF_CONFIG_OFFSET);
2580Sstevel@tonic-gate upa64s_p->estar = (uint64_t *)(upa64s_p->config_base +
2590Sstevel@tonic-gate UPA64S_ESTAR_OFFSET);
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, (caddr_t *)&upa64s_p->imr[0],
2620Sstevel@tonic-gate 0, 0, &attr, &upa64s_p->imr_ah[0]) != DDI_SUCCESS) {
2630Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to map reg2.",
2640Sstevel@tonic-gate ddi_get_name(dip), instance);
2650Sstevel@tonic-gate goto fail1;
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 2, (caddr_t *)&upa64s_p->imr[1],
2690Sstevel@tonic-gate 0, 0, &attr, &upa64s_p->imr_ah[1]) != DDI_SUCCESS) {
2700Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to map reg3.",
2710Sstevel@tonic-gate ddi_get_name(dip), instance);
2720Sstevel@tonic-gate goto fail2;
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate * Power level of a component is unknown at attach time.
2770Sstevel@tonic-gate * Bring the power level to what is needed for normal operation.
2780Sstevel@tonic-gate */
2790Sstevel@tonic-gate upa64s_p->power_level = UPA64S_PM_UNKNOWN;
2800Sstevel@tonic-gate if (pm_raise_power(dip, UPA64S_PM_COMP, UPA64S_PM_NORMOP) !=
2810Sstevel@tonic-gate DDI_SUCCESS) {
2820Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to raise the power.",
2830Sstevel@tonic-gate ddi_get_name(dip), instance);
2840Sstevel@tonic-gate goto fail3;
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate intr_dist_add(upa64s_intrdist, dip);
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate ddi_report_dev(dip);
2900Sstevel@tonic-gate return (DDI_SUCCESS);
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate case DDI_RESUME:
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate upa64s_p = get_upa64s_soft_state(ddi_get_instance(dip));
2950Sstevel@tonic-gate DBG(D_ATTACH, dip, "DDI_RESUME\n");
2960Sstevel@tonic-gate restore_state(upa64s_p);
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate /*
2990Sstevel@tonic-gate * Power level of a component is unknown at resume time.
3000Sstevel@tonic-gate * Bring the power level to what it was before suspend.
3010Sstevel@tonic-gate */
3020Sstevel@tonic-gate upa64s_p->power_level = UPA64S_PM_UNKNOWN;
3030Sstevel@tonic-gate if (pm_raise_power(dip, UPA64S_PM_COMP,
3040Sstevel@tonic-gate upa64s_p->saved_power_level) != DDI_SUCCESS)
3050Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to change power level "
3060Sstevel@tonic-gate "during resume!", ddi_get_name(dip), instance);
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate return (DDI_SUCCESS);
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate default:
3110Sstevel@tonic-gate return (DDI_FAILURE);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate fail3:
3150Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[1]);
3160Sstevel@tonic-gate fail2:
3170Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[0]);
3180Sstevel@tonic-gate fail1:
3190Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->config_base_ah);
3200Sstevel@tonic-gate fail:
3210Sstevel@tonic-gate free_upa64s_soft_state(instance);
3220Sstevel@tonic-gate return (DDI_FAILURE);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate * detach entry point:
3280Sstevel@tonic-gate */
3290Sstevel@tonic-gate static int
upa64s_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3300Sstevel@tonic-gate upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate int instance = ddi_get_instance(dip);
3330Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate switch (cmd) {
3360Sstevel@tonic-gate case DDI_DETACH:
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate DBG(D_DETACH, dip, "DDI_DETACH\n");
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate /*
3410Sstevel@tonic-gate * Power down the device.
3420Sstevel@tonic-gate */
3430Sstevel@tonic-gate if (pm_lower_power(dip, UPA64S_PM_COMP, UPA64S_PM_RESET) !=
3440Sstevel@tonic-gate DDI_SUCCESS)
3450Sstevel@tonic-gate DBG(D_DETACH, dip, "failed to power off!\n");
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate intr_dist_rem(upa64s_intrdist, dip);
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->config_base_ah);
3500Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[0]);
3510Sstevel@tonic-gate ddi_regs_map_free(&upa64s_p->imr_ah[1]);
3520Sstevel@tonic-gate free_upa64s_soft_state(instance);
3530Sstevel@tonic-gate return (DDI_SUCCESS);
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate case DDI_SUSPEND:
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate DBG(D_DETACH, dip, "DDI_SUSPEND\n");
3580Sstevel@tonic-gate save_state(upa64s_p);
3590Sstevel@tonic-gate upa64s_p->saved_power_level = upa64s_p->power_level;
3600Sstevel@tonic-gate return (DDI_SUCCESS);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate return (DDI_FAILURE);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate /*
3670Sstevel@tonic-gate * power entry point:
3680Sstevel@tonic-gate *
3690Sstevel@tonic-gate * This entry point is called by Power Management framework to
3700Sstevel@tonic-gate * reset upa bus and slow down/speed up the upa interface of
3710Sstevel@tonic-gate * Schizo chip.
3720Sstevel@tonic-gate */
3730Sstevel@tonic-gate static int
upa64s_power(dev_info_t * dip,int component,int level)3740Sstevel@tonic-gate upa64s_power(dev_info_t *dip, int component, int level)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate int instance = ddi_get_instance(dip);
3770Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
3780Sstevel@tonic-gate volatile uint64_t uint64_data;
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate DBG2(D_POWER, dip, "component=%d, level=%d\n", component, level);
3810Sstevel@tonic-gate if (component != UPA64S_PM_COMP ||
3820Sstevel@tonic-gate level < UPA64S_PM_RESET || level > UPA64S_PM_NORMOP)
3830Sstevel@tonic-gate return (DDI_FAILURE);
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate * We can't set the hardware to the state that it is
3870Sstevel@tonic-gate * already in. So if the power state is not known, inquire the
3880Sstevel@tonic-gate * state of the hardware. If it is already in that state,
3890Sstevel@tonic-gate * record and return, otherwise make the state change.
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate if (upa64s_p->power_level == UPA64S_PM_UNKNOWN) {
3920Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah,
3930Sstevel@tonic-gate upa64s_p->if_config);
3940Sstevel@tonic-gate if ((level == UPA64S_PM_RESET &&
3950Sstevel@tonic-gate uint64_data == UPA64S_NOT_POK_RST_L) ||
3960Sstevel@tonic-gate (level == UPA64S_PM_NORMOP &&
3970Sstevel@tonic-gate uint64_data == UPA64S_POK_NOT_RST_L)) {
3980Sstevel@tonic-gate upa64s_p->power_level = level;
3990Sstevel@tonic-gate return (DDI_SUCCESS);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate if (level == upa64s_p->power_level) {
4040Sstevel@tonic-gate DBG1(D_POWER, dip, "device is already at power level %d\n",
4050Sstevel@tonic-gate level);
4060Sstevel@tonic-gate return (DDI_SUCCESS);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate if (level == UPA64S_PM_RESET) {
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate * Assert UPA64S_RESET
4130Sstevel@tonic-gate */
4140Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
4150Sstevel@tonic-gate UPA64S_POK_RST_L);
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate /*
4180Sstevel@tonic-gate * Deassert UPA64S_POK. Flush the store buffer.
4190Sstevel@tonic-gate */
4200Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
4210Sstevel@tonic-gate UPA64S_NOT_POK_RST_L);
4220Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah,
4230Sstevel@tonic-gate upa64s_p->if_config);
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate /*
4260Sstevel@tonic-gate * Internal UPA clock to 1/2 speed
4270Sstevel@tonic-gate */
4280Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
4290Sstevel@tonic-gate UPA64S_1_2_SPEED);
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate /*
4320Sstevel@tonic-gate * Internal UPA clock to 1/64 speed. Flush the store buffer.
4330Sstevel@tonic-gate */
4340Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
4350Sstevel@tonic-gate UPA64S_1_64_SPEED);
4360Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah,
4370Sstevel@tonic-gate upa64s_p->estar);
4380Sstevel@tonic-gate } else {
4390Sstevel@tonic-gate /*
4400Sstevel@tonic-gate * Internal UPA clock to 1/2 speed
4410Sstevel@tonic-gate */
4420Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
4430Sstevel@tonic-gate UPA64S_1_2_SPEED);
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate /*
4460Sstevel@tonic-gate * Internal UPA clock to full speed. Flush the store buffer.
4470Sstevel@tonic-gate */
4480Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
4490Sstevel@tonic-gate UPA64S_FULL_SPEED);
4500Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah,
4510Sstevel@tonic-gate upa64s_p->estar);
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate * Assert UPA64S_POK. Flush the store buffer before
4550Sstevel@tonic-gate * the wait delay.
4560Sstevel@tonic-gate */
4570Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
4580Sstevel@tonic-gate UPA64S_POK_RST_L);
4590Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah,
4600Sstevel@tonic-gate upa64s_p->if_config);
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate /*
4630Sstevel@tonic-gate * Delay 20 milliseconds for the signals to settle down.
4640Sstevel@tonic-gate */
4650Sstevel@tonic-gate delay(drv_usectohz(20*1000));
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate /*
4680Sstevel@tonic-gate * Deassert UPA64S_RESET. Flush the store buffer.
4690Sstevel@tonic-gate */
4700Sstevel@tonic-gate ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
4710Sstevel@tonic-gate UPA64S_POK_NOT_RST_L);
4720Sstevel@tonic-gate uint64_data = ddi_get64(upa64s_p->config_base_ah,
4730Sstevel@tonic-gate upa64s_p->if_config);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate upa64s_p->power_level = level;
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate return (DDI_SUCCESS);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate /* bus driver entry points */
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate * bus map entry point:
4840Sstevel@tonic-gate *
4850Sstevel@tonic-gate * if map request is for an rnumber
4860Sstevel@tonic-gate * get the corresponding regspec from device node
4870Sstevel@tonic-gate * build a new regspec in our parent's format
4880Sstevel@tonic-gate * build a new map_req with the new regspec
4890Sstevel@tonic-gate * call up the tree to complete the mapping
4900Sstevel@tonic-gate */
4910Sstevel@tonic-gate static int
upa64s_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t off,off_t len,caddr_t * addrp)4920Sstevel@tonic-gate upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
4930Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate struct regspec regspec;
4960Sstevel@tonic-gate ddi_map_req_t p_map_request;
4970Sstevel@tonic-gate int rnumber, rval;
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate DBG4(D_MAP, dip, "upa64s_map() mp=%x.%x addrp=%x.%08x\n",
5000Sstevel@tonic-gate HI32(mp), LO32(mp), HI32(addrp), LO32(addrp));
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * User level mappings are not supported yet.
5040Sstevel@tonic-gate */
5050Sstevel@tonic-gate if (mp->map_flags & DDI_MF_USER_MAPPING) {
5060Sstevel@tonic-gate DBG2(D_MAP, dip, "rdip=%s%d: no user level mappings yet!\n",
5070Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip));
5080Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /*
5120Sstevel@tonic-gate * Now handle the mapping according to its type.
5130Sstevel@tonic-gate */
5140Sstevel@tonic-gate switch (mp->map_type) {
5150Sstevel@tonic-gate case DDI_MT_REGSPEC:
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate /*
5180Sstevel@tonic-gate * We assume the register specification is in PCI format.
5190Sstevel@tonic-gate * We must convert it into a regspec of our parent's
5200Sstevel@tonic-gate * and pass the request to our parent.
5210Sstevel@tonic-gate */
5220Sstevel@tonic-gate DBG3(D_MAP, dip, "rdip=%s%d: REGSPEC - handlep=%x\n",
5230Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip),
5240Sstevel@tonic-gate mp->map_handlep);
5250Sstevel@tonic-gate rval = xlate_reg_prop(dip, (upa64s_regspec_t *)mp->map_obj.rp,
5260Sstevel@tonic-gate off, len, ®spec);
5270Sstevel@tonic-gate break;
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate case DDI_MT_RNUMBER:
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate /*
5320Sstevel@tonic-gate * Get the "reg" property from the device node and convert
5330Sstevel@tonic-gate * it to our parent's format.
5340Sstevel@tonic-gate */
5350Sstevel@tonic-gate DBG4(D_MAP, dip, "rdip=%s%d: rnumber=%x handlep=%x\n",
5360Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip),
5370Sstevel@tonic-gate mp->map_obj.rnumber, mp->map_handlep);
5380Sstevel@tonic-gate rnumber = mp->map_obj.rnumber;
5390Sstevel@tonic-gate if (rnumber < 0)
5400Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE);
5410Sstevel@tonic-gate rval = get_reg_set(dip, rdip, rnumber, off, len, ®spec);
5420Sstevel@tonic-gate break;
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate default:
5450Sstevel@tonic-gate return (DDI_ME_INVAL);
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate if (rval != DDI_SUCCESS) {
5490Sstevel@tonic-gate DBG(D_MAP, dip, "failed on regspec\n\n");
5500Sstevel@tonic-gate return (rval);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate * Now we have a copy of the upa64s regspec converted to our parent's
5550Sstevel@tonic-gate * format. Build a new map request based on this regspec and pass
5560Sstevel@tonic-gate * it to our parent.
5570Sstevel@tonic-gate */
5580Sstevel@tonic-gate p_map_request = *mp;
5590Sstevel@tonic-gate p_map_request.map_type = DDI_MT_REGSPEC;
5600Sstevel@tonic-gate p_map_request.map_obj.rp = ®spec;
5610Sstevel@tonic-gate rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
5620Sstevel@tonic-gate DBG3(D_MAP, dip, "ddi_map returns: rval=%x addrp=%x.%08x\n\n",
5630Sstevel@tonic-gate rval, HI32(*addrp), LO32(*addrp));
5640Sstevel@tonic-gate return (rval);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate /*
5680Sstevel@tonic-gate * Translate the UPA devices interrupt property. This is the only case I
5690Sstevel@tonic-gate * know of where the interrupts property is meaningless. As a result, we
5700Sstevel@tonic-gate * just use UPA_BASE_INO as our interrupt value and add to it the upa port id.
5710Sstevel@tonic-gate * UPA portid is returned too.
5720Sstevel@tonic-gate */
5730Sstevel@tonic-gate #define UPA_BASE_INO 0x2a
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate static int
upa64s_xlate_intr(dev_info_t * rdip,int32_t safariport,uint32_t * intr)576693Sgovinda upa64s_xlate_intr(dev_info_t *rdip, int32_t safariport, uint32_t *intr)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate uint32_t ino = UPA_BASE_INO;
5790Sstevel@tonic-gate int32_t portid;
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate /* Clear the ffb's interrupts property, it's meaningless */
582693Sgovinda *intr = 0;
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate if ((portid = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
5850Sstevel@tonic-gate "upa-portid", -1)) == -1)
5860Sstevel@tonic-gate return (-1);
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate ino += portid;
5890Sstevel@tonic-gate
590693Sgovinda *intr = UPA64S_MAKE_MONDO(safariport, ino);
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate DBG5(D_A_ISPEC, rdip, "upa64s_xlate_intr: rdip=%s%d: upa portid %d "
5930Sstevel@tonic-gate "ino=%x mondo 0x%x\n", ddi_get_name(rdip), ddi_get_instance(rdip),
594693Sgovinda portid, ino, *intr);
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate return (portid);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate * bus add intrspec entry point:
6010Sstevel@tonic-gate */
6020Sstevel@tonic-gate static int
upa64s_add_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)6030Sstevel@tonic-gate upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
6040Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp)
6050Sstevel@tonic-gate {
6060Sstevel@tonic-gate int upaport, instance = ddi_get_instance(dip);
6070Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
6080Sstevel@tonic-gate #ifdef DEBUG
6090Sstevel@tonic-gate uint_t (*int_handler)(caddr_t, caddr_t) = hdlp->ih_cb_func;
6100Sstevel@tonic-gate caddr_t int_handler_arg1 = hdlp->ih_cb_arg1;
6110Sstevel@tonic-gate #endif /* DEBUG */
6120Sstevel@tonic-gate uint_t cpu_id;
6130Sstevel@tonic-gate volatile uint64_t imr_data;
6140Sstevel@tonic-gate
615693Sgovinda upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id,
616693Sgovinda (uint32_t *)&hdlp->ih_vector);
6170Sstevel@tonic-gate
618693Sgovinda if (hdlp->ih_vector == 0)
6190Sstevel@tonic-gate return (DDI_FAILURE);
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate DBG3(D_A_ISPEC, dip,
6220Sstevel@tonic-gate "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
623693Sgovinda ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector);
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate /*
6260Sstevel@tonic-gate * Make sure an interrupt handler isn't already installed.
6270Sstevel@tonic-gate */
6280Sstevel@tonic-gate if (upa64s_p->ino_state[upaport] != INO_FREE) {
6290Sstevel@tonic-gate return (DDI_FAILURE);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate /*
6330Sstevel@tonic-gate * Install the handler in the system table.
6340Sstevel@tonic-gate */
6350Sstevel@tonic-gate #ifdef DEBUG
6360Sstevel@tonic-gate DBG2(D_A_ISPEC, dip, "i_ddi_add_ivintr: hdlr=%p arg=%p\n",
6370Sstevel@tonic-gate int_handler, int_handler_arg1);
6380Sstevel@tonic-gate #endif
6390Sstevel@tonic-gate if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS)
6400Sstevel@tonic-gate return (DDI_FAILURE);
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate cpu_id = intr_dist_cpuid();
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate * Enable the interrupt through its interrupt mapping register.
6460Sstevel@tonic-gate */
6470Sstevel@tonic-gate imr_data = UPA64S_CPUID_TO_IMR(cpu_id);
6480Sstevel@tonic-gate imr_data = UPA64S_GET_MAP_REG(hdlp->ih_vector, imr_data);
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate DBG4(D_A_ISPEC, dip, "IMR [upaport=%d mapping reg 0x%p] = %x.%x\n",
6510Sstevel@tonic-gate upaport, upa64s_p->imr[upaport], HI32(imr_data), LO32(imr_data));
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], imr_data);
6540Sstevel@tonic-gate /* Read the data back to flush store buffers. */
6550Sstevel@tonic-gate imr_data = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
6560Sstevel@tonic-gate upa64s_p->ino_state[upaport] = INO_INUSE;
6570Sstevel@tonic-gate
658693Sgovinda DBG(D_A_ISPEC, dip, "add_intr success!\n");
6590Sstevel@tonic-gate return (DDI_SUCCESS);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate /*
6640Sstevel@tonic-gate * bus remove intrspec entry point
6650Sstevel@tonic-gate */
6660Sstevel@tonic-gate static int
upa64s_remove_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)6670Sstevel@tonic-gate upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
6680Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate upa64s_devstate_t *upa64s_p =
6710Sstevel@tonic-gate get_upa64s_soft_state(ddi_get_instance(dip));
6720Sstevel@tonic-gate int upaport;
6730Sstevel@tonic-gate #ifndef lint
6740Sstevel@tonic-gate volatile uint64_t tmp;
6750Sstevel@tonic-gate #endif
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate /*
6780Sstevel@tonic-gate * Make sure the mondo is valid.
6790Sstevel@tonic-gate */
680693Sgovinda upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id,
681693Sgovinda (uint32_t *)&hdlp->ih_vector);
6820Sstevel@tonic-gate
683693Sgovinda if (hdlp->ih_vector == 0)
6840Sstevel@tonic-gate return (DDI_FAILURE);
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate DBG3(D_R_ISPEC, dip,
6870Sstevel@tonic-gate "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
688693Sgovinda ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector);
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate if (upa64s_p->ino_state[upaport] != INO_INUSE) {
6910Sstevel@tonic-gate return (DDI_FAILURE);
6920Sstevel@tonic-gate }
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate /* Call up to our parent to handle the removal */
6950Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp);
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], 0);
6980Sstevel@tonic-gate #ifndef lint
6990Sstevel@tonic-gate /* Flush store buffers */
7000Sstevel@tonic-gate tmp = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
7010Sstevel@tonic-gate #endif
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate upa64s_p->ino_state[upaport] = INO_FREE;
7040Sstevel@tonic-gate return (DDI_SUCCESS);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate /* new intr_ops structure */
7090Sstevel@tonic-gate static int
upa64_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)7100Sstevel@tonic-gate upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
7110Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result)
7120Sstevel@tonic-gate {
713693Sgovinda int ret = DDI_SUCCESS;
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate switch (intr_op) {
7160Sstevel@tonic-gate case DDI_INTROP_GETCAP:
717693Sgovinda *(int *)result = DDI_INTR_FLAG_EDGE;
7180Sstevel@tonic-gate break;
7190Sstevel@tonic-gate case DDI_INTROP_ALLOC:
7200Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1;
7210Sstevel@tonic-gate break;
7220Sstevel@tonic-gate case DDI_INTROP_FREE:
7230Sstevel@tonic-gate break;
7240Sstevel@tonic-gate case DDI_INTROP_GETPRI:
7250Sstevel@tonic-gate /*
7260Sstevel@tonic-gate * We only have slave UPA devices so force the PIL to 5.
7270Sstevel@tonic-gate * this is done since all slave UPA devices have historically
7280Sstevel@tonic-gate * had their PILs set to 5. Only do it if the PIL is not
7290Sstevel@tonic-gate * being preset.
7300Sstevel@tonic-gate */
731693Sgovinda *(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 5;
7320Sstevel@tonic-gate break;
7330Sstevel@tonic-gate case DDI_INTROP_SETPRI:
7340Sstevel@tonic-gate break;
7350Sstevel@tonic-gate case DDI_INTROP_ADDISR:
7360Sstevel@tonic-gate ret = upa64s_add_intr_impl(dip, rdip, hdlp);
7370Sstevel@tonic-gate break;
7380Sstevel@tonic-gate case DDI_INTROP_REMISR:
7390Sstevel@tonic-gate ret = upa64s_remove_intr_impl(dip, rdip, hdlp);
7400Sstevel@tonic-gate break;
7410Sstevel@tonic-gate case DDI_INTROP_ENABLE:
7420Sstevel@tonic-gate case DDI_INTROP_DISABLE:
7430Sstevel@tonic-gate break;
7440Sstevel@tonic-gate case DDI_INTROP_NINTRS:
7450Sstevel@tonic-gate case DDI_INTROP_NAVAIL:
7462580Sanish *(int *)result = i_ddi_get_intx_nintrs(rdip);
7470Sstevel@tonic-gate break;
7480Sstevel@tonic-gate case DDI_INTROP_SETCAP:
7490Sstevel@tonic-gate case DDI_INTROP_SETMASK:
7500Sstevel@tonic-gate case DDI_INTROP_CLRMASK:
7510Sstevel@tonic-gate case DDI_INTROP_GETPENDING:
7520Sstevel@tonic-gate ret = DDI_ENOTSUP;
7530Sstevel@tonic-gate break;
7540Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES:
7550Sstevel@tonic-gate /* only support fixed interrupts */
7562580Sanish *(int *)result = i_ddi_get_intx_nintrs(rdip) ?
7570Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0;
7580Sstevel@tonic-gate break;
7590Sstevel@tonic-gate default:
7600Sstevel@tonic-gate ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result);
7610Sstevel@tonic-gate break;
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate
7640Sstevel@tonic-gate return (ret);
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate #ifdef DEBUG
7680Sstevel@tonic-gate uint_t upa64s_debug_flags = (uint_t)0;
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate extern void prom_printf(const char *, ...);
7710Sstevel@tonic-gate #endif
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate * control ops entry point:
7750Sstevel@tonic-gate *
7760Sstevel@tonic-gate * Requests handled completely:
7770Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD see init_child() for details
7780Sstevel@tonic-gate * DDI_CTLOPS_UNINITCHILD
7790Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV see report_dev() for details
7800Sstevel@tonic-gate * DDI_CTLOPS_REGSIZE
7810Sstevel@tonic-gate * DDI_CTLOPS_NREGS
7820Sstevel@tonic-gate *
7830Sstevel@tonic-gate * All others passed to parent.
7840Sstevel@tonic-gate */
7850Sstevel@tonic-gate static int
upa64s_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)7860Sstevel@tonic-gate upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
7870Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate DBG5(D_CTLOPS, dip, "dip=%x.%x rdip=%x.%x op=%x",
7900Sstevel@tonic-gate HI32(dip), LO32(dip), HI32(rdip), LO32(rdip), op);
7910Sstevel@tonic-gate DBG4(D_CTLOPS|D_CONT, dip, " arg=%x.%x result=%x.%x\n",
7920Sstevel@tonic-gate HI32(arg), LO32(arg), HI32(result), LO32(result));
7930Sstevel@tonic-gate
7940Sstevel@tonic-gate switch (op) {
7950Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD:
7960Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
7970Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip));
7980Sstevel@tonic-gate return (init_child((dev_info_t *)arg));
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD:
8010Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
8020Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip));
8030Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, NULL);
8040Sstevel@tonic-gate ddi_remove_minor_node((dev_info_t *)arg, NULL);
8050Sstevel@tonic-gate impl_rem_dev_props((dev_info_t *)arg);
8060Sstevel@tonic-gate return (DDI_SUCCESS);
8070Sstevel@tonic-gate
8080Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV:
8090Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
8100Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip));
8110Sstevel@tonic-gate return (report_dev(rdip));
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE:
8140Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
8150Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip));
8160Sstevel@tonic-gate *((off_t *)result) = get_reg_set_size(rdip, *((int *)arg));
8170Sstevel@tonic-gate return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS);
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate case DDI_CTLOPS_NREGS:
8200Sstevel@tonic-gate DBG2(D_CTLOPS, dip, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
8210Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip));
8220Sstevel@tonic-gate *((uint_t *)result) = get_nreg_set(rdip);
8230Sstevel@tonic-gate return (DDI_SUCCESS);
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate * Now pass the request up to our parent.
8280Sstevel@tonic-gate */
8290Sstevel@tonic-gate DBG3(D_CTLOPS, dip, "passing request to parent: rdip=%s%d op=%x\n\n",
8300Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), op);
8310Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result));
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate /* support routines */
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate /*
8380Sstevel@tonic-gate * get_properties
8390Sstevel@tonic-gate *
8400Sstevel@tonic-gate * This function is called from the attach routine to get the key
8410Sstevel@tonic-gate * properties of the upa64s node.
8420Sstevel@tonic-gate *
8430Sstevel@tonic-gate * used by: upa64s_attach()
8440Sstevel@tonic-gate *
8450Sstevel@tonic-gate * return value: none
8460Sstevel@tonic-gate */
8470Sstevel@tonic-gate static int
get_properties(upa64s_devstate_t * upa64s_p,dev_info_t * dip)8480Sstevel@tonic-gate get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip)
8490Sstevel@tonic-gate {
8500Sstevel@tonic-gate int safari_id;
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate /*
8530Sstevel@tonic-gate * Get the device's safari id.
8540Sstevel@tonic-gate */
8550Sstevel@tonic-gate safari_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
8560Sstevel@tonic-gate "portid", -1);
8570Sstevel@tonic-gate if (safari_id == -1) {
8580Sstevel@tonic-gate int instance = ddi_get_instance(dip);
8590Sstevel@tonic-gate panic("%s%d: no portid property", ddi_get_name(dip), instance);
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate upa64s_p->safari_id = safari_id;
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate return (DDI_SUCCESS);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate * save_state
8690Sstevel@tonic-gate *
8700Sstevel@tonic-gate * This routine saves a copy of the upa64s register state.
8710Sstevel@tonic-gate *
8720Sstevel@tonic-gate * used by: upa64s_detach() on a suspend operation
8730Sstevel@tonic-gate */
8740Sstevel@tonic-gate static void
save_state(upa64s_devstate_t * upa64s_p)8750Sstevel@tonic-gate save_state(upa64s_devstate_t *upa64s_p)
8760Sstevel@tonic-gate {
8770Sstevel@tonic-gate upa64s_p->imr_data[0] = ddi_get64(upa64s_p->imr_ah[0],
8780Sstevel@tonic-gate upa64s_p->imr[0]);
8790Sstevel@tonic-gate upa64s_p->imr_data[1] = ddi_get64(upa64s_p->imr_ah[1],
8800Sstevel@tonic-gate upa64s_p->imr[1]);
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate /*
8850Sstevel@tonic-gate * restore_state
8860Sstevel@tonic-gate *
8870Sstevel@tonic-gate * This routine restores a copy of the upa64s register state.
8880Sstevel@tonic-gate *
8890Sstevel@tonic-gate * used by: upa64s_attach() on a resume operation
8900Sstevel@tonic-gate */
8910Sstevel@tonic-gate static void
restore_state(upa64s_devstate_t * upa64s_p)8920Sstevel@tonic-gate restore_state(upa64s_devstate_t *upa64s_p)
8930Sstevel@tonic-gate {
8940Sstevel@tonic-gate #ifndef lint
8950Sstevel@tonic-gate volatile uint64_t tmp;
8960Sstevel@tonic-gate #endif
8970Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[0], upa64s_p->imr[0],
8980Sstevel@tonic-gate upa64s_p->imr_data[0]);
8990Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[1], upa64s_p->imr[1],
9000Sstevel@tonic-gate upa64s_p->imr_data[1]);
9010Sstevel@tonic-gate #ifndef lint
9020Sstevel@tonic-gate /* Flush the store buffer */
9030Sstevel@tonic-gate tmp = ddi_get64(upa64s_p->imr_ah[0], upa64s_p->imr[0]);
9040Sstevel@tonic-gate tmp = ddi_get64(upa64s_p->imr_ah[1], upa64s_p->imr[1]);
9050Sstevel@tonic-gate #endif
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate * get_reg_set
9110Sstevel@tonic-gate *
9120Sstevel@tonic-gate * This routine will get a upa64s format regspec for a given
9130Sstevel@tonic-gate * device node and register number.
9140Sstevel@tonic-gate *
9150Sstevel@tonic-gate * used by: upa64s_map()
9160Sstevel@tonic-gate *
9170Sstevel@tonic-gate * return value:
9180Sstevel@tonic-gate *
9190Sstevel@tonic-gate * DDI_SUCCESS - on success
9200Sstevel@tonic-gate * DDI_ME_INVAL - regspec is invalid
9210Sstevel@tonic-gate * DDI_ME_RNUMBER_RANGE - rnumber out of range
9220Sstevel@tonic-gate */
9230Sstevel@tonic-gate static int
get_reg_set(dev_info_t * dip,dev_info_t * child,int rnumber,off_t off,off_t len,struct regspec * rp)9240Sstevel@tonic-gate get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
9250Sstevel@tonic-gate off_t off, off_t len, struct regspec *rp)
9260Sstevel@tonic-gate {
9270Sstevel@tonic-gate upa64s_regspec_t *upa64s_rp;
9280Sstevel@tonic-gate int i, n, rval;
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate /*
9310Sstevel@tonic-gate * Get child device "reg" property
9320Sstevel@tonic-gate */
933506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
9340Sstevel@tonic-gate (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
9350Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate n = i / (int)sizeof (upa64s_regspec_t);
9380Sstevel@tonic-gate if (rnumber >= n) {
9390Sstevel@tonic-gate kmem_free(upa64s_rp, i);
9400Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE);
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate /*
9440Sstevel@tonic-gate * Convert each the upa64s format register specification to
9450Sstevel@tonic-gate * out parent format.
9460Sstevel@tonic-gate */
9470Sstevel@tonic-gate rval = xlate_reg_prop(dip, &upa64s_rp[rnumber], off, len, rp);
9480Sstevel@tonic-gate kmem_free(upa64s_rp, i);
9490Sstevel@tonic-gate return (rval);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate * xlate_reg_prop
9550Sstevel@tonic-gate *
9560Sstevel@tonic-gate * This routine converts a upa64s format regspec to a standard
9570Sstevel@tonic-gate * regspec containing the corresponding system address.
9580Sstevel@tonic-gate *
9590Sstevel@tonic-gate * used by: upa64s_map()
9600Sstevel@tonic-gate *
9610Sstevel@tonic-gate * return value:
9620Sstevel@tonic-gate *
9630Sstevel@tonic-gate * DDI_SUCCESS
9640Sstevel@tonic-gate * DDI_FAILURE - off + len is beyond device address range
9650Sstevel@tonic-gate * DDI_ME_INVAL - regspec is invalid
9660Sstevel@tonic-gate */
9670Sstevel@tonic-gate static int
xlate_reg_prop(dev_info_t * dip,upa64s_regspec_t * child_rp,off_t off,off_t len,struct regspec * rp)9680Sstevel@tonic-gate xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *child_rp, off_t off,
9690Sstevel@tonic-gate off_t len, struct regspec *rp)
9700Sstevel@tonic-gate {
9710Sstevel@tonic-gate int n_ranges, ranges_len, i;
9720Sstevel@tonic-gate uint64_t child_beg, child_end;
9730Sstevel@tonic-gate upa64s_ranges_t *range_p, *rng_p;
9740Sstevel@tonic-gate
9750Sstevel@tonic-gate DBG4(D_MAP, dip, "upa64s regspec - ((%x,%x) (%x,%x))\n",
9760Sstevel@tonic-gate HI32(child_rp->upa64s_phys), LO32(child_rp->upa64s_phys),
9770Sstevel@tonic-gate HI32(child_rp->upa64s_size), LO32(child_rp->upa64s_size));
9780Sstevel@tonic-gate DBG2(D_MAP, dip, "upa64s xlate_reg_prp - off=%lx len=%lx\n", off, len);
9790Sstevel@tonic-gate #if 0
9800Sstevel@tonic-gate /*
9810Sstevel@tonic-gate * both FFB and AFB have broken "reg" properties, all mapping
9820Sstevel@tonic-gate * requests are done through reg-0 with very long offsets.
9830Sstevel@tonic-gate * Hence this safety check is always violated.
9840Sstevel@tonic-gate */
9850Sstevel@tonic-gate if (off + len > child_rp->upa64s_size) {
9860Sstevel@tonic-gate DBG(D_MAP, dip, "upa64s xlate_reg_prp: bad off + len\n");
9870Sstevel@tonic-gate return (DDI_FAILURE);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate #endif
9900Sstevel@tonic-gate /*
9910Sstevel@tonic-gate * current "struct regspec" only supports 32-bit sizes.
9920Sstevel@tonic-gate */
9930Sstevel@tonic-gate if (child_rp->upa64s_size >= (1ull << 32))
9940Sstevel@tonic-gate panic("upa64s: reg size must be less than 4 Gb");
9950Sstevel@tonic-gate
996506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
9970Sstevel@tonic-gate "ranges", (caddr_t)&range_p, &ranges_len) != DDI_SUCCESS) {
9980Sstevel@tonic-gate ranges_len = 0;
9990Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no ranges property",
10000Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip));
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate n_ranges = ranges_len / sizeof (upa64s_regspec_t);
10040Sstevel@tonic-gate child_beg = child_rp->upa64s_phys;
10050Sstevel@tonic-gate #if 0
10060Sstevel@tonic-gate /*
10070Sstevel@tonic-gate * again, this safety checking can not be performed.
10080Sstevel@tonic-gate * Hack by adding a pratical max child reg bank length.
10090Sstevel@tonic-gate */
10100Sstevel@tonic-gate child_end = child_beg + child_rp->upa64s_size;
10110Sstevel@tonic-gate #else
10120Sstevel@tonic-gate #define UPA64S_MAX_CHILD_LEN 0xe000000
10130Sstevel@tonic-gate child_end = child_beg + UPA64S_MAX_CHILD_LEN;
10140Sstevel@tonic-gate #endif
10150Sstevel@tonic-gate for (i = 0, rng_p = range_p; i < n_ranges; i++, rng_p++) {
10160Sstevel@tonic-gate uint64_t rng_beg = rng_p->upa64s_child;
10170Sstevel@tonic-gate uint64_t rng_end = rng_beg + rng_p->upa64s_size;
10180Sstevel@tonic-gate if ((rng_beg <= child_beg) && (rng_end >= child_end)) {
10190Sstevel@tonic-gate uint64_t addr = child_beg - rng_beg + off;
10200Sstevel@tonic-gate addr += rng_p->upa64s_parent;
10210Sstevel@tonic-gate rp->regspec_bustype = HI32(addr);
10220Sstevel@tonic-gate rp->regspec_addr = LO32(addr);
10230Sstevel@tonic-gate rp->regspec_size = len ? len : child_rp->upa64s_size;
10240Sstevel@tonic-gate break;
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate if (ranges_len)
10280Sstevel@tonic-gate kmem_free(range_p, ranges_len);
10290Sstevel@tonic-gate DBG4(D_MAP, dip, "regspec (%x,%x,%x) i=%x\n",
10300Sstevel@tonic-gate rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, i);
10310Sstevel@tonic-gate return (i < n_ranges? DDI_SUCCESS : DDI_ME_INVAL);
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate /*
10360Sstevel@tonic-gate * report_dev
10370Sstevel@tonic-gate *
10380Sstevel@tonic-gate * This function is called from our control ops routine on a
10390Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV request.
10400Sstevel@tonic-gate */
10410Sstevel@tonic-gate static int
report_dev(dev_info_t * dip)10420Sstevel@tonic-gate report_dev(dev_info_t *dip)
10430Sstevel@tonic-gate {
10440Sstevel@tonic-gate if (dip == (dev_info_t *)0)
10450Sstevel@tonic-gate return (DDI_FAILURE);
10460Sstevel@tonic-gate cmn_err(CE_CONT, "?UPA64S-device: %s@%s, %s #%d\n",
10470Sstevel@tonic-gate ddi_node_name(dip), ddi_get_name_addr(dip),
1048*8459SJerry.Gilliam@Sun.COM ddi_get_name(dip), ddi_get_instance(dip));
10490Sstevel@tonic-gate return (DDI_SUCCESS);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate * init_child
10550Sstevel@tonic-gate *
10560Sstevel@tonic-gate * This function is called from our control ops routine on a
10570Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD request. It builds and sets the device's
10580Sstevel@tonic-gate * parent private data area.
10590Sstevel@tonic-gate *
10600Sstevel@tonic-gate * used by: upa64s_ctlops()
10610Sstevel@tonic-gate *
10620Sstevel@tonic-gate * return value: none
10630Sstevel@tonic-gate */
10640Sstevel@tonic-gate static int
init_child(dev_info_t * child)10650Sstevel@tonic-gate init_child(dev_info_t *child)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate upa64s_regspec_t *child_rp;
10680Sstevel@tonic-gate int i;
10690Sstevel@tonic-gate char addr[256];
10700Sstevel@tonic-gate int32_t portid;
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate if ((portid = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
10730Sstevel@tonic-gate "upa-portid", -1)) == -1)
10740Sstevel@tonic-gate return (DDI_FAILURE);
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate /*
10770Sstevel@tonic-gate * Set the address portion of the node name based on
10780Sstevel@tonic-gate * the function and device number.
10790Sstevel@tonic-gate */
1080506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
10810Sstevel@tonic-gate (caddr_t)&child_rp, &i) != DDI_SUCCESS) {
10820Sstevel@tonic-gate return (DDI_FAILURE);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate (void) sprintf(addr, "%x,%x", portid, LO32(child_rp->upa64s_phys));
10860Sstevel@tonic-gate ddi_set_name_addr(child, addr);
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate ddi_set_parent_data(child, NULL);
10890Sstevel@tonic-gate kmem_free(child_rp, i);
10900Sstevel@tonic-gate return (DDI_SUCCESS);
10910Sstevel@tonic-gate }
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate /*
10950Sstevel@tonic-gate * get_reg_set_size
10960Sstevel@tonic-gate *
10970Sstevel@tonic-gate * Given a dev info pointer to a child and a register number, this
10980Sstevel@tonic-gate * routine returns the size element of that reg set property.
10990Sstevel@tonic-gate *
11000Sstevel@tonic-gate * used by: upa64s_ctlops() - DDI_CTLOPS_REGSIZE
11010Sstevel@tonic-gate *
11020Sstevel@tonic-gate * return value: size of reg set on success, -1 on error
11030Sstevel@tonic-gate */
11040Sstevel@tonic-gate static off_t
get_reg_set_size(dev_info_t * child,int rnumber)11050Sstevel@tonic-gate get_reg_set_size(dev_info_t *child, int rnumber)
11060Sstevel@tonic-gate {
11070Sstevel@tonic-gate upa64s_regspec_t *upa64s_rp;
11080Sstevel@tonic-gate uint_t size;
11090Sstevel@tonic-gate int i;
11100Sstevel@tonic-gate
11110Sstevel@tonic-gate if (rnumber < 0)
11120Sstevel@tonic-gate return (-1);
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate /*
11150Sstevel@tonic-gate * Get the reg property for the device.
11160Sstevel@tonic-gate */
1117506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
11180Sstevel@tonic-gate (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
11190Sstevel@tonic-gate return (-1);
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate if (rnumber >= (i / (int)sizeof (upa64s_regspec_t))) {
11220Sstevel@tonic-gate kmem_free(upa64s_rp, i);
11230Sstevel@tonic-gate return (-1);
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate /* >4G reg size not supported */
11270Sstevel@tonic-gate size = (uint32_t)upa64s_rp[rnumber].upa64s_size;
11280Sstevel@tonic-gate kmem_free(upa64s_rp, i);
11290Sstevel@tonic-gate return (size);
11300Sstevel@tonic-gate }
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate
11330Sstevel@tonic-gate /*
11340Sstevel@tonic-gate * get_nreg_set
11350Sstevel@tonic-gate *
11360Sstevel@tonic-gate * Given a dev info pointer to a child, this routine returns the
11370Sstevel@tonic-gate * number of sets in its "reg" property.
11380Sstevel@tonic-gate *
11390Sstevel@tonic-gate * used by: upa64s_ctlops() - DDI_CTLOPS_NREGS
11400Sstevel@tonic-gate *
11410Sstevel@tonic-gate * return value: # of reg sets on success, zero on error
11420Sstevel@tonic-gate */
11430Sstevel@tonic-gate static uint_t
get_nreg_set(dev_info_t * child)11440Sstevel@tonic-gate get_nreg_set(dev_info_t *child)
11450Sstevel@tonic-gate {
11460Sstevel@tonic-gate upa64s_regspec_t *upa64s_rp;
11470Sstevel@tonic-gate int i, n;
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate /*
11500Sstevel@tonic-gate * Get the reg property for the device.
11510Sstevel@tonic-gate */
1152506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
11530Sstevel@tonic-gate (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
11540Sstevel@tonic-gate return (0);
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate n = i / (int)sizeof (upa64s_regspec_t);
11570Sstevel@tonic-gate kmem_free(upa64s_rp, i);
11580Sstevel@tonic-gate return (n);
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate
11610Sstevel@tonic-gate
11620Sstevel@tonic-gate /*
11630Sstevel@tonic-gate * upa64s_intrdist
11640Sstevel@tonic-gate *
11650Sstevel@tonic-gate * The following routine is the callback function for this nexus driver
11660Sstevel@tonic-gate * to support interrupt distribution on sun4u systems. When this
11670Sstevel@tonic-gate * function is called by the interrupt distribution framework, it will
11680Sstevel@tonic-gate * reprogram all the active the mondo registers.
11690Sstevel@tonic-gate */
11700Sstevel@tonic-gate static void
upa64s_intrdist(void * arg)11710Sstevel@tonic-gate upa64s_intrdist(void *arg)
11720Sstevel@tonic-gate {
11730Sstevel@tonic-gate dev_info_t *dip = (dev_info_t *)arg;
11740Sstevel@tonic-gate int instance = ddi_get_instance(dip);
11750Sstevel@tonic-gate upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
11760Sstevel@tonic-gate uint_t upaport;
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate for (upaport = 0; upaport < UPA64S_PORTS; upaport++) {
11790Sstevel@tonic-gate volatile uint64_t *imr;
11800Sstevel@tonic-gate volatile uint64_t imr_dat;
11810Sstevel@tonic-gate uint_t mondo;
11820Sstevel@tonic-gate uint32_t cpuid;
11830Sstevel@tonic-gate
11840Sstevel@tonic-gate if (upa64s_p->ino_state[upaport] != INO_INUSE)
11850Sstevel@tonic-gate continue;
11860Sstevel@tonic-gate
11870Sstevel@tonic-gate imr = upa64s_p->imr[upaport];
11880Sstevel@tonic-gate mondo = UPA64S_IMR_TO_MONDO(*imr);
11890Sstevel@tonic-gate cpuid = intr_dist_cpuid();
11900Sstevel@tonic-gate imr_dat = UPA64S_CPUID_TO_IMR(cpuid);
11910Sstevel@tonic-gate imr_dat = UPA64S_GET_MAP_REG(mondo, imr_dat);
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /* Check and re-program cpu target if necessary */
11940Sstevel@tonic-gate DBG2(D_INTRDIST, dip, "mondo=%x cpuid=%x\n", mondo, cpuid);
11950Sstevel@tonic-gate if (UPA64S_IMR_TO_CPUID(*imr) == cpuid) {
11960Sstevel@tonic-gate DBG(D_INTRDIST, dip, "same cpuid\n");
11970Sstevel@tonic-gate continue;
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate ddi_put64(upa64s_p->imr_ah[upaport], (uint64_t *)imr, imr_dat);
12000Sstevel@tonic-gate imr_dat = ddi_get64(upa64s_p->imr_ah[upaport], (uint64_t *)imr);
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate #ifdef DEBUG
12060Sstevel@tonic-gate static void
upa64s_debug(uint_t flag,dev_info_t * dip,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)12070Sstevel@tonic-gate upa64s_debug(uint_t flag, dev_info_t *dip, char *fmt,
12080Sstevel@tonic-gate uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate char *s = NULL;
12110Sstevel@tonic-gate uint_t cont = 0;
12120Sstevel@tonic-gate if (flag & D_CONT) {
12130Sstevel@tonic-gate flag &= ~D_CONT;
12140Sstevel@tonic-gate cont = 1;
12150Sstevel@tonic-gate }
12160Sstevel@tonic-gate if (!(upa64s_debug_flags & flag))
12170Sstevel@tonic-gate return;
12180Sstevel@tonic-gate
12190Sstevel@tonic-gate switch (flag) {
12200Sstevel@tonic-gate case D_ATTACH: s = "attach"; break;
12210Sstevel@tonic-gate case D_DETACH: s = "detach"; break;
12220Sstevel@tonic-gate case D_POWER: s = "power"; break;
12230Sstevel@tonic-gate case D_MAP: s = "map"; break;
12240Sstevel@tonic-gate case D_CTLOPS: s = "ctlops"; break;
12250Sstevel@tonic-gate case D_G_ISPEC: s = "get_intrspec"; break;
12260Sstevel@tonic-gate case D_A_ISPEC: s = "add_intrspec"; break;
12270Sstevel@tonic-gate case D_R_ISPEC: s = "remove_intrspec"; break;
12280Sstevel@tonic-gate case D_INIT_CLD: s = "init_child"; break;
12290Sstevel@tonic-gate case D_INTRDIST: s = "intrdist"; break;
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate
12320Sstevel@tonic-gate if (s && cont == 0) {
12330Sstevel@tonic-gate prom_printf("%s(%d): %s: ", ddi_get_name(dip),
12340Sstevel@tonic-gate ddi_get_instance(dip), s);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate prom_printf(fmt, a1, a2, a3, a4, a5);
12370Sstevel@tonic-gate }
12380Sstevel@tonic-gate #endif
1239